OSDN Git Service

Evernote APIの帯域制限超過時にエラーメッセージを表示するようにした
[neighbornote/NeighborNote.git] / src / cx / fbn / nevernote / NeverNote.java
index 65ba96e..90adc7b 100644 (file)
@@ -1,6 +1,7 @@
 /*
-  * This file is part of NixNote 
+  * This file is part of NixNote/NeighborNote 
  * Copyright 2009 Randy Baumgarte
+ * Copyright 2013 Yuki Takahashi
  * 
  * This file may be licensed under the terms of of the
  * GNU General Public License Version 2 (the ``GPL'').
@@ -46,9 +47,9 @@ import java.util.Vector;
 
 import org.apache.log4j.Level;
 import org.apache.log4j.Logger;
-import org.apache.thrift.TException;
 import org.h2.tools.ChangeFileEncryption;
 
+import com.evernote.edam.error.EDAMErrorCode;
 import com.evernote.edam.error.EDAMNotFoundException;
 import com.evernote.edam.error.EDAMSystemException;
 import com.evernote.edam.error.EDAMUserException;
@@ -65,6 +66,7 @@ import com.evernote.edam.type.Resource;
 import com.evernote.edam.type.SavedSearch;
 import com.evernote.edam.type.Tag;
 import com.evernote.edam.type.User;
+import com.evernote.thrift.TException;
 import com.trolltech.qt.QThread;
 import com.trolltech.qt.core.QByteArray;
 import com.trolltech.qt.core.QDateTime;
@@ -81,6 +83,7 @@ import com.trolltech.qt.core.QModelIndex;
 import com.trolltech.qt.core.QSize;
 import com.trolltech.qt.core.QTemporaryFile;
 import com.trolltech.qt.core.QTextCodec;
+import com.trolltech.qt.core.QTextStream;
 import com.trolltech.qt.core.QThreadPool;
 import com.trolltech.qt.core.QTimer;
 import com.trolltech.qt.core.QTranslator;
@@ -104,7 +107,6 @@ import com.trolltech.qt.gui.QComboBox;
 import com.trolltech.qt.gui.QCursor;
 import com.trolltech.qt.gui.QDesktopServices;
 import com.trolltech.qt.gui.QDialog;
-import com.trolltech.qt.gui.QDockWidget;
 import com.trolltech.qt.gui.QFileDialog;
 import com.trolltech.qt.gui.QFileDialog.AcceptMode;
 import com.trolltech.qt.gui.QFileDialog.FileMode;
@@ -179,6 +181,7 @@ import cx.fbn.nevernote.gui.ExternalBrowse;
 import cx.fbn.nevernote.gui.MainMenuBar;
 import cx.fbn.nevernote.gui.NotebookTreeWidget;
 import cx.fbn.nevernote.gui.RensoNoteList;
+import cx.fbn.nevernote.gui.RensoNoteListDock;
 import cx.fbn.nevernote.gui.SavedSearchTreeWidget;
 import cx.fbn.nevernote.gui.SearchPanel;
 import cx.fbn.nevernote.gui.TabBrowse;
@@ -206,6 +209,7 @@ import cx.fbn.nevernote.xml.ExportData;
 import cx.fbn.nevernote.xml.ImportData;
 import cx.fbn.nevernote.xml.ImportEnex;
 import cx.fbn.nevernote.xml.NoteFormatter;
+//import org.apache.thrift.TException;
 
 
 public class NeverNote extends QMainWindow{
@@ -248,9 +252,10 @@ public class NeverNote extends QMainWindow{
     NoteFilter                         filter;                                         // Note filter
     String                                     currentNoteGuid;                        // GUID of the current note 
     Note                                       currentNote;                            // The currently viewed note
-    boolean                                    noteDirty;                                      // Has the note been changed?
-    boolean                            inkNote;                   // if this is an ink note, it is read only
-    boolean                                    readOnly;                                       // Is this note read-only?
+    // ICHANGED
+    HashMap<Integer, Boolean>  noteDirty;                              // Has the note been changed?
+    HashMap<Integer, Boolean>  inkNote;                // if this is an ink note, it is read only
+    HashMap<Integer, Boolean>  readOnly;                               // Is this note read-only?
        
   
     ListManager                                listManager;                                    // DB runnable task
@@ -325,12 +330,14 @@ public class NeverNote extends QMainWindow{
     int                                        tagDeadCount=0;                         // number of consecutive dead times for the tag thread
     int                                        trashDeadCount=0;                       // number of consecutive dead times for the trash thread
     int                                saveThreadDeadCount=0;          // number of consecutive dead times for the save thread
+    int                                enRelatedNotesThreadDeadCount=0;        // number of consecutive dead times for the EvernoteRelatedNotes Thread
     boolean                            disableTagThreadCheck=false;
     boolean                            disableNotebookThreadCheck=false;
     boolean                            disableTrashThreadCheck=false;
     boolean                            disableSaveThreadCheck=false;
     boolean                            disableSyncThreadCheck=false;
     boolean                            disableIndexThreadCheck=false;
+    boolean                            disableENRelatedNotesThreadCheck=false;
     
     HashMap<String, String>            noteCache;                      // Cash of note content 
     HashMap<String, Boolean>   readOnlyCache;          // List of cashe notes that are read-only
@@ -360,13 +367,8 @@ public class NeverNote extends QMainWindow{
        // ICHANGED
        private final TabBrowserWidget tabBrowser; // ブラウザウィンドウをタブ化
        private final HashMap<Integer, TabBrowse> tabWindows; // タブウィンドウ
-       private final RensoNoteList rensoNoteList; // 連想ノートリスト
-       private final QDockWidget rensoNoteListDock; // 連想ノートリストドックウィジェット
-       
-       // ICHANGED
+       private final RensoNoteListDock rensoNoteListDock; // 連想ノートリストドックウィジェット
        ClipBoardObserver cbObserver;
-       
-       // ICHANGED
        String rensoNotePressedItemGuid;
        
     String iconPath = new String("classpath:cx/fbn/nevernote/icons/");
@@ -415,7 +417,7 @@ public class NeverNote extends QMainWindow{
                logger.log(logger.EXTREME, "Starting GUI build");
 
                QTranslator nevernoteTranslator = new QTranslator();
-               nevernoteTranslator.load(Global.getFileManager().getTranslateFilePath("nevernote_" + QLocale.system().name() + ".qm"));
+               nevernoteTranslator.load(Global.getFileManager().getTranslateFilePath("neighbornote_" + QLocale.system().name() + ".qm"));
                QApplication.instance().installTranslator(nevernoteTranslator);
 
                Global.originalPalette = QApplication.palette();
@@ -454,9 +456,9 @@ public class NeverNote extends QMainWindow{
                indexThread = new QThread(indexRunner, "Index Thread");
         indexRunner.indexAttachmentsLocally = Global.indexAttachmentsLocally();
         indexRunner.indexImageRecognition = Global.indexImageRecognition();
-        indexRunner.indexNoteBody = Global.indexNoteBody();
-        indexRunner.indexNoteTitle = Global.indexNoteTitle();
-        indexRunner.specialIndexCharacters = Global.getSpecialIndexCharacters();
+//        indexRunner.indexNoteBody = Global.indexNoteBody();
+//        indexRunner.indexNoteTitle = Global.indexNoteTitle();
+//        indexRunner.specialIndexCharacters = Global.getSpecialIndexCharacters();
                indexThread.start();
                
         synchronizeAnimationTimer = new QTimer();
@@ -483,6 +485,7 @@ public class NeverNote extends QMainWindow{
         syncRunner.status.message.connect(this, "setMessage(String)");
         syncRunner.syncSignal.finished.connect(this, "syncThreadComplete(Boolean)");
         syncRunner.syncSignal.errorDisconnect.connect(this, "remoteErrorDisconnect()");
+        syncRunner.limitSignal.rateLimitReached.connect(this, "informRateLimit(Integer)");
         syncRunning = false;   
                if (syncTime > 0) {
                        automaticSync = true;
@@ -600,13 +603,20 @@ public class NeverNote extends QMainWindow{
                tabWindows = new HashMap<Integer, TabBrowse>();
                tabBrowser = new TabBrowserWidget(this);
                tabBrowser.setStyleSheet("QTabBar::tab{width:150px;}");
+               tabBrowser.setMovable(true);
+               tabBrowser.setTabsClosable(true);
                TabBrowse tab = new TabBrowse(conn, tabBrowser, cbObserver);
                browserWindow = tab.getBrowserWindow();
                int index = tabBrowser.addNewTab(tab, "");
                tabWindows.put(index, tab);
-               tabBrowser.setTabsClosable(true);
                tabBrowser.currentChanged.connect(this, "tabWindowChanged(int)");
                tabBrowser.tabCloseRequested.connect(this, "tabWindowClosing(int)");
+               
+               noteDirty = new HashMap<Integer, Boolean>();
+               noteDirty.put(index, false);
+               
+               inkNote = new HashMap<Integer, Boolean>();
+               readOnly = new HashMap<Integer, Boolean>();
 
                // ICHANGED
                // 履歴記録のハッシュマップを初期化
@@ -619,11 +629,7 @@ public class NeverNote extends QMainWindow{
         
                // ICHANGED
                // 連想ノートリストをセットアップ
-               rensoNoteList = new RensoNoteList(conn, this);
-               rensoNoteList.itemPressed.connect(this,
-                               "rensoNoteItemPressed(QListWidgetItem)");
-               rensoNoteListDock = new QDockWidget(tr("Renso Note List"), this);
-               rensoNoteListDock.setWidget(rensoNoteList);
+        rensoNoteListDock = new RensoNoteListDock(conn, this, syncRunner, iconPath, tr("Renso Note List"));
                addDockWidget(DockWidgetArea.RightDockWidgetArea, rensoNoteListDock);
 
                if (Global.getListView() == Global.View_List_Wide) {
@@ -732,13 +738,21 @@ public class NeverNote extends QMainWindow{
                noteTableView.setVisible(Global.isWindowVisible("noteList"));
                menuBar.hideNoteList.setChecked(Global.isWindowVisible("noteList"));
                
-               if (!Global.isWindowVisible("editorButtonBar"))
+               // ICHANGED
+               if (!Global.isWindowVisible("editorButtonBar")) {
+                       menuBar.showEditorBar.setChecked(false);
                        toggleEditorButtonBar();
+               }
                
                if (!Global.isWindowVisible("leftPanel"))
                        menuBar.hideLeftSide.setChecked(true);
-               if (Global.isWindowVisible("noteInformation"))
+               
+               // ICHANGED
+               if (Global.isWindowVisible("noteInformation")) {
+                       menuBar.noteAttributes.setChecked(true);
                        toggleNoteInformation();
+               }
+               
                quotaBar.setVisible(Global.isWindowVisible("quota"));
                // IFIXED quotaBar.isVisible() → Global.isWindowVisible("quota")
                // なぜかquotaBar.isVisible()が常にfalseを返すようなので修正
@@ -791,7 +805,6 @@ public class NeverNote extends QMainWindow{
                fromHistory = false;
                */
                
-               noteDirty = false;
                if (!currentNoteGuid.trim().equals("")) {
                        currentNote = conn.getNoteTable().getNote(currentNoteGuid, true,true,false,false,true);
                }
@@ -903,8 +916,12 @@ public class NeverNote extends QMainWindow{
        }
                
                if (Global.checkVersionUpgrade()) {
-                       // ICHANGED TODO とりあえず封印
-                       // checkForUpdates();
+                       checkForUpdates();
+               }
+               
+               // ICHANGED
+               if (currentNoteGuid == null || currentNoteGuid.equals("")) {
+                       menuBar.noteAddNewTab.setEnabled(false);
                }
        }
        
@@ -1233,6 +1250,9 @@ public class NeverNote extends QMainWindow{
                saveNote();
                listManager.stop();
                saveWindowState();
+               
+               // 連想ノートリストのEvernote関連ノート取得スレッドを終了
+               rensoNoteListDock.getRensoNoteList().stopThread();
 
                if (tempFiles != null)
                        tempFiles.clear();
@@ -1435,7 +1455,7 @@ public class NeverNote extends QMainWindow{
                saveNoteColumnPositions();
                saveNoteIndexWidth();
                showColumns();
-        ConfigDialog settings = new ConfigDialog(this);
+        ConfigDialog settings = new ConfigDialog(this, conn);
         String dateFormat = Global.getDateFormat();
         String timeFormat = Global.getTimeFormat();
         
@@ -1444,9 +1464,9 @@ public class NeverNote extends QMainWindow{
         
         settings.exec();
         indexRunner.indexAttachmentsLocally = Global.indexAttachmentsLocally();
-        indexRunner.indexNoteBody = Global.indexNoteBody();
-        indexRunner.indexNoteTitle = Global.indexNoteTitle();
-        indexRunner.specialIndexCharacters = Global.getSpecialIndexCharacters();
+//        indexRunner.indexNoteBody = Global.indexNoteBody();
+//        indexRunner.indexNoteTitle = Global.indexNoteTitle();
+//        indexRunner.specialIndexCharacters = Global.getSpecialIndexCharacters();
         indexRunner.indexImageRecognition = Global.indexImageRecognition();
         if (Global.showTrayIcon() || Global.minimizeOnClose())
                trayIcon.show();
@@ -2522,7 +2542,15 @@ public class NeverNote extends QMainWindow{
                        }
                }
                browserWindow.setTag(names.toString());
-               noteDirty = true;
+               
+               // ICHANGED
+               for (TabBrowse tab: tabWindows.values()) {
+                       if (tab.getBrowserWindow().getNote().getGuid().equals(guid)) {
+                               int index = tabBrowser.indexOf(tab);
+                               noteDirty.put(index, true);
+                               break;
+                       }
+               }
                
                // Now, we need to add any new tags to the tag tree
                for (int i=0; i<newTags.size(); i++) 
@@ -2938,6 +2966,8 @@ public class NeverNote extends QMainWindow{
                status.setTagCount(listManager.getTagIndex().size());
                status.setResourceCount(conn.getNoteTable().noteResourceTable.getResourceCount());
                status.setWordCount(conn.getWordsTable().getWordCount());
+               status.setHistoryCount(conn.getHistoryTable().getHistoryCount());
+               status.setRensoClickCount(conn.getHistoryTable().getRensoClickCount());
                waitCursor(false);
                status.exec();
        }
@@ -2978,7 +3008,12 @@ public class NeverNote extends QMainWindow{
                if (!file.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly,
                 QIODevice.OpenModeFlag.Text)))
                        return;
-               textBox.setText(file.readAll().toString());
+               // ICHANGED 日本語文字化け対策
+               QTextCodec codec = QTextCodec.codecForName("UTF-8");
+               QTextStream textStream = new QTextStream(file);
+               textStream.setCodec(codec);
+               textBox.setText(textStream.readAll().toString());
+               
                file.close();
                dialog.setWindowTitle(tr("Release Notes"));
                dialog.setLayout(layout);
@@ -3188,6 +3223,7 @@ public class NeverNote extends QMainWindow{
        logger.log(logger.HIGH, "Entering NeverNote.setupToolBar");
        toolBar = addToolBar(tr("Tool Bar"));   
        toolBar.setObjectName("toolBar");
+       toolBar.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon);
        menuBar.setupToolBarVisible();
        if (!Global.isWindowVisible("toolBar"))
                toolBar.setVisible(false);
@@ -3197,18 +3233,22 @@ public class NeverNote extends QMainWindow{
 //     toolBar.addWidget(menuBar);
 //     menuBar.setSizePolicy(Policy.Minimum, Policy.Minimum);
 //     toolBar.addSeparator();
-       prevButton = toolBar.addAction(tr("Previous"));
+       prevButton = toolBar.addAction(tr(""));
+       prevButton.setToolTip(tr("Previous"));
        QIcon prevIcon = new QIcon(iconPath+"back.png");
        prevButton.setIcon(prevIcon);
        prevButton.triggered.connect(this, "previousViewedAction()");   
        togglePrevArrowButton(Global.isToolbarButtonVisible("prevArrow"));
        
-       nextButton = toolBar.addAction(tr("Next"));
+       nextButton = toolBar.addAction(tr(""));
+       nextButton.setToolTip(tr("Next"));
        QIcon nextIcon = new QIcon(iconPath+"forward.png");
        nextButton.setIcon(nextIcon);
        nextButton.triggered.connect(this, "nextViewedAction()");       
        toggleNextArrowButton(Global.isToolbarButtonVisible("nextArrow"));
        
+       toolBar.addSeparator();
+       
        upButton = toolBar.addAction(tr("Up"));
        QIcon upIcon = new QIcon(iconPath+"up.png");
        upButton.setIcon(upIcon);
@@ -3559,6 +3599,12 @@ public class NeverNote extends QMainWindow{
                                        
                Global.showDeleted = true;
        }
+       
+       menuBar.noteAddNewTab.setEnabled(newButton.isEnabled());
+               if (currentNoteGuid == null || currentNoteGuid.equals("")) {
+                       menuBar.noteAddNewTab.setEnabled(false);
+               }
+       
        listManager.loadNotesIndex();
        noteIndexUpdated(false);
 ////           browserWindow.setEnabled(newButton.isEnabled());
@@ -3578,6 +3624,10 @@ public class NeverNote extends QMainWindow{
                listManager.setSelectedSavedSearch("");
                newButton.setEnabled(!newButton.isEnabled());
                menuBar.noteAdd.setEnabled(newButton.isEnabled());
+               menuBar.noteAddNewTab.setEnabled(newButton.isEnabled());
+               if (currentNoteGuid == null || currentNoteGuid.equals("")) {
+                       menuBar.noteAddNewTab.setEnabled(false);
+               }
                menuBar.noteAdd.setVisible(true);
                browserWindow.clear();
                
@@ -3616,6 +3666,11 @@ public class NeverNote extends QMainWindow{
                Global.showDeleted = false;
        newButton.setEnabled(true);
        menuBar.noteAdd.setEnabled(true);
+               if (currentNoteGuid == null || currentNoteGuid.equals("")) {
+                       menuBar.noteAddNewTab.setEnabled(false);
+               } else {
+                       menuBar.noteAddNewTab.setEnabled(true);
+               }
        menuBar.noteAdd.setVisible(true);
                trashTree.blockSignals(true);
                trashTree.clearSelection();
@@ -3700,6 +3755,7 @@ public class NeverNote extends QMainWindow{
 
                Global.isConnected = syncRunner.isConnected;
                
+               boolean autoLoginMessageFlag = false;
                if (!Global.isConnected) {
                OAuthWindow window = new OAuthWindow(logger);
                if (window.error) {
@@ -3726,6 +3782,7 @@ public class NeverNote extends QMainWindow{
                syncRunner.authToken = tokenizer.oauth_token;
                        syncRunner.enConnect();
                        Global.isConnected = syncRunner.isConnected;
+                       autoLoginMessageFlag = true;
                }
 //             Global.username = syncRunner.username;
                        
@@ -3733,9 +3790,16 @@ public class NeverNote extends QMainWindow{
                        return;
                setupOnlineMenu();
                setupConnectMenuOptions();
+               
+               // 初回ログイン時に自動ログインが無効だったら、有効化するか確認する
+               if (autoLoginMessageFlag && !Global.automaticLogin()) {
+                       if (QMessageBox.question(this, tr("Confirmation"), tr("Are you sure you want to enable the auto-login feature?"), 
+                                       QMessageBox.StandardButton.Yes, QMessageBox.StandardButton.No) == StandardButton.Yes.value()) {
+                               Global.setAutomaticLogin(true);
+                       }
+               }
+               
                logger.log(logger.HIGH, "Leaving NeverNote.remoteConnect");
-
-
     }
     private void setupConnectMenuOptions() {
        logger.log(logger.HIGH, "entering NeverNote.setupConnectMenuOptions");
@@ -3882,16 +3946,9 @@ public class NeverNote extends QMainWindow{
                saveNote();
                
                // ICHANGED
-               // Ctrlを押しながらノートテーブルを選択した時に選択ノート数0になってしまうのを止める
-               if (noteTableView.selectionModel().selectedRows().size() == 0) {
-                       scrollToGuid(currentNoteGuid);
-                       return;
-               }
-               
-               // ICHANGED
                // 右クリックだったときの処理
                if (QApplication.mouseButtons().isSet(MouseButton.RightButton)) {
-                       // 選択されたノート(current)のguidをcurrentnoteguidにセット
+                       // 選択されたノートのguidをselectedNoteGUIDsにセット
                        List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
                        if(selections.size() > 0){
                                selectedNoteGUIDs.clear();
@@ -3899,8 +3956,7 @@ public class NeverNote extends QMainWindow{
                                        int row = selections.get(i).row();
                                        QModelIndex index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition);
                                        SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
-                                       currentNoteGuid = (String) ix.values().toArray()[0];
-                                       selectedNoteGUIDs.add(currentNoteGuid);
+                                       selectedNoteGUIDs.add((String) ix.values().toArray()[0]);
                                }
                        }
                        return;
@@ -3916,7 +3972,9 @@ public class NeverNote extends QMainWindow{
                // If the ctrl key is pressed, then they are selecting multiple 
                // entries and we don't want to change the currently viewed note.
                // ICHANGED
-               if (QApplication.keyboardModifiers().isSet(KeyboardModifier.ControlModifier) &&
+               // Shiftキーを押しながらの場合の処理も追加
+               if ((QApplication.keyboardModifiers().isSet(KeyboardModifier.ControlModifier) ||
+                               QApplication.keyboardModifiers().isSet(KeyboardModifier.ShiftModifier)) &&
                                QApplication.mouseButtons().isSet(MouseButton.LeftButton)){
                        selectedNoteGUIDs.clear();
                for (int i=0; i<selections.size(); i++) {
@@ -3946,6 +4004,9 @@ public class NeverNote extends QMainWindow{
                menuBar.noteOnlineHistoryAction.setEnabled(true);
                menuBar.noteMergeAction.setEnabled(true);
                selectedNoteGUIDs.clear();
+               if (currentNoteGuid != null && !currentNoteGuid.equals("") && !Global.showDeleted) {
+                       menuBar.noteAddNewTab.setEnabled(true);
+               }
                if (selections.size() != 1 || Global.showDeleted) {
                        menuBar.noteDuplicateAction.setEnabled(false);
                }
@@ -3968,7 +4029,7 @@ public class NeverNote extends QMainWindow{
                        index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition);
                        SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
                                
-                       currentNoteGuid = (String)ix.values().toArray()[0];
+                       currentNoteGuid = (String)ix.values().toArray()[0];                     
                        selectedNoteGUIDs.add(currentNoteGuid);
                }
        }
@@ -4013,7 +4074,7 @@ public class NeverNote extends QMainWindow{
 
                // ICHANGED
                // 連想ノートリストを更新
-               rensoNoteList.refreshRensoNoteList(currentNoteGuid);
+               rensoNoteListDock.getRensoNoteList().refreshRensoNoteList(currentNoteGuid);
                
                waitCursor(false);
                logger.log(logger.HIGH, "Leaving NeverNote.noteTableSelection");
@@ -4522,10 +4583,6 @@ public class NeverNote extends QMainWindow{
                        }
                }
        }
-       
-       // ICHANGED
-       restoreSelectedNoteInfo();
-       
        logger.log(logger.HIGH, "Leaving NeverNote.titleColorChanged");
     }
     // A note has been pinned or unpinned
@@ -4543,10 +4600,6 @@ public class NeverNote extends QMainWindow{
                listManager.updateNoteMetadata(meta);   
                noteTableView.proxyModel.addGuid(selectedNoteGUIDs.get(j), meta);
        }
-       
-       // ICHANGED
-       restoreSelectedNoteInfo();
-
                logger.log(logger.EXTREME, "Leaving NeverNote.notePinned()");
     }
     // Wide list was chosen
@@ -4763,6 +4816,11 @@ public class NeverNote extends QMainWindow{
                TabBrowse newBrowser = new TabBrowse(conn, tabBrowser, cbObserver);
                showEditorButtons(newBrowser.getBrowserWindow());
                
+               String noteTitle = note.getTitle();
+               int index = tabBrowser.addNewTab(newBrowser, noteTitle);
+               tabWindows.put(index, newBrowser);
+               noteDirty.put(index, false);
+               
                // noteTableViewの選択を変更するとselectionChangedが発生してしまうので一度切断
                noteTableView.selectionModel().selectionChanged.disconnect(this, "noteTableSelection()");
                loadNoteBrowserInformation(newBrowser.getBrowserWindow(), guid, note);
@@ -4771,10 +4829,6 @@ public class NeverNote extends QMainWindow{
                
                setupBrowserWindowListeners(newBrowser.getBrowserWindow(), false);
                
-               String noteTitle = note.getTitle();
-               int index = tabBrowser.addNewTab(newBrowser, noteTitle);
-               tabWindows.put(index, newBrowser);
-               
                // ExtendedInformationを必要があれば表示する
                toggleNoteInformation();
                // Sourceを必要があれば表示する
@@ -4828,6 +4882,9 @@ public class NeverNote extends QMainWindow{
                // ノートを削除
                tabWindows.remove(index);
                tabBrowser.removeTab(index);
+               noteDirty.remove(index);
+               inkNote.remove(index);
+               readOnly.remove(index);
 
                // 履歴記録のハッシュマップを削除
                historyGuids.remove(index);
@@ -4840,6 +4897,18 @@ public class NeverNote extends QMainWindow{
                        TabBrowse tab = tabWindows.get(i + 1);
                        tabWindows.put(i, tab);
                        tabWindows.remove(i + 1);
+                       // noteDirty
+                       boolean isNoteDirty = noteDirty.get(i + 1);
+                       noteDirty.put(i, isNoteDirty);
+                       noteDirty.remove(i + 1);
+                       // inkNote
+                       boolean isInkNote = inkNote.get(i + 1);
+                       inkNote.put(i, isInkNote);
+                       inkNote.remove(i + 1);
+                       // readOnly
+                       boolean isReadOnly = readOnly.get(i + 1);
+                       readOnly.put(i, isReadOnly);
+                       readOnly.remove(i + 1);
                        // historyGuids
                        ArrayList<String> histGuids = historyGuids.get(i + 1);
                        historyGuids.put(i, histGuids);
@@ -4854,6 +4923,11 @@ public class NeverNote extends QMainWindow{
                        fromHistory.remove(i + 1);
                }
                
+               // タブが残り1つになったら、閉じるボタンを消す
+               if (tabBrowser.count() == 1) {
+                       tabBrowser.hideTabCloseButton(0);
+               }
+               
                // タブの閉じるボタンを押すと、tabWindowClosingより先にtabWindowChangedが呼ばれてしまうので、手動で呼びなおす
                tabWindowChanged(tabBrowser.currentIndex());
        }
@@ -4864,15 +4938,18 @@ public class NeverNote extends QMainWindow{
                
                // ノート追加前に開いていたノートとの関連性を記録するためにguidをとっておく
                TabBrowse prevTab = (TabBrowse)tabBrowser.currentWidget();
-               String prevTabGuid = prevTab.getBrowserWindow().getNote().getGuid();
+               String prevTabGuid = null;
+               if (prevTab.getBrowserWindow() != null && prevTab.getBrowserWindow().getNote() != null) {
+                       prevTabGuid = prevTab.getBrowserWindow().getNote().getGuid();
+               }
                
                openEmptyTabEditor();
                addNote();
                
                // 追加されたノートのguidを取得し、ノート追加操作履歴としてデータベースに登録
-               TabBrowse addedTab = (TabBrowse)tabBrowser.currentWidget();
-               String addedTabGuid = addedTab.getBrowserWindow().getNote().getGuid();
                if (prevTabGuid != null && !prevTabGuid.equals("")) {
+                       TabBrowse addedTab = (TabBrowse)tabBrowser.currentWidget();
+                       String addedTabGuid = addedTab.getBrowserWindow().getNote().getGuid();
                        if (addedTabGuid != null && !addedTabGuid.equals("")) {
                                if (!prevTabGuid.equals(addedTabGuid)) {
                                        conn.getHistoryTable().addHistory("addNewNote", prevTabGuid, addedTabGuid);
@@ -4891,6 +4968,7 @@ public class NeverNote extends QMainWindow{
                
                int index = tabBrowser.addNewTab(newBrowser, "");
                tabWindows.put(index, newBrowser);
+               noteDirty.put(index, false);
                
                // ExtendedInformationを必要があれば表示する
                toggleNoteInformation();
@@ -4913,61 +4991,79 @@ public class NeverNote extends QMainWindow{
     //** These functions deal with Note specific things
     //***************************************************************
     //***************************************************************    
+       // ICHANGED
        private void setNoteDirty() {
+               for (String guid: selectedNoteGUIDs) {
+                       setNoteDirty(guid);
+               }
+       }
+       
+       // ICHANGED
+       private void setNoteDirty(String targetGuid) {
                logger.log(logger.EXTREME, "Entering NeverNote.setNoteDirty()");
                
                // Find if the note is being edited externally.  If it is, update it.
-               if (externalWindows.containsKey(currentNoteGuid)) {
+               if (externalWindows.containsKey(targetGuid)) {
                        QTextCodec codec = QTextCodec.codecForName("UTF-8");
                QByteArray unicode =  codec.fromUnicode(browserWindow.getContent());
-                       ExternalBrowse window = externalWindows.get(currentNoteGuid);
+                       ExternalBrowse window = externalWindows.get(targetGuid);
                window.getBrowserWindow().setContent(unicode);
                }
                
-               // ICHANGED ↓↓↓ここから↓↓↓
                // 他のタブで同じノートを開いていないか探す。もしあったら、内容を更新する。
-               Collection<TabBrowse> tabBrowsers = tabWindows.values();
-               Iterator<TabBrowse> tabIterator = tabBrowsers.iterator();
                Collection<Integer> tabIndexes = tabWindows.keySet();
                Iterator<Integer>       indexIterator = tabIndexes.iterator();
                
-               while (tabIterator.hasNext()) {
-                       TabBrowse tab = tabIterator.next();
+               for (TabBrowse tab: tabWindows.values()) {
                        int index = indexIterator.next();
                        String guid = tab.getBrowserWindow().getNote().getGuid();
                        
                        QTextCodec codec = QTextCodec.codecForName("UTF-8");
                        QByteArray unicode = codec.fromUnicode(browserWindow.getContent());
                        
-                       if (guid.equals(currentNoteGuid)) {
+                       if (guid.equals(guid)) {
                                if (index != tabBrowser.currentIndex()) {
                                        TabBrowse window = tabWindows.get(index);
                                        window.getBrowserWindow().setContent(unicode);
                                }
                        }
                }
-               // ICHANGED ↑↑↑ここまで↑↑↑
                
+               // ターゲットノートがタブで開かれていて、かつDirty = trueかどうかを取得する
                // If the note is dirty, then it is unsynchronized by default.
-               if (noteDirty) 
+               int index = -1;
+               boolean isNoteDirty = false;
+               for (TabBrowse tab: tabWindows.values()) {
+                       if (tab.getBrowserWindow().getNote().getGuid().equals(targetGuid)) {
+                               index = tabBrowser.indexOf(tab);
+                               isNoteDirty = noteDirty.get(index);
+                               break;
+                       }
+               }
+               if (isNoteDirty) {
                        return;
+               }
                
                // Set the note as dirty and check if its status is synchronized in the display table
-               noteDirty = true;
-               if (listManager.getNoteMetadata().containsKey(currentNoteGuid) && 
-                               listManager.getNoteMetadata().get(currentNoteGuid).isDirty()) {
+               // まだダーティでなく、かつタブで開かれている場合にnoteDirty = trueにする
+               if (index >= 0) {
+                       noteDirty.put(index, true);
+               }
+
+               if (listManager.getNoteMetadata().containsKey(targetGuid) &&
+                               listManager.getNoteMetadata().get(targetGuid).isDirty()) {
                                return;
                }
                
                // If this wasn't already marked as unsynchronized, then we need to update the table
-               listManager.getNoteTableModel().updateNoteSyncStatus(currentNoteGuid, false);
-//     listManager.getUnsynchronizedNotes().add(currentNoteGuid);
+               listManager.getNoteTableModel().updateNoteSyncStatus(targetGuid, false);
+//     listManager.getUnsynchronizedNotes().add(targetGuid);
        for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
                QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
                if (modelIndex != null) {
                        SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
                        String tableGuid =  (String)ix.values().toArray()[0];
-                       if (tableGuid.equals(currentNoteGuid)) {
+                       if (tableGuid.equals(targetGuid)) {
                                listManager.getNoteTableModel().proxyModel.setData(i, Global.noteTableSynchronizedPosition, "false");
                                return;
                        }
@@ -4983,7 +5079,9 @@ public class NeverNote extends QMainWindow{
        noteCache.remove(guid);
                noteCache.put(guid, unicode.toString());
        if (guid.equals(currentNoteGuid)) {
-               noteDirty = true;
+               // ICHANGED
+               int index = tabBrowser.currentIndex();
+               noteDirty.put(index, true);
                browserWindow.setContent(unicode);
        } 
        if (save) {
@@ -5007,11 +5105,23 @@ public class NeverNote extends QMainWindow{
        }
        
     private void saveNote() {
-       if (noteDirty) {
-               saveNote(currentNoteGuid, browserWindow);
-               thumbnailRunner.addWork("GENERATE "+ currentNoteGuid);
-               noteDirty = false;
-       } 
+       // ICHANGED
+       // すべてのタブに対して、Dirtyを確認し、trueならセーブする
+       Collection<Integer> dirtyIndex = noteDirty.keySet();
+       Iterator<Integer> indexIterator = dirtyIndex.iterator();
+       for (boolean isNoteDirty: noteDirty.values()) {
+               int index = indexIterator.next();
+               if (isNoteDirty) {
+                       if (index < 0) {
+                               return;
+                       }
+                       BrowserWindow b = tabWindows.get(index).getBrowserWindow();
+                       String guid = b.getNote().getGuid();
+                       saveNote(guid, b);
+                       thumbnailRunner.addWork("GENERATE "+ guid);
+                       noteDirty.put(index, false);
+               }
+       }
     }
     private void saveNote(String guid, BrowserWindow window) {
                logger.log(logger.EXTREME, "Inside NeverNote.saveNote()");
@@ -5047,12 +5157,15 @@ public class NeverNote extends QMainWindow{
                        browserWindow.setEnabled(false);
                        return;
                }
-               inkNote = false;
-               readOnly = false;
-               if (Global.showDeleted || currentNoteGuid == null || currentNoteGuid.equals(""))
-                       readOnly = true;
+               // ICHANGED
+               inkNote.put(tabBrowser.currentIndex(), false);
+               readOnly.put(tabBrowser.currentIndex(), false);
+               
+               if (Global.showDeleted || currentNoteGuid == null || currentNoteGuid.equals("")) {
+                       readOnly.put(tabBrowser.currentIndex(), true);
+               }
                Global.cryptCounter =0;
-               if (readOnly) {
+               if (readOnly.get(tabBrowser.currentIndex())) {
                        browserWindow.setReadOnly(true);
                }
                
@@ -5074,11 +5187,22 @@ public class NeverNote extends QMainWindow{
                loadNoteBrowserInformation(browserWindow, currentNoteGuid, currentNote);
        }
 
+       // ICHANGED
        private void loadNoteBrowserInformation(BrowserWindow browser, String guid, Note note) {
                NoteFormatter   formatter = new NoteFormatter(logger, conn, tempFiles);
                formatter.setNote(note, Global.pdfPreview());
                formatter.setHighlight(listManager.getEnSearch());
                QByteArray js;
+               int tabIndex = -1;
+               
+               // 対象のタブインデックスを取得
+               for (TabBrowse tab: tabWindows.values()) {
+                       if (tab.getBrowserWindow() == browser) {
+                               tabIndex = tabBrowser.indexOf(tab);
+                               break;
+                       }
+               }
+               
                if (!noteCache.containsKey(guid)) {
                        js = new QByteArray();
                        // We need to prepend the note with <HEAD></HEAD> or encoded characters are ugly 
@@ -5103,7 +5227,7 @@ public class NeverNote extends QMainWindow{
                        noteCache.put(guid, js.toString());
 
                        if (formatter.resourceError)
-                               resourceErrorMessage();
+                               resourceErrorMessage(tabIndex);
                        if (formatter.formatError) {
                                waitCursor(false);
                             QMessageBox.information(this, tr("Error"),
@@ -5111,35 +5235,50 @@ public class NeverNote extends QMainWindow{
                                                " To protect your data this note is being marked as read-only."));      
                             waitCursor(true);
                        }
-                       readOnly = formatter.readOnly;
-                       inkNote = formatter.inkNote;
-                       if (readOnly)
+                       
+                       if (tabIndex >= 0) {
+                               readOnly.put(tabIndex, formatter.readOnly);
+                               inkNote.put(tabIndex, formatter.inkNote);
+                       } 
+                       
+                       if (tabIndex >= 0 && readOnly.get(tabIndex)) {
                                readOnlyCache.put(guid, true);
-                       if (inkNote)
+                       }
+                       if (tabIndex >= 0 && inkNote.get(tabIndex)) {
                                inkNoteCache.put(guid, true);
+                       }
+                       
                } else {
                        logger.log(logger.HIGH, "Note content is being pulled from the cache");
                        String cachedContent = formatter.modifyCachedTodoTags(noteCache.get(guid));
                        js = new QByteArray(cachedContent);
                        browser.setContent(js);
-                       if (readOnlyCache.containsKey(guid))
-                                       readOnly = true;
-                       if (inkNoteCache.containsKey(guid))
-                                       inkNote = true;
+                       if (readOnlyCache.containsKey(guid) && tabIndex >= 0) {
+                               readOnly.put(tabIndex, true);
+                       } else {
+                               readOnly.put(tabIndex, false);
+                       }
+                       if (inkNoteCache.containsKey(guid) && tabIndex >= 0) {
+                               inkNote.put(tabIndex, true);
+                       } else {
+                               inkNote.put(tabIndex, false);
+                       }
                }
                if (conn.getNoteTable().isThumbnailNeeded(guid)) {
                        thumbnailHTMLReady(guid, js, Global.calculateThumbnailZoom(js.toString()));
                }
-               if (readOnly || inkNote || 
-                               (note.getAttributes() != null && note.getAttributes().getContentClass() != null && note.getAttributes().getContentClass() != ""))
+               if (tabIndex >= 0 && (readOnly.get(tabIndex) || inkNote.get(tabIndex) || 
+                               (note.getAttributes() != null && note.getAttributes().getContentClass() != null && note.getAttributes().getContentClass() != "")))
                        browser.getBrowser().page().setContentEditable(false);  // We don't allow editing of ink notes
                else
                        browser.getBrowser().page().setContentEditable(true);
-               browser.setReadOnly(readOnly);
-               deleteButton.setEnabled(!readOnly);
-               tagButton.setEnabled(!readOnly);
-               menuBar.noteDelete.setEnabled(!readOnly);
-               menuBar.noteTags.setEnabled(!readOnly);
+               if (tabIndex >= 0) {
+                       browser.setReadOnly(readOnly.get(tabIndex));
+                       deleteButton.setEnabled(!readOnly.get(tabIndex));
+                       tagButton.setEnabled(!readOnly.get(tabIndex));
+                       menuBar.noteDelete.setEnabled(!readOnly.get(tabIndex));
+                       menuBar.noteTags.setEnabled(!readOnly.get(tabIndex));
+               }
                browser.setNote(note);
                
                if (note != null && note.getNotebookGuid() != null && 
@@ -5180,7 +5319,15 @@ public class NeverNote extends QMainWindow{
                browser.setAllTags(tagList);
                
                browser.setCurrentTags(note.getTagNames());
-               noteDirty = false;
+               // ICHANGED
+               for (TabBrowse tab: tabWindows.values()) {
+                       if (tab.getBrowserWindow().getNote().getGuid().equals(guid)) {
+                               int index = tabBrowser.indexOf(tab);
+                               noteDirty.put(index, false);
+                               break;
+                       }
+               }
+               
                scrollToGuid(guid);
                
                browser.loadingData(false);
@@ -5322,14 +5469,12 @@ public class NeverNote extends QMainWindow{
                        if (QMessageBox.question(this, tr("Confirmation"), msg,
                                        QMessageBox.StandardButton.Yes, 
                                        QMessageBox.StandardButton.No)==StandardButton.No.value() && Global.verifyDelete() == true) {
-                                               // ICHANGED
-                                               restoreSelectedNoteInfo();
-                                               
                                        return;
                        }
                }
                if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals("")) 
                        selectedNoteGUIDs.add(currentNoteGuid);
+               closeTabs(selectedNoteGUIDs);
                for (int i=0; i<selectedNoteGUIDs.size(); i++) {
                        listManager.deleteNote(selectedNoteGUIDs.get(i));
                }
@@ -5347,10 +5492,7 @@ public class NeverNote extends QMainWindow{
                        }
                        if (QMessageBox.question(this, "Confirmation", msg,
                                QMessageBox.StandardButton.Yes, 
-                                       QMessageBox.StandardButton.No)==StandardButton.No.value()) {
-                                       // ICHANGED
-                                               restoreSelectedNoteInfo();
-                                               
+                                       QMessageBox.StandardButton.No)==StandardButton.No.value()) {                                            
                                        return;
                        }
                }
@@ -5368,6 +5510,7 @@ public class NeverNote extends QMainWindow{
                                }
                        }
                }
+                       closeTabs(selectedNoteGUIDs);
                        listManager.expungeNote(selectedNoteGUIDs.get(i));
                        
                        // ICHANGED
@@ -5378,33 +5521,20 @@ public class NeverNote extends QMainWindow{
                }
        }
        currentNoteGuid = "";
-       
-       // ICHANGED ↓↓↓ここから↓↓↓
-               // 削除したノートを外部ウィンドウで開いていたら、閉じる
-               Collection<ExternalBrowse>      windows = externalWindows.values();
-               Iterator<ExternalBrowse>        windowIterator = windows.iterator();
-               Collection<String>                      guids = externalWindows.keySet();
-               Iterator<String>                        guidIterator = guids.iterator();
-               List<ExternalBrowse>            closeWindows = new ArrayList<ExternalBrowse>(); // イテレータ操作中に中身をいじっちゃダメなので
-               
-               while (windowIterator.hasNext()) {
-                       ExternalBrowse browser = windowIterator.next();
-                       String guid = guidIterator.next();
-                       
-                       for (int i = 0; i < selectedNoteGUIDs.size(); i++) {
-                               if (guid.equals(selectedNoteGUIDs.get(i))) {
-                                       closeWindows.add(browser);
-                               }
-                       }
-               }
-               
-               for (int i = closeWindows.size() - 1; i >= 0; i--) {
-                       closeWindows.get(i).close();
+       closeExternalWindows(selectedNoteGUIDs);
+               if (currentNoteGuid == null || currentNoteGuid.equals("")) {
+                       menuBar.noteAddNewTab.setEnabled(false);
                }
-               // ICHANGED ↑↑↑ここまで↑↑↑
                
-       // ICHANGED ↓↓↓ここから↓↓↓
-       // 削除したノートをタブで開いていたら、閉じる
+       listManager.loadNotesIndex();
+       noteIndexUpdated(false);
+       refreshEvernoteNote(true);
+       scrollToGuid(currentNoteGuid);
+       logger.log(logger.HIGH, "Leaving NeverNote.deleteNote");
+    }
+    
+    // 対象ノートをタブで開いていたら閉じる
+    private void closeTabs(List<String> noteGUIDs) {
                Collection<TabBrowse> tabBrowsers = tabWindows.values();
                Iterator<TabBrowse> tabIterator = tabBrowsers.iterator();
                Collection<Integer> tabIndexes = tabWindows.keySet();
@@ -5416,8 +5546,8 @@ public class NeverNote extends QMainWindow{
                        int index = indexIterator.next();
                        String guid = tab.getBrowserWindow().getNote().getGuid();
                        
-                       for(int i = 0; i < selectedNoteGUIDs.size(); i++){
-                               if(guid.equals(selectedNoteGUIDs.get(i))){
+                       for(int i = 0; i < noteGUIDs.size(); i++){
+                               if(guid.equals(noteGUIDs.get(i))){
                                        closeIndexes.add(index);
                                }
                        }
@@ -5426,19 +5556,33 @@ public class NeverNote extends QMainWindow{
                for(int i = closeIndexes.size() - 1; i >= 0; i--){
                        tabWindowClosing(closeIndexes.get(i));
                }
-               // ICHANGED ↑↑↑ここまで↑↑↑              
+    }
+    
+    // 対象ノートを外部ウィンドウで開いていたら閉じる
+    private void closeExternalWindows(List<String> noteGUIDs) {
+               Collection<ExternalBrowse>      windows = externalWindows.values();
+               Iterator<ExternalBrowse>        windowIterator = windows.iterator();
+               Collection<String>                      guids = externalWindows.keySet();
+               Iterator<String>                        guidIterator = guids.iterator();
+               List<ExternalBrowse>            closeWindows = new ArrayList<ExternalBrowse>(); // イテレータ操作中に中身をいじっちゃダメなので
                
-       // ICHANGED
-       restoreSelectedNoteInfo();
-       
-       listManager.loadNotesIndex();
-       noteIndexUpdated(false);
-       refreshEvernoteNote(true);
-       scrollToGuid(currentNoteGuid);
-       logger.log(logger.HIGH, "Leaving NeverNote.deleteNote");
+               while (windowIterator.hasNext()) {
+                       ExternalBrowse browser = windowIterator.next();
+                       String guid = guidIterator.next();
+                       
+                       for (int i = 0; i < noteGUIDs.size(); i++) {
+                               if (guid.equals(noteGUIDs.get(i))) {
+                                       closeWindows.add(browser);
+                               }
+                       }
+               }
+               
+               for (int i = closeWindows.size() - 1; i >= 0; i--) {
+                       closeWindows.get(i).close();
+               }
     }
+    
     // Add a new note
-    // ICHANGED @SuppressWarnings("unused") を削除
        private void addNote() {
        logger.log(logger.HIGH, "Inside NeverNote.addNote");
 //     browserWindow.setEnabled(true);
@@ -5548,12 +5692,6 @@ public class NeverNote extends QMainWindow{
        // IFIXED こいつのせいで、ノート追加時にcurrentNoteGuidが更新されないので消す
        // noteTableView.clearSelection();
        
-       refreshEvernoteNote(true);
-       listManager.countNotebookResults(listManager.getNoteIndex());
-       browserWindow.titleLabel.setFocus();
-       browserWindow.titleLabel.selectAll();
-//     notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
-       
        // ICHANGED 新規に作成したノートとそれまで開いていたノートの関連性を追加
        if (prevCurrentNoteGuid != null && !prevCurrentNoteGuid.equals("")) {
                if (currentNoteGuid != null && !currentNoteGuid.equals("")) {
@@ -5561,6 +5699,12 @@ public class NeverNote extends QMainWindow{
                }
        }
        
+       refreshEvernoteNote(true);
+       listManager.countNotebookResults(listManager.getNoteIndex());
+       browserWindow.titleLabel.setFocus();
+       browserWindow.titleLabel.selectAll();
+//     notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
+       
        // If the window is hidden, then we want to popup this in an external window & 
        if (!isVisible())
                listDoubleClick();
@@ -5643,7 +5787,9 @@ public class NeverNote extends QMainWindow{
                // ICHANGED
                for(int i = 0; i < tabBrowser.count(); i++){
                        TabBrowse b = (TabBrowse)tabBrowser.widget(i);
-                       b.getBrowserWindow().getNote().setGuid(newGuid);
+                       if (b.getBrowserWindow().getNote().getGuid().equals(oldGuid)) {
+                               b.getBrowserWindow().getNote().setGuid(newGuid);
+                       }
                }
 
        for (int i=0; i<listManager.getNoteIndex().size(); i++) {
@@ -6079,6 +6225,9 @@ public class NeverNote extends QMainWindow{
                        setMessage("EDAMUserException: " +e.getMessage());
                        return;
                } catch (EDAMSystemException e) {
+                       if (e.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
+                               QMessageBox.warning(this, tr("Rate limit reached"), tr("Rate limit reached.\nRetry your request in " + e.getRateLimitDuration() + " seconds."));
+                       }
                        setMessage("EDAMSystemException: " +e.getMessage());
                        return;
                } catch (EDAMNotFoundException e) {
@@ -6139,6 +6288,9 @@ public class NeverNote extends QMainWindow{
                                waitCursor(false);
                                return null;
                        } catch (EDAMSystemException e) {
+                               if (e.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
+                                       QMessageBox.warning(this, tr("Rate limit reached"), tr("Rate limit reached.\nRetry your request in " + e.getRateLimitDuration() + " seconds."));
+                               }
                                setMessage("EDAMSystemException: " +e.getMessage());
                                waitCursor(false);
                                return null;
@@ -6203,6 +6355,9 @@ public class NeverNote extends QMainWindow{
                        setMessage("EDAMUserException: " +e.getMessage());
                        return;
                } catch (EDAMSystemException e) {
+                       if (e.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
+                               QMessageBox.warning(this, tr("Rate limit reached"), tr("Rate limit reached.\nRetry your request in " + e.getRateLimitDuration() + " seconds."));
+                       }
                        setMessage("EDAMSystemException: " +e.getMessage());
                        return;
                } catch (TException e) {
@@ -6328,8 +6483,12 @@ public class NeverNote extends QMainWindow{
        //**********************************************************
        //**********************************************************
        // An error has happended fetching a resource.  let the user know
-       private void resourceErrorMessage() {
-               if (inkNote)
+    // ICHANGED
+       private void resourceErrorMessage(int tabIndex) {
+               if (tabIndex < 0) {
+                       return;
+               }
+               if (inkNote.get(tabIndex))
                        return;
                waitCursor(false);
                QMessageBox.information(this, tr("DOUGH!!!"), tr("Well, this is embarrassing."+
@@ -6342,7 +6501,7 @@ public class NeverNote extends QMainWindow{
                "Don't get angry.  I'm doing it to prevent you from messing up\n"+
                "this note on the Evernote servers.  Sorry."+
                "\n\nP.S. You might want to re-synchronize to see if it corrects this problem.\nWho knows, you might get lucky."));
-               inkNote = true;
+               inkNote.put(tabIndex, true);
                browserWindow.setReadOnly(true);
                waitCursor(true);
        }
@@ -6448,7 +6607,23 @@ public class NeverNote extends QMainWindow{
        public void refreshLists() {
                logger.log(logger.EXTREME, "Entering NeverNote.refreshLists");
                updateQuotaBar();
-               listManager.refreshLists(currentNote, noteDirty, browserWindow.getContent());
+               // ICHANGED
+               // すべてのタブのノートを調べて、Dirtyならばセーブする。その後refreshListsする。
+               Collection<Integer> tabIndex = noteDirty.keySet();
+               Iterator<Integer> indexIterator = tabIndex.iterator();
+               HashMap<Integer, Note> saveNotes = new HashMap<Integer, Note>();
+               HashMap<Integer, String> saveContents = new HashMap<Integer, String>();
+               for (boolean isNoteDirty: noteDirty.values()) {
+                       int index = indexIterator.next();
+                       if (isNoteDirty) {
+                               saveNotes.put(index, tabWindows.get(index).getBrowserWindow().getNote());
+                               saveContents.put(index, tabWindows.get(index).getBrowserWindow().getContent());
+                       }
+               }
+               
+               listManager.saveUpdatedNotes(saveNotes, saveContents);
+               listManager.refreshLists();
+
                tagIndexUpdated(true);
                notebookIndexUpdated();
                savedSearchIndexUpdated();
@@ -6599,7 +6774,15 @@ public class NeverNote extends QMainWindow{
                } else
                        indexThreadDeadCount=0;
 
-               
+               if (!rensoNoteListDock.getRensoNoteList().getEnRelatedNotesThread().isAlive()) {
+                       enRelatedNotesThreadDeadCount++;
+                       if (enRelatedNotesThreadDeadCount > MAX && !disableENRelatedNotesThreadCheck) {
+                               QMessageBox.information(this, tr("A thread has died."), tr("It appears as the Evernote Related Notes thread has died.  I recommend "+
+                                       "checking stopping NeighborNote, saving the logs for later viewing, and restarting.  Sorry."));
+                               disableENRelatedNotesThreadCheck = true;
+                       }
+               } else
+                       enRelatedNotesThreadDeadCount=0;
        }
 
        private void thumbnailTimer() {
@@ -7407,7 +7590,7 @@ public class NeverNote extends QMainWindow{
                refreshEvernoteNote(true);
 
                // 連想ノートリストを更新
-               rensoNoteList.refreshRensoNoteList(currentNoteGuid);
+               rensoNoteListDock.getRensoNoteList().refreshRensoNoteList(currentNoteGuid);
        }
        
        // ICHANGD
@@ -7425,6 +7608,10 @@ public class NeverNote extends QMainWindow{
        // toggle the add buttons
        newButton.setEnabled(!newButton.isEnabled());
        menuBar.noteAdd.setEnabled(newButton.isEnabled());
+       menuBar.noteAddNewTab.setEnabled(newButton.isEnabled());
+               if (currentNoteGuid == null || currentNoteGuid.equals("")) {
+                       menuBar.noteAddNewTab.setEnabled(false);
+               }
        menuBar.noteAdd.setVisible(true);
        
        if (!toDeleted) {       // 生存ノートテーブルへ
@@ -7463,10 +7650,10 @@ public class NeverNote extends QMainWindow{
        private void rensoNoteItemPressed(QListWidgetItem current) {
                logger.log(logger.HIGH, "Nevernote.rensoNoteSelectionChangeに入った");
 
-               rensoNotePressedItemGuid = null;
-               // 右クリックだったときの処理
+               rensoNotePressedItemGuid = rensoNoteListDock.getRensoNoteList().getNoteGuid(current);
+               
+               // 右クリックだったら終了
                if (QApplication.mouseButtons().isSet(MouseButton.RightButton)) {
-                       rensoNotePressedItemGuid = rensoNoteList.getNoteGuid(current);
                        return;
                }
                
@@ -7474,82 +7661,27 @@ public class NeverNote extends QMainWindow{
 
                String prevCurrentNoteGuid = new String(currentNoteGuid);
                
-               // 選択されたノート(current)のguidをcurrentnoteguidにセット
-               currentNoteGuid = rensoNoteList.getNoteGuid(current);
-
-               // 選択ノートを更新
-               selectedNoteGUIDs.clear();
-               selectedNoteGUIDs.add(currentNoteGuid);
-
-               nextButton.setEnabled(true);
-               prevButton.setEnabled(true);
-
-               int currentIndex = tabBrowser.currentIndex();
-               ArrayList<String> histGuids = historyGuids.get(currentIndex);
-               int histPosition = historyPosition.get(currentIndex);
-               boolean fromHist = fromHistory.get(currentIndex);
-
-               int endPosition = histGuids.size() - 1;
-               for (int j = histPosition; j <= endPosition; j++) {
-                       histGuids.remove(histGuids.size() - 1);
+               for (int i = 0; i < noteTableView.model().rowCount(); i++) {
+                       QModelIndex modelIndex = noteTableView.model().index(i,
+                                       Global.noteTableGuidPosition);
+                       if (modelIndex != null) {
+                               SortedMap<Integer, Object> ix = noteTableView.model().itemData(
+                                               modelIndex);
+                               String tableGuid = (String) ix.values().toArray()[0];
+                               if (tableGuid.equals(rensoNotePressedItemGuid)) {
+                                       noteTableView.selectRow(i);
+                                       break;
+                               }
+                       }
                }
                
-               histGuids.add(currentNoteGuid);
-               historyPosition.put(currentIndex, histGuids.size());
-               histPosition = histGuids.size();
-
-               if (histPosition <= 1)
-                       prevButton.setEnabled(false);
-               if (histPosition == histGuids.size())
-                       nextButton.setEnabled(false);
-
-               // noteTableViewの選択を変更するとselectionChangedが発生してしまうので一度切断
-               noteTableView.selectionModel().selectionChanged.disconnect(this, "noteTableSelection()");
-               scrollToGuid(currentNoteGuid);
-               // 再接続
-               noteTableView.selectionModel().selectionChanged.connect(this, "noteTableSelection()");
-               
-               refreshEvernoteNote(true); // Evernoteからノートをゲット(そしてブラウザに表示)
-               
-               // upButton, downButton, 選択リストア用のprevRowを設定
-               int row = noteTableView.selectionModel().selectedRows().get(0).row();
-               if (row == 0)
-                       upButton.setEnabled(false);
-               else
-                       upButton.setEnabled(true);
-               if (row < listManager.getNoteTableModel().rowCount() - 1)
-                       downButton.setEnabled(true);
-               else
-                       downButton.setEnabled(false);
-               
                // 連想ノートリストアイテムクリック操作を記録
                conn.getHistoryTable().addHistory("rensoItemClick", prevCurrentNoteGuid, currentNoteGuid);
 
-               // 連想ノートリストを更新
-               rensoNoteList.refreshRensoNoteList(currentNoteGuid);
-
                logger.log(logger.HIGH, "Nevernote.rensoNoteSelectionChangeを出た");
        }
        
        // ICHANGED
-       public void restoreSelectedNoteInfo(){          
-               // 現在のタブからguid取得
-       // currentNoteGuid = browserWindow.getNote().getGuid(); ↓と同じはずだけど敢えて使わない
-               int currentTabIndex = tabBrowser.currentIndex();
-               TabBrowse currentTab = tabWindows.get(currentTabIndex);
-               currentNoteGuid = currentTab.getBrowserWindow().getNote().getGuid();
-               
-               selectedNoteGUIDs.clear();
-               selectedNoteGUIDs.add(currentNoteGuid);
-
-               // noteTableViewの選択を変更するとselectionChangedが発生してしまうので一度切断
-               noteTableView.selectionModel().selectionChanged.disconnect(this, "noteTableSelection()");
-               scrollToGuid(currentNoteGuid);
-               // 再接続
-               noteTableView.selectionModel().selectionChanged.connect(this, "noteTableSelection()");
-       }
-       
-       // ICHANGED
        // 関連ノートリストからノートを除外する
        @SuppressWarnings("unused")
        private void excludeNote() {
@@ -7585,7 +7717,7 @@ public class NeverNote extends QMainWindow{
                // 除外ノートテーブルに追加
                conn.getExcludedTable().addExclusion(guid, currentNoteGuid);
                
-               rensoNoteList.refreshRensoNoteList(currentNoteGuid);
+               rensoNoteListDock.getRensoNoteList().refreshRensoNoteList(currentNoteGuid);
        }
        
        // ICHANGED
@@ -7604,7 +7736,7 @@ public class NeverNote extends QMainWindow{
                // スター付きノートテーブルに追加
                conn.getStaredTable().addStaredItem(currentNoteGuid, guid);
                
-               rensoNoteList.refreshRensoNoteList(currentNoteGuid);
+               rensoNoteListDock.getRensoNoteList().refreshRensoNoteList(currentNoteGuid);
        }
        
        // ICHANGED
@@ -7623,7 +7755,7 @@ public class NeverNote extends QMainWindow{
                // スター付きノートテーブルから削除
                conn.getStaredTable().removeStaredItem(currentNoteGuid, guid);
                
-               rensoNoteList.refreshRensoNoteList(currentNoteGuid);
+               rensoNoteListDock.getRensoNoteList().refreshRensoNoteList(currentNoteGuid);
        }
        
        // ICHANGED
@@ -7631,4 +7763,48 @@ public class NeverNote extends QMainWindow{
        public String getCurrentNoteGuid() {
                return currentNoteGuid;
        }
+       
+       @SuppressWarnings("unused")
+       // タブ入れ替えによってタブインデックスが変わったので、インデックスで管理しているハッシュマップ達も入れ替える
+       private void tabIndexChanged(int from, int to) {
+               // tabWindows
+               TabBrowse tab = tabWindows.get(from);
+               tabWindows.put(from, tabWindows.get(to));
+               tabWindows.put(to, tab);
+               // noteDirty
+               boolean isNoteDirty = noteDirty.get(from);
+               noteDirty.put(from, noteDirty.get(to));
+               noteDirty.put(to, isNoteDirty);
+               // inkNote
+               boolean isInkNote = inkNote.get(from);
+               inkNote.put(from, inkNote.get(to));
+               inkNote.put(to, isInkNote);
+               // readOnly
+               boolean isReadOnly = readOnly.get(from);
+               readOnly.put(from, readOnly.get(to));
+               readOnly.put(to, isReadOnly);
+               // historyGuids
+               ArrayList<String> histGuids = historyGuids.get(from);
+               historyGuids.put(from, historyGuids.get(to));
+               historyGuids.put(to, histGuids);
+               // historyPosition
+               int histPosition = historyPosition.get(from);
+               historyPosition.put(from, historyPosition.get(to));
+               historyPosition.put(to, histPosition);
+               // fromHistory
+               boolean fromHist = fromHistory.get(from);
+               fromHistory.put(from,  fromHistory.get(to));
+               fromHistory.put(to, fromHist);
+       }
+       
+       // 連想ノートリストのgetter
+       public RensoNoteList getRensoNoteList() {
+               return rensoNoteListDock.getRensoNoteList();
+       }
+       
+       // 帯域制限の超過をユーザに通知
+       @SuppressWarnings("unused")
+       private void informRateLimit(Integer rateLimitDuration) {
+               QMessageBox.warning(this, tr("Rate limit reached"), tr("Rate limit reached.\nRetry your request in " + rateLimitDuration + " seconds."));
+       }
 }