OSDN Git Service

9d78b248edcfd8ce97bc3da53ec89bf3c67feddf
[neighbornote/NeighborNote.git] / src / cx / fbn / nevernote / NeverNote.java
1 /*
2   * This file is part of NixNote/NeighborNote 
3  * Copyright 2009 Randy Baumgarte
4  * Copyright 2013 Yuki Takahashi
5  * 
6  * This file may be licensed under the terms of of the
7  * GNU General Public License Version 2 (the ``GPL'').
8  *
9  * Software distributed under the License is distributed
10  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
11  * express or implied. See the GPL for the specific language
12  * governing rights and limitations.
13  *
14  * You should have received a copy of the GPL along with this
15  * program. If not, go to http://www.gnu.org/licenses/gpl.html
16  * or write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  *
19 */
20 package cx.fbn.nevernote;
21 import java.awt.Desktop;
22 import java.io.File;
23 import java.io.FileInputStream;
24 import java.io.FileNotFoundException;
25 import java.io.FileOutputStream;
26 import java.net.Authenticator;
27 import java.net.PasswordAuthentication;
28 import java.security.MessageDigest;
29 import java.security.NoSuchAlgorithmException;
30 import java.sql.Connection;
31 import java.sql.DriverManager;
32 import java.sql.SQLException;
33 import java.sql.Statement;
34 import java.text.SimpleDateFormat;
35 import java.util.ArrayList;
36 import java.util.Calendar;
37 import java.util.Collection;
38 import java.util.Collections;
39 import java.util.Comparator;
40 import java.util.Date;
41 import java.util.GregorianCalendar;
42 import java.util.HashMap;
43 import java.util.Iterator;
44 import java.util.List;
45 import java.util.Map;
46 import java.util.SortedMap;
47 import java.util.Vector;
48
49 import org.apache.log4j.Level;
50 import org.apache.log4j.Logger;
51 import org.h2.tools.ChangeFileEncryption;
52
53 import com.evernote.edam.error.EDAMErrorCode;
54 import com.evernote.edam.error.EDAMNotFoundException;
55 import com.evernote.edam.error.EDAMSystemException;
56 import com.evernote.edam.error.EDAMUserException;
57 import com.evernote.edam.notestore.NoteFilter;
58 import com.evernote.edam.notestore.NoteVersionId;
59 import com.evernote.edam.type.Data;
60 import com.evernote.edam.type.LinkedNotebook;
61 import com.evernote.edam.type.Note;
62 import com.evernote.edam.type.NoteAttributes;
63 import com.evernote.edam.type.Notebook;
64 import com.evernote.edam.type.Publishing;
65 import com.evernote.edam.type.QueryFormat;
66 import com.evernote.edam.type.Resource;
67 import com.evernote.edam.type.SavedSearch;
68 import com.evernote.edam.type.Tag;
69 import com.evernote.edam.type.User;
70 import com.evernote.thrift.TException;
71 import com.trolltech.qt.QThread;
72 import com.trolltech.qt.core.QByteArray;
73 import com.trolltech.qt.core.QDateTime;
74 import com.trolltech.qt.core.QDir;
75 import com.trolltech.qt.core.QEvent;
76 import com.trolltech.qt.core.QFile;
77 import com.trolltech.qt.core.QFileInfo;
78 import com.trolltech.qt.core.QFileSystemWatcher;
79 import com.trolltech.qt.core.QIODevice;
80 import com.trolltech.qt.core.QIODevice.OpenModeFlag;
81 import com.trolltech.qt.core.QLocale;
82 import com.trolltech.qt.core.QMimeData;
83 import com.trolltech.qt.core.QModelIndex;
84 import com.trolltech.qt.core.QSize;
85 import com.trolltech.qt.core.QTemporaryFile;
86 import com.trolltech.qt.core.QTextCodec;
87 import com.trolltech.qt.core.QTextStream;
88 import com.trolltech.qt.core.QThreadPool;
89 import com.trolltech.qt.core.QTimer;
90 import com.trolltech.qt.core.QTranslator;
91 import com.trolltech.qt.core.QUrl;
92 import com.trolltech.qt.core.Qt;
93 import com.trolltech.qt.core.Qt.BGMode;
94 import com.trolltech.qt.core.Qt.DockWidgetArea;
95 import com.trolltech.qt.core.Qt.ItemDataRole;
96 import com.trolltech.qt.core.Qt.KeyboardModifier;
97 import com.trolltech.qt.core.Qt.MouseButton;
98 import com.trolltech.qt.core.Qt.SortOrder;
99 import com.trolltech.qt.core.Qt.WidgetAttribute;
100 import com.trolltech.qt.gui.QAbstractItemView;
101 import com.trolltech.qt.gui.QAbstractItemView.ScrollHint;
102 import com.trolltech.qt.gui.QAction;
103 import com.trolltech.qt.gui.QApplication;
104 import com.trolltech.qt.gui.QClipboard;
105 import com.trolltech.qt.gui.QCloseEvent;
106 import com.trolltech.qt.gui.QColor;
107 import com.trolltech.qt.gui.QCursor;
108 import com.trolltech.qt.gui.QDesktopServices;
109 import com.trolltech.qt.gui.QDialog;
110 import com.trolltech.qt.gui.QFileDialog;
111 import com.trolltech.qt.gui.QFileDialog.AcceptMode;
112 import com.trolltech.qt.gui.QFileDialog.FileMode;
113 import com.trolltech.qt.gui.QGridLayout;
114 import com.trolltech.qt.gui.QHBoxLayout;
115 import com.trolltech.qt.gui.QIcon;
116 import com.trolltech.qt.gui.QImage;
117 import com.trolltech.qt.gui.QKeySequence;
118 import com.trolltech.qt.gui.QListWidgetItem;
119 import com.trolltech.qt.gui.QMainWindow;
120 import com.trolltech.qt.gui.QMenu;
121 import com.trolltech.qt.gui.QMessageBox;
122 import com.trolltech.qt.gui.QMessageBox.StandardButton;
123 import com.trolltech.qt.gui.QPainter;
124 import com.trolltech.qt.gui.QPalette.ColorRole;
125 import com.trolltech.qt.gui.QPixmap;
126 import com.trolltech.qt.gui.QPrintDialog;
127 import com.trolltech.qt.gui.QPrinter;
128 import com.trolltech.qt.gui.QShortcut;
129 import com.trolltech.qt.gui.QSizePolicy;
130 import com.trolltech.qt.gui.QSpinBox;
131 import com.trolltech.qt.gui.QSplashScreen;
132 import com.trolltech.qt.gui.QSplitter;
133 import com.trolltech.qt.gui.QStatusBar;
134 import com.trolltech.qt.gui.QSystemTrayIcon;
135 import com.trolltech.qt.gui.QTableWidgetItem;
136 import com.trolltech.qt.gui.QTextEdit;
137 import com.trolltech.qt.gui.QToolBar;
138 import com.trolltech.qt.gui.QTreeWidgetItem;
139 import com.trolltech.qt.gui.QWidget;
140 import com.trolltech.qt.network.QNetworkAccessManager;
141 import com.trolltech.qt.network.QNetworkProxy;
142 import com.trolltech.qt.network.QNetworkProxy.ProxyType;
143 import com.trolltech.qt.network.QNetworkReply;
144 import com.trolltech.qt.network.QNetworkRequest;
145 import com.trolltech.qt.webkit.QWebPage.WebAction;
146 import com.trolltech.qt.webkit.QWebSettings;
147
148 import cx.fbn.nevernote.clipboard.ClipBoardObserver;
149 import cx.fbn.nevernote.config.InitializationException;
150 import cx.fbn.nevernote.config.StartupConfig;
151 import cx.fbn.nevernote.dialog.AccountDialog;
152 import cx.fbn.nevernote.dialog.ConfigDialog;
153 import cx.fbn.nevernote.dialog.DBEncryptDialog;
154 import cx.fbn.nevernote.dialog.DatabaseLoginDialog;
155 import cx.fbn.nevernote.dialog.DatabaseStatus;
156 import cx.fbn.nevernote.dialog.FindDialog;
157 import cx.fbn.nevernote.dialog.IgnoreSync;
158 import cx.fbn.nevernote.dialog.LogFileDialog;
159 import cx.fbn.nevernote.dialog.NotebookArchive;
160 import cx.fbn.nevernote.dialog.NotebookEdit;
161 import cx.fbn.nevernote.dialog.OnlineNoteHistory;
162 import cx.fbn.nevernote.dialog.PublishNotebook;
163 import cx.fbn.nevernote.dialog.SavedSearchEdit;
164 import cx.fbn.nevernote.dialog.SetIcon;
165 import cx.fbn.nevernote.dialog.ShareNotebook;
166 import cx.fbn.nevernote.dialog.SharedNotebookSyncError;
167 import cx.fbn.nevernote.dialog.StackNotebook;
168 import cx.fbn.nevernote.dialog.SynchronizationRequiredWarning;
169 import cx.fbn.nevernote.dialog.TagEdit;
170 import cx.fbn.nevernote.dialog.TagMerge;
171 import cx.fbn.nevernote.dialog.ThumbnailViewer;
172 import cx.fbn.nevernote.dialog.UpgradeAvailableDialog;
173 import cx.fbn.nevernote.dialog.WatchFolder;
174 import cx.fbn.nevernote.evernote.NoteMetadata;
175 import cx.fbn.nevernote.filters.FilterEditorNotebooks;
176 import cx.fbn.nevernote.filters.FilterEditorTags;
177 import cx.fbn.nevernote.gui.AttributeTreeWidget;
178 import cx.fbn.nevernote.gui.BrowserWindow;
179 import cx.fbn.nevernote.gui.DateAttributeFilterTable;
180 import cx.fbn.nevernote.gui.ExternalBrowse;
181 import cx.fbn.nevernote.gui.MainMenuBar;
182 import cx.fbn.nevernote.gui.NotebookTreeWidget;
183 import cx.fbn.nevernote.gui.RensoNoteList;
184 import cx.fbn.nevernote.gui.RensoNoteListDock;
185 import cx.fbn.nevernote.gui.SavedSearchTreeWidget;
186 import cx.fbn.nevernote.gui.SearchEdit;
187 import cx.fbn.nevernote.gui.TabBrowse;
188 import cx.fbn.nevernote.gui.TabBrowserWidget;
189 import cx.fbn.nevernote.gui.TableView;
190 import cx.fbn.nevernote.gui.TagTreeWidget;
191 import cx.fbn.nevernote.gui.Thumbnailer;
192 import cx.fbn.nevernote.gui.TrashTreeWidget;
193 import cx.fbn.nevernote.gui.ZoomPanel;
194 import cx.fbn.nevernote.gui.controls.QuotaProgressBar;
195 import cx.fbn.nevernote.oauth.OAuthTokenizer;
196 import cx.fbn.nevernote.oauth.OAuthWindow;
197 import cx.fbn.nevernote.sql.DatabaseConnection;
198 import cx.fbn.nevernote.sql.WatchFolderRecord;
199 import cx.fbn.nevernote.threads.IndexRunner;
200 import cx.fbn.nevernote.threads.SyncRunner;
201 import cx.fbn.nevernote.threads.ThumbnailRunner;
202 import cx.fbn.nevernote.utilities.AESEncrypter;
203 import cx.fbn.nevernote.utilities.ApplicationLogger;
204 import cx.fbn.nevernote.utilities.FileImporter;
205 import cx.fbn.nevernote.utilities.FileUtils;
206 import cx.fbn.nevernote.utilities.ListManager;
207 import cx.fbn.nevernote.utilities.SyncTimes;
208 import cx.fbn.nevernote.xml.ExportData;
209 import cx.fbn.nevernote.xml.ImportData;
210 import cx.fbn.nevernote.xml.ImportEnex;
211 import cx.fbn.nevernote.xml.NoteFormatter;
212
213
214 public class NeverNote extends QMainWindow{
215         
216         QStatusBar                              statusBar;                                      // Application status bar
217         
218         DatabaseConnection              conn;
219         
220         MainMenuBar                             menuBar;                                        // Main menu bar
221         FindDialog                              find;                                           // Text search in note dialog
222         List<String>                    emitLog;                                        // Messages displayed in the status bar;
223         QSystemTrayIcon                 trayIcon;                                       // little tray icon
224         QMenu                                   trayMenu;                                       // System tray menu
225         QAction                                 trayExitAction;                         // Exit the application
226         QAction                                 trayShowAction;                         // toggle the show/hide action          
227         QAction                                 trayAddNoteAction;                      // Add a note from the system tray
228         QNetworkAccessManager   versionChecker;                         // Used when checking for new versions
229         
230     NotebookTreeWidget          notebookTree;                           // List of notebooks
231     AttributeTreeWidget         attributeTree;                          // List of note attributes
232     TagTreeWidget                       tagTree;                                        // list of user created tags
233     SavedSearchTreeWidget       savedSearchTree;                        // list of saved searches
234     TrashTreeWidget                     trashTree;                                      // Trashcan
235     TableView                           noteTableView;                          //      List of notes (the widget).
236
237     public BrowserWindow        browserWindow;                          // Window containing browser & labels
238     public QToolBar             toolBar;                                        // The tool bar under the menu
239     SearchEdit                          searchField;                            // search filter bar on the toolbar;
240     QShortcut                           searchShortcut;                         // Shortcut to search bar
241     boolean                                     searchPerformed = false;        // Search was done?
242     QuotaProgressBar            quotaBar;                                       // The current quota usage
243     
244     ApplicationLogger           logger;
245     List<String>                        selectedNotebookGUIDs;          // List of notebook GUIDs
246     List<String>                        selectedTagGUIDs;                       // List of selected tag GUIDs
247     List<String>                        selectedNoteGUIDs;                      // List of selected notes
248     String                                      selectedSavedSearchGUID;        // Currently selected saved searches
249     private final HashMap<String, ExternalBrowse>       externalWindows;        // Notes being edited by an external window;
250     
251     NoteFilter                          filter;                                         // Note filter
252     String                                      currentNoteGuid;                        // GUID of the current note 
253     Note                                        currentNote;                            // The currently viewed note
254     HashMap<Integer, Boolean>   noteDirty;                              // Has the note been changed?
255     HashMap<Integer, Boolean>   inkNote;                // if this is an ink note, it is read only
256     HashMap<Integer, Boolean>   readOnly;                               // Is this note read-only?
257         
258   
259     ListManager                         listManager;                                    // DB runnable task
260     
261     List<QTemporaryFile>        tempFiles;                                      // Array of temporary files;
262     
263     QTimer                                      indexTimer;                                     // timer to start the index thread
264     IndexRunner                         indexRunner;                            // thread to index notes
265     QThread                                     indexThread;
266     
267     QTimer                                      syncTimer;                                      // Sync on an interval
268     QTimer                                      syncDelayTimer;                         // Sync delay to free up database
269     SyncRunner                          syncRunner;                                     // thread to do a sync.
270     QThread                                     syncThread;                                     // Thread which talks to evernote
271     ThumbnailRunner                     thumbnailRunner;                        // Runner for thumbnail thread
272     QThread                                     thumbnailThread;                        // Thread that generates pretty pictures
273     QTimer                                      saveTimer;                                      // Timer to save note contents
274     
275     QTimer                                      authTimer;                                      // Refresh authentication
276     QTimer                                      externalFileSaveTimer;          // Save files altered externally
277     QTimer                                      thumbnailTimer;                         // Wakeup & scan for thumbnails
278     QTimer                                      debugTimer;
279     List<String>                        externalFiles;                          // External files to save later
280     List<String>                        importFilesKeep;                        // Auto-import files to save later
281     List<String>                        importFilesDelete;                      // Auto-import files to save later
282     
283     int                                         indexTime;                                      // how often to try and index
284     boolean                                     indexRunning;                           // Is indexing running?
285     boolean                                     indexDisabled;                          // Is indexing disabled?
286     
287     int                                         syncThreadsReady;                       // number of sync threads that are free
288     int                                         syncTime;                                       // Sync interval
289     boolean                                     syncRunning;                            // Is sync running?
290     boolean                                     automaticSync;                          // do sync automatically?
291     QTreeWidgetItem                     attributeTreeSelected;
292
293     QAction                             prevButton;                                     // Go to the previous item viewed
294     QAction                             nextButton;                                     // Go to the next item in the history
295     QAction                             downButton;                                     // Go to the next item in the list
296     QAction                             upButton;                                       // Go to the prev. item in the list;
297     QAction                             synchronizeButton;                      // Synchronize with Evernote
298     QAction                             allNotesButton;                         // Reset & view all notes
299     QTimer                              synchronizeAnimationTimer;      // Timer to change animation button
300     int                                 synchronizeIconAngle;           // Used to rotate sync icon
301     QAction                     printButton;                            // Print Button
302     QAction                             tagButton;                                      // Tag edit button
303     QAction                             attributeButton;                        // Attribute information button
304     QAction                     emailButton;                            // Email button
305     QAction                     deleteButton;                           // Delete button
306     QAction                             newButton;                                      // new Note Button;
307     QSpinBox                    zoomSpinner;                            // Zoom zoom
308     QAction                             searchClearButton;                      // Clear the search field
309     
310     ZoomPanel                   zoomLayout;                                     // Widget to hold search field, zoom, & quota
311     
312     QSplitter                   mainLeftRightSplitter;          // main splitter for left/right side
313     QSplitter                   leftSplitter1;                          // first left hand splitter
314     QSplitter                   browserIndexSplitter;           // splitter between note index & note text
315     
316     QFileSystemWatcher  importKeepWatcher;                      // Watch & keep auto-import
317     QFileSystemWatcher  importDeleteWatcher;            // Watch & Delete auto-import
318     List<String>                importedFiles;                          // History of imported files (so we don't import twice)
319     
320     OnlineNoteHistory   historyWindow;                          // online history window 
321     List<NoteVersionId> versions;                                       // history versions
322     
323     QTimer                              threadMonitorTimer;                     // Timer to watch threads.
324     int                                 dbThreadDeadCount=0;            // number of consecutive dead times for the db thread
325     int                                 syncThreadDeadCount=0;          // number of consecutive dead times for the sync thread
326     int                                 indexThreadDeadCount=0;         // number of consecutive dead times for the index thread
327     int                                 notebookThreadDeadCount=0;      // number of consecutive dead times for the notebook thread
328     int                                 tagDeadCount=0;                         // number of consecutive dead times for the tag thread
329     int                                 trashDeadCount=0;                       // number of consecutive dead times for the trash thread
330     int                                 saveThreadDeadCount=0;          // number of consecutive dead times for the save thread
331     int                                 enRelatedNotesThreadDeadCount=0;        // number of consecutive dead times for the EvernoteRelatedNotes Thread
332     boolean                             disableTagThreadCheck=false;
333     boolean                             disableNotebookThreadCheck=false;
334     boolean                             disableTrashThreadCheck=false;
335     boolean                             disableSaveThreadCheck=false;
336     boolean                             disableSyncThreadCheck=false;
337     boolean                             disableIndexThreadCheck=false;
338     boolean                             disableENRelatedNotesThreadCheck=false;
339     
340     HashMap<String, String>             noteCache;                      // Cash of note content 
341     HashMap<String, Boolean>    readOnlyCache;          // List of cashe notes that are read-only
342     HashMap<String, Boolean>    inkNoteCache;           // List of cache notes that are ink notes 
343         HashMap<Integer, ArrayList<String>> historyGuids;  // タブごとの以前見たノートのGUID
344         HashMap<Integer, Integer> historyPosition; // Position within the viewed items
345         HashMap<Integer, Boolean> fromHistory; // Is this from the history queue?
346         
347     String                              trashNoteGuid;                          // Guid to restore / set into or out of trash to save position
348     List<Thumbnailer>   thumbGenerators;                                // generate preview image
349     ThumbnailViewer             thumbnailViewer;                        // View preview thumbnail; 
350     boolean                             encryptOnShutdown;                      // should I encrypt when I close?
351     boolean                             decryptOnShutdown;                      // should I decrypt on shutdown;
352     String                              encryptCipher;                          // What cipher should I use?
353     //Signal0                   minimizeToTray;
354     boolean                             windowMaximized = false;        // Keep track of the window state for restores
355     List<String>                pdfReadyQueue;                          // Queue of PDFs that are ready to be rendered.
356     List<QPixmap>               syncIcons;                                      // Array of icons used in sync animation
357     private boolean             closeAction = false;            // Used to say when to close or when to minimize
358     private static Logger log = Logger.getLogger(NeverNote.class); 
359     private String              saveLastPath;                           // last path we used
360     private final QTimer                messageTimer;                           // Timer to clear the status message.
361     private QTimer              blockTimer;
362     BrowserWindow               blockingWindow;
363     
364         private final TabBrowserWidget tabBrowser;                              // ブラウザウィンドウをタブ化
365         private final HashMap<Integer, TabBrowse> tabWindows;   // タブウィンドウ
366         private final RensoNoteListDock rensoNoteListDock;              // 連想ノートリストドックウィジェット
367         ClipBoardObserver cbObserver;
368         String rensoNotePressedItemGuid;
369         
370     String iconPath = new String("classpath:cx/fbn/nevernote/icons/");
371         
372         
373     //***************************************************************
374     //***************************************************************
375     //** Constructor & main entry point
376     //***************************************************************
377     //***************************************************************
378     // Application Constructor  
379         @SuppressWarnings("static-access")
380         public NeverNote(DatabaseConnection dbConn)  {
381                 cbObserver = new ClipBoardObserver();
382                 
383                 conn = dbConn;          
384                 if (conn.getConnection() == null) {
385                         String msg = new String(tr("Unable to connect to the database.\n\nThe most probable reason is that some other process\n" +
386                                 "is accessing the database or NeighborNote is already running.\n\n" +
387                                 "Please end any other process or shutdown the other NeighborNote before starting.\n\nExiting program."));
388                         
389             QMessageBox.critical(null, tr("Database Connection Error") ,msg);
390                         System.exit(16);
391                 }
392                 setObjectName("mainWindow");
393 //              thread().setPriority(Thread.MAX_PRIORITY);
394                 
395                 logger = new ApplicationLogger("nevernote.log");
396                 logger.log(logger.HIGH, "Starting Application");
397                 
398                 decryptOnShutdown = false;
399                 encryptOnShutdown = false;
400                 conn.checkDatabaseVersion();
401                 
402                 
403                 
404                 // Start building the invalid XML tables
405                 Global.invalidElements = conn.getInvalidXMLTable().getInvalidElements();
406                 List<String> elements = conn.getInvalidXMLTable().getInvalidAttributeElements();
407                 
408                 for (int i=0; i<elements.size(); i++) {
409                         Global.invalidAttributes.put(elements.get(i), conn.getInvalidXMLTable().getInvalidAttributes(elements.get(i)));
410                 }
411                 
412                 logger.log(logger.EXTREME, "Starting GUI build");
413
414                 QTranslator nevernoteTranslator = new QTranslator();
415                 nevernoteTranslator.load(Global.getFileManager().getTranslateFilePath("neighbornote_" + QLocale.system().name() + ".qm"));
416                 QApplication.instance().installTranslator(nevernoteTranslator);
417
418                 Global.originalPalette = QApplication.palette();
419                 QApplication.setStyle(Global.getStyle());
420                 if (Global.useStandardPalette())
421                         QApplication.setPalette(QApplication.style().standardPalette());
422         setWindowTitle(tr("NeighborNote"));
423
424         mainLeftRightSplitter = new QSplitter();
425                 mainLeftRightSplitter.setOrientation(Qt.Orientation.Horizontal);
426                 
427         setCentralWidget(mainLeftRightSplitter);
428         leftSplitter1 = new QSplitter();
429         leftSplitter1.setOrientation(Qt.Orientation.Vertical);
430                 
431         browserIndexSplitter = new QSplitter();
432         browserIndexSplitter.setOrientation(Qt.Orientation.Vertical);
433         
434         //* Setup threads & thread timers
435 //        int indexRunnerCount = Global.getIndexThreads();
436 //       indexRunnerCount = 1;
437         QThreadPool.globalInstance().setMaxThreadCount(Global.threadCount);     // increase max thread count
438
439                 logger.log(logger.EXTREME, "Building list manager");
440         listManager = new ListManager(conn, logger);
441         
442                 logger.log(logger.EXTREME, "Building index runners & timers");
443                 indexRunner = new IndexRunner("indexRunner.log",
444                                 Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(),
445                                 Global.getResourceDatabaseUrl(),
446                                 Global.getBehaviorDatabaseUrl(), Global.getDatabaseUserid(),
447                                 Global.getDatabaseUserPassword(), Global.cipherPassword);
448                 
449                 indexThread = new QThread(indexRunner, "Index Thread");
450         indexRunner.indexAttachmentsLocally = Global.indexAttachmentsLocally();
451         indexRunner.indexImageRecognition = Global.indexImageRecognition();
452 //        indexRunner.indexNoteBody = Global.indexNoteBody();
453 //        indexRunner.indexNoteTitle = Global.indexNoteTitle();
454 //        indexRunner.specialIndexCharacters = Global.getSpecialIndexCharacters();
455                 indexThread.start();
456                 
457         synchronizeAnimationTimer = new QTimer();
458         synchronizeAnimationTimer.timeout.connect(this, "updateSyncButton()");
459         
460                 indexTimer = new QTimer();
461                 indexTime = 1000*Global.getIndexThreadSleepInterval();  
462                 indexTimer.start(indexTime);  // Start indexing timer
463                 indexTimer.timeout.connect(this, "indexTimer()");
464                 indexDisabled = false;
465                 indexRunning = false;
466                                 
467                 logger.log(logger.EXTREME, "Setting sync thread & timers");
468                 syncThreadsReady=1;
469                 syncRunner = new SyncRunner("syncRunner.log", Global.getDatabaseUrl(),
470                                 Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(),
471                                 Global.getBehaviorDatabaseUrl(), Global.getDatabaseUserid(),
472                                 Global.getDatabaseUserPassword(), Global.cipherPassword);
473                 
474                 syncTime = new SyncTimes().timeValue(Global.getSyncInterval());
475                 syncTimer = new QTimer();
476                 syncTimer.timeout.connect(this, "syncTimer()");
477         syncRunner.status.message.connect(this, "setMessage(String)");
478         syncRunner.syncSignal.finished.connect(this, "syncThreadComplete(Boolean)");
479         syncRunner.syncSignal.errorDisconnect.connect(this, "remoteErrorDisconnect()");
480         syncRunner.limitSignal.rateLimitReached.connect(this, "informRateLimit(Integer)");
481         syncRunning = false;    
482                 if (syncTime > 0) {
483                         automaticSync = true;
484                         syncTimer.start(syncTime*60*1000);
485                 } else {
486                         automaticSync = false;
487                         syncTimer.stop();
488                 }
489                 syncRunner.setEvernoteUpdateCount(Global.getEvernoteUpdateCount());
490                 syncThread = new QThread(syncRunner, "Synchronization Thread");
491                 syncThread.start();
492                 
493                 
494                 logger.log(logger.EXTREME, "Starting thumnail thread");
495                 pdfReadyQueue = new ArrayList<String>();
496                 thumbnailRunner = new ThumbnailRunner("thumbnailRunner.log",
497                                 Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(),
498                                 Global.getResourceDatabaseUrl(),
499                                 Global.getBehaviorDatabaseUrl(), Global.getDatabaseUserid(),
500                                 Global.getDatabaseUserPassword(), Global.cipherPassword);
501                 
502                 thumbnailThread = new QThread(thumbnailRunner, "Thumbnail Thread");
503                 thumbnailRunner.noteSignal.thumbnailPageReady.connect(this, "thumbnailHTMLReady(String,QByteArray,Integer)");
504                 thumbnailThread.start();
505                 thumbGenerators = new ArrayList<Thumbnailer>();
506                 thumbnailTimer = new QTimer();
507                 thumbnailTimer.timeout.connect(this, "thumbnailTimer()");
508                 thumbnailTimer();
509                 thumbnailTimer.setInterval(500*1000);  // Thumbnail every minute
510                 thumbnailTimer.start();
511                 
512 //              debugTimer = new QTimer();
513 //              debugTimer.timeout.connect(this, "debugDirty()");
514 //              debugTimer.start(1000*60);
515                 
516                 logger.log(logger.EXTREME, "Starting authentication timer");
517                 authTimer = new QTimer();
518                 authTimer.timeout.connect(this, "authTimer()");
519                 authTimer.start(1000*60*15);
520                 syncRunner.syncSignal.authRefreshComplete.connect(this, "authRefreshComplete(boolean)");
521                 
522                 logger.log(logger.EXTREME, "Setting save note timer");
523                 saveTimer = new QTimer();
524                 saveTimer.timeout.connect(this, "saveNote()");
525                 if (Global.getAutoSaveInterval() > 0) {
526                         saveTimer.setInterval(1000*60*Global.getAutoSaveInterval()); 
527                         saveTimer.start();
528                 }
529                 listManager.saveRunner.noteSignals.noteSaveRunnerError.connect(this, "saveRunnerError(String, String)");
530                 
531                 logger.log(logger.EXTREME, "Starting external file monitor timer");
532                 externalFileSaveTimer = new QTimer();
533                 externalFileSaveTimer.timeout.connect(this, "externalFileEditedSaver()");
534                 externalFileSaveTimer.setInterval(1000*5);   // save every 5 seconds;
535                 externalFiles = new ArrayList<String>();
536                 importFilesDelete = new ArrayList<String>();
537                 importFilesKeep = new ArrayList<String>();
538                 externalFileSaveTimer.start();
539                 
540         notebookTree = new NotebookTreeWidget(conn);
541         attributeTree = new AttributeTreeWidget();
542         tagTree = new TagTreeWidget(conn);
543         savedSearchTree = new SavedSearchTreeWidget();
544         trashTree = new TrashTreeWidget();
545                 noteTableView = new TableView(logger, listManager, this);     
546         
547         quotaBar = new QuotaProgressBar();
548         // Setup the zoom
549         zoomSpinner = new QSpinBox();
550         zoomSpinner.setMinimum(10);
551         zoomSpinner.setMaximum(1000);
552         zoomSpinner.setAccelerated(true);
553         zoomSpinner.setSingleStep(10);
554         zoomSpinner.setValue(100);
555         zoomSpinner.valueChanged.connect(this, "zoomChanged()");
556         
557         zoomLayout = new ZoomPanel(quotaBar, notebookTree, zoomSpinner);
558         
559         
560         QGridLayout leftGrid = new QGridLayout();
561         leftSplitter1.setContentsMargins(5, 0, 0, 7);
562         leftSplitter1.setLayout(leftGrid);
563         leftGrid.addWidget(zoomLayout,1,1);
564         leftGrid.addWidget(tagTree,2,1);
565         leftGrid.addWidget(attributeTree,3,1);
566         leftGrid.addWidget(savedSearchTree,4,1);
567         leftGrid.addWidget(trashTree,5, 1);
568         
569         // Setup the browser window
570         noteCache = new HashMap<String,String>();
571         readOnlyCache = new HashMap<String, Boolean>();
572         inkNoteCache = new HashMap<String, Boolean>();
573         browserWindow = new BrowserWindow(conn, cbObserver);
574
575                 // 下から移動してきた。
576                 historyGuids = new HashMap<Integer, ArrayList<String>>();
577                 historyPosition = new HashMap<Integer, Integer>();
578                 fromHistory = new HashMap<Integer, Boolean>();
579                 
580                 // タブブラウザ作成
581                 tabWindows = new HashMap<Integer, TabBrowse>();
582                 tabBrowser = new TabBrowserWidget(this);
583                 tabBrowser.setStyleSheet("QTabBar::tab{width:150px;}");
584                 tabBrowser.setMovable(true);
585                 tabBrowser.setTabsClosable(true);
586                 TabBrowse tab = new TabBrowse(conn, tabBrowser, cbObserver);
587                 browserWindow = tab.getBrowserWindow();
588                 int index = tabBrowser.addNewTab(tab, "");
589                 tabWindows.put(index, tab);
590                 tabBrowser.currentChanged.connect(this, "tabWindowChanged(int)");
591                 tabBrowser.tabCloseRequested.connect(this, "tabCloseRequested(int)");
592                 
593                 noteDirty = new HashMap<Integer, Boolean>();
594                 noteDirty.put(index, false);
595                 
596                 inkNote = new HashMap<Integer, Boolean>();
597                 readOnly = new HashMap<Integer, Boolean>();
598
599                 // 履歴記録のハッシュマップを初期化
600                 historyGuids.put(index, new ArrayList<String>());
601                 historyPosition.put(index, 0);
602                 fromHistory.put(index, false);
603                 
604         mainLeftRightSplitter.addWidget(leftSplitter1);
605         mainLeftRightSplitter.addWidget(browserIndexSplitter);
606         
607                 // 連想ノートリストをセットアップ
608         rensoNoteListDock = new RensoNoteListDock(conn, this, syncRunner, iconPath, tr("Renso Note List"));
609                 addDockWidget(DockWidgetArea.RightDockWidgetArea, rensoNoteListDock);
610
611                 if (Global.getListView() == Global.View_List_Wide) {
612                         browserIndexSplitter.addWidget(noteTableView);
613                         browserIndexSplitter.addWidget(tabBrowser);
614                 } else {
615                         mainLeftRightSplitter.addWidget(noteTableView);
616                         mainLeftRightSplitter.addWidget(tabBrowser);
617                 }
618         
619         // Setup the thumbnail viewer
620         thumbnailViewer = new ThumbnailViewer();
621         thumbnailViewer.upArrow.connect(this, "upAction()");
622         thumbnailViewer.downArrow.connect(this, "downAction()");
623         thumbnailViewer.leftArrow.connect(this, "nextViewedAction()");
624         thumbnailViewer.rightArrow.connect(this, "previousViewedAction()");
625         
626         //Setup external browser manager
627         externalWindows = new HashMap<String, ExternalBrowse>();
628
629         listManager.loadNotesIndex();
630         initializeNotebookTree();
631         initializeTagTree();
632         initializeSavedSearchTree();
633         attributeTree.itemClicked.connect(this, "attributeTreeClicked(QTreeWidgetItem, Integer)");
634         attributeTreeSelected = null;
635         initializeNoteTable();    
636
637                 selectedNoteGUIDs = new ArrayList<String>();
638                 statusBar = new QStatusBar();
639                 setStatusBar(statusBar);
640                 menuBar = new MainMenuBar(this);
641                 emitLog = new ArrayList<String>();
642                 
643                 tagTree.setDeleteAction(menuBar.tagDeleteAction);
644                 tagTree.setMergeAction(menuBar.tagMergeAction);
645                 tagTree.setEditAction(menuBar.tagEditAction);
646                 tagTree.setAddAction(menuBar.tagAddAction);
647                 tagTree.setIconAction(menuBar.tagIconAction);
648                 tagTree.setVisible(Global.isWindowVisible("tagTree"));
649                 leftSplitter1.setVisible(Global.isWindowVisible("leftPanel"));
650                 tagTree.noteSignal.tagsAdded.connect(this, "tagsAdded(String, String)");
651                 menuBar.hideTags.setChecked(Global.isWindowVisible("tagTree"));
652                 listManager.tagSignal.listChanged.connect(this, "reloadTagTree()");
653                 
654                 if (!Global.isWindowVisible("zoom")) {
655                         zoomLayout.hideZoom();
656                         menuBar.hideZoom.setChecked(false);
657                 } 
658         
659                 notebookTree.setDeleteAction(menuBar.notebookDeleteAction);
660                 notebookTree.setEditAction(menuBar.notebookEditAction);
661                 notebookTree.setAddAction(menuBar.notebookAddAction);
662                 notebookTree.setIconAction(menuBar.notebookIconAction);
663                 notebookTree.setStackAction(menuBar.notebookStackAction);
664                 notebookTree.setPublishAction(menuBar.notebookPublishAction);
665                 notebookTree.setShareAction(menuBar.notebookShareAction);
666                 notebookTree.setVisible(Global.isWindowVisible("notebookTree"));
667                 notebookTree.noteSignal.notebookChanged.connect(this, "updateNoteNotebook(String, String)");
668                 notebookTree.noteSignal.tagsChanged.connect(this, "updateNoteTags(String, List)");
669             notebookTree.noteSignal.tagsChanged.connect(this, "updateListTags(String, List)");
670                 menuBar.hideNotebooks.setChecked(Global.isWindowVisible("notebookTree"));
671
672                 savedSearchTree.setAddAction(menuBar.savedSearchAddAction);
673                 savedSearchTree.setEditAction(menuBar.savedSearchEditAction);
674                 savedSearchTree.setDeleteAction(menuBar.savedSearchDeleteAction);
675                 savedSearchTree.setIconAction(menuBar.savedSearchIconAction);
676                 savedSearchTree.itemSelectionChanged.connect(this, "updateSavedSearchSelection()");
677                 savedSearchTree.setVisible(Global.isWindowVisible("savedSearchTree"));
678                 menuBar.hideSavedSearches.setChecked(Global.isWindowVisible("savedSearchTree"));
679                 
680                 // noteTableViewに新しいタブで開くを追加
681                 noteTableView.setOpenNewTabAction(menuBar.noteOpenNewTab);
682                         
683                 noteTableView.setAddAction(menuBar.noteAdd);
684                 
685                 // noteTableViewに新しいタブでノート追加を追加
686                 noteTableView.setAddNoteNewTabAction(menuBar.noteAddNewTab);
687                 
688                 noteTableView.setDeleteAction(menuBar.noteDelete);
689                 noteTableView.setRestoreAction(menuBar.noteRestoreAction);
690                 noteTableView.setNoteDuplicateAction(menuBar.noteDuplicateAction);
691                 noteTableView.setNoteHistoryAction(menuBar.noteOnlineHistoryAction);
692                 noteTableView.noteSignal.titleColorChanged.connect(this, "titleColorChanged(Integer)");
693                 noteTableView.noteSignal.notePinned.connect(this, "notePinned()");
694                 noteTableView.setMergeNotesAction(menuBar.noteMergeAction);
695                 noteTableView.setCopyAsUrlAction(menuBar.noteCopyAsUrlAction);
696                 noteTableView.doubleClicked.connect(this, "listDoubleClick()");
697                 listManager.trashSignal.countChanged.connect(trashTree, "updateCounts(Integer)");
698                 
699                 quotaBar.setMouseClickAction(menuBar.accountAction);
700                 
701                 trashTree.load();
702         trashTree.itemSelectionChanged.connect(this, "trashTreeSelection()");
703                 trashTree.setEmptyAction(menuBar.emptyTrashAction);
704                 trashTree.setVisible(Global.isWindowVisible("trashTree"));
705                 menuBar.hideTrash.setChecked(Global.isWindowVisible("trashTree"));
706                 trashTree.updateCounts(listManager.getTrashCount());
707                 attributeTree.setVisible(Global.isWindowVisible("attributeTree"));
708                 menuBar.hideAttributes.setChecked(Global.isWindowVisible("attributeTree"));
709
710                 noteTableView.setVisible(Global.isWindowVisible("noteList"));
711                 menuBar.hideNoteList.setChecked(Global.isWindowVisible("noteList"));
712                 
713                 if (!Global.isWindowVisible("editorButtonBar")) {
714                         menuBar.showEditorBar.setChecked(false);
715                         toggleEditorButtonBar();
716                 }
717                 
718                 if (!Global.isWindowVisible("leftPanel"))
719                         menuBar.hideLeftSide.setChecked(true);
720                 
721                 if (Global.isWindowVisible("noteInformation")) {
722                         menuBar.noteAttributes.setChecked(true);
723                         toggleNoteInformation();
724                 }
725                 
726                 quotaBar.setVisible(Global.isWindowVisible("quota"));
727                 // IFIXED quotaBar.isVisible() → Global.isWindowVisible("quota")
728                 // なぜかquotaBar.isVisible()が常にfalseを返すようなので修正
729                 if (!Global.isWindowVisible("quota"))
730                         menuBar.hideQuota.setChecked(false);
731                 
732                 if (quotaBar.isHidden() && zoomSpinner.isHidden() && notebookTree.isHidden())
733                         zoomLayout.hide();
734                 
735                 setMenuBar(menuBar);
736                 setupToolBar();
737                 find = new FindDialog();
738                 find.getOkButton().clicked.connect(this, "doFindText()");
739                 
740                 // Setup the tray icon menu bar
741                 trayShowAction = new QAction(tr("Show/Hide"), this);
742                 trayExitAction = new QAction(tr("Exit"), this);
743                 trayAddNoteAction = new QAction(tr("Add Note"), this);
744                 
745                 trayExitAction.triggered.connect(this, "closeNeverNote()");
746                 trayAddNoteAction.triggered.connect(this, "addNote()");
747                 trayShowAction.triggered.connect(this, "trayToggleVisible()");
748                 
749                 trayMenu = new QMenu(this);
750                 trayMenu.addAction(trayAddNoteAction);
751                 trayMenu.addAction(trayShowAction);
752                 trayMenu.addAction(trayExitAction);
753                 
754                 
755                 trayIcon = new QSystemTrayIcon(this);
756                 trayIcon.setToolTip(tr("NeighborNote"));
757                 trayIcon.setContextMenu(trayMenu);
758                 trayIcon.activated.connect(this, "trayActivated(com.trolltech.qt.gui.QSystemTrayIcon$ActivationReason)");
759
760                 currentNoteGuid="";
761                 currentNoteGuid = Global.getLastViewedNoteGuid();
762                 if (currentNoteGuid.equals(""))
763                         currentNote = new Note();
764                 
765                 /* 上に移動したのでここには不要
766                  * historyGuids = new ArrayList<String>();
767                  * historyPosition = 0;
768                  * fromHistory = false;
769                  */
770                 
771                 if (!currentNoteGuid.trim().equals("")) {
772                         currentNote = conn.getNoteTable().getNote(currentNoteGuid, true,true,false,false,true);
773                 }
774                 
775                 noteIndexUpdated(true);
776                 showColumns();
777                 menuBar.showEditorBar.setChecked(Global.isWindowVisible("editorButtonBar"));
778                 if (menuBar.showEditorBar.isChecked())
779                 showEditorButtons(browserWindow);
780                 tagIndexUpdated(true);
781                 savedSearchIndexUpdated();
782                 notebookIndexUpdated();
783                 updateQuotaBar();
784         setupSyncSignalListeners();        
785         setupBrowserSignalListeners();
786         setupIndexListeners();
787               
788         
789         tagTree.tagSignal.listChanged.connect(this, "tagIndexUpdated()");
790         tagTree.showAllTags(true);
791
792                 QIcon appIcon = new QIcon(iconPath+"nevernote.png");
793                 if (QSystemTrayIcon.isSystemTrayAvailable()) {
794                         setWindowIcon(appIcon);
795                         trayIcon.setIcon(appIcon);
796                         if (Global.showTrayIcon() || Global.minimizeOnClose())
797                                 trayIcon.show();
798                         else
799                                 trayIcon.hide();
800                 }
801         
802         scrollToGuid(currentNoteGuid);
803         if (Global.automaticLogin()) {
804                 remoteConnect();
805                 if (Global.isConnected)
806                         syncTimer();
807         }
808         setupFolderImports();
809         
810         loadStyleSheet();
811         restoreWindowState(true);
812         
813         if (Global.mimicEvernoteInterface) {
814                 notebookTree.selectGuid("");
815         }
816         
817         threadMonitorTimer = new QTimer();
818         threadMonitorTimer.timeout.connect(this, "threadMonitorCheck()");
819         threadMonitorTimer.start(1000*10);  // Check for threads every 10 seconds;              
820         
821                 // IFIXED 恐らく不要なのでコメントアウト
822                 /*
823                  * historyGuids.add(currentNoteGuid);
824                  * historyPosition = 1;
825                  */
826         
827         menuBar.blockSignals(true);
828         menuBar.narrowListView.blockSignals(true);
829         menuBar.wideListView.blockSignals(true);
830         if (Global.getListView() == Global.View_List_Narrow) { 
831                 menuBar.narrowListView.setChecked(true);
832         }
833         else{ 
834                 menuBar.wideListView.setChecked(true);
835         }
836         menuBar.blockSignals(false);
837         menuBar.narrowListView.blockSignals(false);
838         menuBar.wideListView.blockSignals(false);
839         
840                 // IFIXED 上に同じコードがあるのでコメントアウト
841                 /*
842                  * if (Global.getListView() == Global.View_List_Wide) {
843                  * browserIndexSplitter.addWidget(noteTableView);
844                  * browserIndexSplitter.addWidget(tabBrowser);
845                  * browserIndexSplitter.addWidget(browserWindow); } else {
846                  * mainLeftRightSplitter.addWidget(noteTableView);
847                  * mainLeftRightSplitter.addWidget(tabBrowser);
848                  * mainLeftRightSplitter.addWidget(browserWindow); }
849                  */
850         
851                 messageTimer = new QTimer();
852                 messageTimer.timeout.connect(this, "clearMessage()");
853                 messageTimer.setInterval(1000*15);
854                 clearMessage();
855         
856         int sortCol = Global.getSortColumn();
857                 int sortOrder = Global.getSortOrder();
858                 noteTableView.proxyModel.blocked = true;
859                 // We sort the table twice to fix a bug.  For some reaosn the table won't sort properly if it is in narrow
860                 // list view and sorted descending on the date  created.  By sorting it twice it forces the proper sort.  Ugly.
861                 if (sortCol == 0 && sortOrder == 1 && Global.getListView() == Global.View_List_Narrow) 
862                         noteTableView.sortByColumn(sortCol, SortOrder.resolve(0));   
863                 noteTableView.sortByColumn(sortCol, SortOrder.resolve(sortOrder));
864                 noteTableView.proxyModel.blocked = false;
865                 noteTableView.proxyModel.sortChanged.connect(this, "tableSortOrderChanged(Integer,Integer)");
866                 
867                 // Set the startup notebook
868         String defaultNotebook = Global.getStartupNotebook();
869         if (!defaultNotebook.equals("AllNotebooks") && !defaultNotebook.equals("")) {
870                 for (int k=0; k<listManager.getNotebookIndex().size(); k++) {
871                         if (listManager.getNotebookIndex().get(k).isDefaultNotebook()) {
872                                 notebookTree.clearSelection();
873                                 notebookTree.selectGuid(listManager.getNotebookIndex().get(k).getGuid());
874                                 notebookTree.selectionSignal.emit();
875                         }
876                 }
877         }
878                 
879                 if (Global.checkVersionUpgrade()) {
880                         checkForUpdates();
881                 }
882                 
883                 if (currentNoteGuid == null || currentNoteGuid.equals("")) {
884                         menuBar.noteAddNewTab.setEnabled(false);
885                 }
886         }
887         
888         
889         public void debugDirty() {
890                 List<Note> dirty = conn.getNoteTable().getDirty();
891                 logger.log(logger.LOW, "------ Dirty Notes List Begin ------");
892                 for (int i=0; i<dirty.size(); i++) {
893                         logger.log(logger.LOW, "GUID: " +dirty.get(i).getGuid() + " Title:" + dirty.get(i).getTitle());
894                 }
895                 logger.log(logger.LOW, "------ Dirty Notes List End ------");
896         }
897                 
898         // Main entry point
899         public static void main(String[] args) {
900                 log.setLevel(Level.FATAL);
901                 QApplication.initialize(args);
902                 QPixmap pixmap = new QPixmap("classpath:cx/fbn/nevernote/icons/splash_logo.png");
903                 QSplashScreen splash = new QSplashScreen(pixmap);
904                 boolean showSplash;
905                 
906                 DatabaseConnection dbConn;
907
908         try {
909             initializeGlobalSettings(args);
910
911             showSplash = Global.isWindowVisible("SplashScreen");
912             if (showSplash)
913                 splash.show();
914
915             dbConn = setupDatabaseConnection();
916
917             // Must be last stage of setup - only safe once DB is open hence we know we are the only instance running
918             Global.getFileManager().purgeResDirectory(true);
919
920         } catch (InitializationException e) {
921             // Fatal
922             e.printStackTrace();
923             QMessageBox.critical(null, "Startup error", "Aborting: " + e.getMessage());
924             return;
925         }
926         
927                 // Setup proxy crap
928                 String proxyUrl = Global.getProxyValue("url");
929                 String proxyPort = Global.getProxyValue("port");
930                 String proxyUserid = Global.getProxyValue("userid");
931                 String proxyPassword = Global.getProxyValue("password");
932                 boolean proxySet = false;
933                 QNetworkProxy proxy = new QNetworkProxy();
934                 proxy.setType(ProxyType.HttpProxy);
935                 if (!proxyUrl.trim().equals("")) {
936                         System.out.println("Proxy URL found: " +proxyUrl);
937                         proxySet = true;
938                         proxy.setHostName(proxyUrl);
939                 }
940                 if (!proxyPort.trim().equals("")) {
941                         System.out.println("Proxy Port found: " +proxyPort);
942                         proxySet = true;
943                         proxy.setPort(Integer.parseInt(proxyPort));
944                 }
945                 if (!proxyUserid.trim().equals("")) {
946                         System.out.println("Proxy Userid found: " +proxyUserid);
947                         proxySet = true;
948                         proxy.setUser(proxyUserid);
949                 }
950                 if (!proxyPassword.trim().equals("")) {
951                         System.out.println("Proxy URL found: " +proxyPassword);
952                         proxySet = true;
953                         proxy.setPassword(proxyPassword);
954                 }
955                 if (proxySet) {
956                         QNetworkProxy.setApplicationProxy(proxy);
957                 }
958                         
959
960         NeverNote application = new NeverNote(dbConn);
961                 if (Global.syncOnly) {
962                         System.out.println("Performing synchronization only.");
963                         application.remoteConnect();
964                         if (Global.isConnected) {
965                                 application.syncRunner.syncNeeded = true;
966                                 application.syncRunner.addWork("SYNC");
967                                 application.syncRunner.addWork("STOP");
968                                 while(!application.syncRunner.isIdle());
969                                 application.closeNeverNote();
970                         }
971                         return;
972                 }
973
974                 application.setAttribute(WidgetAttribute.WA_DeleteOnClose, true);
975                 if (Global.startMinimized()) 
976                         application.showMinimized();
977                 else {
978                         if (Global.wasWindowMaximized())
979                                 application.showMaximized();
980                         else
981                                 application.show();
982                 }
983                 
984                 if (showSplash)
985                         splash.finish(application);
986                 QApplication.exec();
987                 System.out.println("Goodbye.");
988                 QApplication.exit();
989         }
990
991     /**
992      * Open the internal database, or create if not present
993      *
994      * @throws InitializationException when opening the database fails, e.g. because another process has it locked
995      */
996     private static DatabaseConnection setupDatabaseConnection() throws InitializationException {
997         ApplicationLogger logger = new ApplicationLogger("nevernote-database.log");
998         
999         File f = Global.getFileManager().getDbDirFile(Global.databaseName + ".h2.db");
1000         File fr = Global.getFileManager().getDbDirFile(Global.resourceDatabaseName + ".h2.db");
1001                 // IFIXED resourceDatabaseNameになっていたので修正
1002                 File fi = Global.getFileManager().getDbDirFile(Global.indexDatabaseName + ".h2.db");
1003                 File fb = Global.getFileManager().getDbDirFile(Global.behaviorDatabaseName + ".h2.db");
1004                                 
1005                 if (!f.exists())
1006                         Global.setDatabaseUrl("");
1007                 if (!fr.exists())
1008                         Global.setResourceDatabaseUrl("");              
1009                 if (!fi.exists())
1010                         Global.setIndexDatabaseUrl(""); 
1011                 if (!fb.exists())
1012                         Global.setBehaviorDatabaseUrl("");
1013         
1014         if (Global.getDatabaseUrl().toUpperCase().indexOf("CIPHER=") > -1) {
1015             boolean goodCheck = false;
1016             while (!goodCheck) {
1017                 DatabaseLoginDialog dialog = new DatabaseLoginDialog();
1018                 dialog.exec();
1019                 if (!dialog.okPressed())
1020                     System.exit(0);
1021                 Global.cipherPassword = dialog.getPassword();
1022                 goodCheck = databaseCheck(Global.getDatabaseUrl(), Global.getDatabaseUserid(),
1023                         Global.getDatabaseUserPassword(), Global.cipherPassword);
1024             }
1025         }
1026         DatabaseConnection dbConn = new DatabaseConnection(logger,Global.getDatabaseUrl(), 
1027                         Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(), Global.getBehaviorDatabaseUrl(),
1028                         Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword, 0);
1029        return dbConn;
1030     }
1031     
1032     // Encrypt the database upon shutdown
1033     private void encryptOnShutdown() {
1034         String dbPath= Global.getFileManager().getDbDirPath("");
1035         try {
1036                 
1037                 Statement st = conn.getConnection().createStatement();  
1038                 st.execute("shutdown");
1039                 st = conn.getResourceConnection().createStatement();
1040                 st.execute("shutdown");
1041                 st = conn.getIndexConnection().createStatement();
1042                 st.execute("shutdown");
1043                 st = conn.getBehaviorConnection().createStatement();
1044                 st.execute("shutdown");
1045                 
1046                 if (QMessageBox.question(this, tr("Are you sure"), 
1047                                 tr("Are you sure you wish to encrypt the database?"),
1048                                 QMessageBox.StandardButton.Yes, 
1049                                 QMessageBox.StandardButton.No) == StandardButton.Yes.value()) {
1050                         ChangeFileEncryption.execute(dbPath, "NeverNote", encryptCipher, null, Global.cipherPassword.toCharArray(), true);
1051                         ChangeFileEncryption.execute(dbPath, "Resources", encryptCipher, null, Global.cipherPassword.toCharArray(), true);
1052                         ChangeFileEncryption.execute(dbPath, "Index", encryptCipher, null, Global.cipherPassword.toCharArray(), true);
1053                         ChangeFileEncryption.execute(dbPath, "Behavior", encryptCipher, null, Global.cipherPassword.toCharArray(), true);
1054                         
1055                         Global.setDatabaseUrl(Global.getDatabaseUrl() + ";CIPHER="+encryptCipher);
1056                         Global.setResourceDatabaseUrl(Global.getResourceDatabaseUrl() + ";CIPHER="+encryptCipher);
1057                         Global.setIndexDatabaseUrl(Global.getIndexDatabaseUrl() + ";CIPHER="+encryptCipher);
1058                                 Global.setBehaviorDatabaseUrl(Global.getBehaviorDatabaseUrl() + ";CIPHER=" + encryptCipher);
1059
1060                         QMessageBox.information(this, tr("Encryption Complete"), tr("Encryption is complete"));
1061                 }
1062         } catch (SQLException e) {
1063                         e.printStackTrace();
1064                 }       
1065     }
1066     
1067     // Decrypt the database upon shutdown
1068     private void decryptOnShutdown() {
1069         String dbPath= Global.getFileManager().getDbDirPath("");
1070         String dbName = "NeverNote";
1071         try {
1072                 Statement st = conn.getConnection().createStatement();  
1073                 st.execute("shutdown");
1074                 if (Global.getDatabaseUrl().toUpperCase().indexOf(";CIPHER=AES") > -1)
1075                         encryptCipher = "AES";
1076                 else
1077                         encryptCipher = "XTEA";
1078                 if (QMessageBox.question(this, tr("Confirmation"), tr("Are you sure", 
1079                                 "Are you sure you wish to decrypt the database?"),
1080                                 QMessageBox.StandardButton.Yes, 
1081                                 QMessageBox.StandardButton.No) == StandardButton.Yes.value()) {
1082
1083                         ChangeFileEncryption.execute(dbPath, dbName, encryptCipher, Global.cipherPassword.toCharArray(), null, true);
1084                         Global.setDatabaseUrl("");
1085                         Global.setResourceDatabaseUrl("");
1086                         Global.setIndexDatabaseUrl("");
1087                         QMessageBox.information(this, tr("Decryption Complete"), tr("Decryption is complete"));
1088                 }
1089                 } catch (SQLException e) {
1090                         e.printStackTrace();
1091                 }       
1092     }
1093     /**
1094      * Encrypt/Decrypt the local database
1095      **/
1096     public void doDatabaseEncrypt() {
1097         // The database is not currently encrypted
1098         if (Global.getDatabaseUrl().toUpperCase().indexOf("CIPHER=") == -1) {
1099                 if (QMessageBox.question(this, tr("Confirmation"), tr("Encrypting the database is used" +
1100                                 "to enhance security and is performed\nupon shutdown, but please be aware that if"+
1101                                 " you lose the password your\nis lost forever.\n\nIt is highly recommended you " +
1102                                 "perform a backup and/or fully synchronize\n prior to executing this funtction.\n\n" +
1103                                 "Do you wish to proceed?"),
1104                                 QMessageBox.StandardButton.Yes, 
1105                                 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
1106                                 return;
1107                 }
1108                 DBEncryptDialog dialog = new DBEncryptDialog();
1109                 dialog.exec();
1110                 if (dialog.okPressed()) {
1111                         Global.cipherPassword = dialog.getPassword();
1112                         encryptOnShutdown  = true;
1113                         encryptCipher = dialog.getEncryptionMethod();
1114                 }
1115         } else {
1116             DBEncryptDialog dialog = new DBEncryptDialog();
1117             dialog.setWindowTitle(tr("Database Decryption"));
1118             dialog.hideEncryption();
1119             dialog.exec();
1120             if (dialog.okPressed()) {
1121                 if (!dialog.getPassword().equals(Global.cipherPassword)) {
1122                         QMessageBox.critical(null, tr("Incorrect Password"), tr("Incorrect Password"));
1123                         return;
1124                 }
1125                 decryptOnShutdown  = true;
1126                 encryptCipher = "";
1127             }
1128         }
1129         return;
1130     }
1131
1132         private static void initializeGlobalSettings(String[] args) throws InitializationException {
1133                 StartupConfig   startupConfig = new StartupConfig();
1134
1135         for (String arg : args) {
1136             String lower = arg.toLowerCase();
1137             if (lower.startsWith("--name="))
1138                startupConfig.setName(arg.substring(arg.indexOf('=') + 1));
1139             if (lower.startsWith("--home="))
1140                startupConfig.setHomeDirPath(arg.substring(arg.indexOf('=') + 1));
1141             if (lower.startsWith("--disable-viewing"))
1142                startupConfig.setDisableViewing(true);
1143             if (lower.startsWith("--sync-only=true"))
1144                 startupConfig.setSyncOnly(true);
1145         }
1146         Global.setup(startupConfig);
1147         
1148     }
1149
1150     // Exit point
1151         @Override
1152         public void closeEvent(QCloseEvent event) {     
1153                 if (Global.minimizeOnClose() && !closeAction) {
1154                         event.ignore();
1155                         hide();
1156                         return;
1157                 }
1158                 logger.log(logger.HIGH, "Entering NeverNote.closeEvent");
1159                 waitCursor(true);
1160                 
1161                 if (currentNote != null & browserWindow != null) {
1162                         if (currentNote.getTitle() != null && browserWindow != null
1163                                         && !currentNote.getTitle().equals(browserWindow.getTitle()))
1164                                 conn.getNoteTable().updateNoteTitle(currentNote.getGuid(),
1165                                                 browserWindow.getTitle());
1166                 }
1167                 
1168                 saveNote();
1169                 setMessage(tr("Beginning shutdown."));
1170                 
1171                 // Close down external windows
1172                 Collection<ExternalBrowse> windows = externalWindows.values();
1173                 Iterator<ExternalBrowse> iterator = windows.iterator();
1174                 while (iterator.hasNext()) {
1175                         ExternalBrowse browser = iterator.next();
1176                         browser.windowClosing.disconnect();
1177                         browser.close();
1178                 }
1179                 
1180                 // タブブラウザに対してクローズ処理を行う
1181                 Collection<TabBrowse> win = tabWindows.values();
1182                 Iterator<TabBrowse> it = win.iterator();
1183                 tabBrowser.currentChanged.disconnect();
1184                 tabBrowser.tabCloseRequested.disconnect();
1185                 while (it.hasNext()) {
1186                         TabBrowse browser = it.next();
1187                         browser.close();
1188                 }
1189                 
1190                 externalFileEditedSaver();
1191                 if (Global.isConnected && Global.synchronizeOnClose()) {
1192                         setMessage(tr("Performing synchronization before closing."));
1193                         syncRunner.syncNeeded = true;
1194                         syncRunner.addWork("SYNC");
1195                 } else {
1196                         syncRunner.keepRunning = false;
1197                 }
1198                 syncRunner.addWork("STOP");
1199                 setMessage("Closing Program.");
1200                 threadMonitorTimer.stop();
1201
1202                 thumbnailRunner.addWork("STOP");
1203                 indexRunner.addWork("STOP");
1204                 saveNote();
1205                 listManager.stop();
1206                 saveWindowState();
1207                 
1208                 // 連想ノートリストのEvernote関連ノート取得スレッドを終了
1209                 rensoNoteListDock.getRensoNoteList().stopThread();
1210
1211                 if (tempFiles != null)
1212                         tempFiles.clear();
1213
1214                 browserWindow.noteSignal.tagsChanged.disconnect();
1215                 browserWindow.noteSignal.titleChanged.disconnect();
1216                 browserWindow.noteSignal.noteChanged.disconnect();
1217                 browserWindow.noteSignal.notebookChanged.disconnect();
1218                 browserWindow.noteSignal.createdDateChanged.disconnect();
1219                 browserWindow.noteSignal.alteredDateChanged.disconnect();
1220                 syncRunner.searchSignal.listChanged.disconnect();
1221                 syncRunner.tagSignal.listChanged.disconnect();
1222         syncRunner.notebookSignal.listChanged.disconnect();
1223         syncRunner.noteIndexSignal.listChanged.disconnect();
1224
1225                 if (isVisible())
1226                         Global.saveWindowVisible("toolBar", toolBar.isVisible());
1227                 saveNoteColumnPositions();
1228                 saveNoteIndexWidth();
1229                 
1230                 int width = notebookTree.columnWidth(0);
1231                 Global.setColumnWidth("notebookTreeName", width);
1232                 width = tagTree.columnWidth(0);
1233                 Global.setColumnWidth("tagTreeName", width);
1234                 
1235                 Global.saveWindowMaximized(isMaximized());
1236                 Global.saveCurrentNoteGuid(currentNoteGuid);
1237                         
1238                 int sortCol = noteTableView.proxyModel.sortColumn();
1239                 int sortOrder = noteTableView.proxyModel.sortOrder().value();
1240                 Global.setSortColumn(sortCol);
1241                 Global.setSortOrder(sortOrder);
1242                 
1243                 hide();
1244                 trayIcon.hide();
1245                 Global.keepRunning = false;
1246                 try {
1247                         logger.log(logger.MEDIUM, "Waiting for indexThread to stop");
1248                         if (indexRunner.thread().isAlive())
1249                                 indexRunner.thread().join(50);
1250                         if (!indexRunner.thread().isAlive())
1251                                 logger.log(logger.MEDIUM, "Index thread has stopped");
1252                         else {
1253                                 logger.log(logger.MEDIUM, "Index thread still running - interrupting");
1254                                 indexRunner.thread().interrupt();
1255                         }
1256                 } catch (InterruptedException e1) {
1257                         e1.printStackTrace();
1258                 }
1259                 
1260                 if (!syncRunner.thread().isAlive()) {
1261                         logger.log(logger.MEDIUM, "Waiting for syncThread to stop");
1262                         if (syncRunner.thread().isAlive()) {
1263                                 System.out.println(tr("Synchronizing.  Please be patient."));
1264                                 for(;syncRunner.thread().isAlive();) {
1265                                         try {
1266                                                 wait(10);
1267                                         } catch (InterruptedException e) {
1268                                                 e.printStackTrace();
1269                                         }
1270                                 }
1271                         }
1272                         logger.log(logger.MEDIUM, "Sync thread has stopped");
1273                 }
1274
1275                 if (encryptOnShutdown) {
1276                         encryptOnShutdown();
1277                 }
1278                 if (decryptOnShutdown) {
1279                         decryptOnShutdown();
1280                 }
1281                 try {
1282                         Global.getFileManager().purgeResDirectory(false);
1283                 } catch (InitializationException e) {
1284                         System.out.println(tr("Empty res directory purge failed"));
1285                         e.printStackTrace();
1286                 }
1287                 logger.log(logger.HIGH, "Leaving NeverNote.closeEvent");
1288         }
1289
1290
1291         private void closeNeverNote() {
1292                 closeAction = true;
1293                 close();
1294         }
1295         public void setMessage(String s) {
1296                 if (logger != null) 
1297                         logger.log(logger.HIGH, "Entering NeverNote.setMessage");
1298                 else
1299                         System.out.println("*** ERROR *** " +s);
1300                 
1301                 if (statusBar != null) {
1302                         statusBar.show();
1303                         if (logger != null) 
1304                                 logger.log(logger.HIGH, "Message: " +s);
1305                         statusBar.showMessage(s);
1306                         if (emitLog != null)
1307                                 emitLog.add(s);
1308                 
1309                         if (messageTimer != null) {
1310                                 messageTimer.stop();
1311                                 messageTimer.setSingleShot(true);
1312                                 messageTimer.start();
1313                         }
1314                 }
1315                         
1316                 if (logger != null) 
1317                         logger.log(logger.HIGH, "Leaving NeverNote.setMessage");
1318         }
1319         
1320         private void clearMessage() {
1321                 statusBar.clearMessage();
1322                 statusBar.hide();
1323         }
1324                 
1325         private void waitCursor(boolean wait) {
1326                 if (wait) {
1327                         if (QApplication.overrideCursor() == null)
1328                                 QApplication.setOverrideCursor(new QCursor(Qt.CursorShape.WaitCursor));
1329                 }
1330                 else {
1331                         if (QApplication.overrideCursor() != null)
1332                                 QApplication.restoreOverrideCursor();
1333                         else
1334                                 QApplication.setOverrideCursor(new QCursor(Qt.CursorShape.ArrowCursor));
1335                 }
1336                 listManager.refreshCounters();
1337         }
1338         
1339         private void setupIndexListeners() {
1340 //              indexRunner.noteSignal.noteIndexed.connect(this, "indexThreadComplete(String)");
1341 //              indexRunner.resourceSignal.resourceIndexed.connect(this, "indexThreadComplete(String)");
1342                 indexRunner.signal.indexStarted.connect(this, "indexStarted()");
1343                 indexRunner.signal.indexFinished.connect(this, "indexComplete()");
1344         }
1345         private void setupSyncSignalListeners() {
1346                 syncRunner.tagSignal.listChanged.connect(this, "tagIndexUpdated()");
1347         syncRunner.searchSignal.listChanged.connect(this, "savedSearchIndexUpdated()");
1348         syncRunner.notebookSignal.listChanged.connect(this, "notebookIndexUpdated()");
1349         syncRunner.noteIndexSignal.listChanged.connect(this, "noteIndexUpdated(boolean)");
1350         syncRunner.noteSignal.quotaChanged.connect(this, "updateQuotaBar()");
1351         
1352                 syncRunner.syncSignal.saveUploadAmount.connect(this,"saveUploadAmount(long)");
1353                 syncRunner.syncSignal.saveUserInformation.connect(this,"saveUserInformation(User)");
1354                 syncRunner.syncSignal.saveEvernoteUpdateCount.connect(this,"saveEvernoteUpdateCount(int)");
1355                 
1356                 syncRunner.noteSignal.guidChanged.connect(this, "noteGuidChanged(String, String)");
1357                 syncRunner.noteSignal.noteChanged.connect(this, "invalidateNoteCache(String, String)");
1358                 syncRunner.resourceSignal.resourceGuidChanged.connect(this, "noteResourceGuidChanged(String,String,String)");
1359                 syncRunner.noteSignal.noteDownloaded.connect(listManager, "noteDownloaded(Note)");
1360                 syncRunner.noteSignal.notebookChanged.connect(this, "updateNoteNotebook(String, String)");
1361                 
1362                 syncRunner.syncSignal.refreshLists.connect(this, "refreshLists()");
1363         }
1364         
1365         private void setupBrowserSignalListeners() {
1366                 setupBrowserWindowListeners(browserWindow, true);
1367         }
1368
1369         private void setupBrowserWindowListeners(BrowserWindow browser, boolean master) {
1370                 browser.fileWatcher.fileChanged.connect(this, "externalFileEdited(String)");
1371                 browser.noteSignal.tagsChanged.connect(this, "updateNoteTags(String, List)");
1372             browser.noteSignal.tagsChanged.connect(this, "updateListTags(String, List)");
1373             if (master) browser.noteSignal.noteChanged.connect(this, "setNoteDirty()");
1374             browser.noteSignal.titleChanged.connect(listManager, "updateNoteTitle(String, String)");
1375             browser.noteSignal.titleChanged.connect(this, "updateNoteTitle(String, String)");
1376             browser.noteSignal.notebookChanged.connect(this, "updateNoteNotebook(String, String)");
1377             browser.noteSignal.createdDateChanged.connect(listManager, "updateNoteCreatedDate(String, QDateTime)");
1378             browser.noteSignal.alteredDateChanged.connect(listManager, "updateNoteAlteredDate(String, QDateTime)");
1379             browser.noteSignal.subjectDateChanged.connect(listManager, "updateNoteSubjectDate(String, QDateTime)");
1380             browser.noteSignal.authorChanged.connect(listManager, "updateNoteAuthor(String, String)");
1381             browser.noteSignal.geoChanged.connect(listManager, "updateNoteGeoTag(String, Double,Double,Double)");
1382             browser.noteSignal.geoChanged.connect(this, "setNoteDirty()");
1383             browser.noteSignal.sourceUrlChanged.connect(listManager, "updateNoteSourceUrl(String, String)");
1384         browser.blockApplication.connect(this, "blockApplication(BrowserWindow)");
1385         browser.unblockApplication.connect(this, "unblockApplication()");
1386             if (master) browser.focusLost.connect(this, "saveNote()");
1387             browser.resourceSignal.contentChanged.connect(this, "externalFileEdited(String)");
1388             browser.evernoteLinkClicked.connect(this, "evernoteLinkClick(String, String)");
1389         }
1390
1391         //**************************************************
1392         //* Setup shortcuts
1393         //**************************************************
1394         private void setupShortcut(QShortcut action, String text) {
1395                 if (!Global.shortcutKeys.containsAction(text))
1396                         return;
1397                 action.setKey(new QKeySequence(Global.shortcutKeys.getShortcut(text)));
1398         }
1399         
1400         //***************************************************************
1401         //***************************************************************
1402         //* Settings and look & feel
1403         //***************************************************************
1404         //***************************************************************
1405         @SuppressWarnings("unused")
1406         private void settings() {
1407                 logger.log(logger.HIGH, "Entering NeverNote.settings");
1408
1409                 saveNoteColumnPositions();
1410                 saveNoteIndexWidth();
1411                 showColumns();
1412         ConfigDialog settings = new ConfigDialog(this, conn);
1413         String dateFormat = Global.getDateFormat();
1414         String timeFormat = Global.getTimeFormat();
1415         
1416                 indexTime = 1000*Global.getIndexThreadSleepInterval();  
1417                 indexTimer.start(indexTime);  // reset indexing timer
1418         
1419         settings.exec();
1420         indexRunner.indexAttachmentsLocally = Global.indexAttachmentsLocally();
1421 //        indexRunner.indexNoteBody = Global.indexNoteBody();
1422 //        indexRunner.indexNoteTitle = Global.indexNoteTitle();
1423 //        indexRunner.specialIndexCharacters = Global.getSpecialIndexCharacters();
1424         indexRunner.indexImageRecognition = Global.indexImageRecognition();
1425         if (Global.showTrayIcon() || Global.minimizeOnClose())
1426                 trayIcon.show();
1427         else
1428                 trayIcon.hide();
1429         showColumns();
1430         if (menuBar.showEditorBar.isChecked()){
1431                 for(int i = 0; i < tabBrowser.count(); i++){
1432                         BrowserWindow browser = ((TabBrowse) tabBrowser.widget(i)).getBrowserWindow();
1433                         showEditorButtons(browser);
1434                 }
1435                 
1436         }
1437         
1438         // Reset the save timer
1439         if (Global.getAutoSaveInterval() > 0)
1440                         saveTimer.setInterval(1000*60*Global.getAutoSaveInterval());
1441         else
1442                 saveTimer.stop();
1443         
1444         
1445         // Set special reloads
1446         if (settings.getDebugPage().reloadSharedNotebooksClicked()) {
1447                 conn.executeSql("Delete from LinkedNotebook");
1448                 conn.executeSql("delete from SharedNotebook");
1449                 conn.executeSql("Delete from Notebook where linked=true");
1450                 conn.executeSql("Insert into Sync (key, value) values ('FullLinkedNotebookSync', 'true')");
1451                 conn.executeSql("Insert into Sync (key, value) values ('FullSharedNotebookSync', 'true')");
1452         }
1453
1454         // Reload user data
1455         noteCache.clear();
1456         readOnlyCache.clear();
1457         inkNoteCache.clear();
1458         noteIndexUpdated(true);
1459                 
1460         logger.log(logger.HIGH, "Leaving NeverNote.settings");
1461         }
1462         // Restore things to the way they were
1463         private void restoreWindowState(boolean mainWindow) {
1464                 // We need to name things or this doesn't work.
1465                 setObjectName("NeverNote");
1466         restoreState(Global.restoreState(objectName()));
1467                 mainLeftRightSplitter.setObjectName("mainLeftRightSplitter");
1468                 browserIndexSplitter.setObjectName("browserIndexSplitter");
1469                 leftSplitter1.setObjectName("leftSplitter1");
1470                 rensoNoteListDock.setObjectName("rensoNoteListDock");
1471                 
1472                 // Restore the actual positions.
1473                 if (mainWindow)
1474                         restoreGeometry(Global.restoreGeometry(objectName()));
1475         mainLeftRightSplitter.restoreState(Global.restoreState(mainLeftRightSplitter.objectName()));
1476         browserIndexSplitter.restoreState(Global.restoreState(browserIndexSplitter.objectName()));
1477         leftSplitter1.restoreState(Global.restoreState(leftSplitter1.objectName()));
1478         rensoNoteListDock.restoreGeometry(Global.restoreGeometry(rensoNoteListDock.objectName()));
1479        
1480         }
1481         // Save window positions for the next start
1482         private void saveWindowState() {
1483                 Global.saveGeometry(objectName(), saveGeometry());
1484                 Global.saveState(mainLeftRightSplitter.objectName(), mainLeftRightSplitter.saveState());
1485                 Global.saveState(browserIndexSplitter.objectName(), browserIndexSplitter.saveState());
1486                 Global.saveState(leftSplitter1.objectName(), leftSplitter1.saveState());
1487                 Global.saveState(objectName(), saveState());
1488                 Global.saveGeometry(rensoNoteListDock.objectName(), rensoNoteListDock.saveGeometry());
1489         }    
1490         // Load the style sheet
1491         private void loadStyleSheet() {
1492                 String styleSheetName = "default.qss";
1493                 if (Global.getStyle().equalsIgnoreCase("cleanlooks"))
1494                                 styleSheetName = "default-cleanlooks.qss";
1495                 String fileName = Global.getFileManager().getQssDirPathUser("default.qss");
1496                 QFile file = new QFile(fileName);
1497                 
1498                 // If a user default.qss doesn't exist, we use the one shipped with NeverNote
1499                 if (!file.exists()) {
1500                         fileName = Global.getFileManager().getQssDirPath(styleSheetName);
1501                         file = new QFile(fileName);
1502                 }
1503                 file.open(OpenModeFlag.ReadOnly);
1504                 String styleSheet = file.readAll().toString();
1505                 file.close();
1506                 setStyleSheet(styleSheet);
1507         }
1508         // Save column positions for the next time
1509         private void saveNoteColumnPositions() {
1510                 int position = noteTableView.header.visualIndex(Global.noteTableCreationPosition);
1511                 Global.setColumnPosition("noteTableCreationPosition", position);
1512                 position = noteTableView.header.visualIndex(Global.noteTableTagPosition);
1513                 Global.setColumnPosition("noteTableTagPosition", position);
1514                 position = noteTableView.header.visualIndex(Global.noteTableNotebookPosition);
1515                 Global.setColumnPosition("noteTableNotebookPosition", position);
1516                 position = noteTableView.header.visualIndex(Global.noteTableChangedPosition);
1517                 Global.setColumnPosition("noteTableChangedPosition", position);
1518                 position = noteTableView.header.visualIndex(Global.noteTableAuthorPosition);
1519                 Global.setColumnPosition("noteTableAuthorPosition", position);
1520                 position = noteTableView.header.visualIndex(Global.noteTableSourceUrlPosition);
1521                 Global.setColumnPosition("noteTableSourceUrlPosition", position);
1522                 position = noteTableView.header.visualIndex(Global.noteTableSubjectDatePosition);
1523                 Global.setColumnPosition("noteTableSubjectDatePosition", position);
1524                 position = noteTableView.header.visualIndex(Global.noteTableTitlePosition);
1525                 Global.setColumnPosition("noteTableTitlePosition", position);
1526                 position = noteTableView.header.visualIndex(Global.noteTableSynchronizedPosition);
1527                 Global.setColumnPosition("noteTableSynchronizedPosition", position);
1528                 position = noteTableView.header.visualIndex(Global.noteTableGuidPosition);
1529                 Global.setColumnPosition("noteTableGuidPosition", position);
1530                 position = noteTableView.header.visualIndex(Global.noteTableThumbnailPosition);
1531                 Global.setColumnPosition("noteTableThumbnailPosition", position);
1532                 position = noteTableView.header.visualIndex(Global.noteTablePinnedPosition);
1533                 Global.setColumnPosition("noteTablePinnedPosition", position);
1534
1535         }
1536         // Save column widths for the next time
1537         private void saveNoteIndexWidth() {
1538                 int width;
1539         width = noteTableView.getColumnWidth(Global.noteTableCreationPosition);
1540         Global.setColumnWidth("noteTableCreationPosition", width);
1541                 width = noteTableView.getColumnWidth(Global.noteTableChangedPosition);
1542                 Global.setColumnWidth("noteTableChangedPosition", width);
1543                 width = noteTableView.getColumnWidth(Global.noteTableGuidPosition);
1544                 Global.setColumnWidth("noteTableGuidPosition", width);
1545                 width = noteTableView.getColumnWidth(Global.noteTableNotebookPosition);
1546                 Global.setColumnWidth("noteTableNotebookPosition", width);
1547                 width = noteTableView.getColumnWidth(Global.noteTableTagPosition);
1548                 Global.setColumnWidth("noteTableTagPosition", width);
1549                 width = noteTableView.getColumnWidth(Global.noteTableTitlePosition);
1550                 Global.setColumnWidth("noteTableTitlePosition", width);
1551                 width = noteTableView.getColumnWidth(Global.noteTableSourceUrlPosition);
1552                 Global.setColumnWidth("noteTableSourceUrlPosition", width);
1553                 width = noteTableView.getColumnWidth(Global.noteTableAuthorPosition);
1554                 Global.setColumnWidth("noteTableAuthorPosition", width);
1555                 width = noteTableView.getColumnWidth(Global.noteTableSubjectDatePosition);
1556                 Global.setColumnWidth("noteTableSubjectDatePosition", width);
1557                 width = noteTableView.getColumnWidth(Global.noteTableSynchronizedPosition);
1558                 Global.setColumnWidth("noteTableSynchronizedPosition", width);
1559                 width = noteTableView.getColumnWidth(Global.noteTableThumbnailPosition);
1560                 Global.setColumnWidth("noteTableThumbnailPosition", width);
1561                 width = noteTableView.getColumnWidth(Global.noteTableGuidPosition);
1562                 Global.setColumnWidth("noteTableGuidPosition", width);
1563                 width = noteTableView.getColumnWidth(Global.noteTablePinnedPosition);
1564                 Global.setColumnWidth("noteTablePinnedPosition", width);
1565         }
1566         
1567         @SuppressWarnings("unused")
1568         private void toggleSearchWindow() {
1569                 logger.log(logger.HIGH, "Entering NeverNote.toggleSearchWindow");
1570                 toggleSearchField();
1571         menuBar.hideSearch.setChecked(searchField.isVisible());
1572         Global.saveWindowVisible("searchField", searchField.isVisible());
1573         logger.log(logger.HIGH, "Leaving NeverNote.toggleSearchWindow");
1574     }
1575         private void toggleSearchField() {
1576                 if (searchField.isVisible())
1577                         searchField.hide();
1578                 else
1579                         searchField.show();
1580         }
1581         
1582         @SuppressWarnings("unused")
1583         private void toggleQuotaWindow() {
1584                 logger.log(logger.HIGH, "Entering NeverNote.toggleQuotaWindow");
1585         zoomLayout.toggleQuotaBar();
1586         menuBar.hideQuota.setChecked(quotaBar.isVisible());
1587         Global.saveWindowVisible("quota", quotaBar.isVisible());
1588         logger.log(logger.HIGH, "Leaving NeverNote.toggleQuotaWindow");
1589     }   
1590         @SuppressWarnings("unused")
1591         private void toggleZoomWindow() {
1592                 logger.log(logger.HIGH, "Entering NeverNote.toggleZoomWindow");
1593         zoomLayout.toggleZoom();
1594         menuBar.hideZoom.setChecked(zoomSpinner.isVisible());
1595         Global.saveWindowVisible("zoom", zoomSpinner.isVisible());
1596         logger.log(logger.HIGH, "Leaving NeverNote.toggleZoomWindow");
1597     }   
1598         
1599         
1600         
1601     //***************************************************************
1602     //***************************************************************
1603     //** These functions deal with Notebook menu items
1604     //***************************************************************
1605     //***************************************************************
1606     // Setup the tree containing the user's notebooks.
1607     private void initializeNotebookTree() {       
1608         logger.log(logger.HIGH, "Entering NeverNote.initializeNotebookTree");
1609 //      notebookTree.itemClicked.connect(this, "notebookTreeSelection()");
1610         notebookTree.selectionSignal.connect(this, "notebookTreeSelection()");
1611         listManager.notebookSignal.refreshNotebookTreeCounts.connect(notebookTree, "updateCounts(List, List)");
1612         logger.log(logger.HIGH, "Leaving NeverNote.initializeNotebookTree");
1613     }   
1614     // Listener when a notebook is selected
1615         private void notebookTreeSelection() {
1616                 logger.log(logger.HIGH, "Entering NeverNote.notebookTreeSelection");
1617                 noteTableView.proxyModel.blocked = true;
1618                 
1619                 clearTrashFilter();
1620                 clearAttributeFilter();
1621                 clearSavedSearchFilter();
1622                 if (Global.mimicEvernoteInterface) {
1623                         clearTagFilter();
1624                         searchField.clear();
1625                 }
1626                 menuBar.noteRestoreAction.setVisible(false);            
1627         menuBar.notebookEditAction.setEnabled(true);
1628         menuBar.notebookDeleteAction.setEnabled(true);
1629         menuBar.notebookPublishAction.setEnabled(true);
1630         menuBar.notebookShareAction.setEnabled(true);
1631         menuBar.notebookIconAction.setEnabled(true);
1632         menuBar.notebookStackAction.setEnabled(true);
1633         
1634                 // ゴミ箱から元の画面に戻す。連想ノートリストをONに。
1635                 if (!rensoNoteListDock.isEnabled()) {
1636                         rensoNoteListDock.setEnabled(true);
1637                 }
1638                 
1639         List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1640         selectedNotebookGUIDs.clear();
1641         searchField.setTargetNotebook("");
1642         searchField.setTargetStack("");
1643                 String guid = "";
1644                 String stackName = "";
1645                 if (selections.size() > 0) {
1646                 guid = (selections.get(0).text(2));
1647                 stackName = selections.get(0).text(0);
1648         }
1649                 if (!Global.mimicEvernoteInterface) {
1650                         // If no notebooks are selected, we make it look like the "all notebooks" one was selected
1651                         if (selections.size()==0) {
1652                                 selectedNotebookGUIDs.clear();
1653                                 for (int i=0; i < listManager.getNotebookIndex().size(); i++) {
1654                                         selectedNotebookGUIDs.add(listManager.getNotebookIndex().get(i).getGuid());
1655                                 }
1656                                 menuBar.notebookEditAction.setEnabled(false);
1657                                 menuBar.notebookDeleteAction.setEnabled(false);
1658                                 menuBar.notebookStackAction.setEnabled(false);
1659                                 menuBar.notebookIconAction.setEnabled(false);
1660                         }
1661                 }
1662         if (!guid.equals("") && !guid.equals("STACK")) {
1663                 selectedNotebookGUIDs.add(stackName);
1664                 searchField.setTargetNotebook(guid);
1665                 menuBar.notebookIconAction.setEnabled(true);
1666         } else {        // スタック選択
1667                 searchField.setTargetStack(guid);
1668                 menuBar.notebookIconAction.setEnabled(true);
1669                         for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1670                                 Notebook book = listManager.getNotebookIndex().get(j);
1671                                 if (book.getStack() != null && book.getStack().equalsIgnoreCase(stackName)) {
1672                                         selectedNotebookGUIDs.add(book.getGuid());
1673                                 }
1674                         }
1675         }
1676         listManager.setSelectedNotebooks(selectedNotebookGUIDs);
1677         listManager.loadNotesIndex();
1678         noteIndexUpdated(false);
1679         refreshEvernoteNote(true);
1680         listManager.refreshCounters = true;
1681         listManager.refreshCounters();
1682         if (selectedNotebookGUIDs.size() == 1) {
1683                 int col = conn.getNotebookTable().getSortColumn(selectedNotebookGUIDs.get(0));
1684                 int order = conn.getNotebookTable().getSortOrder(selectedNotebookGUIDs.get(0));
1685                 if (col != -1) {
1686                         noteTableView.proxyModel.blocked = true;
1687                         if (order == 1)
1688                                 noteTableView.sortByColumn(col, Qt.SortOrder.DescendingOrder);
1689                         else
1690                                 noteTableView.sortByColumn(col, Qt.SortOrder.AscendingOrder);
1691                 }
1692         }
1693         noteTableView.proxyModel.blocked = false;
1694                 logger.log(logger.HIGH, "Leaving NeverNote.notebookTreeSelection");
1695
1696     }
1697     private void clearNotebookFilter() {
1698         notebookTree.blockSignals(true);
1699         notebookTree.clearSelection();
1700                 menuBar.noteRestoreAction.setVisible(false);
1701         menuBar.notebookEditAction.setEnabled(false);
1702         menuBar.notebookDeleteAction.setEnabled(false);
1703         selectedNotebookGUIDs.clear();
1704         searchField.setTargetNotebook("");
1705         searchField.setTargetStack("");
1706         listManager.setSelectedNotebooks(selectedNotebookGUIDs);
1707         notebookTree.blockSignals(false);
1708     }
1709         // Triggered when the notebook DB has been updated
1710         private void notebookIndexUpdated() {
1711                 logger.log(logger.HIGH, "Entering NeverNote.notebookIndexUpdated");
1712         
1713                 // Get the possible icons
1714                 HashMap<String, QIcon> icons = conn.getNotebookTable().getAllIcons();
1715         notebookTree.setIcons(icons);
1716         
1717         if (selectedNotebookGUIDs == null)
1718                         selectedNotebookGUIDs = new ArrayList<String>();
1719                 List<Notebook> books = conn.getNotebookTable().getAll();
1720                 for (int i=books.size()-1; i>=0; i--) {
1721                         for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
1722                                 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(books.get(i).getGuid())) {
1723                                         books.remove(i);
1724                                         j=listManager.getArchiveNotebookIndex().size();
1725                                 }
1726                         }
1727                 }
1728                 
1729                 
1730                 listManager.countNotebookResults(listManager.getNoteIndex());
1731                 notebookTree.blockSignals(true);
1732         notebookTree.load(books, listManager.getLocalNotebooks());
1733         for (int i=selectedNotebookGUIDs.size()-1; i>=0; i--) {
1734                 boolean found = notebookTree.selectGuid(selectedNotebookGUIDs.get(i));
1735                 if (!found) {
1736                         selectedNotebookGUIDs.remove(i);
1737                         searchField.setTargetNotebook("");
1738                         searchField.setTargetStack("");
1739                 }
1740         }
1741         listManager.refreshCounters = true;
1742         listManager.refreshCounters();
1743         notebookTree.blockSignals(false);
1744         
1745                 logger.log(logger.HIGH, "Leaving NeverNote.notebookIndexUpdated");
1746     }
1747     // Show/Hide note information
1748         @SuppressWarnings("unused")
1749         private void toggleNotebookWindow() {
1750                 logger.log(logger.HIGH, "Entering NeverNote.toggleNotebookWindow");
1751                 zoomLayout.toggleNotebook();
1752         menuBar.hideNotebooks.setChecked(notebookTree.isVisible());
1753         Global.saveWindowVisible("notebookTree", notebookTree.isVisible());
1754         logger.log(logger.HIGH, "Leaving NeverNote.toggleNotebookWindow");
1755     }   
1756         // Add a new notebook
1757         @SuppressWarnings("unused")
1758         private void addNotebook() {
1759                 logger.log(logger.HIGH, "Inside NeverNote.addNotebook");
1760                 NotebookEdit edit = new NotebookEdit();
1761                 edit.setNotebooks(listManager.getNotebookIndex());
1762                 edit.exec();
1763         
1764                 if (!edit.okPressed())
1765                         return;
1766         
1767                 Calendar currentTime = new GregorianCalendar();
1768                 Long l = new Long(currentTime.getTimeInMillis());
1769                 String randint = new String(Long.toString(l));
1770         
1771                 Notebook newBook = new Notebook();
1772                 newBook.setUpdateSequenceNum(0);
1773                 newBook.setGuid(randint);
1774                 newBook.setName(edit.getNotebook());
1775                 newBook.setServiceCreated(new Date().getTime());
1776                 newBook.setServiceUpdated(new Date().getTime());
1777                 newBook.setDefaultNotebook(false);
1778                 newBook.setPublished(false);
1779                 
1780                 listManager.getNotebookIndex().add(newBook);
1781                 if (edit.isLocal())
1782                         listManager.getLocalNotebooks().add(newBook.getGuid());
1783                 conn.getNotebookTable().addNotebook(newBook, true, edit.isLocal());
1784                 notebookIndexUpdated();
1785                 listManager.countNotebookResults(listManager.getNoteIndex());
1786 //              notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
1787                 logger.log(logger.HIGH, "Leaving NeverNote.addNotebook");
1788         }
1789         // Edit an existing notebook
1790         @SuppressWarnings("unused")
1791         private void stackNotebook() {
1792                 logger.log(logger.HIGH, "Entering NeverNote.stackNotebook");
1793                 StackNotebook edit = new StackNotebook();
1794                 
1795                 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1796                 QTreeWidgetItem currentSelection;
1797                 for (int i=0; i<selections.size(); i++) {
1798                         currentSelection = selections.get(0);
1799                         String guid = currentSelection.text(2);
1800                         if (guid.equalsIgnoreCase("")) {
1801                                  QMessageBox.critical(this, tr("Unable To Stack") ,tr("You can't stack the \"All Notebooks\" item."));
1802                                  return;
1803                         }
1804                         if (guid.equalsIgnoreCase("STACK")) {
1805                                  QMessageBox.critical(this, tr("Unable To Stack") ,tr("You can't stack a stack."));
1806                                  return;
1807                         }
1808                 }
1809
1810                 edit.setStackNames(conn.getNotebookTable().getAllStackNames());
1811
1812                 
1813                 edit.exec();
1814         
1815                 if (!edit.okPressed())
1816                         return;
1817         
1818                 String stack = edit.getStackName();
1819                 
1820                 for (int i=0; i<selections.size(); i++) {
1821                         currentSelection = selections.get(i);
1822                         String guid = currentSelection.text(2);
1823                         listManager.updateNotebookStack(guid, stack);
1824                 }
1825                 notebookIndexUpdated();
1826                 logger.log(logger.HIGH, "Leaving NeverNote.stackNotebook");
1827         }
1828         // Edit an existing notebook
1829         @SuppressWarnings("unused")
1830         private void editNotebook() {
1831                 logger.log(logger.HIGH, "Entering NeverNote.editNotebook");
1832                 NotebookEdit edit = new NotebookEdit();
1833                 
1834                 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1835                 QTreeWidgetItem currentSelection;
1836                 currentSelection = selections.get(0);
1837                 edit.setNotebook(currentSelection.text(0));
1838                 
1839                 String guid = currentSelection.text(2);
1840                 if (!guid.equalsIgnoreCase("STACK")) {
1841                         edit.setTitle(tr("Edit Notebook"));
1842                         edit.setNotebooks(listManager.getNotebookIndex());
1843                         edit.setLocalCheckboxEnabled(false);
1844                         for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1845                                 if (listManager.getNotebookIndex().get(i).getGuid().equals(guid)) {
1846                                         edit.setDefaultNotebook(listManager.getNotebookIndex().get(i).isDefaultNotebook());
1847                                         i=listManager.getNotebookIndex().size();
1848                                 }
1849                         }
1850                 } else {
1851                         edit.setTitle(tr("Edit Stack"));
1852                         edit.setStacks(conn.getNotebookTable().getAllStackNames());
1853                         edit.hideLocalCheckbox();
1854                         edit.hideDefaultCheckbox();
1855                 }
1856                 
1857                 edit.exec();
1858         
1859                 if (!edit.okPressed())
1860                         return;
1861         
1862                 
1863                 if (guid.equalsIgnoreCase("STACK")) {
1864                         conn.getNotebookTable().renameStacks(currentSelection.text(0), edit.getNotebook());
1865                         for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1866                                 if (listManager.getNotebookIndex().get(j).getStack() != null && 
1867                                         listManager.getNotebookIndex().get(j).getStack().equalsIgnoreCase(currentSelection.text(0)))
1868                                                 listManager.getNotebookIndex().get(j).setStack(edit.getNotebook());
1869                         }
1870                         conn.getNotebookTable().renameStacks(currentSelection.text(0), edit.getNotebook());
1871                         currentSelection.setText(0, edit.getNotebook());
1872                         return;
1873                 }
1874                 
1875                 updateListNotebookName(currentSelection.text(0), edit.getNotebook());
1876                 currentSelection.setText(0, edit.getNotebook());
1877                 
1878                 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1879                         if (listManager.getNotebookIndex().get(i).getGuid().equals(guid)) {
1880                                 listManager.getNotebookIndex().get(i).setName(edit.getNotebook());
1881                                 if (!listManager.getNotebookIndex().get(i).isDefaultNotebook() && edit.isDefaultNotebook()) {
1882                                         for (int j=0; j<listManager.getNotebookIndex().size(); j++)
1883                                                 listManager.getNotebookIndex().get(j).setDefaultNotebook(false);
1884                                         listManager.getNotebookIndex().get(i).setDefaultNotebook(true);
1885                                         conn.getNotebookTable().setDefaultNotebook(listManager.getNotebookIndex().get(i).getGuid());
1886                                 }
1887                                 conn.getNotebookTable().updateNotebook(listManager.getNotebookIndex().get(i), true);
1888                                 if (conn.getNotebookTable().isLinked(listManager.getNotebookIndex().get(i).getGuid())) {
1889                                         LinkedNotebook linkedNotebook = conn.getLinkedNotebookTable().getByNotebookGuid(listManager.getNotebookIndex().get(i).getGuid());
1890                                         linkedNotebook.setShareName(edit.getNotebook());
1891                                         conn.getLinkedNotebookTable().updateNotebook(linkedNotebook, true);
1892                                 }
1893                                 i=listManager.getNotebookIndex().size();
1894                         }
1895                 }
1896                 
1897                 // Build a list of non-closed notebooks
1898                 List<Notebook> nbooks = new ArrayList<Notebook>();
1899                 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1900                         boolean found=false;
1901                         for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
1902                                 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid()))
1903                                         found = true;
1904                         }
1905                         if (!found)
1906                                 nbooks.add(listManager.getNotebookIndex().get(i));
1907                 }
1908                 
1909                 
1910                 FilterEditorNotebooks notebookFilter = new FilterEditorNotebooks(conn, logger);
1911                 List<Notebook> filteredBooks = notebookFilter.getValidNotebooks(currentNote, listManager.getNotebookIndex());
1912                 browserWindow.setNotebookList(filteredBooks);
1913                 Iterator<String> set = externalWindows.keySet().iterator();
1914                 while(set.hasNext())
1915                         externalWindows.get(set.next()).getBrowserWindow().setNotebookList(filteredBooks);
1916                 
1917                 Iterator<Integer>it = tabWindows.keySet().iterator();
1918                 while (it.hasNext()) {
1919                         tabWindows.get(it.next()).getBrowserWindow()
1920                                         .setNotebookList(filteredBooks);
1921                 }
1922                 
1923                 logger.log(logger.HIGH, "Leaving NeverNote.editNotebook");
1924         }
1925         // Publish a notebook
1926         @SuppressWarnings("unused")
1927         private void publishNotebook() {
1928                 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1929                 QTreeWidgetItem currentSelection;
1930                 currentSelection = selections.get(0);
1931                 String guid = currentSelection.text(2);
1932
1933                 if (guid.equalsIgnoreCase("STACK") || guid.equalsIgnoreCase(""))
1934                         return;
1935                 
1936                 Notebook n = null;
1937                 int position = 0;
1938                 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1939                         if (guid.equals(listManager.getNotebookIndex().get(i).getGuid())) {
1940                                 n = listManager.getNotebookIndex().get(i);
1941                                 position = i;
1942                                 i = listManager.getNotebookIndex().size();
1943                         }
1944                 }
1945                 if (n == null)
1946                         return;
1947                 
1948                 PublishNotebook publish = new PublishNotebook(Global.username, Global.getServer(), n);
1949                 publish.exec();
1950                 
1951                 if (!publish.okClicked()) 
1952                         return;
1953                 
1954                 Publishing p = publish.getPublishing();
1955                 boolean isPublished = !publish.isStopPressed();
1956                 conn.getNotebookTable().setPublishing(n.getGuid(), isPublished, p);
1957                 n.setPublished(isPublished);
1958                 n.setPublishing(p);
1959                 listManager.getNotebookIndex().set(position, n);
1960                 notebookIndexUpdated();
1961         }
1962         // Publish a notebook
1963         @SuppressWarnings("unused")
1964         private void shareNotebook() {
1965                 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1966                 QTreeWidgetItem currentSelection;
1967                 currentSelection = selections.get(0);
1968                 String guid = currentSelection.text(2);
1969
1970                 if (guid.equalsIgnoreCase("STACK") || guid.equalsIgnoreCase(""))
1971                         return;
1972                 
1973                 Notebook n = null;;
1974                 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1975                         if (guid.equals(listManager.getNotebookIndex().get(i).getGuid())) {
1976                                 n = listManager.getNotebookIndex().get(i);
1977                                 i = listManager.getNotebookIndex().size();
1978                         }
1979                 }
1980                                 
1981                 String authToken = null;
1982                 if (syncRunner.isConnected)
1983                         authToken = syncRunner.authToken;
1984                 ShareNotebook share = new ShareNotebook(n.getName(), conn, n, syncRunner);
1985                 share.exec();
1986                 
1987         }
1988
1989         // Delete an existing notebook
1990         @SuppressWarnings("unused")
1991         private void deleteNotebook() {
1992                 logger.log(logger.HIGH, "Entering NeverNote.deleteNotebook");
1993                 boolean stacksFound = false;
1994                 boolean notebooksFound = false;
1995                 boolean assigned = false;
1996                 // Check if any notes have this notebook
1997                 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1998         for (int i=0; i<selections.size(); i++) {
1999                 QTreeWidgetItem currentSelection;
2000                 currentSelection = selections.get(i);
2001                 String guid = currentSelection.text(2);
2002                 if (!guid.equalsIgnoreCase("STACK")) {
2003                         notebooksFound = true;
2004                         for (int j=0; j<listManager.getNoteIndex().size(); j++) {
2005                                 String noteGuid = listManager.getNoteIndex().get(j).getNotebookGuid();
2006                                 if (noteGuid.equals(guid)) {
2007                                         assigned = true;
2008                                         j=listManager.getNoteIndex().size();
2009                                         i=selections.size();
2010                                 }
2011                         }
2012                 } else {
2013                         stacksFound = true;
2014                 }
2015         }
2016                 if (assigned) {
2017                         QMessageBox.information(this, tr("Unable to Delete"), tr("Some of the selected notebook(s) contain notes.\n"+
2018                                         "Please delete the notes or move them to another notebook before deleting any notebooks."));
2019                         return;
2020                 }
2021                 
2022                 if (conn.getNotebookTable().getAll().size() == 1) {
2023                         QMessageBox.information(this, tr("Unable to Delete"), tr("You must have at least one notebook."));
2024                         return;
2025                 }
2026         
2027         // If all notebooks are clear, verify the delete
2028                 String msg1 = new String(tr("Delete selected notebooks?"));
2029                 String msg2 = new String(tr("Remove selected stacks (notebooks will not be deleted)?"));
2030                 String msg3 = new String(tr("Delete selected notebooks & remove stacks? Notebooks under the stacks are" +
2031                                 " not deleted unless selected?"));
2032                 String msg = "";
2033                 if (stacksFound && notebooksFound)
2034                         msg = msg3;
2035                 if (!stacksFound && notebooksFound)
2036                         msg = msg1;
2037                 if (stacksFound && !notebooksFound)
2038                         msg = msg2;
2039                 if (QMessageBox.question(this, tr("Confirmation"), msg,
2040                         QMessageBox.StandardButton.Yes, 
2041                         QMessageBox.StandardButton.No)==StandardButton.No.value()) {
2042                         return;
2043                 }
2044                 
2045                 // If confirmed, delete the notebook
2046         for (int i=selections.size()-1; i>=0; i--) {
2047                 QTreeWidgetItem currentSelection;
2048                 currentSelection = selections.get(i);
2049                 String guid = currentSelection.text(2);
2050                 if (currentSelection.text(2).equalsIgnoreCase("STACK")) {
2051                         conn.getNotebookTable().renameStacks(currentSelection.text(0), "");
2052                         listManager.renameStack(currentSelection.text(0), "");
2053                 } else {
2054                         conn.getNotebookTable().expungeNotebook(guid, true);
2055                         listManager.deleteNotebook(guid);
2056                 }
2057         }
2058
2059                 notebookIndexUpdated();
2060 //        notebookTreeSelection();
2061 //        notebookTree.load(listManager.getNotebookIndex(), listManager.getLocalNotebooks());
2062 //        listManager.countNotebookResults(listManager.getNoteIndex());
2063         logger.log(logger.HIGH, "Entering NeverNote.deleteNotebook");
2064         }
2065         // A note's notebook has been updated
2066         @SuppressWarnings("unused")
2067         private void updateNoteNotebook(String guid, String notebookGuid) {
2068                 // 同じノートブックに入れられたノート間の履歴を登録
2069                 conn.getHistoryTable().addSameNotebookHistory(guid, notebookGuid);
2070                 
2071                 // Update the list manager
2072                 listManager.updateNoteNotebook(guid, notebookGuid);
2073                 listManager.countNotebookResults(listManager.getNoteIndex());
2074 //              notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());    
2075                 
2076                 // Find the name of the notebook
2077                 String notebookName = null;
2078                 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
2079                         if (listManager.getNotebookIndex().get(i).getGuid().equals(notebookGuid)) {
2080                                 notebookName = listManager.getNotebookIndex().get(i).getName();
2081                                 break;
2082                         }
2083                 }
2084                 
2085                 // If we found the name, update the browser window
2086                 if (notebookName != null) {
2087                         updateListNoteNotebook(guid, notebookName);
2088                         if (guid.equals(currentNoteGuid)) {
2089                                 int pos =  browserWindow.notebookBox.findText(notebookName);
2090                                 if (pos >=0)
2091                                         browserWindow.notebookBox.setCurrentIndex(pos);
2092                         }
2093                 }
2094                 
2095                 // If we're dealing with the current note, then we need to be sure and update the notebook there
2096                 if (guid.equals(currentNoteGuid)) {
2097                         if (currentNote != null) {
2098                                 currentNote.setNotebookGuid(notebookGuid);
2099                         }
2100                 }
2101         }
2102         // Open/close notebooks
2103         @SuppressWarnings("unused")
2104         private void closeNotebooks() {
2105                 NotebookArchive na = new NotebookArchive(listManager.getNotebookIndex(), listManager.getArchiveNotebookIndex());
2106                 na.exec();
2107                 if (!na.okClicked())
2108                         return;
2109                 
2110                 waitCursor(true);
2111                 listManager.getArchiveNotebookIndex().clear();
2112                 
2113                 for (int i=na.getClosedBookList().count()-1; i>=0; i--) {
2114                         String text = na.getClosedBookList().takeItem(i).text();
2115                         for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
2116                                 if (listManager.getNotebookIndex().get(j).getName().equalsIgnoreCase(text)) {
2117                                         Notebook n = listManager.getNotebookIndex().get(j);
2118                                         conn.getNotebookTable().setArchived(n.getGuid(),true);
2119                                         listManager.getArchiveNotebookIndex().add(n);
2120                                         j=listManager.getNotebookIndex().size();
2121                                 }
2122                         }
2123                 }
2124                 
2125                 for (int i=na.getOpenBookList().count()-1; i>=0; i--) {
2126                         String text = na.getOpenBookList().takeItem(i).text();
2127                         for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
2128                                 if (listManager.getNotebookIndex().get(j).getName().equalsIgnoreCase(text)) {
2129                                         Notebook n = listManager.getNotebookIndex().get(j);
2130                                         conn.getNotebookTable().setArchived(n.getGuid(),false);
2131                                         j=listManager.getNotebookIndex().size();
2132                                 }
2133                         }
2134                 }
2135                 notebookTreeSelection();
2136                 listManager.loadNotesIndex();
2137                 notebookIndexUpdated();
2138                 noteIndexUpdated(false);
2139                 reloadTagTree(true);
2140 //              noteIndexUpdated(false);
2141                 
2142                 // Build a list of non-closed notebooks
2143                 List<Notebook> nbooks = new ArrayList<Notebook>();
2144                 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
2145                         boolean found=false;
2146                         for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
2147                                 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid()))
2148                                         found = true;
2149                         }
2150                         if (!found)
2151                                 nbooks.add(listManager.getNotebookIndex().get(i));
2152                 }
2153                 
2154                 FilterEditorNotebooks notebookFilter = new FilterEditorNotebooks(conn, logger);
2155                 List<Notebook> filteredBooks = notebookFilter.getValidNotebooks(currentNote, listManager.getNotebookIndex());
2156                 browserWindow.setNotebookList(filteredBooks);
2157                 
2158                 // Update any external windows
2159                 Iterator<String> set = externalWindows.keySet().iterator();
2160                 while(set.hasNext())
2161                         externalWindows.get(set.next()).getBrowserWindow().setNotebookList(filteredBooks);
2162                 
2163                 // 全てのタブウィンドウを更新
2164                 Iterator<Integer> it = tabWindows.keySet().iterator();
2165                 while (it.hasNext()) {
2166                         tabWindows.get(it.next()).getBrowserWindow()
2167                                         .setNotebookList(filteredBooks);
2168                 }
2169                 
2170                 waitCursor(false);
2171         }
2172         // Change the notebook's icon
2173         @SuppressWarnings("unused")
2174         private void setNotebookIcon() {
2175                 boolean stackSelected = false;
2176                 boolean allNotebookSelected = false;
2177                 
2178                 QTreeWidgetItem currentSelection;
2179                 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
2180                 if (selections.size() == 0)
2181                         return;
2182                 
2183                 currentSelection = selections.get(0);   
2184                 String guid = currentSelection.text(2);
2185                 if (guid.equalsIgnoreCase(""))
2186                         allNotebookSelected = true;
2187                 if (guid.equalsIgnoreCase("STACK"))
2188                         stackSelected = true;
2189
2190                 QIcon currentIcon = currentSelection.icon(0);
2191                 QIcon icon;
2192                 SetIcon dialog;
2193                 
2194                 if (!stackSelected && !allNotebookSelected) {
2195                         icon = conn.getNotebookTable().getIcon(guid);
2196                         if (icon == null) {
2197                                 dialog = new SetIcon(currentIcon, saveLastPath);
2198                                 dialog.setUseDefaultIcon(true);
2199                         } else {
2200                                 dialog = new SetIcon(icon, saveLastPath);
2201                                 dialog.setUseDefaultIcon(false);
2202                         }
2203                 } else {
2204                         if (stackSelected) {
2205                                 icon = conn.getSystemIconTable().getIcon(currentSelection.text(0), "STACK");
2206                         } else {
2207                                 icon = conn.getSystemIconTable().getIcon(currentSelection.text(0), "ALLNOTEBOOK");                              
2208                         }
2209                         if (icon == null) {
2210                                 dialog = new SetIcon(currentIcon, saveLastPath);
2211                                 dialog.setUseDefaultIcon(true);
2212                         } else {
2213                                 dialog = new SetIcon(icon, saveLastPath);
2214                                 dialog.setUseDefaultIcon(false);
2215                         }
2216                 }
2217                 dialog.exec();
2218                 if (dialog.okPressed()) {
2219                 saveLastPath = dialog.getPath();
2220
2221                         QIcon newIcon = dialog.getIcon();
2222                         if (stackSelected) {
2223                                 conn.getSystemIconTable().setIcon(currentSelection.text(0), "STACK", newIcon, dialog.getFileType());
2224                                 if (newIcon == null) {
2225                                         newIcon = new QIcon(iconPath+"books2.png");
2226                                 }
2227                                 currentSelection.setIcon(0,newIcon);
2228                                 return;
2229                         }
2230                         if (allNotebookSelected) {
2231                                 conn.getSystemIconTable().setIcon(currentSelection.text(0), "ALLNOTEBOOK", newIcon, dialog.getFileType());
2232                                 if (newIcon == null) {
2233                                         newIcon = new QIcon(iconPath+"notebook-green.png");
2234                                 }
2235                                 currentSelection.setIcon(0,newIcon);
2236                                 return;
2237                         }
2238                         conn.getNotebookTable().setIcon(guid, newIcon, dialog.getFileType());
2239                         if (newIcon == null) {
2240                                 boolean isPublished = false;;
2241                                 boolean found = false;
2242                                 for (int i=0; i<listManager.getNotebookIndex().size() && !found; i++) {
2243                                         if (listManager.getNotebookIndex().get(i).getGuid().equals(guid)) {
2244                                                 isPublished = listManager.getNotebookIndex().get(i).isPublished();
2245                                                 found = true;
2246                                         }
2247                                 }
2248                                 newIcon = notebookTree.findDefaultIcon(guid, currentSelection.text(1), listManager.getLocalNotebooks(), isPublished);
2249                         }
2250                         currentSelection.setIcon(0, newIcon);
2251                 }
2252         
2253         }
2254         
2255         
2256     //***************************************************************
2257     //***************************************************************
2258     //** These functions deal with Tag menu items
2259     //***************************************************************
2260     //***************************************************************
2261         // Add a new notebook
2262         @SuppressWarnings("unused")
2263         private void addTag() {
2264                 logger.log(logger.HIGH, "Inside NeverNote.addTag");
2265                 TagEdit edit = new TagEdit();
2266                 edit.setTagList(listManager.getTagIndex());
2267
2268                 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2269                 QTreeWidgetItem currentSelection = null;
2270                 if (selections.size() > 0) {
2271                         currentSelection = selections.get(0);
2272                         edit.setParentTag(currentSelection.text(0));
2273                 }
2274
2275                 edit.exec();
2276         
2277                 if (!edit.okPressed())
2278                         return;
2279         
2280                 Calendar currentTime = new GregorianCalendar();
2281                 Long l = new Long(currentTime.getTimeInMillis());
2282                 String randint = new String(Long.toString(l));
2283         
2284                 Tag newTag = new Tag();
2285                 newTag.setUpdateSequenceNum(0);
2286                 newTag.setGuid(randint);
2287                 newTag.setName(edit.getTag());
2288                 if (edit.getParentTag().isChecked()) {
2289                         newTag.setParentGuid(currentSelection.text(2));
2290                         newTag.setParentGuidIsSet(true);
2291                         currentSelection.setExpanded(true);
2292                 }
2293                 conn.getTagTable().addTag(newTag, true);
2294                 listManager.getTagIndex().add(newTag);
2295                 reloadTagTree(true);
2296                 
2297                 logger.log(logger.HIGH, "Leaving NeverNote.addTag");
2298         }
2299         @SuppressWarnings("unused")
2300         private void reloadTagTree() {
2301                 reloadTagTree(false);
2302         }
2303         private void reloadTagTree(boolean reload) {
2304                 logger.log(logger.HIGH, "Entering NeverNote.reloadTagTree");
2305                 tagIndexUpdated(reload);
2306                 boolean filter = false;
2307                 if (reload)
2308                         listManager.countTagResults(listManager.getNoteIndex());
2309                 if (notebookTree.selectedItems().size() > 0 
2310                                                   && !notebookTree.selectedItems().get(0).text(0).equalsIgnoreCase("All Notebooks"))
2311                                                   filter = true;
2312                 if (tagTree.selectedItems().size() > 0)
2313                         filter = true;
2314                 tagTree.showAllTags(!filter);
2315                 tagIndexUpdated(false);
2316                 logger.log(logger.HIGH, "Leaving NeverNote.reloadTagTree");
2317         }
2318         // Edit an existing tag
2319         @SuppressWarnings("unused")
2320         private void editTag() {
2321                 logger.log(logger.HIGH, "Entering NeverNote.editTag");
2322                 TagEdit edit = new TagEdit();
2323                 edit.setTitle("Edit Tag");
2324                 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2325                 QTreeWidgetItem currentSelection;
2326                 currentSelection = selections.get(0);
2327                 edit.setTag(currentSelection.text(0));
2328                 edit.setTagList(listManager.getTagIndex());
2329                 edit.exec();
2330         
2331                 if (!edit.okPressed())
2332                         return;
2333         
2334                 String guid = currentSelection.text(2);
2335                 currentSelection.setText(0,edit.getTag());
2336                 
2337                 for (int i=0; i<listManager.getTagIndex().size(); i++) {
2338                         if (listManager.getTagIndex().get(i).getGuid().equals(guid)) {
2339                                 listManager.getTagIndex().get(i).setName(edit.getTag());
2340                                 conn.getTagTable().updateTag(listManager.getTagIndex().get(i), true);
2341                                 updateListTagName(guid);
2342                                 if (currentNote != null && currentNote.getTagGuids().contains(guid))
2343                                         browserWindow.setTag(getTagNamesForNote(currentNote));
2344                                 logger.log(logger.HIGH, "Leaving NeverNote.editTag");
2345                                 //return;
2346                         }
2347                 }
2348                 listManager.reloadNoteTagNames(guid, edit.getTag());
2349                 noteIndexUpdated(true);
2350                 refreshEvernoteNote(true);
2351                 browserWindow.setTag(getTagNamesForNote(currentNote));
2352                 logger.log(logger.HIGH, "Leaving NeverNote.editTag...");
2353         }
2354         // Delete an existing tag
2355         @SuppressWarnings("unused")
2356         private void deleteTag() {
2357                 logger.log(logger.HIGH, "Entering NeverNote.deleteTag");
2358                 
2359                 if (QMessageBox.question(this, tr("Confirmation"), tr("Delete the selected tags?"),
2360                         QMessageBox.StandardButton.Yes, 
2361                         QMessageBox.StandardButton.No)==StandardButton.No.value()) {
2362                                                         return;
2363                 }
2364                 
2365                 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2366         for (int i=selections.size()-1; i>=0; i--) {
2367                 QTreeWidgetItem currentSelection;
2368                 currentSelection = selections.get(i);                   
2369                 removeTagItem(currentSelection.text(2));
2370         }
2371         tagIndexUpdated(true);
2372         tagTreeSelection();
2373         listManager.countTagResults(listManager.getNoteIndex());
2374 //              tagTree.updateCounts(listManager.getTagCounter());
2375         logger.log(logger.HIGH, "Leaving NeverNote.deleteTag");
2376         }
2377         // Remove a tag tree item.  Go recursively down & remove the children too
2378         private void removeTagItem(String guid) {
2379         for (int j=listManager.getTagIndex().size()-1; j>=0; j--) {             
2380                 String parent = listManager.getTagIndex().get(j).getParentGuid();
2381                 if (parent != null && parent.equals(guid)) {            
2382                         //Remove this tag's children
2383                         removeTagItem(listManager.getTagIndex().get(j).getGuid());
2384                 }
2385         }
2386         //Now, remove this tag
2387         removeListTagName(guid);
2388         conn.getTagTable().expungeTag(guid, true);                      
2389         for (int a=0; a<listManager.getTagIndex().size(); a++) {
2390                 if (listManager.getTagIndex().get(a).getGuid().equals(guid)) {
2391                         listManager.getTagIndex().remove(a);
2392                         return;
2393                 }
2394         }
2395         }
2396         // Setup the tree containing the user's tags
2397     private void initializeTagTree() {
2398         logger.log(logger.HIGH, "Entering NeverNote.initializeTagTree");
2399 //      tagTree.itemSelectionChanged.connect(this, "tagTreeSelection()");
2400 //      tagTree.itemClicked.connect(this, "tagTreeSelection()");
2401         tagTree.selectionSignal.connect(this, "tagTreeSelection()");
2402         listManager.tagSignal.refreshTagTreeCounts.connect(tagTree, "updateCounts(List)");
2403         logger.log(logger.HIGH, "Leaving NeverNote.initializeTagTree");
2404     }
2405     // Listener when a tag is selected
2406         private void tagTreeSelection() {
2407         logger.log(logger.HIGH, "Entering NeverNote.tagTreeSelection");
2408                 
2409         clearTrashFilter();
2410         clearAttributeFilter();
2411         clearSavedSearchFilter();
2412         
2413                 menuBar.noteRestoreAction.setVisible(false);
2414                 
2415                 // ゴミ箱から元の画面に戻す。連想ノートリストをONに。
2416                 if (!rensoNoteListDock.isEnabled()) {
2417                         rensoNoteListDock.setEnabled(true);
2418                 }
2419                 
2420         List<QTreeWidgetItem> selections = tagTree.selectedItems();
2421         QTreeWidgetItem currentSelection;
2422         selectedTagGUIDs.clear();
2423         searchField.getTargetTags().clear();
2424         for (int i=0; i<selections.size(); i++) {
2425                 currentSelection = selections.get(i);
2426                 selectedTagGUIDs.add(currentSelection.text(2));
2427                 searchField.addTargetTag(currentSelection.text(2));
2428         }
2429         if (selections.size() > 0) {
2430                 menuBar.tagEditAction.setEnabled(true);
2431                 menuBar.tagDeleteAction.setEnabled(true);
2432                 menuBar.tagIconAction.setEnabled(true);
2433         }
2434         else {
2435                 menuBar.tagEditAction.setEnabled(false);
2436                 menuBar.tagDeleteAction.setEnabled(false);
2437                 menuBar.tagIconAction.setEnabled(true);
2438         }
2439         if (selections.size() > 1)
2440                 menuBar.tagMergeAction.setEnabled(true);
2441         else
2442                 menuBar.tagMergeAction.setEnabled(false);
2443         listManager.setSelectedTags(selectedTagGUIDs);
2444         listManager.loadNotesIndex();
2445         noteIndexUpdated(false);
2446         refreshEvernoteNote(true);
2447         listManager.refreshCounters = true;
2448         listManager.refreshCounters();
2449         logger.log(logger.HIGH, "Leaving NeverNote.tagTreeSelection");
2450     }
2451     // trigger the tag index to be refreshed
2452     @SuppressWarnings("unused")
2453         private void tagIndexUpdated() {
2454         tagIndexUpdated(true);
2455     }
2456     private void tagIndexUpdated(boolean reload) {
2457         logger.log(logger.HIGH, "Entering NeverNote.tagIndexUpdated");
2458                 if (selectedTagGUIDs == null)
2459                         selectedTagGUIDs = new ArrayList<String>();
2460                 if (reload)
2461                         listManager.reloadTagIndex();
2462
2463                 tagTree.blockSignals(true);
2464                 if (reload) {
2465                         tagTree.setIcons(conn.getTagTable().getAllIcons());
2466                         tagTree.load(listManager.getTagIndex());
2467                 }
2468
2469         for (int i=selectedTagGUIDs.size()-1; i>=0; i--) {
2470                 boolean found = tagTree.selectGuid(selectedTagGUIDs.get(i));
2471                 if (!found) {
2472                         selectedTagGUIDs.remove(i);
2473                         searchField.getTargetTags().remove(i);
2474                 }
2475         }
2476         tagTree.blockSignals(false);
2477         
2478                 browserWindow.setTag(getTagNamesForNote(currentNote));
2479         logger.log(logger.HIGH, "Leaving NeverNote.tagIndexUpdated");
2480     }   
2481     // Show/Hide note information
2482         @SuppressWarnings("unused")
2483         private void toggleTagWindow() {
2484                 logger.log(logger.HIGH, "Entering NeverNote.toggleTagWindow");
2485         if (tagTree.isVisible())
2486                 tagTree.hide();
2487         else
2488                 tagTree.show();
2489         menuBar.hideTags.setChecked(tagTree.isVisible());
2490         Global.saveWindowVisible("tagTree", tagTree.isVisible());
2491         logger.log(logger.HIGH, "Leaving NeverNote.toggleTagWindow");
2492     }   
2493         // A note's tags have been updated
2494         @SuppressWarnings("unused")
2495         private void updateNoteTags(String guid, List<String> tags) {
2496                 // Save any new tags.  We'll need them later.
2497                 List<String> newTags = new ArrayList<String>();
2498                 for (int i=0; i<tags.size(); i++) {
2499                         if (conn.getTagTable().findTagByName(tags.get(i))==null) 
2500                                 newTags.add(tags.get(i));
2501                 }
2502                 
2503                 listManager.saveNoteTags(guid, tags, true);
2504                 listManager.countTagResults(listManager.getNoteIndex());
2505                 StringBuffer names = new StringBuffer("");
2506                 for (int i=0; i<tags.size(); i++) {
2507                         names = names.append(tags.get(i));
2508                         if (i<tags.size()-1) {
2509                                 names.append(Global.tagDelimeter + " ");
2510                         }
2511                 }
2512                 browserWindow.setTag(names.toString());
2513                 
2514                 for (TabBrowse tab: tabWindows.values()) {
2515                         if (tab.getBrowserWindow().getNote().getGuid().equals(guid)) {
2516                                 int index = tabBrowser.indexOf(tab);
2517                                 noteDirty.put(index, true);
2518                                 break;
2519                         }
2520                 }
2521                 
2522                 // Now, we need to add any new tags to the tag tree
2523                 for (int i=0; i<newTags.size(); i++) 
2524                         tagTree.insertTag(newTags.get(i), conn.getTagTable().findTagByName(newTags.get(i)));
2525         }
2526         // Get a string containing all tag names for a note
2527         private String getTagNamesForNote(Note n) {
2528                 logger.log(logger.HIGH, "Entering NeverNote.getTagNamesForNote");
2529                 if (n==null || n.getGuid() == null || n.getGuid().equals(""))
2530                         return "";
2531                 StringBuffer buffer = new StringBuffer(100);
2532                 Vector<String> v = new Vector<String>();
2533                 List<String> guids = n.getTagGuids();
2534                 
2535                 if (guids == null) 
2536                         return "";
2537                 
2538                 for (int i=0; i<guids.size(); i++) {
2539                         v.add(listManager.getTagNameByGuid(guids.get(i)));
2540                 }
2541                 Comparator<String> comparator = Collections.reverseOrder();
2542                 Collections.sort(v,comparator);
2543                 Collections.reverse(v);
2544                 
2545                 for (int i = 0; i<v.size(); i++) {
2546                         if (i>0) 
2547                                 buffer.append(", ");
2548                         buffer.append(v.get(i));
2549                 }
2550                 
2551                 logger.log(logger.HIGH, "Leaving NeverNote.getTagNamesForNote");
2552                 return buffer.toString();
2553         }       
2554         // Tags were added via dropping notes from the note list
2555         @SuppressWarnings("unused")
2556         private void tagsAdded(String noteGuid, String tagGuid) {
2557                 String tagName = null;
2558                 for (int i=0; i<listManager.getTagIndex().size(); i++) {
2559                         if (listManager.getTagIndex().get(i).getGuid().equals(tagGuid)) {
2560                                 tagName = listManager.getTagIndex().get(i).getName();
2561                                 i=listManager.getTagIndex().size();
2562                         }
2563                 }
2564                 if (tagName == null)
2565                         return;
2566                 
2567                 for (int i=0; i<listManager.getMasterNoteIndex().size(); i++) {
2568                         if (listManager.getMasterNoteIndex().get(i).getGuid().equals(noteGuid)) {
2569                                 List<String> tagNames = new ArrayList<String>();
2570                                 tagNames.add(new String(tagName));
2571                                 Note n = listManager.getMasterNoteIndex().get(i);
2572                                 for (int j=0; j<n.getTagNames().size(); j++) {
2573                                         tagNames.add(new String(n.getTagNames().get(j)));
2574                                 }
2575                                 listManager.getNoteTableModel().updateNoteTags(noteGuid, n.getTagGuids(), tagNames);
2576                                 if (n.getGuid().equals(currentNoteGuid)) {
2577                                         Collections.sort(tagNames);
2578                                         String display = "";
2579                                         for (int j=0; j<tagNames.size(); j++) {
2580                                                 display = display+tagNames.get(j);
2581                                                 if (j+2<tagNames.size()) 
2582                                                         display = display+Global.tagDelimeter+" ";
2583                                         }
2584                                         browserWindow.setTag(display);
2585                                 }
2586                                 i=listManager.getMasterNoteIndex().size();
2587                         }
2588                 }
2589                 
2590                 
2591                 listManager.getNoteTableModel().updateNoteSyncStatus(noteGuid, false);
2592         }
2593         private void clearTagFilter() {
2594                 tagTree.blockSignals(true);
2595                 tagTree.clearSelection();
2596                 menuBar.noteRestoreAction.setVisible(false);
2597                 menuBar.tagEditAction.setEnabled(false);
2598                 menuBar.tagMergeAction.setEnabled(false);
2599                 menuBar.tagDeleteAction.setEnabled(false);
2600                 menuBar.tagIconAction.setEnabled(false);
2601                 selectedTagGUIDs.clear();
2602                 searchField.getTargetTags().clear();
2603         listManager.setSelectedTags(selectedTagGUIDs);
2604         tagTree.blockSignals(false);
2605         }
2606         // Change the icon for a tag
2607         @SuppressWarnings("unused")
2608         private void setTagIcon() {
2609                 QTreeWidgetItem currentSelection;
2610                 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2611                 if (selections.size() == 0)
2612                         return;
2613                 
2614                 currentSelection = selections.get(0);   
2615                 String guid = currentSelection.text(2);
2616
2617                 QIcon currentIcon = currentSelection.icon(0);
2618                 QIcon icon = conn.getTagTable().getIcon(guid);
2619                 SetIcon dialog;
2620                 if (icon == null) {
2621                         dialog = new SetIcon(currentIcon, saveLastPath);
2622                         dialog.setUseDefaultIcon(true);
2623                 } else {
2624                         dialog = new SetIcon(icon, saveLastPath);
2625                         dialog.setUseDefaultIcon(false);
2626                 }
2627                 dialog.exec();
2628                 if (dialog.okPressed()) {
2629                 saveLastPath = dialog.getPath();
2630                         QIcon newIcon = dialog.getIcon();
2631                         conn.getTagTable().setIcon(guid, newIcon, dialog.getFileType());
2632                         if (newIcon == null) 
2633                                 newIcon = new QIcon(iconPath+"tag.png");
2634                         currentSelection.setIcon(0, newIcon);
2635                 }
2636         
2637         }
2638         // Merge tags
2639         @SuppressWarnings("unused")
2640         private void mergeTags() {
2641                 List<Tag> tags = new ArrayList<Tag>();
2642                 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2643                 for (int i=0; i<selections.size(); i++) {
2644                         Tag record = new Tag();
2645                         record.setGuid(selections.get(i).text(2));
2646                         record.setName(selections.get(i).text(0));
2647                         tags.add(record);
2648                 }
2649
2650                 TagMerge mergeDialog = new TagMerge(tags);
2651                 mergeDialog.exec();
2652                 if (!mergeDialog.okClicked())
2653                         return;
2654                 String newGuid = mergeDialog.getNewTagGuid();
2655                 
2656                 for (int i=0; i<tags.size(); i++) {
2657                         if (!tags.get(i).getGuid().equals(newGuid)) {
2658                                 List<String> noteGuids = conn.getNoteTable().noteTagsTable.getTagNotes(tags.get(i).getGuid());
2659                                 for (int j=0; j<noteGuids.size(); j++) {
2660                                         String noteGuid = noteGuids.get(j);
2661                                         conn.getNoteTable().noteTagsTable.deleteNoteTag(noteGuid);
2662                                         if (!conn.getNoteTable().noteTagsTable.checkNoteNoteTags(noteGuid, newGuid))
2663                                                 conn.getNoteTable().noteTagsTable.saveNoteTag(noteGuid, newGuid, true);
2664                                 }
2665                         }
2666                 }
2667                 listManager.reloadIndexes();
2668         }
2669         
2670     //***************************************************************
2671     //***************************************************************
2672     //** These functions deal with Saved Search menu items
2673     //***************************************************************
2674     //***************************************************************
2675         // Add a new notebook
2676         @SuppressWarnings("unused")
2677         private void addSavedSearch() {
2678                 logger.log(logger.HIGH, "Inside NeverNote.addSavedSearch");
2679                 SavedSearchEdit edit = new SavedSearchEdit();
2680                 edit.setSearchList(listManager.getSavedSearchIndex());
2681                 edit.exec();
2682         
2683                 if (!edit.okPressed())
2684                         return;
2685         
2686                 Calendar currentTime = new GregorianCalendar();         
2687                 Long l = new Long(currentTime.getTimeInMillis());
2688                 String randint = new String(Long.toString(l));
2689         
2690                 SavedSearch search = new SavedSearch();
2691                 search.setUpdateSequenceNum(0);
2692                 search.setGuid(randint);
2693                 search.setName(edit.getName());
2694                 search.setQuery(edit.getQuery());
2695                 search.setFormat(QueryFormat.USER);
2696                 listManager.getSavedSearchIndex().add(search);
2697                 conn.getSavedSearchTable().addSavedSearch(search, true);
2698                 savedSearchIndexUpdated();
2699                 logger.log(logger.HIGH, "Leaving NeverNote.addSavedSearch");
2700         }
2701         // Edit an existing tag
2702         @SuppressWarnings("unused")
2703         private void editSavedSearch() {
2704                 logger.log(logger.HIGH, "Entering NeverNote.editSavedSearch");
2705                 SavedSearchEdit edit = new SavedSearchEdit();
2706                 edit.setTitle(tr("Edit Search"));
2707                 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2708                 QTreeWidgetItem currentSelection;
2709                 currentSelection = selections.get(0);
2710                 String guid = currentSelection.text(1);
2711                 SavedSearch s = conn.getSavedSearchTable().getSavedSearch(guid);
2712                 edit.setName(currentSelection.text(0));
2713                 edit.setQuery(s.getQuery());
2714                 edit.setSearchList(listManager.getSavedSearchIndex());
2715                 edit.exec();
2716         
2717                 if (!edit.okPressed())
2718                         return;
2719         
2720                 List<SavedSearch> list = listManager.getSavedSearchIndex();
2721                 SavedSearch search = null;
2722                 boolean found = false;
2723                 for (int i=0; i<list.size(); i++) {
2724                         search = list.get(i);
2725                         if (search.getGuid().equals(guid)) {
2726                                 i=list.size();
2727                                 found = true;
2728                         }
2729                 }
2730                 if (!found)
2731                         return;
2732                 search.setName(edit.getName());
2733                 search.setQuery(edit.getQuery());
2734                 conn.getSavedSearchTable().updateSavedSearch(search, true);
2735                 savedSearchIndexUpdated();
2736                 logger.log(logger.HIGH, "Leaving NeverNote.editSavedSearch");
2737         }
2738         // Delete an existing tag
2739         @SuppressWarnings("unused")
2740         private void deleteSavedSearch() {
2741                 logger.log(logger.HIGH, "Entering NeverNote.deleteSavedSearch");
2742                 
2743                 if (QMessageBox.question(this, tr("Confirmation"), tr("Delete the selected search?"),
2744                         QMessageBox.StandardButton.Yes, 
2745                         QMessageBox.StandardButton.No)==StandardButton.No.value()) {
2746                                                         return;
2747                 }
2748                 
2749                 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2750         for (int i=selections.size()-1; i>=0; i--) {
2751                 QTreeWidgetItem currentSelection;
2752                 currentSelection = selections.get(i);
2753                 for (int j=0; j<listManager.getSavedSearchIndex().size(); j++) {
2754                         if (listManager.getSavedSearchIndex().get(j).getGuid().equals(currentSelection.text(1))) {
2755                                 conn.getSavedSearchTable().expungeSavedSearch(listManager.getSavedSearchIndex().get(j).getGuid(), true);
2756                                 listManager.getSavedSearchIndex().remove(j);
2757                                 j=listManager.getSavedSearchIndex().size()+1;
2758                         }
2759                 }
2760                 selections.remove(i);
2761         }
2762         savedSearchIndexUpdated();
2763         logger.log(logger.HIGH, "Leaving NeverNote.deleteSavedSearch");
2764         }
2765     // Setup the tree containing the user's tags
2766     private void initializeSavedSearchTree() {
2767         logger.log(logger.HIGH, "Entering NeverNote.initializeSavedSearchTree");
2768         savedSearchTree.itemSelectionChanged.connect(this, "savedSearchTreeSelection()");
2769         logger.log(logger.HIGH, "Leaving NeverNote.initializeSavedSearchTree");
2770     }
2771     // Listener when a tag is selected
2772     @SuppressWarnings("unused")
2773         private void savedSearchTreeSelection() {
2774         logger.log(logger.HIGH, "Entering NeverNote.savedSearchTreeSelection");
2775
2776         clearNotebookFilter();
2777         clearTagFilter();
2778         clearTrashFilter();
2779         clearAttributeFilter();
2780         
2781         String currentGuid = selectedSavedSearchGUID;
2782         menuBar.savedSearchEditAction.setEnabled(true);
2783         menuBar.savedSearchDeleteAction.setEnabled(true);
2784         menuBar.savedSearchIconAction.setEnabled(true);
2785         
2786                 // ゴミ箱から元の画面に戻す。連想ノートリストをONに。
2787                 if (!rensoNoteListDock.isEnabled()) {
2788                         rensoNoteListDock.setEnabled(true);
2789                 }
2790                 
2791         List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2792         QTreeWidgetItem currentSelection;
2793         selectedSavedSearchGUID = "";
2794         for (int i=0; i<selections.size(); i++) {
2795                 currentSelection = selections.get(i);
2796                 if (currentSelection.text(1).equals(currentGuid)) {
2797                         currentSelection.setSelected(false);
2798                 } else {
2799                         selectedSavedSearchGUID = currentSelection.text(1);
2800                 }
2801 //              i = selections.size() +1;
2802         }
2803         
2804         // There is the potential for no notebooks to be selected if this 
2805         // happens then we make it look like all notebooks were selecetd.
2806         // If that happens, just select the "all notebooks"
2807         if (selections.size()==0) {
2808                 clearSavedSearchFilter();
2809         }
2810         listManager.setSelectedSavedSearch(selectedSavedSearchGUID);
2811         
2812         logger.log(logger.HIGH, "Leaving NeverNote.savedSearchTreeSelection");
2813     }
2814     private void clearSavedSearchFilter() {
2815         menuBar.savedSearchEditAction.setEnabled(false);
2816         menuBar.savedSearchDeleteAction.setEnabled(false);
2817         menuBar.savedSearchIconAction.setEnabled(false);
2818         savedSearchTree.blockSignals(true);
2819         savedSearchTree.clearSelection();
2820         savedSearchTree.blockSignals(false);
2821         selectedSavedSearchGUID = "";
2822         searchField.setText("");
2823         searchPerformed = false;
2824         listManager.setSelectedSavedSearch(selectedSavedSearchGUID);
2825     }
2826     // trigger the tag index to be refreshed
2827         private void savedSearchIndexUpdated() { 
2828                 if (selectedSavedSearchGUID == null)
2829                         selectedSavedSearchGUID = new String();
2830                 savedSearchTree.blockSignals(true);
2831                 savedSearchTree.setIcons(conn.getSavedSearchTable().getAllIcons());
2832         savedSearchTree.load(listManager.getSavedSearchIndex());
2833         savedSearchTree.selectGuid(selectedSavedSearchGUID);
2834         savedSearchTree.blockSignals(false);
2835     }
2836     // trigger when the saved search selection changes
2837     @SuppressWarnings("unused")
2838         private void updateSavedSearchSelection() {
2839                 logger.log(logger.HIGH, "Entering NeverNote.updateSavedSearchSelection()");
2840                 
2841         menuBar.savedSearchEditAction.setEnabled(true);
2842         menuBar.savedSearchDeleteAction.setEnabled(true);
2843         menuBar.savedSearchIconAction.setEnabled(true);
2844         List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2845
2846         if (selections.size() > 0) {
2847                 menuBar.savedSearchEditAction.setEnabled(true);
2848                 menuBar.savedSearchDeleteAction.setEnabled(true);
2849                 menuBar.savedSearchIconAction.setEnabled(true);
2850                 selectedSavedSearchGUID = selections.get(0).text(1);
2851                 SavedSearch s = conn.getSavedSearchTable().getSavedSearch(selectedSavedSearchGUID);
2852                 searchField.setText(s.getQuery());
2853         } else { 
2854                 menuBar.savedSearchEditAction.setEnabled(false);
2855                 menuBar.savedSearchDeleteAction.setEnabled(false);
2856                 menuBar.savedSearchIconAction.setEnabled(false);
2857                 selectedSavedSearchGUID = "";
2858                 searchField.setText("");
2859         }
2860         searchFieldChanged();
2861         
2862                 logger.log(logger.HIGH, "Leaving NeverNote.updateSavedSearchSelection()");
2863
2864         
2865     }
2866     // Show/Hide note information
2867         @SuppressWarnings("unused")
2868         private void toggleSavedSearchWindow() {
2869                 logger.log(logger.HIGH, "Entering NeverNote.toggleSavedSearchWindow");
2870         if (savedSearchTree.isVisible())
2871                 savedSearchTree.hide();
2872         else
2873                 savedSearchTree.show();
2874         menuBar.hideSavedSearches.setChecked(savedSearchTree.isVisible());
2875                                 
2876                 Global.saveWindowVisible("savedSearchTree", savedSearchTree.isVisible());
2877         logger.log(logger.HIGH, "Leaving NeverNote.toggleSavedSearchWindow");
2878     }
2879         // Change the icon for a saved search
2880         @SuppressWarnings("unused")
2881         private void setSavedSearchIcon() {
2882                 QTreeWidgetItem currentSelection;
2883                 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2884                 if (selections.size() == 0)
2885                         return;
2886                 
2887                 currentSelection = selections.get(0);   
2888                 String guid = currentSelection.text(1);
2889
2890                 QIcon currentIcon = currentSelection.icon(0);
2891                 QIcon icon = conn.getSavedSearchTable().getIcon(guid);
2892                 SetIcon dialog;
2893                 if (icon == null) {
2894                         dialog = new SetIcon(currentIcon, saveLastPath);
2895                         dialog.setUseDefaultIcon(true);
2896                 } else {
2897                         dialog = new SetIcon(icon, saveLastPath);
2898                         dialog.setUseDefaultIcon(false);
2899                 }
2900                 dialog.exec();
2901                 if (dialog.okPressed()) {
2902                 saveLastPath = dialog.getPath();
2903                         QIcon newIcon = dialog.getIcon();
2904                         conn.getSavedSearchTable().setIcon(guid, newIcon, dialog.getFileType());
2905                         if (newIcon == null) 
2906                                 newIcon = new QIcon(iconPath+"search.png");
2907                         currentSelection.setIcon(0, newIcon);
2908                 }
2909         
2910         }
2911         
2912         
2913         
2914         
2915     //***************************************************************
2916     //***************************************************************
2917     //** These functions deal with Help menu & tool menu items
2918     //***************************************************************
2919     //***************************************************************
2920         // Show database status
2921         @SuppressWarnings("unused")
2922         private void databaseStatus() {
2923                 waitCursor(true);
2924                 indexRunner.interrupt = true;
2925                 int dirty = conn.getNoteTable().getDirtyCount();
2926                 int unindexed = conn.getNoteTable().getUnindexedCount();
2927                 DatabaseStatus status = new DatabaseStatus();
2928                 status.setUnsynchronized(dirty);
2929                 status.setUnindexed(unindexed);
2930                 status.setNoteCount(conn.getNoteTable().getNoteCount());
2931                 status.setNotebookCount(listManager.getNotebookIndex().size());
2932                 status.setUnindexedResourceCount(conn.getNoteTable().noteResourceTable.getUnindexedCount());
2933                 status.setSavedSearchCount(listManager.getSavedSearchIndex().size());
2934                 status.setTagCount(listManager.getTagIndex().size());
2935                 status.setResourceCount(conn.getNoteTable().noteResourceTable.getResourceCount());
2936                 status.setWordCount(conn.getWordsTable().getWordCount());
2937                 status.setHistoryCount(conn.getHistoryTable().getHistoryCount());
2938                 status.setRensoClickCount(conn.getHistoryTable().getRensoClickCount());
2939                 waitCursor(false);
2940                 status.exec();
2941         }
2942         // Compact the database
2943         @SuppressWarnings("unused")
2944         private void compactDatabase() {
2945         logger.log(logger.HIGH, "Entering NeverNote.compactDatabase");
2946                 if (QMessageBox.question(this, tr("Confirmation"), tr("This will free unused space in the database, "+
2947                                 "but please be aware that depending upon the size of your database this can be time consuming " +
2948                                 "and NeighborNote will be unresponsive until it is complete.  Do you wish to continue?"),
2949                                 QMessageBox.StandardButton.Yes, 
2950                                 QMessageBox.StandardButton.No)==StandardButton.No.value() && Global.verifyDelete() == true) {
2951                                                         return;
2952                 }
2953                 setMessage("Compacting database.");
2954                 waitCursor(true);
2955                 listManager.compactDatabase();
2956                 waitCursor(false);
2957                 setMessage("Database compact is complete.");            
2958         logger.log(logger.HIGH, "Leaving NeverNote.compactDatabase");
2959     }
2960         @SuppressWarnings("unused")
2961         private void accountInformation() {
2962                 logger.log(logger.HIGH, "Entering NeverNote.accountInformation");
2963                 AccountDialog dialog = new AccountDialog();
2964                 dialog.show();
2965                 logger.log(logger.HIGH, "Leaving NeverNote.accountInformation");
2966         }
2967         @SuppressWarnings("unused")
2968         private void releaseNotes() {
2969                 logger.log(logger.HIGH, "Entering NeverNote.releaseNotes");
2970                 QDialog dialog = new QDialog(this);
2971                 QHBoxLayout layout = new QHBoxLayout();
2972                 QTextEdit textBox = new QTextEdit();
2973                 layout.addWidget(textBox);
2974                 textBox.setReadOnly(true);
2975                 QFile file = new QFile(Global.getFileManager().getProgramDirPath("release.txt"));
2976                 if (!file.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly,
2977                 QIODevice.OpenModeFlag.Text)))
2978                         return;
2979                 // 日本語文字化け対策
2980                 QTextCodec codec = QTextCodec.codecForName("UTF-8");
2981                 QTextStream textStream = new QTextStream(file);
2982                 textStream.setCodec(codec);
2983                 textBox.setText(textStream.readAll().toString());
2984                 
2985                 file.close();
2986                 dialog.setWindowTitle(tr("Release Notes"));
2987                 dialog.setLayout(layout);
2988                 dialog.show();
2989                 logger.log(logger.HIGH, "Leaving NeverNote.releaseNotes");
2990         }
2991         // Called when user picks Log from the help menu
2992         @SuppressWarnings("unused")
2993         private void logger() {
2994                 logger.log(logger.HIGH, "Entering NeverNote.logger");
2995                 LogFileDialog dialog = new LogFileDialog(emitLog);
2996                 dialog.exec();
2997                 logger.log(logger.HIGH, "Leaving NeverNote.logger");
2998         }
2999         // Menu option "help/about" was selected
3000         @SuppressWarnings("unused")
3001         private void about() {
3002                 logger.log(logger.HIGH, "Entering NeverNote.about");
3003                 QMessageBox.about(this, 
3004                                                 tr("About NeighborNote"),
3005                                                 tr("<h4><center><b>NeighborNote</b></center></h4><hr><center>Version ")
3006                                                 +Global.version + "(based on NixNote 1.6)"
3007                                                 //+"1.2.120724"
3008                                                 +tr("<hr>"
3009                                                                 +"Open Source Evernote Client.<br><br>" 
3010                                                                 +"Licensed under GPL v2.  <br><hr><br>"
3011                                                                 +"</center>Evernote is copyright 2001-2012 by Evernote Corporation<br>"
3012                                                                 +"Jambi and QT are the licensed trademark of Nokia Corporation<br>"
3013                                                                 +"PDFRenderer is licened under the LGPL<br>"
3014                                                                 +"JTidy is copyrighted under the World Wide Web Consortium<br>"
3015                                                                 +"Apache Common Utilities licensed under the Apache License Version 2.0<br>"
3016                                                                 +"Jazzy is licened under the LGPL<br>"
3017                                                                 +"Java is a registered trademark of Oracle Corporation.<br><hr>"
3018                                                                 +"Special thanks to:<br>BitRock InstallBuilder for the Windows installer"
3019                                                                 +"<br>CodeCogs (www.codecogs.com) for the LaTeX image rendering."));
3020                 logger.log(logger.HIGH, "Leaving NeverNote.about");
3021         }
3022         // Hide the entire left hand side
3023         @SuppressWarnings("unused")
3024         private void toggleLeftSide() {
3025                 boolean hidden;
3026                 
3027                 hidden = !menuBar.hideLeftSide.isChecked();
3028                 menuBar.hideLeftSide.setChecked(!hidden);
3029                 
3030                 if (!hidden) 
3031                         leftSplitter1.setHidden(true);
3032                 else
3033                         leftSplitter1.setHidden(false);
3034                 
3035                 Global.saveWindowVisible("leftPanel", hidden);
3036                 
3037         }
3038         public void checkForUpdates() {
3039                 // Send off thread to check for a new version
3040                 versionChecker = new QNetworkAccessManager(this);
3041                 versionChecker.finished.connect(this, "upgradeFileRead(QNetworkReply)");
3042                 QNetworkRequest request = new QNetworkRequest();
3043                 request.setUrl(new QUrl(Global.getUpdatesAvailableUrl()));
3044                 versionChecker.get(request);
3045         }
3046         @SuppressWarnings("unused")
3047         private void upgradeFileRead(QNetworkReply reply) {
3048                 if (!reply.isReadable())
3049                         return;
3050                 
3051                 String winVersion = Global.version;
3052                 String osxVersion = Global.version;
3053                 String linuxVersion = Global.version;
3054                 String linux64Version = Global.version;
3055                 String version = Global.version;
3056                 
3057                 // Determine the versions available
3058                 QByteArray data = reply.readLine();
3059                 while (data != null && !reply.atEnd()) {
3060                         String line = data.toString();
3061                         String lineVersion;
3062                         if (line.contains(":")) 
3063                                 lineVersion = line.substring(line.indexOf(":")+1).replace(" ", "").replace("\n", "");
3064                         else
3065                                 lineVersion = "";
3066                         if (line.toLowerCase().contains("windows")) 
3067                                 winVersion = lineVersion;
3068                         else if (line.toLowerCase().contains("os-x")) 
3069                                 osxVersion = lineVersion;
3070                         else if (line.toLowerCase().contains("linux amd64")) 
3071                                 linux64Version = lineVersion;
3072                         else if (line.toLowerCase().contains("linux i386")) 
3073                                 linuxVersion = lineVersion;
3074                         else if (line.toLowerCase().contains("default")) 
3075                                 version = lineVersion;
3076                         
3077                         // Read the next line
3078                         data = reply.readLine();
3079                 }
3080                 
3081                 // Now we need to determine what system we are on.
3082                 if (System.getProperty("os.name").toLowerCase().contains("windows"))
3083                         version = winVersion;
3084                 if (System.getProperty("os.name").toLowerCase().contains("mac os"))
3085                         version = osxVersion;
3086                 if (System.getProperty("os.name").toLowerCase().contains("Linux")) {
3087                         if (System.getProperty("os.arch").contains("amd64") ||
3088                                 System.getProperty("os.arch").contains("x86_64"))
3089                                         version = linux64Version;
3090                         else
3091                                 version = linuxVersion;
3092                 }
3093                 
3094                 
3095                 for (String validVersion : Global.validVersions) {
3096                         if (version.equals(validVersion))
3097                                 return;
3098                 }
3099                 
3100                 UpgradeAvailableDialog dialog = new UpgradeAvailableDialog();
3101                 dialog.exec();
3102                 if (dialog.remindMe())
3103                         Global.setCheckVersionUpgrade(true);
3104                 else
3105                         Global.setCheckVersionUpgrade(false);
3106         }
3107                 
3108         
3109     //***************************************************************
3110     //***************************************************************
3111     //** These functions deal with the Toolbar
3112     //***************************************************************
3113     //*************************************************************** 
3114         @SuppressWarnings("unused")
3115         private void focusSearch() {
3116                 searchField.setFocus();
3117         }
3118
3119         // Text in the search bar has been cleared
3120         private void searchFieldCleared() {
3121                 saveNote();
3122                 
3123                 // This is done because we want to force a reload of
3124                 // images.  Some images we may want to highlight the text.
3125                 readOnlyCache.clear();
3126                 inkNoteCache.clear();
3127                 noteCache.clear();
3128                 QWebSettings.setMaximumPagesInCache(0);
3129                 QWebSettings.setObjectCacheCapacities(0, 0, 0);
3130         
3131                 searchField.setDefaultText();
3132                 saveNoteColumnPositions();
3133                 saveNoteIndexWidth();
3134                 noteIndexUpdated(true);
3135                 if (currentNote == null && listManager.getNoteIndex().size() > 0) {
3136                         currentNote = listManager.getNoteIndex().get(0);
3137                         currentNoteGuid = currentNote.getGuid();
3138                 }
3139                 refreshEvernoteNote(true);
3140                 if (currentNote != null)
3141                         loadNoteBrowserInformation(browserWindow, currentNoteGuid, currentNote);
3142         }
3143         // text in the search bar changed.  We only use this to tell if it was cleared, 
3144         // otherwise we trigger off searchFieldChanged.
3145         @SuppressWarnings("unused")
3146         private void searchFieldTextChanged(String text) {
3147                 QWebSettings.setMaximumPagesInCache(0);
3148                 QWebSettings.setObjectCacheCapacities(0, 0, 0);
3149
3150                 if (text.trim().equals("") && !searchField.hasFocus()) {
3151                         searchFieldCleared();
3152                         if (searchPerformed) {
3153
3154                                 // This is done because we want to force a reload of
3155                                 // images.  Some images we may want to highlight the text.
3156                                 noteCache.clear();
3157                                 readOnlyCache.clear();
3158                                 inkNoteCache.clear();
3159                                 
3160                                 listManager.setEnSearch("");
3161                                 listManager.loadNotesIndex();
3162                                 refreshEvernoteNote(true);
3163                                 noteIndexUpdated(false);
3164                                 refreshEvernoteNote(true);
3165                         }
3166                         searchPerformed = false;
3167                 }
3168         }
3169     // Text in the toolbar has changed
3170     private void searchFieldChanged() {
3171         logger.log(logger.HIGH, "Entering NeverNote.searchFieldChanged");
3172         noteCache.clear();
3173         readOnlyCache.clear();
3174         inkNoteCache.clear();
3175         saveNoteColumnPositions();
3176         saveNoteIndexWidth();
3177         String query = searchField.getSearchQuery();
3178         listManager.setEnSearch(query.trim());
3179         listManager.loadNotesIndex();
3180         noteIndexUpdated(false);
3181
3182         refreshEvernoteNote(true);
3183         searchPerformed = true;
3184         waitCursor(false);
3185         logger.log(logger.HIGH, "Leaving NeverNote.searchFieldChanged");
3186     }
3187
3188     // Build the window tool bar
3189     private void setupToolBar() {
3190         logger.log(logger.HIGH, "Entering NeverNote.setupToolBar");
3191         toolBar = addToolBar(tr("Tool Bar"));   
3192         toolBar.setObjectName("toolBar");
3193         toolBar.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon);
3194         menuBar.setupToolBarVisible();
3195         if (!Global.isWindowVisible("toolBar"))
3196                 toolBar.setVisible(false);
3197         else
3198                 toolBar.setVisible(true);
3199
3200 //      toolBar.addWidget(menuBar);
3201 //      menuBar.setSizePolicy(Policy.Minimum, Policy.Minimum);
3202 //      toolBar.addSeparator();
3203         prevButton = toolBar.addAction(tr(""));
3204         prevButton.setToolTip(tr("Previous"));
3205         QIcon prevIcon = new QIcon(iconPath+"back.png");
3206         prevButton.setIcon(prevIcon);
3207         prevButton.triggered.connect(this, "previousViewedAction()");   
3208         togglePrevArrowButton(Global.isToolbarButtonVisible("prevArrow", true));
3209         
3210         nextButton = toolBar.addAction(tr(""));
3211         nextButton.setToolTip(tr("Next"));
3212         QIcon nextIcon = new QIcon(iconPath+"forward.png");
3213         nextButton.setIcon(nextIcon);
3214         nextButton.triggered.connect(this, "nextViewedAction()");       
3215         toggleNextArrowButton(Global.isToolbarButtonVisible("nextArrow", true));
3216         
3217         toolBar.addSeparator();
3218         
3219         upButton = toolBar.addAction(tr("Up"));
3220         QIcon upIcon = new QIcon(iconPath+"up.png");
3221         upButton.setIcon(upIcon);
3222         upButton.triggered.connect(this, "upAction()");         
3223         toggleUpArrowButton(Global.isToolbarButtonVisible("upArrow", false));
3224
3225         
3226         downButton = toolBar.addAction(tr("Down"));
3227         QIcon downIcon = new QIcon(iconPath+"down.png");
3228         downButton.setIcon(downIcon);
3229         downButton.triggered.connect(this, "downAction()");
3230         toggleDownArrowButton(Global.isToolbarButtonVisible("downArrow", false));
3231         
3232         synchronizeButton = toolBar.addAction(tr("Synchronize"));
3233         synchronizeButton.setIcon(new QIcon(iconPath+"synchronize.png"));
3234         synchronizeIconAngle = 0;
3235         synchronizeButton.triggered.connect(this, "evernoteSync()");
3236         toggleSynchronizeButton(Global.isToolbarButtonVisible("synchronize", true));
3237         
3238         printButton = toolBar.addAction(tr("Print"));
3239         QIcon printIcon = new QIcon(iconPath+"print.png");
3240         printButton.setIcon(printIcon);
3241         printButton.triggered.connect(this, "printNote()");
3242         togglePrintButton(Global.isToolbarButtonVisible("print", false));
3243
3244         tagButton = toolBar.addAction(tr("Tag")); 
3245         QIcon tagIcon = new QIcon(iconPath+"tag.png");
3246         tagButton.setIcon(tagIcon);
3247         tagButton.triggered.connect(browserWindow, "modifyTags()");
3248         toggleTagButton(Global.isToolbarButtonVisible("tag", false));
3249
3250         attributeButton = toolBar.addAction(tr("Attributes")); 
3251         QIcon attributeIcon = new QIcon(iconPath+"attribute.png");
3252         attributeButton.setIcon(attributeIcon);
3253         attributeButton.triggered.connect(this, "toggleNoteAttributes()");
3254         toggleAttributeButton(Global.isToolbarButtonVisible("attribute", true));
3255                 
3256         emailButton = toolBar.addAction(tr("Email"));
3257         QIcon emailIcon = new QIcon(iconPath+"email.png");
3258         emailButton.setIcon(emailIcon);
3259         emailButton.triggered.connect(this, "emailNote()");
3260         toggleEmailButton(Global.isToolbarButtonVisible("email", false));
3261
3262         deleteButton = toolBar.addAction(tr("Delete"));         
3263         QIcon deleteIcon = new QIcon(iconPath+"delete.png");
3264         deleteButton.setIcon(deleteIcon);
3265         deleteButton.triggered.connect(this, "deleteNote()");
3266         toggleDeleteButton(Global.isToolbarButtonVisible("delete", true));
3267
3268         newButton = toolBar.addAction(tr("New"));
3269         QIcon newIcon = new QIcon(iconPath+"new.png");
3270         if (Global.toolBarNewAction()) {
3271                 newButton.triggered.connect(this, "noteAddNewTab()");
3272         } else {
3273                 newButton.triggered.connect(this, "addNote()");
3274         }
3275
3276         newButton.setIcon(newIcon);
3277         toggleNewButton(Global.isToolbarButtonVisible("new", true));
3278         
3279         allNotesButton = toolBar.addAction(tr("All Notes"));
3280         QIcon allIcon = new QIcon(iconPath+"books.png");
3281         allNotesButton.triggered.connect(this, "allNotes()");
3282         allNotesButton.setIcon(allIcon);
3283         toggleAllNotesButton(Global.isToolbarButtonVisible("allNotes", true));
3284         
3285         //toolBar.addSeparator();
3286         //toolBar.addWidget(new QLabel(tr("Quota:")));
3287         //toolBar.addWidget(quotaBar);
3288         //quotaBar.setSizePolicy(Policy.Minimum, Policy.Minimum);
3289         updateQuotaBar();
3290         //toolBar.addSeparator();
3291         
3292         //toolBar.addWidget(new QLabel(tr("Zoom")));
3293         //toolBar.addWidget(zoomSpinner);
3294         
3295         //toolBar.addWidget(new QLabel("                    "));
3296         //toolBar.addSeparator();
3297         
3298         // 検索ボックスを右寄せするためのスペーサ
3299         QWidget spacerWidget = new QWidget();
3300         spacerWidget.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred);
3301         toolBar.addWidget(spacerWidget);
3302         spacerWidget.setVisible(true);
3303         
3304         searchField = new SearchEdit(iconPath, conn);
3305         searchField.setObjectName("searchField");
3306         searchField.returnPressed.connect(this, "searchFieldChanged()");
3307         searchField.textChanged.connect(this,"searchFieldTextChanged(String)");
3308         searchField.setMaximumWidth(400);
3309         searchField.setMinimumWidth(80);
3310         searchField.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed);
3311         searchShortcut = new QShortcut(this);
3312         setupShortcut(searchShortcut, "Focus_Search");
3313         searchShortcut.activated.connect(this, "focusSearch()");
3314         toolBar.addWidget(searchField);
3315         
3316                 searchField.setVisible(Global.isWindowVisible("searchField"));
3317                 // IFIXED !searchField.isVisible() → !Global.isWindowVisible("searchField")
3318                 // なぜかsearchField.isVisible()が常にfalseを返すようなので修正
3319                 if (!Global.isWindowVisible("searchField"))
3320                         menuBar.hideSearch.setChecked(false);
3321                 
3322 //      QSizePolicy sizePolicy = new QSizePolicy();
3323 //      sizePolicy.setHorizontalPolicy(Policy.MinimumExpanding);
3324 //      QLabel spacer = new QLabel("");
3325 //      spacer.setSizePolicy(sizePolicy);
3326 //      toolBar.addWidget(spacer);
3327                 
3328         //searchField.setInsertPolicy(InsertPolicy.InsertAtTop);
3329
3330         //searchClearButton = toolBar.addAction("Search Clear");
3331         //QIcon searchClearIcon = new QIcon(iconPath+"searchclear.png");
3332         //searchClearButton.setIcon(searchClearIcon);
3333         //searchClearButton.triggered.connect(this, "searchFieldCleared()");
3334         //toggleSearchClearButton(Global.isToolbarButtonVisible("searchClear"));
3335
3336         logger.log(logger.HIGH, "Leaving NeverNote.setupToolBar");
3337     }
3338     // Update the sychronize button picture
3339     @Override
3340         public QMenu createPopupMenu() {
3341         QMenu contextMenu = super.createPopupMenu();
3342         
3343         contextMenu.addSeparator();
3344         QAction prevAction = addContextAction("prevArrow", tr("Previous Arrow"));
3345         contextMenu.addAction(prevAction);
3346         prevAction.triggered.connect(this, "togglePrevArrowButton(Boolean)");
3347
3348         QAction nextAction = addContextAction("nextArrow", tr("Next Arrow"));
3349         contextMenu.addAction(nextAction);
3350         nextAction.triggered.connect(this, "toggleNextArrowButton(Boolean)");
3351
3352         QAction upAction = addContextAction("upArrow", tr("Up Arrow"));
3353         contextMenu.addAction(upAction);
3354         upAction.triggered.connect(this, "toggleUpArrowButton(Boolean)");
3355
3356         QAction downAction = addContextAction("downArrow", tr("Down Arrow"));
3357         contextMenu.addAction(downAction);
3358         downAction.triggered.connect(this, "toggleDownArrowButton(Boolean)");
3359
3360         QAction synchronizeAction = addContextAction("synchronize", tr("Synchronize"));
3361         contextMenu.addAction(synchronizeAction);
3362         synchronizeAction.triggered.connect(this, "toggleSynchronizeButton(Boolean)");
3363
3364         QAction printAction = addContextAction("print", tr("Print"));
3365         contextMenu.addAction(printAction);
3366         printAction.triggered.connect(this, "togglePrintButton(Boolean)");
3367
3368         QAction tagAction = addContextAction("tag", tr("Tag"));
3369         contextMenu.addAction(tagAction);
3370         tagAction.triggered.connect(this, "toggleTagButton(Boolean)");
3371         
3372         QAction attributeAction = addContextAction("attribute", tr("Attribute"));
3373         contextMenu.addAction(attributeAction);
3374         attributeAction.triggered.connect(this, "toggleAttributeButton(Boolean)");
3375         
3376         QAction emailAction = addContextAction("email", tr("Email"));
3377         contextMenu.addAction(emailAction);
3378         emailAction.triggered.connect(this, "toggleEmailButton(Boolean)");
3379
3380         QAction deleteAction = addContextAction("delete", tr("Delete"));
3381         contextMenu.addAction(deleteAction);
3382         deleteAction.triggered.connect(this, "toggleDeleteButton(Boolean)");
3383
3384         QAction newAction = addContextAction("new", tr("Add"));
3385         contextMenu.addAction(newAction);
3386         newAction.triggered.connect(this, "toggleNewButton(Boolean)");
3387
3388         QAction allNotesAction = addContextAction("allNotes", tr("All Notes"));
3389         contextMenu.addAction(allNotesAction);
3390         allNotesAction.triggered.connect(this, "toggleAllNotesButton(Boolean)");
3391         
3392 //      QAction searchClearAction = addContextAction("searchClear", tr("Search Clear"));
3393 //      contextMenu.addAction(searchClearAction);
3394 //      searchClearAction.triggered.connect(this, "toggleSearchClearButton(Boolean)");
3395         
3396         return contextMenu;
3397         
3398     }
3399     private QAction addContextAction(String config, String name) {
3400         QAction newAction = new QAction(this);
3401                 newAction.setText(name);
3402                 newAction.setCheckable(true);
3403                 newAction.setChecked(Global.isToolbarButtonVisible(config, true));
3404                 return newAction;
3405     }
3406     private void togglePrevArrowButton(Boolean toggle) {
3407                 prevButton.setVisible(toggle);
3408                 Global.saveToolbarButtonsVisible("prevArrow", toggle);
3409     }
3410     private void toggleNextArrowButton(Boolean toggle) {
3411                 nextButton.setVisible(toggle);
3412                 Global.saveToolbarButtonsVisible("nextArrow", toggle);
3413     }
3414     private void toggleUpArrowButton(Boolean toggle) {
3415                 upButton.setVisible(toggle);
3416                 Global.saveToolbarButtonsVisible("upArrow", toggle);
3417     }
3418     private void toggleDownArrowButton(Boolean toggle) {
3419                 downButton.setVisible(toggle);
3420                 Global.saveToolbarButtonsVisible("downArrow", toggle);
3421     }
3422     private void toggleSynchronizeButton(Boolean toggle) {
3423                 synchronizeButton.setVisible(toggle);
3424                 Global.saveToolbarButtonsVisible("synchronize", toggle);
3425     }
3426     private void togglePrintButton(Boolean toggle) {
3427                 printButton.setVisible(toggle);
3428                 Global.saveToolbarButtonsVisible("print", toggle);
3429     }
3430     private void toggleTagButton(Boolean toggle) {
3431                 tagButton.setVisible(toggle);
3432                 Global.saveToolbarButtonsVisible("tag", toggle);
3433     }
3434     private void toggleAttributeButton(Boolean toggle) {
3435                 attributeButton.setVisible(toggle);
3436                 Global.saveToolbarButtonsVisible("attribute", toggle);
3437     }
3438     private void toggleEmailButton(Boolean toggle) {
3439                 emailButton.setVisible(toggle);
3440                 Global.saveToolbarButtonsVisible("email", toggle);
3441     }
3442     private void toggleDeleteButton(Boolean toggle) {
3443                 deleteButton.setVisible(toggle);
3444                 Global.saveToolbarButtonsVisible("delete", toggle);
3445     }
3446     private void toggleNewButton(Boolean toggle) {
3447                 newButton.setVisible(toggle);
3448                 Global.saveToolbarButtonsVisible("new", toggle);
3449     }
3450     private void toggleAllNotesButton(Boolean toggle) {
3451                 allNotesButton.setVisible(toggle);
3452                 Global.saveToolbarButtonsVisible("allNotes", toggle);
3453     }
3454 //    @SuppressWarnings("unused")
3455 //      private void toggleSearchClearButton(Boolean toggle) {
3456 //              searchClearButton.setVisible(toggle);
3457 //              Global.saveToolbarButtonsVisible("searchClear", toggle);
3458 //    }
3459
3460
3461
3462
3463
3464     @SuppressWarnings("unused")
3465         private void updateSyncButton() {
3466                 
3467         if (syncIcons == null) {
3468                 syncIcons = new ArrayList<QPixmap>();
3469                 double angle = 0.0;
3470                 synchronizeIconAngle = 0;
3471                 QPixmap pix = new QPixmap(iconPath+"synchronize.png");
3472                 syncIcons.add(pix);
3473                 for (int i=0; i<=360; i++) {
3474                         QPixmap rotatedPix = new QPixmap(pix.size());
3475                         QPainter p = new QPainter(rotatedPix);
3476                 rotatedPix.fill(toolBar.palette().color(ColorRole.Button));
3477                 QSize size = pix.size();
3478                 p.translate(size.width()/2, size.height()/2);
3479                 angle = angle+1.0;
3480                 p.rotate(angle);
3481                 p.setBackgroundMode(BGMode.OpaqueMode);
3482                 p.translate(-size.width()/2, -size.height()/2);
3483                 p.drawPixmap(0,0, pix);
3484                 p.end();
3485                 syncIcons.add(rotatedPix);
3486                 }
3487         }
3488
3489         synchronizeIconAngle++;
3490         if (synchronizeIconAngle > 359)
3491                 synchronizeIconAngle=0;
3492         synchronizeButton.setIcon(syncIcons.get(synchronizeIconAngle));
3493         
3494     }
3495     // Synchronize with Evernote
3496
3497         private void evernoteSync() {
3498         logger.log(logger.HIGH, "Entering NeverNote.evernoteSync");
3499         if (!Global.isConnected)
3500                 remoteConnect();
3501         if (Global.isConnected)
3502                 synchronizeAnimationTimer.start(5);
3503 //                      synchronizeAnimationTimer.start(200);
3504         syncTimer();
3505         logger.log(logger.HIGH, "Leaving NeverNote.evernoteSync");
3506     }
3507     private void updateQuotaBar() {
3508         long limit = Global.getUploadLimit();
3509         long amount = Global.getUploadAmount();
3510         if (amount>0 && limit>0) {
3511                 int percent =(int)(amount*100/limit);
3512                 quotaBar.setValue(percent);
3513         } else 
3514                 quotaBar.setValue(0);
3515     }
3516         // Zoom changed
3517     @SuppressWarnings("unused")
3518         private void zoomChanged() {
3519         browserWindow.getBrowser().setZoomFactor(new Double(zoomSpinner.value())/100);
3520     }
3521
3522     //****************************************************************
3523     //****************************************************************
3524     //* System Tray functions
3525     //****************************************************************
3526     //****************************************************************
3527         private void trayToggleVisible() {
3528         if (isVisible()) {
3529                 hide();
3530         } else {
3531                 show();
3532                 if (windowMaximized)
3533                         showMaximized();
3534                 else
3535                         showNormal();
3536                 raise();
3537         }
3538     }
3539     @SuppressWarnings("unused")
3540         private void trayActivated(QSystemTrayIcon.ActivationReason reason) {
3541         if (reason == QSystemTrayIcon.ActivationReason.DoubleClick) {
3542                 String name = QSystemTrayIcon.MessageIcon.resolve(reason.value()).name();
3543                 trayToggleVisible();
3544         }
3545     }
3546     
3547     
3548     //***************************************************************
3549     //***************************************************************
3550     //** These functions deal with the trash tree
3551     //***************************************************************
3552     //***************************************************************    
3553     // Setup the tree containing the trash.
3554     @SuppressWarnings("unused")
3555         private void trashTreeSelection() {     
3556         logger.log(logger.HIGH, "Entering NeverNote.trashTreeSelection");
3557         
3558         clearNotebookFilter();
3559         clearTagFilter();
3560         clearAttributeFilter();
3561         clearSavedSearchFilter();
3562         
3563         String tempGuid = currentNoteGuid;
3564         
3565 //      currentNoteGuid = "";
3566         currentNote = new Note();
3567         selectedNoteGUIDs.clear();
3568         listManager.getSelectedNotebooks().clear();
3569         listManager.getSelectedTags().clear();
3570         listManager.setSelectedSavedSearch("");
3571         browserWindow.clear();
3572     
3573         // toggle the add buttons
3574         newButton.setEnabled(!newButton.isEnabled());
3575         menuBar.noteAdd.setEnabled(newButton.isEnabled());
3576         menuBar.noteAdd.setVisible(true);
3577         
3578         List<QTreeWidgetItem> selections = trashTree.selectedItems();
3579         if (selections.size() == 0) {
3580                 currentNoteGuid = trashNoteGuid;
3581                         trashNoteGuid = tempGuid;
3582                 Global.showDeleted = false;
3583                 menuBar.noteRestoreAction.setEnabled(false);
3584                 menuBar.noteRestoreAction.setVisible(false);
3585                         // ゴミ箱から元の画面に戻す。連想ノートリストをONに。
3586                         rensoNoteListDock.setEnabled(true);
3587         }
3588         else {
3589                 trashNoteGuid = tempGuid;
3590                 currentNoteGuid = trashNoteGuid;
3591                 menuBar.noteRestoreAction.setEnabled(true);
3592                 menuBar.noteRestoreAction.setVisible(true);
3593                 // ゴミ箱を開く。連想ノートリストをOFFに。
3594                 rensoNoteListDock.setEnabled(false);
3595                                         
3596                 Global.showDeleted = true;
3597         }
3598         
3599         menuBar.noteAddNewTab.setEnabled(newButton.isEnabled());
3600                 if (currentNoteGuid == null || currentNoteGuid.equals("")) {
3601                         menuBar.noteAddNewTab.setEnabled(false);
3602                 }
3603         
3604         listManager.loadNotesIndex();
3605         noteIndexUpdated(false);
3606 ////            browserWindow.setEnabled(newButton.isEnabled());
3607         browserWindow.setReadOnly(!newButton.isEnabled());
3608         logger.log(logger.HIGH, "Leaving NeverNote.trashTreeSelection");
3609     }
3610     // Empty the trash file
3611     @SuppressWarnings("unused")
3612         private void emptyTrash() {
3613 //      browserWindow.clear();
3614         logger.log(logger.EXTREME, "Emptying Trash");
3615         listManager.emptyTrash();
3616         logger.log(logger.EXTREME, "Resetting view after trash empty");
3617         if (trashTree.selectedItems().size() > 0) {
3618                 listManager.getSelectedNotebooks().clear();
3619                 listManager.getSelectedTags().clear();
3620                 listManager.setSelectedSavedSearch("");
3621                 newButton.setEnabled(!newButton.isEnabled());
3622                 menuBar.noteAdd.setEnabled(newButton.isEnabled());
3623                 menuBar.noteAddNewTab.setEnabled(newButton.isEnabled());
3624                 if (currentNoteGuid == null || currentNoteGuid.equals("")) {
3625                         menuBar.noteAddNewTab.setEnabled(false);
3626                 }
3627                 menuBar.noteAdd.setVisible(true);
3628                 browserWindow.clear();
3629                 
3630                 clearTagFilter();
3631                 clearNotebookFilter();
3632                 clearSavedSearchFilter();
3633                 clearAttributeFilter();
3634                         
3635                 Global.showDeleted = false;
3636                 menuBar.noteRestoreAction.setEnabled(false);
3637                 menuBar.noteRestoreAction.setVisible(false);
3638                 
3639                 listManager.loadNotesIndex();
3640                 noteIndexUpdated(false);
3641                 
3642                 // ゴミ箱から元の画面に戻す。連想ノートリストをONに。
3643                 if (!rensoNoteListDock.isEnabled()) {
3644                         rensoNoteListDock.setEnabled(true);
3645                 }
3646         }       
3647    }
3648     // Show/Hide trash window
3649         @SuppressWarnings("unused")
3650         private void toggleTrashWindow() {
3651                 logger.log(logger.HIGH, "Entering NeverNote.toggleTrashWindow");
3652         if (trashTree.isVisible())
3653                 trashTree.hide();
3654         else
3655                 trashTree.show();
3656         menuBar.hideTrash.setChecked(trashTree.isVisible());
3657         
3658                 Global.saveWindowVisible("trashTree", trashTree.isVisible());
3659         logger.log(logger.HIGH, "Leaving NeverNote.trashWindow");
3660     }    
3661         private void clearTrashFilter() {
3662                 Global.showDeleted = false;
3663         newButton.setEnabled(true);
3664         menuBar.noteAdd.setEnabled(true);
3665                 if (currentNoteGuid == null || currentNoteGuid.equals("")) {
3666                         menuBar.noteAddNewTab.setEnabled(false);
3667                 } else {
3668                         menuBar.noteAddNewTab.setEnabled(true);
3669                 }
3670         menuBar.noteAdd.setVisible(true);
3671                 trashTree.blockSignals(true);
3672                 trashTree.clearSelection();
3673                 trashTree.blockSignals(false);
3674                 
3675         }
3676     
3677    
3678     //***************************************************************
3679     //***************************************************************
3680     //** These functions deal with connection settings
3681     //***************************************************************
3682     //***************************************************************
3683         // SyncRunner had a problem and things are disconnected
3684         @SuppressWarnings("unused")
3685         private void remoteErrorDisconnect() {
3686                 menuBar.connectAction.setText(tr("Connect"));
3687                 menuBar.connectAction.setToolTip(tr("Connect to Evernote"));
3688                 menuBar.synchronizeAction.setEnabled(false);
3689                 Global.isConnected = false;
3690                 synchronizeAnimationTimer.stop();
3691                 return;
3692         }
3693         // Do a manual connect/disconnect
3694     private void remoteConnect() {
3695         
3696         logger.log(logger.HIGH, "Entering NeverNote.remoteConnect");
3697
3698         // If we are already connected, we just disconnect
3699         if (Global.isConnected) {
3700                 Global.isConnected = false;
3701                 syncRunner.enDisconnect();
3702                 setupConnectMenuOptions();
3703                 setupOnlineMenu();
3704                 return;
3705         }
3706         
3707         OAuthTokenizer tokenizer = new OAuthTokenizer();
3708         AESEncrypter aes = new AESEncrypter();
3709         try {
3710                         aes.decrypt(new FileInputStream(Global.getFileManager().getHomeDirFile("oauthkey.txt")));
3711                 } catch (FileNotFoundException e) {
3712                         // File not found, so we'll just get empty strings anyway. 
3713                 }
3714         
3715                 
3716                 if (Global.getProxyValue("url").equals("")) {
3717                         System.setProperty("http.proxyHost","") ;
3718                         System.setProperty("http.proxyPort", "") ;
3719                         System.setProperty("https.proxyHost","") ;
3720                         System.setProperty("https.proxyPort", "") ;         
3721                 } else {
3722                         // PROXY
3723                         System.setProperty("http.proxyHost",Global.getProxyValue("url")) ;
3724                         System.setProperty("http.proxyPort", Global.getProxyValue("port")) ;
3725                         System.setProperty("https.proxyHost",Global.getProxyValue("url")) ;
3726                         System.setProperty("https.proxyPort", Global.getProxyValue("port")) ;
3727  
3728                         if (Global.getProxyValue("userid").equals("")) {
3729                                 Authenticator.setDefault(new Authenticator() {
3730                         @Override
3731                         protected PasswordAuthentication getPasswordAuthentication() {
3732                                 return new
3733                                 PasswordAuthentication(Global.getProxyValue("userid"),Global.getProxyValue("password").toCharArray());
3734                                 }
3735                         });
3736                 }
3737         }
3738
3739                 syncRunner.userStoreUrl = Global.userStoreUrl;
3740                 syncRunner.noteStoreUrl = Global.noteStoreUrl;
3741                 syncRunner.noteStoreUrlBase = Global.noteStoreUrlBase;
3742                 
3743                 
3744                 
3745                 String authString = aes.getString();
3746                 if (!authString.equals("")) {
3747                         tokenizer.tokenize(authString);
3748                         syncRunner.authToken = tokenizer.oauth_token;
3749                 syncRunner.enConnect();
3750                 }               
3751
3752                 Global.isConnected = syncRunner.isConnected;
3753                 
3754                 boolean autoLoginMessageFlag = false;
3755                 if (!Global.isConnected) {
3756                 OAuthWindow window = new OAuthWindow(logger);
3757                 if (window.error) {
3758                         setMessage(window.errorMessage);
3759                         return;
3760                 }
3761                 window.exec();
3762                 if (window.error) {
3763                         setMessage(window.errorMessage);
3764                         return;
3765                         }
3766                 tokenizer.tokenize(window.response);
3767                 if (tokenizer.oauth_token.equals("")) {
3768                         setMessage(tr("Invalid authorization token received."));
3769                         return;
3770                 }
3771                 aes.setString(window.response);
3772                 try {
3773                                 aes.encrypt(new FileOutputStream(Global.getFileManager().getHomeDirFile("oauthkey.txt")));
3774                         } catch (FileNotFoundException e) {
3775                                 // TODO Auto-generated catch block
3776                                 e.printStackTrace();
3777                         }
3778                 syncRunner.authToken = tokenizer.oauth_token;
3779                         syncRunner.enConnect();
3780                         Global.isConnected = syncRunner.isConnected;
3781                         autoLoginMessageFlag = true;
3782                 }
3783 //              Global.username = syncRunner.username;
3784                         
3785                 if (!Global.isConnected)
3786                         return;
3787                 setupOnlineMenu();
3788                 setupConnectMenuOptions();
3789                 
3790                 // 初回ログイン時に自動ログインが無効だったら、有効化するか確認する
3791                 if (autoLoginMessageFlag && !Global.automaticLogin()) {
3792                         if (QMessageBox.question(this, tr("Confirmation"), tr("Are you sure you want to enable the auto-login feature?"), 
3793                                         QMessageBox.StandardButton.Yes, QMessageBox.StandardButton.No) == StandardButton.Yes.value()) {
3794                                 Global.setAutomaticLogin(true);
3795                         }
3796                 }
3797                 
3798                 logger.log(logger.HIGH, "Leaving NeverNote.remoteConnect");
3799     }
3800     private void setupConnectMenuOptions() {
3801         logger.log(logger.HIGH, "entering NeverNote.setupConnectMenuOptions");
3802                 if (!Global.isConnected) {
3803                         menuBar.connectAction.setText(tr("Connect"));
3804                         menuBar.connectAction.setToolTip(tr("Connect to Evernote"));
3805                         menuBar.synchronizeAction.setEnabled(false);
3806                 } else {
3807                         menuBar.connectAction.setText(tr("Disconnect"));
3808                         menuBar.connectAction.setToolTip(tr("Disconnect from Evernote"));
3809                         menuBar.synchronizeAction.setEnabled(true);
3810                 }
3811                 logger.log(logger.HIGH, "Leaving NeverNote.setupConnectionMenuOptions");
3812     }
3813     
3814     
3815     
3816     //***************************************************************
3817     //***************************************************************
3818     //** These functions deal with the GUI Attribute tree
3819     //***************************************************************
3820     //***************************************************************    
3821     @SuppressWarnings("unused")
3822         private void attributeTreeClicked(QTreeWidgetItem item, Integer integer) {
3823         
3824 //      clearTagFilter();
3825 //      clearNotebookFilter();
3826         clearTrashFilter();
3827 //      clearSavedSearchFilter();
3828         
3829                 // ゴミ箱から元の画面に戻す。連想ノートリストをONに。
3830                 if (!rensoNoteListDock.isEnabled()) {
3831                         rensoNoteListDock.setEnabled(true);
3832                 }
3833
3834         if (attributeTreeSelected == null || item.nativeId() != attributeTreeSelected.nativeId()) {
3835                 if (item.childCount() > 0) {
3836                         item.setSelected(false);
3837                 } else {
3838                 Global.createdBeforeFilter.reset();
3839                 Global.createdSinceFilter.reset();
3840                 Global.changedBeforeFilter.reset();
3841                 Global.changedSinceFilter.reset();
3842                 Global.containsFilter.reset();
3843                         attributeTreeSelected = item;
3844                         DateAttributeFilterTable f = null;
3845                         f = findDateAttributeFilterTable(item.parent());
3846                         if (f!=null)
3847                                 f.select(item.parent().indexOfChild(item));
3848                         else {
3849                                 Global.containsFilter.select(item.parent().indexOfChild(item));
3850                         }
3851                 }
3852                 listManager.loadNotesIndex();
3853                 noteIndexUpdated(false);
3854                 return;
3855         }
3856                 attributeTreeSelected = null;
3857                 item.setSelected(false);
3858         Global.createdBeforeFilter.reset();
3859         Global.createdSinceFilter.reset();
3860         Global.changedBeforeFilter.reset();
3861         Global.changedSinceFilter.reset();
3862         Global.containsFilter.reset();
3863         listManager.loadNotesIndex();
3864                 noteIndexUpdated(false); 
3865     }
3866     // This determines what attribute filter we need, depending upon the selection
3867     private DateAttributeFilterTable findDateAttributeFilterTable(QTreeWidgetItem w) {
3868                 if (w.parent() != null && w.childCount() > 0) {
3869                         QTreeWidgetItem parent = w.parent();
3870                         if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Created && 
3871                                 w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Since)
3872                                         return Global.createdSinceFilter;
3873                         if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Created && 
3874                         w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Before)
3875                                         return Global.createdBeforeFilter;
3876                         if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.LastModified && 
3877                         w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Since)
3878                                         return Global.changedSinceFilter;
3879                 if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.LastModified && 
3880                         w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Before)
3881                                                 return Global.changedBeforeFilter;
3882                 }
3883                 return null;
3884     }
3885
3886     // Show/Hide attribute search window
3887         @SuppressWarnings("unused")
3888         private void toggleAttributesWindow() {
3889                 logger.log(logger.HIGH, "Entering NeverNote.toggleAttributesWindow");
3890         if (attributeTree.isVisible())
3891                 attributeTree.hide();
3892         else
3893                 attributeTree.show();
3894         menuBar.hideAttributes.setChecked(attributeTree.isVisible());
3895         
3896                 Global.saveWindowVisible("attributeTree", attributeTree.isVisible());
3897         logger.log(logger.HIGH, "Leaving NeverNote.toggleAttributeWindow");
3898     }    
3899         private void clearAttributeFilter() {
3900         Global.createdBeforeFilter.reset();
3901         Global.createdSinceFilter.reset();
3902         Global.changedBeforeFilter.reset();
3903         Global.changedSinceFilter.reset();
3904         Global.containsFilter.reset();
3905         attributeTreeSelected = null;
3906                 attributeTree.blockSignals(true);
3907                 attributeTree.clearSelection();
3908                 attributeTree.blockSignals(false);
3909         }
3910     
3911         
3912     //***************************************************************
3913     //***************************************************************
3914     //** These functions deal with the GUI Note index table
3915     //***************************************************************
3916     //***************************************************************    
3917     // Initialize the note list table
3918         private void initializeNoteTable() {
3919                 logger.log(logger.HIGH, "Entering NeverNote.initializeNoteTable");
3920                 noteTableView.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection);
3921                 noteTableView.selectionModel().selectionChanged.connect(this, "noteTableSelection()");
3922                 logger.log(logger.HIGH, "Leaving NeverNote.initializeNoteTable");
3923         }       
3924     // Show/Hide trash window
3925         @SuppressWarnings("unused")
3926         private void toggleNoteListWindow() {
3927                 logger.log(logger.HIGH, "Entering NeverNote.toggleNoteListWindow");
3928         if (noteTableView.isVisible())
3929                 noteTableView.hide();
3930         else
3931                 noteTableView.show();
3932         menuBar.hideNoteList.setChecked(noteTableView.isVisible());
3933         
3934                 Global.saveWindowVisible("noteList", noteTableView.isVisible());
3935         logger.log(logger.HIGH, "Leaving NeverNote.toggleNoteListWindow");
3936     }   
3937         // Handle the event that a user selects a note from the table
3938     @SuppressWarnings("unused")
3939         private void noteTableSelection() {
3940                 logger.log(logger.HIGH, "Entering NeverNote.noteTableSelection");
3941
3942                 saveNote();
3943                 
3944                 // 右クリックだったときの処理
3945                 if (QApplication.mouseButtons().isSet(MouseButton.RightButton)) {
3946                         // 選択されたノートのguidをselectedNoteGUIDsにセット
3947                         List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
3948                         if(selections.size() > 0){
3949                                 selectedNoteGUIDs.clear();
3950                                 for(int i = 0; i < selections.size(); i++){
3951                                         int row = selections.get(i).row();
3952                                         QModelIndex index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition);
3953                                         SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
3954                                         selectedNoteGUIDs.add((String) ix.values().toArray()[0]);
3955                                 }
3956                         }
3957                         return;
3958                 }
3959                 
3960                 // If we have more than one selection, then set the merge note action to true.
3961         List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
3962                 if (selections.size() > 1) 
3963                 menuBar.noteMergeAction.setEnabled(true);
3964                 else
3965                         menuBar.noteMergeAction.setEnabled(false);
3966
3967                 // If the ctrl key is pressed, then they are selecting multiple 
3968                 // entries and we don't want to change the currently viewed note.
3969                 // Shiftキーを押しながらの場合の処理も追加
3970                 if ((QApplication.keyboardModifiers().isSet(KeyboardModifier.ControlModifier) ||
3971                                 QApplication.keyboardModifiers().isSet(KeyboardModifier.ShiftModifier)) &&
3972                                 QApplication.mouseButtons().isSet(MouseButton.LeftButton)){
3973                         selectedNoteGUIDs.clear();
3974                 for (int i=0; i<selections.size(); i++) {
3975                         int row = selections.get(i).row();
3976                         QModelIndex index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition);
3977                         SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
3978                         selectedNoteGUIDs.add((String)ix.values().toArray()[0]);
3979                 }
3980                         return;
3981                 }
3982                 
3983                 // IFIXED 恐らく不要なのでコメントアウト
3984 //              if (historyGuids.size() == 0) {
3985 //                      historyGuids.add(currentNoteGuid);
3986 //                      historyPosition = 1;
3987 //              }
3988
3989         noteTableView.showColumn(Global.noteTableGuidPosition);
3990         
3991         if (!Global.isColumnVisible("guid"))
3992                 noteTableView.hideColumn(Global.noteTableGuidPosition);
3993         
3994         if (selections.size() > 0) {
3995                 QModelIndex index;
3996                 menuBar.noteDuplicateAction.setEnabled(true);
3997                 menuBar.noteOnlineHistoryAction.setEnabled(true);
3998                 menuBar.noteMergeAction.setEnabled(true);
3999                 selectedNoteGUIDs.clear();
4000                 if (currentNoteGuid != null && !currentNoteGuid.equals("") && !Global.showDeleted) {
4001                         menuBar.noteAddNewTab.setEnabled(true);
4002                 }
4003                 if (selections.size() != 1 || Global.showDeleted) {
4004                         menuBar.noteDuplicateAction.setEnabled(false);
4005                 }
4006                 if (selections.size() != 1 || !Global.isConnected) {
4007                         menuBar.noteOnlineHistoryAction.setEnabled(false);
4008                 }
4009                 if (selections.size() == 1) {
4010                         menuBar.noteMergeAction.setEnabled(false);
4011                 }
4012                 for (int i=0; i<selections.size(); i++) {
4013                         int row = selections.get(i).row();
4014                         if (row == 0) 
4015                                 upButton.setEnabled(false);
4016                         else
4017                                 upButton.setEnabled(true);
4018                         if (row < listManager.getNoteTableModel().rowCount()-1)
4019                                 downButton.setEnabled(true);
4020                         else
4021                                 downButton.setEnabled(false);
4022                         index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition);
4023                         SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
4024                                 
4025                         currentNoteGuid = (String)ix.values().toArray()[0];                     
4026                         selectedNoteGUIDs.add(currentNoteGuid);
4027                 }
4028         }
4029         
4030         nextButton.setEnabled(true);
4031                 prevButton.setEnabled(true);
4032                 
4033                 int currentIndex = tabBrowser.currentIndex();
4034                 ArrayList<String> histGuids = historyGuids.get(currentIndex);
4035                 int histPosition = historyPosition.get(currentIndex);
4036                 boolean fromHist = fromHistory.get(currentIndex);
4037                 
4038                 if (!fromHist) {
4039                         int endPosition = histGuids.size() - 1;
4040
4041                         for (int j = histPosition; j <= endPosition; j++) {
4042                                 histGuids.remove(histGuids.size() - 1);
4043                         }
4044                         histGuids.add(currentNoteGuid);
4045                         historyPosition.put(currentIndex, histGuids.size());
4046                         histPosition = histGuids.size();
4047                 }
4048                 if (histPosition <= 1){
4049                         prevButton.setEnabled(false);
4050                 }
4051                 if (histPosition == histGuids.size())
4052                         nextButton.setEnabled(false);
4053                 fromHistory.put(currentIndex, false);
4054                 fromHist = false;
4055                 
4056         scrollToGuid(currentNoteGuid);
4057         refreshEvernoteNote(true);
4058         
4059                 if (currentNoteGuid != null && !currentNoteGuid.equals("")) {
4060                         if (!Global.showDeleted) { // ゴミ箱じゃなければ
4061                                 addBrowseHistory();
4062                         }
4063                 }
4064
4065                 // 連想ノートリストを更新
4066                 rensoNoteListDock.getRensoNoteList().refreshRensoNoteList(currentNoteGuid);
4067                 
4068                 waitCursor(false);
4069                 logger.log(logger.HIGH, "Leaving NeverNote.noteTableSelection");
4070     }
4071     
4072     // 複数ノートの同時閲覧履歴をデータベースに保存
4073         private void addBrowseHistory() {
4074                 // このノートと他のタブウィンドウノートの関連性を内部データベースのHistoryテーブルに登録
4075                 if (tabWindows.size() >= 2) {
4076                         Iterator<Integer> it = tabWindows.keySet().iterator();
4077                         while (it.hasNext()) {
4078                                 int tabIndex = it.next();
4079                                 String nextGuid = ((TabBrowse) tabBrowser.widget(tabIndex)).getBrowserWindow().getNote().getGuid();
4080                                 // guid1=guid2のデータは登録しない
4081                                 if (!currentNoteGuid.equals(nextGuid)) {
4082                                         conn.getHistoryTable().addHistory("browse", currentNoteGuid, nextGuid);
4083                                 }
4084                         }
4085                 }
4086                 // このノートと他の外部ウィンドウノートの関連性を内部データベースのHistoryテーブルに登録
4087                 if (externalWindows.size() >= 1) {
4088                         Iterator<String> it = externalWindows.keySet().iterator();
4089                         while (it.hasNext()) {
4090                                 String nextGuid = it.next();
4091                                 // guid1=guid2のデータは登録しない
4092                                 if (!currentNoteGuid.equals(nextGuid)) {
4093                                         conn.getHistoryTable().addHistory("browse", currentNoteGuid, nextGuid);
4094                                 }
4095                         }
4096                 }
4097         }
4098         
4099         // Trigger a refresh when the note db has been updated
4100         private void noteIndexUpdated(boolean reload) {
4101                 logger.log(logger.HIGH, "Entering NeverNote.noteIndexUpdated");
4102                 saveNote();
4103         refreshEvernoteNoteList();
4104         logger.log(logger.HIGH, "Calling note table reload in NeverNote.noteIndexUpdated() - "+reload);
4105         noteTableView.load(reload);
4106         if (currentNoteGuid == null || currentNoteGuid.equals("")) {
4107                 int pos;
4108                 if (noteTableView.proxyModel.sortOrder() == SortOrder.AscendingOrder)
4109                         pos = noteTableView.proxyModel.rowCount();
4110                 else 
4111                         pos = 1;
4112                 if (noteTableView.proxyModel.rowCount() == 0)
4113                         pos = 0;
4114                 if (pos>0)      {
4115                         QModelIndex i = noteTableView.proxyModel.index(pos-1, Global.noteTableGuidPosition);
4116                         if (i!=null) {
4117                                 currentNoteGuid = (String)i.data();
4118                         }
4119                 }
4120         }               
4121                 if (!noteTableView.isColumnHidden(Global.noteTableGuidPosition))
4122                         showColumns();
4123                 scrollToGuid(currentNoteGuid);
4124                 logger.log(logger.HIGH, "Leaving NeverNote.noteIndexUpdated");
4125     }
4126         // Called when the list of notes is updated
4127     private void refreshEvernoteNoteList() {
4128         logger.log(logger.HIGH, "Entering NeverNote.refreshEvernoteNoteList");
4129         browserWindow.setDisabled(false);
4130                 if (selectedNoteGUIDs == null)
4131                         selectedNoteGUIDs = new ArrayList<String>();
4132                 selectedNoteGUIDs.clear();  // clear out old entries
4133                 
4134                 String saveCurrentNoteGuid = new String();
4135                 String tempNoteGuid = new String();
4136                 
4137                 int currentIndex = tabBrowser.currentIndex();
4138                 ArrayList<String> histGuids = historyGuids.get(currentIndex);
4139                 histGuids.clear();
4140                 historyPosition.put(currentIndex, 0);
4141                 
4142                 prevButton.setEnabled(false);
4143                 nextButton.setEnabled(false);
4144                 
4145                 if (currentNoteGuid == null) 
4146                         currentNoteGuid = new String();
4147                 
4148                 //determine current note guid
4149                 for (Note note : listManager.getNoteIndex()) {
4150                         tempNoteGuid = note.getGuid();
4151                         if (currentNoteGuid.equals(tempNoteGuid)) {
4152                                 saveCurrentNoteGuid = tempNoteGuid;
4153                         }
4154                 }
4155                 
4156                 if (listManager.getNoteIndex().size() == 0) {
4157                         currentNoteGuid = "";
4158                         currentNote = null;
4159                         browserWindow.clear();
4160                         browserWindow.setDisabled(true);
4161                         waitCursor(false);
4162                 } 
4163                 
4164                 if (Global.showDeleted && listManager.getNoteIndex().size() > 0 && saveCurrentNoteGuid.equals("")) {
4165                         currentNoteGuid = listManager.getNoteIndex().get(0).getGuid();
4166                         saveCurrentNoteGuid = currentNoteGuid;
4167                         refreshEvernoteNote(true);
4168                 }
4169                 
4170                 if (!saveCurrentNoteGuid.equals("")) {
4171                         refreshEvernoteNote(false);
4172                 } else {
4173                                 currentNoteGuid = "";
4174                 }
4175                 reloadTagTree(false);
4176
4177                 logger.log(logger.HIGH, "Leaving NeverNote.refreshEvernoteNoteList");
4178         } 
4179     
4180         // Called when the previous arrow button is clicked
4181         @SuppressWarnings("unused")
4182         private void previousViewedAction() {
4183                 int currentIndex = tabBrowser.currentIndex();
4184                 ArrayList<String> histGuids = historyGuids.get(currentIndex);
4185                 int histPosition = historyPosition.get(currentIndex);
4186                 boolean fromHist = fromHistory.get(currentIndex);
4187                 if (!prevButton.isEnabled())
4188                         return;
4189                 if (histPosition == 0)
4190                         return;
4191                 histPosition--;
4192                 historyPosition.put(currentIndex, histPosition);
4193                 if (histPosition <= 0)
4194                         return;
4195                 String historyGuid = histGuids.get(histPosition - 1);
4196                 fromHistory.put(currentIndex, true);
4197                 fromHist = true;
4198                 for (int i = 0; i < noteTableView.model().rowCount(); i++) {
4199                         QModelIndex modelIndex = noteTableView.model().index(i,
4200                                         Global.noteTableGuidPosition);
4201                         if (modelIndex != null) {
4202                                 SortedMap<Integer, Object> ix = noteTableView.model().itemData(
4203                                                 modelIndex);
4204                                 String tableGuid = (String) ix.values().toArray()[0];
4205                                 if (tableGuid.equals(historyGuid)) {
4206                                         noteTableView.selectRow(i);
4207                                         return;
4208                                 }
4209                         }
4210                 }
4211         }
4212         
4213     @SuppressWarnings("unused")
4214         private void nextViewedAction() {
4215         if (!nextButton.isEnabled())
4216                 return;
4217         
4218                 int currentIndex = tabBrowser.currentIndex();
4219                 ArrayList<String> histGuids = historyGuids.get(currentIndex);
4220                 int histPosition = historyPosition.get(currentIndex);
4221                 boolean fromHist = fromHistory.get(currentIndex);
4222                 String historyGuid = histGuids.get(histPosition);
4223                 histPosition++;
4224                 historyPosition.put(currentIndex, histPosition);
4225                 fromHistory.put(currentIndex, true);
4226                 fromHist = true;
4227                 for (int i = 0; i < noteTableView.model().rowCount(); i++) {
4228                         QModelIndex modelIndex = noteTableView.model().index(i,
4229                                         Global.noteTableGuidPosition);
4230                         if (modelIndex != null) {
4231                                 SortedMap<Integer, Object> ix = noteTableView.model().itemData(
4232                                                 modelIndex);
4233                                 String tableGuid = (String) ix.values().toArray()[0];
4234                                 if (tableGuid.equals(historyGuid)) {
4235                                         noteTableView.selectRow(i);
4236                                         return;
4237                                 }
4238                         }
4239                 }
4240     }
4241     // Called when the up arrow is clicked 
4242     @SuppressWarnings("unused")
4243         private void upAction() {
4244         List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
4245         int row = selections.get(0).row();
4246         if (row > 0) {
4247                 noteTableView.selectRow(row-1);
4248         }
4249     }
4250     // Called when the down arrow is clicked 
4251     @SuppressWarnings("unused")
4252         private void downAction() {
4253         List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
4254         int row = selections.get(0).row();
4255         int max = listManager.getNoteTableModel().rowCount();
4256         if (row < max-1) {
4257                 noteTableView.selectRow(row+1);
4258         }
4259     }
4260     // Update a tag string for a specific note in the list
4261     @SuppressWarnings("unused")
4262         private void updateListTags(String guid, List<String> tags) {
4263         logger.log(logger.HIGH, "Entering NeverNote.updateListTags");
4264         StringBuffer tagBuffer = new StringBuffer();
4265         for (int i=0; i<tags.size(); i++) {
4266                 tagBuffer.append(tags.get(i));
4267                 if (i<tags.size()-1)
4268                         tagBuffer.append(", ");
4269         }
4270         
4271         for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4272                 QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4273                 if (modelIndex != null) {
4274                         SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4275                         String tableGuid =  (String)ix.values().toArray()[0];
4276                         if (tableGuid.equals(guid)) {
4277                                 listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition,tagBuffer.toString());
4278                                 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
4279                                 noteTableView.proxyModel.invalidate();
4280                                 return;
4281                         }
4282                 }
4283         }
4284         logger.log(logger.HIGH, "Leaving NeverNote.updateListTags");
4285     }
4286     // Update a title for a specific note in the list
4287     @SuppressWarnings("unused")
4288         private void updateListAuthor(String guid, String author) {
4289         logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
4290
4291         for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4292                 //QModelIndex modelIndex =  noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
4293                 QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4294                 if (modelIndex != null) {
4295                         SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4296                         String tableGuid =  (String)ix.values().toArray()[0];
4297                         if (tableGuid.equals(guid)) {
4298                                 listManager.getNoteTableModel().setData(i, Global.noteTableAuthorPosition,author);
4299                                 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
4300                                 noteTableView.proxyModel.invalidate();
4301                                 return;
4302                         }       
4303                 }
4304         }
4305         
4306         logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
4307     }
4308         private void updateListNoteNotebook(String guid, String notebook) {
4309         logger.log(logger.HIGH, "Entering NeverNote.updateListNoteNotebook");
4310         listManager.getNoteTableModel().updateNoteSyncStatus(guid, false);
4311         logger.log(logger.HIGH, "Leaving NeverNote.updateListNoteNotebook");
4312     }
4313     // Update a title for a specific note in the list
4314     @SuppressWarnings("unused")
4315         private void updateListSourceUrl(String guid, String url) {
4316         logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
4317
4318         for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4319                 //QModelIndex modelIndex =  noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
4320                 QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4321                 if (modelIndex != null) {
4322 //                      SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(modelIndex);
4323                         SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4324                         String tableGuid =  (String)ix.values().toArray()[0];
4325                         if (tableGuid.equals(guid)) {
4326                                 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
4327                                 listManager.getNoteTableModel().setData(i, Global.noteTableSourceUrlPosition,url);
4328                                 noteTableView.proxyModel.invalidate();
4329                                 return;
4330                         }       
4331                 }
4332         }
4333         logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
4334     }
4335         @SuppressWarnings("unused")
4336         private void updateListGuid(String oldGuid, String newGuid) {
4337         logger.log(logger.HIGH, "Entering NeverNote.updateListTitle");
4338
4339         for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4340                 QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4341                 if (modelIndex != null) {
4342                         SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4343                         String tableGuid =  (String)ix.values().toArray()[0];
4344                         if (tableGuid.equals(oldGuid)) {
4345                                 listManager.getNoteTableModel().setData(i, Global.noteTableGuidPosition,newGuid);
4346                                 //listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
4347                                 return;
4348                         }       
4349                 }
4350         }
4351         logger.log(logger.HIGH, "Leaving NeverNote.updateListTitle");
4352     }
4353         private void updateListTagName(String guid) {
4354         logger.log(logger.HIGH, "Entering NeverNote.updateTagName");
4355                 
4356                 for (int j=0; j<listManager.getNoteIndex().size(); j++) {
4357                         if (listManager.getNoteIndex().get(j).getTagGuids().contains(guid)) {
4358                                 String newName = listManager.getTagNamesForNote(listManager.getNoteIndex().get(j));
4359
4360                                 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4361                                         QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4362                                         if (modelIndex != null) {
4363                                                 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4364                                                 String noteGuid = (String)ix.values().toArray()[0];
4365                                                 if (noteGuid.equalsIgnoreCase(listManager.getNoteIndex().get(j).getGuid())) {
4366                                                         listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition, newName);
4367                                                         i=listManager.getNoteTableModel().rowCount();
4368                                                 }
4369                                         }
4370                                 }
4371                         }
4372                 }       
4373         logger.log(logger.HIGH, "Leaving NeverNote.updateListNotebook");
4374     }
4375         private void removeListTagName(String guid) {
4376         logger.log(logger.HIGH, "Entering NeverNote.updateTagName");
4377                 
4378                 for (int j=0; j<listManager.getNoteIndex().size(); j++) {
4379                         if (listManager.getNoteIndex().get(j).getTagGuids().contains(guid)) {
4380                                 for (int i=listManager.getNoteIndex().get(j).getTagGuids().size()-1; i>=0; i--) {
4381                                         if (listManager.getNoteIndex().get(j).getTagGuids().get(i).equals(guid))
4382                                                 listManager.getNoteIndex().get(j).getTagGuids().remove(i);
4383                                 }
4384                                 
4385                                 String newName = listManager.getTagNamesForNote(listManager.getNoteIndex().get(j));
4386                                 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4387                                         QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4388                                         if (modelIndex != null) {
4389                                                 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4390                                                 String noteGuid = (String)ix.values().toArray()[0];
4391                                                 if (noteGuid.equalsIgnoreCase(listManager.getNoteIndex().get(j).getGuid())) {
4392                                                         listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition, newName);
4393                                                         i=listManager.getNoteTableModel().rowCount();
4394                                                 }
4395                                         }
4396                                 }
4397                         }
4398                 }       
4399         logger.log(logger.HIGH, "Leaving NeverNote.updateListNotebook");
4400     }
4401     private void updateListNotebookName(String oldName, String newName) {
4402         logger.log(logger.HIGH, "Entering NeverNote.updateListNotebookName");
4403
4404         for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4405                 QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableNotebookPosition); 
4406                 if (modelIndex != null) {
4407                         SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4408                         String tableName =  (String)ix.values().toArray()[0];
4409                         if (tableName.equalsIgnoreCase(oldName)) {
4410                                 listManager.getNoteTableModel().setData(i, Global.noteTableNotebookPosition, newName);
4411                         }
4412                 }
4413         }
4414         logger.log(logger.HIGH, "Leaving NeverNote.updateListNotebookName");
4415     }
4416     @SuppressWarnings("unused")
4417         private void updateListDateCreated(String guid, QDateTime date) {
4418         logger.log(logger.HIGH, "Entering NeverNote.updateListDateCreated");
4419
4420         for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4421                 QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4422                 if (modelIndex != null) {
4423                         SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4424                         String tableGuid =  (String)ix.values().toArray()[0];
4425                         if (tableGuid.equals(guid)) {
4426                                 listManager.getNoteTableModel().setData(i, Global.noteTableCreationPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
4427                                 noteTableView.proxyModel.invalidate();
4428                                 return;
4429                         }
4430                 }
4431         }
4432         logger.log(logger.HIGH, "Leaving NeverNote.updateListDateCreated");
4433     }
4434     @SuppressWarnings("unused")
4435         private void updateListDateSubject(String guid, QDateTime date) {
4436         logger.log(logger.HIGH, "Entering NeverNote.updateListDateSubject");
4437
4438         for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4439                 QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4440                 if (modelIndex != null) {
4441                         SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4442                         String tableGuid =  (String)ix.values().toArray()[0];
4443                         if (tableGuid.equals(guid)) {
4444                                 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
4445                                 listManager.getNoteTableModel().setData(i, Global.noteTableSubjectDatePosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
4446                                 noteTableView.proxyModel.invalidate();
4447                                 return;
4448                         }
4449                 }
4450         }
4451         logger.log(logger.HIGH, "Leaving NeverNote.updateListDateCreated");
4452     }
4453         private void updateListDateChanged(String guid, QDateTime date) {
4454         logger.log(logger.HIGH, "Entering NeverNote.updateListDateChanged");
4455
4456         for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4457                 QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4458                 if (modelIndex != null) {
4459                         SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4460                         String tableGuid =  (String)ix.values().toArray()[0];
4461                         if (tableGuid.equals(guid)) {
4462                                 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
4463                                 listManager.getNoteTableModel().setData(i, Global.noteTableChangedPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
4464                                 return;
4465                         }
4466                 }
4467         }
4468         logger.log(logger.HIGH, "Leaving NeverNote.updateListDateChanged");
4469     }
4470     private void updateListDateChanged() {
4471         logger.log(logger.HIGH, "Entering NeverNote.updateListDateChanged");
4472         QDateTime date = new QDateTime(QDateTime.currentDateTime());
4473         updateListDateChanged(currentNoteGuid, date);
4474         logger.log(logger.HIGH, "Leaving NeverNote.updateListDateChanged");
4475     }  
4476     // Redo scroll
4477         private void scrollToCurrentGuid() {
4478         //scrollToGuid(currentNoteGuid);
4479         List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
4480         if (selections.size() == 0)
4481                 return;
4482         QModelIndex index = selections.get(0);
4483         int row = selections.get(0).row();
4484         String guid = (String)index.model().index(row, Global.noteTableGuidPosition).data();
4485         scrollToGuid(guid);
4486     }
4487         // Scroll to the current GUID in tthe list.
4488     // Scroll to a particular index item
4489     private void scrollToGuid(String guid) {
4490         if (currentNote == null || guid == null) 
4491                 return;
4492         if (currentNote.isActive() && Global.showDeleted) {
4493                 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
4494                         if (!listManager.getNoteIndex().get(i).isActive()) {
4495                                 currentNote = listManager.getNoteIndex().get(i);
4496                                 currentNoteGuid =  currentNote.getGuid();
4497                                 i = listManager.getNoteIndex().size();
4498                         }
4499                 }
4500         }
4501         if (!currentNote.isActive() && !Global.showDeleted) {
4502                 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
4503                         if (listManager.getNoteIndex().get(i).isActive()) {
4504                                 currentNote = listManager.getNoteIndex().get(i);
4505                                 currentNoteGuid =  currentNote.getGuid();
4506                                 i = listManager.getNoteIndex().size();
4507                         }
4508                 }
4509         }
4510         QModelIndex index; 
4511         for (int i=0; i<noteTableView.model().rowCount(); i++) {
4512                 index = noteTableView.model().index(i, Global.noteTableGuidPosition);
4513                 if (currentNoteGuid.equals(index.data())) {
4514 //                      noteTableView.selectionModel().blockSignals(true);
4515                         noteTableView.selectRow(i);
4516 //                              noteTableView.selectionModel().blockSignals(false);
4517                         noteTableView.scrollTo(index, ScrollHint.EnsureVisible);  // This should work, but it doesn't
4518                                 i=listManager.getNoteTableModel().rowCount();
4519                 }
4520         }
4521         noteTableView.repaint();
4522     }
4523     // Show/Hide columns
4524     private void showColumns() {
4525                 noteTableView.setColumnHidden(Global.noteTableCreationPosition, !Global.isColumnVisible("dateCreated"));
4526                 noteTableView.setColumnHidden(Global.noteTableChangedPosition, !Global.isColumnVisible("dateChanged"));
4527                 noteTableView.setColumnHidden(Global.noteTableSubjectDatePosition, !Global.isColumnVisible("dateSubject"));
4528                 noteTableView.setColumnHidden(Global.noteTableAuthorPosition, !Global.isColumnVisible("author"));
4529                 noteTableView.setColumnHidden(Global.noteTableSourceUrlPosition, !Global.isColumnVisible("sourceUrl"));
4530                 noteTableView.setColumnHidden(Global.noteTableTagPosition, !Global.isColumnVisible("tags"));
4531                 noteTableView.setColumnHidden(Global.noteTableNotebookPosition, !Global.isColumnVisible("notebook"));
4532                 noteTableView.setColumnHidden(Global.noteTableSynchronizedPosition, !Global.isColumnVisible("synchronized"));
4533                 noteTableView.setColumnHidden(Global.noteTableGuidPosition, !Global.isColumnVisible("guid"));
4534                 noteTableView.setColumnHidden(Global.noteTableThumbnailPosition, !Global.isColumnVisible("thumbnail"));
4535                 noteTableView.setColumnHidden(Global.noteTableTitlePosition, !Global.isColumnVisible("title"));         
4536                 noteTableView.setColumnHidden(Global.noteTablePinnedPosition, !Global.isColumnVisible("pinned")); 
4537     }
4538     // Title color has changed
4539     @SuppressWarnings("unused")
4540         private void titleColorChanged(Integer color) {
4541         logger.log(logger.HIGH, "Entering NeverNote.titleColorChanged");
4542
4543         setNoteDirty();
4544         QColor backgroundColor = new QColor();
4545                 QColor foregroundColor = new QColor(QColor.black);
4546                 backgroundColor.setRgb(color);
4547                 
4548                 if (backgroundColor.rgb() == QColor.black.rgb() || backgroundColor.rgb() == QColor.blue.rgb())
4549                         foregroundColor.setRgb(QColor.white.rgb());
4550         
4551                 if (selectedNoteGUIDs.size() == 0)
4552                         selectedNoteGUIDs.add(currentNoteGuid);
4553                 
4554         for (int j=0; j<selectedNoteGUIDs.size(); j++) {
4555                 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4556                         QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4557                         if (modelIndex != null) {
4558                                 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4559                                 String tableGuid =  (String)ix.values().toArray()[0];
4560                                 if (tableGuid.equals(selectedNoteGUIDs.get(j))) {
4561                                         for (int k=0; k<Global.noteTableColumnCount; k++) {
4562                                                 listManager.getNoteTableModel().setData(i, k, backgroundColor, Qt.ItemDataRole.BackgroundRole);
4563                                                 listManager.getNoteTableModel().setData(i, k, foregroundColor, Qt.ItemDataRole.ForegroundRole);
4564                                                 listManager.updateNoteTitleColor(selectedNoteGUIDs.get(j), backgroundColor.rgb());
4565                                         }
4566                                         i=listManager.getNoteTableModel().rowCount();
4567                                 }
4568                         }
4569                 }
4570         }
4571         logger.log(logger.HIGH, "Leaving NeverNote.titleColorChanged");
4572     }
4573     // A note has been pinned or unpinned
4574         @SuppressWarnings("unused")
4575         private void notePinned() {
4576                 logger.log(logger.EXTREME, "Entering NeverNote.notePinned()");
4577                 setNoteDirty();
4578
4579         for (int j=0; j<selectedNoteGUIDs.size(); j++) {
4580                 NoteMetadata meta = listManager.getNoteMetadata().get(selectedNoteGUIDs.get(j));
4581                 boolean pinned = !meta.isPinned();
4582                 meta.setPinned(pinned);   // Toggle the pinned/unpinned 
4583                 
4584                 // Update the list & table
4585                 listManager.updateNoteMetadata(meta);   
4586                 noteTableView.proxyModel.addGuid(selectedNoteGUIDs.get(j), meta);
4587         }
4588                 logger.log(logger.EXTREME, "Leaving NeverNote.notePinned()");
4589     }
4590     // Wide list was chosen
4591     public void narrowListView() {
4592         saveNoteColumnPositions();
4593         saveNoteIndexWidth();
4594         saveWindowState();
4595                 int sortCol = noteTableView.proxyModel.sortColumn();
4596                 int sortOrder = noteTableView.proxyModel.sortOrder().value();
4597                 Global.setSortColumn(sortCol);
4598                 Global.setSortOrder(sortOrder);
4599
4600                 Global.setListView(Global.View_List_Narrow);
4601         
4602         menuBar.wideListView.blockSignals(true);
4603         menuBar.narrowListView.blockSignals(true);
4604         
4605         menuBar.wideListView.setChecked(false);
4606         menuBar.narrowListView.setChecked(true);
4607         
4608         menuBar.wideListView.blockSignals(false);
4609         menuBar.narrowListView.blockSignals(false);
4610         
4611         mainLeftRightSplitter.addWidget(noteTableView);
4612         mainLeftRightSplitter.addWidget(tabBrowser);
4613         
4614         restoreWindowState(false);
4615         noteTableView.repositionColumns();
4616         noteTableView.resizeColumnWidths();
4617         noteTableView.resizeRowHeights();
4618         
4619         sortCol = Global.getSortColumn();
4620                 sortOrder = Global.getSortOrder();
4621                 noteTableView.proxyModel.blocked = true;
4622                 noteTableView.sortByColumn(sortCol, SortOrder.resolve(sortOrder));
4623                 noteTableView.proxyModel.blocked = false;
4624
4625                 
4626         showColumns();
4627         noteTableView.load(false);
4628         refreshEvernoteNote(true);
4629         scrollToCurrentGuid();
4630     }
4631     public void wideListView() {
4632                 int sortCol = noteTableView.proxyModel.sortColumn();
4633                 int sortOrder = noteTableView.proxyModel.sortOrder().value();
4634                 Global.setSortColumn(sortCol);
4635                 Global.setSortOrder(sortOrder);
4636
4637                 saveWindowState();
4638         saveNoteColumnPositions();
4639         saveNoteIndexWidth();
4640         Global.setListView(Global.View_List_Wide);
4641
4642         menuBar.wideListView.blockSignals(true);
4643         menuBar.narrowListView.blockSignals(true);
4644         
4645         menuBar.wideListView.setChecked(true);
4646         menuBar.narrowListView.setChecked(false);
4647
4648         menuBar.wideListView.blockSignals(false);
4649         menuBar.narrowListView.blockSignals(false);
4650         browserIndexSplitter.setVisible(true);
4651         browserIndexSplitter.addWidget(noteTableView);
4652                 browserIndexSplitter.addWidget(tabBrowser);
4653                 
4654         restoreWindowState(false);
4655         noteTableView.repositionColumns();
4656         noteTableView.resizeColumnWidths();
4657         noteTableView.resizeRowHeights();
4658         
4659         sortCol = Global.getSortColumn();
4660                 sortOrder = Global.getSortOrder();
4661                 noteTableView.proxyModel.blocked = true;
4662                 noteTableView.sortByColumn(sortCol, SortOrder.resolve(sortOrder));
4663                 noteTableView.proxyModel.blocked = false;
4664
4665         showColumns();
4666         noteTableView.load(false);
4667         scrollToCurrentGuid();
4668     }
4669     // Sort order for the notebook has changed   
4670     public void tableSortOrderChanged(Integer column, Integer order) {
4671         
4672         // Find what notebook (if any) is selected.  We ignore stacks & the "All Notebooks".
4673         List<QTreeWidgetItem> selectedNotebook = notebookTree.selectedItems();
4674         if (selectedNotebook.size() > 0 && !selectedNotebook.get(0).text(0).equalsIgnoreCase("All Notebooks") && !selectedNotebook.get(0).text(2).equalsIgnoreCase("STACK")) {
4675                 QTreeWidgetItem currentSelectedNotebook = selectedNotebook.get(0);
4676                 String notebook;
4677                 notebook = currentSelectedNotebook.text(2);
4678                 conn.getNotebookTable().setSortOrder(notebook, column, order);
4679         }       
4680     }
4681     
4682     //***************************************************************
4683     @SuppressWarnings("unused")
4684         private void evernoteLinkClick(String syncGuid, String locGuid) {
4685         String guid = null;
4686         if (conn.getNoteTable().guidExists(syncGuid)) {
4687                 guid = syncGuid;
4688         } else {
4689                 // If we didn't find it via the synchronized guid, look under the local guid
4690                 // Iwe don't find it there, look to see if the GUID is posted under the local GUID, but was 
4691                 // later synchronized (that causes the guid to change so we need to find the new one).
4692                 if (conn.getNoteTable().guidExists(locGuid)) 
4693                         guid = locGuid;
4694                 else
4695                         guid = conn.getNoteTable().findAlternateGuid(locGuid);
4696         }
4697                 if (guid != null) {
4698                         openExternalEditor(guid);
4699                         return;
4700                 }
4701         
4702         //If we've gotten this far, we can't find the note
4703         QMessageBox.information(this, tr("Note Not Found"), tr("Sorry, but I can't"+
4704                         " seem to find that note."));
4705     }
4706     //***************************************************************
4707     //***************************************************************
4708     //** External editor window functions                    
4709     //***************************************************************
4710     //***************************************************************
4711         private void listDoubleClick() {
4712                 saveNote();
4713         openExternalEditor(currentNoteGuid);
4714     }
4715     private void openExternalEditor(String guid) {
4716         
4717         if (externalWindows.containsKey(guid)) {
4718                 externalWindows.get(guid).raise();
4719                 return;
4720         }
4721         
4722         Note note = conn.getNoteTable().getNote(guid, true, true, false, true, true);
4723         // We have a new external editor to create
4724         QIcon appIcon = new QIcon(iconPath+"nevernote.png");
4725         ExternalBrowse newBrowser = new ExternalBrowse(conn, cbObserver);
4726         
4727         newBrowser.setWindowIcon(appIcon);
4728         externalWindows.put(guid, newBrowser);
4729         showEditorButtons(newBrowser.getBrowserWindow());
4730         loadNoteBrowserInformation(newBrowser.getBrowserWindow(), guid, note);
4731         setupBrowserWindowListeners(newBrowser.getBrowserWindow(), false);
4732         newBrowser.windowClosing.connect(this, "externalWindowClosing(String)");
4733         //newBrowser.getBrowserWindow().noteSignal.titleChanged.connect(this, "externalWindowTitleEdited(String, String)");
4734         newBrowser.getBrowserWindow().noteSignal.tagsChanged.connect(this, "externalWindowTagsEdited(String, List)");
4735         newBrowser.contentsChanged.connect(this, "saveNoteExternalBrowser(String, String, Boolean, BrowserWindow)");
4736         newBrowser.getBrowserWindow().blockApplication.connect(this, "blockApplication(BrowserWindow)");
4737         newBrowser.getBrowserWindow().unblockApplication.connect(this, "unblockApplication()");
4738
4739         browserWindow.noteSignal.tagsChanged.connect(newBrowser, "updateTags(String, List)");
4740         browserWindow.noteSignal.titleChanged.connect(newBrowser, "updateTitle(String, String)");
4741         browserWindow.noteSignal.notebookChanged.connect(newBrowser, "updateNotebook(String, String)");
4742         
4743         newBrowser.show();
4744     }
4745     @SuppressWarnings({ "rawtypes", "unused" })
4746         private void externalWindowTagsEdited(String guid, List values) {
4747         StringBuffer line = new StringBuffer(100);
4748         for (int i=0; i<values.size(); i++) {
4749                 if (i>0) 
4750                         line.append(Global.tagDelimeter+" ");
4751                 line.append(values.get(i));
4752         }
4753         if (guid.equals(currentNoteGuid)) {
4754                 browserWindow.setTag(line.toString());
4755         }
4756     }
4757     @SuppressWarnings("unused")
4758         private void externalWindowClosing(String guid) {
4759                 externalWindows.remove(guid);
4760     }
4761     
4762         // ***************************************************************
4763         // ***************************************************************
4764         // ** タブウィンドウの機能
4765         // ***************************************************************
4766         // ***************************************************************
4767         @SuppressWarnings("unused")
4768         private void openNewTab() {
4769                 saveNote();
4770
4771                 // selectedNoteGUIDsをディープコピー
4772                 List<String> copySelected = new ArrayList<String>(selectedNoteGUIDs);
4773                 
4774                 for (int i=0; i < copySelected.size() ; i++) {
4775                         openTabEditor(copySelected.get(i));
4776                 }
4777         }
4778         
4779         // 連想ノートリストから新しいタブで開く
4780         @SuppressWarnings("unused")
4781         private void openNewTabFromRNL(){
4782                 if(rensoNotePressedItemGuid != null){
4783                         String prevCurrentNoteGuid = new String(currentNoteGuid);
4784                         
4785                         saveNote();
4786                         openTabEditor(rensoNotePressedItemGuid);
4787                         
4788                         // 連想ノートリストアイテムクリック操作を記録
4789                         conn.getHistoryTable().addHistory("rensoItemClick", prevCurrentNoteGuid, rensoNotePressedItemGuid);
4790                 }
4791         }
4792         
4793         private void openTabEditor(String guid) {
4794                 
4795                 Note note = conn.getNoteTable().getNote(guid, true, true, false, true, true);
4796                 // 新しいタブエディタを作成
4797                 TabBrowse newBrowser = new TabBrowse(conn, tabBrowser, cbObserver);
4798                 showEditorButtons(newBrowser.getBrowserWindow());
4799                 
4800                 String noteTitle = note.getTitle();
4801                 int index = tabBrowser.addNewTab(newBrowser, noteTitle);
4802                 tabWindows.put(index, newBrowser);
4803                 noteDirty.put(index, false);
4804                 
4805                 // noteTableViewの選択を変更するとselectionChangedが発生してしまうので一度切断
4806                 noteTableView.selectionModel().selectionChanged.disconnect(this, "noteTableSelection()");
4807                 loadNoteBrowserInformation(newBrowser.getBrowserWindow(), guid, note);
4808                 // 再接続
4809                 noteTableView.selectionModel().selectionChanged.connect(this, "noteTableSelection()");
4810                 
4811                 setupBrowserWindowListeners(newBrowser.getBrowserWindow(), false);
4812                 
4813                 // ExtendedInformationを必要があれば表示する
4814                 toggleNoteInformation();
4815                 // Sourceを必要があれば表示する
4816                 viewSource();
4817                 // EditorButtonsBarを必要があれば表示する
4818                 toggleEditorButtonBar();
4819
4820                 // 履歴記録のハッシュマップを初期化
4821                 ArrayList<String> histGuids = new ArrayList<String>();
4822                 historyGuids.put(index, histGuids);
4823                 historyPosition.put(index, 0);
4824                 fromHistory.put(index, false);
4825
4826                 // 履歴に今開いたノートを追加
4827                 histGuids.add(guid);
4828                 historyPosition.put(index, histGuids.size());
4829
4830                 tabBrowser.setCurrentIndex(index);
4831
4832                 if (guid != null && !guid.equals("")) {
4833                         if (!Global.showDeleted) { // ゴミ箱じゃなければ
4834                                 addBrowseHistory();
4835                         }
4836                 }
4837         }
4838         
4839         // タブが閉じられた
4840         @SuppressWarnings("unused")
4841         private void tabCloseRequested(int index) {
4842                 tabWindowClosing((TabBrowse)tabBrowser.widget(index));
4843         }
4844
4845         // タブが閉じられた
4846         private void tabWindowClosing(TabBrowse tab) {
4847                 // タブが1つしかなかったら閉じない
4848                 if (tabBrowser.count() <= 1) {
4849                         return;
4850                 }
4851
4852                 int index = tabBrowser.indexOf(tab);
4853 //              String guid = tab.getBrowserWindow().getNote().getGuid();
4854 //              String content = tab.getBrowserWindow().getContent();
4855                 BrowserWindow browser = tab.getBrowserWindow();
4856 //              // ノートが変更されていたら保存
4857 //              if (tab.getNoteDirty()) {
4858 //                      saveNoteTabBrowser(guid, content, true, browser);
4859 //              }
4860
4861                 // シグナル切断
4862                 browser.noteSignal.tagsChanged.disconnect();
4863                 browser.noteSignal.titleChanged.disconnect();
4864                 browser.noteSignal.noteChanged.disconnect();
4865                 browser.noteSignal.notebookChanged.disconnect();
4866                 browser.noteSignal.createdDateChanged.disconnect();
4867                 browser.noteSignal.alteredDateChanged.disconnect();
4868
4869                 // ノートを削除
4870                 tabBrowser.removeTab(index);
4871                 tabWindows.remove(index);
4872                 noteDirty.remove(index);
4873                 inkNote.remove(index);
4874                 readOnly.remove(index);
4875
4876                 // 履歴記録のハッシュマップを削除
4877                 historyGuids.remove(index);
4878                 historyPosition.remove(index);
4879                 fromHistory.remove(index);
4880                 
4881                 // タブのインデックスを更新(削除によって空いた部分を詰める)
4882                 for(int i = index ; tabWindows.containsKey(i + 1) ; i++){
4883                         // tabWindows
4884                         TabBrowse nextTab = tabWindows.get(i + 1);
4885                         tabWindows.put(i, nextTab);
4886                         tabWindows.remove(i + 1);
4887                         // noteDirty
4888                         boolean isNoteDirty = noteDirty.get(i + 1);
4889                         noteDirty.put(i, isNoteDirty);
4890                         noteDirty.remove(i + 1);
4891                         // inkNote
4892                         boolean isInkNote = inkNote.get(i + 1);
4893                         inkNote.put(i, isInkNote);
4894                         inkNote.remove(i + 1);
4895                         // readOnly
4896                         boolean isReadOnly = readOnly.get(i + 1);
4897                         readOnly.put(i, isReadOnly);
4898                         readOnly.remove(i + 1);
4899                         // historyGuids
4900                         ArrayList<String> histGuids = historyGuids.get(i + 1);
4901                         historyGuids.put(i, histGuids);
4902                         historyGuids.remove(i + 1);
4903                         // historyPosition
4904                         int histPosition = historyPosition.get(i + 1);
4905                         historyPosition.put(i, histPosition);
4906                         historyPosition.remove(i + 1);
4907                         // fromHistory
4908                         boolean fromHist = fromHistory.get(i + 1);
4909                         fromHistory.put(i,  fromHist);
4910                         fromHistory.remove(i + 1);
4911                 }
4912                 
4913                 // タブが残り1つになったら、閉じるボタンを消す
4914                 if (tabBrowser.count() == 1) {
4915                         tabBrowser.hideTabCloseButton(0);
4916                 }
4917                 
4918                 // タブの閉じるボタンを押すと、tabWindowClosingより先にtabWindowChangedが呼ばれてしまうので、手動で呼びなおす
4919                 tabWindowChanged(tabBrowser.currentIndex());
4920         }
4921         
4922         @SuppressWarnings("unused")
4923         private void noteAddNewTab() {
4924                 saveNote();
4925                 
4926                 // ノートを何も開いていないときは現在のタブにノート追加
4927                 if (currentNoteGuid == null || currentNoteGuid.equals("")) {
4928                         addNote();
4929                         return;
4930                 }
4931                 
4932                 // ノート追加前に開いていたノートとの関連性を記録するためにguidをとっておく
4933                 TabBrowse prevTab = (TabBrowse)tabBrowser.currentWidget();
4934                 String prevTabGuid = null;
4935                 if (prevTab.getBrowserWindow() != null && prevTab.getBrowserWindow().getNote() != null) {
4936                         prevTabGuid = prevTab.getBrowserWindow().getNote().getGuid();
4937                 }
4938                 
4939                 openEmptyTabEditor();
4940                 addNote();
4941                 
4942                 // 追加されたノートのguidを取得し、ノート追加操作履歴としてデータベースに登録
4943                 if (prevTabGuid != null && !prevTabGuid.equals("")) {
4944                         TabBrowse addedTab = (TabBrowse)tabBrowser.currentWidget();
4945                         String addedTabGuid = addedTab.getBrowserWindow().getNote().getGuid();
4946                         if (addedTabGuid != null && !addedTabGuid.equals("")) {
4947                                 if (!prevTabGuid.equals(addedTabGuid)) {
4948                                         conn.getHistoryTable().addHistory("addNewNote", prevTabGuid, addedTabGuid);
4949                                 }
4950                         }
4951                 }
4952         }
4953         
4954         private void openEmptyTabEditor() {
4955                 // 新しいタブエディタを作成
4956                 TabBrowse newBrowser = new TabBrowse(conn, tabBrowser, cbObserver);
4957                 showEditorButtons(newBrowser.getBrowserWindow());
4958                 
4959                 setupBrowserWindowListeners(newBrowser.getBrowserWindow(), false);
4960                 
4961                 int index = tabBrowser.addNewTab(newBrowser, "");
4962                 tabWindows.put(index, newBrowser);
4963                 noteDirty.put(index, false);
4964                 
4965                 // ExtendedInformationを必要があれば表示する
4966                 toggleNoteInformation();
4967                 // Sourceを必要があれば表示する
4968                 viewSource();
4969                 // EditorButtonsBarを必要があれば表示する
4970                 toggleEditorButtonBar();
4971
4972                 // 履歴記録のハッシュマップを初期化
4973                 ArrayList<String> histGuids = new ArrayList<String>();
4974                 historyGuids.put(index, histGuids);
4975                 historyPosition.put(index, 0);
4976                 fromHistory.put(index, false);
4977
4978                 tabBrowser.setCurrentIndex(index);
4979         }
4980
4981     //***************************************************************
4982     //***************************************************************
4983     //** These functions deal with Note specific things
4984     //***************************************************************
4985     //***************************************************************    
4986         private void setNoteDirty() {
4987                 for (String guid: selectedNoteGUIDs) {
4988                         setNoteDirty(guid);
4989                 }
4990         }
4991         
4992         private void setNoteDirty(String targetGuid) {
4993                 logger.log(logger.EXTREME, "Entering NeverNote.setNoteDirty()");
4994                 
4995                 // Find if the note is being edited externally.  If it is, update it.
4996                 if (externalWindows.containsKey(targetGuid)) {
4997                         QTextCodec codec = QTextCodec.codecForName("UTF-8");
4998                 QByteArray unicode =  codec.fromUnicode(browserWindow.getContent());
4999                         ExternalBrowse window = externalWindows.get(targetGuid);
5000                 window.getBrowserWindow().setContent(unicode);
5001                 }
5002                 
5003                 // 他のタブで同じノートを開いていないか探す。もしあったら、内容を更新する。
5004                 Collection<Integer> tabIndexes = tabWindows.keySet();
5005                 Iterator<Integer>       indexIterator = tabIndexes.iterator();
5006                 
5007                 for (TabBrowse tab: tabWindows.values()) {
5008                         int index = indexIterator.next();
5009                         String guid = tab.getBrowserWindow().getNote().getGuid();
5010                         
5011                         QTextCodec codec = QTextCodec.codecForName("UTF-8");
5012                         QByteArray unicode = codec.fromUnicode(browserWindow.getContent());
5013                         
5014                         if (guid.equals(guid)) {
5015                                 if (index != tabBrowser.currentIndex()) {
5016                                         TabBrowse window = tabWindows.get(index);
5017                                         window.getBrowserWindow().setContent(unicode);
5018                                 }
5019                         }
5020                 }
5021                 
5022                 // ターゲットノートがタブで開かれていて、かつDirty = trueかどうかを取得する
5023                 // If the note is dirty, then it is unsynchronized by default.
5024                 int index = -1;
5025                 boolean isNoteDirty = false;
5026                 for (TabBrowse tab: tabWindows.values()) {
5027                         if (tab.getBrowserWindow().getNote().getGuid().equals(targetGuid)) {
5028                                 index = tabBrowser.indexOf(tab);
5029                                 isNoteDirty = noteDirty.get(index);
5030                                 break;
5031                         }
5032                 }
5033                 if (isNoteDirty) {
5034                         return;
5035                 }
5036                 
5037                 // Set the note as dirty and check if its status is synchronized in the display table
5038                 // まだダーティでなく、かつタブで開かれている場合にnoteDirty = trueにする
5039                 if (index >= 0) {
5040                         noteDirty.put(index, true);
5041                 }
5042
5043                 if (listManager.getNoteMetadata().containsKey(targetGuid) &&
5044                                 listManager.getNoteMetadata().get(targetGuid).isDirty()) {
5045                                 return;
5046                 }
5047                 
5048                 // If this wasn't already marked as unsynchronized, then we need to update the table
5049                 listManager.getNoteTableModel().updateNoteSyncStatus(targetGuid, false);
5050 //      listManager.getUnsynchronizedNotes().add(targetGuid);
5051         for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
5052                 QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
5053                 if (modelIndex != null) {
5054                         SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
5055                         String tableGuid =  (String)ix.values().toArray()[0];
5056                         if (tableGuid.equals(targetGuid)) {
5057                                 listManager.getNoteTableModel().proxyModel.setData(i, Global.noteTableSynchronizedPosition, "false");
5058                                 return;
5059                         }
5060                 }
5061         }
5062         
5063                 logger.log(logger.EXTREME, "Leaving NeverNote.setNoteDirty()");
5064     }
5065     @SuppressWarnings("unused")
5066         private void saveNoteExternalBrowser(String guid, String content, Boolean save, BrowserWindow browser) {
5067                 QTextCodec codec = QTextCodec.codecForName("UTF-8");
5068         QByteArray unicode =  codec.fromUnicode(content);
5069         noteCache.remove(guid);
5070                 noteCache.put(guid, unicode.toString());
5071         if (guid.equals(currentNoteGuid)) {
5072                 int index = tabBrowser.currentIndex();
5073                 noteDirty.put(index, true);
5074                 browserWindow.setContent(unicode);
5075         } 
5076         if (save) {
5077                 thumbnailRunner.addWork("GENERATE "+ guid);
5078                 saveNote(guid, browser);
5079         }
5080         
5081     }
5082     
5083 //      private void saveNoteTabBrowser(String guid, String content, Boolean save,
5084 //                      BrowserWindow browser) {
5085 //              QTextCodec codec = QTextCodec.codecForName("UTF-8");
5086 //              QByteArray unicode = codec.fromUnicode(content);
5087 //              noteCache.remove(guid);
5088 //              noteCache.put(guid, unicode.toString());
5089 //              if (save) {
5090 //                      thumbnailRunner.addWork("GENERATE " + guid);
5091 //                      saveNote(guid, browser);
5092 //              }
5093 //      }
5094         
5095     private void saveNote() {
5096         // すべてのタブに対して、Dirtyを確認し、trueならセーブする
5097         Collection<Integer> dirtyIndex = noteDirty.keySet();
5098         Iterator<Integer> indexIterator = dirtyIndex.iterator();
5099         for (boolean isNoteDirty: noteDirty.values()) {
5100                 int index = indexIterator.next();
5101                 if (isNoteDirty) {
5102                         if (index < 0) {
5103                                 return;
5104                         }
5105                         BrowserWindow b = tabWindows.get(index).getBrowserWindow();
5106                         String guid = b.getNote().getGuid();
5107                         saveNote(guid, b);
5108                         thumbnailRunner.addWork("GENERATE "+ guid);
5109                         noteDirty.put(index, false);
5110                 }
5111         }
5112     }
5113     private void saveNote(String guid, BrowserWindow window) {
5114                 logger.log(logger.EXTREME, "Inside NeverNote.saveNote()");
5115                 waitCursor(true);
5116                 
5117                 logger.log(logger.EXTREME, "Saving to cache");
5118                 QTextCodec codec = QTextCodec.codecForLocale();
5119 //              QTextDecoder decoder = codec.makeDecoder();
5120                 codec = QTextCodec.codecForName("UTF-8");
5121         QByteArray unicode =  codec.fromUnicode(window.getContent());
5122                 noteCache.put(guid, unicode.toString());
5123                         
5124                 logger.log(logger.EXTREME, "updating list manager");
5125                 listManager.updateNoteContent(guid, window.getContent());
5126                 logger.log(logger.EXTREME, "Updating title");
5127                 listManager.updateNoteTitle(guid, window.getTitle());
5128                 updateListDateChanged();
5129
5130                 logger.log(logger.EXTREME, "Looking through note index for refreshed note");
5131                 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
5132                 if (listManager.getNoteIndex().get(i).getGuid().equals(guid)) {
5133                         currentNote = listManager.getNoteIndex().get(i);
5134                         i = listManager.getNoteIndex().size();
5135                 }
5136         }
5137         waitCursor(false);
5138     }
5139     // Get a note from Evernote (and put it in the browser)
5140         private void refreshEvernoteNote(boolean reload) {
5141                 logger.log(logger.HIGH, "Entering NeverNote.refreshEvernoteNote");
5142                 
5143                 if (Global.disableViewing) {
5144                         browserWindow.setEnabled(false);
5145                         return;
5146                 }
5147                 inkNote.put(tabBrowser.currentIndex(), false);
5148                 readOnly.put(tabBrowser.currentIndex(), false);
5149                 
5150                 if (Global.showDeleted || currentNoteGuid == null || currentNoteGuid.equals("")) {
5151                         readOnly.put(tabBrowser.currentIndex(), true);
5152                 }
5153                 Global.cryptCounter =0;
5154                 if (readOnly.get(tabBrowser.currentIndex())) {
5155                         browserWindow.setReadOnly(true);
5156                 }
5157                 
5158                 if (!reload)
5159                         return;
5160                 
5161                 waitCursor(true);
5162                 browserWindow.loadingData(true);
5163
5164                 currentNote = conn.getNoteTable().getNote(currentNoteGuid, true,true,false,false,true);
5165                 if (currentNote == null) {
5166                         waitCursor(false);
5167                         return;
5168                 }
5169                 
5170                 tabBrowser.setTabTitle(tabBrowser.currentIndex(), currentNote.getTitle());
5171                 
5172                 loadNoteBrowserInformation(browserWindow, currentNoteGuid, currentNote);
5173         }
5174
5175         private void loadNoteBrowserInformation(BrowserWindow browser, String guid, Note note) {
5176                 NoteFormatter   formatter = new NoteFormatter(logger, conn, tempFiles);
5177                 formatter.setNote(note, Global.pdfPreview());
5178                 formatter.setHighlight(listManager.getEnSearch());
5179                 QByteArray js;
5180                 int tabIndex = -1;
5181                 
5182                 // 対象のタブインデックスを取得
5183                 for (TabBrowse tab: tabWindows.values()) {
5184                         if (tab.getBrowserWindow() == browser) {
5185                                 tabIndex = tabBrowser.indexOf(tab);
5186                                 break;
5187                         }
5188                 }
5189                 
5190                 if (!noteCache.containsKey(guid)) {
5191                         js = new QByteArray();
5192                         // We need to prepend the note with <HEAD></HEAD> or encoded characters are ugly 
5193                         js.append("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">");               
5194                         js.append("<style type=\"text/css\">.en-crypt-temp { border-collapse:collapse; border-style:solid; border-color:blue; padding:0.0mm 0.0mm 0.0mm 0.0mm; }</style>");
5195                         js.append("<style type=\"text/css\">en-hilight { background-color: rgb(255,255,0) }</style>");
5196                         js.append("<style> img { height:auto; width:auto; max-height:auto; max-width:100%; }</style>");
5197                         if (Global.displayRightToLeft())
5198                                 js.append("<style> body { direction:rtl; }</style>");
5199                         js.append("<style type=\"text/css\">en-spell { text-decoration: none; border-bottom: dotted 1px #cc0000; }</style>");
5200                         js.append("</head>");
5201                         formatter.setNote(note, Global.pdfPreview());
5202                         js.append(formatter.rebuildNoteHTML());
5203                         js.append("</HTML>");
5204                         js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml.dtd'>", "");
5205                         js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml2.dtd'>", "");
5206                         js.replace("<?xml version='1.0' encoding='UTF-8'?>", "");
5207 //              if (Global.enableHTMLEntitiesFix) {
5208 //                      browser.getBrowser().setContent(new QByteArray(StringEscapeUtils.unescapeHtml(js.toString())));
5209 //              } else
5210                         browser.setContent(js);
5211                         noteCache.put(guid, js.toString());
5212
5213                         if (formatter.resourceError)
5214                                 resourceErrorMessage(tabIndex);
5215                         if (formatter.formatError) {
5216                                 waitCursor(false);
5217                              QMessageBox.information(this, tr("Error"),
5218                                                 tr("NeighborNote had issues formatting this note." +
5219                                                 " To protect your data this note is being marked as read-only."));      
5220                              waitCursor(true);
5221                         }
5222                         
5223                         if (tabIndex >= 0) {
5224                                 readOnly.put(tabIndex, formatter.readOnly);
5225                                 inkNote.put(tabIndex, formatter.inkNote);
5226                         } 
5227                         
5228                         if (tabIndex >= 0 && readOnly.get(tabIndex)) {
5229                                 readOnlyCache.put(guid, true);
5230                         }
5231                         if (tabIndex >= 0 && inkNote.get(tabIndex)) {
5232                                 inkNoteCache.put(guid, true);
5233                         }
5234                         
5235                 } else {
5236                         logger.log(logger.HIGH, "Note content is being pulled from the cache");
5237                         String cachedContent = formatter.modifyCachedTodoTags(noteCache.get(guid));
5238                         js = new QByteArray(cachedContent);
5239                         browser.setContent(js);
5240                         if (readOnlyCache.containsKey(guid) && tabIndex >= 0) {
5241                                 readOnly.put(tabIndex, true);
5242                         } else {
5243                                 readOnly.put(tabIndex, false);
5244                         }
5245                         if (inkNoteCache.containsKey(guid) && tabIndex >= 0) {
5246                                 inkNote.put(tabIndex, true);
5247                         } else {
5248                                 inkNote.put(tabIndex, false);
5249                         }
5250                 }
5251                 if (conn.getNoteTable().isThumbnailNeeded(guid)) {
5252                         thumbnailHTMLReady(guid, js, Global.calculateThumbnailZoom(js.toString()));
5253                 }
5254                 if (tabIndex >= 0 && (readOnly.get(tabIndex) || inkNote.get(tabIndex) || 
5255                                 (note.getAttributes() != null && note.getAttributes().getContentClass() != null && note.getAttributes().getContentClass() != "")))
5256                         browser.getBrowser().page().setContentEditable(false);  // We don't allow editing of ink notes
5257                 else
5258                         browser.getBrowser().page().setContentEditable(true);
5259                 if (tabIndex >= 0) {
5260                         browser.setReadOnly(readOnly.get(tabIndex));
5261                         deleteButton.setEnabled(!readOnly.get(tabIndex));
5262                         tagButton.setEnabled(!readOnly.get(tabIndex));
5263                         menuBar.noteDelete.setEnabled(!readOnly.get(tabIndex));
5264                         menuBar.noteTags.setEnabled(!readOnly.get(tabIndex));
5265                 }
5266                 browser.setNote(note);
5267                 
5268                 if (note != null && note.getNotebookGuid() != null && 
5269                                 conn.getNotebookTable().isLinked(note.getNotebookGuid())) {
5270                         deleteButton.setEnabled(false);
5271                         menuBar.notebookDeleteAction.setEnabled(false);
5272                 } else {
5273                         deleteButton.setEnabled(true);
5274                         menuBar.notebookDeleteAction.setEnabled(true);
5275                 }
5276                 
5277                 // Build a list of non-closed notebooks
5278                 List<Notebook> nbooks = new ArrayList<Notebook>();
5279                 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
5280                         boolean found=false;
5281                         for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
5282                                 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid())) 
5283                                         found = true;
5284                         }
5285                         if (!found)
5286                                 nbooks.add(listManager.getNotebookIndex().get(i));
5287                 }
5288                 
5289                 browser.setTitle(note.getTitle());
5290                 browser.setTag(getTagNamesForNote(note));
5291                 browser.setAuthor(note.getAttributes().getAuthor());
5292
5293                 browser.setAltered(note.getUpdated());
5294                 browser.setCreation(note.getCreated());
5295                 if (note.getAttributes().getSubjectDate() > 0)
5296                         browser.setSubjectDate(note.getAttributes().getSubjectDate());
5297                 else
5298                         browser.setSubjectDate(note.getCreated());
5299                 browser.setUrl(note.getAttributes().getSourceURL());
5300                 
5301                 FilterEditorTags tagFilter = new FilterEditorTags(conn, logger);
5302                 List<Tag> tagList = tagFilter.getValidTags(note);
5303                 browser.setAllTags(tagList);
5304                 
5305                 browser.setCurrentTags(note.getTagNames());
5306                 for (TabBrowse tab: tabWindows.values()) {
5307                         if (tab.getBrowserWindow().getNote().getGuid().equals(guid)) {
5308                                 int index = tabBrowser.indexOf(tab);
5309                                 noteDirty.put(index, false);
5310                                 break;
5311                         }
5312                 }
5313                 
5314                 scrollToGuid(guid);
5315                 
5316                 browser.loadingData(false);
5317                 if (thumbnailViewer.isActiveWindow())
5318                         thumbnailView();
5319                 
5320                 FilterEditorNotebooks notebookFilter = new FilterEditorNotebooks(conn, logger);
5321                 browser.setNotebookList(notebookFilter.getValidNotebooks(note, listManager.getNotebookIndex()));
5322
5323                 waitCursor(false);
5324                 logger.log(logger.HIGH, "Leaving NeverNote.refreshEvernoteNote");
5325         }
5326         
5327         @SuppressWarnings("unused")
5328         private void toggleNoteAttributes() {
5329                 menuBar.noteAttributes.setChecked(!menuBar.noteAttributes.isChecked());
5330                 toggleNoteInformation();
5331         }
5332         
5333         // Save a generated thumbnail
5334         private void toggleNoteInformation() {
5335                 logger.log(logger.HIGH, "Entering NeverNote.toggleNoteInformation");
5336         
5337                 boolean isChecked = menuBar.noteAttributes.isChecked();
5338                 
5339         for(int i = 0; i < tabBrowser.count(); i++){
5340                 BrowserWindow browser = ((TabBrowse) tabBrowser.widget(i)).getBrowserWindow();
5341                 boolean isExtended = browser.isExtended();
5342                 if((isChecked && !isExtended) || (!isChecked && isExtended)){
5343                         browser.toggleInformation();
5344                 }
5345         }
5346         
5347         menuBar.noteAttributes.setChecked(browserWindow.isExtended());
5348         Global.saveWindowVisible("noteInformation", browserWindow.isExtended());
5349         logger.log(logger.HIGH, "Leaving NeverNote.toggleNoteInformation");
5350     }
5351         
5352         // Listener triggered when a print button is pressed
5353     @SuppressWarnings("unused")
5354         private void printNote() {
5355                 logger.log(logger.HIGH, "Entering NeverNote.printNote");
5356
5357         QPrintDialog dialog = new QPrintDialog();
5358         if (dialog.exec() == QDialog.DialogCode.Accepted.value()) {
5359                 QPrinter printer = dialog.printer();
5360                 browserWindow.getBrowser().print(printer);
5361         }
5362                 logger.log(logger.HIGH, "Leaving NeverNote.printNote");
5363
5364     }
5365     // Listener triggered when the email button is pressed
5366     @SuppressWarnings("unused")
5367         private void emailNote() {
5368         logger.log(logger.HIGH, "Entering NeverNote.emailNote");
5369         
5370         if (Desktop.isDesktopSupported()) {
5371             Desktop desktop = Desktop.getDesktop();
5372             
5373             String text2 = browserWindow.getContentsToEmail();
5374             QUrl url = new QUrl("mailto:");
5375             url.addQueryItem("subject", currentNote.getTitle());
5376 //            url.addQueryItem("body", QUrl.toPercentEncoding(text2).toString());
5377             url.addQueryItem("body", text2);
5378             QDesktopServices.openUrl(url);
5379         }
5380 /*            
5381             
5382             if (desktop.isSupported(Desktop.Action.MAIL)) {
5383                 URI uriMailTo = null;
5384                 try {
5385                         //String text = browserWindow.getBrowser().page().currentFrame().toPlainText();
5386                         String text = browserWindow.getContentsToEmail();
5387                         //text = "<b>" +text +"</b>";
5388                                         uriMailTo = new URI("mailto", "&SUBJECT="+currentNote.getTitle()
5389                                                         +"&BODY=" +text, null);
5390                                         uriMailTo = new URI("mailto", "&SUBJECT="+currentNote.getTitle()
5391                                                         +"&ATTACHMENT=d:/test.pdf", null);
5392                                         desktop.mail(uriMailTo);
5393                                 } catch (URISyntaxException e) {
5394                                         e.printStackTrace();
5395                                 } catch (IOException e) {
5396                                         e.printStackTrace();
5397                                 }
5398
5399             }
5400
5401         }     
5402  */     
5403         logger.log(logger.HIGH, "Leaving NeverNote.emailNote");
5404     }
5405         // Reindex all notes
5406     @SuppressWarnings("unused")
5407         private void fullReindex() {
5408         logger.log(logger.HIGH, "Entering NeverNote.fullReindex");
5409         indexRunner.addWork("REINDEXALL");
5410         setMessage(tr("Database will be reindexed."));
5411         logger.log(logger.HIGH, "Leaving NeverNote.fullReindex");
5412     }
5413     // Listener when a user wants to reindex a specific note
5414     @SuppressWarnings("unused")
5415         private void reindexNote() {
5416         logger.log(logger.HIGH, "Entering NeverNote.reindexNote");
5417                 for (int i=0; i<selectedNoteGUIDs.size(); i++) {
5418                         indexRunner.addWork("REINDEXNOTE "+selectedNoteGUIDs.get(i));
5419                 }
5420                 if (selectedNotebookGUIDs.size() > 1)
5421                         setMessage(tr("Notes will be reindexed."));
5422                 else
5423                         setMessage(tr("Note will be reindexed."));
5424         logger.log(logger.HIGH, "Leaving NeverNote.reindexNote");
5425     }
5426     // Delete the note
5427     @SuppressWarnings("unused")
5428         private void deleteNote() {
5429         logger.log(logger.HIGH, "Entering NeverNote.deleteNote");
5430         if (currentNote == null) 
5431                 return;
5432         if (currentNoteGuid.equals(""))
5433                 return;
5434         
5435         String title = null;
5436         if (selectedNoteGUIDs.size() == 1)
5437                 title = conn.getNoteTable().getNote(selectedNoteGUIDs.get(0),false,false,false,false,false).getTitle();
5438
5439         // If we are deleting non-trash notes
5440         if (currentNote.isActive()) { 
5441                 if (Global.verifyDelete()) {
5442                         String msg;
5443                         if (selectedNoteGUIDs.size() > 1) {
5444                                 msg = new String(tr("Delete ") +selectedNoteGUIDs.size() +" notes?");
5445                         } else {
5446                                 if (title != null)
5447                                         msg = new String(tr("Delete note \"") +title +"\"?");
5448                                 else                            
5449                                         msg = new String(tr("Delete note selected note?"));
5450                         }
5451                         if (QMessageBox.question(this, tr("Confirmation"), msg,
5452                                         QMessageBox.StandardButton.Yes, 
5453                                         QMessageBox.StandardButton.No)==StandardButton.No.value() && Global.verifyDelete() == true) {
5454                                         return;
5455                         }
5456                 }
5457                 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals("")) {
5458                         selectedNoteGUIDs.add(currentNoteGuid);
5459                 }
5460                 
5461                 List<String> deleteNoteGUIDs = new ArrayList<String>(selectedNoteGUIDs);        // タブを閉じるとselectedNoteGUIDsが変わってしまうのでその前にコピー
5462                 closeTabs(selectedNoteGUIDs);
5463                 for (String guid : deleteNoteGUIDs) {
5464                         listManager.deleteNote(guid);
5465                 }
5466                 
5467                 closeExternalWindows(deleteNoteGUIDs);
5468         } else { 
5469                 // If we are deleting from the trash.
5470                 if (Global.verifyDelete()) {
5471                         String msg;
5472                         if (selectedNoteGUIDs.size() > 1) {
5473                                 msg = new String(tr("Permanently delete ") +selectedNoteGUIDs.size() +" notes?");
5474                         } else {
5475                                 if (title != null)
5476                                 msg = new String(tr("Permanently delete note \"") +title +"\"?");
5477                                 else
5478                                         msg = new String(tr("Permanently delete note selected note?"));
5479                         }
5480                         if (QMessageBox.question(this, "Confirmation", msg,
5481                                 QMessageBox.StandardButton.Yes, 
5482                                         QMessageBox.StandardButton.No)==StandardButton.No.value()) {                                            
5483                                         return;
5484                         }
5485                 }
5486                 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals("")) 
5487                         selectedNoteGUIDs.add(currentNoteGuid);
5488                 
5489                 List<String> deleteNoteGUIDs = new ArrayList<String>(selectedNoteGUIDs);        // タブを閉じるとselectedNoteGUIDsが変わってしまうのでその前にコピー
5490                 for (int i=deleteNoteGUIDs.size()-1; i>=0; i--) {
5491                         for (int j=listManager.getNoteTableModel().rowCount()-1; j>=0; j--) {
5492                         QModelIndex modelIndex =  listManager.getNoteTableModel().index(j, Global.noteTableGuidPosition);
5493                         if (modelIndex != null) {
5494                                 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
5495                                 String tableGuid =  (String)ix.values().toArray()[0];
5496                                 if (tableGuid.equals(deleteNoteGUIDs.get(i))) {
5497                                         listManager.getNoteTableModel().removeRow(j);
5498                                         j=-1;
5499                                 }
5500                         }
5501                 }
5502                         closeTab(deleteNoteGUIDs.get(i));
5503                         listManager.expungeNote(deleteNoteGUIDs.get(i));
5504                         
5505                         conn.getHistoryTable().expungeHistory(deleteNoteGUIDs.get(i));
5506                         conn.getExcludedTable().expungeExcludedNote(deleteNoteGUIDs.get(i));
5507                         conn.getStaredTable().expungeStaredNote(deleteNoteGUIDs.get(i));
5508                 }
5509                 
5510                 closeExternalWindows(deleteNoteGUIDs);
5511         }
5512         
5513                 if (currentNoteGuid == null || currentNoteGuid.equals("")) {
5514                         menuBar.noteAddNewTab.setEnabled(false);
5515                 }
5516                 
5517         listManager.loadNotesIndex();
5518         noteIndexUpdated(false);
5519         refreshEvernoteNote(true);
5520         scrollToGuid(currentNoteGuid);
5521         logger.log(logger.HIGH, "Leaving NeverNote.deleteNote");
5522     }
5523     
5524     // 対象ノートをタブで開いていたら閉じる
5525     private void closeTabs(List<String> noteGUIDs) {
5526         for (String guid : noteGUIDs) {
5527                 closeTab(guid);
5528         }
5529     }
5530     
5531     // 対象ノートをタブで開いていたら閉じる
5532     private void closeTab(String noteGUID) {
5533         List<TabBrowse> closeTabs = new ArrayList<TabBrowse>();
5534         
5535         for (TabBrowse tab : tabWindows.values()) {
5536                 String guid = tab.getBrowserWindow().getNote().getGuid();
5537                 
5538                 if (guid.equals(noteGUID)) {
5539                         closeTabs.add(tab);
5540                 }
5541         }
5542         
5543         for (TabBrowse tab : closeTabs) {
5544                 tabWindowClosing(tab);
5545         }
5546     }
5547     
5548     // 対象ノートを外部ウィンドウで開いていたら閉じる
5549     private void closeExternalWindows(List<String> noteGUIDs) {
5550                 List<ExternalBrowse> closeWindows = new ArrayList<ExternalBrowse>();
5551                 
5552                 for (Map.Entry<String, ExternalBrowse> e : externalWindows.entrySet()) {
5553                         for (String guid : noteGUIDs) {
5554                                 if (guid.equals(e.getKey())) {
5555                                         closeWindows.add(e.getValue());
5556                                 }
5557                         }
5558                 }
5559                 
5560                 for (ExternalBrowse externalBrowse : closeWindows) {
5561                         externalBrowse.close();
5562                 }
5563     }
5564     
5565     // Add a new note
5566         private void addNote() {
5567         logger.log(logger.HIGH, "Inside NeverNote.addNote");
5568 //      browserWindow.setEnabled(true);
5569         browserWindow.setReadOnly(false);
5570         saveNote();
5571         Calendar currentTime = new GregorianCalendar();
5572         StringBuffer noteString = new StringBuffer(100);
5573         noteString.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
5574                 "<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">\n" +
5575                 "<en-note>\n");
5576         
5577         if (Global.overrideDefaultFont()) {
5578                 noteString.append("<font face=\"" +Global.getDefaultFont() +"\" >");
5579                 noteString.append("<span style=\"font-size:" +Global.getDefaultFontSize() +"pt;\">");
5580                 noteString.append("<br clear=\"none\" />\n");
5581                 noteString.append("</span>\n</font>\n");
5582         } else
5583                 noteString.append("<br clear=\"none\" />\n");
5584         noteString.append("</en-note>");
5585         
5586         Long l = new Long(currentTime.getTimeInMillis());
5587         String randint = new String(Long.toString(l));          
5588         
5589         // Find a notebook.  We first look for a selected notebook (the "All Notebooks" one doesn't count).  
5590         // Then we look
5591         // for the first non-archived notebook.  Finally, if nothing else we 
5592         // pick the first notebook in the list.
5593         String notebook = null;
5594         listManager.getNotebookIndex().get(0).getGuid();
5595         List<QTreeWidgetItem> selectedNotebook = notebookTree.selectedItems();
5596         if (selectedNotebook.size() > 0 && !selectedNotebook.get(0).text(0).equalsIgnoreCase("All Notebooks") && !selectedNotebook.get(0).text(2).equalsIgnoreCase("STACK")) {
5597                 QTreeWidgetItem currentSelectedNotebook = selectedNotebook.get(0);
5598                 notebook = currentSelectedNotebook.text(2);
5599         } else {
5600                 boolean found = false;
5601                 List<Notebook> goodNotebooks = new ArrayList<Notebook>();
5602                 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
5603                         boolean match = false;
5604                         for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
5605                                 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid())) {
5606                                         match = true;
5607                                         j = listManager.getArchiveNotebookIndex().size();
5608                                 }
5609                         }
5610                         if (!match)
5611                                 //goodNotebooks.add(listManager.getNotebookIndex().get(i).deepCopy());
5612                                 goodNotebooks.add((Notebook)Global.deepCopy(listManager.getNotebookIndex().get(i)));
5613                 }
5614                 // Now we have a list of good notebooks, so we can look for the default
5615                 found = false;
5616                 for (int i=0; i<goodNotebooks.size(); i++) {
5617                         if (goodNotebooks.get(i).isDefaultNotebook()) {
5618                                 notebook = goodNotebooks.get(i).getGuid();
5619                                 found = true;
5620                                 i = goodNotebooks.size();
5621                         }
5622                 }
5623                 
5624                 if (goodNotebooks.size() > 0 && !found)
5625                         notebook = goodNotebooks.get(0).getGuid();
5626      
5627                 if (notebook==null)
5628                         notebook = listManager.getNotebookIndex().get(0).getGuid();             
5629         }
5630         
5631         Note newNote = new Note();
5632         newNote.setUpdateSequenceNum(0);
5633         newNote.setGuid(randint);
5634         newNote.setNotebookGuid(notebook);
5635         newNote.setTitle("Untitled Note");
5636         newNote.setContent(noteString.toString());
5637         newNote.setDeleted(0);
5638         newNote.setCreated(System.currentTimeMillis());
5639         newNote.setUpdated(System.currentTimeMillis());
5640         newNote.setActive(true);
5641         NoteAttributes na = new NoteAttributes();
5642         na.setLatitude(0.0);
5643         na.setLongitude(0.0);
5644         na.setAltitude(0.0);
5645         newNote.setAttributes(new NoteAttributes());
5646                 newNote.setTagGuids(new ArrayList<String>());
5647                 newNote.setTagNames(new ArrayList<String>());
5648         
5649         // If new notes are to be created based upon the selected tags, then we need to assign the tags
5650         if (Global.newNoteWithSelectedTags()) { 
5651                 List<QTreeWidgetItem> selections = tagTree.selectedItems();
5652                 QTreeWidgetItem currentSelection;
5653                 for (int i=0; i<selections.size(); i++) {
5654                         currentSelection = selections.get(i);
5655                         newNote.getTagGuids().add(currentSelection.text(2));
5656                         newNote.getTagNames().add(currentSelection.text(0));
5657                 }
5658         }
5659         
5660         conn.getNoteTable().addNote(newNote, true);
5661         NoteMetadata metadata = new NoteMetadata();
5662         metadata.setGuid(newNote.getGuid());
5663         metadata.setDirty(true);
5664         listManager.addNote(newNote, metadata);
5665 //      noteTableView.insertRow(newNote, true, -1);
5666         
5667         String prevCurrentNoteGuid = new String(currentNoteGuid);
5668         
5669         currentNote = newNote;
5670         currentNoteGuid = currentNote.getGuid();
5671         // IFIXED こいつのせいで、ノート追加時にcurrentNoteGuidが更新されないので消す
5672         // noteTableView.clearSelection();
5673         
5674         // 新規に作成したノートとそれまで開いていたノートの関連性を追加
5675         if (prevCurrentNoteGuid != null && !prevCurrentNoteGuid.equals("")) {
5676                 if (currentNoteGuid != null && !currentNoteGuid.equals("")) {
5677                         conn.getHistoryTable().addHistory("addNewNote", prevCurrentNoteGuid, currentNoteGuid);
5678                 }
5679         }
5680         
5681         refreshEvernoteNote(true);
5682         listManager.countNotebookResults(listManager.getNoteIndex());
5683         browserWindow.titleLabel.setFocus();
5684         browserWindow.titleLabel.selectAll();
5685 //      notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
5686         
5687         // If the window is hidden, then we want to popup this in an external window & 
5688         if (!isVisible())
5689                 listDoubleClick();
5690         waitCursor(false);
5691         logger.log(logger.HIGH, "Leaving NeverNote.addNote");
5692     }
5693     // Restore a note from the trash;
5694     @SuppressWarnings("unused")
5695         private void restoreNote() {
5696         waitCursor(true);
5697                 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals("")) 
5698                         selectedNoteGUIDs.add(currentNoteGuid);
5699                 for (int i=0; i<selectedNoteGUIDs.size(); i++) {
5700                         listManager.restoreNote(selectedNoteGUIDs.get(i));
5701                 }
5702         currentNoteGuid = "";
5703         listManager.loadNotesIndex();
5704         noteIndexUpdated(false);
5705         waitCursor(false);
5706     }
5707     // Search a note for specific txt
5708     @SuppressWarnings("unused")
5709         private void findText() {
5710         find.show();
5711         find.setFocusOnTextField();
5712     }
5713     @SuppressWarnings("unused")
5714         private void doFindText() {
5715         browserWindow.getBrowser().page().findText(find.getText(), find.getFlags());
5716         find.setFocus();
5717     }
5718     @SuppressWarnings("unused")
5719         private void updateNoteTitle(String guid, String title) {
5720         listManager.setNoteSynchronized(guid, false);
5721         
5722         // We do this manually because if we've edited the note in an 
5723         // external window we run into the possibility of signal recursion
5724         // looping.
5725         if (guid.equals(currentNoteGuid)) {
5726                 browserWindow.titleLabel.blockSignals(true);
5727                 browserWindow.titleLabel.setText(title);
5728                 browserWindow.titleLabel.blockSignals(false);
5729         }
5730     }
5731     // Signal received that note content has changed.  Normally we just need the guid to remove
5732     // it from the cache.
5733     @SuppressWarnings("unused")
5734         private void invalidateNoteCache(String guid, String content) {
5735         noteCache.remove(guid);
5736                 refreshEvernoteNote(true);
5737     }
5738     // Signal received that a note guid has changed
5739     @SuppressWarnings("unused")
5740         private void noteGuidChanged(String oldGuid, String newGuid) {
5741         if (noteCache.containsKey(oldGuid)) {
5742                 if (!oldGuid.equals(currentNoteGuid)) {
5743                         String cache = noteCache.get(oldGuid);
5744                         noteCache.put(newGuid, cache);
5745                         noteCache.remove(oldGuid);
5746                 } else {
5747                         noteCache.remove(oldGuid);
5748                         noteCache.put(newGuid, browserWindow.getContent());
5749                 }
5750         }
5751   
5752         listManager.updateNoteGuid(oldGuid, newGuid, false);
5753         if (currentNoteGuid.equals(oldGuid)) {
5754                 if (currentNote != null)
5755                         currentNote.setGuid(newGuid);
5756                 currentNoteGuid = newGuid;
5757         }
5758                 
5759         if (externalWindows.containsKey(oldGuid)) {
5760                         ExternalBrowse b = externalWindows.get(oldGuid);
5761                         externalWindows.remove(oldGuid);
5762                         b.getBrowserWindow().getNote().setGuid(newGuid);
5763                         externalWindows.put(newGuid, b);
5764                 }
5765         
5766                 for(int i = 0; i < tabBrowser.count(); i++){
5767                         TabBrowse b = (TabBrowse)tabBrowser.widget(i);
5768                         if (b.getBrowserWindow().getNote().getGuid().equals(oldGuid)) {
5769                                 b.getBrowserWindow().getNote().setGuid(newGuid);
5770                         }
5771                 }
5772
5773         for (int i=0; i<listManager.getNoteIndex().size(); i++) {
5774                 if (listManager.getNoteIndex().get(i).getGuid().equals(newGuid)) {
5775                         noteTableView.proxyModel.addGuid(newGuid, listManager.getNoteMetadata().get(newGuid));
5776                         i=listManager.getNoteIndex().size();
5777                 }
5778         }
5779         
5780         if (listManager.getNoteTableModel().metaData.containsKey(oldGuid)) {
5781                 NoteMetadata meta = listManager.getNoteTableModel().metaData.get(oldGuid);
5782                 listManager.getNoteTableModel().metaData.put(newGuid, meta);
5783                 listManager.getNoteTableModel().metaData.remove(oldGuid);
5784         }
5785         
5786     }
5787         
5788     // Toggle the note editor button bar
5789     // すべてのタブに
5790     private void toggleEditorButtonBar() {
5791         boolean isChecked = menuBar.showEditorBar.isChecked();
5792         
5793         for(int i = 0; i < tabBrowser.count(); i++){
5794                 BrowserWindow browser = ((TabBrowse) tabBrowser.widget(i)).getBrowserWindow();
5795                 boolean isVisible = browser.buttonsVisible;
5796
5797                 if (isChecked && !isVisible) {
5798                         browser.buttonsVisible = true;
5799                         showEditorButtons(browser);
5800                 } else if(!isChecked && isVisible) {
5801                         browser.hideButtons();
5802                 }
5803         }
5804
5805         Global.saveWindowVisible("editorButtonBar", browserWindow.buttonsVisible);
5806     }
5807     
5808     // Show editor buttons
5809     private void showEditorButtons(BrowserWindow browser) {
5810                 browser.buttonLayout.setVisible(true);
5811                 browser.undoAction.setVisible(false);
5812                 
5813                 browser.undoButton.setVisible(false);
5814
5815                 browser.undoAction.setVisible(Global.isEditorButtonVisible("undo"));
5816                 browser.redoAction.setVisible(Global.isEditorButtonVisible("redo"));
5817                 browser.cutAction.setVisible(Global.isEditorButtonVisible("cut"));
5818                 browser.copyAction.setVisible(Global.isEditorButtonVisible("copy"));
5819                 browser.pasteAction.setVisible(Global.isEditorButtonVisible("paste"));
5820                 browser.strikethroughAction.setVisible(Global.isEditorButtonVisible("strikethrough"));
5821                 browser.underlineAction.setVisible(Global.isEditorButtonVisible("underline"));
5822                 browser.boldAction.setVisible(Global.isEditorButtonVisible("bold"));
5823                 browser.italicAction.setVisible(Global.isEditorButtonVisible("italic"));
5824                 browser.hlineAction.setVisible(Global.isEditorButtonVisible("hline"));
5825                 browser.indentAction.setVisible(Global.isEditorButtonVisible("indent"));
5826                 browser.outdentAction.setVisible(Global.isEditorButtonVisible("outdent"));
5827                 browser.bulletListAction.setVisible(Global.isEditorButtonVisible("bulletList"));
5828                 browser.numberListAction.setVisible(Global.isEditorButtonVisible("numberList"));
5829                 browser.fontListAction.setVisible(Global.isEditorButtonVisible("font"));
5830                 browser.fontSizeAction.setVisible(Global.isEditorButtonVisible("fontSize"));
5831                 browser.fontColorAction.setVisible(Global.isEditorButtonVisible("fontColor"));
5832                 browser.fontHilightAction.setVisible(Global.isEditorButtonVisible("fontHilight"));
5833                 browser.leftAlignAction.setVisible(Global.isEditorButtonVisible("alignLeft"));
5834                 browser.centerAlignAction.setVisible(Global.isEditorButtonVisible("alignCenter"));
5835                 browser.rightAlignAction.setVisible(Global.isEditorButtonVisible("alignRight"));
5836                 browser.spellCheckAction.setVisible(Global.isEditorButtonVisible("spellCheck"));
5837                 browser.todoAction.setVisible(Global.isEditorButtonVisible("todo"));
5838     }
5839     private void duplicateNote(String guid) {
5840                 
5841                 Note oldNote = conn.getNoteTable().getNote(guid, true, false,false,false,true);
5842                 List<Resource> resList = conn.getNoteTable().noteResourceTable.getNoteResources(guid, true);
5843                 oldNote.setContent(conn.getNoteTable().getNoteContentNoUTFConversion(guid));
5844                 oldNote.setResources(resList);
5845                 duplicateNote(oldNote);
5846         }
5847         private void duplicateNote(Note oldNote) {
5848                 waitCursor(true);
5849                 // Now that we have a good notebook guid, we need to move the conflicting note
5850                 // to the local notebook
5851                 Calendar currentTime = new GregorianCalendar();
5852                 Long l = new Long(currentTime.getTimeInMillis());
5853                 String newGuid = new String(Long.toString(l));
5854                                         
5855 //              Note newNote = oldNote.deepCopy();
5856                 Note newNote = (Note)Global.deepCopy(oldNote);
5857                 newNote.setUpdateSequenceNum(0);
5858                 newNote.setGuid(newGuid);
5859                 newNote.setDeleted(0);
5860                 newNote.setActive(true);
5861                 
5862                 /*
5863                 List<String> tagNames = new ArrayList<String>();
5864                 List<String> tagGuids = new ArrayList<String>();;
5865                 for (int i=0; i<oldNote.getTagGuidsSize(); i++) {
5866                         tagNames.add(oldNote.getTagNames().get(i));
5867                         tagGuids.add(oldNote.getTagGuids().get(i));
5868                 }
5869
5870                 // Sort note Tags to make them look nice
5871                 for (int i=0; i<tagNames.size()-1; i++) {
5872                         if (tagNames.get(i).compareTo(tagNames.get(i+1))<0) {
5873                                 String n1 = tagNames.get(i);
5874                                 String n2 = tagNames.get(i+1);
5875                                 tagNames.set(i, n2);
5876                                 tagNames.set(i+1, n1);
5877                         }
5878                 }
5879                 newNote.setTagGuids(tagGuids);
5880                 newNote.setTagNames(tagNames);
5881                 
5882                 // Add tag guids to note
5883                 */
5884                 
5885                 // Duplicate resources
5886                 List<Resource> resList = oldNote.getResources();
5887                 if (resList == null)
5888                         resList = new ArrayList<Resource>();
5889                 long prevGuid = 0;
5890                 for (int i=0; i<resList.size(); i++) {
5891                         l = prevGuid;
5892                         while (l == prevGuid) {
5893                                 currentTime = new GregorianCalendar();
5894                                 l = new Long(currentTime.getTimeInMillis());
5895                         }
5896                         prevGuid = l;
5897                         String newResGuid = new String(Long.toString(l));
5898                         resList.get(i).setNoteGuid(newGuid);
5899                         resList.get(i).setGuid(newResGuid);
5900                         resList.get(i).setUpdateSequenceNum(0);
5901                         resList.get(i).setActive(true);
5902                         conn.getNoteTable().noteResourceTable.saveNoteResource(
5903                                         (Resource)Global.deepCopy(resList.get(i)), true);
5904                 }
5905                 newNote.setResources(resList);
5906                 
5907                 // 操作履歴と除外ノートとスター付きノートも複製する
5908                 if(Global.getDuplicateRensoNote()) {
5909                         conn.getHistoryTable().duplicateHistory(newGuid, oldNote.getGuid());
5910                         conn.getExcludedTable().duplicateExcludedNotes(newGuid, oldNote.getGuid());
5911                         conn.getStaredTable().duplicateStaredNotes(newGuid, oldNote.getGuid());
5912                 }
5913                 
5914                 // Add note to the database
5915                 conn.getNoteTable().addNote(newNote, true);
5916                 NoteMetadata metaData = new NoteMetadata();
5917                 NoteMetadata oldMeta = listManager.getNoteMetadata().get(oldNote.getGuid());
5918                 metaData.copy(oldMeta);
5919                 metaData.setGuid(newNote.getGuid());
5920                 listManager.addNote(newNote, metaData);
5921                 noteTableView.insertRow(newNote, metaData, true, -1);
5922                 currentNoteGuid = newNote.getGuid();
5923                 currentNote = newNote;
5924                 refreshEvernoteNote(true);
5925                 listManager.countNotebookResults(listManager.getNoteIndex());
5926                 waitCursor(false);
5927                 
5928         }
5929         // View all notes
5930         @SuppressWarnings("unused")
5931         private void allNotes() {
5932                 clearAttributeFilter();
5933                 clearNotebookFilter();
5934                 clearSavedSearchFilter();
5935                 clearTrashFilter();
5936                 clearTagFilter();
5937                 searchField.clear();
5938                 if (Global.mimicEvernoteInterface) {
5939                         notebookTree.selectGuid("");
5940                 }
5941                 notebookTreeSelection();
5942                 refreshEvernoteNote(true);
5943                 
5944                 // ゴミ箱から元の画面に戻す。連想ノートリストをONに。
5945                 if (!rensoNoteListDock.isEnabled()) {
5946                         rensoNoteListDock.setEnabled(true);
5947                 }
5948         }
5949         // Merge notes
5950         @SuppressWarnings("unused")
5951         private void mergeNotes() {
5952                 logger.log(logger.HIGH, "Merging notes");
5953                 waitCursor(true);
5954                 saveNote();
5955                 String masterGuid = null;
5956                 List<String> sources = new ArrayList<String>();
5957                 QModelIndex index;
5958                 for (int i=0; i<noteTableView.selectionModel().selectedRows().size(); i++) {
5959                         int r = noteTableView.selectionModel().selectedRows().get(i).row();
5960                         index = noteTableView.proxyModel.index(r, Global.noteTableGuidPosition);
5961                         SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
5962                 if (i == 0) 
5963                         masterGuid = (String)ix.values().toArray()[0];
5964                 else 
5965                         sources.add((String)ix.values().toArray()[0]);  
5966                 }
5967                 
5968                 logger.log(logger.EXTREME, "Master guid=" +masterGuid);
5969                 logger.log(logger.EXTREME, "Children count: "+sources.size());
5970                 mergeNoteContents(masterGuid, sources);
5971                 currentNoteGuid = masterGuid;
5972                 
5973                 // 操作履歴と除外ノートとスター付きノートをマージ
5974                 if(Global.getMergeRensoNote()) {
5975                         for (int i = 0; i < sources.size(); i++) {
5976                                 String childGuid = sources.get(i);
5977                                 if(masterGuid != null && childGuid != null) {
5978                                         if(!masterGuid.equals(childGuid)) {
5979                                                 conn.getHistoryTable().mergeHistoryGuid(masterGuid, childGuid);
5980                                                 conn.getExcludedTable().mergeHistoryGuid(masterGuid, childGuid);
5981                                                 conn.getStaredTable().mergeHistoryGuid(masterGuid, childGuid);
5982                                         }
5983                                 }
5984                         }
5985                 }
5986                 
5987                 // マージしたノート(child)を外部ウィンドウで開いていたら、閉じる
5988                 Collection<ExternalBrowse>      windows = externalWindows.values();
5989                 Iterator<ExternalBrowse>        windowIterator = windows.iterator();
5990                 Collection<String>                      guids = externalWindows.keySet();
5991                 Iterator<String>                        guidIterator = guids.iterator();
5992                 List<ExternalBrowse>            closeWindows = new ArrayList<ExternalBrowse>();
5993                 
5994                 while (windowIterator.hasNext()) {
5995                         ExternalBrowse browser = windowIterator.next();
5996                         String guid = guidIterator.next();
5997                         
5998                         for (int i = 0; i < sources.size(); i++) {
5999                                 if (guid.equals(sources.get(i))) {
6000                                         closeWindows.add(browser);
6001                                 }
6002                         }
6003                 }
6004                 
6005                 for (int i = closeWindows.size() - 1; i >= 0; i--) {
6006                         closeWindows.get(i).close();
6007                 }
6008                 
6009         // マージしたノート(child)をタブで開いていたら、閉じる
6010                 List<TabBrowse> closeTabs = new ArrayList<TabBrowse>();
6011                 for (TabBrowse tab : tabWindows.values()) {
6012                         String guid = tab.getBrowserWindow().getNote().getGuid();
6013                         
6014                         for (String source : sources) {
6015                                 if (guid.equals(source)) {
6016                                         closeTabs.add(tab);
6017                                 }
6018                         }
6019                 }
6020                 for (TabBrowse tab : closeTabs) {
6021                         tabWindowClosing(tab);
6022                 }
6023                 
6024                 noteIndexUpdated(false);
6025                 // IFIXED 
6026                 // マージ後の新しいノートコンテンツを表示するためキャッシュを削除
6027                 noteCache.remove(masterGuid);
6028                 
6029                 refreshEvernoteNote(true);
6030                 waitCursor(false);
6031         }
6032         private void mergeNoteContents(String targetGuid, List<String> sources) {
6033                 Note target = conn.getNoteTable().getNote(targetGuid, true, false, false, false, false);
6034                 String newContent = target.getContent();
6035                 newContent = newContent.replace("</en-note>", "<br></br>");
6036                 
6037                 for (int i=0; i<sources.size(); i++) {
6038                         Note source = conn.getNoteTable().getNote(sources.get(i), true, true, false, false, false);
6039                         if (source.isSetTitle()) {
6040                                 newContent = newContent +("<table bgcolor=\"lightgrey\"><tr><td><font size=\"6\"><b>" +source.getTitle() +"</b></font></td></tr></table>");
6041                         }
6042                         String sourceContent = source.getContent();
6043                         logger.log(logger.EXTREME, "Merging contents into note");
6044                         logger.log(logger.EXTREME, sourceContent);
6045                         logger.log(logger.EXTREME, "End of content");
6046                         int startOfNote = sourceContent.indexOf("<en-note>");
6047                         sourceContent = sourceContent.substring(startOfNote+9);
6048                         int endOfNote = sourceContent.indexOf("</en-note>");
6049                         sourceContent = sourceContent.substring(0,endOfNote);
6050                         newContent = newContent + sourceContent;
6051                         logger.log(logger.EXTREME, "New note content");
6052                         logger.log(logger.EXTREME, newContent);
6053                         logger.log(logger.EXTREME, "End of content");
6054                         for (int j=0; j<source.getResourcesSize(); j++) {
6055                                 logger.log(logger.EXTREME, "Reassigning resource: "+source.getResources().get(j).getGuid());
6056                                 Resource r = source.getResources().get(j);
6057                                 Resource newRes = conn.getNoteTable().noteResourceTable.getNoteResource(r.getGuid(), true);
6058                                 
6059                                 Calendar currentTime = new GregorianCalendar();
6060                                 Long l = new Long(currentTime.getTimeInMillis());
6061                                                         
6062                                 long prevGuid = 0;
6063                                 l = prevGuid;
6064                                 while (l == prevGuid) {
6065                                         currentTime = new GregorianCalendar();
6066                                         l = new Long(currentTime.getTimeInMillis());
6067                                 }
6068                                 String newResGuid = new String(Long.toString(l));
6069                                 newRes.setNoteGuid(targetGuid);
6070                                 newRes.setGuid(newResGuid);
6071                                 newRes.setUpdateSequenceNum(0);
6072                                 newRes.setActive(true);
6073                                 conn.getNoteTable().noteResourceTable.saveNoteResource(newRes, true);
6074                         }
6075                 }
6076                 logger.log(logger.EXTREME, "Updating note");
6077                 conn.getNoteTable().updateNoteContent(targetGuid, newContent +"</en-note>");
6078                 for (int i=0; i<sources.size(); i++) {
6079                         logger.log(logger.EXTREME, "Deleting note " +sources.get(i));
6080                         listManager.deleteNote(sources.get(i));
6081                 }
6082                 logger.log(logger.EXTREME, "Exiting merge note");
6083         }
6084         // A resource within a note has had a guid change 
6085         @SuppressWarnings("unused")
6086         private void noteResourceGuidChanged(String noteGuid, String oldGuid, String newGuid) {
6087                 if (oldGuid != null && !oldGuid.equals(newGuid))
6088                         Global.resourceMap.put(oldGuid, newGuid);
6089         }
6090         // View a thumbnail of the note
6091         public void thumbnailView() {
6092                 
6093                 String thumbnailName = Global.getFileManager().getResDirPath("thumbnail-" + currentNoteGuid + ".png");
6094                 QFile thumbnail = new QFile(thumbnailName);
6095                 if (!thumbnail.exists()) {
6096                         
6097                         QImage img = new QImage();
6098                         img.loadFromData(conn.getNoteTable().getThumbnail(currentNoteGuid));
6099                         thumbnailViewer.setThumbnail(img);
6100                 } else
6101                         thumbnailViewer.setThumbnail(thumbnailName);
6102                 if (!thumbnailViewer.isVisible()) 
6103                         thumbnailViewer.showFullScreen();
6104         }
6105         // An error happened while saving a note.  Inform the user
6106         @SuppressWarnings("unused")
6107         private void saveRunnerError(String guid, String msg) {
6108                 if (msg == null) {
6109                         String title = "*Unknown*";
6110                         for (int i=0; i<listManager.getMasterNoteIndex().size(); i++) {
6111                                 if (listManager.getMasterNoteIndex().get(i).getGuid().equals(guid)) {
6112                                         title = listManager.getMasterNoteIndex().get(i).getTitle();
6113                                         i=listManager.getMasterNoteIndex().size();
6114                                 }
6115                         }
6116                         msg = tr("An error has happened while saving the note \"") +title+
6117                         tr("\".\n\nThis is probably due to a document that is too complex for NeighborNote to process.  "+
6118                         "As a result, changes to the note may not be saved properly in the database."+
6119                         "\n\nA cached copy is being preserved so you can recover any data, but data may" +
6120                         "\nbe lost.  Please review the note to recover any critical data before restarting.");
6121                         
6122                         QMessageBox.information(this, tr("Error Saving Note"), tr(msg));
6123                 }
6124         }
6125         private void thumbnailHTMLReady(String guid, QByteArray html, Integer zoom) {
6126                 logger.log(logger.HIGH, "Entering thumnailHTMLReady()");
6127                 logger.log(logger.HIGH, "Thumbnail ready for " +guid);
6128                 // Find an idle preview object
6129                 for (int i=0; i<thumbGenerators.size(); i++) {
6130                         if (thumbGenerators.get(i).mutex.tryLock()) {
6131                                 logger.log(logger.EXTREME, "Idle generator found - loading thumbnail for " +guid);
6132                                 thumbGenerators.get(i).loadContent(guid, html, zoom);
6133                                 return;
6134                         }
6135                 } 
6136                 if (thumbGenerators.size() >= 1) {
6137                         logger.log(logger.EXTREME, "No available thumbnail generators.  Aborting " +guid);
6138                         return;
6139                 }
6140                 
6141                 logger.log(logger.EXTREME, "Creating new thumbnail generator " +guid);
6142                 Thumbnailer preview = new Thumbnailer(logger, conn, listManager, thumbnailRunner);
6143                 thumbGenerators.add(preview);
6144
6145                 if (preview.mutex.tryLock()) {
6146                         logger.log(logger.EXTREME, "Loading thumbnail for  " +guid);
6147                         preview.loadContent(guid, html, zoom);
6148                 }
6149                 logger.log(logger.HIGH, "Exiting thumnailHTMLReady()");
6150         }
6151         
6152         
6153         
6154         //**********************************************************
6155     //**********************************************************
6156     //* Online user actions
6157     //**********************************************************
6158     //**********************************************************
6159     private void setupOnlineMenu() {
6160         if (!Global.isConnected) {
6161                 menuBar.noteOnlineHistoryAction.setEnabled(false);
6162                 menuBar.selectiveSyncAction.setEnabled(false);
6163                 return;
6164         } else {
6165                 menuBar.noteOnlineHistoryAction.setEnabled(true);
6166                 menuBar.selectiveSyncAction.setEnabled(true);
6167         }
6168     }
6169     @SuppressWarnings("unused")
6170         private void viewNoteHistory() {
6171         if (currentNoteGuid == null || currentNoteGuid.equals("")) 
6172                 return;
6173         if (currentNote.getUpdateSequenceNum() == 0) {
6174                 setMessage(tr("Note has never been synchronized."));
6175                         QMessageBox.information(this, tr("Error"), tr("This note has never been sent to Evernote, so there is no history."));
6176                         return;
6177         }
6178         
6179         setMessage(tr("Getting Note History"));
6180         waitCursor(true);
6181         Note currentOnlineNote = null;
6182         versions = null;
6183         try {
6184                 if (Global.isPremium())
6185                         versions = syncRunner.localNoteStore.listNoteVersions(syncRunner.authToken, currentNoteGuid);
6186                 else
6187                         versions = new ArrayList<NoteVersionId>();
6188                 currentOnlineNote = syncRunner.localNoteStore.getNote(syncRunner.authToken, currentNoteGuid, true, true, false, false);
6189                 } catch (EDAMUserException e) {
6190                         setMessage("EDAMUserException: " +e.getMessage());
6191                         return;
6192                 } catch (EDAMSystemException e) {
6193                         if (e.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
6194                                 QMessageBox.warning(this, tr("Rate limit reached"), tr("Evernote usage has been temporarily exceeded. Please try again in ") +  + e.getRateLimitDuration() + tr(" seconds."));
6195                         }
6196                         setMessage("EDAMSystemException: " +e.getMessage());
6197                         return;
6198                 } catch (EDAMNotFoundException e) {
6199                         setMessage(tr("Note not found on server."));
6200                         QMessageBox.information(this, tr("Error"), tr("This note could not be found on Evernote's servers."));
6201                         return;
6202                 } catch (TException e) {
6203                         setMessage("EDAMTransactionException: " +e.getMessage());
6204                         return;
6205                 }
6206                 
6207                 // If we've gotten this far, we have a good note.
6208                 if (historyWindow == null) {
6209                         historyWindow = new OnlineNoteHistory(logger, conn, cbObserver);
6210                         
6211                         historyWindow.historyCombo.activated.connect(this, "reloadHistoryWindow(String)");
6212                         historyWindow.restoreAsNew.clicked.connect(this, "restoreHistoryNoteAsNew()");
6213                         historyWindow.restore.clicked.connect(this, "restoreHistoryNote()");
6214                 } else {
6215                         historyWindow.historyCombo.clear();
6216                 }
6217                 boolean isDirty = conn.getNoteTable().isNoteDirty(currentNoteGuid);
6218                 if (currentNote.getUpdateSequenceNum() != currentOnlineNote.getUpdateSequenceNum())
6219                         isDirty = true;
6220                 historyWindow.setCurrent(isDirty);
6221                 
6222                 loadHistoryWindowContent(currentOnlineNote);
6223                 historyWindow.load(versions);
6224                 setMessage(tr("History retrieved"));
6225                 waitCursor(false);
6226                 historyWindow.exec();
6227     }
6228     private Note reloadHistoryWindow(String selection) {
6229         waitCursor(true);
6230                 String fmt = Global.getDateFormat() + " " + Global.getTimeFormat();
6231                 String dateTimeFormat = new String(fmt);
6232                 SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);
6233                 int index = -1;
6234                 int usn = 0;
6235                 
6236                 for (int i=0; i<versions.size(); i++) {
6237                         StringBuilder versionDate = new StringBuilder(simple.format(versions.get(i).getSaved()));
6238                         if (versionDate.toString().equals(selection))
6239                                 index = i;
6240                 }
6241                 
6242                 if (index > -1 || selection.indexOf("Current") > -1) {
6243                         Note historyNote = null;
6244                         try {
6245                                 if (index > -1) {
6246                                         usn = versions.get(index).getUpdateSequenceNum();
6247                                         historyNote = syncRunner.localNoteStore.getNoteVersion(syncRunner.authToken, currentNoteGuid, usn, true, true, true);
6248                                 } else
6249                                         historyNote = syncRunner.localNoteStore.getNote(syncRunner.authToken, currentNoteGuid, true,true,true,true);
6250                         } catch (EDAMUserException e) {
6251                                 setMessage("EDAMUserException: " +e.getMessage());
6252                                 waitCursor(false);
6253                                 return null;
6254                         } catch (EDAMSystemException e) {
6255                                 if (e.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
6256                                         QMessageBox.warning(this, tr("Rate limit reached"), tr("Evernote usage has been temporarily exceeded. Please try again in ") +  + e.getRateLimitDuration() + tr(" seconds."));
6257                                 }
6258                                 setMessage("EDAMSystemException: " +e.getMessage());
6259                                 waitCursor(false);
6260                                 return null;
6261                         } catch (EDAMNotFoundException e) {
6262                                 setMessage("EDAMNotFoundException: " +e.getMessage());
6263                                 waitCursor(false);
6264                                 return null;
6265                         } catch (TException e) {
6266                                 setMessage("EDAMTransactionException: " +e.getMessage());
6267                                 waitCursor(false);
6268                                 return null;
6269                         }
6270                         
6271                         waitCursor(false);
6272                         if (historyNote != null) 
6273                                 historyWindow.setContent(historyNote);
6274                         return historyNote;
6275                 }
6276                 waitCursor(false);
6277                 return null;
6278     }
6279     private void loadHistoryWindowContent(Note note) {
6280         note.setUpdateSequenceNum(0);
6281                 historyWindow.setContent(note); 
6282     }
6283     @SuppressWarnings("unused")
6284         private void restoreHistoryNoteAsNew() {
6285         setMessage(tr("Restoring as new note."));
6286         duplicateNote(reloadHistoryWindow(historyWindow.historyCombo.currentText()));
6287         setMessage(tr("Note has been restored as a new note."));
6288     }
6289     @SuppressWarnings("unused")
6290         private void restoreHistoryNote() {
6291         setMessage(tr("Restoring note."));
6292         Note n = reloadHistoryWindow(historyWindow.historyCombo.currentText());
6293         conn.getNoteTable().expungeNote(n.getGuid(), true, false);
6294         n.setActive(true);
6295         n.setDeleted(0);
6296                 for (int i=0; i<n.getResourcesSize(); i++) {
6297                         n.getResources().get(i).setActive(true);
6298                         conn.getNoteTable().noteResourceTable.saveNoteResource(n.getResources().get(i), true);
6299                 }
6300                 NoteMetadata metadata = new NoteMetadata();
6301                 metadata.setGuid(n.getGuid());
6302         listManager.addNote(n, metadata);
6303         conn.getNoteTable().addNote(n, true);
6304         refreshEvernoteNote(true);
6305         setMessage(tr("Note has been restored."));
6306     }
6307     @SuppressWarnings("unused")
6308         private void setupSelectiveSync() {
6309         
6310         // Get a list of valid notebooks
6311         List<Notebook> notebooks = null; 
6312         List<Tag> tags = null;
6313         List<LinkedNotebook> linkedNotebooks = null;
6314         try {
6315                         notebooks = syncRunner.localNoteStore.listNotebooks(syncRunner.authToken);
6316                         tags = syncRunner.localNoteStore.listTags(syncRunner.authToken);
6317                         linkedNotebooks = syncRunner.localNoteStore.listLinkedNotebooks(syncRunner.authToken);
6318                 } catch (EDAMUserException e) {
6319                         setMessage("EDAMUserException: " +e.getMessage());
6320                         return;
6321                 } catch (EDAMSystemException e) {
6322                         if (e.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
6323                                 QMessageBox.warning(this, tr("Rate limit reached"), tr("Evernote usage has been temporarily exceeded. Please try again in ") +  + e.getRateLimitDuration() + tr(" seconds."));
6324                         }
6325                         setMessage("EDAMSystemException: " +e.getMessage());
6326                         return;
6327                 } catch (TException e) {
6328                         setMessage("EDAMTransactionException: " +e.getMessage());
6329                         return;
6330                 } catch (EDAMNotFoundException e) {
6331                         setMessage("EDAMNotFoundException: " +e.getMessage());
6332                         return;
6333                 }
6334         
6335                 // Split up notebooks into synchronized & non-synchronized
6336         List<Notebook> ignoredBooks = new ArrayList<Notebook>();
6337         List<String> dbIgnoredNotebooks = conn.getSyncTable().getIgnoreRecords("NOTEBOOK");
6338         
6339         for (int i=notebooks.size()-1; i>=0; i--) {
6340                 for (int j=0; j<dbIgnoredNotebooks.size(); j++) {
6341                         if (notebooks.get(i).getGuid().equalsIgnoreCase(dbIgnoredNotebooks.get(j))) {
6342                                 ignoredBooks.add(notebooks.get(i));
6343                                 j=dbIgnoredNotebooks.size();
6344                         }
6345                 }
6346         }
6347         
6348         // split up tags into synchronized & non-synchronized
6349         List<Tag> ignoredTags = new ArrayList<Tag>();
6350         List<String> dbIgnoredTags = conn.getSyncTable().getIgnoreRecords("TAG");
6351         
6352         for (int i=tags.size()-1; i>=0; i--) {
6353                 for (int j=0; j<dbIgnoredTags.size(); j++) {
6354                         if (tags.get(i).getGuid().equalsIgnoreCase(dbIgnoredTags.get(j))) {
6355                                 ignoredTags.add(tags.get(i));
6356                                 j=dbIgnoredTags.size();
6357                         }
6358                 }
6359         }
6360         
6361         // split up linked notebooks into synchronized & non-synchronized
6362         List<LinkedNotebook> ignoredLinkedNotebooks = new ArrayList<LinkedNotebook>();
6363         List<String> dbIgnoredLinkedNotebooks = conn.getSyncTable().getIgnoreRecords("LINKEDNOTEBOOK");
6364         for (int i=linkedNotebooks.size()-1; i>=0; i--) {
6365                 String notebookGuid = linkedNotebooks.get(i).getGuid();
6366                 for (int j=0; j<dbIgnoredLinkedNotebooks.size(); j++) {
6367                         if (notebookGuid.equalsIgnoreCase(dbIgnoredLinkedNotebooks.get(j))) {
6368                                 ignoredLinkedNotebooks.add(linkedNotebooks.get(i));
6369                                 j=dbIgnoredLinkedNotebooks.size();
6370                         }
6371                 }
6372         }
6373         
6374                 IgnoreSync ignore = new IgnoreSync(notebooks, ignoredBooks, tags, ignoredTags, linkedNotebooks, ignoredLinkedNotebooks);
6375                 ignore.exec();
6376                 if (!ignore.okClicked())
6377                         return;
6378                 
6379                 waitCursor(true);
6380                 
6381                 // Clear out old notebooks & add  the new ones
6382                 List<String> oldIgnoreNotebooks = conn.getSyncTable().getIgnoreRecords("NOTEBOOK");
6383                 for (int i=0; i<oldIgnoreNotebooks.size(); i++) {
6384                         conn.getSyncTable().deleteRecord("IGNORENOTEBOOK-"+oldIgnoreNotebooks.get(i));
6385                 }
6386                 
6387                 List<String> newNotebooks = new ArrayList<String>();
6388                 for (int i=ignore.getIgnoredBookList().count()-1; i>=0; i--) {
6389                         String text = ignore.getIgnoredBookList().takeItem(i).text();
6390                         for (int j=0; j<notebooks.size(); j++) {
6391                                 if (notebooks.get(j).getName().equalsIgnoreCase(text)) {
6392                                         Notebook n = notebooks.get(j);
6393                                         conn.getSyncTable().addRecord("IGNORENOTEBOOK-"+n.getGuid(), n.getGuid());
6394                                         j=notebooks.size();
6395                                         newNotebooks.add(n.getGuid());
6396                                 }
6397                         }
6398                 }
6399                 
6400                 // Clear out old tags & add new ones
6401                 List<String> oldIgnoreTags = conn.getSyncTable().getIgnoreRecords("TAG");
6402                 for (int i=0; i<oldIgnoreTags.size(); i++) {
6403                         conn.getSyncTable().deleteRecord("IGNORETAG-"+oldIgnoreTags.get(i));
6404                 }
6405                 
6406                 List<String> newTags = new ArrayList<String>();
6407                 for (int i=ignore.getIgnoredTagList().count()-1; i>=0; i--) {
6408                         String text = ignore.getIgnoredTagList().takeItem(i).text();
6409                         for (int j=0; j<tags.size(); j++) {
6410                                 if (tags.get(j).getName().equalsIgnoreCase(text)) {
6411                                         Tag t = tags.get(j);
6412                                         conn.getSyncTable().addRecord("IGNORETAG-"+t.getGuid(), t.getGuid());
6413                                         newTags.add(t.getGuid());
6414                                         j=tags.size();
6415                                 }
6416                         }
6417                 }
6418                 
6419                 // Clear out old tags & add new ones
6420                 List<String> oldIgnoreLinkedNotebooks = conn.getSyncTable().getIgnoreRecords("LINKEDNOTEBOOK");
6421                 for (int i=0; i<oldIgnoreLinkedNotebooks.size(); i++) {
6422                         conn.getSyncTable().deleteRecord("IGNORELINKEDNOTEBOOK-"+oldIgnoreLinkedNotebooks.get(i));
6423                 }
6424                 
6425                 List<String> newLinked = new ArrayList<String>();
6426                 for (int i=ignore.getIgnoredLinkedNotebookList().count()-1; i>=0; i--) {
6427                         String text = ignore.getIgnoredLinkedNotebookList().takeItem(i).text();
6428                         for (int j=0; j<linkedNotebooks.size(); j++) {
6429                                 if (linkedNotebooks.get(j).getShareName().equalsIgnoreCase(text)) {
6430                                         LinkedNotebook t = linkedNotebooks.get(j);
6431                                         conn.getSyncTable().addRecord("IGNORELINKEDNOTEBOOK-"+t.getGuid(), t.getGuid());
6432                                         newLinked.add(t.getGuid());
6433                                         j=linkedNotebooks.size();
6434                                 }
6435                         }
6436                 }
6437                 
6438                 conn.getNoteTable().expungeIgnoreSynchronizedNotes(newNotebooks, newTags, newLinked);
6439                 waitCursor(false);
6440                 refreshLists();
6441     }
6442     
6443     
6444         //**********************************************************
6445         //**********************************************************
6446         //* XML Modifying methods
6447         //**********************************************************
6448         //**********************************************************
6449         // An error has happended fetching a resource.  let the user know
6450         private void resourceErrorMessage(int tabIndex) {
6451                 if (tabIndex < 0) {
6452                         return;
6453                 }
6454                 if (inkNote.get(tabIndex))
6455                         return;
6456                 waitCursor(false);
6457                 QMessageBox.information(this, tr("DOUGH!!!"), tr("Well, this is embarrassing."+
6458                 "\n\nSome attachments or images for this note appear to be missing from my database.\n"+
6459                 "In a perfect world this wouldn't happen, but it has.\n" +
6460                 "It is embarasing when a program like me, designed to save all your\n"+
6461                 "precious data, has a problem finding data.\n\n" +
6462                 "I guess life isn't fair, but I'll survive.  Somehow...\n\n" +
6463                 "In the mean time, I'm not going to let you make changes to this note.\n" +
6464                 "Don't get angry.  I'm doing it to prevent you from messing up\n"+
6465                 "this note on the Evernote servers.  Sorry."+
6466                 "\n\nP.S. You might want to re-synchronize to see if it corrects this problem.\nWho knows, you might get lucky."));
6467                 inkNote.put(tabIndex, true);
6468                 browserWindow.setReadOnly(true);
6469                 waitCursor(true);
6470         }
6471
6472         
6473         
6474         
6475         //**********************************************************
6476         //**********************************************************
6477         //* Timer functions
6478         //**********************************************************
6479         //**********************************************************
6480         // We should now do a sync with Evernote
6481         private void syncTimer() {
6482                 logger.log(logger.EXTREME, "Entering NeverNote.syncTimer()");
6483                 syncRunner.syncNeeded = true;
6484                 syncRunner.disableUploads = Global.disableUploads;
6485                 syncStart();
6486                 logger.log(logger.EXTREME, "Leaving NeverNote.syncTimer()");
6487         }
6488         private void syncStart() {
6489                 logger.log(logger.EXTREME, "Entering NeverNote.syncStart()");
6490                 saveNote();
6491                 if (!syncRunning && Global.isConnected) {
6492                         syncRunner.setConnected(true);
6493                         syncRunner.setKeepRunning(Global.keepRunning);
6494                         syncRunner.syncDeletedContent = Global.synchronizeDeletedContent();
6495                         
6496                         if (syncThreadsReady > 0) {
6497                                 thumbnailRunner.interrupt = true;
6498                                 saveNoteIndexWidth();
6499                                 saveNoteColumnPositions();
6500                                 if (syncRunner.addWork("SYNC")) {
6501                                         syncRunning = true;
6502                                         syncRunner.syncNeeded = true;
6503                                         syncThreadsReady--;
6504                                 }                               
6505                         }
6506                 }
6507                 logger.log(logger.EXTREME, "Leaving NeverNote.syncStart");
6508         }
6509         @SuppressWarnings("unused")
6510         private void syncThreadComplete(Boolean refreshNeeded) {
6511                 setMessage(tr("Finalizing Synchronization"));
6512                 syncThreadsReady++;
6513                 syncRunning = false;
6514                 syncRunner.syncNeeded = false;
6515                 synchronizeAnimationTimer.stop();
6516                 synchronizeButton.setIcon(new QIcon(iconPath+"synchronize.png"));
6517                 saveNote();
6518                 if (currentNote == null) {
6519                         currentNote = conn.getNoteTable().getNote(currentNoteGuid, false, false, false, false, true);
6520                 }
6521                 listManager.refreshNoteMetadata();
6522                 noteIndexUpdated(true);
6523                 noteTableView.selectionModel().blockSignals(true);
6524                 scrollToGuid(currentNoteGuid);
6525                 noteTableView.selectionModel().blockSignals(false);
6526                 refreshEvernoteNote(false);
6527                 scrollToGuid(currentNoteGuid);
6528                 waitCursor(false);
6529                 
6530                 // Check to see if there were any shared notebook errors
6531                 if (syncRunner.error && syncRunner.errorSharedNotebooks.size() > 0) {
6532                         String guid = syncRunner.errorSharedNotebooks.get(0);
6533                         String notebookGuid = conn.getLinkedNotebookTable().getLocalNotebookGuid(guid);
6534                         String localName = listManager.getNotebookNameByGuid(notebookGuid);
6535                         SharedNotebookSyncError syncDialog = new SharedNotebookSyncError(localName);
6536                         syncDialog.exec();
6537                         if (syncDialog.okPressed()) {
6538                                 if (syncDialog.doNothing.isChecked()) {
6539                                         syncRunner.errorSharedNotebooksIgnored.put(guid, guid);
6540                                         evernoteSync();
6541                                 }
6542                                 if (syncDialog.deleteNotebook.isChecked()) {
6543                                         conn.getNoteTable().expungeNotesByNotebook(notebookGuid, true, false);
6544                                         conn.getNotebookTable().expungeNotebook(notebookGuid, false);
6545                                         conn.getLinkedNotebookTable().expungeNotebook(guid, false);
6546                                         conn.getLinkedNotebookTable().expungeNotebook(guid, false);
6547                                         evernoteSync();
6548                                 }
6549                                 refreshLists();
6550                                 return;
6551                         }
6552                 }
6553                 
6554                 // Finalize the synchronization
6555                 if (!syncRunner.error)
6556                         setMessage(tr("Synchronization Complete"));
6557                 else
6558                         setMessage(tr("Synchronization completed with errors.  Please check the log for details."));
6559                 logger.log(logger.MEDIUM, "Sync complete.");
6560         }   
6561         public void saveUploadAmount(long t) {
6562                 Global.saveUploadAmount(t);
6563         }
6564         public void saveUserInformation(User user) {
6565                 Global.saveUserInformation(user);
6566         }
6567         public void saveEvernoteUpdateCount(int i) {
6568                 Global.saveEvernoteUpdateCount(i);
6569         }
6570         public void refreshLists() {
6571                 logger.log(logger.EXTREME, "Entering NeverNote.refreshLists");
6572                 updateQuotaBar();
6573                 // すべてのタブのノートを調べて、Dirtyならばセーブする。その後refreshListsする。
6574                 Collection<Integer> tabIndex = noteDirty.keySet();
6575                 Iterator<Integer> indexIterator = tabIndex.iterator();
6576                 HashMap<Integer, Note> saveNotes = new HashMap<Integer, Note>();
6577                 HashMap<Integer, String> saveContents = new HashMap<Integer, String>();
6578                 for (boolean isNoteDirty: noteDirty.values()) {
6579                         int index = indexIterator.next();
6580                         if (isNoteDirty) {
6581                                 saveNotes.put(index, tabWindows.get(index).getBrowserWindow().getNote());
6582                                 saveContents.put(index, tabWindows.get(index).getBrowserWindow().getContent());
6583                         }
6584                 }
6585                 
6586                 listManager.saveUpdatedNotes(saveNotes, saveContents);
6587                 listManager.refreshLists();
6588
6589                 tagIndexUpdated(true);
6590                 notebookIndexUpdated();
6591                 savedSearchIndexUpdated();
6592                 listManager.loadNotesIndex();
6593
6594                 noteTableView.selectionModel().blockSignals(true);
6595         noteIndexUpdated(true);
6596                 noteTableView.selectionModel().blockSignals(false);
6597                 logger.log(logger.EXTREME, "Leaving NeverNote.refreshLists");
6598         }
6599
6600         
6601         @SuppressWarnings("unused")
6602         private void authTimer() {
6603         Calendar cal = Calendar.getInstance();
6604                 
6605         // If we are not connected let's get out of here
6606         if (!Global.isConnected)
6607                 return;
6608                 
6609                 // If this is the first time through, then we need to set this
6610  //             if (syncRunner.authRefreshTime == 0 || cal.getTimeInMillis() > syncRunner.authRefreshTime) 
6611 //                      syncRunner.authRefreshTime = cal.getTimeInMillis();
6612                 
6613 //              long now = new Date().getTime();
6614 //              if (now > Global.authRefreshTime && Global.isConnected) {
6615                         syncRunner.authRefreshNeeded = true;
6616                         syncStart();
6617 //              }
6618         }
6619         @SuppressWarnings("unused")
6620         private void authRefreshComplete(boolean goodSync) {
6621                 logger.log(logger.EXTREME, "Entering NeverNote.authRefreshComplete");
6622                 Global.isConnected = syncRunner.isConnected;
6623                 if (goodSync) {
6624 //                      authTimer.start((int)syncRunner.authTimeRemaining/4);
6625                         authTimer.start(1000*60*15);
6626                         logger.log(logger.LOW, "Authentication token has been renewed");
6627 //                      setMessage("Authentication token has been renewed.");
6628                 } else {
6629                         authTimer.start(1000*60*5);
6630                         logger.log(logger.LOW, "Authentication token renew has failed - retry in 5 minutes.");
6631 //                      setMessage("Authentication token renew has failed - retry in 5 minutes.");
6632                 }
6633                 logger.log(logger.EXTREME, "Leaving NeverNote.authRefreshComplete");
6634         }
6635         
6636         
6637         @SuppressWarnings("unused")
6638         private synchronized void indexTimer() {
6639                 logger.log(logger.EXTREME, "Index timer activated.  Sync running="+syncRunning);
6640                 if (syncRunning) 
6641                         return;
6642                 if (!indexDisabled && indexRunner.idle) { 
6643                         thumbnailRunner.interrupt = true;
6644                         indexRunner.addWork("SCAN");
6645                 }
6646                 logger.log(logger.EXTREME, "Leaving NeighborNote index timer");
6647         }
6648
6649         @SuppressWarnings("unused")
6650         private void indexStarted() {
6651                 setMessage(tr("Indexing notes"));
6652         }
6653         @SuppressWarnings("unused")
6654         private void indexComplete() {
6655                 setMessage(tr("Index complete"));
6656         }
6657         @SuppressWarnings("unused")
6658         private synchronized void toggleNoteIndexing() {
6659                 logger.log(logger.HIGH, "Entering NeverNote.toggleIndexing");
6660                 indexDisabled = !indexDisabled;
6661                 if (!indexDisabled)
6662                         setMessage(tr("Indexing is now enabled."));
6663                 else
6664                         setMessage(tr("Indexing is now disabled."));
6665                 menuBar.disableIndexing.setChecked(indexDisabled);
6666         logger.log(logger.HIGH, "Leaving NeverNote.toggleIndexing");
6667     }  
6668         
6669         @SuppressWarnings("unused")
6670         private void threadMonitorCheck() {
6671                 int MAX=3;
6672                 
6673                 
6674                 boolean alive;
6675                 alive = listManager.threadCheck(Global.tagCounterThreadId);
6676                 if (!alive) {
6677                         tagDeadCount++;
6678                         if (tagDeadCount > MAX && !disableTagThreadCheck) {
6679                                 QMessageBox.information(this, tr("A thread has died."), tr("It appears as the tag counter thread has died.  I recommend "+
6680                                 "checking stopping NeighborNote, saving the logs for later viewing, and restarting.  Sorry."));
6681                                 disableTagThreadCheck = true;
6682                         }
6683                 } else
6684                         tagDeadCount=0;
6685                 
6686                 alive = listManager.threadCheck(Global.notebookCounterThreadId);
6687                 if (!alive) {
6688                         notebookThreadDeadCount++;
6689                         if (notebookThreadDeadCount > MAX && !disableNotebookThreadCheck) {
6690                                 QMessageBox.information(this, tr("A thread has died."), tr("It appears as the notebook counter thread has died.  I recommend "+
6691                                         "checking stopping NeighborNote, saving the logs for later viewing, and restarting.  Sorry."));
6692                                 disableNotebookThreadCheck=true;
6693                         }
6694                 } else
6695                         notebookThreadDeadCount=0;
6696                 
6697                 alive = listManager.threadCheck(Global.trashCounterThreadId);
6698                 if (!alive) {
6699                         trashDeadCount++;
6700                         if (trashDeadCount > MAX && !disableTrashThreadCheck) {
6701                                 QMessageBox.information(this, tr("A thread has died."), ("It appears as the trash counter thread has died.  I recommend "+
6702                                         "checking stopping NeighborNote, saving the logs for later viewing, and restarting.  Sorry."));
6703                                 disableTrashThreadCheck = true;
6704                         }
6705                 } else
6706                         trashDeadCount = 0;
6707
6708                 alive = listManager.threadCheck(Global.saveThreadId);
6709                 if (!alive) {
6710                         saveThreadDeadCount++;
6711                         if (saveThreadDeadCount > MAX && !disableSaveThreadCheck) {
6712                                 QMessageBox.information(this, tr("A thread has died."), tr("It appears as the note saver thread has died.  I recommend "+
6713                                         "checking stopping NeighborNote, saving the logs for later viewing, and restarting.  Sorry."));
6714                                 disableSaveThreadCheck = true;
6715                         }
6716                 } else
6717                         saveThreadDeadCount=0;
6718
6719                 if (!syncThread.isAlive()) {
6720                         syncThreadDeadCount++;
6721                         if (syncThreadDeadCount > MAX && !disableSyncThreadCheck) {
6722                                 QMessageBox.information(this, tr("A thread has died."), tr("It appears as the synchronization thread has died.  I recommend "+
6723                                         "checking stopping NeighborNote, saving the logs for later viewing, and restarting.  Sorry."));
6724                                 disableSyncThreadCheck = true;
6725                         }
6726                 } else
6727                         syncThreadDeadCount=0;
6728
6729                 if (!indexThread.isAlive()) {
6730                         indexThreadDeadCount++;
6731                         if (indexThreadDeadCount > MAX && !disableIndexThreadCheck) {
6732                                 QMessageBox.information(this, tr("A thread has died."), tr("It appears as the index thread has died.  I recommend "+
6733                                         "checking stopping NeighborNote, saving the logs for later viewing, and restarting.  Sorry."));
6734                                 disableIndexThreadCheck = true;
6735                         }
6736                 } else
6737                         indexThreadDeadCount=0;
6738
6739                 if (!rensoNoteListDock.getRensoNoteList().getEnRelatedNotesThread().isAlive()) {
6740                         enRelatedNotesThreadDeadCount++;
6741                         if (enRelatedNotesThreadDeadCount > MAX && !disableENRelatedNotesThreadCheck) {
6742                                 QMessageBox.information(this, tr("A thread has died."), tr("It appears as the Evernote Related Notes thread has died.  I recommend "+
6743                                         "checking stopping NeighborNote, saving the logs for later viewing, and restarting.  Sorry."));
6744                                 disableENRelatedNotesThreadCheck = true;
6745                         }
6746                 } else
6747                         enRelatedNotesThreadDeadCount=0;
6748         }
6749
6750         private void thumbnailTimer() {
6751                 if (Global.enableThumbnails() && !syncRunning && indexRunner.idle) {
6752                         thumbnailRunner.addWork("SCAN");
6753                 }
6754         }
6755         
6756         //**************************************************
6757         //* Backup & Restore
6758         //**************************************************
6759         @SuppressWarnings("unused")
6760         private void databaseBackup() {
6761                 QFileDialog fd = new QFileDialog(this);
6762                 fd.setFileMode(FileMode.AnyFile);
6763                 fd.setConfirmOverwrite(true);
6764                 fd.setWindowTitle(tr("Backup Database"));
6765                 fd.setFilter(tr("NixNote Export (*.nnex);;All Files (*.*)"));
6766                 fd.setAcceptMode(AcceptMode.AcceptSave);
6767                 if (saveLastPath == null || saveLastPath.equals(""))
6768                         fd.setDirectory(System.getProperty("user.home"));
6769                 else
6770                         fd.setDirectory(saveLastPath);
6771                 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
6772                         return;
6773                 }
6774                 
6775                 
6776         waitCursor(true);
6777         saveLastPath = fd.selectedFiles().get(0);
6778         saveLastPath = saveLastPath.substring(0,saveLastPath.lastIndexOf("/"));
6779         setMessage(tr("Backing up database"));
6780         saveNote();
6781 //      conn.backupDatabase(Global.getUpdateSequenceNumber(), Global.getSequenceDate());
6782         
6783         ExportData noteWriter = new ExportData(conn, true);
6784         String fileName = fd.selectedFiles().get(0);
6785
6786         if (!fileName.endsWith(".nnex"))
6787                 fileName = fileName +".nnex";
6788         noteWriter.exportData(fileName);
6789         setMessage(tr("Database backup completed."));
6790  
6791
6792         waitCursor(false);
6793         }
6794         @SuppressWarnings("unused")
6795         private void databaseRestore() {
6796                 if (QMessageBox.question(this, tr("Confirmation"),
6797                                 tr("This is used to restore a database from backups.\n" +
6798                                 "It is HIGHLY recommened that this only be used to populate\n" +
6799                                 "an empty database.  Restoring into a database that\n already has data" +
6800                                 " can cause problems.\n\nAre you sure you want to continue?"),
6801                                 QMessageBox.StandardButton.Yes, 
6802                                 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
6803                                         return;
6804                                 }
6805                 
6806                 
6807                 QFileDialog fd = new QFileDialog(this);
6808                 fd.setFileMode(FileMode.ExistingFile);
6809                 fd.setConfirmOverwrite(true);
6810                 fd.setWindowTitle(tr("Restore Database"));
6811                 fd.setFilter(tr("NixNote Export (*.nnex);;All Files (*.*)"));
6812                 fd.setAcceptMode(AcceptMode.AcceptOpen);
6813                 if (saveLastPath == null || saveLastPath.equals(""))
6814                         fd.setDirectory(System.getProperty("user.home"));
6815                 else
6816                         fd.setDirectory(saveLastPath);
6817                 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
6818                         return;
6819                 }
6820                 
6821                 
6822                 waitCursor(true);
6823         saveLastPath = fd.selectedFiles().get(0);
6824         saveLastPath = saveLastPath.substring(0,saveLastPath.lastIndexOf("/"));
6825
6826                 setMessage(tr("Restoring database"));
6827         ImportData noteReader = new ImportData(conn, true);
6828         noteReader.importData(fd.selectedFiles().get(0));
6829         
6830         if (noteReader.lastError != 0) {
6831                 setMessage(noteReader.getErrorMessage());
6832                 logger.log(logger.LOW, "Restore problem: " +noteReader.lastError);
6833                 waitCursor(false);
6834                 return;
6835         }
6836         
6837         listManager.loadNoteTitleColors();
6838         refreshLists();
6839         refreshEvernoteNote(true);
6840         setMessage(tr("Database has been restored."));
6841         waitCursor(false);
6842         }
6843         @SuppressWarnings("unused")
6844         private void exportNotes() {
6845                 QFileDialog fd = new QFileDialog(this);
6846                 fd.setFileMode(FileMode.AnyFile);
6847                 fd.setConfirmOverwrite(true);
6848                 fd.setWindowTitle(tr("Backup Database"));
6849                 fd.setFilter(tr("NixNote Export (*.nnex);;All Files (*.*)"));
6850                 fd.setAcceptMode(AcceptMode.AcceptSave);
6851                 fd.setDirectory(System.getProperty("user.home"));
6852                 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
6853                         return;
6854                 }
6855                 
6856                 
6857         waitCursor(true);
6858         setMessage(tr("Exporting Notes"));
6859         saveNote();
6860         
6861                 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals("")) 
6862                         selectedNoteGUIDs.add(currentNoteGuid);
6863                 
6864         ExportData noteWriter = new ExportData(conn, false, selectedNoteGUIDs);
6865         String fileName = fd.selectedFiles().get(0);
6866
6867         if (!fileName.endsWith(".nnex"))
6868                 fileName = fileName +".nnex";
6869         noteWriter.exportData(fileName);
6870         setMessage(tr("Export completed."));
6871  
6872
6873         waitCursor(false);
6874                 
6875         }
6876         @SuppressWarnings("unused")
6877         private void importNotes() {
6878                 QFileDialog fd = new QFileDialog(this);
6879                 fd.setFileMode(FileMode.ExistingFile);
6880                 fd.setConfirmOverwrite(true);
6881                 fd.setWindowTitle(tr("Import Notes"));
6882                 fd.setFilter(tr("NixNote Export (*.nnex);;Evernote Export (*.enex);;All Files (*.*)"));
6883                 fd.setAcceptMode(AcceptMode.AcceptOpen);
6884                 if (saveLastPath == null || saveLastPath.equals(""))
6885                         fd.setDirectory(System.getProperty("user.home"));
6886                 else
6887                         fd.setDirectory(saveLastPath);
6888                 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
6889                         return;
6890                 }
6891                 
6892                 
6893         waitCursor(true);
6894         setMessage(tr("Importing Notes"));
6895         saveNote();
6896         
6897                 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals("")) 
6898                         selectedNoteGUIDs.add(currentNoteGuid);
6899                 
6900         String fileName = fd.selectedFiles().get(0);
6901 //      saveLastPath.substring(0,fileName.lastIndexOf("/"));
6902
6903         if (fileName.endsWith(".nnex")) {
6904                 ImportData noteReader = new ImportData(conn, false);
6905                 if (selectedNotebookGUIDs != null && selectedNotebookGUIDs.size() > 0) 
6906                         noteReader.setNotebookGuid(selectedNotebookGUIDs.get(0));
6907                 else
6908                         noteReader.setNotebookGuid(listManager.getNotebookIndex().get(0).getGuid());
6909   
6910                 noteReader.importData(fileName);
6911         
6912                 if (noteReader.lastError != 0) {
6913                         setMessage(noteReader.getErrorMessage());
6914                         logger.log(logger.LOW, "Import problem: " +noteReader.lastError);
6915                         waitCursor(false);
6916                         return;
6917                 }
6918         } else {
6919                 if (fileName.endsWith(".enex")) {
6920                 ImportEnex noteReader = new ImportEnex(conn, false);
6921                         if (selectedNotebookGUIDs != null && selectedNotebookGUIDs.size() > 0) 
6922                                 noteReader.setNotebookGuid(selectedNotebookGUIDs.get(0));
6923                         else
6924                                 noteReader.setNotebookGuid(listManager.getNotebookIndex().get(0).getGuid());
6925   
6926                         waitCursor(false);
6927                         if (QMessageBox.question(this, tr("Confirmation"), 
6928                                         tr("Create new tags from import?"),
6929                                         QMessageBox.StandardButton.Yes, 
6930                                         QMessageBox.StandardButton.No) == StandardButton.Yes.value()) {
6931                                                                 noteReader.createNewTags = true;
6932                         } else
6933                                 noteReader.createNewTags = false;
6934                         waitCursor(true);
6935                         noteReader.importData(fileName);
6936         
6937                         if (noteReader.lastError != 0) {
6938                                 setMessage(noteReader.getErrorMessage());
6939                                 logger.log(logger.LOW, "Import problem: " +noteReader.lastError);
6940                                 waitCursor(false);
6941                                 return;
6942                         }
6943                 }
6944         }
6945         
6946         listManager.loadNoteTitleColors();
6947         refreshLists();
6948         refreshEvernoteNote(false);
6949         setMessage(tr("Notes have been imported."));
6950         waitCursor(false);
6951         
6952         setMessage(tr("Import completed."));
6953  
6954
6955         waitCursor(false);
6956                 
6957         }
6958         
6959         //**************************************************
6960         //* Duplicate a note 
6961         //**************************************************
6962         @SuppressWarnings("unused")
6963         private void duplicateNote() {
6964                 saveNote();
6965                 duplicateNote(currentNoteGuid);
6966         }
6967
6968         //**************************************************
6969         //* Action from when a user clicks Copy As URL
6970         //**************************************************
6971         @SuppressWarnings("unused")
6972         private void copyAsUrlClicked() {
6973                 QClipboard clipboard = QApplication.clipboard();
6974                 QMimeData mime = new QMimeData();
6975                 String url;
6976                 mime.setText(currentNoteGuid);
6977                 List<QUrl> urls = new ArrayList<QUrl>();
6978                 
6979                 // Start building the URL
6980                 User user = Global.getUserInformation();
6981
6982                 // Check that we have everything we need
6983                 if ((user.getShardId().equals("") || user.getId() == 0) && !Global.bypassSynchronizationWarning()) {
6984                         SynchronizationRequiredWarning warning = new SynchronizationRequiredWarning(this);
6985                         warning.exec();
6986                         if (!warning.neverSynchronize())
6987                                 return;
6988                         else {
6989                                 Global.setBypassSynchronizationWarning(true);
6990                                 user.setShardId("s0");
6991                                 user.setId(0);
6992                         }       
6993                 }
6994
6995                 
6996                 // Start building a list of URLs based upon the selected notes
6997         noteTableView.showColumn(Global.noteTableGuidPosition);
6998         
6999         List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
7000         if (!Global.isColumnVisible("guid"))
7001                 noteTableView.hideColumn(Global.noteTableGuidPosition);
7002
7003                 // Check that the note is either synchronized, or in a local notebook
7004                 for (int i=0; i<selections.size(); i++) {
7005                         QModelIndex index;
7006                         int row = selections.get(i).row();
7007                 index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition);
7008                 SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
7009                 String selectedGuid = (String)ix.values().toArray()[0];
7010                 
7011                 Note n = conn.getNoteTable().getNote(selectedGuid, false, false, false, false, false);
7012                 if (n.getUpdateSequenceNum() == 0 && !conn.getNotebookTable().isNotebookLocal(n.getNotebookGuid())) {
7013                         QMessageBox.critical(this, tr("Please Synchronize") ,tr("Please either synchronize or move any " +
7014                                         "new notes to a local notebook."));
7015                         return; 
7016                 }
7017                 }
7018
7019                 // Start building the URLs
7020         for (int i=0; i<selections.size(); i++) {
7021                 QModelIndex index;
7022                         int row = selections.get(i).row();
7023                 index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition);
7024                 SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
7025                 String selectedGuid = (String)ix.values().toArray()[0];
7026                 mime.setText(selectedGuid);
7027                 
7028                 String lid;
7029                 String gid;
7030                 Note selectedNote = conn.getNoteTable().getNote(selectedGuid, false, false, false, false, false);
7031                 if (selectedNote.getUpdateSequenceNum() > 0) {
7032                         gid = selectedGuid;
7033                         lid = selectedGuid;
7034                 } else {
7035                         gid = "00000000-0000-0000-0000-000000000000";
7036                         lid = selectedGuid;
7037                 }
7038                 url = new String("evernote://///view/") + new String(user.getId() + "/" +user.getShardId() +"/"
7039                                 +gid+"/"+lid +"/");
7040                 urls.add(new QUrl(url));
7041         }
7042                 mime.setUrls(urls);
7043                 clipboard.setMimeData(mime);
7044         }
7045         
7046         
7047         //**************************************************
7048         //* Folder Imports
7049         //**************************************************
7050         public void setupFolderImports() {
7051                 List<WatchFolderRecord> records = conn.getWatchFolderTable().getAll();
7052                 
7053                 if (importKeepWatcher == null)
7054                         importKeepWatcher = new QFileSystemWatcher();
7055                 if (importDeleteWatcher == null) {
7056                         importDeleteWatcher = new QFileSystemWatcher();
7057                         for (int i=0; i<records.size(); i++) {
7058                                 if (!records.get(i).keep)
7059                                         folderImportDelete(records.get(i).folder); 
7060                         }
7061                 }
7062
7063                                 
7064                 
7065 //              importKeepWatcher.addPath(records.get(i).folder.replace('\\', '/'));
7066                 for (int i=0; i<records.size(); i++) {
7067                         logger.log(logger.LOW, "Adding file monitor: " +records.get(i).folder);
7068                         if (records.get(i).keep) 
7069                                 importKeepWatcher.addPath(records.get(i).folder);
7070                         else
7071                                 importDeleteWatcher.addPath(records.get(i).folder);
7072                 }
7073                 
7074                 logger.log(logger.EXTREME, "List of directories being watched (kept)...");
7075                 List<String> monitorDelete = importKeepWatcher.directories();
7076                 for (int i=0; i<monitorDelete.size(); i++) {
7077                         logger.log(logger.EXTREME, monitorDelete.get(i));
7078                 }
7079                 logger.log(logger.EXTREME, "<end of list>");
7080                 logger.log(logger.EXTREME, "List of directories being watched (delete)...");
7081                 monitorDelete = importDeleteWatcher.directories();
7082                 for (int i=0; i<monitorDelete.size(); i++) {
7083                         logger.log(logger.EXTREME, monitorDelete.get(i));
7084                 }
7085                 logger.log(logger.EXTREME, "<end of list>");
7086                 
7087                 importKeepWatcher.directoryChanged.connect(this, "folderImportKeep(String)");
7088                 importDeleteWatcher.directoryChanged.connect(this, "folderImportDelete(String)");
7089                 
7090                 // Look at the files already there so we don't import them again if a new file is created
7091                 if (importedFiles == null) {
7092                         importedFiles = new ArrayList<String>();
7093                         for (int j=0; j<records.size(); j++) {
7094                                 QDir dir = new QDir(records.get(j).folder);
7095                                 List<QFileInfo> list = dir.entryInfoList();
7096                                 for (int k=0; k<list.size(); k++) {
7097                                         if (list.get(k).isFile())
7098                                                 importedFiles.add(list.get(k).absoluteFilePath());
7099                                 }
7100                         }
7101                 }
7102         }
7103         
7104         // Menu folderImport action triggered
7105         public void folderImport() {
7106                 List<WatchFolderRecord> recs = conn.getWatchFolderTable().getAll();
7107                 WatchFolder dialog = new WatchFolder(recs, listManager.getNotebookIndex());
7108                 dialog.exec();
7109                 if (!dialog.okClicked())
7110                         return;
7111                 
7112                 // We have some sort of update.
7113                 if (importKeepWatcher.directories().size() > 0)
7114                         importKeepWatcher.removePaths(importKeepWatcher.directories());
7115                 if (importDeleteWatcher.directories().size() > 0)
7116                         importDeleteWatcher.removePaths(importDeleteWatcher.directories());
7117                 
7118                 conn.getWatchFolderTable().expungeAll();
7119                 // Start building from the table
7120                 for (int i=0; i<dialog.table.rowCount(); i++) {
7121                         QTableWidgetItem item = dialog.table.item(i, 0);
7122                         String dir = item.text();
7123                         item = dialog.table.item(i, 1);
7124                         String notebook = item.text();
7125                         item = dialog.table.item(i, 2);
7126                         boolean keep;
7127                         if (item.text().equalsIgnoreCase("Keep"))
7128                                 keep = true;
7129                         else
7130                                 keep = false;
7131                         
7132                         String guid = conn.getNotebookTable().findNotebookByName(notebook);
7133                         conn.getWatchFolderTable().addWatchFolder(dir, guid, keep, 0);
7134                 }
7135                 setupFolderImports();
7136         }
7137         
7138         
7139         public void folderImportKeep(String dirName) throws NoSuchAlgorithmException {
7140                 logger.log(logger.LOW, "Inside folderImportKeep");
7141                 String whichOS = System.getProperty("os.name");
7142                 if (whichOS.contains("Windows")) 
7143                         dirName = dirName.replace('/','\\');
7144                 
7145                 FileImporter importer = new FileImporter(logger, conn);
7146                 
7147                 QDir dir = new QDir(dirName);
7148                 List<QFileInfo> list = dir.entryInfoList();
7149                 String notebook = conn.getWatchFolderTable().getNotebook(dirName);
7150
7151                 for (int i=0; i<list.size(); i++){
7152                         logger.log(logger.LOW, "File found: " +list.get(i).fileName());
7153                         boolean redundant = false;
7154                         // Check if we've already imported this one or if it existed before
7155                         for (int j=0; j<importedFiles.size(); j++) {
7156                                 logger.log(logger.LOW, "redundant file list: " +list.get(i).absoluteFilePath());
7157                                 if (importedFiles.get(j).equals(list.get(i).absoluteFilePath()))
7158                                         redundant = true;
7159                         }
7160                         
7161                         logger.log(logger.LOW, "Checking if redundant: " +redundant);
7162                         if (!redundant) {
7163                                 importer.setFileInfo(list.get(i));
7164                                 importer.setFileName(list.get(i).absoluteFilePath());
7165                         
7166                         
7167                                 logger.log(logger.LOW, "File importing is a file: " +list.get(i).isFile());
7168                                 logger.log(logger.LOW, "File importing is a valid: " +importer.isValidType());
7169                                 if (list.get(i).isFile() && importer.isValidType()) {
7170                         
7171                                         if (!importer.importFile()) {
7172                                                 // If we can't get to the file, it is probably locked.  We'll try again later.
7173                                                 logger.log(logger.LOW, "Unable to save externally edited file.  Saving for later.");
7174                                                 importFilesKeep.add(list.get(i).absoluteFilePath());
7175                                         } else {
7176
7177                                                 Note newNote = importer.getNote();
7178                                                 newNote.setNotebookGuid(notebook);
7179                                                 newNote.setTitle(dir.at(i));
7180                                                 NoteMetadata metadata = new NoteMetadata();
7181                                                 metadata.setDirty(true);
7182                                                 metadata.setGuid(newNote.getGuid());
7183                                                 listManager.addNote(newNote, metadata);
7184                                                 conn.getNoteTable().addNote(newNote, true);
7185                                                 noteTableView.insertRow(newNote, metadata, true, -1);
7186                                                 listManager.updateNoteContent(newNote.getGuid(), importer.getNoteContent());
7187                                                 listManager.countNotebookResults(listManager.getNoteIndex());
7188                                                 importedFiles.add(list.get(i).absoluteFilePath());
7189                                         }
7190                                 }
7191                         }
7192                 }
7193         
7194         
7195         }
7196         
7197         public void folderImportDelete(String dirName) {
7198                 logger.log(logger.LOW, "Inside folderImportDelete");
7199                 String whichOS = System.getProperty("os.name");
7200                 if (whichOS.contains("Windows")) 
7201                         dirName = dirName.replace('/','\\');
7202                 
7203                 FileImporter importer = new FileImporter(logger, conn);
7204                 QDir dir = new QDir(dirName);
7205                 List<QFileInfo> list = dir.entryInfoList();
7206                 String notebook = conn.getWatchFolderTable().getNotebook(dirName);
7207                 
7208                 for (int i=0; i<list.size(); i++){
7209                         logger.log(logger.LOW, "File found: " +list.get(i).fileName());
7210                         importer.setFileInfo(list.get(i));
7211                         importer.setFileName(list.get(i).absoluteFilePath());
7212                         
7213                         logger.log(logger.LOW, "File importing is a file: " +list.get(i).isFile());
7214                         logger.log(logger.LOW, "File importing is a valid: " +importer.isValidType());
7215                         if (list.get(i).isFile() && importer.isValidType()) {
7216                 
7217                                 if (!importer.importFile()) {
7218                                         // If we can't get to the file, it is probably locked.  We'll try again later.
7219                                         logger.log(logger.LOW, "Unable to save externally edited file.  Saving for later.");
7220                                         importFilesKeep.add(list.get(i).absoluteFilePath());
7221                                 } else {
7222                 
7223                                         Note newNote = importer.getNote();
7224                                         newNote.setNotebookGuid(notebook);
7225                                         newNote.setTitle(dir.at(i));
7226                                         NoteMetadata metadata = new NoteMetadata();
7227                                         metadata.setDirty(true);
7228                                         metadata.setGuid(newNote.getGuid());
7229                                         listManager.addNote(newNote, metadata);
7230                                         conn.getNoteTable().addNote(newNote, true);
7231                                         noteTableView.insertRow(newNote, metadata, true, -1);
7232                                         listManager.updateNoteContent(newNote.getGuid(), importer.getNoteContent());
7233                                         listManager.countNotebookResults(listManager.getNoteIndex());
7234                                         dir.remove(dir.at(i));
7235                                 }
7236                         }
7237                 }
7238         }
7239         
7240         
7241         //**************************************************
7242         //* External events
7243         //**************************************************
7244         private void externalFileEdited(String fileName) throws NoSuchAlgorithmException {
7245                 logger.log(logger.HIGH, "Entering exernalFileEdited");
7246
7247                 // Strip URL prefix and base dir path
7248                 String dPath = FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath());
7249                 String name = fileName.replace(dPath, "");
7250                 int pos = name.lastIndexOf('.');
7251                 String guid = name;
7252                 if (pos > -1) {
7253                         guid = guid.substring(0,pos);
7254                 }
7255                 pos = name.lastIndexOf(Global.attachmentNameDelimeter);
7256                 if (pos > -1) {
7257                         guid = name.substring(0, pos);
7258                 }
7259                 
7260                 QFile file = new QFile(fileName);
7261         if (!file.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly))) {
7262                 // If we can't get to the file, it is probably locked.  We'll try again later.
7263                 logger.log(logger.LOW, "Unable to save externally edited file.  Saving for later.");
7264                 externalFiles.add(fileName);
7265                 return;
7266                 }
7267                 QByteArray binData = file.readAll();
7268         file.close();
7269         if (binData.size() == 0) {
7270                 // If we can't get to the file, it is probably locked.  We'll try again later.
7271                 logger.log(logger.LOW, "Unable to save externally edited file.  Saving for later.");
7272                 externalFiles.add(fileName);
7273                 return;
7274         }
7275         
7276         Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
7277         if (r==null)
7278                 r = conn.getNoteTable().noteResourceTable.getNoteResource(Global.resourceMap.get(guid), true);
7279         if (r == null || r.getData() == null || r.getData().getBody() == null)
7280                 return;
7281         String oldHash = Global.byteArrayToHexString(r.getData().getBodyHash());
7282         MessageDigest md = MessageDigest.getInstance("MD5");
7283                 md.update(binData.toByteArray());
7284                 byte[] hash = md.digest();
7285         String newHash = Global.byteArrayToHexString(hash);
7286         if (r.getNoteGuid().equalsIgnoreCase(currentNoteGuid)) {
7287                 updateResourceContentHash(browserWindow, r.getGuid(), oldHash, newHash);
7288         }
7289         if (externalWindows.containsKey(r.getNoteGuid())) {
7290                 updateResourceContentHash(externalWindows.get(r.getNoteGuid()).getBrowserWindow(), 
7291                                 r.getGuid(), oldHash, newHash);
7292         }
7293         conn.getNoteTable().updateResourceContentHash(r.getNoteGuid(), oldHash, newHash);
7294         Data data = r.getData();
7295         data.setBody(binData.toByteArray());
7296         data.setBodyHash(hash);
7297         logger.log(logger.LOW, "externalFileEdited: " +data.getSize() +" bytes");
7298         r.setData(data);
7299         conn.getNoteTable().noteResourceTable.updateNoteResource(r,true);
7300         
7301         if (r.getNoteGuid().equals(currentNoteGuid)) {
7302                         QWebSettings.setMaximumPagesInCache(0);
7303                         QWebSettings.setObjectCacheCapacities(0, 0, 0);
7304                         refreshEvernoteNote(true);
7305                         browserWindow.getBrowser().triggerPageAction(WebAction.Reload);
7306         }
7307         
7308         if (externalWindows.containsKey(r.getNoteGuid())) {
7309                 QWebSettings.setMaximumPagesInCache(0);
7310                         QWebSettings.setObjectCacheCapacities(0, 0, 0);
7311                         externalWindows.get(r.getNoteGuid()).getBrowserWindow().getBrowser().triggerPageAction(WebAction.Reload);
7312                         
7313         }
7314         
7315                 logger.log(logger.HIGH, "Exiting externalFielEdited");
7316         }
7317         // This is a timer event that tries to save any external files that were edited.  This
7318         // is only needed if we couldn't save a file earlier.
7319         public void externalFileEditedSaver() {
7320                 for (int i=externalFiles.size()-1; i>=0; i--) {
7321                         try {
7322                                 logger.log(logger.MEDIUM, "Trying to save " +externalFiles.get(i));
7323                                 externalFileEdited(externalFiles.get(i));
7324                                 externalFiles.remove(i);
7325                         } catch (NoSuchAlgorithmException e) {e.printStackTrace();}
7326                 }
7327                 for (int i=0; i<importFilesKeep.size(); i++) {
7328                         try {
7329                                 logger.log(logger.MEDIUM, "Trying to save " +importFilesKeep.get(i));
7330                                 folderImportKeep(importFilesKeep.get(i));
7331                                 importFilesKeep.remove(i);
7332                         } catch (NoSuchAlgorithmException e) {e.printStackTrace();}
7333                 }
7334                 for (int i=0; i<importFilesDelete.size(); i++) {
7335                         logger.log(logger.MEDIUM, "Trying to save " +importFilesDelete.get(i));
7336                         folderImportDelete(importFilesDelete.get(i));
7337                         importFilesDelete.remove(i);
7338                 }
7339         }
7340         
7341         
7342         
7343         
7344         // If an attachment on the current note was edited, we need to update the current notes's hash
7345         // Update a note content's hash.  This happens if a resource is edited outside of NN
7346         public void updateResourceContentHash(BrowserWindow browser, String guid, String oldHash, String newHash) {
7347                 int position = browserWindow.getContent().indexOf("en-tag=\"en-media\" guid=\""+guid+"\" type=");
7348                 int endPos;
7349                 for (;position>-1;) {
7350                         endPos = browser.getContent().indexOf(">", position+1);
7351                         String oldSegment = browser.getContent().substring(position,endPos);
7352                         int hashPos = oldSegment.indexOf("hash=\"");
7353                         int hashEnd = oldSegment.indexOf("\"", hashPos+7);
7354                         String hash = oldSegment.substring(hashPos+6, hashEnd);
7355                         if (hash.equalsIgnoreCase(oldHash)) {
7356                                 String newSegment = oldSegment.replace(oldHash, newHash);
7357                                 String content = browser.getContent().substring(0,position) +
7358                                                  newSegment +
7359                                                  browser.getContent().substring(endPos);
7360                                 browser.setContent(new QByteArray(content));;
7361                         }
7362                         
7363                         position = browser.getContent().indexOf("en-tag=\"en-media\" guid=\""+guid+"\" type=", position+1);
7364                 }
7365         }
7366
7367
7368         //*************************************************
7369         //* Minimize to tray
7370         //*************************************************
7371         @Override
7372         public void changeEvent(QEvent e) {
7373                 if (e.type() == QEvent.Type.WindowStateChange) {
7374                         if (QSystemTrayIcon.isSystemTrayAvailable()) {
7375                                 if (isMinimized() && (Global.showTrayIcon() || Global.showTrayIcon())) {
7376                                         e.accept();
7377                                         QTimer.singleShot(10, this, "hide()");
7378                                         return;
7379                                 }
7380                                 if (isMaximized())
7381                                         windowMaximized = true;
7382                                 else 
7383                                         windowMaximized = false;
7384                         }
7385                 }
7386         }
7387         
7388         //*************************************************
7389         //* Check database userid & passwords
7390         //*************************************************
7391         private static boolean databaseCheck(String url,String userid, String userPassword, String cypherPassword) {
7392                         Connection connection;
7393                         
7394                         try {
7395                                 Class.forName("org.h2.Driver");
7396                         } catch (ClassNotFoundException e1) {
7397                                 e1.printStackTrace();
7398                                 System.exit(16);
7399                         }
7400
7401                         try {
7402                                 String passwordString = null;
7403                                 if (cypherPassword==null || cypherPassword.trim().equals(""))
7404                                         passwordString = userPassword;
7405                                 else
7406                                         passwordString = cypherPassword+" "+userPassword;
7407                                 connection = DriverManager.getConnection(url,userid,passwordString);
7408                         } catch (SQLException e) {
7409                                 return false;
7410                         }
7411                         try {
7412                                 connection.close();
7413                         } catch (SQLException e) {
7414                                 e.printStackTrace();
7415                         }
7416                         return true;
7417         }
7418
7419         //*************************************************
7420         //* View / Hide source HTML for a note
7421         //*************************************************
7422         public void viewSource() {
7423                 // すべてのタブに対して
7424         for(int i = 0; i < tabBrowser.count(); i++){
7425                 BrowserWindow browser = ((TabBrowse) tabBrowser.widget(i)).getBrowserWindow();
7426                 browser.showSource(menuBar.viewSource.isChecked());
7427         }
7428         }
7429         //*************************************************
7430         // Block the program.  This is used for things  
7431         // like async web calls.
7432         //*************************************************
7433         @SuppressWarnings("unused")
7434         private void blockApplication(BrowserWindow b) {
7435                 // Block all signals
7436                 waitCursor(true);
7437                 blockSignals(true);
7438                 
7439                 blockTimer = new QTimer();
7440                 blockTimer.setSingleShot(true);
7441                 blockTimer.setInterval(15000);
7442                 blockTimer.timeout.connect(this, "unblockApplication()");
7443                 blockingWindow  = b;
7444                 blockTimer.start();
7445         }
7446         
7447         @SuppressWarnings("unused")
7448         private void unblockApplication() {
7449                 waitCursor(false);
7450                 if (blockingWindow != null && new GregorianCalendar().getTimeInMillis() > blockingWindow.unblockTime && blockingWindow.unblockTime != -1) {
7451                         QMessageBox.critical(null, tr("No Response from CodeCogs") ,tr("Unable to contact CodeCogs for LaTeX formula."));
7452                         blockingWindow.unblockTime = -1;
7453                         blockingWindow.awaitingHttpResponse = false;
7454                 }
7455                 blockingWindow = null;
7456                 blockSignals(false);
7457         }
7458         
7459         // タブが変更された
7460         private void tabWindowChanged(int index) {
7461                 if (index < 0 || index >= tabBrowser.count()) {
7462                         return;
7463                 }
7464                 
7465                 saveNote();
7466
7467                 TabBrowse tab = (TabBrowse) tabBrowser.widget(index);
7468                 if (tab.getBrowserWindow().getNote() != null) {
7469                         currentNoteGuid = tab.getBrowserWindow().getNote().getGuid();
7470                         currentNote = tab.getBrowserWindow().getNote();
7471                 } else {
7472                         currentNoteGuid = "";
7473                         currentNote = null;
7474                 }
7475
7476                 // 選択ノートを更新
7477                 selectedNoteGUIDs.clear();
7478                 if (currentNoteGuid != null && !currentNoteGuid.equals("")) {
7479                         selectedNoteGUIDs.add(currentNoteGuid);
7480                 }
7481                 
7482                 // browserWindowを更新
7483                 browserWindow.noteSignal.noteChanged.disconnect(this,"setNoteDirty()");
7484                 browserWindow.focusLost.disconnect(this, "saveNote()");
7485                 browserWindow = tab.getBrowserWindow();
7486                 browserWindow.noteSignal.noteChanged.connect(this, "setNoteDirty()");
7487                 browserWindow.focusLost.connect(this, "saveNote()");
7488                 // メニューバーのボタンを新しいbrowserWindowに合わせる
7489                 menuBar.refreshTargetWindow();
7490                 
7491                 // 現在ゴミ箱かつ移るタブがアクティブなら通常テーブルに、現在通常テーブルかつこれから非アクティブのタブに移るならゴミ箱を表示させる
7492                 boolean nextIsActive;
7493                 if (tab.getBrowserWindow().getNote() != null) {
7494                         nextIsActive = tab.getBrowserWindow().getNote().isActive();
7495                 } else {
7496                         nextIsActive = true;
7497                 }
7498                 if (Global.showDeleted && nextIsActive) {
7499                         switchNoteTable(false);
7500                 } else if (!Global.showDeleted && !nextIsActive) {
7501                         switchNoteTable(true);
7502                 }
7503
7504                 // noteTableViewの選択を変更するとselectionChangedが発生してしまうので一度切断
7505                 noteTableView.selectionModel().selectionChanged.disconnect(this,"noteTableSelection()");
7506                 scrollToGuid(currentNoteGuid);
7507                 // 再接続
7508                 noteTableView.selectionModel().selectionChanged.connect(this,"noteTableSelection()");
7509
7510                 menuBar.noteDuplicateAction.setEnabled(true);
7511                 menuBar.noteOnlineHistoryAction.setEnabled(true);
7512                 menuBar.noteMergeAction.setEnabled(true);
7513                 
7514                 if (Global.showDeleted) {
7515                         menuBar.noteDuplicateAction.setEnabled(false);
7516                 }
7517                 if (!Global.isConnected) {
7518                         menuBar.noteOnlineHistoryAction.setEnabled(false);
7519                 }
7520                 menuBar.noteMergeAction.setEnabled(false);
7521                 try {
7522                         int row = noteTableView.selectionModel().selectedRows().get(0).row();
7523                         if (row == 0)
7524                                 upButton.setEnabled(false);
7525                         else
7526                                 upButton.setEnabled(true);
7527                         if (row < listManager.getNoteTableModel().rowCount() - 1)
7528                                 downButton.setEnabled(true);
7529                         else
7530                                 downButton.setEnabled(false);
7531                 } catch (Exception e) {
7532                         upButton.setEnabled(false);
7533                         downButton.setEnabled(false);
7534                 }
7535                 
7536                 int currentIndex = tabBrowser.currentIndex();
7537                 ArrayList<String> histGuids = historyGuids.get(currentIndex);
7538                 int histPosition = historyPosition.get(currentIndex);
7539
7540                 // prev, nextボタンの有効・無効化
7541                 nextButton.setEnabled(true);
7542                 prevButton.setEnabled(true);
7543
7544                 if (histPosition <= 1){
7545                         prevButton.setEnabled(false);
7546                 }
7547                 if (histPosition == histGuids.size()){
7548                         nextButton.setEnabled(false);
7549                 }
7550
7551                 refreshEvernoteNote(true);
7552
7553                 // 連想ノートリストを更新
7554                 rensoNoteListDock.getRensoNoteList().refreshRensoNoteList(currentNoteGuid);
7555         }
7556         
7557         // 生存ノートテーブル→ゴミ箱(またはその逆)に切り替える
7558         private void switchNoteTable(boolean toDeleted) {
7559         clearNotebookFilter();
7560         clearTagFilter();
7561         clearAttributeFilter();
7562         clearSavedSearchFilter();
7563         
7564         listManager.getSelectedNotebooks().clear();
7565         listManager.getSelectedTags().clear();
7566         listManager.setSelectedSavedSearch("");
7567     
7568         // toggle the add buttons
7569         newButton.setEnabled(!newButton.isEnabled());
7570         menuBar.noteAdd.setEnabled(newButton.isEnabled());
7571         menuBar.noteAddNewTab.setEnabled(newButton.isEnabled());
7572                 if (currentNoteGuid == null || currentNoteGuid.equals("")) {
7573                         menuBar.noteAddNewTab.setEnabled(false);
7574                 }
7575         menuBar.noteAdd.setVisible(true);
7576         
7577         if (!toDeleted) {       // 生存ノートテーブルへ
7578                 trashTree.itemSelectionChanged.disconnect(this, "trashTreeSelection()");
7579                 trashTree.clearSelection();
7580                 trashTree.itemSelectionChanged.connect(this, "trashTreeSelection()");
7581                 Global.showDeleted = false;
7582                 menuBar.noteRestoreAction.setEnabled(false);
7583                 menuBar.noteRestoreAction.setVisible(false);
7584                 // ゴミ箱から元の画面に戻す。連想ノートリストをONに。
7585                 rensoNoteListDock.setEnabled(true);
7586         } else {        // ゴミ箱へ
7587                 trashTree.itemSelectionChanged.disconnect(this, "trashTreeSelection()");
7588                 trashTree.setCurrentItem(trashTree.getTrashItem());
7589                 trashTree.itemSelectionChanged.connect(this, "trashTreeSelection()");
7590                 Global.showDeleted = true;
7591                 menuBar.noteRestoreAction.setEnabled(true);
7592                 menuBar.noteRestoreAction.setVisible(true);
7593                 // ゴミ箱を開く。連想ノートリストをOFFに。
7594                 rensoNoteListDock.setEnabled(false);
7595         }
7596         
7597         listManager.loadNotesIndex();
7598         // noteTableViewの選択を変更するとselectionChangedが発生してしまうので一度切断
7599         noteTableView.selectionModel().selectionChanged.disconnect(this,"noteTableSelection()");
7600         noteIndexUpdated(false);
7601         // 再接続
7602         noteTableView.selectionModel().selectionChanged.connect(this,"noteTableSelection()");
7603         
7604         browserWindow.setReadOnly(!newButton.isEnabled());
7605         }
7606
7607         // ユーザが連想ノートリストのアイテムを選択した時の処理
7608         @SuppressWarnings("unused")
7609         private void rensoNoteItemPressed(QListWidgetItem current) {
7610                 logger.log(logger.HIGH, "Nevernote.rensoNoteSelectionChangeに入った");
7611
7612                 rensoNotePressedItemGuid = rensoNoteListDock.getRensoNoteList().getNoteGuid(current);
7613                 
7614                 // 右クリックだったら終了
7615                 if (QApplication.mouseButtons().isSet(MouseButton.RightButton)) {
7616                         return;
7617                 }
7618                 
7619                 saveNote();
7620
7621                 String prevCurrentNoteGuid = new String(currentNoteGuid);
7622                 
7623                 for (int i = 0; i < noteTableView.model().rowCount(); i++) {
7624                         QModelIndex modelIndex = noteTableView.model().index(i,
7625                                         Global.noteTableGuidPosition);
7626                         if (modelIndex != null) {
7627                                 SortedMap<Integer, Object> ix = noteTableView.model().itemData(
7628                                                 modelIndex);
7629                                 String tableGuid = (String) ix.values().toArray()[0];
7630                                 if (tableGuid.equals(rensoNotePressedItemGuid)) {
7631                                         noteTableView.selectRow(i);
7632                                         break;
7633                                 }
7634                         }
7635                 }
7636                 
7637                 // 連想ノートリストアイテムクリック操作を記録
7638                 conn.getHistoryTable().addHistory("rensoItemClick", prevCurrentNoteGuid, currentNoteGuid);
7639
7640                 logger.log(logger.HIGH, "Nevernote.rensoNoteSelectionChangeを出た");
7641         }
7642         
7643         // 関連ノートリストからノートを除外する
7644         @SuppressWarnings("unused")
7645         private void excludeNote() {
7646                 if (rensoNotePressedItemGuid != null) {
7647                         saveNote();
7648                         excludeNote(rensoNotePressedItemGuid);
7649                 }
7650         }
7651         
7652         // 関連ノートリストからノートを除外する
7653         private void excludeNote(String guid) {
7654                 if (Global.verifyExclude()) {
7655                         String msg;
7656                         Note note = conn.getNoteTable().getNote(guid, false, false, false, false, false);
7657                         String title = note.getTitle();
7658                         if (title != null) {
7659                                 msg = new String(tr("Exclude note \"") +title +"\"?");
7660                         } else {                                
7661                                 msg = new String(tr("Exclude note selected note?"));
7662                         }
7663                         
7664                         if (QMessageBox.question(this, tr("Confirmation"), msg,
7665                                         QMessageBox.StandardButton.Yes, 
7666                                         QMessageBox.StandardButton.No)==StandardButton.No.value() && Global.verifyDelete() == true) {
7667                                         return;
7668                         }
7669                 }
7670                 
7671                 // Historyデータベースから除外するノートのデータを削除
7672                 conn.getHistoryTable().expungeHistory(guid, currentNoteGuid);
7673                 
7674                 // 除外ノートテーブルに追加
7675                 conn.getExcludedTable().addExclusion(guid, currentNoteGuid);
7676                 
7677                 rensoNoteListDock.getRensoNoteList().refreshRensoNoteList(currentNoteGuid);
7678         }
7679         
7680         // 関連ノートリストのノートにスターを付ける
7681         @SuppressWarnings("unused")
7682         private void starNote() {
7683                 if (rensoNotePressedItemGuid != null) {
7684                         saveNote();
7685                         starNote(rensoNotePressedItemGuid);
7686                 }
7687         }
7688         
7689         // 関連ノートリストのノートにスターを付ける
7690         private void starNote(String guid) {
7691                 // スター付きノートテーブルに追加
7692                 conn.getStaredTable().addStaredItem(currentNoteGuid, guid);
7693                 
7694                 rensoNoteListDock.getRensoNoteList().refreshRensoNoteList(currentNoteGuid);
7695         }
7696         
7697         // 関連ノートリストのノートからスターを外す
7698         @SuppressWarnings("unused")
7699         private void unstarNote() {
7700                 if (rensoNotePressedItemGuid != null) {
7701                         saveNote();
7702                         unstarNote(rensoNotePressedItemGuid);
7703                 }
7704         }
7705         
7706         // 関連ノートリストのノートからスターを外す
7707         private void unstarNote(String guid) {
7708                 // スター付きノートテーブルから削除
7709                 conn.getStaredTable().removeStaredItem(currentNoteGuid, guid);
7710                 
7711                 rensoNoteListDock.getRensoNoteList().refreshRensoNoteList(currentNoteGuid);
7712         }
7713         
7714         // currentNoteGuidを返す
7715         public String getCurrentNoteGuid() {
7716                 return currentNoteGuid;
7717         }
7718         
7719         @SuppressWarnings("unused")
7720         // タブ入れ替えによってタブインデックスが変わったので、インデックスで管理しているハッシュマップ達も入れ替える
7721         private void tabIndexChanged(int from, int to) {
7722                 // tabWindows
7723                 TabBrowse tab = tabWindows.get(from);
7724                 tabWindows.put(from, tabWindows.get(to));
7725                 tabWindows.put(to, tab);
7726                 // noteDirty
7727                 boolean isNoteDirty = noteDirty.get(from);
7728                 noteDirty.put(from, noteDirty.get(to));
7729                 noteDirty.put(to, isNoteDirty);
7730                 // inkNote
7731                 boolean isInkNote = inkNote.get(from);
7732                 inkNote.put(from, inkNote.get(to));
7733                 inkNote.put(to, isInkNote);
7734                 // readOnly
7735                 boolean isReadOnly = readOnly.get(from);
7736                 readOnly.put(from, readOnly.get(to));
7737                 readOnly.put(to, isReadOnly);
7738                 // historyGuids
7739                 ArrayList<String> histGuids = historyGuids.get(from);
7740                 historyGuids.put(from, historyGuids.get(to));
7741                 historyGuids.put(to, histGuids);
7742                 // historyPosition
7743                 int histPosition = historyPosition.get(from);
7744                 historyPosition.put(from, historyPosition.get(to));
7745                 historyPosition.put(to, histPosition);
7746                 // fromHistory
7747                 boolean fromHist = fromHistory.get(from);
7748                 fromHistory.put(from,  fromHistory.get(to));
7749                 fromHistory.put(to, fromHist);
7750         }
7751         
7752         // 連想ノートリストのgetter
7753         public RensoNoteList getRensoNoteList() {
7754                 return rensoNoteListDock.getRensoNoteList();
7755         }
7756         
7757         // 帯域制限の超過をユーザに通知
7758         @SuppressWarnings("unused")
7759         private void informRateLimit(Integer rateLimitDuration) {
7760                 QMessageBox.warning(this, tr("Rate limit reached"), tr("Evernote usage has been temporarily exceeded. Please try again in ") +  + rateLimitDuration + tr(" seconds."));
7761         }
7762         
7763         // ツールバーの「新規」ボタンの接続スロットを設定
7764         public void connectNewButtonSlot(String slot) {
7765                 newButton.triggered.disconnect();
7766                 newButton.triggered.connect(this, slot);
7767         }
7768 }