OSDN Git Service

cec0514048188a0715653eac2d5347d23b0e9123
[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                 String guid = "";
1642                 String stackName = "";
1643                 if (selections.size() > 0) {
1644                 guid = (selections.get(0).text(2));
1645                 stackName = selections.get(0).text(0);
1646         }
1647                 if (!Global.mimicEvernoteInterface) {
1648                         // If no notebooks are selected, we make it look like the "all notebooks" one was selected
1649                         if (selections.size()==0) {
1650                                 selectedNotebookGUIDs.clear();
1651                                 for (int i=0; i < listManager.getNotebookIndex().size(); i++) {
1652                                         selectedNotebookGUIDs.add(listManager.getNotebookIndex().get(i).getGuid());
1653                                 }
1654                                 menuBar.notebookEditAction.setEnabled(false);
1655                                 menuBar.notebookDeleteAction.setEnabled(false);
1656                                 menuBar.notebookStackAction.setEnabled(false);
1657                                 menuBar.notebookIconAction.setEnabled(false);
1658                         }
1659                 }
1660         if (!guid.equals("") && !guid.equals("STACK")) {
1661                 selectedNotebookGUIDs.add(guid);
1662                 menuBar.notebookIconAction.setEnabled(true);
1663         } else {
1664                 menuBar.notebookIconAction.setEnabled(true);
1665                         for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1666                                 Notebook book = listManager.getNotebookIndex().get(j);
1667                                 if (book.getStack() != null && book.getStack().equalsIgnoreCase(stackName))
1668                                         selectedNotebookGUIDs.add(book.getGuid());
1669                         }
1670         }
1671         listManager.setSelectedNotebooks(selectedNotebookGUIDs);
1672         listManager.loadNotesIndex();
1673         noteIndexUpdated(false);
1674         refreshEvernoteNote(true);
1675         listManager.refreshCounters = true;
1676         listManager.refreshCounters();
1677         if (selectedNotebookGUIDs.size() == 1) {
1678                 int col = conn.getNotebookTable().getSortColumn(selectedNotebookGUIDs.get(0));
1679                 int order = conn.getNotebookTable().getSortOrder(selectedNotebookGUIDs.get(0));
1680                 if (col != -1) {
1681                         noteTableView.proxyModel.blocked = true;
1682                         if (order == 1)
1683                                 noteTableView.sortByColumn(col, Qt.SortOrder.DescendingOrder);
1684                         else
1685                                 noteTableView.sortByColumn(col, Qt.SortOrder.AscendingOrder);
1686                 }
1687         }
1688         noteTableView.proxyModel.blocked = false;
1689                 logger.log(logger.HIGH, "Leaving NeverNote.notebookTreeSelection");
1690
1691     }
1692     private void clearNotebookFilter() {
1693         notebookTree.blockSignals(true);
1694         notebookTree.clearSelection();
1695                 menuBar.noteRestoreAction.setVisible(false);
1696         menuBar.notebookEditAction.setEnabled(false);
1697         menuBar.notebookDeleteAction.setEnabled(false);
1698         selectedNotebookGUIDs.clear();
1699         listManager.setSelectedNotebooks(selectedNotebookGUIDs);
1700         notebookTree.blockSignals(false);
1701     }
1702         // Triggered when the notebook DB has been updated
1703         private void notebookIndexUpdated() {
1704                 logger.log(logger.HIGH, "Entering NeverNote.notebookIndexUpdated");
1705         
1706                 // Get the possible icons
1707                 HashMap<String, QIcon> icons = conn.getNotebookTable().getAllIcons();
1708         notebookTree.setIcons(icons);
1709         
1710         if (selectedNotebookGUIDs == null)
1711                         selectedNotebookGUIDs = new ArrayList<String>();
1712                 List<Notebook> books = conn.getNotebookTable().getAll();
1713                 for (int i=books.size()-1; i>=0; i--) {
1714                         for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
1715                                 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(books.get(i).getGuid())) {
1716                                         books.remove(i);
1717                                         j=listManager.getArchiveNotebookIndex().size();
1718                                 }
1719                         }
1720                 }
1721                 
1722                 
1723                 listManager.countNotebookResults(listManager.getNoteIndex());
1724                 notebookTree.blockSignals(true);
1725         notebookTree.load(books, listManager.getLocalNotebooks());
1726         for (int i=selectedNotebookGUIDs.size()-1; i>=0; i--) {
1727                 boolean found = notebookTree.selectGuid(selectedNotebookGUIDs.get(i));
1728                 if (!found)
1729                         selectedNotebookGUIDs.remove(i);
1730         }
1731         listManager.refreshCounters = true;
1732         listManager.refreshCounters();
1733         notebookTree.blockSignals(false);
1734         
1735                 logger.log(logger.HIGH, "Leaving NeverNote.notebookIndexUpdated");
1736     }
1737     // Show/Hide note information
1738         @SuppressWarnings("unused")
1739         private void toggleNotebookWindow() {
1740                 logger.log(logger.HIGH, "Entering NeverNote.toggleNotebookWindow");
1741                 zoomLayout.toggleNotebook();
1742         menuBar.hideNotebooks.setChecked(notebookTree.isVisible());
1743         Global.saveWindowVisible("notebookTree", notebookTree.isVisible());
1744         logger.log(logger.HIGH, "Leaving NeverNote.toggleNotebookWindow");
1745     }   
1746         // Add a new notebook
1747         @SuppressWarnings("unused")
1748         private void addNotebook() {
1749                 logger.log(logger.HIGH, "Inside NeverNote.addNotebook");
1750                 NotebookEdit edit = new NotebookEdit();
1751                 edit.setNotebooks(listManager.getNotebookIndex());
1752                 edit.exec();
1753         
1754                 if (!edit.okPressed())
1755                         return;
1756         
1757                 Calendar currentTime = new GregorianCalendar();
1758                 Long l = new Long(currentTime.getTimeInMillis());
1759                 String randint = new String(Long.toString(l));
1760         
1761                 Notebook newBook = new Notebook();
1762                 newBook.setUpdateSequenceNum(0);
1763                 newBook.setGuid(randint);
1764                 newBook.setName(edit.getNotebook());
1765                 newBook.setServiceCreated(new Date().getTime());
1766                 newBook.setServiceUpdated(new Date().getTime());
1767                 newBook.setDefaultNotebook(false);
1768                 newBook.setPublished(false);
1769                 
1770                 listManager.getNotebookIndex().add(newBook);
1771                 if (edit.isLocal())
1772                         listManager.getLocalNotebooks().add(newBook.getGuid());
1773                 conn.getNotebookTable().addNotebook(newBook, true, edit.isLocal());
1774                 notebookIndexUpdated();
1775                 listManager.countNotebookResults(listManager.getNoteIndex());
1776 //              notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
1777                 logger.log(logger.HIGH, "Leaving NeverNote.addNotebook");
1778         }
1779         // Edit an existing notebook
1780         @SuppressWarnings("unused")
1781         private void stackNotebook() {
1782                 logger.log(logger.HIGH, "Entering NeverNote.stackNotebook");
1783                 StackNotebook edit = new StackNotebook();
1784                 
1785                 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1786                 QTreeWidgetItem currentSelection;
1787                 for (int i=0; i<selections.size(); i++) {
1788                         currentSelection = selections.get(0);
1789                         String guid = currentSelection.text(2);
1790                         if (guid.equalsIgnoreCase("")) {
1791                                  QMessageBox.critical(this, tr("Unable To Stack") ,tr("You can't stack the \"All Notebooks\" item."));
1792                                  return;
1793                         }
1794                         if (guid.equalsIgnoreCase("STACK")) {
1795                                  QMessageBox.critical(this, tr("Unable To Stack") ,tr("You can't stack a stack."));
1796                                  return;
1797                         }
1798                 }
1799
1800                 edit.setStackNames(conn.getNotebookTable().getAllStackNames());
1801
1802                 
1803                 edit.exec();
1804         
1805                 if (!edit.okPressed())
1806                         return;
1807         
1808                 String stack = edit.getStackName();
1809                 
1810                 for (int i=0; i<selections.size(); i++) {
1811                         currentSelection = selections.get(i);
1812                         String guid = currentSelection.text(2);
1813                         listManager.updateNotebookStack(guid, stack);
1814                 }
1815                 notebookIndexUpdated();
1816                 logger.log(logger.HIGH, "Leaving NeverNote.stackNotebook");
1817         }
1818         // Edit an existing notebook
1819         @SuppressWarnings("unused")
1820         private void editNotebook() {
1821                 logger.log(logger.HIGH, "Entering NeverNote.editNotebook");
1822                 NotebookEdit edit = new NotebookEdit();
1823                 
1824                 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1825                 QTreeWidgetItem currentSelection;
1826                 currentSelection = selections.get(0);
1827                 edit.setNotebook(currentSelection.text(0));
1828                 
1829                 String guid = currentSelection.text(2);
1830                 if (!guid.equalsIgnoreCase("STACK")) {
1831                         edit.setTitle(tr("Edit Notebook"));
1832                         edit.setNotebooks(listManager.getNotebookIndex());
1833                         edit.setLocalCheckboxEnabled(false);
1834                         for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1835                                 if (listManager.getNotebookIndex().get(i).getGuid().equals(guid)) {
1836                                         edit.setDefaultNotebook(listManager.getNotebookIndex().get(i).isDefaultNotebook());
1837                                         i=listManager.getNotebookIndex().size();
1838                                 }
1839                         }
1840                 } else {
1841                         edit.setTitle(tr("Edit Stack"));
1842                         edit.setStacks(conn.getNotebookTable().getAllStackNames());
1843                         edit.hideLocalCheckbox();
1844                         edit.hideDefaultCheckbox();
1845                 }
1846                 
1847                 edit.exec();
1848         
1849                 if (!edit.okPressed())
1850                         return;
1851         
1852                 
1853                 if (guid.equalsIgnoreCase("STACK")) {
1854                         conn.getNotebookTable().renameStacks(currentSelection.text(0), edit.getNotebook());
1855                         for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1856                                 if (listManager.getNotebookIndex().get(j).getStack() != null && 
1857                                         listManager.getNotebookIndex().get(j).getStack().equalsIgnoreCase(currentSelection.text(0)))
1858                                                 listManager.getNotebookIndex().get(j).setStack(edit.getNotebook());
1859                         }
1860                         conn.getNotebookTable().renameStacks(currentSelection.text(0), edit.getNotebook());
1861                         currentSelection.setText(0, edit.getNotebook());
1862                         return;
1863                 }
1864                 
1865                 updateListNotebookName(currentSelection.text(0), edit.getNotebook());
1866                 currentSelection.setText(0, edit.getNotebook());
1867                 
1868                 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1869                         if (listManager.getNotebookIndex().get(i).getGuid().equals(guid)) {
1870                                 listManager.getNotebookIndex().get(i).setName(edit.getNotebook());
1871                                 if (!listManager.getNotebookIndex().get(i).isDefaultNotebook() && edit.isDefaultNotebook()) {
1872                                         for (int j=0; j<listManager.getNotebookIndex().size(); j++)
1873                                                 listManager.getNotebookIndex().get(j).setDefaultNotebook(false);
1874                                         listManager.getNotebookIndex().get(i).setDefaultNotebook(true);
1875                                         conn.getNotebookTable().setDefaultNotebook(listManager.getNotebookIndex().get(i).getGuid());
1876                                 }
1877                                 conn.getNotebookTable().updateNotebook(listManager.getNotebookIndex().get(i), true);
1878                                 if (conn.getNotebookTable().isLinked(listManager.getNotebookIndex().get(i).getGuid())) {
1879                                         LinkedNotebook linkedNotebook = conn.getLinkedNotebookTable().getByNotebookGuid(listManager.getNotebookIndex().get(i).getGuid());
1880                                         linkedNotebook.setShareName(edit.getNotebook());
1881                                         conn.getLinkedNotebookTable().updateNotebook(linkedNotebook, true);
1882                                 }
1883                                 i=listManager.getNotebookIndex().size();
1884                         }
1885                 }
1886                 
1887                 // Build a list of non-closed notebooks
1888                 List<Notebook> nbooks = new ArrayList<Notebook>();
1889                 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1890                         boolean found=false;
1891                         for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
1892                                 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid()))
1893                                         found = true;
1894                         }
1895                         if (!found)
1896                                 nbooks.add(listManager.getNotebookIndex().get(i));
1897                 }
1898                 
1899                 
1900                 FilterEditorNotebooks notebookFilter = new FilterEditorNotebooks(conn, logger);
1901                 List<Notebook> filteredBooks = notebookFilter.getValidNotebooks(currentNote, listManager.getNotebookIndex());
1902                 browserWindow.setNotebookList(filteredBooks);
1903                 Iterator<String> set = externalWindows.keySet().iterator();
1904                 while(set.hasNext())
1905                         externalWindows.get(set.next()).getBrowserWindow().setNotebookList(filteredBooks);
1906                 
1907                 Iterator<Integer>it = tabWindows.keySet().iterator();
1908                 while (it.hasNext()) {
1909                         tabWindows.get(it.next()).getBrowserWindow()
1910                                         .setNotebookList(filteredBooks);
1911                 }
1912                 
1913                 logger.log(logger.HIGH, "Leaving NeverNote.editNotebook");
1914         }
1915         // Publish a notebook
1916         @SuppressWarnings("unused")
1917         private void publishNotebook() {
1918                 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1919                 QTreeWidgetItem currentSelection;
1920                 currentSelection = selections.get(0);
1921                 String guid = currentSelection.text(2);
1922
1923                 if (guid.equalsIgnoreCase("STACK") || guid.equalsIgnoreCase(""))
1924                         return;
1925                 
1926                 Notebook n = null;
1927                 int position = 0;
1928                 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1929                         if (guid.equals(listManager.getNotebookIndex().get(i).getGuid())) {
1930                                 n = listManager.getNotebookIndex().get(i);
1931                                 position = i;
1932                                 i = listManager.getNotebookIndex().size();
1933                         }
1934                 }
1935                 if (n == null)
1936                         return;
1937                 
1938                 PublishNotebook publish = new PublishNotebook(Global.username, Global.getServer(), n);
1939                 publish.exec();
1940                 
1941                 if (!publish.okClicked()) 
1942                         return;
1943                 
1944                 Publishing p = publish.getPublishing();
1945                 boolean isPublished = !publish.isStopPressed();
1946                 conn.getNotebookTable().setPublishing(n.getGuid(), isPublished, p);
1947                 n.setPublished(isPublished);
1948                 n.setPublishing(p);
1949                 listManager.getNotebookIndex().set(position, n);
1950                 notebookIndexUpdated();
1951         }
1952         // Publish a notebook
1953         @SuppressWarnings("unused")
1954         private void shareNotebook() {
1955                 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1956                 QTreeWidgetItem currentSelection;
1957                 currentSelection = selections.get(0);
1958                 String guid = currentSelection.text(2);
1959
1960                 if (guid.equalsIgnoreCase("STACK") || guid.equalsIgnoreCase(""))
1961                         return;
1962                 
1963                 Notebook n = null;;
1964                 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1965                         if (guid.equals(listManager.getNotebookIndex().get(i).getGuid())) {
1966                                 n = listManager.getNotebookIndex().get(i);
1967                                 i = listManager.getNotebookIndex().size();
1968                         }
1969                 }
1970                                 
1971                 String authToken = null;
1972                 if (syncRunner.isConnected)
1973                         authToken = syncRunner.authToken;
1974                 ShareNotebook share = new ShareNotebook(n.getName(), conn, n, syncRunner);
1975                 share.exec();
1976                 
1977         }
1978
1979         // Delete an existing notebook
1980         @SuppressWarnings("unused")
1981         private void deleteNotebook() {
1982                 logger.log(logger.HIGH, "Entering NeverNote.deleteNotebook");
1983                 boolean stacksFound = false;
1984                 boolean notebooksFound = false;
1985                 boolean assigned = false;
1986                 // Check if any notes have this notebook
1987                 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1988         for (int i=0; i<selections.size(); i++) {
1989                 QTreeWidgetItem currentSelection;
1990                 currentSelection = selections.get(i);
1991                 String guid = currentSelection.text(2);
1992                 if (!guid.equalsIgnoreCase("STACK")) {
1993                         notebooksFound = true;
1994                         for (int j=0; j<listManager.getNoteIndex().size(); j++) {
1995                                 String noteGuid = listManager.getNoteIndex().get(j).getNotebookGuid();
1996                                 if (noteGuid.equals(guid)) {
1997                                         assigned = true;
1998                                         j=listManager.getNoteIndex().size();
1999                                         i=selections.size();
2000                                 }
2001                         }
2002                 } else {
2003                         stacksFound = true;
2004                 }
2005         }
2006                 if (assigned) {
2007                         QMessageBox.information(this, tr("Unable to Delete"), tr("Some of the selected notebook(s) contain notes.\n"+
2008                                         "Please delete the notes or move them to another notebook before deleting any notebooks."));
2009                         return;
2010                 }
2011                 
2012                 if (conn.getNotebookTable().getAll().size() == 1) {
2013                         QMessageBox.information(this, tr("Unable to Delete"), tr("You must have at least one notebook."));
2014                         return;
2015                 }
2016         
2017         // If all notebooks are clear, verify the delete
2018                 String msg1 = new String(tr("Delete selected notebooks?"));
2019                 String msg2 = new String(tr("Remove selected stacks (notebooks will not be deleted)?"));
2020                 String msg3 = new String(tr("Delete selected notebooks & remove stacks? Notebooks under the stacks are" +
2021                                 " not deleted unless selected?"));
2022                 String msg = "";
2023                 if (stacksFound && notebooksFound)
2024                         msg = msg3;
2025                 if (!stacksFound && notebooksFound)
2026                         msg = msg1;
2027                 if (stacksFound && !notebooksFound)
2028                         msg = msg2;
2029                 if (QMessageBox.question(this, tr("Confirmation"), msg,
2030                         QMessageBox.StandardButton.Yes, 
2031                         QMessageBox.StandardButton.No)==StandardButton.No.value()) {
2032                         return;
2033                 }
2034                 
2035                 // If confirmed, delete the notebook
2036         for (int i=selections.size()-1; i>=0; i--) {
2037                 QTreeWidgetItem currentSelection;
2038                 currentSelection = selections.get(i);
2039                 String guid = currentSelection.text(2);
2040                 if (currentSelection.text(2).equalsIgnoreCase("STACK")) {
2041                         conn.getNotebookTable().renameStacks(currentSelection.text(0), "");
2042                         listManager.renameStack(currentSelection.text(0), "");
2043                 } else {
2044                         conn.getNotebookTable().expungeNotebook(guid, true);
2045                         listManager.deleteNotebook(guid);
2046                 }
2047         }
2048
2049                 notebookIndexUpdated();
2050 //        notebookTreeSelection();
2051 //        notebookTree.load(listManager.getNotebookIndex(), listManager.getLocalNotebooks());
2052 //        listManager.countNotebookResults(listManager.getNoteIndex());
2053         logger.log(logger.HIGH, "Entering NeverNote.deleteNotebook");
2054         }
2055         // A note's notebook has been updated
2056         @SuppressWarnings("unused")
2057         private void updateNoteNotebook(String guid, String notebookGuid) {
2058                 // 同じノートブックに入れられたノート間の履歴を登録
2059                 conn.getHistoryTable().addSameNotebookHistory(guid, notebookGuid);
2060                 
2061                 // Update the list manager
2062                 listManager.updateNoteNotebook(guid, notebookGuid);
2063                 listManager.countNotebookResults(listManager.getNoteIndex());
2064 //              notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());    
2065                 
2066                 // Find the name of the notebook
2067                 String notebookName = null;
2068                 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
2069                         if (listManager.getNotebookIndex().get(i).getGuid().equals(notebookGuid)) {
2070                                 notebookName = listManager.getNotebookIndex().get(i).getName();
2071                                 break;
2072                         }
2073                 }
2074                 
2075                 // If we found the name, update the browser window
2076                 if (notebookName != null) {
2077                         updateListNoteNotebook(guid, notebookName);
2078                         if (guid.equals(currentNoteGuid)) {
2079                                 int pos =  browserWindow.notebookBox.findText(notebookName);
2080                                 if (pos >=0)
2081                                         browserWindow.notebookBox.setCurrentIndex(pos);
2082                         }
2083                 }
2084                 
2085                 // If we're dealing with the current note, then we need to be sure and update the notebook there
2086                 if (guid.equals(currentNoteGuid)) {
2087                         if (currentNote != null) {
2088                                 currentNote.setNotebookGuid(notebookGuid);
2089                         }
2090                 }
2091         }
2092         // Open/close notebooks
2093         @SuppressWarnings("unused")
2094         private void closeNotebooks() {
2095                 NotebookArchive na = new NotebookArchive(listManager.getNotebookIndex(), listManager.getArchiveNotebookIndex());
2096                 na.exec();
2097                 if (!na.okClicked())
2098                         return;
2099                 
2100                 waitCursor(true);
2101                 listManager.getArchiveNotebookIndex().clear();
2102                 
2103                 for (int i=na.getClosedBookList().count()-1; i>=0; i--) {
2104                         String text = na.getClosedBookList().takeItem(i).text();
2105                         for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
2106                                 if (listManager.getNotebookIndex().get(j).getName().equalsIgnoreCase(text)) {
2107                                         Notebook n = listManager.getNotebookIndex().get(j);
2108                                         conn.getNotebookTable().setArchived(n.getGuid(),true);
2109                                         listManager.getArchiveNotebookIndex().add(n);
2110                                         j=listManager.getNotebookIndex().size();
2111                                 }
2112                         }
2113                 }
2114                 
2115                 for (int i=na.getOpenBookList().count()-1; i>=0; i--) {
2116                         String text = na.getOpenBookList().takeItem(i).text();
2117                         for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
2118                                 if (listManager.getNotebookIndex().get(j).getName().equalsIgnoreCase(text)) {
2119                                         Notebook n = listManager.getNotebookIndex().get(j);
2120                                         conn.getNotebookTable().setArchived(n.getGuid(),false);
2121                                         j=listManager.getNotebookIndex().size();
2122                                 }
2123                         }
2124                 }
2125                 notebookTreeSelection();
2126                 listManager.loadNotesIndex();
2127                 notebookIndexUpdated();
2128                 noteIndexUpdated(false);
2129                 reloadTagTree(true);
2130 //              noteIndexUpdated(false);
2131                 
2132                 // Build a list of non-closed notebooks
2133                 List<Notebook> nbooks = new ArrayList<Notebook>();
2134                 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
2135                         boolean found=false;
2136                         for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
2137                                 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid()))
2138                                         found = true;
2139                         }
2140                         if (!found)
2141                                 nbooks.add(listManager.getNotebookIndex().get(i));
2142                 }
2143                 
2144                 FilterEditorNotebooks notebookFilter = new FilterEditorNotebooks(conn, logger);
2145                 List<Notebook> filteredBooks = notebookFilter.getValidNotebooks(currentNote, listManager.getNotebookIndex());
2146                 browserWindow.setNotebookList(filteredBooks);
2147                 
2148                 // Update any external windows
2149                 Iterator<String> set = externalWindows.keySet().iterator();
2150                 while(set.hasNext())
2151                         externalWindows.get(set.next()).getBrowserWindow().setNotebookList(filteredBooks);
2152                 
2153                 // 全てのタブウィンドウを更新
2154                 Iterator<Integer> it = tabWindows.keySet().iterator();
2155                 while (it.hasNext()) {
2156                         tabWindows.get(it.next()).getBrowserWindow()
2157                                         .setNotebookList(filteredBooks);
2158                 }
2159                 
2160                 waitCursor(false);
2161         }
2162         // Change the notebook's icon
2163         @SuppressWarnings("unused")
2164         private void setNotebookIcon() {
2165                 boolean stackSelected = false;
2166                 boolean allNotebookSelected = false;
2167                 
2168                 QTreeWidgetItem currentSelection;
2169                 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
2170                 if (selections.size() == 0)
2171                         return;
2172                 
2173                 currentSelection = selections.get(0);   
2174                 String guid = currentSelection.text(2);
2175                 if (guid.equalsIgnoreCase(""))
2176                         allNotebookSelected = true;
2177                 if (guid.equalsIgnoreCase("STACK"))
2178                         stackSelected = true;
2179
2180                 QIcon currentIcon = currentSelection.icon(0);
2181                 QIcon icon;
2182                 SetIcon dialog;
2183                 
2184                 if (!stackSelected && !allNotebookSelected) {
2185                         icon = conn.getNotebookTable().getIcon(guid);
2186                         if (icon == null) {
2187                                 dialog = new SetIcon(currentIcon, saveLastPath);
2188                                 dialog.setUseDefaultIcon(true);
2189                         } else {
2190                                 dialog = new SetIcon(icon, saveLastPath);
2191                                 dialog.setUseDefaultIcon(false);
2192                         }
2193                 } else {
2194                         if (stackSelected) {
2195                                 icon = conn.getSystemIconTable().getIcon(currentSelection.text(0), "STACK");
2196                         } else {
2197                                 icon = conn.getSystemIconTable().getIcon(currentSelection.text(0), "ALLNOTEBOOK");                              
2198                         }
2199                         if (icon == null) {
2200                                 dialog = new SetIcon(currentIcon, saveLastPath);
2201                                 dialog.setUseDefaultIcon(true);
2202                         } else {
2203                                 dialog = new SetIcon(icon, saveLastPath);
2204                                 dialog.setUseDefaultIcon(false);
2205                         }
2206                 }
2207                 dialog.exec();
2208                 if (dialog.okPressed()) {
2209                 saveLastPath = dialog.getPath();
2210
2211                         QIcon newIcon = dialog.getIcon();
2212                         if (stackSelected) {
2213                                 conn.getSystemIconTable().setIcon(currentSelection.text(0), "STACK", newIcon, dialog.getFileType());
2214                                 if (newIcon == null) {
2215                                         newIcon = new QIcon(iconPath+"books2.png");
2216                                 }
2217                                 currentSelection.setIcon(0,newIcon);
2218                                 return;
2219                         }
2220                         if (allNotebookSelected) {
2221                                 conn.getSystemIconTable().setIcon(currentSelection.text(0), "ALLNOTEBOOK", newIcon, dialog.getFileType());
2222                                 if (newIcon == null) {
2223                                         newIcon = new QIcon(iconPath+"notebook-green.png");
2224                                 }
2225                                 currentSelection.setIcon(0,newIcon);
2226                                 return;
2227                         }
2228                         conn.getNotebookTable().setIcon(guid, newIcon, dialog.getFileType());
2229                         if (newIcon == null) {
2230                                 boolean isPublished = false;;
2231                                 boolean found = false;
2232                                 for (int i=0; i<listManager.getNotebookIndex().size() && !found; i++) {
2233                                         if (listManager.getNotebookIndex().get(i).getGuid().equals(guid)) {
2234                                                 isPublished = listManager.getNotebookIndex().get(i).isPublished();
2235                                                 found = true;
2236                                         }
2237                                 }
2238                                 newIcon = notebookTree.findDefaultIcon(guid, currentSelection.text(1), listManager.getLocalNotebooks(), isPublished);
2239                         }
2240                         currentSelection.setIcon(0, newIcon);
2241                 }
2242         
2243         }
2244         
2245         
2246     //***************************************************************
2247     //***************************************************************
2248     //** These functions deal with Tag menu items
2249     //***************************************************************
2250     //***************************************************************
2251         // Add a new notebook
2252         @SuppressWarnings("unused")
2253         private void addTag() {
2254                 logger.log(logger.HIGH, "Inside NeverNote.addTag");
2255                 TagEdit edit = new TagEdit();
2256                 edit.setTagList(listManager.getTagIndex());
2257
2258                 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2259                 QTreeWidgetItem currentSelection = null;
2260                 if (selections.size() > 0) {
2261                         currentSelection = selections.get(0);
2262                         edit.setParentTag(currentSelection.text(0));
2263                 }
2264
2265                 edit.exec();
2266         
2267                 if (!edit.okPressed())
2268                         return;
2269         
2270                 Calendar currentTime = new GregorianCalendar();
2271                 Long l = new Long(currentTime.getTimeInMillis());
2272                 String randint = new String(Long.toString(l));
2273         
2274                 Tag newTag = new Tag();
2275                 newTag.setUpdateSequenceNum(0);
2276                 newTag.setGuid(randint);
2277                 newTag.setName(edit.getTag());
2278                 if (edit.getParentTag().isChecked()) {
2279                         newTag.setParentGuid(currentSelection.text(2));
2280                         newTag.setParentGuidIsSet(true);
2281                         currentSelection.setExpanded(true);
2282                 }
2283                 conn.getTagTable().addTag(newTag, true);
2284                 listManager.getTagIndex().add(newTag);
2285                 reloadTagTree(true);
2286                 
2287                 logger.log(logger.HIGH, "Leaving NeverNote.addTag");
2288         }
2289         @SuppressWarnings("unused")
2290         private void reloadTagTree() {
2291                 reloadTagTree(false);
2292         }
2293         private void reloadTagTree(boolean reload) {
2294                 logger.log(logger.HIGH, "Entering NeverNote.reloadTagTree");
2295                 tagIndexUpdated(reload);
2296                 boolean filter = false;
2297                 if (reload)
2298                         listManager.countTagResults(listManager.getNoteIndex());
2299                 if (notebookTree.selectedItems().size() > 0 
2300                                                   && !notebookTree.selectedItems().get(0).text(0).equalsIgnoreCase("All Notebooks"))
2301                                                   filter = true;
2302                 if (tagTree.selectedItems().size() > 0)
2303                         filter = true;
2304                 tagTree.showAllTags(!filter);
2305                 tagIndexUpdated(false);
2306                 logger.log(logger.HIGH, "Leaving NeverNote.reloadTagTree");
2307         }
2308         // Edit an existing tag
2309         @SuppressWarnings("unused")
2310         private void editTag() {
2311                 logger.log(logger.HIGH, "Entering NeverNote.editTag");
2312                 TagEdit edit = new TagEdit();
2313                 edit.setTitle("Edit Tag");
2314                 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2315                 QTreeWidgetItem currentSelection;
2316                 currentSelection = selections.get(0);
2317                 edit.setTag(currentSelection.text(0));
2318                 edit.setTagList(listManager.getTagIndex());
2319                 edit.exec();
2320         
2321                 if (!edit.okPressed())
2322                         return;
2323         
2324                 String guid = currentSelection.text(2);
2325                 currentSelection.setText(0,edit.getTag());
2326                 
2327                 for (int i=0; i<listManager.getTagIndex().size(); i++) {
2328                         if (listManager.getTagIndex().get(i).getGuid().equals(guid)) {
2329                                 listManager.getTagIndex().get(i).setName(edit.getTag());
2330                                 conn.getTagTable().updateTag(listManager.getTagIndex().get(i), true);
2331                                 updateListTagName(guid);
2332                                 if (currentNote != null && currentNote.getTagGuids().contains(guid))
2333                                         browserWindow.setTag(getTagNamesForNote(currentNote));
2334                                 logger.log(logger.HIGH, "Leaving NeverNote.editTag");
2335                                 //return;
2336                         }
2337                 }
2338                 listManager.reloadNoteTagNames(guid, edit.getTag());
2339                 noteIndexUpdated(true);
2340                 refreshEvernoteNote(true);
2341                 browserWindow.setTag(getTagNamesForNote(currentNote));
2342                 logger.log(logger.HIGH, "Leaving NeverNote.editTag...");
2343         }
2344         // Delete an existing tag
2345         @SuppressWarnings("unused")
2346         private void deleteTag() {
2347                 logger.log(logger.HIGH, "Entering NeverNote.deleteTag");
2348                 
2349                 if (QMessageBox.question(this, tr("Confirmation"), tr("Delete the selected tags?"),
2350                         QMessageBox.StandardButton.Yes, 
2351                         QMessageBox.StandardButton.No)==StandardButton.No.value()) {
2352                                                         return;
2353                 }
2354                 
2355                 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2356         for (int i=selections.size()-1; i>=0; i--) {
2357                 QTreeWidgetItem currentSelection;
2358                 currentSelection = selections.get(i);                   
2359                 removeTagItem(currentSelection.text(2));
2360         }
2361         tagIndexUpdated(true);
2362         tagTreeSelection();
2363         listManager.countTagResults(listManager.getNoteIndex());
2364 //              tagTree.updateCounts(listManager.getTagCounter());
2365         logger.log(logger.HIGH, "Leaving NeverNote.deleteTag");
2366         }
2367         // Remove a tag tree item.  Go recursively down & remove the children too
2368         private void removeTagItem(String guid) {
2369         for (int j=listManager.getTagIndex().size()-1; j>=0; j--) {             
2370                 String parent = listManager.getTagIndex().get(j).getParentGuid();
2371                 if (parent != null && parent.equals(guid)) {            
2372                         //Remove this tag's children
2373                         removeTagItem(listManager.getTagIndex().get(j).getGuid());
2374                 }
2375         }
2376         //Now, remove this tag
2377         removeListTagName(guid);
2378         conn.getTagTable().expungeTag(guid, true);                      
2379         for (int a=0; a<listManager.getTagIndex().size(); a++) {
2380                 if (listManager.getTagIndex().get(a).getGuid().equals(guid)) {
2381                         listManager.getTagIndex().remove(a);
2382                         return;
2383                 }
2384         }
2385         }
2386         // Setup the tree containing the user's tags
2387     private void initializeTagTree() {
2388         logger.log(logger.HIGH, "Entering NeverNote.initializeTagTree");
2389 //      tagTree.itemSelectionChanged.connect(this, "tagTreeSelection()");
2390 //      tagTree.itemClicked.connect(this, "tagTreeSelection()");
2391         tagTree.selectionSignal.connect(this, "tagTreeSelection()");
2392         listManager.tagSignal.refreshTagTreeCounts.connect(tagTree, "updateCounts(List)");
2393         logger.log(logger.HIGH, "Leaving NeverNote.initializeTagTree");
2394     }
2395     // Listener when a tag is selected
2396         private void tagTreeSelection() {
2397         logger.log(logger.HIGH, "Entering NeverNote.tagTreeSelection");
2398                 
2399         clearTrashFilter();
2400         clearAttributeFilter();
2401         clearSavedSearchFilter();
2402         
2403                 menuBar.noteRestoreAction.setVisible(false);
2404                 
2405                 // ゴミ箱から元の画面に戻す。連想ノートリストをONに。
2406                 if (!rensoNoteListDock.isEnabled()) {
2407                         rensoNoteListDock.setEnabled(true);
2408                 }
2409                 
2410         List<QTreeWidgetItem> selections = tagTree.selectedItems();
2411         QTreeWidgetItem currentSelection;
2412         selectedTagGUIDs.clear();
2413         for (int i=0; i<selections.size(); i++) {
2414                 currentSelection = selections.get(i);
2415                 selectedTagGUIDs.add(currentSelection.text(2));
2416         }
2417         if (selections.size() > 0) {
2418                 menuBar.tagEditAction.setEnabled(true);
2419                 menuBar.tagDeleteAction.setEnabled(true);
2420                 menuBar.tagIconAction.setEnabled(true);
2421         }
2422         else {
2423                 menuBar.tagEditAction.setEnabled(false);
2424                 menuBar.tagDeleteAction.setEnabled(false);
2425                 menuBar.tagIconAction.setEnabled(true);
2426         }
2427         if (selections.size() > 1)
2428                 menuBar.tagMergeAction.setEnabled(true);
2429         else
2430                 menuBar.tagMergeAction.setEnabled(false);
2431         listManager.setSelectedTags(selectedTagGUIDs);
2432         listManager.loadNotesIndex();
2433         noteIndexUpdated(false);
2434         refreshEvernoteNote(true);
2435         listManager.refreshCounters = true;
2436         listManager.refreshCounters();
2437         logger.log(logger.HIGH, "Leaving NeverNote.tagTreeSelection");
2438     }
2439     // trigger the tag index to be refreshed
2440     @SuppressWarnings("unused")
2441         private void tagIndexUpdated() {
2442         tagIndexUpdated(true);
2443     }
2444     private void tagIndexUpdated(boolean reload) {
2445         logger.log(logger.HIGH, "Entering NeverNote.tagIndexUpdated");
2446                 if (selectedTagGUIDs == null)
2447                         selectedTagGUIDs = new ArrayList<String>();
2448                 if (reload)
2449                         listManager.reloadTagIndex();
2450
2451                 tagTree.blockSignals(true);
2452                 if (reload) {
2453                         tagTree.setIcons(conn.getTagTable().getAllIcons());
2454                         tagTree.load(listManager.getTagIndex());
2455                 }
2456
2457         for (int i=selectedTagGUIDs.size()-1; i>=0; i--) {
2458                 boolean found = tagTree.selectGuid(selectedTagGUIDs.get(i));
2459                 if (!found)
2460                         selectedTagGUIDs.remove(i);
2461         }
2462         tagTree.blockSignals(false);
2463         
2464                 browserWindow.setTag(getTagNamesForNote(currentNote));
2465         logger.log(logger.HIGH, "Leaving NeverNote.tagIndexUpdated");
2466     }   
2467     // Show/Hide note information
2468         @SuppressWarnings("unused")
2469         private void toggleTagWindow() {
2470                 logger.log(logger.HIGH, "Entering NeverNote.toggleTagWindow");
2471         if (tagTree.isVisible())
2472                 tagTree.hide();
2473         else
2474                 tagTree.show();
2475         menuBar.hideTags.setChecked(tagTree.isVisible());
2476         Global.saveWindowVisible("tagTree", tagTree.isVisible());
2477         logger.log(logger.HIGH, "Leaving NeverNote.toggleTagWindow");
2478     }   
2479         // A note's tags have been updated
2480         @SuppressWarnings("unused")
2481         private void updateNoteTags(String guid, List<String> tags) {
2482                 // Save any new tags.  We'll need them later.
2483                 List<String> newTags = new ArrayList<String>();
2484                 for (int i=0; i<tags.size(); i++) {
2485                         if (conn.getTagTable().findTagByName(tags.get(i))==null) 
2486                                 newTags.add(tags.get(i));
2487                 }
2488                 
2489                 listManager.saveNoteTags(guid, tags, true);
2490                 listManager.countTagResults(listManager.getNoteIndex());
2491                 StringBuffer names = new StringBuffer("");
2492                 for (int i=0; i<tags.size(); i++) {
2493                         names = names.append(tags.get(i));
2494                         if (i<tags.size()-1) {
2495                                 names.append(Global.tagDelimeter + " ");
2496                         }
2497                 }
2498                 browserWindow.setTag(names.toString());
2499                 
2500                 for (TabBrowse tab: tabWindows.values()) {
2501                         if (tab.getBrowserWindow().getNote().getGuid().equals(guid)) {
2502                                 int index = tabBrowser.indexOf(tab);
2503                                 noteDirty.put(index, true);
2504                                 break;
2505                         }
2506                 }
2507                 
2508                 // Now, we need to add any new tags to the tag tree
2509                 for (int i=0; i<newTags.size(); i++) 
2510                         tagTree.insertTag(newTags.get(i), conn.getTagTable().findTagByName(newTags.get(i)));
2511         }
2512         // Get a string containing all tag names for a note
2513         private String getTagNamesForNote(Note n) {
2514                 logger.log(logger.HIGH, "Entering NeverNote.getTagNamesForNote");
2515                 if (n==null || n.getGuid() == null || n.getGuid().equals(""))
2516                         return "";
2517                 StringBuffer buffer = new StringBuffer(100);
2518                 Vector<String> v = new Vector<String>();
2519                 List<String> guids = n.getTagGuids();
2520                 
2521                 if (guids == null) 
2522                         return "";
2523                 
2524                 for (int i=0; i<guids.size(); i++) {
2525                         v.add(listManager.getTagNameByGuid(guids.get(i)));
2526                 }
2527                 Comparator<String> comparator = Collections.reverseOrder();
2528                 Collections.sort(v,comparator);
2529                 Collections.reverse(v);
2530                 
2531                 for (int i = 0; i<v.size(); i++) {
2532                         if (i>0) 
2533                                 buffer.append(", ");
2534                         buffer.append(v.get(i));
2535                 }
2536                 
2537                 logger.log(logger.HIGH, "Leaving NeverNote.getTagNamesForNote");
2538                 return buffer.toString();
2539         }       
2540         // Tags were added via dropping notes from the note list
2541         @SuppressWarnings("unused")
2542         private void tagsAdded(String noteGuid, String tagGuid) {
2543                 String tagName = null;
2544                 for (int i=0; i<listManager.getTagIndex().size(); i++) {
2545                         if (listManager.getTagIndex().get(i).getGuid().equals(tagGuid)) {
2546                                 tagName = listManager.getTagIndex().get(i).getName();
2547                                 i=listManager.getTagIndex().size();
2548                         }
2549                 }
2550                 if (tagName == null)
2551                         return;
2552                 
2553                 for (int i=0; i<listManager.getMasterNoteIndex().size(); i++) {
2554                         if (listManager.getMasterNoteIndex().get(i).getGuid().equals(noteGuid)) {
2555                                 List<String> tagNames = new ArrayList<String>();
2556                                 tagNames.add(new String(tagName));
2557                                 Note n = listManager.getMasterNoteIndex().get(i);
2558                                 for (int j=0; j<n.getTagNames().size(); j++) {
2559                                         tagNames.add(new String(n.getTagNames().get(j)));
2560                                 }
2561                                 listManager.getNoteTableModel().updateNoteTags(noteGuid, n.getTagGuids(), tagNames);
2562                                 if (n.getGuid().equals(currentNoteGuid)) {
2563                                         Collections.sort(tagNames);
2564                                         String display = "";
2565                                         for (int j=0; j<tagNames.size(); j++) {
2566                                                 display = display+tagNames.get(j);
2567                                                 if (j+2<tagNames.size()) 
2568                                                         display = display+Global.tagDelimeter+" ";
2569                                         }
2570                                         browserWindow.setTag(display);
2571                                 }
2572                                 i=listManager.getMasterNoteIndex().size();
2573                         }
2574                 }
2575                 
2576                 
2577                 listManager.getNoteTableModel().updateNoteSyncStatus(noteGuid, false);
2578         }
2579         private void clearTagFilter() {
2580                 tagTree.blockSignals(true);
2581                 tagTree.clearSelection();
2582                 menuBar.noteRestoreAction.setVisible(false);
2583                 menuBar.tagEditAction.setEnabled(false);
2584                 menuBar.tagMergeAction.setEnabled(false);
2585                 menuBar.tagDeleteAction.setEnabled(false);
2586                 menuBar.tagIconAction.setEnabled(false);
2587                 selectedTagGUIDs.clear();
2588         listManager.setSelectedTags(selectedTagGUIDs);
2589         tagTree.blockSignals(false);
2590         }
2591         // Change the icon for a tag
2592         @SuppressWarnings("unused")
2593         private void setTagIcon() {
2594                 QTreeWidgetItem currentSelection;
2595                 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2596                 if (selections.size() == 0)
2597                         return;
2598                 
2599                 currentSelection = selections.get(0);   
2600                 String guid = currentSelection.text(2);
2601
2602                 QIcon currentIcon = currentSelection.icon(0);
2603                 QIcon icon = conn.getTagTable().getIcon(guid);
2604                 SetIcon dialog;
2605                 if (icon == null) {
2606                         dialog = new SetIcon(currentIcon, saveLastPath);
2607                         dialog.setUseDefaultIcon(true);
2608                 } else {
2609                         dialog = new SetIcon(icon, saveLastPath);
2610                         dialog.setUseDefaultIcon(false);
2611                 }
2612                 dialog.exec();
2613                 if (dialog.okPressed()) {
2614                 saveLastPath = dialog.getPath();
2615                         QIcon newIcon = dialog.getIcon();
2616                         conn.getTagTable().setIcon(guid, newIcon, dialog.getFileType());
2617                         if (newIcon == null) 
2618                                 newIcon = new QIcon(iconPath+"tag.png");
2619                         currentSelection.setIcon(0, newIcon);
2620                 }
2621         
2622         }
2623         // Merge tags
2624         @SuppressWarnings("unused")
2625         private void mergeTags() {
2626                 List<Tag> tags = new ArrayList<Tag>();
2627                 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2628                 for (int i=0; i<selections.size(); i++) {
2629                         Tag record = new Tag();
2630                         record.setGuid(selections.get(i).text(2));
2631                         record.setName(selections.get(i).text(0));
2632                         tags.add(record);
2633                 }
2634
2635                 TagMerge mergeDialog = new TagMerge(tags);
2636                 mergeDialog.exec();
2637                 if (!mergeDialog.okClicked())
2638                         return;
2639                 String newGuid = mergeDialog.getNewTagGuid();
2640                 
2641                 for (int i=0; i<tags.size(); i++) {
2642                         if (!tags.get(i).getGuid().equals(newGuid)) {
2643                                 List<String> noteGuids = conn.getNoteTable().noteTagsTable.getTagNotes(tags.get(i).getGuid());
2644                                 for (int j=0; j<noteGuids.size(); j++) {
2645                                         String noteGuid = noteGuids.get(j);
2646                                         conn.getNoteTable().noteTagsTable.deleteNoteTag(noteGuid);
2647                                         if (!conn.getNoteTable().noteTagsTable.checkNoteNoteTags(noteGuid, newGuid))
2648                                                 conn.getNoteTable().noteTagsTable.saveNoteTag(noteGuid, newGuid, true);
2649                                 }
2650                         }
2651                 }
2652                 listManager.reloadIndexes();
2653         }
2654         
2655     //***************************************************************
2656     //***************************************************************
2657     //** These functions deal with Saved Search menu items
2658     //***************************************************************
2659     //***************************************************************
2660         // Add a new notebook
2661         @SuppressWarnings("unused")
2662         private void addSavedSearch() {
2663                 logger.log(logger.HIGH, "Inside NeverNote.addSavedSearch");
2664                 SavedSearchEdit edit = new SavedSearchEdit();
2665                 edit.setSearchList(listManager.getSavedSearchIndex());
2666                 edit.exec();
2667         
2668                 if (!edit.okPressed())
2669                         return;
2670         
2671                 Calendar currentTime = new GregorianCalendar();         
2672                 Long l = new Long(currentTime.getTimeInMillis());
2673                 String randint = new String(Long.toString(l));
2674         
2675                 SavedSearch search = new SavedSearch();
2676                 search.setUpdateSequenceNum(0);
2677                 search.setGuid(randint);
2678                 search.setName(edit.getName());
2679                 search.setQuery(edit.getQuery());
2680                 search.setFormat(QueryFormat.USER);
2681                 listManager.getSavedSearchIndex().add(search);
2682                 conn.getSavedSearchTable().addSavedSearch(search, true);
2683                 savedSearchIndexUpdated();
2684                 logger.log(logger.HIGH, "Leaving NeverNote.addSavedSearch");
2685         }
2686         // Edit an existing tag
2687         @SuppressWarnings("unused")
2688         private void editSavedSearch() {
2689                 logger.log(logger.HIGH, "Entering NeverNote.editSavedSearch");
2690                 SavedSearchEdit edit = new SavedSearchEdit();
2691                 edit.setTitle(tr("Edit Search"));
2692                 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2693                 QTreeWidgetItem currentSelection;
2694                 currentSelection = selections.get(0);
2695                 String guid = currentSelection.text(1);
2696                 SavedSearch s = conn.getSavedSearchTable().getSavedSearch(guid);
2697                 edit.setName(currentSelection.text(0));
2698                 edit.setQuery(s.getQuery());
2699                 edit.setSearchList(listManager.getSavedSearchIndex());
2700                 edit.exec();
2701         
2702                 if (!edit.okPressed())
2703                         return;
2704         
2705                 List<SavedSearch> list = listManager.getSavedSearchIndex();
2706                 SavedSearch search = null;
2707                 boolean found = false;
2708                 for (int i=0; i<list.size(); i++) {
2709                         search = list.get(i);
2710                         if (search.getGuid().equals(guid)) {
2711                                 i=list.size();
2712                                 found = true;
2713                         }
2714                 }
2715                 if (!found)
2716                         return;
2717                 search.setName(edit.getName());
2718                 search.setQuery(edit.getQuery());
2719                 conn.getSavedSearchTable().updateSavedSearch(search, true);
2720                 savedSearchIndexUpdated();
2721                 logger.log(logger.HIGH, "Leaving NeverNote.editSavedSearch");
2722         }
2723         // Delete an existing tag
2724         @SuppressWarnings("unused")
2725         private void deleteSavedSearch() {
2726                 logger.log(logger.HIGH, "Entering NeverNote.deleteSavedSearch");
2727                 
2728                 if (QMessageBox.question(this, tr("Confirmation"), tr("Delete the selected search?"),
2729                         QMessageBox.StandardButton.Yes, 
2730                         QMessageBox.StandardButton.No)==StandardButton.No.value()) {
2731                                                         return;
2732                 }
2733                 
2734                 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2735         for (int i=selections.size()-1; i>=0; i--) {
2736                 QTreeWidgetItem currentSelection;
2737                 currentSelection = selections.get(i);
2738                 for (int j=0; j<listManager.getSavedSearchIndex().size(); j++) {
2739                         if (listManager.getSavedSearchIndex().get(j).getGuid().equals(currentSelection.text(1))) {
2740                                 conn.getSavedSearchTable().expungeSavedSearch(listManager.getSavedSearchIndex().get(j).getGuid(), true);
2741                                 listManager.getSavedSearchIndex().remove(j);
2742                                 j=listManager.getSavedSearchIndex().size()+1;
2743                         }
2744                 }
2745                 selections.remove(i);
2746         }
2747         savedSearchIndexUpdated();
2748         logger.log(logger.HIGH, "Leaving NeverNote.deleteSavedSearch");
2749         }
2750     // Setup the tree containing the user's tags
2751     private void initializeSavedSearchTree() {
2752         logger.log(logger.HIGH, "Entering NeverNote.initializeSavedSearchTree");
2753         savedSearchTree.itemSelectionChanged.connect(this, "savedSearchTreeSelection()");
2754         logger.log(logger.HIGH, "Leaving NeverNote.initializeSavedSearchTree");
2755     }
2756     // Listener when a tag is selected
2757     @SuppressWarnings("unused")
2758         private void savedSearchTreeSelection() {
2759         logger.log(logger.HIGH, "Entering NeverNote.savedSearchTreeSelection");
2760
2761         clearNotebookFilter();
2762         clearTagFilter();
2763         clearTrashFilter();
2764         clearAttributeFilter();
2765         
2766         String currentGuid = selectedSavedSearchGUID;
2767         menuBar.savedSearchEditAction.setEnabled(true);
2768         menuBar.savedSearchDeleteAction.setEnabled(true);
2769         menuBar.savedSearchIconAction.setEnabled(true);
2770         
2771                 // ゴミ箱から元の画面に戻す。連想ノートリストをONに。
2772                 if (!rensoNoteListDock.isEnabled()) {
2773                         rensoNoteListDock.setEnabled(true);
2774                 }
2775                 
2776         List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2777         QTreeWidgetItem currentSelection;
2778         selectedSavedSearchGUID = "";
2779         for (int i=0; i<selections.size(); i++) {
2780                 currentSelection = selections.get(i);
2781                 if (currentSelection.text(1).equals(currentGuid)) {
2782                         currentSelection.setSelected(false);
2783                 } else {
2784                         selectedSavedSearchGUID = currentSelection.text(1);
2785                 }
2786 //              i = selections.size() +1;
2787         }
2788         
2789         // There is the potential for no notebooks to be selected if this 
2790         // happens then we make it look like all notebooks were selecetd.
2791         // If that happens, just select the "all notebooks"
2792         if (selections.size()==0) {
2793                 clearSavedSearchFilter();
2794         }
2795         listManager.setSelectedSavedSearch(selectedSavedSearchGUID);
2796         
2797         logger.log(logger.HIGH, "Leaving NeverNote.savedSearchTreeSelection");
2798     }
2799     private void clearSavedSearchFilter() {
2800         menuBar.savedSearchEditAction.setEnabled(false);
2801         menuBar.savedSearchDeleteAction.setEnabled(false);
2802         menuBar.savedSearchIconAction.setEnabled(false);
2803         savedSearchTree.blockSignals(true);
2804         savedSearchTree.clearSelection();
2805         savedSearchTree.blockSignals(false);
2806         selectedSavedSearchGUID = "";
2807         searchField.setText("");
2808         searchPerformed = false;
2809         listManager.setSelectedSavedSearch(selectedSavedSearchGUID);
2810     }
2811     // trigger the tag index to be refreshed
2812         private void savedSearchIndexUpdated() { 
2813                 if (selectedSavedSearchGUID == null)
2814                         selectedSavedSearchGUID = new String();
2815                 savedSearchTree.blockSignals(true);
2816                 savedSearchTree.setIcons(conn.getSavedSearchTable().getAllIcons());
2817         savedSearchTree.load(listManager.getSavedSearchIndex());
2818         savedSearchTree.selectGuid(selectedSavedSearchGUID);
2819         savedSearchTree.blockSignals(false);
2820     }
2821     // trigger when the saved search selection changes
2822     @SuppressWarnings("unused")
2823         private void updateSavedSearchSelection() {
2824                 logger.log(logger.HIGH, "Entering NeverNote.updateSavedSearchSelection()");
2825                 
2826         menuBar.savedSearchEditAction.setEnabled(true);
2827         menuBar.savedSearchDeleteAction.setEnabled(true);
2828         menuBar.savedSearchIconAction.setEnabled(true);
2829         List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2830
2831         if (selections.size() > 0) {
2832                 menuBar.savedSearchEditAction.setEnabled(true);
2833                 menuBar.savedSearchDeleteAction.setEnabled(true);
2834                 menuBar.savedSearchIconAction.setEnabled(true);
2835                 selectedSavedSearchGUID = selections.get(0).text(1);
2836                 SavedSearch s = conn.getSavedSearchTable().getSavedSearch(selectedSavedSearchGUID);
2837                 searchField.setText(s.getQuery());
2838         } else { 
2839                 menuBar.savedSearchEditAction.setEnabled(false);
2840                 menuBar.savedSearchDeleteAction.setEnabled(false);
2841                 menuBar.savedSearchIconAction.setEnabled(false);
2842                 selectedSavedSearchGUID = "";
2843                 searchField.setText("");
2844         }
2845         searchFieldChanged();
2846         
2847                 logger.log(logger.HIGH, "Leaving NeverNote.updateSavedSearchSelection()");
2848
2849         
2850     }
2851     // Show/Hide note information
2852         @SuppressWarnings("unused")
2853         private void toggleSavedSearchWindow() {
2854                 logger.log(logger.HIGH, "Entering NeverNote.toggleSavedSearchWindow");
2855         if (savedSearchTree.isVisible())
2856                 savedSearchTree.hide();
2857         else
2858                 savedSearchTree.show();
2859         menuBar.hideSavedSearches.setChecked(savedSearchTree.isVisible());
2860                                 
2861                 Global.saveWindowVisible("savedSearchTree", savedSearchTree.isVisible());
2862         logger.log(logger.HIGH, "Leaving NeverNote.toggleSavedSearchWindow");
2863     }
2864         // Change the icon for a saved search
2865         @SuppressWarnings("unused")
2866         private void setSavedSearchIcon() {
2867                 QTreeWidgetItem currentSelection;
2868                 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2869                 if (selections.size() == 0)
2870                         return;
2871                 
2872                 currentSelection = selections.get(0);   
2873                 String guid = currentSelection.text(1);
2874
2875                 QIcon currentIcon = currentSelection.icon(0);
2876                 QIcon icon = conn.getSavedSearchTable().getIcon(guid);
2877                 SetIcon dialog;
2878                 if (icon == null) {
2879                         dialog = new SetIcon(currentIcon, saveLastPath);
2880                         dialog.setUseDefaultIcon(true);
2881                 } else {
2882                         dialog = new SetIcon(icon, saveLastPath);
2883                         dialog.setUseDefaultIcon(false);
2884                 }
2885                 dialog.exec();
2886                 if (dialog.okPressed()) {
2887                 saveLastPath = dialog.getPath();
2888                         QIcon newIcon = dialog.getIcon();
2889                         conn.getSavedSearchTable().setIcon(guid, newIcon, dialog.getFileType());
2890                         if (newIcon == null) 
2891                                 newIcon = new QIcon(iconPath+"search.png");
2892                         currentSelection.setIcon(0, newIcon);
2893                 }
2894         
2895         }
2896         
2897         
2898         
2899         
2900     //***************************************************************
2901     //***************************************************************
2902     //** These functions deal with Help menu & tool menu items
2903     //***************************************************************
2904     //***************************************************************
2905         // Show database status
2906         @SuppressWarnings("unused")
2907         private void databaseStatus() {
2908                 waitCursor(true);
2909                 indexRunner.interrupt = true;
2910                 int dirty = conn.getNoteTable().getDirtyCount();
2911                 int unindexed = conn.getNoteTable().getUnindexedCount();
2912                 DatabaseStatus status = new DatabaseStatus();
2913                 status.setUnsynchronized(dirty);
2914                 status.setUnindexed(unindexed);
2915                 status.setNoteCount(conn.getNoteTable().getNoteCount());
2916                 status.setNotebookCount(listManager.getNotebookIndex().size());
2917                 status.setUnindexedResourceCount(conn.getNoteTable().noteResourceTable.getUnindexedCount());
2918                 status.setSavedSearchCount(listManager.getSavedSearchIndex().size());
2919                 status.setTagCount(listManager.getTagIndex().size());
2920                 status.setResourceCount(conn.getNoteTable().noteResourceTable.getResourceCount());
2921                 status.setWordCount(conn.getWordsTable().getWordCount());
2922                 status.setHistoryCount(conn.getHistoryTable().getHistoryCount());
2923                 status.setRensoClickCount(conn.getHistoryTable().getRensoClickCount());
2924                 waitCursor(false);
2925                 status.exec();
2926         }
2927         // Compact the database
2928         @SuppressWarnings("unused")
2929         private void compactDatabase() {
2930         logger.log(logger.HIGH, "Entering NeverNote.compactDatabase");
2931                 if (QMessageBox.question(this, tr("Confirmation"), tr("This will free unused space in the database, "+
2932                                 "but please be aware that depending upon the size of your database this can be time consuming " +
2933                                 "and NeighborNote will be unresponsive until it is complete.  Do you wish to continue?"),
2934                                 QMessageBox.StandardButton.Yes, 
2935                                 QMessageBox.StandardButton.No)==StandardButton.No.value() && Global.verifyDelete() == true) {
2936                                                         return;
2937                 }
2938                 setMessage("Compacting database.");
2939                 waitCursor(true);
2940                 listManager.compactDatabase();
2941                 waitCursor(false);
2942                 setMessage("Database compact is complete.");            
2943         logger.log(logger.HIGH, "Leaving NeverNote.compactDatabase");
2944     }
2945         @SuppressWarnings("unused")
2946         private void accountInformation() {
2947                 logger.log(logger.HIGH, "Entering NeverNote.accountInformation");
2948                 AccountDialog dialog = new AccountDialog();
2949                 dialog.show();
2950                 logger.log(logger.HIGH, "Leaving NeverNote.accountInformation");
2951         }
2952         @SuppressWarnings("unused")
2953         private void releaseNotes() {
2954                 logger.log(logger.HIGH, "Entering NeverNote.releaseNotes");
2955                 QDialog dialog = new QDialog(this);
2956                 QHBoxLayout layout = new QHBoxLayout();
2957                 QTextEdit textBox = new QTextEdit();
2958                 layout.addWidget(textBox);
2959                 textBox.setReadOnly(true);
2960                 QFile file = new QFile(Global.getFileManager().getProgramDirPath("release.txt"));
2961                 if (!file.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly,
2962                 QIODevice.OpenModeFlag.Text)))
2963                         return;
2964                 // 日本語文字化け対策
2965                 QTextCodec codec = QTextCodec.codecForName("UTF-8");
2966                 QTextStream textStream = new QTextStream(file);
2967                 textStream.setCodec(codec);
2968                 textBox.setText(textStream.readAll().toString());
2969                 
2970                 file.close();
2971                 dialog.setWindowTitle(tr("Release Notes"));
2972                 dialog.setLayout(layout);
2973                 dialog.show();
2974                 logger.log(logger.HIGH, "Leaving NeverNote.releaseNotes");
2975         }
2976         // Called when user picks Log from the help menu
2977         @SuppressWarnings("unused")
2978         private void logger() {
2979                 logger.log(logger.HIGH, "Entering NeverNote.logger");
2980                 LogFileDialog dialog = new LogFileDialog(emitLog);
2981                 dialog.exec();
2982                 logger.log(logger.HIGH, "Leaving NeverNote.logger");
2983         }
2984         // Menu option "help/about" was selected
2985         @SuppressWarnings("unused")
2986         private void about() {
2987                 logger.log(logger.HIGH, "Entering NeverNote.about");
2988                 QMessageBox.about(this, 
2989                                                 tr("About NeighborNote"),
2990                                                 tr("<h4><center><b>NeighborNote</b></center></h4><hr><center>Version ")
2991                                                 +Global.version + "(based on NixNote 1.6)"
2992                                                 //+"1.2.120724"
2993                                                 +tr("<hr>"
2994                                                                 +"Open Source Evernote Client.<br><br>" 
2995                                                                 +"Licensed under GPL v2.  <br><hr><br>"
2996                                                                 +"</center>Evernote is copyright 2001-2012 by Evernote Corporation<br>"
2997                                                                 +"Jambi and QT are the licensed trademark of Nokia Corporation<br>"
2998                                                                 +"PDFRenderer is licened under the LGPL<br>"
2999                                                                 +"JTidy is copyrighted under the World Wide Web Consortium<br>"
3000                                                                 +"Apache Common Utilities licensed under the Apache License Version 2.0<br>"
3001                                                                 +"Jazzy is licened under the LGPL<br>"
3002                                                                 +"Java is a registered trademark of Oracle Corporation.<br><hr>"
3003                                                                 +"Special thanks to:<br>BitRock InstallBuilder for the Windows installer"
3004                                                                 +"<br>CodeCogs (www.codecogs.com) for the LaTeX image rendering."));
3005                 logger.log(logger.HIGH, "Leaving NeverNote.about");
3006         }
3007         // Hide the entire left hand side
3008         @SuppressWarnings("unused")
3009         private void toggleLeftSide() {
3010                 boolean hidden;
3011                 
3012                 hidden = !menuBar.hideLeftSide.isChecked();
3013                 menuBar.hideLeftSide.setChecked(!hidden);
3014                 
3015                 if (!hidden) 
3016                         leftSplitter1.setHidden(true);
3017                 else
3018                         leftSplitter1.setHidden(false);
3019                 
3020                 Global.saveWindowVisible("leftPanel", hidden);
3021                 
3022         }
3023         public void checkForUpdates() {
3024                 // Send off thread to check for a new version
3025                 versionChecker = new QNetworkAccessManager(this);
3026                 versionChecker.finished.connect(this, "upgradeFileRead(QNetworkReply)");
3027                 QNetworkRequest request = new QNetworkRequest();
3028                 request.setUrl(new QUrl(Global.getUpdatesAvailableUrl()));
3029                 versionChecker.get(request);
3030         }
3031         @SuppressWarnings("unused")
3032         private void upgradeFileRead(QNetworkReply reply) {
3033                 if (!reply.isReadable())
3034                         return;
3035                 
3036                 String winVersion = Global.version;
3037                 String osxVersion = Global.version;
3038                 String linuxVersion = Global.version;
3039                 String linux64Version = Global.version;
3040                 String version = Global.version;
3041                 
3042                 // Determine the versions available
3043                 QByteArray data = reply.readLine();
3044                 while (data != null && !reply.atEnd()) {
3045                         String line = data.toString();
3046                         String lineVersion;
3047                         if (line.contains(":")) 
3048                                 lineVersion = line.substring(line.indexOf(":")+1).replace(" ", "").replace("\n", "");
3049                         else
3050                                 lineVersion = "";
3051                         if (line.toLowerCase().contains("windows")) 
3052                                 winVersion = lineVersion;
3053                         else if (line.toLowerCase().contains("os-x")) 
3054                                 osxVersion = lineVersion;
3055                         else if (line.toLowerCase().contains("linux amd64")) 
3056                                 linux64Version = lineVersion;
3057                         else if (line.toLowerCase().contains("linux i386")) 
3058                                 linuxVersion = lineVersion;
3059                         else if (line.toLowerCase().contains("default")) 
3060                                 version = lineVersion;
3061                         
3062                         // Read the next line
3063                         data = reply.readLine();
3064                 }
3065                 
3066                 // Now we need to determine what system we are on.
3067                 if (System.getProperty("os.name").toLowerCase().contains("windows"))
3068                         version = winVersion;
3069                 if (System.getProperty("os.name").toLowerCase().contains("mac os"))
3070                         version = osxVersion;
3071                 if (System.getProperty("os.name").toLowerCase().contains("Linux")) {
3072                         if (System.getProperty("os.arch").contains("amd64") ||
3073                                 System.getProperty("os.arch").contains("x86_64"))
3074                                         version = linux64Version;
3075                         else
3076                                 version = linuxVersion;
3077                 }
3078                 
3079                 
3080                 for (String validVersion : Global.validVersions) {
3081                         if (version.equals(validVersion))
3082                                 return;
3083                 }
3084                 
3085                 UpgradeAvailableDialog dialog = new UpgradeAvailableDialog();
3086                 dialog.exec();
3087                 if (dialog.remindMe())
3088                         Global.setCheckVersionUpgrade(true);
3089                 else
3090                         Global.setCheckVersionUpgrade(false);
3091         }
3092                 
3093         
3094     //***************************************************************
3095     //***************************************************************
3096     //** These functions deal with the Toolbar
3097     //***************************************************************
3098     //*************************************************************** 
3099         @SuppressWarnings("unused")
3100         private void focusSearch() {
3101                 searchField.setFocus();
3102         }
3103
3104         // Text in the search bar has been cleared
3105         private void searchFieldCleared() {
3106                 saveNote();
3107                 
3108                 // This is done because we want to force a reload of
3109                 // images.  Some images we may want to highlight the text.
3110                 readOnlyCache.clear();
3111                 inkNoteCache.clear();
3112                 noteCache.clear();
3113                 QWebSettings.setMaximumPagesInCache(0);
3114                 QWebSettings.setObjectCacheCapacities(0, 0, 0);
3115         
3116                 searchField.setdefaultText();
3117                 saveNoteColumnPositions();
3118                 saveNoteIndexWidth();
3119                 noteIndexUpdated(true);
3120                 if (currentNote == null && listManager.getNoteIndex().size() > 0) {
3121                         currentNote = listManager.getNoteIndex().get(0);
3122                         currentNoteGuid = currentNote.getGuid();
3123                 }
3124                 refreshEvernoteNote(true);
3125                 if (currentNote != null)
3126                         loadNoteBrowserInformation(browserWindow, currentNoteGuid, currentNote);
3127         }
3128         // text in the search bar changed.  We only use this to tell if it was cleared, 
3129         // otherwise we trigger off searchFieldChanged.
3130         @SuppressWarnings("unused")
3131         private void searchFieldTextChanged(String text) {
3132                 QWebSettings.setMaximumPagesInCache(0);
3133                 QWebSettings.setObjectCacheCapacities(0, 0, 0);
3134
3135                 if (text.trim().equals("") && !searchField.hasFocus()) {
3136                         searchFieldCleared();
3137                         if (searchPerformed) {
3138
3139                                 // This is done because we want to force a reload of
3140                                 // images.  Some images we may want to highlight the text.
3141                                 noteCache.clear();
3142                                 readOnlyCache.clear();
3143                                 inkNoteCache.clear();
3144                                 
3145                                 listManager.setEnSearch("");
3146                                 listManager.loadNotesIndex();
3147                                 refreshEvernoteNote(true);
3148                                 noteIndexUpdated(false);
3149                                 refreshEvernoteNote(true);
3150                         }
3151                         searchPerformed = false;
3152                 }
3153         }
3154     // Text in the toolbar has changed
3155     private void searchFieldChanged() {
3156         logger.log(logger.HIGH, "Entering NeverNote.searchFieldChanged");
3157         noteCache.clear();
3158         readOnlyCache.clear();
3159         inkNoteCache.clear();
3160         saveNoteColumnPositions();
3161         saveNoteIndexWidth();
3162         String text = searchField.text();
3163         listManager.setEnSearch(text.trim());
3164         listManager.loadNotesIndex();
3165         noteIndexUpdated(false);
3166
3167         refreshEvernoteNote(true);
3168         searchPerformed = true;
3169         waitCursor(false);
3170         logger.log(logger.HIGH, "Leaving NeverNote.searchFieldChanged");
3171     }
3172
3173     // Build the window tool bar
3174     private void setupToolBar() {
3175         logger.log(logger.HIGH, "Entering NeverNote.setupToolBar");
3176         toolBar = addToolBar(tr("Tool Bar"));   
3177         toolBar.setObjectName("toolBar");
3178         toolBar.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon);
3179         menuBar.setupToolBarVisible();
3180         if (!Global.isWindowVisible("toolBar"))
3181                 toolBar.setVisible(false);
3182         else
3183                 toolBar.setVisible(true);
3184
3185 //      toolBar.addWidget(menuBar);
3186 //      menuBar.setSizePolicy(Policy.Minimum, Policy.Minimum);
3187 //      toolBar.addSeparator();
3188         prevButton = toolBar.addAction(tr(""));
3189         prevButton.setToolTip(tr("Previous"));
3190         QIcon prevIcon = new QIcon(iconPath+"back.png");
3191         prevButton.setIcon(prevIcon);
3192         prevButton.triggered.connect(this, "previousViewedAction()");   
3193         togglePrevArrowButton(Global.isToolbarButtonVisible("prevArrow", true));
3194         
3195         nextButton = toolBar.addAction(tr(""));
3196         nextButton.setToolTip(tr("Next"));
3197         QIcon nextIcon = new QIcon(iconPath+"forward.png");
3198         nextButton.setIcon(nextIcon);
3199         nextButton.triggered.connect(this, "nextViewedAction()");       
3200         toggleNextArrowButton(Global.isToolbarButtonVisible("nextArrow", true));
3201         
3202         toolBar.addSeparator();
3203         
3204         upButton = toolBar.addAction(tr("Up"));
3205         QIcon upIcon = new QIcon(iconPath+"up.png");
3206         upButton.setIcon(upIcon);
3207         upButton.triggered.connect(this, "upAction()");         
3208         toggleUpArrowButton(Global.isToolbarButtonVisible("upArrow", false));
3209
3210         
3211         downButton = toolBar.addAction(tr("Down"));
3212         QIcon downIcon = new QIcon(iconPath+"down.png");
3213         downButton.setIcon(downIcon);
3214         downButton.triggered.connect(this, "downAction()");
3215         toggleDownArrowButton(Global.isToolbarButtonVisible("downArrow", false));
3216         
3217         synchronizeButton = toolBar.addAction(tr("Synchronize"));
3218         synchronizeButton.setIcon(new QIcon(iconPath+"synchronize.png"));
3219         synchronizeIconAngle = 0;
3220         synchronizeButton.triggered.connect(this, "evernoteSync()");
3221         toggleSynchronizeButton(Global.isToolbarButtonVisible("synchronize", true));
3222         
3223         printButton = toolBar.addAction(tr("Print"));
3224         QIcon printIcon = new QIcon(iconPath+"print.png");
3225         printButton.setIcon(printIcon);
3226         printButton.triggered.connect(this, "printNote()");
3227         togglePrintButton(Global.isToolbarButtonVisible("print", false));
3228
3229         tagButton = toolBar.addAction(tr("Tag")); 
3230         QIcon tagIcon = new QIcon(iconPath+"tag.png");
3231         tagButton.setIcon(tagIcon);
3232         tagButton.triggered.connect(browserWindow, "modifyTags()");
3233         toggleTagButton(Global.isToolbarButtonVisible("tag", false));
3234
3235         attributeButton = toolBar.addAction(tr("Attributes")); 
3236         QIcon attributeIcon = new QIcon(iconPath+"attribute.png");
3237         attributeButton.setIcon(attributeIcon);
3238         attributeButton.triggered.connect(this, "toggleNoteAttributes()");
3239         toggleAttributeButton(Global.isToolbarButtonVisible("attribute", true));
3240                 
3241         emailButton = toolBar.addAction(tr("Email"));
3242         QIcon emailIcon = new QIcon(iconPath+"email.png");
3243         emailButton.setIcon(emailIcon);
3244         emailButton.triggered.connect(this, "emailNote()");
3245         toggleEmailButton(Global.isToolbarButtonVisible("email", false));
3246
3247         deleteButton = toolBar.addAction(tr("Delete"));         
3248         QIcon deleteIcon = new QIcon(iconPath+"delete.png");
3249         deleteButton.setIcon(deleteIcon);
3250         deleteButton.triggered.connect(this, "deleteNote()");
3251         toggleDeleteButton(Global.isToolbarButtonVisible("delete", true));
3252
3253         newButton = toolBar.addAction(tr("New"));
3254         QIcon newIcon = new QIcon(iconPath+"new.png");
3255         if (Global.toolBarNewAction()) {
3256                 newButton.triggered.connect(this, "noteAddNewTab()");
3257         } else {
3258                 newButton.triggered.connect(this, "addNote()");
3259         }
3260
3261         newButton.setIcon(newIcon);
3262         toggleNewButton(Global.isToolbarButtonVisible("new", true));
3263         
3264         allNotesButton = toolBar.addAction(tr("All Notes"));
3265         QIcon allIcon = new QIcon(iconPath+"books.png");
3266         allNotesButton.triggered.connect(this, "allNotes()");
3267         allNotesButton.setIcon(allIcon);
3268         toggleAllNotesButton(Global.isToolbarButtonVisible("allNotes", true));
3269         
3270         //toolBar.addSeparator();
3271         //toolBar.addWidget(new QLabel(tr("Quota:")));
3272         //toolBar.addWidget(quotaBar);
3273         //quotaBar.setSizePolicy(Policy.Minimum, Policy.Minimum);
3274         updateQuotaBar();
3275         //toolBar.addSeparator();
3276         
3277         //toolBar.addWidget(new QLabel(tr("Zoom")));
3278         //toolBar.addWidget(zoomSpinner);
3279         
3280         //toolBar.addWidget(new QLabel("                    "));
3281         //toolBar.addSeparator();
3282         
3283         // 検索ボックスを右寄せするためのスペーサ
3284         QWidget spacerWidget = new QWidget();
3285         spacerWidget.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred);
3286         toolBar.addWidget(spacerWidget);
3287         spacerWidget.setVisible(true);
3288         
3289         searchField = new SearchEdit(iconPath);
3290         searchField.setObjectName("searchField");
3291         searchField.returnPressed.connect(this, "searchFieldChanged()");
3292         searchField.textChanged.connect(this,"searchFieldTextChanged(String)");
3293         searchField.setFixedWidth(300);
3294         searchShortcut = new QShortcut(this);
3295         setupShortcut(searchShortcut, "Focus_Search");
3296         searchShortcut.activated.connect(this, "focusSearch()");
3297         toolBar.addWidget(searchField);
3298         
3299                 searchField.setVisible(Global.isWindowVisible("searchField"));
3300                 // IFIXED !searchField.isVisible() → !Global.isWindowVisible("searchField")
3301                 // なぜかsearchField.isVisible()が常にfalseを返すようなので修正
3302                 if (!Global.isWindowVisible("searchField"))
3303                         menuBar.hideSearch.setChecked(false);
3304                 
3305 //      QSizePolicy sizePolicy = new QSizePolicy();
3306 //      sizePolicy.setHorizontalPolicy(Policy.MinimumExpanding);
3307 //      QLabel spacer = new QLabel("");
3308 //      spacer.setSizePolicy(sizePolicy);
3309 //      toolBar.addWidget(spacer);
3310                 
3311         //searchField.setInsertPolicy(InsertPolicy.InsertAtTop);
3312
3313         //searchClearButton = toolBar.addAction("Search Clear");
3314         //QIcon searchClearIcon = new QIcon(iconPath+"searchclear.png");
3315         //searchClearButton.setIcon(searchClearIcon);
3316         //searchClearButton.triggered.connect(this, "searchFieldCleared()");
3317         //toggleSearchClearButton(Global.isToolbarButtonVisible("searchClear"));
3318
3319         logger.log(logger.HIGH, "Leaving NeverNote.setupToolBar");
3320     }
3321     // Update the sychronize button picture
3322     @Override
3323         public QMenu createPopupMenu() {
3324         QMenu contextMenu = super.createPopupMenu();
3325         
3326         contextMenu.addSeparator();
3327         QAction prevAction = addContextAction("prevArrow", tr("Previous Arrow"));
3328         contextMenu.addAction(prevAction);
3329         prevAction.triggered.connect(this, "togglePrevArrowButton(Boolean)");
3330
3331         QAction nextAction = addContextAction("nextArrow", tr("Next Arrow"));
3332         contextMenu.addAction(nextAction);
3333         nextAction.triggered.connect(this, "toggleNextArrowButton(Boolean)");
3334
3335         QAction upAction = addContextAction("upArrow", tr("Up Arrow"));
3336         contextMenu.addAction(upAction);
3337         upAction.triggered.connect(this, "toggleUpArrowButton(Boolean)");
3338
3339         QAction downAction = addContextAction("downArrow", tr("Down Arrow"));
3340         contextMenu.addAction(downAction);
3341         downAction.triggered.connect(this, "toggleDownArrowButton(Boolean)");
3342
3343         QAction synchronizeAction = addContextAction("synchronize", tr("Synchronize"));
3344         contextMenu.addAction(synchronizeAction);
3345         synchronizeAction.triggered.connect(this, "toggleSynchronizeButton(Boolean)");
3346
3347         QAction printAction = addContextAction("print", tr("Print"));
3348         contextMenu.addAction(printAction);
3349         printAction.triggered.connect(this, "togglePrintButton(Boolean)");
3350
3351         QAction tagAction = addContextAction("tag", tr("Tag"));
3352         contextMenu.addAction(tagAction);
3353         tagAction.triggered.connect(this, "toggleTagButton(Boolean)");
3354         
3355         QAction attributeAction = addContextAction("attribute", tr("Attribute"));
3356         contextMenu.addAction(attributeAction);
3357         attributeAction.triggered.connect(this, "toggleAttributeButton(Boolean)");
3358         
3359         QAction emailAction = addContextAction("email", tr("Email"));
3360         contextMenu.addAction(emailAction);
3361         emailAction.triggered.connect(this, "toggleEmailButton(Boolean)");
3362
3363         QAction deleteAction = addContextAction("delete", tr("Delete"));
3364         contextMenu.addAction(deleteAction);
3365         deleteAction.triggered.connect(this, "toggleDeleteButton(Boolean)");
3366
3367         QAction newAction = addContextAction("new", tr("Add"));
3368         contextMenu.addAction(newAction);
3369         newAction.triggered.connect(this, "toggleNewButton(Boolean)");
3370
3371         QAction allNotesAction = addContextAction("allNotes", tr("All Notes"));
3372         contextMenu.addAction(allNotesAction);
3373         allNotesAction.triggered.connect(this, "toggleAllNotesButton(Boolean)");
3374         
3375 //      QAction searchClearAction = addContextAction("searchClear", tr("Search Clear"));
3376 //      contextMenu.addAction(searchClearAction);
3377 //      searchClearAction.triggered.connect(this, "toggleSearchClearButton(Boolean)");
3378         
3379         return contextMenu;
3380         
3381     }
3382     private QAction addContextAction(String config, String name) {
3383         QAction newAction = new QAction(this);
3384                 newAction.setText(name);
3385                 newAction.setCheckable(true);
3386                 newAction.setChecked(Global.isToolbarButtonVisible(config, true));
3387                 return newAction;
3388     }
3389     private void togglePrevArrowButton(Boolean toggle) {
3390                 prevButton.setVisible(toggle);
3391                 Global.saveToolbarButtonsVisible("prevArrow", toggle);
3392     }
3393     private void toggleNextArrowButton(Boolean toggle) {
3394                 nextButton.setVisible(toggle);
3395                 Global.saveToolbarButtonsVisible("nextArrow", toggle);
3396     }
3397     private void toggleUpArrowButton(Boolean toggle) {
3398                 upButton.setVisible(toggle);
3399                 Global.saveToolbarButtonsVisible("upArrow", toggle);
3400     }
3401     private void toggleDownArrowButton(Boolean toggle) {
3402                 downButton.setVisible(toggle);
3403                 Global.saveToolbarButtonsVisible("downArrow", toggle);
3404     }
3405     private void toggleSynchronizeButton(Boolean toggle) {
3406                 synchronizeButton.setVisible(toggle);
3407                 Global.saveToolbarButtonsVisible("synchronize", toggle);
3408     }
3409     private void togglePrintButton(Boolean toggle) {
3410                 printButton.setVisible(toggle);
3411                 Global.saveToolbarButtonsVisible("print", toggle);
3412     }
3413     private void toggleTagButton(Boolean toggle) {
3414                 tagButton.setVisible(toggle);
3415                 Global.saveToolbarButtonsVisible("tag", toggle);
3416     }
3417     private void toggleAttributeButton(Boolean toggle) {
3418                 attributeButton.setVisible(toggle);
3419                 Global.saveToolbarButtonsVisible("attribute", toggle);
3420     }
3421     private void toggleEmailButton(Boolean toggle) {
3422                 emailButton.setVisible(toggle);
3423                 Global.saveToolbarButtonsVisible("email", toggle);
3424     }
3425     private void toggleDeleteButton(Boolean toggle) {
3426                 deleteButton.setVisible(toggle);
3427                 Global.saveToolbarButtonsVisible("delete", toggle);
3428     }
3429     private void toggleNewButton(Boolean toggle) {
3430                 newButton.setVisible(toggle);
3431                 Global.saveToolbarButtonsVisible("new", toggle);
3432     }
3433     private void toggleAllNotesButton(Boolean toggle) {
3434                 allNotesButton.setVisible(toggle);
3435                 Global.saveToolbarButtonsVisible("allNotes", toggle);
3436     }
3437 //    @SuppressWarnings("unused")
3438 //      private void toggleSearchClearButton(Boolean toggle) {
3439 //              searchClearButton.setVisible(toggle);
3440 //              Global.saveToolbarButtonsVisible("searchClear", toggle);
3441 //    }
3442
3443
3444
3445
3446
3447     @SuppressWarnings("unused")
3448         private void updateSyncButton() {
3449                 
3450         if (syncIcons == null) {
3451                 syncIcons = new ArrayList<QPixmap>();
3452                 double angle = 0.0;
3453                 synchronizeIconAngle = 0;
3454                 QPixmap pix = new QPixmap(iconPath+"synchronize.png");
3455                 syncIcons.add(pix);
3456                 for (int i=0; i<=360; i++) {
3457                         QPixmap rotatedPix = new QPixmap(pix.size());
3458                         QPainter p = new QPainter(rotatedPix);
3459                 rotatedPix.fill(toolBar.palette().color(ColorRole.Button));
3460                 QSize size = pix.size();
3461                 p.translate(size.width()/2, size.height()/2);
3462                 angle = angle+1.0;
3463                 p.rotate(angle);
3464                 p.setBackgroundMode(BGMode.OpaqueMode);
3465                 p.translate(-size.width()/2, -size.height()/2);
3466                 p.drawPixmap(0,0, pix);
3467                 p.end();
3468                 syncIcons.add(rotatedPix);
3469                 }
3470         }
3471
3472         synchronizeIconAngle++;
3473         if (synchronizeIconAngle > 359)
3474                 synchronizeIconAngle=0;
3475         synchronizeButton.setIcon(syncIcons.get(synchronizeIconAngle));
3476         
3477     }
3478     // Synchronize with Evernote
3479
3480         private void evernoteSync() {
3481         logger.log(logger.HIGH, "Entering NeverNote.evernoteSync");
3482         if (!Global.isConnected)
3483                 remoteConnect();
3484         if (Global.isConnected)
3485                 synchronizeAnimationTimer.start(5);
3486 //                      synchronizeAnimationTimer.start(200);
3487         syncTimer();
3488         logger.log(logger.HIGH, "Leaving NeverNote.evernoteSync");
3489     }
3490     private void updateQuotaBar() {
3491         long limit = Global.getUploadLimit();
3492         long amount = Global.getUploadAmount();
3493         if (amount>0 && limit>0) {
3494                 int percent =(int)(amount*100/limit);
3495                 quotaBar.setValue(percent);
3496         } else 
3497                 quotaBar.setValue(0);
3498     }
3499         // Zoom changed
3500     @SuppressWarnings("unused")
3501         private void zoomChanged() {
3502         browserWindow.getBrowser().setZoomFactor(new Double(zoomSpinner.value())/100);
3503     }
3504
3505     //****************************************************************
3506     //****************************************************************
3507     //* System Tray functions
3508     //****************************************************************
3509     //****************************************************************
3510         private void trayToggleVisible() {
3511         if (isVisible()) {
3512                 hide();
3513         } else {
3514                 show();
3515                 if (windowMaximized)
3516                         showMaximized();
3517                 else
3518                         showNormal();
3519                 raise();
3520         }
3521     }
3522     @SuppressWarnings("unused")
3523         private void trayActivated(QSystemTrayIcon.ActivationReason reason) {
3524         if (reason == QSystemTrayIcon.ActivationReason.DoubleClick) {
3525                 String name = QSystemTrayIcon.MessageIcon.resolve(reason.value()).name();
3526                 trayToggleVisible();
3527         }
3528     }
3529     
3530     
3531     //***************************************************************
3532     //***************************************************************
3533     //** These functions deal with the trash tree
3534     //***************************************************************
3535     //***************************************************************    
3536     // Setup the tree containing the trash.
3537     @SuppressWarnings("unused")
3538         private void trashTreeSelection() {     
3539         logger.log(logger.HIGH, "Entering NeverNote.trashTreeSelection");
3540         
3541         clearNotebookFilter();
3542         clearTagFilter();
3543         clearAttributeFilter();
3544         clearSavedSearchFilter();
3545         
3546         String tempGuid = currentNoteGuid;
3547         
3548 //      currentNoteGuid = "";
3549         currentNote = new Note();
3550         selectedNoteGUIDs.clear();
3551         listManager.getSelectedNotebooks().clear();
3552         listManager.getSelectedTags().clear();
3553         listManager.setSelectedSavedSearch("");
3554         browserWindow.clear();
3555     
3556         // toggle the add buttons
3557         newButton.setEnabled(!newButton.isEnabled());
3558         menuBar.noteAdd.setEnabled(newButton.isEnabled());
3559         menuBar.noteAdd.setVisible(true);
3560         
3561         List<QTreeWidgetItem> selections = trashTree.selectedItems();
3562         if (selections.size() == 0) {
3563                 currentNoteGuid = trashNoteGuid;
3564                         trashNoteGuid = tempGuid;
3565                 Global.showDeleted = false;
3566                 menuBar.noteRestoreAction.setEnabled(false);
3567                 menuBar.noteRestoreAction.setVisible(false);
3568                         // ゴミ箱から元の画面に戻す。連想ノートリストをONに。
3569                         rensoNoteListDock.setEnabled(true);
3570         }
3571         else {
3572                 trashNoteGuid = tempGuid;
3573                 currentNoteGuid = trashNoteGuid;
3574                 menuBar.noteRestoreAction.setEnabled(true);
3575                 menuBar.noteRestoreAction.setVisible(true);
3576                 // ゴミ箱を開く。連想ノートリストをOFFに。
3577                 rensoNoteListDock.setEnabled(false);
3578                                         
3579                 Global.showDeleted = true;
3580         }
3581         
3582         menuBar.noteAddNewTab.setEnabled(newButton.isEnabled());
3583                 if (currentNoteGuid == null || currentNoteGuid.equals("")) {
3584                         menuBar.noteAddNewTab.setEnabled(false);
3585                 }
3586         
3587         listManager.loadNotesIndex();
3588         noteIndexUpdated(false);
3589 ////            browserWindow.setEnabled(newButton.isEnabled());
3590         browserWindow.setReadOnly(!newButton.isEnabled());
3591         logger.log(logger.HIGH, "Leaving NeverNote.trashTreeSelection");
3592     }
3593     // Empty the trash file
3594     @SuppressWarnings("unused")
3595         private void emptyTrash() {
3596 //      browserWindow.clear();
3597         logger.log(logger.EXTREME, "Emptying Trash");
3598         listManager.emptyTrash();
3599         logger.log(logger.EXTREME, "Resetting view after trash empty");
3600         if (trashTree.selectedItems().size() > 0) {
3601                 listManager.getSelectedNotebooks().clear();
3602                 listManager.getSelectedTags().clear();
3603                 listManager.setSelectedSavedSearch("");
3604                 newButton.setEnabled(!newButton.isEnabled());
3605                 menuBar.noteAdd.setEnabled(newButton.isEnabled());
3606                 menuBar.noteAddNewTab.setEnabled(newButton.isEnabled());
3607                 if (currentNoteGuid == null || currentNoteGuid.equals("")) {
3608                         menuBar.noteAddNewTab.setEnabled(false);
3609                 }
3610                 menuBar.noteAdd.setVisible(true);
3611                 browserWindow.clear();
3612                 
3613                 clearTagFilter();
3614                 clearNotebookFilter();
3615                 clearSavedSearchFilter();
3616                 clearAttributeFilter();
3617                         
3618                 Global.showDeleted = false;
3619                 menuBar.noteRestoreAction.setEnabled(false);
3620                 menuBar.noteRestoreAction.setVisible(false);
3621                 
3622                 listManager.loadNotesIndex();
3623                 noteIndexUpdated(false);
3624                 
3625                 // ゴミ箱から元の画面に戻す。連想ノートリストをONに。
3626                 if (!rensoNoteListDock.isEnabled()) {
3627                         rensoNoteListDock.setEnabled(true);
3628                 }
3629         }       
3630    }
3631     // Show/Hide trash window
3632         @SuppressWarnings("unused")
3633         private void toggleTrashWindow() {
3634                 logger.log(logger.HIGH, "Entering NeverNote.toggleTrashWindow");
3635         if (trashTree.isVisible())
3636                 trashTree.hide();
3637         else
3638                 trashTree.show();
3639         menuBar.hideTrash.setChecked(trashTree.isVisible());
3640         
3641                 Global.saveWindowVisible("trashTree", trashTree.isVisible());
3642         logger.log(logger.HIGH, "Leaving NeverNote.trashWindow");
3643     }    
3644         private void clearTrashFilter() {
3645                 Global.showDeleted = false;
3646         newButton.setEnabled(true);
3647         menuBar.noteAdd.setEnabled(true);
3648                 if (currentNoteGuid == null || currentNoteGuid.equals("")) {
3649                         menuBar.noteAddNewTab.setEnabled(false);
3650                 } else {
3651                         menuBar.noteAddNewTab.setEnabled(true);
3652                 }
3653         menuBar.noteAdd.setVisible(true);
3654                 trashTree.blockSignals(true);
3655                 trashTree.clearSelection();
3656                 trashTree.blockSignals(false);
3657                 
3658         }
3659     
3660    
3661     //***************************************************************
3662     //***************************************************************
3663     //** These functions deal with connection settings
3664     //***************************************************************
3665     //***************************************************************
3666         // SyncRunner had a problem and things are disconnected
3667         @SuppressWarnings("unused")
3668         private void remoteErrorDisconnect() {
3669                 menuBar.connectAction.setText(tr("Connect"));
3670                 menuBar.connectAction.setToolTip(tr("Connect to Evernote"));
3671                 menuBar.synchronizeAction.setEnabled(false);
3672                 Global.isConnected = false;
3673                 synchronizeAnimationTimer.stop();
3674                 return;
3675         }
3676         // Do a manual connect/disconnect
3677     private void remoteConnect() {
3678         
3679         logger.log(logger.HIGH, "Entering NeverNote.remoteConnect");
3680
3681         // If we are already connected, we just disconnect
3682         if (Global.isConnected) {
3683                 Global.isConnected = false;
3684                 syncRunner.enDisconnect();
3685                 setupConnectMenuOptions();
3686                 setupOnlineMenu();
3687                 return;
3688         }
3689         
3690         OAuthTokenizer tokenizer = new OAuthTokenizer();
3691         AESEncrypter aes = new AESEncrypter();
3692         try {
3693                         aes.decrypt(new FileInputStream(Global.getFileManager().getHomeDirFile("oauthkey.txt")));
3694                 } catch (FileNotFoundException e) {
3695                         // File not found, so we'll just get empty strings anyway. 
3696                 }
3697         
3698                 
3699                 if (Global.getProxyValue("url").equals("")) {
3700                         System.setProperty("http.proxyHost","") ;
3701                         System.setProperty("http.proxyPort", "") ;
3702                         System.setProperty("https.proxyHost","") ;
3703                         System.setProperty("https.proxyPort", "") ;         
3704                 } else {
3705                         // PROXY
3706                         System.setProperty("http.proxyHost",Global.getProxyValue("url")) ;
3707                         System.setProperty("http.proxyPort", Global.getProxyValue("port")) ;
3708                         System.setProperty("https.proxyHost",Global.getProxyValue("url")) ;
3709                         System.setProperty("https.proxyPort", Global.getProxyValue("port")) ;
3710  
3711                         if (Global.getProxyValue("userid").equals("")) {
3712                                 Authenticator.setDefault(new Authenticator() {
3713                         @Override
3714                         protected PasswordAuthentication getPasswordAuthentication() {
3715                                 return new
3716                                 PasswordAuthentication(Global.getProxyValue("userid"),Global.getProxyValue("password").toCharArray());
3717                                 }
3718                         });
3719                 }
3720         }
3721
3722                 syncRunner.userStoreUrl = Global.userStoreUrl;
3723                 syncRunner.noteStoreUrl = Global.noteStoreUrl;
3724                 syncRunner.noteStoreUrlBase = Global.noteStoreUrlBase;
3725                 
3726                 
3727                 
3728                 String authString = aes.getString();
3729                 if (!authString.equals("")) {
3730                         tokenizer.tokenize(authString);
3731                         syncRunner.authToken = tokenizer.oauth_token;
3732                 syncRunner.enConnect();
3733                 }               
3734
3735                 Global.isConnected = syncRunner.isConnected;
3736                 
3737                 boolean autoLoginMessageFlag = false;
3738                 if (!Global.isConnected) {
3739                 OAuthWindow window = new OAuthWindow(logger);
3740                 if (window.error) {
3741                         setMessage(window.errorMessage);
3742                         return;
3743                 }
3744                 window.exec();
3745                 if (window.error) {
3746                         setMessage(window.errorMessage);
3747                         return;
3748                         }
3749                 tokenizer.tokenize(window.response);
3750                 if (tokenizer.oauth_token.equals("")) {
3751                         setMessage(tr("Invalid authorization token received."));
3752                         return;
3753                 }
3754                 aes.setString(window.response);
3755                 try {
3756                                 aes.encrypt(new FileOutputStream(Global.getFileManager().getHomeDirFile("oauthkey.txt")));
3757                         } catch (FileNotFoundException e) {
3758                                 // TODO Auto-generated catch block
3759                                 e.printStackTrace();
3760                         }
3761                 syncRunner.authToken = tokenizer.oauth_token;
3762                         syncRunner.enConnect();
3763                         Global.isConnected = syncRunner.isConnected;
3764                         autoLoginMessageFlag = true;
3765                 }
3766 //              Global.username = syncRunner.username;
3767                         
3768                 if (!Global.isConnected)
3769                         return;
3770                 setupOnlineMenu();
3771                 setupConnectMenuOptions();
3772                 
3773                 // 初回ログイン時に自動ログインが無効だったら、有効化するか確認する
3774                 if (autoLoginMessageFlag && !Global.automaticLogin()) {
3775                         if (QMessageBox.question(this, tr("Confirmation"), tr("Are you sure you want to enable the auto-login feature?"), 
3776                                         QMessageBox.StandardButton.Yes, QMessageBox.StandardButton.No) == StandardButton.Yes.value()) {
3777                                 Global.setAutomaticLogin(true);
3778                         }
3779                 }
3780                 
3781                 logger.log(logger.HIGH, "Leaving NeverNote.remoteConnect");
3782     }
3783     private void setupConnectMenuOptions() {
3784         logger.log(logger.HIGH, "entering NeverNote.setupConnectMenuOptions");
3785                 if (!Global.isConnected) {
3786                         menuBar.connectAction.setText(tr("Connect"));
3787                         menuBar.connectAction.setToolTip(tr("Connect to Evernote"));
3788                         menuBar.synchronizeAction.setEnabled(false);
3789                 } else {
3790                         menuBar.connectAction.setText(tr("Disconnect"));
3791                         menuBar.connectAction.setToolTip(tr("Disconnect from Evernote"));
3792                         menuBar.synchronizeAction.setEnabled(true);
3793                 }
3794                 logger.log(logger.HIGH, "Leaving NeverNote.setupConnectionMenuOptions");
3795     }
3796     
3797     
3798     
3799     //***************************************************************
3800     //***************************************************************
3801     //** These functions deal with the GUI Attribute tree
3802     //***************************************************************
3803     //***************************************************************    
3804     @SuppressWarnings("unused")
3805         private void attributeTreeClicked(QTreeWidgetItem item, Integer integer) {
3806         
3807 //      clearTagFilter();
3808 //      clearNotebookFilter();
3809         clearTrashFilter();
3810 //      clearSavedSearchFilter();
3811         
3812                 // ゴミ箱から元の画面に戻す。連想ノートリストをONに。
3813                 if (!rensoNoteListDock.isEnabled()) {
3814                         rensoNoteListDock.setEnabled(true);
3815                 }
3816
3817         if (attributeTreeSelected == null || item.nativeId() != attributeTreeSelected.nativeId()) {
3818                 if (item.childCount() > 0) {
3819                         item.setSelected(false);
3820                 } else {
3821                 Global.createdBeforeFilter.reset();
3822                 Global.createdSinceFilter.reset();
3823                 Global.changedBeforeFilter.reset();
3824                 Global.changedSinceFilter.reset();
3825                 Global.containsFilter.reset();
3826                         attributeTreeSelected = item;
3827                         DateAttributeFilterTable f = null;
3828                         f = findDateAttributeFilterTable(item.parent());
3829                         if (f!=null)
3830                                 f.select(item.parent().indexOfChild(item));
3831                         else {
3832                                 Global.containsFilter.select(item.parent().indexOfChild(item));
3833                         }
3834                 }
3835                 listManager.loadNotesIndex();
3836                 noteIndexUpdated(false);
3837                 return;
3838         }
3839                 attributeTreeSelected = null;
3840                 item.setSelected(false);
3841         Global.createdBeforeFilter.reset();
3842         Global.createdSinceFilter.reset();
3843         Global.changedBeforeFilter.reset();
3844         Global.changedSinceFilter.reset();
3845         Global.containsFilter.reset();
3846         listManager.loadNotesIndex();
3847                 noteIndexUpdated(false); 
3848     }
3849     // This determines what attribute filter we need, depending upon the selection
3850     private DateAttributeFilterTable findDateAttributeFilterTable(QTreeWidgetItem w) {
3851                 if (w.parent() != null && w.childCount() > 0) {
3852                         QTreeWidgetItem parent = w.parent();
3853                         if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Created && 
3854                                 w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Since)
3855                                         return Global.createdSinceFilter;
3856                         if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Created && 
3857                         w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Before)
3858                                         return Global.createdBeforeFilter;
3859                         if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.LastModified && 
3860                         w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Since)
3861                                         return Global.changedSinceFilter;
3862                 if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.LastModified && 
3863                         w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Before)
3864                                                 return Global.changedBeforeFilter;
3865                 }
3866                 return null;
3867     }
3868
3869     // Show/Hide attribute search window
3870         @SuppressWarnings("unused")
3871         private void toggleAttributesWindow() {
3872                 logger.log(logger.HIGH, "Entering NeverNote.toggleAttributesWindow");
3873         if (attributeTree.isVisible())
3874                 attributeTree.hide();
3875         else
3876                 attributeTree.show();
3877         menuBar.hideAttributes.setChecked(attributeTree.isVisible());
3878         
3879                 Global.saveWindowVisible("attributeTree", attributeTree.isVisible());
3880         logger.log(logger.HIGH, "Leaving NeverNote.toggleAttributeWindow");
3881     }    
3882         private void clearAttributeFilter() {
3883         Global.createdBeforeFilter.reset();
3884         Global.createdSinceFilter.reset();
3885         Global.changedBeforeFilter.reset();
3886         Global.changedSinceFilter.reset();
3887         Global.containsFilter.reset();
3888         attributeTreeSelected = null;
3889                 attributeTree.blockSignals(true);
3890                 attributeTree.clearSelection();
3891                 attributeTree.blockSignals(false);
3892         }
3893     
3894         
3895     //***************************************************************
3896     //***************************************************************
3897     //** These functions deal with the GUI Note index table
3898     //***************************************************************
3899     //***************************************************************    
3900     // Initialize the note list table
3901         private void initializeNoteTable() {
3902                 logger.log(logger.HIGH, "Entering NeverNote.initializeNoteTable");
3903                 noteTableView.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection);
3904                 noteTableView.selectionModel().selectionChanged.connect(this, "noteTableSelection()");
3905                 logger.log(logger.HIGH, "Leaving NeverNote.initializeNoteTable");
3906         }       
3907     // Show/Hide trash window
3908         @SuppressWarnings("unused")
3909         private void toggleNoteListWindow() {
3910                 logger.log(logger.HIGH, "Entering NeverNote.toggleNoteListWindow");
3911         if (noteTableView.isVisible())
3912                 noteTableView.hide();
3913         else
3914                 noteTableView.show();
3915         menuBar.hideNoteList.setChecked(noteTableView.isVisible());
3916         
3917                 Global.saveWindowVisible("noteList", noteTableView.isVisible());
3918         logger.log(logger.HIGH, "Leaving NeverNote.toggleNoteListWindow");
3919     }   
3920         // Handle the event that a user selects a note from the table
3921     @SuppressWarnings("unused")
3922         private void noteTableSelection() {
3923                 logger.log(logger.HIGH, "Entering NeverNote.noteTableSelection");
3924
3925                 saveNote();
3926                 
3927                 // 右クリックだったときの処理
3928                 if (QApplication.mouseButtons().isSet(MouseButton.RightButton)) {
3929                         // 選択されたノートのguidをselectedNoteGUIDsにセット
3930                         List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
3931                         if(selections.size() > 0){
3932                                 selectedNoteGUIDs.clear();
3933                                 for(int i = 0; i < selections.size(); i++){
3934                                         int row = selections.get(i).row();
3935                                         QModelIndex index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition);
3936                                         SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
3937                                         selectedNoteGUIDs.add((String) ix.values().toArray()[0]);
3938                                 }
3939                         }
3940                         return;
3941                 }
3942                 
3943                 // If we have more than one selection, then set the merge note action to true.
3944         List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
3945                 if (selections.size() > 1) 
3946                 menuBar.noteMergeAction.setEnabled(true);
3947                 else
3948                         menuBar.noteMergeAction.setEnabled(false);
3949
3950                 // If the ctrl key is pressed, then they are selecting multiple 
3951                 // entries and we don't want to change the currently viewed note.
3952                 // Shiftキーを押しながらの場合の処理も追加
3953                 if ((QApplication.keyboardModifiers().isSet(KeyboardModifier.ControlModifier) ||
3954                                 QApplication.keyboardModifiers().isSet(KeyboardModifier.ShiftModifier)) &&
3955                                 QApplication.mouseButtons().isSet(MouseButton.LeftButton)){
3956                         selectedNoteGUIDs.clear();
3957                 for (int i=0; i<selections.size(); i++) {
3958                         int row = selections.get(i).row();
3959                         QModelIndex index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition);
3960                         SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
3961                         selectedNoteGUIDs.add((String)ix.values().toArray()[0]);
3962                 }
3963                         return;
3964                 }
3965                 
3966                 // IFIXED 恐らく不要なのでコメントアウト
3967 //              if (historyGuids.size() == 0) {
3968 //                      historyGuids.add(currentNoteGuid);
3969 //                      historyPosition = 1;
3970 //              }
3971
3972         noteTableView.showColumn(Global.noteTableGuidPosition);
3973         
3974         if (!Global.isColumnVisible("guid"))
3975                 noteTableView.hideColumn(Global.noteTableGuidPosition);
3976         
3977         if (selections.size() > 0) {
3978                 QModelIndex index;
3979                 menuBar.noteDuplicateAction.setEnabled(true);
3980                 menuBar.noteOnlineHistoryAction.setEnabled(true);
3981                 menuBar.noteMergeAction.setEnabled(true);
3982                 selectedNoteGUIDs.clear();
3983                 if (currentNoteGuid != null && !currentNoteGuid.equals("") && !Global.showDeleted) {
3984                         menuBar.noteAddNewTab.setEnabled(true);
3985                 }
3986                 if (selections.size() != 1 || Global.showDeleted) {
3987                         menuBar.noteDuplicateAction.setEnabled(false);
3988                 }
3989                 if (selections.size() != 1 || !Global.isConnected) {
3990                         menuBar.noteOnlineHistoryAction.setEnabled(false);
3991                 }
3992                 if (selections.size() == 1) {
3993                         menuBar.noteMergeAction.setEnabled(false);
3994                 }
3995                 for (int i=0; i<selections.size(); i++) {
3996                         int row = selections.get(i).row();
3997                         if (row == 0) 
3998                                 upButton.setEnabled(false);
3999                         else
4000                                 upButton.setEnabled(true);
4001                         if (row < listManager.getNoteTableModel().rowCount()-1)
4002                                 downButton.setEnabled(true);
4003                         else
4004                                 downButton.setEnabled(false);
4005                         index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition);
4006                         SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
4007                                 
4008                         currentNoteGuid = (String)ix.values().toArray()[0];                     
4009                         selectedNoteGUIDs.add(currentNoteGuid);
4010                 }
4011         }
4012         
4013         nextButton.setEnabled(true);
4014                 prevButton.setEnabled(true);
4015                 
4016                 int currentIndex = tabBrowser.currentIndex();
4017                 ArrayList<String> histGuids = historyGuids.get(currentIndex);
4018                 int histPosition = historyPosition.get(currentIndex);
4019                 boolean fromHist = fromHistory.get(currentIndex);
4020                 
4021                 if (!fromHist) {
4022                         int endPosition = histGuids.size() - 1;
4023
4024                         for (int j = histPosition; j <= endPosition; j++) {
4025                                 histGuids.remove(histGuids.size() - 1);
4026                         }
4027                         histGuids.add(currentNoteGuid);
4028                         historyPosition.put(currentIndex, histGuids.size());
4029                         histPosition = histGuids.size();
4030                 }
4031                 if (histPosition <= 1){
4032                         prevButton.setEnabled(false);
4033                 }
4034                 if (histPosition == histGuids.size())
4035                         nextButton.setEnabled(false);
4036                 fromHistory.put(currentIndex, false);
4037                 fromHist = false;
4038                 
4039         scrollToGuid(currentNoteGuid);
4040         refreshEvernoteNote(true);
4041         
4042                 if (currentNoteGuid != null && !currentNoteGuid.equals("")) {
4043                         if (!Global.showDeleted) { // ゴミ箱じゃなければ
4044                                 addBrowseHistory();
4045                         }
4046                 }
4047
4048                 // 連想ノートリストを更新
4049                 rensoNoteListDock.getRensoNoteList().refreshRensoNoteList(currentNoteGuid);
4050                 
4051                 waitCursor(false);
4052                 logger.log(logger.HIGH, "Leaving NeverNote.noteTableSelection");
4053     }
4054     
4055     // 複数ノートの同時閲覧履歴をデータベースに保存
4056         private void addBrowseHistory() {
4057                 // このノートと他のタブウィンドウノートの関連性を内部データベースのHistoryテーブルに登録
4058                 if (tabWindows.size() >= 2) {
4059                         Iterator<Integer> it = tabWindows.keySet().iterator();
4060                         while (it.hasNext()) {
4061                                 int tabIndex = it.next();
4062                                 String nextGuid = ((TabBrowse) tabBrowser.widget(tabIndex)).getBrowserWindow().getNote().getGuid();
4063                                 // guid1=guid2のデータは登録しない
4064                                 if (!currentNoteGuid.equals(nextGuid)) {
4065                                         conn.getHistoryTable().addHistory("browse", currentNoteGuid, nextGuid);
4066                                 }
4067                         }
4068                 }
4069                 // このノートと他の外部ウィンドウノートの関連性を内部データベースのHistoryテーブルに登録
4070                 if (externalWindows.size() >= 1) {
4071                         Iterator<String> it = externalWindows.keySet().iterator();
4072                         while (it.hasNext()) {
4073                                 String nextGuid = it.next();
4074                                 // guid1=guid2のデータは登録しない
4075                                 if (!currentNoteGuid.equals(nextGuid)) {
4076                                         conn.getHistoryTable().addHistory("browse", currentNoteGuid, nextGuid);
4077                                 }
4078                         }
4079                 }
4080         }
4081         
4082         // Trigger a refresh when the note db has been updated
4083         private void noteIndexUpdated(boolean reload) {
4084                 logger.log(logger.HIGH, "Entering NeverNote.noteIndexUpdated");
4085                 saveNote();
4086         refreshEvernoteNoteList();
4087         logger.log(logger.HIGH, "Calling note table reload in NeverNote.noteIndexUpdated() - "+reload);
4088         noteTableView.load(reload);
4089         if (currentNoteGuid == null || currentNoteGuid.equals("")) {
4090                 int pos;
4091                 if (noteTableView.proxyModel.sortOrder() == SortOrder.AscendingOrder)
4092                         pos = noteTableView.proxyModel.rowCount();
4093                 else 
4094                         pos = 1;
4095                 if (noteTableView.proxyModel.rowCount() == 0)
4096                         pos = 0;
4097                 if (pos>0)      {
4098                         QModelIndex i = noteTableView.proxyModel.index(pos-1, Global.noteTableGuidPosition);
4099                         if (i!=null) {
4100                                 currentNoteGuid = (String)i.data();
4101                         }
4102                 }
4103         }               
4104                 if (!noteTableView.isColumnHidden(Global.noteTableGuidPosition))
4105                         showColumns();
4106                 scrollToGuid(currentNoteGuid);
4107                 logger.log(logger.HIGH, "Leaving NeverNote.noteIndexUpdated");
4108     }
4109         // Called when the list of notes is updated
4110     private void refreshEvernoteNoteList() {
4111         logger.log(logger.HIGH, "Entering NeverNote.refreshEvernoteNoteList");
4112         browserWindow.setDisabled(false);
4113                 if (selectedNoteGUIDs == null)
4114                         selectedNoteGUIDs = new ArrayList<String>();
4115                 selectedNoteGUIDs.clear();  // clear out old entries
4116                 
4117                 String saveCurrentNoteGuid = new String();
4118                 String tempNoteGuid = new String();
4119                 
4120                 int currentIndex = tabBrowser.currentIndex();
4121                 ArrayList<String> histGuids = historyGuids.get(currentIndex);
4122                 histGuids.clear();
4123                 historyPosition.put(currentIndex, 0);
4124                 
4125                 prevButton.setEnabled(false);
4126                 nextButton.setEnabled(false);
4127                 
4128                 if (currentNoteGuid == null) 
4129                         currentNoteGuid = new String();
4130                 
4131                 //determine current note guid
4132                 for (Note note : listManager.getNoteIndex()) {
4133                         tempNoteGuid = note.getGuid();
4134                         if (currentNoteGuid.equals(tempNoteGuid)) {
4135                                 saveCurrentNoteGuid = tempNoteGuid;
4136                         }
4137                 }
4138                 
4139                 if (listManager.getNoteIndex().size() == 0) {
4140                         currentNoteGuid = "";
4141                         currentNote = null;
4142                         browserWindow.clear();
4143                         browserWindow.setDisabled(true);
4144                         waitCursor(false);
4145                 } 
4146                 
4147                 if (Global.showDeleted && listManager.getNoteIndex().size() > 0 && saveCurrentNoteGuid.equals("")) {
4148                         currentNoteGuid = listManager.getNoteIndex().get(0).getGuid();
4149                         saveCurrentNoteGuid = currentNoteGuid;
4150                         refreshEvernoteNote(true);
4151                 }
4152                 
4153                 if (!saveCurrentNoteGuid.equals("")) {
4154                         refreshEvernoteNote(false);
4155                 } else {
4156                                 currentNoteGuid = "";
4157                 }
4158                 reloadTagTree(false);
4159
4160                 logger.log(logger.HIGH, "Leaving NeverNote.refreshEvernoteNoteList");
4161         } 
4162     
4163         // Called when the previous arrow button is clicked
4164         @SuppressWarnings("unused")
4165         private void previousViewedAction() {
4166                 int currentIndex = tabBrowser.currentIndex();
4167                 ArrayList<String> histGuids = historyGuids.get(currentIndex);
4168                 int histPosition = historyPosition.get(currentIndex);
4169                 boolean fromHist = fromHistory.get(currentIndex);
4170                 if (!prevButton.isEnabled())
4171                         return;
4172                 if (histPosition == 0)
4173                         return;
4174                 histPosition--;
4175                 historyPosition.put(currentIndex, histPosition);
4176                 if (histPosition <= 0)
4177                         return;
4178                 String historyGuid = histGuids.get(histPosition - 1);
4179                 fromHistory.put(currentIndex, true);
4180                 fromHist = true;
4181                 for (int i = 0; i < noteTableView.model().rowCount(); i++) {
4182                         QModelIndex modelIndex = noteTableView.model().index(i,
4183                                         Global.noteTableGuidPosition);
4184                         if (modelIndex != null) {
4185                                 SortedMap<Integer, Object> ix = noteTableView.model().itemData(
4186                                                 modelIndex);
4187                                 String tableGuid = (String) ix.values().toArray()[0];
4188                                 if (tableGuid.equals(historyGuid)) {
4189                                         noteTableView.selectRow(i);
4190                                         return;
4191                                 }
4192                         }
4193                 }
4194         }
4195         
4196     @SuppressWarnings("unused")
4197         private void nextViewedAction() {
4198         if (!nextButton.isEnabled())
4199                 return;
4200         
4201                 int currentIndex = tabBrowser.currentIndex();
4202                 ArrayList<String> histGuids = historyGuids.get(currentIndex);
4203                 int histPosition = historyPosition.get(currentIndex);
4204                 boolean fromHist = fromHistory.get(currentIndex);
4205                 String historyGuid = histGuids.get(histPosition);
4206                 histPosition++;
4207                 historyPosition.put(currentIndex, histPosition);
4208                 fromHistory.put(currentIndex, true);
4209                 fromHist = true;
4210                 for (int i = 0; i < noteTableView.model().rowCount(); i++) {
4211                         QModelIndex modelIndex = noteTableView.model().index(i,
4212                                         Global.noteTableGuidPosition);
4213                         if (modelIndex != null) {
4214                                 SortedMap<Integer, Object> ix = noteTableView.model().itemData(
4215                                                 modelIndex);
4216                                 String tableGuid = (String) ix.values().toArray()[0];
4217                                 if (tableGuid.equals(historyGuid)) {
4218                                         noteTableView.selectRow(i);
4219                                         return;
4220                                 }
4221                         }
4222                 }
4223     }
4224     // Called when the up arrow is clicked 
4225     @SuppressWarnings("unused")
4226         private void upAction() {
4227         List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
4228         int row = selections.get(0).row();
4229         if (row > 0) {
4230                 noteTableView.selectRow(row-1);
4231         }
4232     }
4233     // Called when the down arrow is clicked 
4234     @SuppressWarnings("unused")
4235         private void downAction() {
4236         List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
4237         int row = selections.get(0).row();
4238         int max = listManager.getNoteTableModel().rowCount();
4239         if (row < max-1) {
4240                 noteTableView.selectRow(row+1);
4241         }
4242     }
4243     // Update a tag string for a specific note in the list
4244     @SuppressWarnings("unused")
4245         private void updateListTags(String guid, List<String> tags) {
4246         logger.log(logger.HIGH, "Entering NeverNote.updateListTags");
4247         StringBuffer tagBuffer = new StringBuffer();
4248         for (int i=0; i<tags.size(); i++) {
4249                 tagBuffer.append(tags.get(i));
4250                 if (i<tags.size()-1)
4251                         tagBuffer.append(", ");
4252         }
4253         
4254         for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4255                 QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4256                 if (modelIndex != null) {
4257                         SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4258                         String tableGuid =  (String)ix.values().toArray()[0];
4259                         if (tableGuid.equals(guid)) {
4260                                 listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition,tagBuffer.toString());
4261                                 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
4262                                 noteTableView.proxyModel.invalidate();
4263                                 return;
4264                         }
4265                 }
4266         }
4267         logger.log(logger.HIGH, "Leaving NeverNote.updateListTags");
4268     }
4269     // Update a title for a specific note in the list
4270     @SuppressWarnings("unused")
4271         private void updateListAuthor(String guid, String author) {
4272         logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
4273
4274         for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4275                 //QModelIndex modelIndex =  noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
4276                 QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4277                 if (modelIndex != null) {
4278                         SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4279                         String tableGuid =  (String)ix.values().toArray()[0];
4280                         if (tableGuid.equals(guid)) {
4281                                 listManager.getNoteTableModel().setData(i, Global.noteTableAuthorPosition,author);
4282                                 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
4283                                 noteTableView.proxyModel.invalidate();
4284                                 return;
4285                         }       
4286                 }
4287         }
4288         
4289         logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
4290     }
4291         private void updateListNoteNotebook(String guid, String notebook) {
4292         logger.log(logger.HIGH, "Entering NeverNote.updateListNoteNotebook");
4293         listManager.getNoteTableModel().updateNoteSyncStatus(guid, false);
4294         logger.log(logger.HIGH, "Leaving NeverNote.updateListNoteNotebook");
4295     }
4296     // Update a title for a specific note in the list
4297     @SuppressWarnings("unused")
4298         private void updateListSourceUrl(String guid, String url) {
4299         logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
4300
4301         for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4302                 //QModelIndex modelIndex =  noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
4303                 QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4304                 if (modelIndex != null) {
4305 //                      SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(modelIndex);
4306                         SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4307                         String tableGuid =  (String)ix.values().toArray()[0];
4308                         if (tableGuid.equals(guid)) {
4309                                 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
4310                                 listManager.getNoteTableModel().setData(i, Global.noteTableSourceUrlPosition,url);
4311                                 noteTableView.proxyModel.invalidate();
4312                                 return;
4313                         }       
4314                 }
4315         }
4316         logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
4317     }
4318         @SuppressWarnings("unused")
4319         private void updateListGuid(String oldGuid, String newGuid) {
4320         logger.log(logger.HIGH, "Entering NeverNote.updateListTitle");
4321
4322         for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4323                 QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4324                 if (modelIndex != null) {
4325                         SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4326                         String tableGuid =  (String)ix.values().toArray()[0];
4327                         if (tableGuid.equals(oldGuid)) {
4328                                 listManager.getNoteTableModel().setData(i, Global.noteTableGuidPosition,newGuid);
4329                                 //listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
4330                                 return;
4331                         }       
4332                 }
4333         }
4334         logger.log(logger.HIGH, "Leaving NeverNote.updateListTitle");
4335     }
4336         private void updateListTagName(String guid) {
4337         logger.log(logger.HIGH, "Entering NeverNote.updateTagName");
4338                 
4339                 for (int j=0; j<listManager.getNoteIndex().size(); j++) {
4340                         if (listManager.getNoteIndex().get(j).getTagGuids().contains(guid)) {
4341                                 String newName = listManager.getTagNamesForNote(listManager.getNoteIndex().get(j));
4342
4343                                 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4344                                         QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4345                                         if (modelIndex != null) {
4346                                                 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4347                                                 String noteGuid = (String)ix.values().toArray()[0];
4348                                                 if (noteGuid.equalsIgnoreCase(listManager.getNoteIndex().get(j).getGuid())) {
4349                                                         listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition, newName);
4350                                                         i=listManager.getNoteTableModel().rowCount();
4351                                                 }
4352                                         }
4353                                 }
4354                         }
4355                 }       
4356         logger.log(logger.HIGH, "Leaving NeverNote.updateListNotebook");
4357     }
4358         private void removeListTagName(String guid) {
4359         logger.log(logger.HIGH, "Entering NeverNote.updateTagName");
4360                 
4361                 for (int j=0; j<listManager.getNoteIndex().size(); j++) {
4362                         if (listManager.getNoteIndex().get(j).getTagGuids().contains(guid)) {
4363                                 for (int i=listManager.getNoteIndex().get(j).getTagGuids().size()-1; i>=0; i--) {
4364                                         if (listManager.getNoteIndex().get(j).getTagGuids().get(i).equals(guid))
4365                                                 listManager.getNoteIndex().get(j).getTagGuids().remove(i);
4366                                 }
4367                                 
4368                                 String newName = listManager.getTagNamesForNote(listManager.getNoteIndex().get(j));
4369                                 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4370                                         QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4371                                         if (modelIndex != null) {
4372                                                 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4373                                                 String noteGuid = (String)ix.values().toArray()[0];
4374                                                 if (noteGuid.equalsIgnoreCase(listManager.getNoteIndex().get(j).getGuid())) {
4375                                                         listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition, newName);
4376                                                         i=listManager.getNoteTableModel().rowCount();
4377                                                 }
4378                                         }
4379                                 }
4380                         }
4381                 }       
4382         logger.log(logger.HIGH, "Leaving NeverNote.updateListNotebook");
4383     }
4384     private void updateListNotebookName(String oldName, String newName) {
4385         logger.log(logger.HIGH, "Entering NeverNote.updateListNotebookName");
4386
4387         for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4388                 QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableNotebookPosition); 
4389                 if (modelIndex != null) {
4390                         SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4391                         String tableName =  (String)ix.values().toArray()[0];
4392                         if (tableName.equalsIgnoreCase(oldName)) {
4393                                 listManager.getNoteTableModel().setData(i, Global.noteTableNotebookPosition, newName);
4394                         }
4395                 }
4396         }
4397         logger.log(logger.HIGH, "Leaving NeverNote.updateListNotebookName");
4398     }
4399     @SuppressWarnings("unused")
4400         private void updateListDateCreated(String guid, QDateTime date) {
4401         logger.log(logger.HIGH, "Entering NeverNote.updateListDateCreated");
4402
4403         for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4404                 QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4405                 if (modelIndex != null) {
4406                         SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4407                         String tableGuid =  (String)ix.values().toArray()[0];
4408                         if (tableGuid.equals(guid)) {
4409                                 listManager.getNoteTableModel().setData(i, Global.noteTableCreationPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
4410                                 noteTableView.proxyModel.invalidate();
4411                                 return;
4412                         }
4413                 }
4414         }
4415         logger.log(logger.HIGH, "Leaving NeverNote.updateListDateCreated");
4416     }
4417     @SuppressWarnings("unused")
4418         private void updateListDateSubject(String guid, QDateTime date) {
4419         logger.log(logger.HIGH, "Entering NeverNote.updateListDateSubject");
4420
4421         for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4422                 QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4423                 if (modelIndex != null) {
4424                         SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4425                         String tableGuid =  (String)ix.values().toArray()[0];
4426                         if (tableGuid.equals(guid)) {
4427                                 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
4428                                 listManager.getNoteTableModel().setData(i, Global.noteTableSubjectDatePosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
4429                                 noteTableView.proxyModel.invalidate();
4430                                 return;
4431                         }
4432                 }
4433         }
4434         logger.log(logger.HIGH, "Leaving NeverNote.updateListDateCreated");
4435     }
4436         private void updateListDateChanged(String guid, QDateTime date) {
4437         logger.log(logger.HIGH, "Entering NeverNote.updateListDateChanged");
4438
4439         for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4440                 QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4441                 if (modelIndex != null) {
4442                         SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4443                         String tableGuid =  (String)ix.values().toArray()[0];
4444                         if (tableGuid.equals(guid)) {
4445                                 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
4446                                 listManager.getNoteTableModel().setData(i, Global.noteTableChangedPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
4447                                 return;
4448                         }
4449                 }
4450         }
4451         logger.log(logger.HIGH, "Leaving NeverNote.updateListDateChanged");
4452     }
4453     private void updateListDateChanged() {
4454         logger.log(logger.HIGH, "Entering NeverNote.updateListDateChanged");
4455         QDateTime date = new QDateTime(QDateTime.currentDateTime());
4456         updateListDateChanged(currentNoteGuid, date);
4457         logger.log(logger.HIGH, "Leaving NeverNote.updateListDateChanged");
4458     }  
4459     // Redo scroll
4460         private void scrollToCurrentGuid() {
4461         //scrollToGuid(currentNoteGuid);
4462         List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
4463         if (selections.size() == 0)
4464                 return;
4465         QModelIndex index = selections.get(0);
4466         int row = selections.get(0).row();
4467         String guid = (String)index.model().index(row, Global.noteTableGuidPosition).data();
4468         scrollToGuid(guid);
4469     }
4470         // Scroll to the current GUID in tthe list.
4471     // Scroll to a particular index item
4472     private void scrollToGuid(String guid) {
4473         if (currentNote == null || guid == null) 
4474                 return;
4475         if (currentNote.isActive() && Global.showDeleted) {
4476                 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
4477                         if (!listManager.getNoteIndex().get(i).isActive()) {
4478                                 currentNote = listManager.getNoteIndex().get(i);
4479                                 currentNoteGuid =  currentNote.getGuid();
4480                                 i = listManager.getNoteIndex().size();
4481                         }
4482                 }
4483         }
4484         if (!currentNote.isActive() && !Global.showDeleted) {
4485                 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
4486                         if (listManager.getNoteIndex().get(i).isActive()) {
4487                                 currentNote = listManager.getNoteIndex().get(i);
4488                                 currentNoteGuid =  currentNote.getGuid();
4489                                 i = listManager.getNoteIndex().size();
4490                         }
4491                 }
4492         }
4493         QModelIndex index; 
4494         for (int i=0; i<noteTableView.model().rowCount(); i++) {
4495                 index = noteTableView.model().index(i, Global.noteTableGuidPosition);
4496                 if (currentNoteGuid.equals(index.data())) {
4497 //                      noteTableView.selectionModel().blockSignals(true);
4498                         noteTableView.selectRow(i);
4499 //                              noteTableView.selectionModel().blockSignals(false);
4500                         noteTableView.scrollTo(index, ScrollHint.EnsureVisible);  // This should work, but it doesn't
4501                                 i=listManager.getNoteTableModel().rowCount();
4502                 }
4503         }
4504         noteTableView.repaint();
4505     }
4506     // Show/Hide columns
4507     private void showColumns() {
4508                 noteTableView.setColumnHidden(Global.noteTableCreationPosition, !Global.isColumnVisible("dateCreated"));
4509                 noteTableView.setColumnHidden(Global.noteTableChangedPosition, !Global.isColumnVisible("dateChanged"));
4510                 noteTableView.setColumnHidden(Global.noteTableSubjectDatePosition, !Global.isColumnVisible("dateSubject"));
4511                 noteTableView.setColumnHidden(Global.noteTableAuthorPosition, !Global.isColumnVisible("author"));
4512                 noteTableView.setColumnHidden(Global.noteTableSourceUrlPosition, !Global.isColumnVisible("sourceUrl"));
4513                 noteTableView.setColumnHidden(Global.noteTableTagPosition, !Global.isColumnVisible("tags"));
4514                 noteTableView.setColumnHidden(Global.noteTableNotebookPosition, !Global.isColumnVisible("notebook"));
4515                 noteTableView.setColumnHidden(Global.noteTableSynchronizedPosition, !Global.isColumnVisible("synchronized"));
4516                 noteTableView.setColumnHidden(Global.noteTableGuidPosition, !Global.isColumnVisible("guid"));
4517                 noteTableView.setColumnHidden(Global.noteTableThumbnailPosition, !Global.isColumnVisible("thumbnail"));
4518                 noteTableView.setColumnHidden(Global.noteTableTitlePosition, !Global.isColumnVisible("title"));         
4519                 noteTableView.setColumnHidden(Global.noteTablePinnedPosition, !Global.isColumnVisible("pinned")); 
4520     }
4521     // Title color has changed
4522     @SuppressWarnings("unused")
4523         private void titleColorChanged(Integer color) {
4524         logger.log(logger.HIGH, "Entering NeverNote.titleColorChanged");
4525
4526         setNoteDirty();
4527         QColor backgroundColor = new QColor();
4528                 QColor foregroundColor = new QColor(QColor.black);
4529                 backgroundColor.setRgb(color);
4530                 
4531                 if (backgroundColor.rgb() == QColor.black.rgb() || backgroundColor.rgb() == QColor.blue.rgb())
4532                         foregroundColor.setRgb(QColor.white.rgb());
4533         
4534                 if (selectedNoteGUIDs.size() == 0)
4535                         selectedNoteGUIDs.add(currentNoteGuid);
4536                 
4537         for (int j=0; j<selectedNoteGUIDs.size(); j++) {
4538                 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4539                         QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4540                         if (modelIndex != null) {
4541                                 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4542                                 String tableGuid =  (String)ix.values().toArray()[0];
4543                                 if (tableGuid.equals(selectedNoteGUIDs.get(j))) {
4544                                         for (int k=0; k<Global.noteTableColumnCount; k++) {
4545                                                 listManager.getNoteTableModel().setData(i, k, backgroundColor, Qt.ItemDataRole.BackgroundRole);
4546                                                 listManager.getNoteTableModel().setData(i, k, foregroundColor, Qt.ItemDataRole.ForegroundRole);
4547                                                 listManager.updateNoteTitleColor(selectedNoteGUIDs.get(j), backgroundColor.rgb());
4548                                         }
4549                                         i=listManager.getNoteTableModel().rowCount();
4550                                 }
4551                         }
4552                 }
4553         }
4554         logger.log(logger.HIGH, "Leaving NeverNote.titleColorChanged");
4555     }
4556     // A note has been pinned or unpinned
4557         @SuppressWarnings("unused")
4558         private void notePinned() {
4559                 logger.log(logger.EXTREME, "Entering NeverNote.notePinned()");
4560                 setNoteDirty();
4561
4562         for (int j=0; j<selectedNoteGUIDs.size(); j++) {
4563                 NoteMetadata meta = listManager.getNoteMetadata().get(selectedNoteGUIDs.get(j));
4564                 boolean pinned = !meta.isPinned();
4565                 meta.setPinned(pinned);   // Toggle the pinned/unpinned 
4566                 
4567                 // Update the list & table
4568                 listManager.updateNoteMetadata(meta);   
4569                 noteTableView.proxyModel.addGuid(selectedNoteGUIDs.get(j), meta);
4570         }
4571                 logger.log(logger.EXTREME, "Leaving NeverNote.notePinned()");
4572     }
4573     // Wide list was chosen
4574     public void narrowListView() {
4575         saveNoteColumnPositions();
4576         saveNoteIndexWidth();
4577         saveWindowState();
4578                 int sortCol = noteTableView.proxyModel.sortColumn();
4579                 int sortOrder = noteTableView.proxyModel.sortOrder().value();
4580                 Global.setSortColumn(sortCol);
4581                 Global.setSortOrder(sortOrder);
4582
4583                 Global.setListView(Global.View_List_Narrow);
4584         
4585         menuBar.wideListView.blockSignals(true);
4586         menuBar.narrowListView.blockSignals(true);
4587         
4588         menuBar.wideListView.setChecked(false);
4589         menuBar.narrowListView.setChecked(true);
4590         
4591         menuBar.wideListView.blockSignals(false);
4592         menuBar.narrowListView.blockSignals(false);
4593         
4594         mainLeftRightSplitter.addWidget(noteTableView);
4595         mainLeftRightSplitter.addWidget(tabBrowser);
4596         
4597         restoreWindowState(false);
4598         noteTableView.repositionColumns();
4599         noteTableView.resizeColumnWidths();
4600         noteTableView.resizeRowHeights();
4601         
4602         sortCol = Global.getSortColumn();
4603                 sortOrder = Global.getSortOrder();
4604                 noteTableView.proxyModel.blocked = true;
4605                 noteTableView.sortByColumn(sortCol, SortOrder.resolve(sortOrder));
4606                 noteTableView.proxyModel.blocked = false;
4607
4608                 
4609         showColumns();
4610         noteTableView.load(false);
4611         refreshEvernoteNote(true);
4612         scrollToCurrentGuid();
4613     }
4614     public void wideListView() {
4615                 int sortCol = noteTableView.proxyModel.sortColumn();
4616                 int sortOrder = noteTableView.proxyModel.sortOrder().value();
4617                 Global.setSortColumn(sortCol);
4618                 Global.setSortOrder(sortOrder);
4619
4620                 saveWindowState();
4621         saveNoteColumnPositions();
4622         saveNoteIndexWidth();
4623         Global.setListView(Global.View_List_Wide);
4624
4625         menuBar.wideListView.blockSignals(true);
4626         menuBar.narrowListView.blockSignals(true);
4627         
4628         menuBar.wideListView.setChecked(true);
4629         menuBar.narrowListView.setChecked(false);
4630
4631         menuBar.wideListView.blockSignals(false);
4632         menuBar.narrowListView.blockSignals(false);
4633         browserIndexSplitter.setVisible(true);
4634         browserIndexSplitter.addWidget(noteTableView);
4635                 browserIndexSplitter.addWidget(tabBrowser);
4636                 
4637         restoreWindowState(false);
4638         noteTableView.repositionColumns();
4639         noteTableView.resizeColumnWidths();
4640         noteTableView.resizeRowHeights();
4641         
4642         sortCol = Global.getSortColumn();
4643                 sortOrder = Global.getSortOrder();
4644                 noteTableView.proxyModel.blocked = true;
4645                 noteTableView.sortByColumn(sortCol, SortOrder.resolve(sortOrder));
4646                 noteTableView.proxyModel.blocked = false;
4647
4648         showColumns();
4649         noteTableView.load(false);
4650         scrollToCurrentGuid();
4651     }
4652     // Sort order for the notebook has changed   
4653     public void tableSortOrderChanged(Integer column, Integer order) {
4654         
4655         // Find what notebook (if any) is selected.  We ignore stacks & the "All Notebooks".
4656         List<QTreeWidgetItem> selectedNotebook = notebookTree.selectedItems();
4657         if (selectedNotebook.size() > 0 && !selectedNotebook.get(0).text(0).equalsIgnoreCase("All Notebooks") && !selectedNotebook.get(0).text(2).equalsIgnoreCase("STACK")) {
4658                 QTreeWidgetItem currentSelectedNotebook = selectedNotebook.get(0);
4659                 String notebook;
4660                 notebook = currentSelectedNotebook.text(2);
4661                 conn.getNotebookTable().setSortOrder(notebook, column, order);
4662         }       
4663     }
4664     
4665     //***************************************************************
4666     @SuppressWarnings("unused")
4667         private void evernoteLinkClick(String syncGuid, String locGuid) {
4668         String guid = null;
4669         if (conn.getNoteTable().guidExists(syncGuid)) {
4670                 guid = syncGuid;
4671         } else {
4672                 // If we didn't find it via the synchronized guid, look under the local guid
4673                 // Iwe don't find it there, look to see if the GUID is posted under the local GUID, but was 
4674                 // later synchronized (that causes the guid to change so we need to find the new one).
4675                 if (conn.getNoteTable().guidExists(locGuid)) 
4676                         guid = locGuid;
4677                 else
4678                         guid = conn.getNoteTable().findAlternateGuid(locGuid);
4679         }
4680                 if (guid != null) {
4681                         openExternalEditor(guid);
4682                         return;
4683                 }
4684         
4685         //If we've gotten this far, we can't find the note
4686         QMessageBox.information(this, tr("Note Not Found"), tr("Sorry, but I can't"+
4687                         " seem to find that note."));
4688     }
4689     //***************************************************************
4690     //***************************************************************
4691     //** External editor window functions                    
4692     //***************************************************************
4693     //***************************************************************
4694         private void listDoubleClick() {
4695                 saveNote();
4696         openExternalEditor(currentNoteGuid);
4697     }
4698     private void openExternalEditor(String guid) {
4699         
4700         if (externalWindows.containsKey(guid)) {
4701                 externalWindows.get(guid).raise();
4702                 return;
4703         }
4704         
4705         Note note = conn.getNoteTable().getNote(guid, true, true, false, true, true);
4706         // We have a new external editor to create
4707         QIcon appIcon = new QIcon(iconPath+"nevernote.png");
4708         ExternalBrowse newBrowser = new ExternalBrowse(conn, cbObserver);
4709         
4710         newBrowser.setWindowIcon(appIcon);
4711         externalWindows.put(guid, newBrowser);
4712         showEditorButtons(newBrowser.getBrowserWindow());
4713         loadNoteBrowserInformation(newBrowser.getBrowserWindow(), guid, note);
4714         setupBrowserWindowListeners(newBrowser.getBrowserWindow(), false);
4715         newBrowser.windowClosing.connect(this, "externalWindowClosing(String)");
4716         //newBrowser.getBrowserWindow().noteSignal.titleChanged.connect(this, "externalWindowTitleEdited(String, String)");
4717         newBrowser.getBrowserWindow().noteSignal.tagsChanged.connect(this, "externalWindowTagsEdited(String, List)");
4718         newBrowser.contentsChanged.connect(this, "saveNoteExternalBrowser(String, String, Boolean, BrowserWindow)");
4719         newBrowser.getBrowserWindow().blockApplication.connect(this, "blockApplication(BrowserWindow)");
4720         newBrowser.getBrowserWindow().unblockApplication.connect(this, "unblockApplication()");
4721
4722         browserWindow.noteSignal.tagsChanged.connect(newBrowser, "updateTags(String, List)");
4723         browserWindow.noteSignal.titleChanged.connect(newBrowser, "updateTitle(String, String)");
4724         browserWindow.noteSignal.notebookChanged.connect(newBrowser, "updateNotebook(String, String)");
4725         
4726         newBrowser.show();
4727     }
4728     @SuppressWarnings({ "rawtypes", "unused" })
4729         private void externalWindowTagsEdited(String guid, List values) {
4730         StringBuffer line = new StringBuffer(100);
4731         for (int i=0; i<values.size(); i++) {
4732                 if (i>0) 
4733                         line.append(Global.tagDelimeter+" ");
4734                 line.append(values.get(i));
4735         }
4736         if (guid.equals(currentNoteGuid)) {
4737                 browserWindow.setTag(line.toString());
4738         }
4739     }
4740     @SuppressWarnings("unused")
4741         private void externalWindowClosing(String guid) {
4742                 externalWindows.remove(guid);
4743     }
4744     
4745         // ***************************************************************
4746         // ***************************************************************
4747         // ** タブウィンドウの機能
4748         // ***************************************************************
4749         // ***************************************************************
4750         @SuppressWarnings("unused")
4751         private void openNewTab() {
4752                 saveNote();
4753
4754                 // selectedNoteGUIDsをディープコピー
4755                 List<String> copySelected = new ArrayList<String>(selectedNoteGUIDs);
4756                 
4757                 for (int i=0; i < copySelected.size() ; i++) {
4758                         openTabEditor(copySelected.get(i));
4759                 }
4760         }
4761         
4762         // 連想ノートリストから新しいタブで開く
4763         @SuppressWarnings("unused")
4764         private void openNewTabFromRNL(){
4765                 if(rensoNotePressedItemGuid != null){
4766                         String prevCurrentNoteGuid = new String(currentNoteGuid);
4767                         
4768                         saveNote();
4769                         openTabEditor(rensoNotePressedItemGuid);
4770                         
4771                         // 連想ノートリストアイテムクリック操作を記録
4772                         conn.getHistoryTable().addHistory("rensoItemClick", prevCurrentNoteGuid, rensoNotePressedItemGuid);
4773                 }
4774         }
4775         
4776         private void openTabEditor(String guid) {
4777                 
4778                 Note note = conn.getNoteTable().getNote(guid, true, true, false, true, true);
4779                 // 新しいタブエディタを作成
4780                 TabBrowse newBrowser = new TabBrowse(conn, tabBrowser, cbObserver);
4781                 showEditorButtons(newBrowser.getBrowserWindow());
4782                 
4783                 String noteTitle = note.getTitle();
4784                 int index = tabBrowser.addNewTab(newBrowser, noteTitle);
4785                 tabWindows.put(index, newBrowser);
4786                 noteDirty.put(index, false);
4787                 
4788                 // noteTableViewの選択を変更するとselectionChangedが発生してしまうので一度切断
4789                 noteTableView.selectionModel().selectionChanged.disconnect(this, "noteTableSelection()");
4790                 loadNoteBrowserInformation(newBrowser.getBrowserWindow(), guid, note);
4791                 // 再接続
4792                 noteTableView.selectionModel().selectionChanged.connect(this, "noteTableSelection()");
4793                 
4794                 setupBrowserWindowListeners(newBrowser.getBrowserWindow(), false);
4795                 
4796                 // ExtendedInformationを必要があれば表示する
4797                 toggleNoteInformation();
4798                 // Sourceを必要があれば表示する
4799                 viewSource();
4800                 // EditorButtonsBarを必要があれば表示する
4801                 toggleEditorButtonBar();
4802
4803                 // 履歴記録のハッシュマップを初期化
4804                 ArrayList<String> histGuids = new ArrayList<String>();
4805                 historyGuids.put(index, histGuids);
4806                 historyPosition.put(index, 0);
4807                 fromHistory.put(index, false);
4808
4809                 // 履歴に今開いたノートを追加
4810                 histGuids.add(guid);
4811                 historyPosition.put(index, histGuids.size());
4812
4813                 tabBrowser.setCurrentIndex(index);
4814
4815                 if (guid != null && !guid.equals("")) {
4816                         if (!Global.showDeleted) { // ゴミ箱じゃなければ
4817                                 addBrowseHistory();
4818                         }
4819                 }
4820         }
4821         
4822         // タブが閉じられた
4823         @SuppressWarnings("unused")
4824         private void tabCloseRequested(int index) {
4825                 tabWindowClosing((TabBrowse)tabBrowser.widget(index));
4826         }
4827
4828         // タブが閉じられた
4829         private void tabWindowClosing(TabBrowse tab) {
4830                 // タブが1つしかなかったら閉じない
4831                 if (tabBrowser.count() <= 1) {
4832                         return;
4833                 }
4834
4835                 int index = tabBrowser.indexOf(tab);
4836 //              String guid = tab.getBrowserWindow().getNote().getGuid();
4837 //              String content = tab.getBrowserWindow().getContent();
4838                 BrowserWindow browser = tab.getBrowserWindow();
4839 //              // ノートが変更されていたら保存
4840 //              if (tab.getNoteDirty()) {
4841 //                      saveNoteTabBrowser(guid, content, true, browser);
4842 //              }
4843
4844                 // シグナル切断
4845                 browser.noteSignal.tagsChanged.disconnect();
4846                 browser.noteSignal.titleChanged.disconnect();
4847                 browser.noteSignal.noteChanged.disconnect();
4848                 browser.noteSignal.notebookChanged.disconnect();
4849                 browser.noteSignal.createdDateChanged.disconnect();
4850                 browser.noteSignal.alteredDateChanged.disconnect();
4851
4852                 // ノートを削除
4853                 tabWindows.remove(index);
4854                 tabBrowser.removeTab(index);
4855                 noteDirty.remove(index);
4856                 inkNote.remove(index);
4857                 readOnly.remove(index);
4858
4859                 // 履歴記録のハッシュマップを削除
4860                 historyGuids.remove(index);
4861                 historyPosition.remove(index);
4862                 fromHistory.remove(index);
4863                 
4864                 // タブのインデックスを更新(削除によって空いた部分を詰める)
4865                 for(int i = index ; tabWindows.containsKey(i + 1) ; i++){
4866                         // tabWindows
4867                         TabBrowse nextTab = tabWindows.get(i + 1);
4868                         tabWindows.put(i, nextTab);
4869                         tabWindows.remove(i + 1);
4870                         // noteDirty
4871                         boolean isNoteDirty = noteDirty.get(i + 1);
4872                         noteDirty.put(i, isNoteDirty);
4873                         noteDirty.remove(i + 1);
4874                         // inkNote
4875                         boolean isInkNote = inkNote.get(i + 1);
4876                         inkNote.put(i, isInkNote);
4877                         inkNote.remove(i + 1);
4878                         // readOnly
4879                         boolean isReadOnly = readOnly.get(i + 1);
4880                         readOnly.put(i, isReadOnly);
4881                         readOnly.remove(i + 1);
4882                         // historyGuids
4883                         ArrayList<String> histGuids = historyGuids.get(i + 1);
4884                         historyGuids.put(i, histGuids);
4885                         historyGuids.remove(i + 1);
4886                         // historyPosition
4887                         int histPosition = historyPosition.get(i + 1);
4888                         historyPosition.put(i, histPosition);
4889                         historyPosition.remove(i + 1);
4890                         // fromHistory
4891                         boolean fromHist = fromHistory.get(i + 1);
4892                         fromHistory.put(i,  fromHist);
4893                         fromHistory.remove(i + 1);
4894                 }
4895                 
4896                 // タブが残り1つになったら、閉じるボタンを消す
4897                 if (tabBrowser.count() == 1) {
4898                         tabBrowser.hideTabCloseButton(0);
4899                 }
4900                 
4901                 // タブの閉じるボタンを押すと、tabWindowClosingより先にtabWindowChangedが呼ばれてしまうので、手動で呼びなおす
4902                 tabWindowChanged(tabBrowser.currentIndex());
4903         }
4904         
4905         @SuppressWarnings("unused")
4906         private void noteAddNewTab() {
4907                 saveNote();
4908                 
4909                 // ノートを何も開いていないときは現在のタブにノート追加
4910                 if (currentNoteGuid == null || currentNoteGuid.equals("")) {
4911                         addNote();
4912                         return;
4913                 }
4914                 
4915                 // ノート追加前に開いていたノートとの関連性を記録するためにguidをとっておく
4916                 TabBrowse prevTab = (TabBrowse)tabBrowser.currentWidget();
4917                 String prevTabGuid = null;
4918                 if (prevTab.getBrowserWindow() != null && prevTab.getBrowserWindow().getNote() != null) {
4919                         prevTabGuid = prevTab.getBrowserWindow().getNote().getGuid();
4920                 }
4921                 
4922                 openEmptyTabEditor();
4923                 addNote();
4924                 
4925                 // 追加されたノートのguidを取得し、ノート追加操作履歴としてデータベースに登録
4926                 if (prevTabGuid != null && !prevTabGuid.equals("")) {
4927                         TabBrowse addedTab = (TabBrowse)tabBrowser.currentWidget();
4928                         String addedTabGuid = addedTab.getBrowserWindow().getNote().getGuid();
4929                         if (addedTabGuid != null && !addedTabGuid.equals("")) {
4930                                 if (!prevTabGuid.equals(addedTabGuid)) {
4931                                         conn.getHistoryTable().addHistory("addNewNote", prevTabGuid, addedTabGuid);
4932                                 }
4933                         }
4934                 }
4935         }
4936         
4937         private void openEmptyTabEditor() {
4938                 // 新しいタブエディタを作成
4939                 TabBrowse newBrowser = new TabBrowse(conn, tabBrowser, cbObserver);
4940                 showEditorButtons(newBrowser.getBrowserWindow());
4941                 
4942                 setupBrowserWindowListeners(newBrowser.getBrowserWindow(), false);
4943                 
4944                 int index = tabBrowser.addNewTab(newBrowser, "");
4945                 tabWindows.put(index, newBrowser);
4946                 noteDirty.put(index, false);
4947                 
4948                 // ExtendedInformationを必要があれば表示する
4949                 toggleNoteInformation();
4950                 // Sourceを必要があれば表示する
4951                 viewSource();
4952                 // EditorButtonsBarを必要があれば表示する
4953                 toggleEditorButtonBar();
4954
4955                 // 履歴記録のハッシュマップを初期化
4956                 ArrayList<String> histGuids = new ArrayList<String>();
4957                 historyGuids.put(index, histGuids);
4958                 historyPosition.put(index, 0);
4959                 fromHistory.put(index, false);
4960
4961                 tabBrowser.setCurrentIndex(index);
4962         }
4963
4964     //***************************************************************
4965     //***************************************************************
4966     //** These functions deal with Note specific things
4967     //***************************************************************
4968     //***************************************************************    
4969         private void setNoteDirty() {
4970                 for (String guid: selectedNoteGUIDs) {
4971                         setNoteDirty(guid);
4972                 }
4973         }
4974         
4975         private void setNoteDirty(String targetGuid) {
4976                 logger.log(logger.EXTREME, "Entering NeverNote.setNoteDirty()");
4977                 
4978                 // Find if the note is being edited externally.  If it is, update it.
4979                 if (externalWindows.containsKey(targetGuid)) {
4980                         QTextCodec codec = QTextCodec.codecForName("UTF-8");
4981                 QByteArray unicode =  codec.fromUnicode(browserWindow.getContent());
4982                         ExternalBrowse window = externalWindows.get(targetGuid);
4983                 window.getBrowserWindow().setContent(unicode);
4984                 }
4985                 
4986                 // 他のタブで同じノートを開いていないか探す。もしあったら、内容を更新する。
4987                 Collection<Integer> tabIndexes = tabWindows.keySet();
4988                 Iterator<Integer>       indexIterator = tabIndexes.iterator();
4989                 
4990                 for (TabBrowse tab: tabWindows.values()) {
4991                         int index = indexIterator.next();
4992                         String guid = tab.getBrowserWindow().getNote().getGuid();
4993                         
4994                         QTextCodec codec = QTextCodec.codecForName("UTF-8");
4995                         QByteArray unicode = codec.fromUnicode(browserWindow.getContent());
4996                         
4997                         if (guid.equals(guid)) {
4998                                 if (index != tabBrowser.currentIndex()) {
4999                                         TabBrowse window = tabWindows.get(index);
5000                                         window.getBrowserWindow().setContent(unicode);
5001                                 }
5002                         }
5003                 }
5004                 
5005                 // ターゲットノートがタブで開かれていて、かつDirty = trueかどうかを取得する
5006                 // If the note is dirty, then it is unsynchronized by default.
5007                 int index = -1;
5008                 boolean isNoteDirty = false;
5009                 for (TabBrowse tab: tabWindows.values()) {
5010                         if (tab.getBrowserWindow().getNote().getGuid().equals(targetGuid)) {
5011                                 index = tabBrowser.indexOf(tab);
5012                                 isNoteDirty = noteDirty.get(index);
5013                                 break;
5014                         }
5015                 }
5016                 if (isNoteDirty) {
5017                         return;
5018                 }
5019                 
5020                 // Set the note as dirty and check if its status is synchronized in the display table
5021                 // まだダーティでなく、かつタブで開かれている場合にnoteDirty = trueにする
5022                 if (index >= 0) {
5023                         noteDirty.put(index, true);
5024                 }
5025
5026                 if (listManager.getNoteMetadata().containsKey(targetGuid) &&
5027                                 listManager.getNoteMetadata().get(targetGuid).isDirty()) {
5028                                 return;
5029                 }
5030                 
5031                 // If this wasn't already marked as unsynchronized, then we need to update the table
5032                 listManager.getNoteTableModel().updateNoteSyncStatus(targetGuid, false);
5033 //      listManager.getUnsynchronizedNotes().add(targetGuid);
5034         for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
5035                 QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
5036                 if (modelIndex != null) {
5037                         SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
5038                         String tableGuid =  (String)ix.values().toArray()[0];
5039                         if (tableGuid.equals(targetGuid)) {
5040                                 listManager.getNoteTableModel().proxyModel.setData(i, Global.noteTableSynchronizedPosition, "false");
5041                                 return;
5042                         }
5043                 }
5044         }
5045         
5046                 logger.log(logger.EXTREME, "Leaving NeverNote.setNoteDirty()");
5047     }
5048     @SuppressWarnings("unused")
5049         private void saveNoteExternalBrowser(String guid, String content, Boolean save, BrowserWindow browser) {
5050                 QTextCodec codec = QTextCodec.codecForName("UTF-8");
5051         QByteArray unicode =  codec.fromUnicode(content);
5052         noteCache.remove(guid);
5053                 noteCache.put(guid, unicode.toString());
5054         if (guid.equals(currentNoteGuid)) {
5055                 int index = tabBrowser.currentIndex();
5056                 noteDirty.put(index, true);
5057                 browserWindow.setContent(unicode);
5058         } 
5059         if (save) {
5060                 thumbnailRunner.addWork("GENERATE "+ guid);
5061                 saveNote(guid, browser);
5062         }
5063         
5064     }
5065     
5066 //      private void saveNoteTabBrowser(String guid, String content, Boolean save,
5067 //                      BrowserWindow browser) {
5068 //              QTextCodec codec = QTextCodec.codecForName("UTF-8");
5069 //              QByteArray unicode = codec.fromUnicode(content);
5070 //              noteCache.remove(guid);
5071 //              noteCache.put(guid, unicode.toString());
5072 //              if (save) {
5073 //                      thumbnailRunner.addWork("GENERATE " + guid);
5074 //                      saveNote(guid, browser);
5075 //              }
5076 //      }
5077         
5078     private void saveNote() {
5079         // すべてのタブに対して、Dirtyを確認し、trueならセーブする
5080         Collection<Integer> dirtyIndex = noteDirty.keySet();
5081         Iterator<Integer> indexIterator = dirtyIndex.iterator();
5082         for (boolean isNoteDirty: noteDirty.values()) {
5083                 int index = indexIterator.next();
5084                 if (isNoteDirty) {
5085                         if (index < 0) {
5086                                 return;
5087                         }
5088                         BrowserWindow b = tabWindows.get(index).getBrowserWindow();
5089                         String guid = b.getNote().getGuid();
5090                         saveNote(guid, b);
5091                         thumbnailRunner.addWork("GENERATE "+ guid);
5092                         noteDirty.put(index, false);
5093                 }
5094         }
5095     }
5096     private void saveNote(String guid, BrowserWindow window) {
5097                 logger.log(logger.EXTREME, "Inside NeverNote.saveNote()");
5098                 waitCursor(true);
5099                 
5100                 logger.log(logger.EXTREME, "Saving to cache");
5101                 QTextCodec codec = QTextCodec.codecForLocale();
5102 //              QTextDecoder decoder = codec.makeDecoder();
5103                 codec = QTextCodec.codecForName("UTF-8");
5104         QByteArray unicode =  codec.fromUnicode(window.getContent());
5105                 noteCache.put(guid, unicode.toString());
5106                         
5107                 logger.log(logger.EXTREME, "updating list manager");
5108                 listManager.updateNoteContent(guid, window.getContent());
5109                 logger.log(logger.EXTREME, "Updating title");
5110                 listManager.updateNoteTitle(guid, window.getTitle());
5111                 updateListDateChanged();
5112
5113                 logger.log(logger.EXTREME, "Looking through note index for refreshed note");
5114                 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
5115                 if (listManager.getNoteIndex().get(i).getGuid().equals(guid)) {
5116                         currentNote = listManager.getNoteIndex().get(i);
5117                         i = listManager.getNoteIndex().size();
5118                 }
5119         }
5120         waitCursor(false);
5121     }
5122     // Get a note from Evernote (and put it in the browser)
5123         private void refreshEvernoteNote(boolean reload) {
5124                 logger.log(logger.HIGH, "Entering NeverNote.refreshEvernoteNote");
5125                 
5126                 if (Global.disableViewing) {
5127                         browserWindow.setEnabled(false);
5128                         return;
5129                 }
5130                 inkNote.put(tabBrowser.currentIndex(), false);
5131                 readOnly.put(tabBrowser.currentIndex(), false);
5132                 
5133                 if (Global.showDeleted || currentNoteGuid == null || currentNoteGuid.equals("")) {
5134                         readOnly.put(tabBrowser.currentIndex(), true);
5135                 }
5136                 Global.cryptCounter =0;
5137                 if (readOnly.get(tabBrowser.currentIndex())) {
5138                         browserWindow.setReadOnly(true);
5139                 }
5140                 
5141                 if (!reload)
5142                         return;
5143                 
5144                 waitCursor(true);
5145                 browserWindow.loadingData(true);
5146
5147                 currentNote = conn.getNoteTable().getNote(currentNoteGuid, true,true,false,false,true);
5148                 if (currentNote == null) {
5149                         waitCursor(false);
5150                         return;
5151                 }
5152                 
5153                 tabBrowser.setTabTitle(tabBrowser.currentIndex(), currentNote.getTitle());
5154                 
5155                 loadNoteBrowserInformation(browserWindow, currentNoteGuid, currentNote);
5156         }
5157
5158         private void loadNoteBrowserInformation(BrowserWindow browser, String guid, Note note) {
5159                 NoteFormatter   formatter = new NoteFormatter(logger, conn, tempFiles);
5160                 formatter.setNote(note, Global.pdfPreview());
5161                 formatter.setHighlight(listManager.getEnSearch());
5162                 QByteArray js;
5163                 int tabIndex = -1;
5164                 
5165                 // 対象のタブインデックスを取得
5166                 for (TabBrowse tab: tabWindows.values()) {
5167                         if (tab.getBrowserWindow() == browser) {
5168                                 tabIndex = tabBrowser.indexOf(tab);
5169                                 break;
5170                         }
5171                 }
5172                 
5173                 if (!noteCache.containsKey(guid)) {
5174                         js = new QByteArray();
5175                         // We need to prepend the note with <HEAD></HEAD> or encoded characters are ugly 
5176                         js.append("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">");               
5177                         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>");
5178                         js.append("<style type=\"text/css\">en-hilight { background-color: rgb(255,255,0) }</style>");
5179                         js.append("<style> img { height:auto; width:auto; max-height:auto; max-width:100%; }</style>");
5180                         if (Global.displayRightToLeft())
5181                                 js.append("<style> body { direction:rtl; }</style>");
5182                         js.append("<style type=\"text/css\">en-spell { text-decoration: none; border-bottom: dotted 1px #cc0000; }</style>");
5183                         js.append("</head>");
5184                         formatter.setNote(note, Global.pdfPreview());
5185                         js.append(formatter.rebuildNoteHTML());
5186                         js.append("</HTML>");
5187                         js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml.dtd'>", "");
5188                         js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml2.dtd'>", "");
5189                         js.replace("<?xml version='1.0' encoding='UTF-8'?>", "");
5190 //              if (Global.enableHTMLEntitiesFix) {
5191 //                      browser.getBrowser().setContent(new QByteArray(StringEscapeUtils.unescapeHtml(js.toString())));
5192 //              } else
5193                         browser.setContent(js);
5194                         noteCache.put(guid, js.toString());
5195
5196                         if (formatter.resourceError)
5197                                 resourceErrorMessage(tabIndex);
5198                         if (formatter.formatError) {
5199                                 waitCursor(false);
5200                              QMessageBox.information(this, tr("Error"),
5201                                                 tr("NeighborNote had issues formatting this note." +
5202                                                 " To protect your data this note is being marked as read-only."));      
5203                              waitCursor(true);
5204                         }
5205                         
5206                         if (tabIndex >= 0) {
5207                                 readOnly.put(tabIndex, formatter.readOnly);
5208                                 inkNote.put(tabIndex, formatter.inkNote);
5209                         } 
5210                         
5211                         if (tabIndex >= 0 && readOnly.get(tabIndex)) {
5212                                 readOnlyCache.put(guid, true);
5213                         }
5214                         if (tabIndex >= 0 && inkNote.get(tabIndex)) {
5215                                 inkNoteCache.put(guid, true);
5216                         }
5217                         
5218                 } else {
5219                         logger.log(logger.HIGH, "Note content is being pulled from the cache");
5220                         String cachedContent = formatter.modifyCachedTodoTags(noteCache.get(guid));
5221                         js = new QByteArray(cachedContent);
5222                         browser.setContent(js);
5223                         if (readOnlyCache.containsKey(guid) && tabIndex >= 0) {
5224                                 readOnly.put(tabIndex, true);
5225                         } else {
5226                                 readOnly.put(tabIndex, false);
5227                         }
5228                         if (inkNoteCache.containsKey(guid) && tabIndex >= 0) {
5229                                 inkNote.put(tabIndex, true);
5230                         } else {
5231                                 inkNote.put(tabIndex, false);
5232                         }
5233                 }
5234                 if (conn.getNoteTable().isThumbnailNeeded(guid)) {
5235                         thumbnailHTMLReady(guid, js, Global.calculateThumbnailZoom(js.toString()));
5236                 }
5237                 if (tabIndex >= 0 && (readOnly.get(tabIndex) || inkNote.get(tabIndex) || 
5238                                 (note.getAttributes() != null && note.getAttributes().getContentClass() != null && note.getAttributes().getContentClass() != "")))
5239                         browser.getBrowser().page().setContentEditable(false);  // We don't allow editing of ink notes
5240                 else
5241                         browser.getBrowser().page().setContentEditable(true);
5242                 if (tabIndex >= 0) {
5243                         browser.setReadOnly(readOnly.get(tabIndex));
5244                         deleteButton.setEnabled(!readOnly.get(tabIndex));
5245                         tagButton.setEnabled(!readOnly.get(tabIndex));
5246                         menuBar.noteDelete.setEnabled(!readOnly.get(tabIndex));
5247                         menuBar.noteTags.setEnabled(!readOnly.get(tabIndex));
5248                 }
5249                 browser.setNote(note);
5250                 
5251                 if (note != null && note.getNotebookGuid() != null && 
5252                                 conn.getNotebookTable().isLinked(note.getNotebookGuid())) {
5253                         deleteButton.setEnabled(false);
5254                         menuBar.notebookDeleteAction.setEnabled(false);
5255                 } else {
5256                         deleteButton.setEnabled(true);
5257                         menuBar.notebookDeleteAction.setEnabled(true);
5258                 }
5259                 
5260                 // Build a list of non-closed notebooks
5261                 List<Notebook> nbooks = new ArrayList<Notebook>();
5262                 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
5263                         boolean found=false;
5264                         for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
5265                                 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid())) 
5266                                         found = true;
5267                         }
5268                         if (!found)
5269                                 nbooks.add(listManager.getNotebookIndex().get(i));
5270                 }
5271                 
5272                 browser.setTitle(note.getTitle());
5273                 browser.setTag(getTagNamesForNote(note));
5274                 browser.setAuthor(note.getAttributes().getAuthor());
5275
5276                 browser.setAltered(note.getUpdated());
5277                 browser.setCreation(note.getCreated());
5278                 if (note.getAttributes().getSubjectDate() > 0)
5279                         browser.setSubjectDate(note.getAttributes().getSubjectDate());
5280                 else
5281                         browser.setSubjectDate(note.getCreated());
5282                 browser.setUrl(note.getAttributes().getSourceURL());
5283                 
5284                 FilterEditorTags tagFilter = new FilterEditorTags(conn, logger);
5285                 List<Tag> tagList = tagFilter.getValidTags(note);
5286                 browser.setAllTags(tagList);
5287                 
5288                 browser.setCurrentTags(note.getTagNames());
5289                 for (TabBrowse tab: tabWindows.values()) {
5290                         if (tab.getBrowserWindow().getNote().getGuid().equals(guid)) {
5291                                 int index = tabBrowser.indexOf(tab);
5292                                 noteDirty.put(index, false);
5293                                 break;
5294                         }
5295                 }
5296                 
5297                 scrollToGuid(guid);
5298                 
5299                 browser.loadingData(false);
5300                 if (thumbnailViewer.isActiveWindow())
5301                         thumbnailView();
5302                 
5303                 FilterEditorNotebooks notebookFilter = new FilterEditorNotebooks(conn, logger);
5304                 browser.setNotebookList(notebookFilter.getValidNotebooks(note, listManager.getNotebookIndex()));
5305
5306                 waitCursor(false);
5307                 logger.log(logger.HIGH, "Leaving NeverNote.refreshEvernoteNote");
5308         }
5309         
5310         @SuppressWarnings("unused")
5311         private void toggleNoteAttributes() {
5312                 menuBar.noteAttributes.setChecked(!menuBar.noteAttributes.isChecked());
5313                 toggleNoteInformation();
5314         }
5315         
5316         // Save a generated thumbnail
5317         private void toggleNoteInformation() {
5318                 logger.log(logger.HIGH, "Entering NeverNote.toggleNoteInformation");
5319         
5320                 boolean isChecked = menuBar.noteAttributes.isChecked();
5321                 
5322         for(int i = 0; i < tabBrowser.count(); i++){
5323                 BrowserWindow browser = ((TabBrowse) tabBrowser.widget(i)).getBrowserWindow();
5324                 boolean isExtended = browser.isExtended();
5325                 if((isChecked && !isExtended) || (!isChecked && isExtended)){
5326                         browser.toggleInformation();
5327                 }
5328         }
5329         
5330         menuBar.noteAttributes.setChecked(browserWindow.isExtended());
5331         Global.saveWindowVisible("noteInformation", browserWindow.isExtended());
5332         logger.log(logger.HIGH, "Leaving NeverNote.toggleNoteInformation");
5333     }
5334         
5335         // Listener triggered when a print button is pressed
5336     @SuppressWarnings("unused")
5337         private void printNote() {
5338                 logger.log(logger.HIGH, "Entering NeverNote.printNote");
5339
5340         QPrintDialog dialog = new QPrintDialog();
5341         if (dialog.exec() == QDialog.DialogCode.Accepted.value()) {
5342                 QPrinter printer = dialog.printer();
5343                 browserWindow.getBrowser().print(printer);
5344         }
5345                 logger.log(logger.HIGH, "Leaving NeverNote.printNote");
5346
5347     }
5348     // Listener triggered when the email button is pressed
5349     @SuppressWarnings("unused")
5350         private void emailNote() {
5351         logger.log(logger.HIGH, "Entering NeverNote.emailNote");
5352         
5353         if (Desktop.isDesktopSupported()) {
5354             Desktop desktop = Desktop.getDesktop();
5355             
5356             String text2 = browserWindow.getContentsToEmail();
5357             QUrl url = new QUrl("mailto:");
5358             url.addQueryItem("subject", currentNote.getTitle());
5359 //            url.addQueryItem("body", QUrl.toPercentEncoding(text2).toString());
5360             url.addQueryItem("body", text2);
5361             QDesktopServices.openUrl(url);
5362         }
5363 /*            
5364             
5365             if (desktop.isSupported(Desktop.Action.MAIL)) {
5366                 URI uriMailTo = null;
5367                 try {
5368                         //String text = browserWindow.getBrowser().page().currentFrame().toPlainText();
5369                         String text = browserWindow.getContentsToEmail();
5370                         //text = "<b>" +text +"</b>";
5371                                         uriMailTo = new URI("mailto", "&SUBJECT="+currentNote.getTitle()
5372                                                         +"&BODY=" +text, null);
5373                                         uriMailTo = new URI("mailto", "&SUBJECT="+currentNote.getTitle()
5374                                                         +"&ATTACHMENT=d:/test.pdf", null);
5375                                         desktop.mail(uriMailTo);
5376                                 } catch (URISyntaxException e) {
5377                                         e.printStackTrace();
5378                                 } catch (IOException e) {
5379                                         e.printStackTrace();
5380                                 }
5381
5382             }
5383
5384         }     
5385  */     
5386         logger.log(logger.HIGH, "Leaving NeverNote.emailNote");
5387     }
5388         // Reindex all notes
5389     @SuppressWarnings("unused")
5390         private void fullReindex() {
5391         logger.log(logger.HIGH, "Entering NeverNote.fullReindex");
5392         indexRunner.addWork("REINDEXALL");
5393         setMessage(tr("Database will be reindexed."));
5394         logger.log(logger.HIGH, "Leaving NeverNote.fullReindex");
5395     }
5396     // Listener when a user wants to reindex a specific note
5397     @SuppressWarnings("unused")
5398         private void reindexNote() {
5399         logger.log(logger.HIGH, "Entering NeverNote.reindexNote");
5400                 for (int i=0; i<selectedNoteGUIDs.size(); i++) {
5401                         indexRunner.addWork("REINDEXNOTE "+selectedNoteGUIDs.get(i));
5402                 }
5403                 if (selectedNotebookGUIDs.size() > 1)
5404                         setMessage(tr("Notes will be reindexed."));
5405                 else
5406                         setMessage(tr("Note will be reindexed."));
5407         logger.log(logger.HIGH, "Leaving NeverNote.reindexNote");
5408     }
5409     // Delete the note
5410     @SuppressWarnings("unused")
5411         private void deleteNote() {
5412         logger.log(logger.HIGH, "Entering NeverNote.deleteNote");
5413         if (currentNote == null) 
5414                 return;
5415         if (currentNoteGuid.equals(""))
5416                 return;
5417         
5418         String title = null;
5419         if (selectedNoteGUIDs.size() == 1)
5420                 title = conn.getNoteTable().getNote(selectedNoteGUIDs.get(0),false,false,false,false,false).getTitle();
5421
5422         // If we are deleting non-trash notes
5423         if (currentNote.isActive()) { 
5424                 if (Global.verifyDelete()) {
5425                         String msg;
5426                         if (selectedNoteGUIDs.size() > 1) {
5427                                 msg = new String(tr("Delete ") +selectedNoteGUIDs.size() +" notes?");
5428                         } else {
5429                                 if (title != null)
5430                                         msg = new String(tr("Delete note \"") +title +"\"?");
5431                                 else                            
5432                                         msg = new String(tr("Delete note selected note?"));
5433                         }
5434                         if (QMessageBox.question(this, tr("Confirmation"), msg,
5435                                         QMessageBox.StandardButton.Yes, 
5436                                         QMessageBox.StandardButton.No)==StandardButton.No.value() && Global.verifyDelete() == true) {
5437                                         return;
5438                         }
5439                 }
5440                 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals("")) {
5441                         selectedNoteGUIDs.add(currentNoteGuid);
5442                 }
5443                 
5444                 List<String> deleteNoteGUIDs = new ArrayList<String>(selectedNoteGUIDs);        // タブを閉じるとselectedNoteGUIDsが変わってしまうのでその前にコピー
5445                 closeTabs(selectedNoteGUIDs);
5446                 for (String guid : deleteNoteGUIDs) {
5447                         listManager.deleteNote(guid);
5448                 }
5449                 
5450                 closeExternalWindows(deleteNoteGUIDs);
5451         } else { 
5452                 // If we are deleting from the trash.
5453                 if (Global.verifyDelete()) {
5454                         String msg;
5455                         if (selectedNoteGUIDs.size() > 1) {
5456                                 msg = new String(tr("Permanently delete ") +selectedNoteGUIDs.size() +" notes?");
5457                         } else {
5458                                 if (title != null)
5459                                 msg = new String(tr("Permanently delete note \"") +title +"\"?");
5460                                 else
5461                                         msg = new String(tr("Permanently delete note selected note?"));
5462                         }
5463                         if (QMessageBox.question(this, "Confirmation", msg,
5464                                 QMessageBox.StandardButton.Yes, 
5465                                         QMessageBox.StandardButton.No)==StandardButton.No.value()) {                                            
5466                                         return;
5467                         }
5468                 }
5469                 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals("")) 
5470                         selectedNoteGUIDs.add(currentNoteGuid);
5471                 
5472                 List<String> deleteNoteGUIDs = new ArrayList<String>(selectedNoteGUIDs);        // タブを閉じるとselectedNoteGUIDsが変わってしまうのでその前にコピー
5473                 for (int i=deleteNoteGUIDs.size()-1; i>=0; i--) {
5474                         for (int j=listManager.getNoteTableModel().rowCount()-1; j>=0; j--) {
5475                         QModelIndex modelIndex =  listManager.getNoteTableModel().index(j, Global.noteTableGuidPosition);
5476                         if (modelIndex != null) {
5477                                 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
5478                                 String tableGuid =  (String)ix.values().toArray()[0];
5479                                 if (tableGuid.equals(deleteNoteGUIDs.get(i))) {
5480                                         listManager.getNoteTableModel().removeRow(j);
5481                                         j=-1;
5482                                 }
5483                         }
5484                 }
5485                         closeTab(deleteNoteGUIDs.get(i));
5486                         listManager.expungeNote(deleteNoteGUIDs.get(i));
5487                         
5488                         conn.getHistoryTable().expungeHistory(deleteNoteGUIDs.get(i));
5489                         conn.getExcludedTable().expungeExcludedNote(deleteNoteGUIDs.get(i));
5490                         conn.getStaredTable().expungeStaredNote(deleteNoteGUIDs.get(i));
5491                 }
5492                 
5493                 closeExternalWindows(deleteNoteGUIDs);
5494         }
5495         
5496                 if (currentNoteGuid == null || currentNoteGuid.equals("")) {
5497                         menuBar.noteAddNewTab.setEnabled(false);
5498                 }
5499                 
5500         listManager.loadNotesIndex();
5501         noteIndexUpdated(false);
5502         refreshEvernoteNote(true);
5503         scrollToGuid(currentNoteGuid);
5504         logger.log(logger.HIGH, "Leaving NeverNote.deleteNote");
5505     }
5506     
5507     // 対象ノートをタブで開いていたら閉じる
5508     private void closeTabs(List<String> noteGUIDs) {
5509         for (String guid : noteGUIDs) {
5510                 closeTab(guid);
5511         }
5512     }
5513     
5514     // 対象ノートをタブで開いていたら閉じる
5515     private void closeTab(String noteGUID) {
5516         List<TabBrowse> closeTabs = new ArrayList<TabBrowse>();
5517         
5518         for (TabBrowse tab : tabWindows.values()) {
5519                 String guid = tab.getBrowserWindow().getNote().getGuid();
5520                 
5521                 if (guid.equals(noteGUID)) {
5522                         closeTabs.add(tab);
5523                 }
5524         }
5525         
5526         for (TabBrowse tab : closeTabs) {
5527                 tabWindowClosing(tab);
5528         }
5529     }
5530     
5531     // 対象ノートを外部ウィンドウで開いていたら閉じる
5532     private void closeExternalWindows(List<String> noteGUIDs) {
5533                 List<ExternalBrowse> closeWindows = new ArrayList<ExternalBrowse>();
5534                 
5535                 for (Map.Entry<String, ExternalBrowse> e : externalWindows.entrySet()) {
5536                         for (String guid : noteGUIDs) {
5537                                 if (guid.equals(e.getKey())) {
5538                                         closeWindows.add(e.getValue());
5539                                 }
5540                         }
5541                 }
5542                 
5543                 for (ExternalBrowse externalBrowse : closeWindows) {
5544                         externalBrowse.close();
5545                 }
5546     }
5547     
5548     // Add a new note
5549         private void addNote() {
5550         logger.log(logger.HIGH, "Inside NeverNote.addNote");
5551 //      browserWindow.setEnabled(true);
5552         browserWindow.setReadOnly(false);
5553         saveNote();
5554         Calendar currentTime = new GregorianCalendar();
5555         StringBuffer noteString = new StringBuffer(100);
5556         noteString.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
5557                 "<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">\n" +
5558                 "<en-note>\n");
5559         
5560         if (Global.overrideDefaultFont()) {
5561                 noteString.append("<font face=\"" +Global.getDefaultFont() +"\" >");
5562                 noteString.append("<span style=\"font-size:" +Global.getDefaultFontSize() +"pt;\">");
5563                 noteString.append("<br clear=\"none\" />\n");
5564                 noteString.append("</span>\n</font>\n");
5565         } else
5566                 noteString.append("<br clear=\"none\" />\n");
5567         noteString.append("</en-note>");
5568         
5569         Long l = new Long(currentTime.getTimeInMillis());
5570         String randint = new String(Long.toString(l));          
5571         
5572         // Find a notebook.  We first look for a selected notebook (the "All Notebooks" one doesn't count).  
5573         // Then we look
5574         // for the first non-archived notebook.  Finally, if nothing else we 
5575         // pick the first notebook in the list.
5576         String notebook = null;
5577         listManager.getNotebookIndex().get(0).getGuid();
5578         List<QTreeWidgetItem> selectedNotebook = notebookTree.selectedItems();
5579         if (selectedNotebook.size() > 0 && !selectedNotebook.get(0).text(0).equalsIgnoreCase("All Notebooks") && !selectedNotebook.get(0).text(2).equalsIgnoreCase("STACK")) {
5580                 QTreeWidgetItem currentSelectedNotebook = selectedNotebook.get(0);
5581                 notebook = currentSelectedNotebook.text(2);
5582         } else {
5583                 boolean found = false;
5584                 List<Notebook> goodNotebooks = new ArrayList<Notebook>();
5585                 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
5586                         boolean match = false;
5587                         for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
5588                                 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid())) {
5589                                         match = true;
5590                                         j = listManager.getArchiveNotebookIndex().size();
5591                                 }
5592                         }
5593                         if (!match)
5594                                 //goodNotebooks.add(listManager.getNotebookIndex().get(i).deepCopy());
5595                                 goodNotebooks.add((Notebook)Global.deepCopy(listManager.getNotebookIndex().get(i)));
5596                 }
5597                 // Now we have a list of good notebooks, so we can look for the default
5598                 found = false;
5599                 for (int i=0; i<goodNotebooks.size(); i++) {
5600                         if (goodNotebooks.get(i).isDefaultNotebook()) {
5601                                 notebook = goodNotebooks.get(i).getGuid();
5602                                 found = true;
5603                                 i = goodNotebooks.size();
5604                         }
5605                 }
5606                 
5607                 if (goodNotebooks.size() > 0 && !found)
5608                         notebook = goodNotebooks.get(0).getGuid();
5609      
5610                 if (notebook==null)
5611                         notebook = listManager.getNotebookIndex().get(0).getGuid();             
5612         }
5613         
5614         Note newNote = new Note();
5615         newNote.setUpdateSequenceNum(0);
5616         newNote.setGuid(randint);
5617         newNote.setNotebookGuid(notebook);
5618         newNote.setTitle("Untitled Note");
5619         newNote.setContent(noteString.toString());
5620         newNote.setDeleted(0);
5621         newNote.setCreated(System.currentTimeMillis());
5622         newNote.setUpdated(System.currentTimeMillis());
5623         newNote.setActive(true);
5624         NoteAttributes na = new NoteAttributes();
5625         na.setLatitude(0.0);
5626         na.setLongitude(0.0);
5627         na.setAltitude(0.0);
5628         newNote.setAttributes(new NoteAttributes());
5629                 newNote.setTagGuids(new ArrayList<String>());
5630                 newNote.setTagNames(new ArrayList<String>());
5631         
5632         // If new notes are to be created based upon the selected tags, then we need to assign the tags
5633         if (Global.newNoteWithSelectedTags()) { 
5634                 List<QTreeWidgetItem> selections = tagTree.selectedItems();
5635                 QTreeWidgetItem currentSelection;
5636                 for (int i=0; i<selections.size(); i++) {
5637                         currentSelection = selections.get(i);
5638                         newNote.getTagGuids().add(currentSelection.text(2));
5639                         newNote.getTagNames().add(currentSelection.text(0));
5640                 }
5641         }
5642         
5643         conn.getNoteTable().addNote(newNote, true);
5644         NoteMetadata metadata = new NoteMetadata();
5645         metadata.setGuid(newNote.getGuid());
5646         metadata.setDirty(true);
5647         listManager.addNote(newNote, metadata);
5648 //      noteTableView.insertRow(newNote, true, -1);
5649         
5650         String prevCurrentNoteGuid = new String(currentNoteGuid);
5651         
5652         currentNote = newNote;
5653         currentNoteGuid = currentNote.getGuid();
5654         // IFIXED こいつのせいで、ノート追加時にcurrentNoteGuidが更新されないので消す
5655         // noteTableView.clearSelection();
5656         
5657         // 新規に作成したノートとそれまで開いていたノートの関連性を追加
5658         if (prevCurrentNoteGuid != null && !prevCurrentNoteGuid.equals("")) {
5659                 if (currentNoteGuid != null && !currentNoteGuid.equals("")) {
5660                         conn.getHistoryTable().addHistory("addNewNote", prevCurrentNoteGuid, currentNoteGuid);
5661                 }
5662         }
5663         
5664         refreshEvernoteNote(true);
5665         listManager.countNotebookResults(listManager.getNoteIndex());
5666         browserWindow.titleLabel.setFocus();
5667         browserWindow.titleLabel.selectAll();
5668 //      notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
5669         
5670         // If the window is hidden, then we want to popup this in an external window & 
5671         if (!isVisible())
5672                 listDoubleClick();
5673         waitCursor(false);
5674         logger.log(logger.HIGH, "Leaving NeverNote.addNote");
5675     }
5676     // Restore a note from the trash;
5677     @SuppressWarnings("unused")
5678         private void restoreNote() {
5679         waitCursor(true);
5680                 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals("")) 
5681                         selectedNoteGUIDs.add(currentNoteGuid);
5682                 for (int i=0; i<selectedNoteGUIDs.size(); i++) {
5683                         listManager.restoreNote(selectedNoteGUIDs.get(i));
5684                 }
5685         currentNoteGuid = "";
5686         listManager.loadNotesIndex();
5687         noteIndexUpdated(false);
5688         waitCursor(false);
5689     }
5690     // Search a note for specific txt
5691     @SuppressWarnings("unused")
5692         private void findText() {
5693         find.show();
5694         find.setFocusOnTextField();
5695     }
5696     @SuppressWarnings("unused")
5697         private void doFindText() {
5698         browserWindow.getBrowser().page().findText(find.getText(), find.getFlags());
5699         find.setFocus();
5700     }
5701     @SuppressWarnings("unused")
5702         private void updateNoteTitle(String guid, String title) {
5703         listManager.setNoteSynchronized(guid, false);
5704         
5705         // We do this manually because if we've edited the note in an 
5706         // external window we run into the possibility of signal recursion
5707         // looping.
5708         if (guid.equals(currentNoteGuid)) {
5709                 browserWindow.titleLabel.blockSignals(true);
5710                 browserWindow.titleLabel.setText(title);
5711                 browserWindow.titleLabel.blockSignals(false);
5712         }
5713     }
5714     // Signal received that note content has changed.  Normally we just need the guid to remove
5715     // it from the cache.
5716     @SuppressWarnings("unused")
5717         private void invalidateNoteCache(String guid, String content) {
5718         noteCache.remove(guid);
5719                 refreshEvernoteNote(true);
5720     }
5721     // Signal received that a note guid has changed
5722     @SuppressWarnings("unused")
5723         private void noteGuidChanged(String oldGuid, String newGuid) {
5724         if (noteCache.containsKey(oldGuid)) {
5725                 if (!oldGuid.equals(currentNoteGuid)) {
5726                         String cache = noteCache.get(oldGuid);
5727                         noteCache.put(newGuid, cache);
5728                         noteCache.remove(oldGuid);
5729                 } else {
5730                         noteCache.remove(oldGuid);
5731                         noteCache.put(newGuid, browserWindow.getContent());
5732                 }
5733         }
5734   
5735         listManager.updateNoteGuid(oldGuid, newGuid, false);
5736         if (currentNoteGuid.equals(oldGuid)) {
5737                 if (currentNote != null)
5738                         currentNote.setGuid(newGuid);
5739                 currentNoteGuid = newGuid;
5740         }
5741                 
5742         if (externalWindows.containsKey(oldGuid)) {
5743                         ExternalBrowse b = externalWindows.get(oldGuid);
5744                         externalWindows.remove(oldGuid);
5745                         b.getBrowserWindow().getNote().setGuid(newGuid);
5746                         externalWindows.put(newGuid, b);
5747                 }
5748         
5749                 for(int i = 0; i < tabBrowser.count(); i++){
5750                         TabBrowse b = (TabBrowse)tabBrowser.widget(i);
5751                         if (b.getBrowserWindow().getNote().getGuid().equals(oldGuid)) {
5752                                 b.getBrowserWindow().getNote().setGuid(newGuid);
5753                         }
5754                 }
5755
5756         for (int i=0; i<listManager.getNoteIndex().size(); i++) {
5757                 if (listManager.getNoteIndex().get(i).getGuid().equals(newGuid)) {
5758                         noteTableView.proxyModel.addGuid(newGuid, listManager.getNoteMetadata().get(newGuid));
5759                         i=listManager.getNoteIndex().size();
5760                 }
5761         }
5762         
5763         if (listManager.getNoteTableModel().metaData.containsKey(oldGuid)) {
5764                 NoteMetadata meta = listManager.getNoteTableModel().metaData.get(oldGuid);
5765                 listManager.getNoteTableModel().metaData.put(newGuid, meta);
5766                 listManager.getNoteTableModel().metaData.remove(oldGuid);
5767         }
5768         
5769     }
5770         
5771     // Toggle the note editor button bar
5772     // すべてのタブに
5773     private void toggleEditorButtonBar() {
5774         boolean isChecked = menuBar.showEditorBar.isChecked();
5775         
5776         for(int i = 0; i < tabBrowser.count(); i++){
5777                 BrowserWindow browser = ((TabBrowse) tabBrowser.widget(i)).getBrowserWindow();
5778                 boolean isVisible = browser.buttonsVisible;
5779
5780                 if (isChecked && !isVisible) {
5781                         browser.buttonsVisible = true;
5782                         showEditorButtons(browser);
5783                 } else if(!isChecked && isVisible) {
5784                         browser.hideButtons();
5785                 }
5786         }
5787
5788         Global.saveWindowVisible("editorButtonBar", browserWindow.buttonsVisible);
5789     }
5790     
5791     // Show editor buttons
5792     private void showEditorButtons(BrowserWindow browser) {
5793                 browser.buttonLayout.setVisible(true);
5794                 browser.undoAction.setVisible(false);
5795                 
5796                 browser.undoButton.setVisible(false);
5797
5798                 browser.undoAction.setVisible(Global.isEditorButtonVisible("undo"));
5799                 browser.redoAction.setVisible(Global.isEditorButtonVisible("redo"));
5800                 browser.cutAction.setVisible(Global.isEditorButtonVisible("cut"));
5801                 browser.copyAction.setVisible(Global.isEditorButtonVisible("copy"));
5802                 browser.pasteAction.setVisible(Global.isEditorButtonVisible("paste"));
5803                 browser.strikethroughAction.setVisible(Global.isEditorButtonVisible("strikethrough"));
5804                 browser.underlineAction.setVisible(Global.isEditorButtonVisible("underline"));
5805                 browser.boldAction.setVisible(Global.isEditorButtonVisible("bold"));
5806                 browser.italicAction.setVisible(Global.isEditorButtonVisible("italic"));
5807                 browser.hlineAction.setVisible(Global.isEditorButtonVisible("hline"));
5808                 browser.indentAction.setVisible(Global.isEditorButtonVisible("indent"));
5809                 browser.outdentAction.setVisible(Global.isEditorButtonVisible("outdent"));
5810                 browser.bulletListAction.setVisible(Global.isEditorButtonVisible("bulletList"));
5811                 browser.numberListAction.setVisible(Global.isEditorButtonVisible("numberList"));
5812                 browser.fontListAction.setVisible(Global.isEditorButtonVisible("font"));
5813                 browser.fontSizeAction.setVisible(Global.isEditorButtonVisible("fontSize"));
5814                 browser.fontColorAction.setVisible(Global.isEditorButtonVisible("fontColor"));
5815                 browser.fontHilightAction.setVisible(Global.isEditorButtonVisible("fontHilight"));
5816                 browser.leftAlignAction.setVisible(Global.isEditorButtonVisible("alignLeft"));
5817                 browser.centerAlignAction.setVisible(Global.isEditorButtonVisible("alignCenter"));
5818                 browser.rightAlignAction.setVisible(Global.isEditorButtonVisible("alignRight"));
5819                 browser.spellCheckAction.setVisible(Global.isEditorButtonVisible("spellCheck"));
5820                 browser.todoAction.setVisible(Global.isEditorButtonVisible("todo"));
5821     }
5822     private void duplicateNote(String guid) {
5823                 
5824                 Note oldNote = conn.getNoteTable().getNote(guid, true, false,false,false,true);
5825                 List<Resource> resList = conn.getNoteTable().noteResourceTable.getNoteResources(guid, true);
5826                 oldNote.setContent(conn.getNoteTable().getNoteContentNoUTFConversion(guid));
5827                 oldNote.setResources(resList);
5828                 duplicateNote(oldNote);
5829         }
5830         private void duplicateNote(Note oldNote) {
5831                 waitCursor(true);
5832                 // Now that we have a good notebook guid, we need to move the conflicting note
5833                 // to the local notebook
5834                 Calendar currentTime = new GregorianCalendar();
5835                 Long l = new Long(currentTime.getTimeInMillis());
5836                 String newGuid = new String(Long.toString(l));
5837                                         
5838 //              Note newNote = oldNote.deepCopy();
5839                 Note newNote = (Note)Global.deepCopy(oldNote);
5840                 newNote.setUpdateSequenceNum(0);
5841                 newNote.setGuid(newGuid);
5842                 newNote.setDeleted(0);
5843                 newNote.setActive(true);
5844                 
5845                 /*
5846                 List<String> tagNames = new ArrayList<String>();
5847                 List<String> tagGuids = new ArrayList<String>();;
5848                 for (int i=0; i<oldNote.getTagGuidsSize(); i++) {
5849                         tagNames.add(oldNote.getTagNames().get(i));
5850                         tagGuids.add(oldNote.getTagGuids().get(i));
5851                 }
5852
5853                 // Sort note Tags to make them look nice
5854                 for (int i=0; i<tagNames.size()-1; i++) {
5855                         if (tagNames.get(i).compareTo(tagNames.get(i+1))<0) {
5856                                 String n1 = tagNames.get(i);
5857                                 String n2 = tagNames.get(i+1);
5858                                 tagNames.set(i, n2);
5859                                 tagNames.set(i+1, n1);
5860                         }
5861                 }
5862                 newNote.setTagGuids(tagGuids);
5863                 newNote.setTagNames(tagNames);
5864                 
5865                 // Add tag guids to note
5866                 */
5867                 
5868                 // Duplicate resources
5869                 List<Resource> resList = oldNote.getResources();
5870                 if (resList == null)
5871                         resList = new ArrayList<Resource>();
5872                 long prevGuid = 0;
5873                 for (int i=0; i<resList.size(); i++) {
5874                         l = prevGuid;
5875                         while (l == prevGuid) {
5876                                 currentTime = new GregorianCalendar();
5877                                 l = new Long(currentTime.getTimeInMillis());
5878                         }
5879                         prevGuid = l;
5880                         String newResGuid = new String(Long.toString(l));
5881                         resList.get(i).setNoteGuid(newGuid);
5882                         resList.get(i).setGuid(newResGuid);
5883                         resList.get(i).setUpdateSequenceNum(0);
5884                         resList.get(i).setActive(true);
5885                         conn.getNoteTable().noteResourceTable.saveNoteResource(
5886                                         (Resource)Global.deepCopy(resList.get(i)), true);
5887                 }
5888                 newNote.setResources(resList);
5889                 
5890                 // 操作履歴と除外ノートとスター付きノートも複製する
5891                 if(Global.getDuplicateRensoNote()) {
5892                         conn.getHistoryTable().duplicateHistory(newGuid, oldNote.getGuid());
5893                         conn.getExcludedTable().duplicateExcludedNotes(newGuid, oldNote.getGuid());
5894                         conn.getStaredTable().duplicateStaredNotes(newGuid, oldNote.getGuid());
5895                 }
5896                 
5897                 // Add note to the database
5898                 conn.getNoteTable().addNote(newNote, true);
5899                 NoteMetadata metaData = new NoteMetadata();
5900                 NoteMetadata oldMeta = listManager.getNoteMetadata().get(oldNote.getGuid());
5901                 metaData.copy(oldMeta);
5902                 metaData.setGuid(newNote.getGuid());
5903                 listManager.addNote(newNote, metaData);
5904                 noteTableView.insertRow(newNote, metaData, true, -1);
5905                 currentNoteGuid = newNote.getGuid();
5906                 currentNote = newNote;
5907                 refreshEvernoteNote(true);
5908                 listManager.countNotebookResults(listManager.getNoteIndex());
5909                 waitCursor(false);
5910                 
5911         }
5912         // View all notes
5913         @SuppressWarnings("unused")
5914         private void allNotes() {
5915                 clearAttributeFilter();
5916                 clearNotebookFilter();
5917                 clearSavedSearchFilter();
5918                 clearTrashFilter();
5919                 clearTagFilter();
5920                 searchField.clear();
5921                 if (Global.mimicEvernoteInterface) {
5922                         notebookTree.selectGuid("");
5923                 }
5924                 notebookTreeSelection();
5925                 refreshEvernoteNote(true);
5926                 
5927                 // ゴミ箱から元の画面に戻す。連想ノートリストをONに。
5928                 if (!rensoNoteListDock.isEnabled()) {
5929                         rensoNoteListDock.setEnabled(true);
5930                 }
5931         }
5932         // Merge notes
5933         @SuppressWarnings("unused")
5934         private void mergeNotes() {
5935                 logger.log(logger.HIGH, "Merging notes");
5936                 waitCursor(true);
5937                 saveNote();
5938                 String masterGuid = null;
5939                 List<String> sources = new ArrayList<String>();
5940                 QModelIndex index;
5941                 for (int i=0; i<noteTableView.selectionModel().selectedRows().size(); i++) {
5942                         int r = noteTableView.selectionModel().selectedRows().get(i).row();
5943                         index = noteTableView.proxyModel.index(r, Global.noteTableGuidPosition);
5944                         SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
5945                 if (i == 0) 
5946                         masterGuid = (String)ix.values().toArray()[0];
5947                 else 
5948                         sources.add((String)ix.values().toArray()[0]);  
5949                 }
5950                 
5951                 logger.log(logger.EXTREME, "Master guid=" +masterGuid);
5952                 logger.log(logger.EXTREME, "Children count: "+sources.size());
5953                 mergeNoteContents(masterGuid, sources);
5954                 currentNoteGuid = masterGuid;
5955                 
5956                 // 操作履歴と除外ノートとスター付きノートをマージ
5957                 if(Global.getMergeRensoNote()) {
5958                         for (int i = 0; i < sources.size(); i++) {
5959                                 String childGuid = sources.get(i);
5960                                 if(masterGuid != null && childGuid != null) {
5961                                         if(!masterGuid.equals(childGuid)) {
5962                                                 conn.getHistoryTable().mergeHistoryGuid(masterGuid, childGuid);
5963                                                 conn.getExcludedTable().mergeHistoryGuid(masterGuid, childGuid);
5964                                                 conn.getStaredTable().mergeHistoryGuid(masterGuid, childGuid);
5965                                         }
5966                                 }
5967                         }
5968                 }
5969                 
5970                 // マージしたノート(child)を外部ウィンドウで開いていたら、閉じる
5971                 Collection<ExternalBrowse>      windows = externalWindows.values();
5972                 Iterator<ExternalBrowse>        windowIterator = windows.iterator();
5973                 Collection<String>                      guids = externalWindows.keySet();
5974                 Iterator<String>                        guidIterator = guids.iterator();
5975                 List<ExternalBrowse>            closeWindows = new ArrayList<ExternalBrowse>();
5976                 
5977                 while (windowIterator.hasNext()) {
5978                         ExternalBrowse browser = windowIterator.next();
5979                         String guid = guidIterator.next();
5980                         
5981                         for (int i = 0; i < sources.size(); i++) {
5982                                 if (guid.equals(sources.get(i))) {
5983                                         closeWindows.add(browser);
5984                                 }
5985                         }
5986                 }
5987                 
5988                 for (int i = closeWindows.size() - 1; i >= 0; i--) {
5989                         closeWindows.get(i).close();
5990                 }
5991                 
5992         // マージしたノート(child)をタブで開いていたら、閉じる
5993                 List<TabBrowse> closeTabs = new ArrayList<TabBrowse>();
5994                 for (TabBrowse tab : tabWindows.values()) {
5995                         String guid = tab.getBrowserWindow().getNote().getGuid();
5996                         
5997                         for (String source : sources) {
5998                                 if (guid.equals(source)) {
5999                                         closeTabs.add(tab);
6000                                 }
6001                         }
6002                 }
6003                 for (TabBrowse tab : closeTabs) {
6004                         tabWindowClosing(tab);
6005                 }
6006                 
6007                 noteIndexUpdated(false);
6008                 // IFIXED 
6009                 // マージ後の新しいノートコンテンツを表示するためキャッシュを削除
6010                 noteCache.remove(masterGuid);
6011                 
6012                 refreshEvernoteNote(true);
6013                 waitCursor(false);
6014         }
6015         private void mergeNoteContents(String targetGuid, List<String> sources) {
6016                 Note target = conn.getNoteTable().getNote(targetGuid, true, false, false, false, false);
6017                 String newContent = target.getContent();
6018                 newContent = newContent.replace("</en-note>", "<br></br>");
6019                 
6020                 for (int i=0; i<sources.size(); i++) {
6021                         Note source = conn.getNoteTable().getNote(sources.get(i), true, true, false, false, false);
6022                         if (source.isSetTitle()) {
6023                                 newContent = newContent +("<table bgcolor=\"lightgrey\"><tr><td><font size=\"6\"><b>" +source.getTitle() +"</b></font></td></tr></table>");
6024                         }
6025                         String sourceContent = source.getContent();
6026                         logger.log(logger.EXTREME, "Merging contents into note");
6027                         logger.log(logger.EXTREME, sourceContent);
6028                         logger.log(logger.EXTREME, "End of content");
6029                         int startOfNote = sourceContent.indexOf("<en-note>");
6030                         sourceContent = sourceContent.substring(startOfNote+9);
6031                         int endOfNote = sourceContent.indexOf("</en-note>");
6032                         sourceContent = sourceContent.substring(0,endOfNote);
6033                         newContent = newContent + sourceContent;
6034                         logger.log(logger.EXTREME, "New note content");
6035                         logger.log(logger.EXTREME, newContent);
6036                         logger.log(logger.EXTREME, "End of content");
6037                         for (int j=0; j<source.getResourcesSize(); j++) {
6038                                 logger.log(logger.EXTREME, "Reassigning resource: "+source.getResources().get(j).getGuid());
6039                                 Resource r = source.getResources().get(j);
6040                                 Resource newRes = conn.getNoteTable().noteResourceTable.getNoteResource(r.getGuid(), true);
6041                                 
6042                                 Calendar currentTime = new GregorianCalendar();
6043                                 Long l = new Long(currentTime.getTimeInMillis());
6044                                                         
6045                                 long prevGuid = 0;
6046                                 l = prevGuid;
6047                                 while (l == prevGuid) {
6048                                         currentTime = new GregorianCalendar();
6049                                         l = new Long(currentTime.getTimeInMillis());
6050                                 }
6051                                 String newResGuid = new String(Long.toString(l));
6052                                 newRes.setNoteGuid(targetGuid);
6053                                 newRes.setGuid(newResGuid);
6054                                 newRes.setUpdateSequenceNum(0);
6055                                 newRes.setActive(true);
6056                                 conn.getNoteTable().noteResourceTable.saveNoteResource(newRes, true);
6057                         }
6058                 }
6059                 logger.log(logger.EXTREME, "Updating note");
6060                 conn.getNoteTable().updateNoteContent(targetGuid, newContent +"</en-note>");
6061                 for (int i=0; i<sources.size(); i++) {
6062                         logger.log(logger.EXTREME, "Deleting note " +sources.get(i));
6063                         listManager.deleteNote(sources.get(i));
6064                 }
6065                 logger.log(logger.EXTREME, "Exiting merge note");
6066         }
6067         // A resource within a note has had a guid change 
6068         @SuppressWarnings("unused")
6069         private void noteResourceGuidChanged(String noteGuid, String oldGuid, String newGuid) {
6070                 if (oldGuid != null && !oldGuid.equals(newGuid))
6071                         Global.resourceMap.put(oldGuid, newGuid);
6072         }
6073         // View a thumbnail of the note
6074         public void thumbnailView() {
6075                 
6076                 String thumbnailName = Global.getFileManager().getResDirPath("thumbnail-" + currentNoteGuid + ".png");
6077                 QFile thumbnail = new QFile(thumbnailName);
6078                 if (!thumbnail.exists()) {
6079                         
6080                         QImage img = new QImage();
6081                         img.loadFromData(conn.getNoteTable().getThumbnail(currentNoteGuid));
6082                         thumbnailViewer.setThumbnail(img);
6083                 } else
6084                         thumbnailViewer.setThumbnail(thumbnailName);
6085                 if (!thumbnailViewer.isVisible()) 
6086                         thumbnailViewer.showFullScreen();
6087         }
6088         // An error happened while saving a note.  Inform the user
6089         @SuppressWarnings("unused")
6090         private void saveRunnerError(String guid, String msg) {
6091                 if (msg == null) {
6092                         String title = "*Unknown*";
6093                         for (int i=0; i<listManager.getMasterNoteIndex().size(); i++) {
6094                                 if (listManager.getMasterNoteIndex().get(i).getGuid().equals(guid)) {
6095                                         title = listManager.getMasterNoteIndex().get(i).getTitle();
6096                                         i=listManager.getMasterNoteIndex().size();
6097                                 }
6098                         }
6099                         msg = tr("An error has happened while saving the note \"") +title+
6100                         tr("\".\n\nThis is probably due to a document that is too complex for NeighborNote to process.  "+
6101                         "As a result, changes to the note may not be saved properly in the database."+
6102                         "\n\nA cached copy is being preserved so you can recover any data, but data may" +
6103                         "\nbe lost.  Please review the note to recover any critical data before restarting.");
6104                         
6105                         QMessageBox.information(this, tr("Error Saving Note"), tr(msg));
6106                 }
6107         }
6108         private void thumbnailHTMLReady(String guid, QByteArray html, Integer zoom) {
6109                 logger.log(logger.HIGH, "Entering thumnailHTMLReady()");
6110                 logger.log(logger.HIGH, "Thumbnail ready for " +guid);
6111                 // Find an idle preview object
6112                 for (int i=0; i<thumbGenerators.size(); i++) {
6113                         if (thumbGenerators.get(i).mutex.tryLock()) {
6114                                 logger.log(logger.EXTREME, "Idle generator found - loading thumbnail for " +guid);
6115                                 thumbGenerators.get(i).loadContent(guid, html, zoom);
6116                                 return;
6117                         }
6118                 } 
6119                 if (thumbGenerators.size() >= 1) {
6120                         logger.log(logger.EXTREME, "No available thumbnail generators.  Aborting " +guid);
6121                         return;
6122                 }
6123                 
6124                 logger.log(logger.EXTREME, "Creating new thumbnail generator " +guid);
6125                 Thumbnailer preview = new Thumbnailer(logger, conn, listManager, thumbnailRunner);
6126                 thumbGenerators.add(preview);
6127
6128                 if (preview.mutex.tryLock()) {
6129                         logger.log(logger.EXTREME, "Loading thumbnail for  " +guid);
6130                         preview.loadContent(guid, html, zoom);
6131                 }
6132                 logger.log(logger.HIGH, "Exiting thumnailHTMLReady()");
6133         }
6134         
6135         
6136         
6137         //**********************************************************
6138     //**********************************************************
6139     //* Online user actions
6140     //**********************************************************
6141     //**********************************************************
6142     private void setupOnlineMenu() {
6143         if (!Global.isConnected) {
6144                 menuBar.noteOnlineHistoryAction.setEnabled(false);
6145                 menuBar.selectiveSyncAction.setEnabled(false);
6146                 return;
6147         } else {
6148                 menuBar.noteOnlineHistoryAction.setEnabled(true);
6149                 menuBar.selectiveSyncAction.setEnabled(true);
6150         }
6151     }
6152     @SuppressWarnings("unused")
6153         private void viewNoteHistory() {
6154         if (currentNoteGuid == null || currentNoteGuid.equals("")) 
6155                 return;
6156         if (currentNote.getUpdateSequenceNum() == 0) {
6157                 setMessage(tr("Note has never been synchronized."));
6158                         QMessageBox.information(this, tr("Error"), tr("This note has never been sent to Evernote, so there is no history."));
6159                         return;
6160         }
6161         
6162         setMessage(tr("Getting Note History"));
6163         waitCursor(true);
6164         Note currentOnlineNote = null;
6165         versions = null;
6166         try {
6167                 if (Global.isPremium())
6168                         versions = syncRunner.localNoteStore.listNoteVersions(syncRunner.authToken, currentNoteGuid);
6169                 else
6170                         versions = new ArrayList<NoteVersionId>();
6171                 currentOnlineNote = syncRunner.localNoteStore.getNote(syncRunner.authToken, currentNoteGuid, true, true, false, false);
6172                 } catch (EDAMUserException e) {
6173                         setMessage("EDAMUserException: " +e.getMessage());
6174                         return;
6175                 } catch (EDAMSystemException e) {
6176                         if (e.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
6177                                 QMessageBox.warning(this, tr("Rate limit reached"), tr("Evernote usage has been temporarily exceeded. Please try again in ") +  + e.getRateLimitDuration() + tr(" seconds."));
6178                         }
6179                         setMessage("EDAMSystemException: " +e.getMessage());
6180                         return;
6181                 } catch (EDAMNotFoundException e) {
6182                         setMessage(tr("Note not found on server."));
6183                         QMessageBox.information(this, tr("Error"), tr("This note could not be found on Evernote's servers."));
6184                         return;
6185                 } catch (TException e) {
6186                         setMessage("EDAMTransactionException: " +e.getMessage());
6187                         return;
6188                 }
6189                 
6190                 // If we've gotten this far, we have a good note.
6191                 if (historyWindow == null) {
6192                         historyWindow = new OnlineNoteHistory(logger, conn, cbObserver);
6193                         
6194                         historyWindow.historyCombo.activated.connect(this, "reloadHistoryWindow(String)");
6195                         historyWindow.restoreAsNew.clicked.connect(this, "restoreHistoryNoteAsNew()");
6196                         historyWindow.restore.clicked.connect(this, "restoreHistoryNote()");
6197                 } else {
6198                         historyWindow.historyCombo.clear();
6199                 }
6200                 boolean isDirty = conn.getNoteTable().isNoteDirty(currentNoteGuid);
6201                 if (currentNote.getUpdateSequenceNum() != currentOnlineNote.getUpdateSequenceNum())
6202                         isDirty = true;
6203                 historyWindow.setCurrent(isDirty);
6204                 
6205                 loadHistoryWindowContent(currentOnlineNote);
6206                 historyWindow.load(versions);
6207                 setMessage(tr("History retrieved"));
6208                 waitCursor(false);
6209                 historyWindow.exec();
6210     }
6211     private Note reloadHistoryWindow(String selection) {
6212         waitCursor(true);
6213                 String fmt = Global.getDateFormat() + " " + Global.getTimeFormat();
6214                 String dateTimeFormat = new String(fmt);
6215                 SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);
6216                 int index = -1;
6217                 int usn = 0;
6218                 
6219                 for (int i=0; i<versions.size(); i++) {
6220                         StringBuilder versionDate = new StringBuilder(simple.format(versions.get(i).getSaved()));
6221                         if (versionDate.toString().equals(selection))
6222                                 index = i;
6223                 }
6224                 
6225                 if (index > -1 || selection.indexOf("Current") > -1) {
6226                         Note historyNote = null;
6227                         try {
6228                                 if (index > -1) {
6229                                         usn = versions.get(index).getUpdateSequenceNum();
6230                                         historyNote = syncRunner.localNoteStore.getNoteVersion(syncRunner.authToken, currentNoteGuid, usn, true, true, true);
6231                                 } else
6232                                         historyNote = syncRunner.localNoteStore.getNote(syncRunner.authToken, currentNoteGuid, true,true,true,true);
6233                         } catch (EDAMUserException e) {
6234                                 setMessage("EDAMUserException: " +e.getMessage());
6235                                 waitCursor(false);
6236                                 return null;
6237                         } catch (EDAMSystemException e) {
6238                                 if (e.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
6239                                         QMessageBox.warning(this, tr("Rate limit reached"), tr("Evernote usage has been temporarily exceeded. Please try again in ") +  + e.getRateLimitDuration() + tr(" seconds."));
6240                                 }
6241                                 setMessage("EDAMSystemException: " +e.getMessage());
6242                                 waitCursor(false);
6243                                 return null;
6244                         } catch (EDAMNotFoundException e) {
6245                                 setMessage("EDAMNotFoundException: " +e.getMessage());
6246                                 waitCursor(false);
6247                                 return null;
6248                         } catch (TException e) {
6249                                 setMessage("EDAMTransactionException: " +e.getMessage());
6250                                 waitCursor(false);
6251                                 return null;
6252                         }
6253                         
6254                         waitCursor(false);
6255                         if (historyNote != null) 
6256                                 historyWindow.setContent(historyNote);
6257                         return historyNote;
6258                 }
6259                 waitCursor(false);
6260                 return null;
6261     }
6262     private void loadHistoryWindowContent(Note note) {
6263         note.setUpdateSequenceNum(0);
6264                 historyWindow.setContent(note); 
6265     }
6266     @SuppressWarnings("unused")
6267         private void restoreHistoryNoteAsNew() {
6268         setMessage(tr("Restoring as new note."));
6269         duplicateNote(reloadHistoryWindow(historyWindow.historyCombo.currentText()));
6270         setMessage(tr("Note has been restored as a new note."));
6271     }
6272     @SuppressWarnings("unused")
6273         private void restoreHistoryNote() {
6274         setMessage(tr("Restoring note."));
6275         Note n = reloadHistoryWindow(historyWindow.historyCombo.currentText());
6276         conn.getNoteTable().expungeNote(n.getGuid(), true, false);
6277         n.setActive(true);
6278         n.setDeleted(0);
6279                 for (int i=0; i<n.getResourcesSize(); i++) {
6280                         n.getResources().get(i).setActive(true);
6281                         conn.getNoteTable().noteResourceTable.saveNoteResource(n.getResources().get(i), true);
6282                 }
6283                 NoteMetadata metadata = new NoteMetadata();
6284                 metadata.setGuid(n.getGuid());
6285         listManager.addNote(n, metadata);
6286         conn.getNoteTable().addNote(n, true);
6287         refreshEvernoteNote(true);
6288         setMessage(tr("Note has been restored."));
6289     }
6290     @SuppressWarnings("unused")
6291         private void setupSelectiveSync() {
6292         
6293         // Get a list of valid notebooks
6294         List<Notebook> notebooks = null; 
6295         List<Tag> tags = null;
6296         List<LinkedNotebook> linkedNotebooks = null;
6297         try {
6298                         notebooks = syncRunner.localNoteStore.listNotebooks(syncRunner.authToken);
6299                         tags = syncRunner.localNoteStore.listTags(syncRunner.authToken);
6300                         linkedNotebooks = syncRunner.localNoteStore.listLinkedNotebooks(syncRunner.authToken);
6301                 } catch (EDAMUserException e) {
6302                         setMessage("EDAMUserException: " +e.getMessage());
6303                         return;
6304                 } catch (EDAMSystemException e) {
6305                         if (e.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
6306                                 QMessageBox.warning(this, tr("Rate limit reached"), tr("Evernote usage has been temporarily exceeded. Please try again in ") +  + e.getRateLimitDuration() + tr(" seconds."));
6307                         }
6308                         setMessage("EDAMSystemException: " +e.getMessage());
6309                         return;
6310                 } catch (TException e) {
6311                         setMessage("EDAMTransactionException: " +e.getMessage());
6312                         return;
6313                 } catch (EDAMNotFoundException e) {
6314                         setMessage("EDAMNotFoundException: " +e.getMessage());
6315                         return;
6316                 }
6317         
6318                 // Split up notebooks into synchronized & non-synchronized
6319         List<Notebook> ignoredBooks = new ArrayList<Notebook>();
6320         List<String> dbIgnoredNotebooks = conn.getSyncTable().getIgnoreRecords("NOTEBOOK");
6321         
6322         for (int i=notebooks.size()-1; i>=0; i--) {
6323                 for (int j=0; j<dbIgnoredNotebooks.size(); j++) {
6324                         if (notebooks.get(i).getGuid().equalsIgnoreCase(dbIgnoredNotebooks.get(j))) {
6325                                 ignoredBooks.add(notebooks.get(i));
6326                                 j=dbIgnoredNotebooks.size();
6327                         }
6328                 }
6329         }
6330         
6331         // split up tags into synchronized & non-synchronized
6332         List<Tag> ignoredTags = new ArrayList<Tag>();
6333         List<String> dbIgnoredTags = conn.getSyncTable().getIgnoreRecords("TAG");
6334         
6335         for (int i=tags.size()-1; i>=0; i--) {
6336                 for (int j=0; j<dbIgnoredTags.size(); j++) {
6337                         if (tags.get(i).getGuid().equalsIgnoreCase(dbIgnoredTags.get(j))) {
6338                                 ignoredTags.add(tags.get(i));
6339                                 j=dbIgnoredTags.size();
6340                         }
6341                 }
6342         }
6343         
6344         // split up linked notebooks into synchronized & non-synchronized
6345         List<LinkedNotebook> ignoredLinkedNotebooks = new ArrayList<LinkedNotebook>();
6346         List<String> dbIgnoredLinkedNotebooks = conn.getSyncTable().getIgnoreRecords("LINKEDNOTEBOOK");
6347         for (int i=linkedNotebooks.size()-1; i>=0; i--) {
6348                 String notebookGuid = linkedNotebooks.get(i).getGuid();
6349                 for (int j=0; j<dbIgnoredLinkedNotebooks.size(); j++) {
6350                         if (notebookGuid.equalsIgnoreCase(dbIgnoredLinkedNotebooks.get(j))) {
6351                                 ignoredLinkedNotebooks.add(linkedNotebooks.get(i));
6352                                 j=dbIgnoredLinkedNotebooks.size();
6353                         }
6354                 }
6355         }
6356         
6357                 IgnoreSync ignore = new IgnoreSync(notebooks, ignoredBooks, tags, ignoredTags, linkedNotebooks, ignoredLinkedNotebooks);
6358                 ignore.exec();
6359                 if (!ignore.okClicked())
6360                         return;
6361                 
6362                 waitCursor(true);
6363                 
6364                 // Clear out old notebooks & add  the new ones
6365                 List<String> oldIgnoreNotebooks = conn.getSyncTable().getIgnoreRecords("NOTEBOOK");
6366                 for (int i=0; i<oldIgnoreNotebooks.size(); i++) {
6367                         conn.getSyncTable().deleteRecord("IGNORENOTEBOOK-"+oldIgnoreNotebooks.get(i));
6368                 }
6369                 
6370                 List<String> newNotebooks = new ArrayList<String>();
6371                 for (int i=ignore.getIgnoredBookList().count()-1; i>=0; i--) {
6372                         String text = ignore.getIgnoredBookList().takeItem(i).text();
6373                         for (int j=0; j<notebooks.size(); j++) {
6374                                 if (notebooks.get(j).getName().equalsIgnoreCase(text)) {
6375                                         Notebook n = notebooks.get(j);
6376                                         conn.getSyncTable().addRecord("IGNORENOTEBOOK-"+n.getGuid(), n.getGuid());
6377                                         j=notebooks.size();
6378                                         newNotebooks.add(n.getGuid());
6379                                 }
6380                         }
6381                 }
6382                 
6383                 // Clear out old tags & add new ones
6384                 List<String> oldIgnoreTags = conn.getSyncTable().getIgnoreRecords("TAG");
6385                 for (int i=0; i<oldIgnoreTags.size(); i++) {
6386                         conn.getSyncTable().deleteRecord("IGNORETAG-"+oldIgnoreTags.get(i));
6387                 }
6388                 
6389                 List<String> newTags = new ArrayList<String>();
6390                 for (int i=ignore.getIgnoredTagList().count()-1; i>=0; i--) {
6391                         String text = ignore.getIgnoredTagList().takeItem(i).text();
6392                         for (int j=0; j<tags.size(); j++) {
6393                                 if (tags.get(j).getName().equalsIgnoreCase(text)) {
6394                                         Tag t = tags.get(j);
6395                                         conn.getSyncTable().addRecord("IGNORETAG-"+t.getGuid(), t.getGuid());
6396                                         newTags.add(t.getGuid());
6397                                         j=tags.size();
6398                                 }
6399                         }
6400                 }
6401                 
6402                 // Clear out old tags & add new ones
6403                 List<String> oldIgnoreLinkedNotebooks = conn.getSyncTable().getIgnoreRecords("LINKEDNOTEBOOK");
6404                 for (int i=0; i<oldIgnoreLinkedNotebooks.size(); i++) {
6405                         conn.getSyncTable().deleteRecord("IGNORELINKEDNOTEBOOK-"+oldIgnoreLinkedNotebooks.get(i));
6406                 }
6407                 
6408                 List<String> newLinked = new ArrayList<String>();
6409                 for (int i=ignore.getIgnoredLinkedNotebookList().count()-1; i>=0; i--) {
6410                         String text = ignore.getIgnoredLinkedNotebookList().takeItem(i).text();
6411                         for (int j=0; j<linkedNotebooks.size(); j++) {
6412                                 if (linkedNotebooks.get(j).getShareName().equalsIgnoreCase(text)) {
6413                                         LinkedNotebook t = linkedNotebooks.get(j);
6414                                         conn.getSyncTable().addRecord("IGNORELINKEDNOTEBOOK-"+t.getGuid(), t.getGuid());
6415                                         newLinked.add(t.getGuid());
6416                                         j=linkedNotebooks.size();
6417                                 }
6418                         }
6419                 }
6420                 
6421                 conn.getNoteTable().expungeIgnoreSynchronizedNotes(newNotebooks, newTags, newLinked);
6422                 waitCursor(false);
6423                 refreshLists();
6424     }
6425     
6426     
6427         //**********************************************************
6428         //**********************************************************
6429         //* XML Modifying methods
6430         //**********************************************************
6431         //**********************************************************
6432         // An error has happended fetching a resource.  let the user know
6433         private void resourceErrorMessage(int tabIndex) {
6434                 if (tabIndex < 0) {
6435                         return;
6436                 }
6437                 if (inkNote.get(tabIndex))
6438                         return;
6439                 waitCursor(false);
6440                 QMessageBox.information(this, tr("DOUGH!!!"), tr("Well, this is embarrassing."+
6441                 "\n\nSome attachments or images for this note appear to be missing from my database.\n"+
6442                 "In a perfect world this wouldn't happen, but it has.\n" +
6443                 "It is embarasing when a program like me, designed to save all your\n"+
6444                 "precious data, has a problem finding data.\n\n" +
6445                 "I guess life isn't fair, but I'll survive.  Somehow...\n\n" +
6446                 "In the mean time, I'm not going to let you make changes to this note.\n" +
6447                 "Don't get angry.  I'm doing it to prevent you from messing up\n"+
6448                 "this note on the Evernote servers.  Sorry."+
6449                 "\n\nP.S. You might want to re-synchronize to see if it corrects this problem.\nWho knows, you might get lucky."));
6450                 inkNote.put(tabIndex, true);
6451                 browserWindow.setReadOnly(true);
6452                 waitCursor(true);
6453         }
6454
6455         
6456         
6457         
6458         //**********************************************************
6459         //**********************************************************
6460         //* Timer functions
6461         //**********************************************************
6462         //**********************************************************
6463         // We should now do a sync with Evernote
6464         private void syncTimer() {
6465                 logger.log(logger.EXTREME, "Entering NeverNote.syncTimer()");
6466                 syncRunner.syncNeeded = true;
6467                 syncRunner.disableUploads = Global.disableUploads;
6468                 syncStart();
6469                 logger.log(logger.EXTREME, "Leaving NeverNote.syncTimer()");
6470         }
6471         private void syncStart() {
6472                 logger.log(logger.EXTREME, "Entering NeverNote.syncStart()");
6473                 saveNote();
6474                 if (!syncRunning && Global.isConnected) {
6475                         syncRunner.setConnected(true);
6476                         syncRunner.setKeepRunning(Global.keepRunning);
6477                         syncRunner.syncDeletedContent = Global.synchronizeDeletedContent();
6478                         
6479                         if (syncThreadsReady > 0) {
6480                                 thumbnailRunner.interrupt = true;
6481                                 saveNoteIndexWidth();
6482                                 saveNoteColumnPositions();
6483                                 if (syncRunner.addWork("SYNC")) {
6484                                         syncRunning = true;
6485                                         syncRunner.syncNeeded = true;
6486                                         syncThreadsReady--;
6487                                 }                               
6488                         }
6489                 }
6490                 logger.log(logger.EXTREME, "Leaving NeverNote.syncStart");
6491         }
6492         @SuppressWarnings("unused")
6493         private void syncThreadComplete(Boolean refreshNeeded) {
6494                 setMessage(tr("Finalizing Synchronization"));
6495                 syncThreadsReady++;
6496                 syncRunning = false;
6497                 syncRunner.syncNeeded = false;
6498                 synchronizeAnimationTimer.stop();
6499                 synchronizeButton.setIcon(new QIcon(iconPath+"synchronize.png"));
6500                 saveNote();
6501                 if (currentNote == null) {
6502                         currentNote = conn.getNoteTable().getNote(currentNoteGuid, false, false, false, false, true);
6503                 }
6504                 listManager.refreshNoteMetadata();
6505                 noteIndexUpdated(true);
6506                 noteTableView.selectionModel().blockSignals(true);
6507                 scrollToGuid(currentNoteGuid);
6508                 noteTableView.selectionModel().blockSignals(false);
6509                 refreshEvernoteNote(false);
6510                 scrollToGuid(currentNoteGuid);
6511                 waitCursor(false);
6512                 
6513                 // Check to see if there were any shared notebook errors
6514                 if (syncRunner.error && syncRunner.errorSharedNotebooks.size() > 0) {
6515                         String guid = syncRunner.errorSharedNotebooks.get(0);
6516                         String notebookGuid = conn.getLinkedNotebookTable().getLocalNotebookGuid(guid);
6517                         String localName = listManager.getNotebookNameByGuid(notebookGuid);
6518                         SharedNotebookSyncError syncDialog = new SharedNotebookSyncError(localName);
6519                         syncDialog.exec();
6520                         if (syncDialog.okPressed()) {
6521                                 if (syncDialog.doNothing.isChecked()) {
6522                                         syncRunner.errorSharedNotebooksIgnored.put(guid, guid);
6523                                         evernoteSync();
6524                                 }
6525                                 if (syncDialog.deleteNotebook.isChecked()) {
6526                                         conn.getNoteTable().expungeNotesByNotebook(notebookGuid, true, false);
6527                                         conn.getNotebookTable().expungeNotebook(notebookGuid, false);
6528                                         conn.getLinkedNotebookTable().expungeNotebook(guid, false);
6529                                         conn.getLinkedNotebookTable().expungeNotebook(guid, false);
6530                                         evernoteSync();
6531                                 }
6532                                 refreshLists();
6533                                 return;
6534                         }
6535                 }
6536                 
6537                 // Finalize the synchronization
6538                 if (!syncRunner.error)
6539                         setMessage(tr("Synchronization Complete"));
6540                 else
6541                         setMessage(tr("Synchronization completed with errors.  Please check the log for details."));
6542                 logger.log(logger.MEDIUM, "Sync complete.");
6543         }   
6544         public void saveUploadAmount(long t) {
6545                 Global.saveUploadAmount(t);
6546         }
6547         public void saveUserInformation(User user) {
6548                 Global.saveUserInformation(user);
6549         }
6550         public void saveEvernoteUpdateCount(int i) {
6551                 Global.saveEvernoteUpdateCount(i);
6552         }
6553         public void refreshLists() {
6554                 logger.log(logger.EXTREME, "Entering NeverNote.refreshLists");
6555                 updateQuotaBar();
6556                 // すべてのタブのノートを調べて、Dirtyならばセーブする。その後refreshListsする。
6557                 Collection<Integer> tabIndex = noteDirty.keySet();
6558                 Iterator<Integer> indexIterator = tabIndex.iterator();
6559                 HashMap<Integer, Note> saveNotes = new HashMap<Integer, Note>();
6560                 HashMap<Integer, String> saveContents = new HashMap<Integer, String>();
6561                 for (boolean isNoteDirty: noteDirty.values()) {
6562                         int index = indexIterator.next();
6563                         if (isNoteDirty) {
6564                                 saveNotes.put(index, tabWindows.get(index).getBrowserWindow().getNote());
6565                                 saveContents.put(index, tabWindows.get(index).getBrowserWindow().getContent());
6566                         }
6567                 }
6568                 
6569                 listManager.saveUpdatedNotes(saveNotes, saveContents);
6570                 listManager.refreshLists();
6571
6572                 tagIndexUpdated(true);
6573                 notebookIndexUpdated();
6574                 savedSearchIndexUpdated();
6575                 listManager.loadNotesIndex();
6576
6577                 noteTableView.selectionModel().blockSignals(true);
6578         noteIndexUpdated(true);
6579                 noteTableView.selectionModel().blockSignals(false);
6580                 logger.log(logger.EXTREME, "Leaving NeverNote.refreshLists");
6581         }
6582
6583         
6584         @SuppressWarnings("unused")
6585         private void authTimer() {
6586         Calendar cal = Calendar.getInstance();
6587                 
6588         // If we are not connected let's get out of here
6589         if (!Global.isConnected)
6590                 return;
6591                 
6592                 // If this is the first time through, then we need to set this
6593  //             if (syncRunner.authRefreshTime == 0 || cal.getTimeInMillis() > syncRunner.authRefreshTime) 
6594 //                      syncRunner.authRefreshTime = cal.getTimeInMillis();
6595                 
6596 //              long now = new Date().getTime();
6597 //              if (now > Global.authRefreshTime && Global.isConnected) {
6598                         syncRunner.authRefreshNeeded = true;
6599                         syncStart();
6600 //              }
6601         }
6602         @SuppressWarnings("unused")
6603         private void authRefreshComplete(boolean goodSync) {
6604                 logger.log(logger.EXTREME, "Entering NeverNote.authRefreshComplete");
6605                 Global.isConnected = syncRunner.isConnected;
6606                 if (goodSync) {
6607 //                      authTimer.start((int)syncRunner.authTimeRemaining/4);
6608                         authTimer.start(1000*60*15);
6609                         logger.log(logger.LOW, "Authentication token has been renewed");
6610 //                      setMessage("Authentication token has been renewed.");
6611                 } else {
6612                         authTimer.start(1000*60*5);
6613                         logger.log(logger.LOW, "Authentication token renew has failed - retry in 5 minutes.");
6614 //                      setMessage("Authentication token renew has failed - retry in 5 minutes.");
6615                 }
6616                 logger.log(logger.EXTREME, "Leaving NeverNote.authRefreshComplete");
6617         }
6618         
6619         
6620         @SuppressWarnings("unused")
6621         private synchronized void indexTimer() {
6622                 logger.log(logger.EXTREME, "Index timer activated.  Sync running="+syncRunning);
6623                 if (syncRunning) 
6624                         return;
6625                 if (!indexDisabled && indexRunner.idle) { 
6626                         thumbnailRunner.interrupt = true;
6627                         indexRunner.addWork("SCAN");
6628                 }
6629                 logger.log(logger.EXTREME, "Leaving NeighborNote index timer");
6630         }
6631
6632         @SuppressWarnings("unused")
6633         private void indexStarted() {
6634                 setMessage(tr("Indexing notes"));
6635         }
6636         @SuppressWarnings("unused")
6637         private void indexComplete() {
6638                 setMessage(tr("Index complete"));
6639         }
6640         @SuppressWarnings("unused")
6641         private synchronized void toggleNoteIndexing() {
6642                 logger.log(logger.HIGH, "Entering NeverNote.toggleIndexing");
6643                 indexDisabled = !indexDisabled;
6644                 if (!indexDisabled)
6645                         setMessage(tr("Indexing is now enabled."));
6646                 else
6647                         setMessage(tr("Indexing is now disabled."));
6648                 menuBar.disableIndexing.setChecked(indexDisabled);
6649         logger.log(logger.HIGH, "Leaving NeverNote.toggleIndexing");
6650     }  
6651         
6652         @SuppressWarnings("unused")
6653         private void threadMonitorCheck() {
6654                 int MAX=3;
6655                 
6656                 
6657                 boolean alive;
6658                 alive = listManager.threadCheck(Global.tagCounterThreadId);
6659                 if (!alive) {
6660                         tagDeadCount++;
6661                         if (tagDeadCount > MAX && !disableTagThreadCheck) {
6662                                 QMessageBox.information(this, tr("A thread has died."), tr("It appears as the tag counter thread has died.  I recommend "+
6663                                 "checking stopping NeighborNote, saving the logs for later viewing, and restarting.  Sorry."));
6664                                 disableTagThreadCheck = true;
6665                         }
6666                 } else
6667                         tagDeadCount=0;
6668                 
6669                 alive = listManager.threadCheck(Global.notebookCounterThreadId);
6670                 if (!alive) {
6671                         notebookThreadDeadCount++;
6672                         if (notebookThreadDeadCount > MAX && !disableNotebookThreadCheck) {
6673                                 QMessageBox.information(this, tr("A thread has died."), tr("It appears as the notebook counter thread has died.  I recommend "+
6674                                         "checking stopping NeighborNote, saving the logs for later viewing, and restarting.  Sorry."));
6675                                 disableNotebookThreadCheck=true;
6676                         }
6677                 } else
6678                         notebookThreadDeadCount=0;
6679                 
6680                 alive = listManager.threadCheck(Global.trashCounterThreadId);
6681                 if (!alive) {
6682                         trashDeadCount++;
6683                         if (trashDeadCount > MAX && !disableTrashThreadCheck) {
6684                                 QMessageBox.information(this, tr("A thread has died."), ("It appears as the trash counter thread has died.  I recommend "+
6685                                         "checking stopping NeighborNote, saving the logs for later viewing, and restarting.  Sorry."));
6686                                 disableTrashThreadCheck = true;
6687                         }
6688                 } else
6689                         trashDeadCount = 0;
6690
6691                 alive = listManager.threadCheck(Global.saveThreadId);
6692                 if (!alive) {
6693                         saveThreadDeadCount++;
6694                         if (saveThreadDeadCount > MAX && !disableSaveThreadCheck) {
6695                                 QMessageBox.information(this, tr("A thread has died."), tr("It appears as the note saver thread has died.  I recommend "+
6696                                         "checking stopping NeighborNote, saving the logs for later viewing, and restarting.  Sorry."));
6697                                 disableSaveThreadCheck = true;
6698                         }
6699                 } else
6700                         saveThreadDeadCount=0;
6701
6702                 if (!syncThread.isAlive()) {
6703                         syncThreadDeadCount++;
6704                         if (syncThreadDeadCount > MAX && !disableSyncThreadCheck) {
6705                                 QMessageBox.information(this, tr("A thread has died."), tr("It appears as the synchronization thread has died.  I recommend "+
6706                                         "checking stopping NeighborNote, saving the logs for later viewing, and restarting.  Sorry."));
6707                                 disableSyncThreadCheck = true;
6708                         }
6709                 } else
6710                         syncThreadDeadCount=0;
6711
6712                 if (!indexThread.isAlive()) {
6713                         indexThreadDeadCount++;
6714                         if (indexThreadDeadCount > MAX && !disableIndexThreadCheck) {
6715                                 QMessageBox.information(this, tr("A thread has died."), tr("It appears as the index thread has died.  I recommend "+
6716                                         "checking stopping NeighborNote, saving the logs for later viewing, and restarting.  Sorry."));
6717                                 disableIndexThreadCheck = true;
6718                         }
6719                 } else
6720                         indexThreadDeadCount=0;
6721
6722                 if (!rensoNoteListDock.getRensoNoteList().getEnRelatedNotesThread().isAlive()) {
6723                         enRelatedNotesThreadDeadCount++;
6724                         if (enRelatedNotesThreadDeadCount > MAX && !disableENRelatedNotesThreadCheck) {
6725                                 QMessageBox.information(this, tr("A thread has died."), tr("It appears as the Evernote Related Notes thread has died.  I recommend "+
6726                                         "checking stopping NeighborNote, saving the logs for later viewing, and restarting.  Sorry."));
6727                                 disableENRelatedNotesThreadCheck = true;
6728                         }
6729                 } else
6730                         enRelatedNotesThreadDeadCount=0;
6731         }
6732
6733         private void thumbnailTimer() {
6734                 if (Global.enableThumbnails() && !syncRunning && indexRunner.idle) {
6735                         thumbnailRunner.addWork("SCAN");
6736                 }
6737         }
6738         
6739         //**************************************************
6740         //* Backup & Restore
6741         //**************************************************
6742         @SuppressWarnings("unused")
6743         private void databaseBackup() {
6744                 QFileDialog fd = new QFileDialog(this);
6745                 fd.setFileMode(FileMode.AnyFile);
6746                 fd.setConfirmOverwrite(true);
6747                 fd.setWindowTitle(tr("Backup Database"));
6748                 fd.setFilter(tr("NixNote Export (*.nnex);;All Files (*.*)"));
6749                 fd.setAcceptMode(AcceptMode.AcceptSave);
6750                 if (saveLastPath == null || saveLastPath.equals(""))
6751                         fd.setDirectory(System.getProperty("user.home"));
6752                 else
6753                         fd.setDirectory(saveLastPath);
6754                 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
6755                         return;
6756                 }
6757                 
6758                 
6759         waitCursor(true);
6760         saveLastPath = fd.selectedFiles().get(0);
6761         saveLastPath = saveLastPath.substring(0,saveLastPath.lastIndexOf("/"));
6762         setMessage(tr("Backing up database"));
6763         saveNote();
6764 //      conn.backupDatabase(Global.getUpdateSequenceNumber(), Global.getSequenceDate());
6765         
6766         ExportData noteWriter = new ExportData(conn, true);
6767         String fileName = fd.selectedFiles().get(0);
6768
6769         if (!fileName.endsWith(".nnex"))
6770                 fileName = fileName +".nnex";
6771         noteWriter.exportData(fileName);
6772         setMessage(tr("Database backup completed."));
6773  
6774
6775         waitCursor(false);
6776         }
6777         @SuppressWarnings("unused")
6778         private void databaseRestore() {
6779                 if (QMessageBox.question(this, tr("Confirmation"),
6780                                 tr("This is used to restore a database from backups.\n" +
6781                                 "It is HIGHLY recommened that this only be used to populate\n" +
6782                                 "an empty database.  Restoring into a database that\n already has data" +
6783                                 " can cause problems.\n\nAre you sure you want to continue?"),
6784                                 QMessageBox.StandardButton.Yes, 
6785                                 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
6786                                         return;
6787                                 }
6788                 
6789                 
6790                 QFileDialog fd = new QFileDialog(this);
6791                 fd.setFileMode(FileMode.ExistingFile);
6792                 fd.setConfirmOverwrite(true);
6793                 fd.setWindowTitle(tr("Restore Database"));
6794                 fd.setFilter(tr("NixNote Export (*.nnex);;All Files (*.*)"));
6795                 fd.setAcceptMode(AcceptMode.AcceptOpen);
6796                 if (saveLastPath == null || saveLastPath.equals(""))
6797                         fd.setDirectory(System.getProperty("user.home"));
6798                 else
6799                         fd.setDirectory(saveLastPath);
6800                 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
6801                         return;
6802                 }
6803                 
6804                 
6805                 waitCursor(true);
6806         saveLastPath = fd.selectedFiles().get(0);
6807         saveLastPath = saveLastPath.substring(0,saveLastPath.lastIndexOf("/"));
6808
6809                 setMessage(tr("Restoring database"));
6810         ImportData noteReader = new ImportData(conn, true);
6811         noteReader.importData(fd.selectedFiles().get(0));
6812         
6813         if (noteReader.lastError != 0) {
6814                 setMessage(noteReader.getErrorMessage());
6815                 logger.log(logger.LOW, "Restore problem: " +noteReader.lastError);
6816                 waitCursor(false);
6817                 return;
6818         }
6819         
6820         listManager.loadNoteTitleColors();
6821         refreshLists();
6822         refreshEvernoteNote(true);
6823         setMessage(tr("Database has been restored."));
6824         waitCursor(false);
6825         }
6826         @SuppressWarnings("unused")
6827         private void exportNotes() {
6828                 QFileDialog fd = new QFileDialog(this);
6829                 fd.setFileMode(FileMode.AnyFile);
6830                 fd.setConfirmOverwrite(true);
6831                 fd.setWindowTitle(tr("Backup Database"));
6832                 fd.setFilter(tr("NixNote Export (*.nnex);;All Files (*.*)"));
6833                 fd.setAcceptMode(AcceptMode.AcceptSave);
6834                 fd.setDirectory(System.getProperty("user.home"));
6835                 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
6836                         return;
6837                 }
6838                 
6839                 
6840         waitCursor(true);
6841         setMessage(tr("Exporting Notes"));
6842         saveNote();
6843         
6844                 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals("")) 
6845                         selectedNoteGUIDs.add(currentNoteGuid);
6846                 
6847         ExportData noteWriter = new ExportData(conn, false, selectedNoteGUIDs);
6848         String fileName = fd.selectedFiles().get(0);
6849
6850         if (!fileName.endsWith(".nnex"))
6851                 fileName = fileName +".nnex";
6852         noteWriter.exportData(fileName);
6853         setMessage(tr("Export completed."));
6854  
6855
6856         waitCursor(false);
6857                 
6858         }
6859         @SuppressWarnings("unused")
6860         private void importNotes() {
6861                 QFileDialog fd = new QFileDialog(this);
6862                 fd.setFileMode(FileMode.ExistingFile);
6863                 fd.setConfirmOverwrite(true);
6864                 fd.setWindowTitle(tr("Import Notes"));
6865                 fd.setFilter(tr("NixNote Export (*.nnex);;Evernote Export (*.enex);;All Files (*.*)"));
6866                 fd.setAcceptMode(AcceptMode.AcceptOpen);
6867                 if (saveLastPath == null || saveLastPath.equals(""))
6868                         fd.setDirectory(System.getProperty("user.home"));
6869                 else
6870                         fd.setDirectory(saveLastPath);
6871                 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
6872                         return;
6873                 }
6874                 
6875                 
6876         waitCursor(true);
6877         setMessage(tr("Importing Notes"));
6878         saveNote();
6879         
6880                 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals("")) 
6881                         selectedNoteGUIDs.add(currentNoteGuid);
6882                 
6883         String fileName = fd.selectedFiles().get(0);
6884 //      saveLastPath.substring(0,fileName.lastIndexOf("/"));
6885
6886         if (fileName.endsWith(".nnex")) {
6887                 ImportData noteReader = new ImportData(conn, false);
6888                 if (selectedNotebookGUIDs != null && selectedNotebookGUIDs.size() > 0) 
6889                         noteReader.setNotebookGuid(selectedNotebookGUIDs.get(0));
6890                 else
6891                         noteReader.setNotebookGuid(listManager.getNotebookIndex().get(0).getGuid());
6892   
6893                 noteReader.importData(fileName);
6894         
6895                 if (noteReader.lastError != 0) {
6896                         setMessage(noteReader.getErrorMessage());
6897                         logger.log(logger.LOW, "Import problem: " +noteReader.lastError);
6898                         waitCursor(false);
6899                         return;
6900                 }
6901         } else {
6902                 if (fileName.endsWith(".enex")) {
6903                 ImportEnex noteReader = new ImportEnex(conn, false);
6904                         if (selectedNotebookGUIDs != null && selectedNotebookGUIDs.size() > 0) 
6905                                 noteReader.setNotebookGuid(selectedNotebookGUIDs.get(0));
6906                         else
6907                                 noteReader.setNotebookGuid(listManager.getNotebookIndex().get(0).getGuid());
6908   
6909                         waitCursor(false);
6910                         if (QMessageBox.question(this, tr("Confirmation"), 
6911                                         tr("Create new tags from import?"),
6912                                         QMessageBox.StandardButton.Yes, 
6913                                         QMessageBox.StandardButton.No) == StandardButton.Yes.value()) {
6914                                                                 noteReader.createNewTags = true;
6915                         } else
6916                                 noteReader.createNewTags = false;
6917                         waitCursor(true);
6918                         noteReader.importData(fileName);
6919         
6920                         if (noteReader.lastError != 0) {
6921                                 setMessage(noteReader.getErrorMessage());
6922                                 logger.log(logger.LOW, "Import problem: " +noteReader.lastError);
6923                                 waitCursor(false);
6924                                 return;
6925                         }
6926                 }
6927         }
6928         
6929         listManager.loadNoteTitleColors();
6930         refreshLists();
6931         refreshEvernoteNote(false);
6932         setMessage(tr("Notes have been imported."));
6933         waitCursor(false);
6934         
6935         setMessage(tr("Import completed."));
6936  
6937
6938         waitCursor(false);
6939                 
6940         }
6941         
6942         //**************************************************
6943         //* Duplicate a note 
6944         //**************************************************
6945         @SuppressWarnings("unused")
6946         private void duplicateNote() {
6947                 saveNote();
6948                 duplicateNote(currentNoteGuid);
6949         }
6950
6951         //**************************************************
6952         //* Action from when a user clicks Copy As URL
6953         //**************************************************
6954         @SuppressWarnings("unused")
6955         private void copyAsUrlClicked() {
6956                 QClipboard clipboard = QApplication.clipboard();
6957                 QMimeData mime = new QMimeData();
6958                 String url;
6959                 mime.setText(currentNoteGuid);
6960                 List<QUrl> urls = new ArrayList<QUrl>();
6961                 
6962                 // Start building the URL
6963                 User user = Global.getUserInformation();
6964
6965                 // Check that we have everything we need
6966                 if ((user.getShardId().equals("") || user.getId() == 0) && !Global.bypassSynchronizationWarning()) {
6967                         SynchronizationRequiredWarning warning = new SynchronizationRequiredWarning(this);
6968                         warning.exec();
6969                         if (!warning.neverSynchronize())
6970                                 return;
6971                         else {
6972                                 Global.setBypassSynchronizationWarning(true);
6973                                 user.setShardId("s0");
6974                                 user.setId(0);
6975                         }       
6976                 }
6977
6978                 
6979                 // Start building a list of URLs based upon the selected notes
6980         noteTableView.showColumn(Global.noteTableGuidPosition);
6981         
6982         List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
6983         if (!Global.isColumnVisible("guid"))
6984                 noteTableView.hideColumn(Global.noteTableGuidPosition);
6985
6986                 // Check that the note is either synchronized, or in a local notebook
6987                 for (int i=0; i<selections.size(); i++) {
6988                         QModelIndex index;
6989                         int row = selections.get(i).row();
6990                 index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition);
6991                 SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
6992                 String selectedGuid = (String)ix.values().toArray()[0];
6993                 
6994                 Note n = conn.getNoteTable().getNote(selectedGuid, false, false, false, false, false);
6995                 if (n.getUpdateSequenceNum() == 0 && !conn.getNotebookTable().isNotebookLocal(n.getNotebookGuid())) {
6996                         QMessageBox.critical(this, tr("Please Synchronize") ,tr("Please either synchronize or move any " +
6997                                         "new notes to a local notebook."));
6998                         return; 
6999                 }
7000                 }
7001
7002                 // Start building the URLs
7003         for (int i=0; i<selections.size(); i++) {
7004                 QModelIndex index;
7005                         int row = selections.get(i).row();
7006                 index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition);
7007                 SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
7008                 String selectedGuid = (String)ix.values().toArray()[0];
7009                 mime.setText(selectedGuid);
7010                 
7011                 String lid;
7012                 String gid;
7013                 Note selectedNote = conn.getNoteTable().getNote(selectedGuid, false, false, false, false, false);
7014                 if (selectedNote.getUpdateSequenceNum() > 0) {
7015                         gid = selectedGuid;
7016                         lid = selectedGuid;
7017                 } else {
7018                         gid = "00000000-0000-0000-0000-000000000000";
7019                         lid = selectedGuid;
7020                 }
7021                 url = new String("evernote://///view/") + new String(user.getId() + "/" +user.getShardId() +"/"
7022                                 +gid+"/"+lid +"/");
7023                 urls.add(new QUrl(url));
7024         }
7025                 mime.setUrls(urls);
7026                 clipboard.setMimeData(mime);
7027         }
7028         
7029         
7030         //**************************************************
7031         //* Folder Imports
7032         //**************************************************
7033         public void setupFolderImports() {
7034                 List<WatchFolderRecord> records = conn.getWatchFolderTable().getAll();
7035                 
7036                 if (importKeepWatcher == null)
7037                         importKeepWatcher = new QFileSystemWatcher();
7038                 if (importDeleteWatcher == null) {
7039                         importDeleteWatcher = new QFileSystemWatcher();
7040                         for (int i=0; i<records.size(); i++) {
7041                                 if (!records.get(i).keep)
7042                                         folderImportDelete(records.get(i).folder); 
7043                         }
7044                 }
7045
7046                                 
7047                 
7048 //              importKeepWatcher.addPath(records.get(i).folder.replace('\\', '/'));
7049                 for (int i=0; i<records.size(); i++) {
7050                         logger.log(logger.LOW, "Adding file monitor: " +records.get(i).folder);
7051                         if (records.get(i).keep) 
7052                                 importKeepWatcher.addPath(records.get(i).folder);
7053                         else
7054                                 importDeleteWatcher.addPath(records.get(i).folder);
7055                 }
7056                 
7057                 logger.log(logger.EXTREME, "List of directories being watched (kept)...");
7058                 List<String> monitorDelete = importKeepWatcher.directories();
7059                 for (int i=0; i<monitorDelete.size(); i++) {
7060                         logger.log(logger.EXTREME, monitorDelete.get(i));
7061                 }
7062                 logger.log(logger.EXTREME, "<end of list>");
7063                 logger.log(logger.EXTREME, "List of directories being watched (delete)...");
7064                 monitorDelete = importDeleteWatcher.directories();
7065                 for (int i=0; i<monitorDelete.size(); i++) {
7066                         logger.log(logger.EXTREME, monitorDelete.get(i));
7067                 }
7068                 logger.log(logger.EXTREME, "<end of list>");
7069                 
7070                 importKeepWatcher.directoryChanged.connect(this, "folderImportKeep(String)");
7071                 importDeleteWatcher.directoryChanged.connect(this, "folderImportDelete(String)");
7072                 
7073                 // Look at the files already there so we don't import them again if a new file is created
7074                 if (importedFiles == null) {
7075                         importedFiles = new ArrayList<String>();
7076                         for (int j=0; j<records.size(); j++) {
7077                                 QDir dir = new QDir(records.get(j).folder);
7078                                 List<QFileInfo> list = dir.entryInfoList();
7079                                 for (int k=0; k<list.size(); k++) {
7080                                         if (list.get(k).isFile())
7081                                                 importedFiles.add(list.get(k).absoluteFilePath());
7082                                 }
7083                         }
7084                 }
7085         }
7086         
7087         // Menu folderImport action triggered
7088         public void folderImport() {
7089                 List<WatchFolderRecord> recs = conn.getWatchFolderTable().getAll();
7090                 WatchFolder dialog = new WatchFolder(recs, listManager.getNotebookIndex());
7091                 dialog.exec();
7092                 if (!dialog.okClicked())
7093                         return;
7094                 
7095                 // We have some sort of update.
7096                 if (importKeepWatcher.directories().size() > 0)
7097                         importKeepWatcher.removePaths(importKeepWatcher.directories());
7098                 if (importDeleteWatcher.directories().size() > 0)
7099                         importDeleteWatcher.removePaths(importDeleteWatcher.directories());
7100                 
7101                 conn.getWatchFolderTable().expungeAll();
7102                 // Start building from the table
7103                 for (int i=0; i<dialog.table.rowCount(); i++) {
7104                         QTableWidgetItem item = dialog.table.item(i, 0);
7105                         String dir = item.text();
7106                         item = dialog.table.item(i, 1);
7107                         String notebook = item.text();
7108                         item = dialog.table.item(i, 2);
7109                         boolean keep;
7110                         if (item.text().equalsIgnoreCase("Keep"))
7111                                 keep = true;
7112                         else
7113                                 keep = false;
7114                         
7115                         String guid = conn.getNotebookTable().findNotebookByName(notebook);
7116                         conn.getWatchFolderTable().addWatchFolder(dir, guid, keep, 0);
7117                 }
7118                 setupFolderImports();
7119         }
7120         
7121         
7122         public void folderImportKeep(String dirName) throws NoSuchAlgorithmException {
7123                 logger.log(logger.LOW, "Inside folderImportKeep");
7124                 String whichOS = System.getProperty("os.name");
7125                 if (whichOS.contains("Windows")) 
7126                         dirName = dirName.replace('/','\\');
7127                 
7128                 FileImporter importer = new FileImporter(logger, conn);
7129                 
7130                 QDir dir = new QDir(dirName);
7131                 List<QFileInfo> list = dir.entryInfoList();
7132                 String notebook = conn.getWatchFolderTable().getNotebook(dirName);
7133
7134                 for (int i=0; i<list.size(); i++){
7135                         logger.log(logger.LOW, "File found: " +list.get(i).fileName());
7136                         boolean redundant = false;
7137                         // Check if we've already imported this one or if it existed before
7138                         for (int j=0; j<importedFiles.size(); j++) {
7139                                 logger.log(logger.LOW, "redundant file list: " +list.get(i).absoluteFilePath());
7140                                 if (importedFiles.get(j).equals(list.get(i).absoluteFilePath()))
7141                                         redundant = true;
7142                         }
7143                         
7144                         logger.log(logger.LOW, "Checking if redundant: " +redundant);
7145                         if (!redundant) {
7146                                 importer.setFileInfo(list.get(i));
7147                                 importer.setFileName(list.get(i).absoluteFilePath());
7148                         
7149                         
7150                                 logger.log(logger.LOW, "File importing is a file: " +list.get(i).isFile());
7151                                 logger.log(logger.LOW, "File importing is a valid: " +importer.isValidType());
7152                                 if (list.get(i).isFile() && importer.isValidType()) {
7153                         
7154                                         if (!importer.importFile()) {
7155                                                 // If we can't get to the file, it is probably locked.  We'll try again later.
7156                                                 logger.log(logger.LOW, "Unable to save externally edited file.  Saving for later.");
7157                                                 importFilesKeep.add(list.get(i).absoluteFilePath());
7158                                         } else {
7159
7160                                                 Note newNote = importer.getNote();
7161                                                 newNote.setNotebookGuid(notebook);
7162                                                 newNote.setTitle(dir.at(i));
7163                                                 NoteMetadata metadata = new NoteMetadata();
7164                                                 metadata.setDirty(true);
7165                                                 metadata.setGuid(newNote.getGuid());
7166                                                 listManager.addNote(newNote, metadata);
7167                                                 conn.getNoteTable().addNote(newNote, true);
7168                                                 noteTableView.insertRow(newNote, metadata, true, -1);
7169                                                 listManager.updateNoteContent(newNote.getGuid(), importer.getNoteContent());
7170                                                 listManager.countNotebookResults(listManager.getNoteIndex());
7171                                                 importedFiles.add(list.get(i).absoluteFilePath());
7172                                         }
7173                                 }
7174                         }
7175                 }
7176         
7177         
7178         }
7179         
7180         public void folderImportDelete(String dirName) {
7181                 logger.log(logger.LOW, "Inside folderImportDelete");
7182                 String whichOS = System.getProperty("os.name");
7183                 if (whichOS.contains("Windows")) 
7184                         dirName = dirName.replace('/','\\');
7185                 
7186                 FileImporter importer = new FileImporter(logger, conn);
7187                 QDir dir = new QDir(dirName);
7188                 List<QFileInfo> list = dir.entryInfoList();
7189                 String notebook = conn.getWatchFolderTable().getNotebook(dirName);
7190                 
7191                 for (int i=0; i<list.size(); i++){
7192                         logger.log(logger.LOW, "File found: " +list.get(i).fileName());
7193                         importer.setFileInfo(list.get(i));
7194                         importer.setFileName(list.get(i).absoluteFilePath());
7195                         
7196                         logger.log(logger.LOW, "File importing is a file: " +list.get(i).isFile());
7197                         logger.log(logger.LOW, "File importing is a valid: " +importer.isValidType());
7198                         if (list.get(i).isFile() && importer.isValidType()) {
7199                 
7200                                 if (!importer.importFile()) {
7201                                         // If we can't get to the file, it is probably locked.  We'll try again later.
7202                                         logger.log(logger.LOW, "Unable to save externally edited file.  Saving for later.");
7203                                         importFilesKeep.add(list.get(i).absoluteFilePath());
7204                                 } else {
7205                 
7206                                         Note newNote = importer.getNote();
7207                                         newNote.setNotebookGuid(notebook);
7208                                         newNote.setTitle(dir.at(i));
7209                                         NoteMetadata metadata = new NoteMetadata();
7210                                         metadata.setDirty(true);
7211                                         metadata.setGuid(newNote.getGuid());
7212                                         listManager.addNote(newNote, metadata);
7213                                         conn.getNoteTable().addNote(newNote, true);
7214                                         noteTableView.insertRow(newNote, metadata, true, -1);
7215                                         listManager.updateNoteContent(newNote.getGuid(), importer.getNoteContent());
7216                                         listManager.countNotebookResults(listManager.getNoteIndex());
7217                                         dir.remove(dir.at(i));
7218                                 }
7219                         }
7220                 }
7221         }
7222         
7223         
7224         //**************************************************
7225         //* External events
7226         //**************************************************
7227         private void externalFileEdited(String fileName) throws NoSuchAlgorithmException {
7228                 logger.log(logger.HIGH, "Entering exernalFileEdited");
7229
7230                 // Strip URL prefix and base dir path
7231                 String dPath = FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath());
7232                 String name = fileName.replace(dPath, "");
7233                 int pos = name.lastIndexOf('.');
7234                 String guid = name;
7235                 if (pos > -1) {
7236                         guid = guid.substring(0,pos);
7237                 }
7238                 pos = name.lastIndexOf(Global.attachmentNameDelimeter);
7239                 if (pos > -1) {
7240                         guid = name.substring(0, pos);
7241                 }
7242                 
7243                 QFile file = new QFile(fileName);
7244         if (!file.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly))) {
7245                 // If we can't get to the file, it is probably locked.  We'll try again later.
7246                 logger.log(logger.LOW, "Unable to save externally edited file.  Saving for later.");
7247                 externalFiles.add(fileName);
7248                 return;
7249                 }
7250                 QByteArray binData = file.readAll();
7251         file.close();
7252         if (binData.size() == 0) {
7253                 // If we can't get to the file, it is probably locked.  We'll try again later.
7254                 logger.log(logger.LOW, "Unable to save externally edited file.  Saving for later.");
7255                 externalFiles.add(fileName);
7256                 return;
7257         }
7258         
7259         Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
7260         if (r==null)
7261                 r = conn.getNoteTable().noteResourceTable.getNoteResource(Global.resourceMap.get(guid), true);
7262         if (r == null || r.getData() == null || r.getData().getBody() == null)
7263                 return;
7264         String oldHash = Global.byteArrayToHexString(r.getData().getBodyHash());
7265         MessageDigest md = MessageDigest.getInstance("MD5");
7266                 md.update(binData.toByteArray());
7267                 byte[] hash = md.digest();
7268         String newHash = Global.byteArrayToHexString(hash);
7269         if (r.getNoteGuid().equalsIgnoreCase(currentNoteGuid)) {
7270                 updateResourceContentHash(browserWindow, r.getGuid(), oldHash, newHash);
7271         }
7272         if (externalWindows.containsKey(r.getNoteGuid())) {
7273                 updateResourceContentHash(externalWindows.get(r.getNoteGuid()).getBrowserWindow(), 
7274                                 r.getGuid(), oldHash, newHash);
7275         }
7276         conn.getNoteTable().updateResourceContentHash(r.getNoteGuid(), oldHash, newHash);
7277         Data data = r.getData();
7278         data.setBody(binData.toByteArray());
7279         data.setBodyHash(hash);
7280         logger.log(logger.LOW, "externalFileEdited: " +data.getSize() +" bytes");
7281         r.setData(data);
7282         conn.getNoteTable().noteResourceTable.updateNoteResource(r,true);
7283         
7284         if (r.getNoteGuid().equals(currentNoteGuid)) {
7285                         QWebSettings.setMaximumPagesInCache(0);
7286                         QWebSettings.setObjectCacheCapacities(0, 0, 0);
7287                         refreshEvernoteNote(true);
7288                         browserWindow.getBrowser().triggerPageAction(WebAction.Reload);
7289         }
7290         
7291         if (externalWindows.containsKey(r.getNoteGuid())) {
7292                 QWebSettings.setMaximumPagesInCache(0);
7293                         QWebSettings.setObjectCacheCapacities(0, 0, 0);
7294                         externalWindows.get(r.getNoteGuid()).getBrowserWindow().getBrowser().triggerPageAction(WebAction.Reload);
7295                         
7296         }
7297         
7298                 logger.log(logger.HIGH, "Exiting externalFielEdited");
7299         }
7300         // This is a timer event that tries to save any external files that were edited.  This
7301         // is only needed if we couldn't save a file earlier.
7302         public void externalFileEditedSaver() {
7303                 for (int i=externalFiles.size()-1; i>=0; i--) {
7304                         try {
7305                                 logger.log(logger.MEDIUM, "Trying to save " +externalFiles.get(i));
7306                                 externalFileEdited(externalFiles.get(i));
7307                                 externalFiles.remove(i);
7308                         } catch (NoSuchAlgorithmException e) {e.printStackTrace();}
7309                 }
7310                 for (int i=0; i<importFilesKeep.size(); i++) {
7311                         try {
7312                                 logger.log(logger.MEDIUM, "Trying to save " +importFilesKeep.get(i));
7313                                 folderImportKeep(importFilesKeep.get(i));
7314                                 importFilesKeep.remove(i);
7315                         } catch (NoSuchAlgorithmException e) {e.printStackTrace();}
7316                 }
7317                 for (int i=0; i<importFilesDelete.size(); i++) {
7318                         logger.log(logger.MEDIUM, "Trying to save " +importFilesDelete.get(i));
7319                         folderImportDelete(importFilesDelete.get(i));
7320                         importFilesDelete.remove(i);
7321                 }
7322         }
7323         
7324         
7325         
7326         
7327         // If an attachment on the current note was edited, we need to update the current notes's hash
7328         // Update a note content's hash.  This happens if a resource is edited outside of NN
7329         public void updateResourceContentHash(BrowserWindow browser, String guid, String oldHash, String newHash) {
7330                 int position = browserWindow.getContent().indexOf("en-tag=\"en-media\" guid=\""+guid+"\" type=");
7331                 int endPos;
7332                 for (;position>-1;) {
7333                         endPos = browser.getContent().indexOf(">", position+1);
7334                         String oldSegment = browser.getContent().substring(position,endPos);
7335                         int hashPos = oldSegment.indexOf("hash=\"");
7336                         int hashEnd = oldSegment.indexOf("\"", hashPos+7);
7337                         String hash = oldSegment.substring(hashPos+6, hashEnd);
7338                         if (hash.equalsIgnoreCase(oldHash)) {
7339                                 String newSegment = oldSegment.replace(oldHash, newHash);
7340                                 String content = browser.getContent().substring(0,position) +
7341                                                  newSegment +
7342                                                  browser.getContent().substring(endPos);
7343                                 browser.setContent(new QByteArray(content));;
7344                         }
7345                         
7346                         position = browser.getContent().indexOf("en-tag=\"en-media\" guid=\""+guid+"\" type=", position+1);
7347                 }
7348         }
7349
7350
7351         //*************************************************
7352         //* Minimize to tray
7353         //*************************************************
7354         @Override
7355         public void changeEvent(QEvent e) {
7356                 if (e.type() == QEvent.Type.WindowStateChange) {
7357                         if (QSystemTrayIcon.isSystemTrayAvailable()) {
7358                                 if (isMinimized() && (Global.showTrayIcon() || Global.showTrayIcon())) {
7359                                         e.accept();
7360                                         QTimer.singleShot(10, this, "hide()");
7361                                         return;
7362                                 }
7363                                 if (isMaximized())
7364                                         windowMaximized = true;
7365                                 else 
7366                                         windowMaximized = false;
7367                         }
7368                 }
7369         }
7370         
7371         //*************************************************
7372         //* Check database userid & passwords
7373         //*************************************************
7374         private static boolean databaseCheck(String url,String userid, String userPassword, String cypherPassword) {
7375                         Connection connection;
7376                         
7377                         try {
7378                                 Class.forName("org.h2.Driver");
7379                         } catch (ClassNotFoundException e1) {
7380                                 e1.printStackTrace();
7381                                 System.exit(16);
7382                         }
7383
7384                         try {
7385                                 String passwordString = null;
7386                                 if (cypherPassword==null || cypherPassword.trim().equals(""))
7387                                         passwordString = userPassword;
7388                                 else
7389                                         passwordString = cypherPassword+" "+userPassword;
7390                                 connection = DriverManager.getConnection(url,userid,passwordString);
7391                         } catch (SQLException e) {
7392                                 return false;
7393                         }
7394                         try {
7395                                 connection.close();
7396                         } catch (SQLException e) {
7397                                 e.printStackTrace();
7398                         }
7399                         return true;
7400         }
7401
7402         //*************************************************
7403         //* View / Hide source HTML for a note
7404         //*************************************************
7405         public void viewSource() {
7406                 // すべてのタブに対して
7407         for(int i = 0; i < tabBrowser.count(); i++){
7408                 BrowserWindow browser = ((TabBrowse) tabBrowser.widget(i)).getBrowserWindow();
7409                 browser.showSource(menuBar.viewSource.isChecked());
7410         }
7411         }
7412         //*************************************************
7413         // Block the program.  This is used for things  
7414         // like async web calls.
7415         //*************************************************
7416         @SuppressWarnings("unused")
7417         private void blockApplication(BrowserWindow b) {
7418                 // Block all signals
7419                 waitCursor(true);
7420                 blockSignals(true);
7421                 
7422                 blockTimer = new QTimer();
7423                 blockTimer.setSingleShot(true);
7424                 blockTimer.setInterval(15000);
7425                 blockTimer.timeout.connect(this, "unblockApplication()");
7426                 blockingWindow  = b;
7427                 blockTimer.start();
7428         }
7429         
7430         @SuppressWarnings("unused")
7431         private void unblockApplication() {
7432                 waitCursor(false);
7433                 if (blockingWindow != null && new GregorianCalendar().getTimeInMillis() > blockingWindow.unblockTime && blockingWindow.unblockTime != -1) {
7434                         QMessageBox.critical(null, tr("No Response from CodeCogs") ,tr("Unable to contact CodeCogs for LaTeX formula."));
7435                         blockingWindow.unblockTime = -1;
7436                         blockingWindow.awaitingHttpResponse = false;
7437                 }
7438                 blockingWindow = null;
7439                 blockSignals(false);
7440         }
7441         
7442         // タブが変更された
7443         private void tabWindowChanged(int index) {
7444                 if (index < 0 || index >= tabBrowser.count()) {
7445                         return;
7446                 }
7447                 
7448                 saveNote();
7449
7450                 TabBrowse tab = (TabBrowse) tabBrowser.widget(index);
7451                 if (tab.getBrowserWindow().getNote() != null) {
7452                         currentNoteGuid = tab.getBrowserWindow().getNote().getGuid();
7453                         currentNote = tab.getBrowserWindow().getNote();
7454                 } else {
7455                         currentNoteGuid = "";
7456                         currentNote = null;
7457                 }
7458
7459                 // 選択ノートを更新
7460                 selectedNoteGUIDs.clear();
7461                 if (currentNoteGuid != null && !currentNoteGuid.equals("")) {
7462                         selectedNoteGUIDs.add(currentNoteGuid);
7463                 }
7464                 
7465                 // browserWindowを更新
7466                 browserWindow.noteSignal.noteChanged.disconnect(this,"setNoteDirty()");
7467                 browserWindow.focusLost.disconnect(this, "saveNote()");
7468                 browserWindow = tab.getBrowserWindow();
7469                 browserWindow.noteSignal.noteChanged.connect(this, "setNoteDirty()");
7470                 browserWindow.focusLost.connect(this, "saveNote()");
7471                 // メニューバーのボタンを新しいbrowserWindowに合わせる
7472                 menuBar.refreshTargetWindow();
7473                 
7474                 // 現在ゴミ箱かつ移るタブがアクティブなら通常テーブルに、現在通常テーブルかつこれから非アクティブのタブに移るならゴミ箱を表示させる
7475                 boolean nextIsActive;
7476                 if (tab.getBrowserWindow().getNote() != null) {
7477                         nextIsActive = tab.getBrowserWindow().getNote().isActive();
7478                 } else {
7479                         nextIsActive = true;
7480                 }
7481                 if (Global.showDeleted && nextIsActive) {
7482                         switchNoteTable(false);
7483                 } else if (!Global.showDeleted && !nextIsActive) {
7484                         switchNoteTable(true);
7485                 }
7486
7487                 // noteTableViewの選択を変更するとselectionChangedが発生してしまうので一度切断
7488                 noteTableView.selectionModel().selectionChanged.disconnect(this,"noteTableSelection()");
7489                 scrollToGuid(currentNoteGuid);
7490                 // 再接続
7491                 noteTableView.selectionModel().selectionChanged.connect(this,"noteTableSelection()");
7492
7493                 menuBar.noteDuplicateAction.setEnabled(true);
7494                 menuBar.noteOnlineHistoryAction.setEnabled(true);
7495                 menuBar.noteMergeAction.setEnabled(true);
7496                 
7497                 if (Global.showDeleted) {
7498                         menuBar.noteDuplicateAction.setEnabled(false);
7499                 }
7500                 if (!Global.isConnected) {
7501                         menuBar.noteOnlineHistoryAction.setEnabled(false);
7502                 }
7503                 menuBar.noteMergeAction.setEnabled(false);
7504                 try {
7505                         int row = noteTableView.selectionModel().selectedRows().get(0).row();
7506                         if (row == 0)
7507                                 upButton.setEnabled(false);
7508                         else
7509                                 upButton.setEnabled(true);
7510                         if (row < listManager.getNoteTableModel().rowCount() - 1)
7511                                 downButton.setEnabled(true);
7512                         else
7513                                 downButton.setEnabled(false);
7514                 } catch (Exception e) {
7515                         upButton.setEnabled(false);
7516                         downButton.setEnabled(false);
7517                 }
7518                 
7519                 int currentIndex = tabBrowser.currentIndex();
7520                 ArrayList<String> histGuids = historyGuids.get(currentIndex);
7521                 int histPosition = historyPosition.get(currentIndex);
7522
7523                 // prev, nextボタンの有効・無効化
7524                 nextButton.setEnabled(true);
7525                 prevButton.setEnabled(true);
7526
7527                 if (histPosition <= 1){
7528                         prevButton.setEnabled(false);
7529                 }
7530                 if (histPosition == histGuids.size()){
7531                         nextButton.setEnabled(false);
7532                 }
7533
7534                 refreshEvernoteNote(true);
7535
7536                 // 連想ノートリストを更新
7537                 rensoNoteListDock.getRensoNoteList().refreshRensoNoteList(currentNoteGuid);
7538         }
7539         
7540         // 生存ノートテーブル→ゴミ箱(またはその逆)に切り替える
7541         private void switchNoteTable(boolean toDeleted) {
7542         clearNotebookFilter();
7543         clearTagFilter();
7544         clearAttributeFilter();
7545         clearSavedSearchFilter();
7546         
7547         listManager.getSelectedNotebooks().clear();
7548         listManager.getSelectedTags().clear();
7549         listManager.setSelectedSavedSearch("");
7550     
7551         // toggle the add buttons
7552         newButton.setEnabled(!newButton.isEnabled());
7553         menuBar.noteAdd.setEnabled(newButton.isEnabled());
7554         menuBar.noteAddNewTab.setEnabled(newButton.isEnabled());
7555                 if (currentNoteGuid == null || currentNoteGuid.equals("")) {
7556                         menuBar.noteAddNewTab.setEnabled(false);
7557                 }
7558         menuBar.noteAdd.setVisible(true);
7559         
7560         if (!toDeleted) {       // 生存ノートテーブルへ
7561                 trashTree.itemSelectionChanged.disconnect(this, "trashTreeSelection()");
7562                 trashTree.clearSelection();
7563                 trashTree.itemSelectionChanged.connect(this, "trashTreeSelection()");
7564                 Global.showDeleted = false;
7565                 menuBar.noteRestoreAction.setEnabled(false);
7566                 menuBar.noteRestoreAction.setVisible(false);
7567                 // ゴミ箱から元の画面に戻す。連想ノートリストをONに。
7568                 rensoNoteListDock.setEnabled(true);
7569         } else {        // ゴミ箱へ
7570                 trashTree.itemSelectionChanged.disconnect(this, "trashTreeSelection()");
7571                 trashTree.setCurrentItem(trashTree.getTrashItem());
7572                 trashTree.itemSelectionChanged.connect(this, "trashTreeSelection()");
7573                 Global.showDeleted = true;
7574                 menuBar.noteRestoreAction.setEnabled(true);
7575                 menuBar.noteRestoreAction.setVisible(true);
7576                 // ゴミ箱を開く。連想ノートリストをOFFに。
7577                 rensoNoteListDock.setEnabled(false);
7578         }
7579         
7580         listManager.loadNotesIndex();
7581         // noteTableViewの選択を変更するとselectionChangedが発生してしまうので一度切断
7582         noteTableView.selectionModel().selectionChanged.disconnect(this,"noteTableSelection()");
7583         noteIndexUpdated(false);
7584         // 再接続
7585         noteTableView.selectionModel().selectionChanged.connect(this,"noteTableSelection()");
7586         
7587         browserWindow.setReadOnly(!newButton.isEnabled());
7588         }
7589
7590         // ユーザが連想ノートリストのアイテムを選択した時の処理
7591         @SuppressWarnings("unused")
7592         private void rensoNoteItemPressed(QListWidgetItem current) {
7593                 logger.log(logger.HIGH, "Nevernote.rensoNoteSelectionChangeに入った");
7594
7595                 rensoNotePressedItemGuid = rensoNoteListDock.getRensoNoteList().getNoteGuid(current);
7596                 
7597                 // 右クリックだったら終了
7598                 if (QApplication.mouseButtons().isSet(MouseButton.RightButton)) {
7599                         return;
7600                 }
7601                 
7602                 saveNote();
7603
7604                 String prevCurrentNoteGuid = new String(currentNoteGuid);
7605                 
7606                 for (int i = 0; i < noteTableView.model().rowCount(); i++) {
7607                         QModelIndex modelIndex = noteTableView.model().index(i,
7608                                         Global.noteTableGuidPosition);
7609                         if (modelIndex != null) {
7610                                 SortedMap<Integer, Object> ix = noteTableView.model().itemData(
7611                                                 modelIndex);
7612                                 String tableGuid = (String) ix.values().toArray()[0];
7613                                 if (tableGuid.equals(rensoNotePressedItemGuid)) {
7614                                         noteTableView.selectRow(i);
7615                                         break;
7616                                 }
7617                         }
7618                 }
7619                 
7620                 // 連想ノートリストアイテムクリック操作を記録
7621                 conn.getHistoryTable().addHistory("rensoItemClick", prevCurrentNoteGuid, currentNoteGuid);
7622
7623                 logger.log(logger.HIGH, "Nevernote.rensoNoteSelectionChangeを出た");
7624         }
7625         
7626         // 関連ノートリストからノートを除外する
7627         @SuppressWarnings("unused")
7628         private void excludeNote() {
7629                 if (rensoNotePressedItemGuid != null) {
7630                         saveNote();
7631                         excludeNote(rensoNotePressedItemGuid);
7632                 }
7633         }
7634         
7635         // 関連ノートリストからノートを除外する
7636         private void excludeNote(String guid) {
7637                 if (Global.verifyExclude()) {
7638                         String msg;
7639                         Note note = conn.getNoteTable().getNote(guid, false, false, false, false, false);
7640                         String title = note.getTitle();
7641                         if (title != null) {
7642                                 msg = new String(tr("Exclude note \"") +title +"\"?");
7643                         } else {                                
7644                                 msg = new String(tr("Exclude note selected note?"));
7645                         }
7646                         
7647                         if (QMessageBox.question(this, tr("Confirmation"), msg,
7648                                         QMessageBox.StandardButton.Yes, 
7649                                         QMessageBox.StandardButton.No)==StandardButton.No.value() && Global.verifyDelete() == true) {
7650                                         return;
7651                         }
7652                 }
7653                 
7654                 // Historyデータベースから除外するノートのデータを削除
7655                 conn.getHistoryTable().expungeHistory(guid, currentNoteGuid);
7656                 
7657                 // 除外ノートテーブルに追加
7658                 conn.getExcludedTable().addExclusion(guid, currentNoteGuid);
7659                 
7660                 rensoNoteListDock.getRensoNoteList().refreshRensoNoteList(currentNoteGuid);
7661         }
7662         
7663         // 関連ノートリストのノートにスターを付ける
7664         @SuppressWarnings("unused")
7665         private void starNote() {
7666                 if (rensoNotePressedItemGuid != null) {
7667                         saveNote();
7668                         starNote(rensoNotePressedItemGuid);
7669                 }
7670         }
7671         
7672         // 関連ノートリストのノートにスターを付ける
7673         private void starNote(String guid) {
7674                 // スター付きノートテーブルに追加
7675                 conn.getStaredTable().addStaredItem(currentNoteGuid, guid);
7676                 
7677                 rensoNoteListDock.getRensoNoteList().refreshRensoNoteList(currentNoteGuid);
7678         }
7679         
7680         // 関連ノートリストのノートからスターを外す
7681         @SuppressWarnings("unused")
7682         private void unstarNote() {
7683                 if (rensoNotePressedItemGuid != null) {
7684                         saveNote();
7685                         unstarNote(rensoNotePressedItemGuid);
7686                 }
7687         }
7688         
7689         // 関連ノートリストのノートからスターを外す
7690         private void unstarNote(String guid) {
7691                 // スター付きノートテーブルから削除
7692                 conn.getStaredTable().removeStaredItem(currentNoteGuid, guid);
7693                 
7694                 rensoNoteListDock.getRensoNoteList().refreshRensoNoteList(currentNoteGuid);
7695         }
7696         
7697         // currentNoteGuidを返す
7698         public String getCurrentNoteGuid() {
7699                 return currentNoteGuid;
7700         }
7701         
7702         @SuppressWarnings("unused")
7703         // タブ入れ替えによってタブインデックスが変わったので、インデックスで管理しているハッシュマップ達も入れ替える
7704         private void tabIndexChanged(int from, int to) {
7705                 // tabWindows
7706                 TabBrowse tab = tabWindows.get(from);
7707                 tabWindows.put(from, tabWindows.get(to));
7708                 tabWindows.put(to, tab);
7709                 // noteDirty
7710                 boolean isNoteDirty = noteDirty.get(from);
7711                 noteDirty.put(from, noteDirty.get(to));
7712                 noteDirty.put(to, isNoteDirty);
7713                 // inkNote
7714                 boolean isInkNote = inkNote.get(from);
7715                 inkNote.put(from, inkNote.get(to));
7716                 inkNote.put(to, isInkNote);
7717                 // readOnly
7718                 boolean isReadOnly = readOnly.get(from);
7719                 readOnly.put(from, readOnly.get(to));
7720                 readOnly.put(to, isReadOnly);
7721                 // historyGuids
7722                 ArrayList<String> histGuids = historyGuids.get(from);
7723                 historyGuids.put(from, historyGuids.get(to));
7724                 historyGuids.put(to, histGuids);
7725                 // historyPosition
7726                 int histPosition = historyPosition.get(from);
7727                 historyPosition.put(from, historyPosition.get(to));
7728                 historyPosition.put(to, histPosition);
7729                 // fromHistory
7730                 boolean fromHist = fromHistory.get(from);
7731                 fromHistory.put(from,  fromHistory.get(to));
7732                 fromHistory.put(to, fromHist);
7733         }
7734         
7735         // 連想ノートリストのgetter
7736         public RensoNoteList getRensoNoteList() {
7737                 return rensoNoteListDock.getRensoNoteList();
7738         }
7739         
7740         // 帯域制限の超過をユーザに通知
7741         @SuppressWarnings("unused")
7742         private void informRateLimit(Integer rateLimitDuration) {
7743                 QMessageBox.warning(this, tr("Rate limit reached"), tr("Evernote usage has been temporarily exceeded. Please try again in ") +  + rateLimitDuration + tr(" seconds."));
7744         }
7745         
7746         // ツールバーの「新規」ボタンの接続スロットを設定
7747         public void connectNewButtonSlot(String slot) {
7748                 newButton.triggered.disconnect();
7749                 newButton.triggered.connect(this, slot);
7750         }
7751 }