OSDN Git Service

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