OSDN Git Service

Change generation of files/paths in images dir to use FileManager
[neighbornote/NeighborNote.git] / src / cx / fbn / nevernote / NeverNote.java
1 /*
2  * This file is part of NeverNote 
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.security.MessageDigest;
25 import java.security.NoSuchAlgorithmException;
26 import java.sql.Connection;
27 import java.sql.DriverManager;
28 import java.sql.SQLException;
29 import java.text.SimpleDateFormat;
30 import java.util.ArrayList;
31 import java.util.Calendar;
32 import java.util.Collections;
33 import java.util.Comparator;
34 import java.util.Date;
35 import java.util.GregorianCalendar;
36 import java.util.HashMap;
37 import java.util.List;
38 import java.util.SortedMap;
39 import java.util.Vector;
40
41 import org.apache.thrift.TException;
42
43 import com.evernote.edam.error.EDAMNotFoundException;
44 import com.evernote.edam.error.EDAMSystemException;
45 import com.evernote.edam.error.EDAMUserException;
46 import com.evernote.edam.notestore.NoteFilter;
47 import com.evernote.edam.notestore.NoteVersionId;
48 import com.evernote.edam.type.Data;
49 import com.evernote.edam.type.Note;
50 import com.evernote.edam.type.NoteAttributes;
51 import com.evernote.edam.type.Notebook;
52 import com.evernote.edam.type.QueryFormat;
53 import com.evernote.edam.type.Resource;
54 import com.evernote.edam.type.SavedSearch;
55 import com.evernote.edam.type.Tag;
56 import com.evernote.edam.type.User;
57 import com.trolltech.qt.QThread;
58 import com.trolltech.qt.core.QByteArray;
59 import com.trolltech.qt.core.QDataStream;
60 import com.trolltech.qt.core.QDateTime;
61 import com.trolltech.qt.core.QDir;
62 import com.trolltech.qt.core.QFile;
63 import com.trolltech.qt.core.QFileInfo;
64 import com.trolltech.qt.core.QFileSystemWatcher;
65 import com.trolltech.qt.core.QIODevice;
66 import com.trolltech.qt.core.QModelIndex;
67 import com.trolltech.qt.core.QSize;
68 import com.trolltech.qt.core.QTemporaryFile;
69 import com.trolltech.qt.core.QTextCodec;
70 import com.trolltech.qt.core.QThreadPool;
71 import com.trolltech.qt.core.QTimer;
72 import com.trolltech.qt.core.QUrl;
73 import com.trolltech.qt.core.Qt;
74 import com.trolltech.qt.core.QIODevice.OpenModeFlag;
75 import com.trolltech.qt.core.Qt.SortOrder;
76 import com.trolltech.qt.core.Qt.WidgetAttribute;
77 import com.trolltech.qt.gui.QAbstractItemView;
78 import com.trolltech.qt.gui.QAction;
79 import com.trolltech.qt.gui.QApplication;
80 import com.trolltech.qt.gui.QCloseEvent;
81 import com.trolltech.qt.gui.QColor;
82 import com.trolltech.qt.gui.QComboBox;
83 import com.trolltech.qt.gui.QCursor;
84 import com.trolltech.qt.gui.QDesktopServices;
85 import com.trolltech.qt.gui.QDialog;
86 import com.trolltech.qt.gui.QFileDialog;
87 import com.trolltech.qt.gui.QGridLayout;
88 import com.trolltech.qt.gui.QHBoxLayout;
89 import com.trolltech.qt.gui.QIcon;
90 import com.trolltech.qt.gui.QImage;
91 import com.trolltech.qt.gui.QLabel;
92 import com.trolltech.qt.gui.QListWidget;
93 import com.trolltech.qt.gui.QMainWindow;
94 import com.trolltech.qt.gui.QMenu;
95 import com.trolltech.qt.gui.QMessageBox;
96 import com.trolltech.qt.gui.QPixmap;
97 import com.trolltech.qt.gui.QPrintDialog;
98 import com.trolltech.qt.gui.QPrinter;
99 import com.trolltech.qt.gui.QProgressBar;
100 import com.trolltech.qt.gui.QSizePolicy;
101 import com.trolltech.qt.gui.QSpinBox;
102 import com.trolltech.qt.gui.QSplashScreen;
103 import com.trolltech.qt.gui.QSplitter;
104 import com.trolltech.qt.gui.QStatusBar;
105 import com.trolltech.qt.gui.QSystemTrayIcon;
106 import com.trolltech.qt.gui.QTableWidgetItem;
107 import com.trolltech.qt.gui.QTextEdit;
108 import com.trolltech.qt.gui.QToolBar;
109 import com.trolltech.qt.gui.QTreeWidgetItem;
110 import com.trolltech.qt.gui.QAbstractItemView.ScrollHint;
111 import com.trolltech.qt.gui.QComboBox.InsertPolicy;
112 import com.trolltech.qt.gui.QFileDialog.AcceptMode;
113 import com.trolltech.qt.gui.QFileDialog.FileMode;
114 import com.trolltech.qt.gui.QMessageBox.StandardButton;
115 import com.trolltech.qt.gui.QSizePolicy.Policy;
116 import com.trolltech.qt.webkit.QWebSettings;
117 import com.trolltech.qt.webkit.QWebPage.WebAction;
118 import com.trolltech.qt.xml.QDomAttr;
119 import com.trolltech.qt.xml.QDomDocument;
120 import com.trolltech.qt.xml.QDomElement;
121 import com.trolltech.qt.xml.QDomNodeList;
122
123 import cx.fbn.nevernote.config.InitializationException;
124 import cx.fbn.nevernote.config.StartupConfig;
125 import cx.fbn.nevernote.dialog.AccountDialog;
126 import cx.fbn.nevernote.dialog.ConfigDialog;
127 import cx.fbn.nevernote.dialog.DatabaseLoginDialog;
128 import cx.fbn.nevernote.dialog.DatabaseStatus;
129 import cx.fbn.nevernote.dialog.FindDialog;
130 import cx.fbn.nevernote.dialog.LoginDialog;
131 import cx.fbn.nevernote.dialog.NotebookArchive;
132 import cx.fbn.nevernote.dialog.NotebookEdit;
133 import cx.fbn.nevernote.dialog.OnlineNoteHistory;
134 import cx.fbn.nevernote.dialog.SavedSearchEdit;
135 import cx.fbn.nevernote.dialog.TagEdit;
136 import cx.fbn.nevernote.dialog.ThumbnailViewer;
137 import cx.fbn.nevernote.dialog.WatchFolder;
138 import cx.fbn.nevernote.filters.EnSearch;
139 import cx.fbn.nevernote.gui.AttributeTreeWidget;
140 import cx.fbn.nevernote.gui.BrowserWindow;
141 import cx.fbn.nevernote.gui.DateAttributeFilterTable;
142 import cx.fbn.nevernote.gui.MainMenuBar;
143 import cx.fbn.nevernote.gui.NotebookTreeWidget;
144 import cx.fbn.nevernote.gui.PDFPreview;
145 import cx.fbn.nevernote.gui.SavedSearchTreeWidget;
146 import cx.fbn.nevernote.gui.TableView;
147 import cx.fbn.nevernote.gui.TagTreeWidget;
148 import cx.fbn.nevernote.gui.Thumbnailer;
149 import cx.fbn.nevernote.gui.TrashTreeWidget;
150 import cx.fbn.nevernote.signals.DBRunnerSignal;
151 import cx.fbn.nevernote.sql.DatabaseConnection;
152 import cx.fbn.nevernote.sql.runners.WatchFolderRecord;
153 import cx.fbn.nevernote.threads.DBRunner;
154 import cx.fbn.nevernote.threads.IndexRunner;
155 import cx.fbn.nevernote.threads.SyncRunner;
156 import cx.fbn.nevernote.utilities.AESEncrypter;
157 import cx.fbn.nevernote.utilities.ApplicationLogger;
158 import cx.fbn.nevernote.utilities.FileImporter;
159 import cx.fbn.nevernote.utilities.ListManager;
160 import cx.fbn.nevernote.utilities.SyncTimes;
161 import cx.fbn.nevernote.xml.ExportData;
162 import cx.fbn.nevernote.xml.ImportData;
163 import cx.fbn.nevernote.xml.XMLInsertHilight;
164
165
166 public class NeverNote extends QMainWindow{
167         
168         QStatusBar                              statusBar;                                      // Application status bar
169         
170         DatabaseConnection              conn;
171         
172         MainMenuBar                             menuBar;                                        // Main menu bar
173         FindDialog                              find;                                           // Text search in note dialog
174         List<String>                    emitLog;                                        // Messages displayed in the status bar;
175         QSystemTrayIcon                 trayIcon;                                       // little tray icon
176         QMenu                                   trayMenu;                                       // System tray menu
177         QAction                                 trayExitAction;                         // Exit the application
178         QAction                                 trayShowAction;                         // toggle the show/hide action          
179         QAction                                 trayAddNoteAction;                      // Add a note from the system tray
180         
181     NotebookTreeWidget          notebookTree;                           // List of notebooks
182     AttributeTreeWidget         attributeTree;                          // List of note attributes
183     TagTreeWidget                       tagTree;                                        // list of user created tags
184     SavedSearchTreeWidget       savedSearchTree;                        // list of saved searches
185     TrashTreeWidget                     trashTree;                                      // Trashcan
186     TableView                           noteTableView;                          //      List of notes (the widget).
187
188     public BrowserWindow        browserWindow;                          // Window containing browser & labels
189     QToolBar                            toolBar;                                        // The tool bar under the menu
190 //    QLineEdit                                 searchField;                            // The search filter bar on the toolbar
191     QComboBox                           searchField;                            // search filter bar on the toolbar;
192     boolean                                     searchPerformed = false;        // Search was done?
193     QProgressBar                        quotaBar;                                       // The current quota usage
194     
195     ApplicationLogger           logger;
196     List<String>                        selectedNotebookGUIDs;          // List of notebook GUIDs
197     List<String>                        selectedTagGUIDs;                       // List of selected tag GUIDs
198     List<String>                        selectedNoteGUIDs;                      // List of selected notes
199     String                                      selectedSavedSearchGUID;        // Currently selected saved searches
200     
201     NoteFilter                          filter;                                         // Note filter
202     String                                      currentNoteGuid;                        // GUID of the current note 
203     Note                                        currentNote;                            // The currently viewed note
204     boolean                                     noteDirty;                                      // Has the note been changed?
205     boolean                             inkNote;                    // if this is an ink note, it is read only
206   
207     QThread                                     dbThread;                                       // Thread to handle DB communication
208     ListManager                         listManager;                                    // DB runnable task
209     
210     List<QTemporaryFile>        tempFiles;                                      // Array of temporary files;
211     
212     QTimer                                      indexTimer;                                     // timer to start the index thread
213     IndexRunner                         indexRunner;                            // thread to index notes
214     QThread                                     indexThread;
215     
216     QTimer                                      syncTimer;                                      // Sync on an interval
217     QTimer                                      syncDelayTimer;                         // Sync delay to free up database
218     SyncRunner                          syncRunner;                                     // thread to do a sync.
219     QThread                                     syncThread;
220     QTimer                                      saveTimer;                                      // Timer to save note contents
221     
222     QTimer                                      authTimer;                                      // Refresh authentication
223     QTimer                                      externalFileSaveTimer;          // Save files altered externally
224     List<String>                        externalFiles;                          // External files to save later
225     List<String>                        importFilesKeep;                        // Auto-import files to save later
226     List<String>                        importFilesDelete;                      // Auto-import files to save later
227     
228     int                                         indexTime;                                      // how often to try and index
229     boolean                                     indexRunning;                           // Is indexing running?
230     boolean                                     indexDisabled;                          // Is indexing disabled?
231     
232     int                                         syncThreadsReady;                       // number of sync threads that are free
233     int                                         syncTime;                                       // Sync interval
234     boolean                                     syncRunning;                            // Is sync running?
235     boolean                                     automaticSync;                          // do sync automatically?
236     QTreeWidgetItem                     attributeTreeSelected;
237
238     QAction                             prevButton;                                     // Go to the previous item viewed
239     QAction                             nextButton;                                     // Go to the next item in the history
240     QAction                             downButton;                                     // Go to the next item in the list
241     QAction                             upButton;                                       // Go to the prev. item in the list;
242     QAction                             synchronizeButton;                      // Synchronize with Evernote
243     List<QIcon>                 synchronizeAnimation;           // Synchronize movie
244     QTimer                              synchronizeAnimationTimer;      // Timer to change animation button
245     int                                 synchronizeFrame;                       // Current frame being viewed
246     QAction                     printButton;                            // Print Button
247     QAction                             tagButton;                                      // Tag edit button
248     QAction                             attributeButton;                        // Attribute information button
249     QAction                     emailButton;                            // Email button
250     QAction                     deleteButton;                           // Delete button
251     QAction                             newButton;                                      // new Note Button;
252     QSpinBox                    zoomSpinner;                            // Zoom zoom
253     QAction                             searchClearButton;                      // Clear the search field
254     
255     QSplitter                   mainLeftRightSplitter;          // main splitter for left/right side
256     QSplitter                   leftSplitter1;                          // first left hand splitter
257     QSplitter                   browserIndexSplitter;           // splitter between note index & note text
258     
259     QFileSystemWatcher  importKeepWatcher;                      // Watch & keep auto-import
260     QFileSystemWatcher  importDeleteWatcher;            // Watch & Delete auto-import
261     List<String>                importedFiles;                          // History of imported files (so we don't import twice)
262     
263     OnlineNoteHistory   historyWindow;                          // online history window 
264     List<NoteVersionId> versions;                                       // history versions
265     
266     QTimer                              threadMonitorTimer;                     // Timer to watch threads.
267     int                                 dbThreadDeadCount=0;            // number of consecutive dead times for the db thread
268     int                                 syncThreadDeadCount=0;          // number of consecutive dead times for the sync thread
269     int                                 indexThreadDeadCount=0;         // number of consecutive dead times for the index thread
270     int                                 notebookThreadDeadCount=0;      // number of consecutive dead times for the notebook thread
271     int                                 tagDeadCount=0;                         // number of consecutive dead times for the tag thread
272     int                                 trashDeadCount=0;                       // number of consecutive dead times for the trash thread
273     int                                 saveThreadDeadCount=0;          // number of consecutive dead times for the save thread
274     
275     HashMap<String, String>             noteCache;                      // Cash of note content 
276     List<String>                historyGuids;                           // GUIDs of previously viewed items
277     int                                 historyPosition;                        // Position within the viewed items
278     boolean                             fromHistory;                            // Is this from the history queue?
279     String                              trashNoteGuid;                          // Guid to restore / set into or out of trash to save position
280     Thumbnailer                 preview;                                        // generate preview image
281     ThumbnailViewer             thumbnailViewer;                        // View preview thumbnail; 
282     
283     String iconPath = new String("classpath:cx/fbn/nevernote/icons/");
284         
285         
286     //***************************************************************
287     //***************************************************************
288     //** Constructor & main entry point
289     //***************************************************************
290     //***************************************************************
291     // Application Constructor  
292         public NeverNote()  {
293                                 
294                 if (!lockApplication()) {
295                         System.exit(0);
296                 }
297                 thread().setPriority(Thread.MAX_PRIORITY);
298                 
299                 logger = new ApplicationLogger("nevernote.log");
300                 logger.log(logger.HIGH, tr("Starting Application"));
301                 conn = new DatabaseConnection(logger, Global.mainThreadId);
302                 conn.dbSetup();
303                 
304                 logger.log(logger.EXTREME, tr("Creating index connection"));    
305                 logger.log(logger.EXTREME, tr("Building DB thread"));
306                 Global.dbRunnerSignal = new DBRunnerSignal();
307                 if (Global.getDatabaseUrl().toUpperCase().indexOf("CIPHER=") > -1) {
308                         boolean goodCheck = false;
309                         while (!goodCheck) {
310                                 DatabaseLoginDialog dialog = new DatabaseLoginDialog();
311                                 dialog.exec();
312                                 if (!dialog.okPressed())
313                                         System.exit(0);
314                                 Global.cipherPassword = dialog.getPassword();
315                                 goodCheck = databaseCheck(Global.getDatabaseUrl(), Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
316                         }
317                 }
318                 Global.dbRunner = new DBRunner(Global.getDatabaseUrl(), Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
319                 logger.log(logger.EXTREME, tr("Starting DB thread"));
320                 dbThread = new QThread(Global.dbRunner, "Database Thread");
321                 dbThread.start();
322                 logger.log(logger.EXTREME, tr("DB Thread has started"));
323                 Global.dbRunnerSignal.start.emit();
324                 logger.log(logger.EXTREME, tr("Setting main thread DB connection"));
325                 logger.log(logger.EXTREME, tr("main DB thread setup complete."));
326                 conn.checkDatabaseVersion();
327                 
328                 // Start building the invalid XML tables
329                 Global.invalidElements = conn.getInvalidXMLTable().getInvalidElements();
330                 List<String> elements = conn.getInvalidXMLTable().getInvalidAttributeElements();
331                 
332                 for (int i=0; i<elements.size(); i++) {
333                         Global.invalidAttributes.put(elements.get(i), conn.getInvalidXMLTable().getInvalidAttributes(elements.get(i)));
334                 }
335                 
336                 logger.log(logger.EXTREME, tr("Starting GUI build"));
337                 Global.originalPalette = QApplication.palette();
338                 QApplication.setStyle(Global.getStyle());
339                 if (Global.useStandardPalette())
340                         QApplication.setPalette(QApplication.style().standardPalette());
341         setWindowTitle("NeverNote");
342         
343         mainLeftRightSplitter = new QSplitter();
344         setCentralWidget(mainLeftRightSplitter);
345         leftSplitter1 = new QSplitter();
346         leftSplitter1.setOrientation(Qt.Orientation.Vertical);
347                 
348         browserIndexSplitter = new QSplitter();
349         browserIndexSplitter.setOrientation(Qt.Orientation.Vertical);
350         
351         //* Setup threads & thread timers
352         int indexRunnerCount = Global.getIndexThreads();
353         indexRunnerCount = 1;
354         QThreadPool.globalInstance().setMaxThreadCount(indexRunnerCount+5);     // increase max thread count
355
356                 logger.log(logger.EXTREME, tr("Building list manager"));
357         listManager = new ListManager(conn, logger, Global.mainThreadId);
358         
359                 logger.log(logger.EXTREME, tr("Building index runners & timers"));
360         indexRunner = new IndexRunner("indexRunner.log");
361                 indexThread = new QThread(indexRunner, "Index Thread");
362                 indexThread.start();
363                 
364         synchronizeAnimationTimer = new QTimer();
365         synchronizeAnimationTimer.timeout.connect(this, "updateSyncButton()");
366         
367                 indexTimer = new QTimer();
368                 indexTime = 1000*60*5;     // look for unindexed every 5 minutes
369 //              indexTime = 1000*5;
370                 indexTimer.start(indexTime);  // Start indexing timer
371                 indexTimer.timeout.connect(this, "indexTimer()");
372                 indexDisabled = false;
373                 indexRunning = false;
374                                 
375                 logger.log(logger.EXTREME, tr("Setting sync thread & timers"));
376                 syncThreadsReady=1;
377                 syncRunner = new SyncRunner("syncRunner.log");
378                 syncTime = new SyncTimes().timeValue(Global.getSyncInterval());
379                 syncTimer = new QTimer();
380                 syncTimer.timeout.connect(this, "syncTimer()");
381         syncRunner.status.message.connect(this, "setMessage(String)");
382         syncRunner.syncSignal.finished.connect(this, "syncThreadComplete(Boolean)");
383         syncRunner.syncSignal.errorDisconnect.connect(this, "remoteErrorDisconnect()");
384         syncRunning = false;    
385                 if (syncTime > 0) {
386                         automaticSync = true;
387                         syncTimer.start(syncTime*60*1000);
388                 } else {
389                         automaticSync = false;
390                         syncTimer.stop();
391                 }
392                 syncRunner.setEvernoteUpdateCount(Global.getEvernoteUpdateCount());
393                 syncThread = new QThread(syncRunner, "Synchronization Thread");
394                 syncThread.start();
395                 
396                 
397                 logger.log(logger.EXTREME, tr("Starting authentication timer"));
398                 authTimer = new QTimer();
399                 authTimer.timeout.connect(this, "authTimer()");
400                 authTimer.start(1000*60*15);
401                 syncRunner.syncSignal.authRefreshComplete.connect(this, "authRefreshComplete(boolean)");
402                 
403                 logger.log(logger.EXTREME, tr("Setting save note timer"));
404                 saveTimer = new QTimer();
405                 saveTimer.timeout.connect(this, "saveNote()");
406                 if (Global.getAutoSaveInterval() > 0) {
407                         saveTimer.setInterval(1000*60*Global.getAutoSaveInterval()); 
408 //                      saveTimer.setInterval(1000*10); // auto save every 20 seconds;
409                         saveTimer.start();
410                 }
411                 
412 //              Global.trace();
413                 logger.log(logger.EXTREME, tr("Starting external file monitor timer"));
414                 externalFileSaveTimer = new QTimer();
415                 externalFileSaveTimer.timeout.connect(this, "externalFileEditedSaver()");
416                 externalFileSaveTimer.setInterval(1000*5);   // save every 5 seconds;
417                 externalFiles = new ArrayList<String>();
418                 importFilesDelete = new ArrayList<String>();
419                 importFilesKeep = new ArrayList<String>();
420                 externalFileSaveTimer.start();
421                 
422         notebookTree = new NotebookTreeWidget();
423         attributeTree = new AttributeTreeWidget();
424         tagTree = new TagTreeWidget(conn);
425         savedSearchTree = new SavedSearchTreeWidget();
426         trashTree = new TrashTreeWidget();
427         noteTableView = new TableView(logger);
428         
429         QGridLayout leftGrid = new QGridLayout();
430         leftSplitter1.setLayout(leftGrid);
431         leftGrid.addWidget(notebookTree, 1, 1);
432         leftGrid.addWidget(tagTree,2,1);
433         leftGrid.addWidget(attributeTree,3,1);
434         leftGrid.addWidget(savedSearchTree,4,1);
435         leftGrid.addWidget(trashTree, 5, 1);
436         
437         // Setup the browser window
438         noteCache = new HashMap<String,String>();
439         browserWindow = new BrowserWindow(conn);
440
441         browserIndexSplitter.addWidget(noteTableView);
442         browserIndexSplitter.addWidget(browserWindow);
443         
444         mainLeftRightSplitter.addWidget(leftSplitter1);
445         mainLeftRightSplitter.addWidget(browserIndexSplitter);
446
447         searchField = new QComboBox();
448         searchField.setEditable(true);
449         searchField.activatedIndex.connect(this, "searchFieldChanged()");
450         searchField.setDuplicatesEnabled(false);
451         searchField.editTextChanged.connect(this,"searchFieldTextChanged(String)");
452         
453         quotaBar = new QProgressBar();
454         
455         // Setup the thumbnail viewer
456         thumbnailViewer = new ThumbnailViewer();
457         thumbnailViewer.upArrow.connect(this, "upAction()");
458         thumbnailViewer.downArrow.connect(this, "downAction()");
459         thumbnailViewer.leftArrow.connect(this, "nextViewedAction()");
460         thumbnailViewer.rightArrow.connect(this, "previousViewedAction()");
461
462         listManager.loadNotesIndex();
463         initializeNotebookTree();
464         initializeTagTree();
465         initializeSavedSearchTree();
466         attributeTree.itemClicked.connect(this, "attributeTreeClicked(QTreeWidgetItem, Integer)");
467         attributeTreeSelected = null;
468         initializeNoteTable();    
469
470                 selectedNoteGUIDs = new ArrayList<String>();
471                 statusBar = new QStatusBar();
472                 setStatusBar(statusBar);
473                 menuBar = new MainMenuBar(this);
474                 emitLog = new ArrayList<String>();
475                 
476                 tagTree.setDeleteAction(menuBar.tagDeleteAction);
477                 tagTree.setEditAction(menuBar.tagEditAction);
478                 tagTree.setAddAction(menuBar.tagAddAction);
479                 tagTree.setVisible(Global.isWindowVisible("tagTree"));
480                 tagTree.noteSignal.tagsAdded.connect(this, "tagsAdded(String, String)");
481                 menuBar.hideTags.setChecked(Global.isWindowVisible("tagTree"));
482                 listManager.tagSignal.listChanged.connect(this, "reloadTagTree()");
483         
484                 notebookTree.setDeleteAction(menuBar.notebookDeleteAction);
485                 notebookTree.setEditAction(menuBar.notebookEditAction);
486                 notebookTree.setAddAction(menuBar.notebookAddAction);
487                 notebookTree.setVisible(Global.isWindowVisible("notebookTree"));
488                 notebookTree.noteSignal.notebookChanged.connect(this, "updateNoteNotebook(String, String)");
489                 menuBar.hideNotebooks.setChecked(Global.isWindowVisible("notebookTree"));
490
491                 savedSearchTree.setAddAction(menuBar.savedSearchAddAction);
492                 savedSearchTree.setEditAction(menuBar.savedSearchEditAction);
493                 savedSearchTree.setDeleteAction(menuBar.savedSearchDeleteAction);
494                 savedSearchTree.itemSelectionChanged.connect(this, "updateSavedSearchSelection()");
495                 savedSearchTree.setVisible(Global.isWindowVisible("savedSearchTree"));
496                 menuBar.hideSavedSearches.setChecked(Global.isWindowVisible("savedSearchTree"));
497                         
498                 noteTableView.setAddAction(menuBar.noteAdd);
499                 noteTableView.setDeleteAction(menuBar.noteDelete);
500                 noteTableView.setRestoreAction(menuBar.noteRestoreAction);
501                 noteTableView.setNoteDuplicateAction(menuBar.noteDuplicateAction);
502                 noteTableView.setNoteHistoryAction(menuBar.noteOnlineHistoryAction);
503                 noteTableView.noteSignal.titleColorChanged.connect(this, "titleColorChanged(Integer)");
504                 noteTableView.setMergeNotesAction(menuBar.noteMergeAction);
505                 noteTableView.rowChanged.connect(this, "scrollToGuid(String)");
506                 noteTableView.resetViewport.connect(this, "scrollToCurrentGuid()");
507                 noteTableView.doubleClicked.connect(this, "listDoubleClick()");
508                 listManager.trashSignal.countChanged.connect(trashTree, "updateCounts(Integer)");
509                 trashTree.load();
510         trashTree.itemSelectionChanged.connect(this, "trashTreeSelection()");
511                 trashTree.setEmptyAction(menuBar.emptyTrashAction);
512                 trashTree.setVisible(Global.isWindowVisible("trashTree"));
513                 menuBar.hideTrash.setChecked(Global.isWindowVisible("trashTree"));
514                 trashTree.updateCounts(listManager.getTrashCount());
515
516                 attributeTree.setVisible(Global.isWindowVisible("attributeTree"));
517                 menuBar.hideAttributes.setChecked(Global.isWindowVisible("attributeTree"));
518
519                 noteTableView.setVisible(Global.isWindowVisible("noteList"));
520                 menuBar.hideNoteList.setChecked(Global.isWindowVisible("noteList"));
521                 
522                 if (!Global.isWindowVisible("editorButtonBar"))
523                         toggleEditorButtonBar();
524                 if (!Global.isWindowVisible("leftPanel"))
525                         menuBar.hideLeftSide.setChecked(true);
526                 
527                 setMenuBar(menuBar);
528                 setupToolBar();
529                 find = new FindDialog();
530                 find.getOkButton().clicked.connect(this, "doFindText()");
531                 
532                 // Setup the tray icon menu bar
533                 trayShowAction = new QAction("Show/Hide", this);
534                 trayExitAction = new QAction("Exit", this);
535                 trayAddNoteAction = new QAction("Add Note", this);
536                 
537                 trayExitAction.triggered.connect(this, "close()");
538                 trayAddNoteAction.triggered.connect(this, "addNote()");
539                 trayShowAction.triggered.connect(this, "trayToggleVisible()");
540                 
541                 trayMenu = new QMenu(this);
542                 trayMenu.addAction(trayAddNoteAction);
543                 trayMenu.addAction(trayShowAction);
544                 trayMenu.addAction(trayExitAction);
545                 
546                 
547                 trayIcon = new QSystemTrayIcon(this);
548                 trayIcon.setToolTip("NeverNote");
549                 trayIcon.setContextMenu(trayMenu);
550                 trayIcon.activated.connect(this, "trayActivated(com.trolltech.qt.gui.QSystemTrayIcon$ActivationReason)");
551
552                 currentNoteGuid="";
553                 currentNoteGuid = Global.getLastViewedNoteGuid();
554         historyGuids = new ArrayList<String>();
555         historyPosition = 0;
556         fromHistory = false;
557                 noteDirty = false;
558                 if (!currentNoteGuid.trim().equals("")) {
559                         currentNote = conn.getNoteTable().getNote(currentNoteGuid, true,true,false,false,true);
560                 }
561                 
562                 noteIndexUpdated(true);
563                 showColumns();
564                 menuBar.showEditorBar.setChecked(Global.isWindowVisible("editorButtonBar"));
565                 if (menuBar.showEditorBar.isChecked())
566                 showEditorButtons();
567                 tagIndexUpdated(true);
568                 savedSearchIndexUpdated();
569                 notebookIndexUpdated();
570                 updateQuotaBar();
571         setupSyncSignalListeners();        
572         setupBrowserSignalListeners();
573         setupIndexListeners();
574               
575         
576         tagTree.tagSignal.listChanged.connect(this, "tagIndexUpdated()");
577         tagTree.showAllTags(true);
578
579                 QIcon appIcon = new QIcon(iconPath+"nevernote.png");
580         setWindowIcon(appIcon);
581         trayIcon.setIcon(appIcon);
582         if (Global.showTrayIcon())
583                 trayIcon.show();
584         else
585                 trayIcon.hide();
586         
587         scrollToGuid(currentNoteGuid);
588         if (Global.automaticLogin()) {
589                 remoteConnect();
590                 if (Global.isConnected)
591                         syncTimer();
592         }
593         setupFolderImports();
594         
595         loadStyleSheet();
596         restoreWindowState();
597         
598         if (Global.mimicEvernoteInterface) {
599                 notebookTree.selectGuid("");
600         }
601         
602         threadMonitorTimer = new QTimer();
603         threadMonitorTimer.timeout.connect(this, "threadMonitorCheck()");
604         threadMonitorTimer.start(1000*10);  // Check for threads every 10 seconds;              
605         
606         historyGuids.add(currentNoteGuid);
607         historyPosition = 1;
608         
609         int sortCol = Global.getSortColumn();
610                 int sortOrder = Global.getSortOrder();
611                 noteTableView.sortByColumn(sortCol, SortOrder.resolve(sortOrder));
612         }
613
614         
615         // Main entry point
616         public static void main(String[] args) {
617                 QApplication.initialize(args);
618                 QPixmap pixmap = new QPixmap("classpath:cx/fbn/nevernote/icons/splash_logo.png");
619                 QSplashScreen splash = new QSplashScreen(pixmap);
620
621                 try {
622                     initializeGlobalSettings(args);
623                 } catch (InitializationException e) {
624                         QMessageBox.critical(null, "Startup error", "Aborting: " + e.getMessage());
625                         return;
626                 }
627
628                 boolean showSplash = Global.isWindowVisible("SplashScreen");
629                 if (showSplash) 
630                         splash.show();
631                 NeverNote application = new NeverNote();
632                 application.setAttribute(WidgetAttribute.WA_DeleteOnClose, true);
633                 if (Global.wasWindowMaximized())
634                         application.showMaximized();
635                 else
636                         application.show();
637                 if (showSplash)
638                         splash.finish(application);
639                 QApplication.exec();
640                 System.out.println("Goodbye.");
641                 QApplication.exit();
642         }
643
644         private static void initializeGlobalSettings(String[] args) throws InitializationException {
645                 StartupConfig startupConfig = new StartupConfig();
646
647                 for (String arg : args) {
648                         String lower = arg.toLowerCase();
649                         if (lower.startsWith("--name="))
650                                 startupConfig.setName(arg.substring(arg.indexOf('=') + 1));
651                         if (lower.startsWith("--home="))
652                                 startupConfig.setHomeDirPath(arg.substring(arg.indexOf('=') + 1));
653                         if (lower.startsWith("--disable-viewing"))
654                                 startupConfig.setDisableViewing(true);
655                 }
656
657                 Global.setup(startupConfig);
658         }
659
660     // Exit point
661         @Override
662         public void closeEvent(QCloseEvent event) {     
663                 logger.log(logger.HIGH, "Entering NeverNote.closeEvent");
664                 waitCursor(true);
665                 
666                 if (currentNote!= null & browserWindow!=null) {
667                         if (!currentNote.getTitle().equals(browserWindow.getTitle()))
668                                 conn.getNoteTable().updateNoteTitle(currentNote.getGuid(), browserWindow.getTitle());
669                 }
670                 saveNote();
671                 setMessage("Beginning shutdown.");
672
673                 externalFileEditedSaver();
674                 if (Global.isConnected && Global.synchronizeOnClose()) {
675                         setMessage("Performing synchronization before closing.");
676                         syncRunner.addWork("SYNC");
677                 }
678                 setMessage("Closing Program.");
679                 threadMonitorTimer.stop();
680
681                 syncRunner.addWork("STOP");
682                 indexRunner.addWork("STOP");
683                 saveNote();
684                 listManager.stop();
685                 saveWindowState();
686
687                 if (tempFiles != null)
688                         tempFiles.clear();
689
690                 browserWindow.noteSignal.tagsChanged.disconnect();
691                 browserWindow.noteSignal.titleChanged.disconnect();
692                 browserWindow.noteSignal.noteChanged.disconnect();
693                 browserWindow.noteSignal.notebookChanged.disconnect();
694                 browserWindow.noteSignal.createdDateChanged.disconnect();
695                 browserWindow.noteSignal.alteredDateChanged.disconnect();
696                 syncRunner.searchSignal.listChanged.disconnect();
697                 syncRunner.tagSignal.listChanged.disconnect();
698         syncRunner.notebookSignal.listChanged.disconnect();
699         syncRunner.noteIndexSignal.listChanged.disconnect();
700
701
702                 int position = noteTableView.header.visualIndex(Global.noteTableCreationPosition);
703                 Global.setColumnPosition("noteTableCreationPosition", position);
704                 position = noteTableView.header.visualIndex(Global.noteTableTagPosition);
705                 Global.setColumnPosition("noteTableTagPosition", position);
706                 position = noteTableView.header.visualIndex(Global.noteTableNotebookPosition);
707                 Global.setColumnPosition("noteTableNotebookPosition", position);
708                 position = noteTableView.header.visualIndex(Global.noteTableChangedPosition);
709                 Global.setColumnPosition("noteTableChangedPosition", position);
710                 position = noteTableView.header.visualIndex(Global.noteTableAuthorPosition);
711                 Global.setColumnPosition("noteTableAuthorPosition", position);
712                 position = noteTableView.header.visualIndex(Global.noteTableSourceUrlPosition);
713                 Global.setColumnPosition("noteTableSourceUrlPosition", position);
714                 position = noteTableView.header.visualIndex(Global.noteTableSubjectDatePosition);
715                 Global.setColumnPosition("noteTableSubjectDatePosition", position);
716                 position = noteTableView.header.visualIndex(Global.noteTableTitlePosition);
717                 Global.setColumnPosition("noteTableTitlePosition", position);
718                 position = noteTableView.header.visualIndex(Global.noteTableSynchronizedPosition);
719                 Global.setColumnPosition("noteTableSynchronizedPosition", position);
720                 
721                 saveNoteIndexWidth();
722                 
723                 int width = notebookTree.columnWidth(0);
724                 Global.setColumnWidth("notebookTreeName", width);
725                 width = tagTree.columnWidth(0);
726                 Global.setColumnWidth("tagTreeName", width);
727                 
728                 Global.saveWindowMaximized(isMaximized());
729                 Global.saveCurrentNoteGuid(currentNoteGuid);
730                         
731                 int sortCol = noteTableView.proxyModel.sortColumn();
732                 int sortOrder = noteTableView.proxyModel.sortOrder().value();
733                 Global.setSortColumn(sortCol);
734                 Global.setSortOrder(sortOrder);
735                 
736                 hide();
737                 trayIcon.hide();
738                 Global.keepRunning = false;
739                 try {
740                         logger.log(logger.MEDIUM, "Waiting for indexThread to stop");
741                         indexRunner.thread().join(50);
742                         logger.log(logger.MEDIUM, "Index thread has stopped");
743                 } catch (InterruptedException e1) {
744                         e1.printStackTrace();
745                 }
746                 if (!syncRunner.isIdle()) {
747                         try {
748                                 logger.log(logger.MEDIUM, "Waiting for syncThread to stop");
749                                 syncThread.join();
750                                 logger.log(logger.MEDIUM, "Sync thread has stopped");
751                         } catch (InterruptedException e1) {
752                                 e1.printStackTrace();
753                         }
754                 }
755
756                 logger.log(logger.EXTREME, "Shutting down database");
757                 conn.dbShutdown();
758                 logger.log(logger.EXTREME, "Waiting for DB thread to terminate");
759                 try {
760                         dbThread.join();
761                 } catch (InterruptedException e) {
762                         e.printStackTrace();
763                 }
764                 logger.log(logger.EXTREME, "DB Thread has terminated");
765                 unlockApplication();
766                 logger.log(logger.HIGH, "Leaving NeverNote.closeEvent");
767         }
768
769         public void setMessage(String s) {
770                 logger.log(logger.HIGH, "Entering NeverNote.setMessage");
771                 logger.log(logger.HIGH, "Message: " +s);
772                 statusBar.showMessage(s);
773                 emitLog.add(s);
774                 logger.log(logger.HIGH, "Leaving NeverNote.setMessage");
775         }
776                 
777         private void waitCursor(boolean wait) {
778                 if (wait)
779                         QApplication.setOverrideCursor(new QCursor(Qt.CursorShape.WaitCursor));
780                 else
781                         QApplication.restoreOverrideCursor();
782         }
783         
784         private void setupIndexListeners() {
785                 indexRunner.noteSignal.noteIndexed.connect(this, "indexThreadComplete(String)");
786                 indexRunner.resourceSignal.resourceIndexed.connect(this, "indexThreadComplete(String)");
787 //                      indexRunner.threadSignal.indexNeeded.connect(listManager, "setIndexNeeded(String, String, Boolean)");
788         }
789         private void setupSyncSignalListeners() {
790                 syncRunner.tagSignal.listChanged.connect(this, "tagIndexUpdated()");
791         syncRunner.searchSignal.listChanged.connect(this, "savedSearchIndexUpdated()");
792         syncRunner.notebookSignal.listChanged.connect(this, "notebookIndexUpdated()");
793         syncRunner.noteIndexSignal.listChanged.connect(this, "noteIndexUpdated(boolean)");
794         syncRunner.noteSignal.quotaChanged.connect(this, "updateQuotaBar()");
795         
796 //              syncRunner.syncSignal.setSequenceDate.connect(this,"setSequenceDate(long)");
797                 syncRunner.syncSignal.saveUploadAmount.connect(this,"saveUploadAmount(long)");
798 //              syncRunner.syncSignal.setUpdateSequenceNumber.connect(this,"setUpdateSequenceNumber(int)");
799                 syncRunner.syncSignal.saveUserInformation.connect(this,"saveUserInformation(User)");
800                 syncRunner.syncSignal.saveEvernoteUpdateCount.connect(this,"saveEvernoteUpdateCount(int)");
801                 
802                 syncRunner.noteSignal.guidChanged.connect(this, "noteGuidChanged(String, String)");
803                 syncRunner.noteSignal.noteChanged.connect(this, "invalidateNoteCache(String, String)");
804                 syncRunner.resourceSignal.resourceGuidChanged.connect(this, "noteResourceGuidChanged(String,String,String)");
805                 
806                 syncRunner.syncSignal.refreshLists.connect(this, "refreshLists()");
807         }
808         
809         private void setupBrowserSignalListeners() {
810                 
811                 browserWindow.fileWatcher.fileChanged.connect(this, "externalFileEdited(String)");
812                 browserWindow.noteSignal.tagsChanged.connect(this, "updateNoteTags(String, List)");
813             browserWindow.noteSignal.tagsChanged.connect(this, "updateListTags(String, List)");
814                 browserWindow.noteSignal.noteChanged.connect(this, "invalidateNoteCache(String, String)");
815             browserWindow.noteSignal.noteChanged.connect(this, "setNoteDirty()");
816             browserWindow.noteSignal.titleChanged.connect(listManager, "updateNoteTitle(String, String)");
817             browserWindow.noteSignal.titleChanged.connect(this, "updateListTitle(String, String)");
818             browserWindow.noteSignal.notebookChanged.connect(this, "updateNoteNotebook(String, String)");
819             browserWindow.noteSignal.createdDateChanged.connect(listManager, "updateNoteCreatedDate(String, QDateTime)");
820             browserWindow.noteSignal.createdDateChanged.connect(this, "updateListDateCreated(String, QDateTime)");
821             browserWindow.noteSignal.alteredDateChanged.connect(listManager, "updateNoteAlteredDate(String, QDateTime)");
822             browserWindow.noteSignal.alteredDateChanged.connect(this, "updateListDateChanged(String, QDateTime)");
823             browserWindow.noteSignal.subjectDateChanged.connect(listManager, "updateNoteSubjectDate(String, QDateTime)");
824             browserWindow.noteSignal.subjectDateChanged.connect(this, "updateListDateSubject(String, QDateTime)");
825             browserWindow.noteSignal.authorChanged.connect(listManager, "updateNoteAuthor(String, String)");
826             browserWindow.noteSignal.authorChanged.connect(this, "updateListAuthor(String, String)");
827             browserWindow.noteSignal.sourceUrlChanged.connect(listManager, "updateNoteSourceUrl(String, String)");
828             browserWindow.noteSignal.sourceUrlChanged.connect(this, "updateListSourceUrl(String, String)");
829             browserWindow.focusLost.connect(this, "saveNote()");
830             browserWindow.resourceSignal.contentChanged.connect(this, "externalFileEdited(String)");
831 //          browserWindow.resourceSignal.externalFileEdit.connect(this, "saveResourceLater(String, String)");
832         }
833         private boolean lockApplication() {
834                                 
835                 // NFC TODO: who creates this - H2? should it be parameterized with databaseName like in RDatabaseConnection? 
836                 String fileName = Global.getFileManager().getDbDirPath("NeverNote.lock.db");
837 //              QFile.remove(fileName);
838                 if (QFile.exists(fileName)) {
839                         QMessageBox.question(this, "Lock File Detected",
840                                         "While starting I've found a database lock file.\n" +
841                                         "to prevent multiple instances from accessing the database \n"+
842                                         "at the same time.  Please stop any other program, or (if you\n" +
843                                         "are sure nothing else is using the database) remove the file\n" +
844                                         fileName +".");
845                         return false;
846                         
847                 }
848                 return true;
849 /*              String fileName = Global.currentDir +"nevernote.lock";
850
851                 
852                 if (QFile.exists(fileName)) {
853                         if (QMessageBox.question(this, "Confirmation",
854                                 "While starting I've found a lock file.  This file is used to prevent multiple "+
855                                 "instances of this program running at once.  If NeverNote has crashed this " +
856                                 "is just a file that wasn't cleaned up and you can safely, "+
857                                 "continue, but if there is another instance of this running you are " +
858                                 "running the risk of creating problems.\n\n" +
859                                 "Are you sure you want to continue?",
860                                 QMessageBox.StandardButton.Yes, 
861                                 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
862                                         return false;
863                                 }
864                 }
865                 
866                 QFile file = new QFile(fileName);
867                 file.open(OpenModeFlag.WriteOnly);
868                 file.write(new QByteArray("This file is used to prevent multiple instances " +
869                                 "of NeverNote running more than once.  " +
870                                 "It should be deleted when NeverNote ends"));
871                 file.close();
872                 return true;
873 */
874         }
875         private void unlockApplication() {
876                 // NFC TODO: should this be removed? Looks like H2 now handles the locking, which it will clean up itself. See #lockApplication.
877                 String fileName = Global.getFileManager().getHomeDirPath("nevernote.lock");
878                 if (QFile.exists(fileName)) {
879                         QFile.remove(fileName);
880                 }
881         }
882         
883
884         //***************************************************************
885         //***************************************************************
886         //* Settings and look & feel
887         //***************************************************************
888         //***************************************************************
889         @SuppressWarnings("unused")
890         private void settings() {
891                 logger.log(logger.HIGH, "Entering NeverNote.settings");
892         ConfigDialog settings = new ConfigDialog(this);
893         String dateFormat = Global.getDateFormat();
894         String timeFormat = Global.getTimeFormat();
895         
896         settings.exec();
897         if (Global.showTrayIcon())
898                 trayIcon.show();
899         else
900                 trayIcon.hide();
901         showColumns();
902         if (menuBar.showEditorBar.isChecked())
903                 showEditorButtons();
904         
905         // Reset the save timer
906         if (Global.getAutoSaveInterval() > 0)
907                         saveTimer.setInterval(1000*60*Global.getAutoSaveInterval());
908         else
909                 saveTimer.stop();
910         
911         // This is a hack to force a reload of the index in case the date or time changed.
912 //        if (!dateFormat.equals(Global.getDateFormat()) ||
913 //                      !timeFormat.equals(Global.getTimeFormat())) {
914                 noteCache.clear();
915                 noteIndexUpdated(true);
916 //        }
917         
918         logger.log(logger.HIGH, "Leaving NeverNote.settings");
919         }
920         // Restore things to the way they were
921         private void restoreWindowState() {
922                 // We need to name things or this doesn't work.
923                 setObjectName("NeverNote");
924                 mainLeftRightSplitter.setObjectName("mainLeftRightSplitter");
925                 browserIndexSplitter.setObjectName("browserIndexSplitter");
926                 leftSplitter1.setObjectName("leftSplitter1");   
927                 
928                 // Restore the actual positions.
929                 restoreGeometry(Global.restoreGeometry(objectName()));
930         mainLeftRightSplitter.restoreState(Global.restoreState(mainLeftRightSplitter.objectName()));
931         browserIndexSplitter.restoreState(Global.restoreState(browserIndexSplitter.objectName()));
932         leftSplitter1.restoreState(Global.restoreState(leftSplitter1.objectName()));
933        
934         }
935         // Save window positions for the next start
936         private void saveWindowState() {
937                 Global.saveGeometry(objectName(), saveGeometry());
938                 Global.saveState(mainLeftRightSplitter.objectName(), mainLeftRightSplitter.saveState());
939                 Global.saveState(browserIndexSplitter.objectName(), browserIndexSplitter.saveState());
940                 Global.saveState(leftSplitter1.objectName(), leftSplitter1.saveState());
941         }    
942         // Load the style sheet
943         private void loadStyleSheet() {
944                 String fileName = Global.currentDir +"qss"+System.getProperty("file.separator")+ "default.qss";
945                 QFile file = new QFile(fileName);
946                 file.open(OpenModeFlag.ReadOnly);
947                 String styleSheet = file.readAll().toString();
948                 file.close();
949                 setStyleSheet(styleSheet);
950         }
951         // Save column widths for the next time
952         private void saveNoteIndexWidth() {
953                 int width;
954         width = noteTableView.getColumnWidth(Global.noteTableCreationPosition);
955         Global.setColumnWidth("noteTableCreationPosition", width);
956                 width = noteTableView.getColumnWidth(Global.noteTableChangedPosition);
957                 Global.setColumnWidth("noteTableChangedPosition", width);
958                 width = noteTableView.getColumnWidth(Global.noteTableGuidPosition);
959                 Global.setColumnWidth("noteTableGuidPosition", width);
960                 width = noteTableView.getColumnWidth(Global.noteTableNotebookPosition);
961                 Global.setColumnWidth("noteTableNotebookPosition", width);
962                 width = noteTableView.getColumnWidth(Global.noteTableTagPosition);
963                 Global.setColumnWidth("noteTableTagPosition", width);
964                 width = noteTableView.getColumnWidth(Global.noteTableTitlePosition);
965                 Global.setColumnWidth("noteTableTitlePosition", width);
966                 width = noteTableView.getColumnWidth(Global.noteTableSourceUrlPosition);
967                 Global.setColumnWidth("noteTableSourceUrlPosition", width);
968                 width = noteTableView.getColumnWidth(Global.noteTableAuthorPosition);
969                 Global.setColumnWidth("noteTableAuthorPosition", width);
970                 width = noteTableView.getColumnWidth(Global.noteTableSubjectDatePosition);
971                 Global.setColumnWidth("noteTableSubjectDatePosition", width);
972                 width = noteTableView.getColumnWidth(Global.noteTableSynchronizedPosition);
973                 Global.setColumnWidth("noteTableSynchronizedPosition", width);
974         }
975         
976         
977     //***************************************************************
978     //***************************************************************
979     //** These functions deal with Notebook menu items
980     //***************************************************************
981     //***************************************************************
982     // Setup the tree containing the user's notebooks.
983     private void initializeNotebookTree() {       
984         logger.log(logger.HIGH, "Entering NeverNote.initializeNotebookTree");
985         notebookTree.itemSelectionChanged.connect(this, "notebookTreeSelection()");
986         listManager.notebookSignal.refreshNotebookTreeCounts.connect(notebookTree, "updateCounts(List, List)");
987  //     notebookTree.resize(Global.getSize("notebookTree"));
988         logger.log(logger.HIGH, "Leaving NeverNote.initializeNotebookTree");
989     }   
990     // Listener when a notebook is selected
991     @SuppressWarnings("unused")
992         private void notebookTreeSelection() {
993                 logger.log(logger.HIGH, "Entering NeverNote.notebookTreeSelection");
994
995                 clearTrashFilter();
996                 clearAttributeFilter();
997                 clearSavedSearchFilter();
998                 if (Global.mimicEvernoteInterface) {
999                         clearTagFilter();
1000                         searchField.clear();
1001                 }
1002                 
1003                 menuBar.noteRestoreAction.setVisible(false);            
1004         menuBar.notebookEditAction.setEnabled(true);
1005         menuBar.notebookDeleteAction.setEnabled(true);
1006         List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1007         QTreeWidgetItem currentSelection;
1008         selectedNotebookGUIDs.clear();
1009         if (!Global.mimicEvernoteInterface) {
1010                 for (int i=0; i<selections.size(); i++) {
1011                         currentSelection = selections.get(i);
1012                         selectedNotebookGUIDs.add(currentSelection.text(2));
1013                 }
1014         
1015                 
1016                 // There is the potential for no notebooks to be selected if this 
1017                 // happens then we make it look like all notebooks were selecetd.
1018                 // If that happens, just select the "all notebooks"
1019                 selections = notebookTree.selectedItems();
1020                 if (selections.size()==0) {
1021                         selectedNotebookGUIDs.clear();
1022                         menuBar.notebookEditAction.setEnabled(false);
1023                         menuBar.notebookDeleteAction.setEnabled(false);
1024                 }
1025         } else {
1026                 String guid = "";
1027                 if (selections.size() > 0)
1028                         guid = (selections.get(0).text(2));
1029                 if (!guid.equals(""))
1030                         selectedNotebookGUIDs.add(guid);
1031         }
1032         listManager.setSelectedNotebooks(selectedNotebookGUIDs);
1033         listManager.loadNotesIndex();
1034         noteIndexUpdated(false);
1035                 logger.log(logger.HIGH, "Leaving NeverNote.notebookTreeSelection");
1036
1037     }
1038     private void clearNotebookFilter() {
1039         notebookTree.blockSignals(true);
1040         notebookTree.clearSelection();
1041                 menuBar.noteRestoreAction.setVisible(false);
1042         menuBar.notebookEditAction.setEnabled(false);
1043         menuBar.notebookDeleteAction.setEnabled(false);
1044         selectedNotebookGUIDs.clear();
1045         listManager.setSelectedNotebooks(selectedNotebookGUIDs);
1046         notebookTree.blockSignals(false);
1047     }
1048         // Triggered when the notebook DB has been updated
1049         private void notebookIndexUpdated() {
1050                 logger.log(logger.HIGH, "Entering NeverNote.notebookIndexUpdated");
1051                 if (selectedNotebookGUIDs == null)
1052                         selectedNotebookGUIDs = new ArrayList<String>();
1053                 List<Notebook> books = conn.getNotebookTable().getAll();
1054                 for (int i=books.size()-1; i>=0; i--) {
1055                         for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
1056                                 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(books.get(i).getGuid())) {
1057                                         books.remove(i);
1058                                         j=listManager.getArchiveNotebookIndex().size();
1059                                 }
1060                         }
1061                 }
1062                 
1063                 
1064                 listManager.countNotebookResults(listManager.getNoteIndex());
1065                 notebookTree.blockSignals(true);
1066         notebookTree.load(books, listManager.getLocalNotebooks());
1067         for (int i=selectedNotebookGUIDs.size()-1; i>=0; i--) {
1068                 boolean found = notebookTree.selectGuid(selectedNotebookGUIDs.get(i));
1069                 if (!found)
1070                         selectedNotebookGUIDs.remove(i);
1071         }
1072         notebookTree.blockSignals(false);
1073         
1074                 logger.log(logger.HIGH, "Leaving NeverNote.notebookIndexUpdated");
1075     }
1076     // Show/Hide note information
1077         private void toggleNotebookWindow() {
1078                 logger.log(logger.HIGH, "Entering NeverNote.toggleNotebookWindow");
1079         if (notebookTree.isVisible())
1080                 notebookTree.hide();
1081         else
1082                 notebookTree.show();
1083         menuBar.hideNotebooks.setChecked(notebookTree.isVisible());
1084         Global.saveWindowVisible("notebookTree", notebookTree.isVisible());
1085         logger.log(logger.HIGH, "Leaving NeverNote.toggleNotebookWindow");
1086     }   
1087         // Add a new notebook
1088         @SuppressWarnings("unused")
1089         private void addNotebook() {
1090                 logger.log(logger.HIGH, "Inside NeverNote.addNotebook");
1091                 NotebookEdit edit = new NotebookEdit();
1092                 edit.setNotebooks(listManager.getNotebookIndex());
1093                 edit.exec();
1094         
1095                 if (!edit.okPressed())
1096                         return;
1097         
1098                 Calendar currentTime = new GregorianCalendar();
1099                 Long l = new Long(currentTime.getTimeInMillis());
1100                 String randint = new String(Long.toString(l));
1101         
1102                 Notebook newBook = new Notebook();
1103                 newBook.setUpdateSequenceNum(0);
1104                 newBook.setGuid(randint);
1105                 newBook.setName(edit.getNotebook());
1106                 newBook.setServiceCreated(new Date().getTime());
1107                 newBook.setServiceUpdated(new Date().getTime());
1108                 newBook.setDefaultNotebook(false);
1109                 newBook.setPublished(false);
1110                 
1111                 listManager.getNotebookIndex().add(newBook);
1112                 if (edit.isLocal())
1113                         listManager.getLocalNotebooks().add(newBook.getGuid());
1114                 conn.getNotebookTable().addNotebook(newBook, true, edit.isLocal());
1115                 notebookIndexUpdated();
1116                 listManager.countNotebookResults(listManager.getNoteIndex());
1117 //              notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
1118                 logger.log(logger.HIGH, "Leaving NeverNote.addNotebook");
1119         }
1120         // Edit an existing notebook
1121         @SuppressWarnings("unused")
1122         private void editNotebook() {
1123                 logger.log(logger.HIGH, "Entering NeverNote.editNotebook");
1124                 NotebookEdit edit = new NotebookEdit();
1125                 edit.setTitle("Edit Notebook");
1126                 edit.setLocalCheckboxEnabled(false);
1127                 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1128                 QTreeWidgetItem currentSelection;
1129                 currentSelection = selections.get(0);
1130                 edit.setNotebook(currentSelection.text(0));
1131                 edit.setNotebooks(listManager.getNotebookIndex());
1132                 edit.exec();
1133         
1134                 if (!edit.okPressed())
1135                         return;
1136         
1137                 String guid = currentSelection.text(2);
1138                 updateListNotebookName(currentSelection.text(0), edit.getNotebook());
1139                 currentSelection.setText(0, edit.getNotebook());
1140                 
1141                 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1142                         if (listManager.getNotebookIndex().get(i).getGuid().equals(guid)) {
1143                                 listManager.getNotebookIndex().get(i).setName(edit.getNotebook());
1144                                 conn.getNotebookTable().updateNotebook(listManager.getNotebookIndex().get(i), true);
1145                                 i=listManager.getNotebookIndex().size();
1146                         }
1147                 }
1148                 
1149                 // Build a list of non-closed notebooks
1150                 List<Notebook> nbooks = new ArrayList<Notebook>();
1151                 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1152                         boolean found=false;
1153                         for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
1154                                 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid()))
1155                                         found = true;
1156                         }
1157                         if (!found)
1158                                 nbooks.add(listManager.getNotebookIndex().get(i));
1159                 }
1160                 
1161                 browserWindow.setNotebookList(nbooks);
1162                 logger.log(logger.HIGH, "Leaving NeverNote.editNotebook");
1163         }
1164         // Delete an existing notebook
1165         @SuppressWarnings("unused")
1166         private void deleteNotebook() {
1167                 logger.log(logger.HIGH, "Entering NeverNote.deleteNotebook");
1168                 boolean assigned = false;
1169                 // Check if any notes have this notebook
1170                 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1171         for (int i=0; i<selections.size(); i++) {
1172                 QTreeWidgetItem currentSelection;
1173                 currentSelection = selections.get(i);
1174                 String guid = currentSelection.text(2);
1175                 for (int j=0; j<listManager.getNoteIndex().size(); j++) {
1176                         String noteGuid = listManager.getNoteIndex().get(j).getNotebookGuid();
1177                         if (noteGuid.equals(guid)) {
1178                                 assigned = true;
1179                                 j=listManager.getNoteIndex().size();
1180                                 i=selections.size();
1181                         }
1182                 }
1183         }
1184                 if (assigned) {
1185                         QMessageBox.information(this, "Unable to Delete", "Some of the selected notebook(s) contain notes.\n"+
1186                                         "Please delete the notes or move them to another notebook before deleting any notebooks.");
1187                         return;
1188                 }
1189                 
1190                 if (conn.getNotebookTable().getAll().size() == 1) {
1191                         QMessageBox.information(this, "Unable to Delete", "You must have at least one notebook.");
1192                         return;
1193                 }
1194         
1195         // If all notebooks are clear, verify the delete
1196                 if (QMessageBox.question(this, "Confirmation", "Delete the selected notebooks?",
1197                         QMessageBox.StandardButton.Yes, 
1198                         QMessageBox.StandardButton.No)==StandardButton.No.value()) {
1199                         return;
1200                 }
1201                 
1202                 // If confirmed, delete the notebook
1203         for (int i=selections.size()-1; i>=0; i--) {
1204                 QTreeWidgetItem currentSelection;
1205                 currentSelection = selections.get(i);
1206                 String guid = currentSelection.text(2);
1207                 conn.getNotebookTable().expungeNotebook(guid, true);
1208                 listManager.deleteNotebook(guid);
1209         }
1210 //        for (int i=<dbRunner.getLocalNotebooks().size()-1; i>=0; i--) {
1211  //             if (dbRunner.getLocalNotebooks().get(i).equals(arg0))
1212  //       }
1213         notebookTree.load(listManager.getNotebookIndex(), listManager.getLocalNotebooks());
1214         listManager.countNotebookResults(listManager.getNoteIndex());
1215 //              notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
1216         logger.log(logger.HIGH, "Entering NeverNote.deleteNotebook");
1217         }
1218         // A note's notebook has been updated
1219         @SuppressWarnings("unused")
1220         private void updateNoteNotebook(String guid, String notebookGuid) {
1221                 
1222                 // Update the list manager
1223                 listManager.updateNoteNotebook(guid, notebookGuid);
1224                 listManager.countNotebookResults(listManager.getNoteIndex());
1225 //              notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());    
1226                 
1227                 // Find the name of the notebook
1228                 String notebookName = null;
1229                 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1230                         if (listManager.getNotebookIndex().get(i).getGuid().equals(notebookGuid)) {
1231                                 notebookName = listManager.getNotebookIndex().get(i).getName();
1232                                 i=listManager.getNotebookIndex().size();
1233                         }
1234                 }
1235                 
1236                 // If we found the name, update the browser window
1237                 if (notebookName != null) {
1238                         updateListNoteNotebook(guid, notebookName);
1239                         if (guid.equals(currentNoteGuid)) {
1240                                 int pos =  browserWindow.notebookBox.findText(notebookName);
1241                                 if (pos >=0)
1242                                         browserWindow.notebookBox.setCurrentIndex(pos);
1243                         }
1244                 }
1245                 
1246                 // If we're dealing with the current note, then we need to be sure and update the notebook there
1247                 if (guid.equals(currentNoteGuid)) {
1248                         if (currentNote != null) {
1249                                 currentNote.setNotebookGuid(notebookGuid);
1250                         }
1251                 }
1252         }
1253         // Open/close notebooks
1254         @SuppressWarnings("unused")
1255         private void closeNotebooks() {
1256                 NotebookArchive na = new NotebookArchive(listManager.getNotebookIndex(), listManager.getArchiveNotebookIndex());
1257                 na.exec();
1258                 if (!na.okClicked())
1259                         return;
1260                 
1261                 waitCursor(true);
1262                 listManager.getArchiveNotebookIndex().clear();
1263                 
1264                 for (int i=na.getClosedBookList().count()-1; i>=0; i--) {
1265                         String text = na.getClosedBookList().takeItem(i).text();
1266                         for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1267                                 if (listManager.getNotebookIndex().get(j).getName().equalsIgnoreCase(text)) {
1268                                         Notebook n = listManager.getNotebookIndex().get(j);
1269                                         conn.getNotebookTable().setArchived(n.getGuid(),true);
1270                                         listManager.getArchiveNotebookIndex().add(n);
1271                                         j=listManager.getNotebookIndex().size();
1272                                 }
1273                         }
1274                 }
1275                 
1276                 for (int i=na.getOpenBookList().count()-1; i>=0; i--) {
1277                         String text = na.getOpenBookList().takeItem(i).text();
1278                         for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1279                                 if (listManager.getNotebookIndex().get(j).getName().equalsIgnoreCase(text)) {
1280                                         Notebook n = listManager.getNotebookIndex().get(j);
1281                                         conn.getNotebookTable().setArchived(n.getGuid(),false);
1282                                         j=listManager.getNotebookIndex().size();
1283                                 }
1284                         }
1285                 }
1286                 
1287                 listManager.loadNotesIndex();
1288                 notebookIndexUpdated();
1289                 noteIndexUpdated(true);
1290 //              noteIndexUpdated(false);
1291                 
1292                 // Build a list of non-closed notebooks
1293                 List<Notebook> nbooks = new ArrayList<Notebook>();
1294                 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1295                         boolean found=false;
1296                         for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
1297                                 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid()))
1298                                         found = true;
1299                         }
1300                         if (!found)
1301                                 nbooks.add(listManager.getNotebookIndex().get(i));
1302                 }
1303                 waitCursor(false);
1304                 browserWindow.setNotebookList(nbooks);
1305         }
1306
1307         
1308         
1309         
1310         
1311     //***************************************************************
1312     //***************************************************************
1313     //** These functions deal with Tag menu items
1314     //***************************************************************
1315     //***************************************************************
1316         // Add a new notebook
1317         @SuppressWarnings("unused")
1318         private void addTag() {
1319                 logger.log(logger.HIGH, "Inside NeverNote.addTag");
1320                 TagEdit edit = new TagEdit();
1321                 edit.setTagList(listManager.getTagIndex());
1322                 edit.exec();
1323         
1324                 if (!edit.okPressed())
1325                         return;
1326         
1327                 Calendar currentTime = new GregorianCalendar();
1328                 Long l = new Long(currentTime.getTimeInMillis());
1329                 String randint = new String(Long.toString(l));
1330         
1331                 Tag newTag = new Tag();
1332                 newTag.setUpdateSequenceNum(0);
1333                 newTag.setGuid(randint);
1334                 newTag.setName(edit.getTag());
1335                 conn.getTagTable().addTag(newTag, true);
1336                 listManager.getTagIndex().add(newTag);
1337                 reloadTagTree();
1338                 
1339                 logger.log(logger.HIGH, "Leaving NeverNote.addTag");
1340         }
1341         private void reloadTagTree() {
1342                 logger.log(logger.HIGH, "Entering NeverNote.reloadTagTree");
1343                 tagIndexUpdated(false);
1344                 boolean filter = false;
1345                 listManager.countTagResults(listManager.getNoteIndex());
1346                 if (notebookTree.selectedItems().size() > 0 
1347                                                   && !notebookTree.selectedItems().get(0).text(0).equalsIgnoreCase("All Notebooks"))
1348                                                   filter = true;
1349                 if (tagTree.selectedItems().size() > 0)
1350                         filter = true;
1351                 tagTree.showAllTags(!filter);
1352                 logger.log(logger.HIGH, "Leaving NeverNote.reloadTagTree");
1353         }
1354         // Edit an existing tag
1355         @SuppressWarnings("unused")
1356         private void editTag() {
1357                 logger.log(logger.HIGH, "Entering NeverNote.editTag");
1358                 TagEdit edit = new TagEdit();
1359                 edit.setTitle("Edit Tag");
1360                 List<QTreeWidgetItem> selections = tagTree.selectedItems();
1361                 QTreeWidgetItem currentSelection;
1362                 currentSelection = selections.get(0);
1363                 edit.setTag(currentSelection.text(0));
1364                 edit.setTagList(listManager.getTagIndex());
1365                 edit.exec();
1366         
1367                 if (!edit.okPressed())
1368                         return;
1369         
1370                 String guid = currentSelection.text(2);
1371                 currentSelection.setText(0,edit.getTag());
1372                 
1373                 for (int i=0; i<listManager.getTagIndex().size(); i++) {
1374                         if (listManager.getTagIndex().get(i).getGuid().equals(guid)) {
1375                                 listManager.getTagIndex().get(i).setName(edit.getTag());
1376                                 conn.getTagTable().updateTag(listManager.getTagIndex().get(i), true);
1377                                 updateListTagName(guid);
1378                                 if (currentNote != null && currentNote.getTagGuids().contains(guid))
1379                                         browserWindow.setTag(getTagNamesForNote(currentNote));
1380                                 logger.log(logger.HIGH, "Leaving NeverNote.editTag");
1381                                 return;
1382                         }
1383                 }
1384                 browserWindow.setTag(getTagNamesForNote(currentNote));
1385                 logger.log(logger.HIGH, "Leaving NeverNote.editTag...");
1386         }
1387         // Delete an existing tag
1388         @SuppressWarnings("unused")
1389         private void deleteTag() {
1390                 logger.log(logger.HIGH, "Entering NeverNote.deleteTag");
1391                 
1392                 if (QMessageBox.question(this, "Confirmation", "Delete the selected tags?",
1393                         QMessageBox.StandardButton.Yes, 
1394                         QMessageBox.StandardButton.No)==StandardButton.No.value()) {
1395                                                         return;
1396                 }
1397                 
1398                 List<QTreeWidgetItem> selections = tagTree.selectedItems();
1399         for (int i=selections.size()-1; i>=0; i--) {
1400                 QTreeWidgetItem currentSelection;
1401                 currentSelection = selections.get(i);                   
1402                 removeTagItem(currentSelection.text(2));
1403         }
1404         tagIndexUpdated(true);
1405         listManager.countTagResults(listManager.getNoteIndex());
1406 //              tagTree.updateCounts(listManager.getTagCounter());
1407         logger.log(logger.HIGH, "Leaving NeverNote.deleteTag");
1408         }
1409         // Remove a tag tree item.  Go recursively down & remove the children too
1410         private void removeTagItem(String guid) {
1411         for (int j=listManager.getTagIndex().size()-1; j>=0; j--) {             
1412                 String parent = listManager.getTagIndex().get(j).getParentGuid();
1413                 if (parent != null && parent.equals(guid)) {            
1414                         //Remove this tag's children
1415                         removeTagItem(listManager.getTagIndex().get(j).getGuid());
1416                 }
1417         }
1418         //Now, remove this tag
1419         removeListTagName(guid);
1420         conn.getTagTable().expungeTag(guid, true);                      
1421         for (int a=0; a<listManager.getTagIndex().size(); a++) {
1422                 if (listManager.getTagIndex().get(a).getGuid().equals(guid)) {
1423                         listManager.getTagIndex().remove(a);
1424                         return;
1425                 }
1426         }
1427         }
1428         // Setup the tree containing the user's tags
1429     private void initializeTagTree() {
1430         logger.log(logger.HIGH, "Entering NeverNote.initializeTagTree");
1431         tagTree.itemSelectionChanged.connect(this, "tagTreeSelection()");
1432         listManager.tagSignal.refreshTagTreeCounts.connect(tagTree, "updateCounts(List)");
1433         logger.log(logger.HIGH, "Leaving NeverNote.initializeTagTree");
1434     }
1435     // Listener when a tag is selected
1436     @SuppressWarnings("unused")
1437         private void tagTreeSelection() {
1438         logger.log(logger.HIGH, "Entering NeverNote.tagTreeSelection");
1439         
1440         List<QTreeWidgetItem> x = tagTree.selectedItems();
1441         for (int i=0; i<x.size(); i++) {
1442         }
1443         
1444         clearTrashFilter();
1445         clearAttributeFilter();
1446         clearSavedSearchFilter();
1447         
1448                 menuBar.noteRestoreAction.setVisible(false);
1449                 
1450         List<QTreeWidgetItem> selections = tagTree.selectedItems();
1451         QTreeWidgetItem currentSelection;
1452         selectedTagGUIDs.clear();
1453         for (int i=0; i<selections.size(); i++) {
1454                 currentSelection = selections.get(i);
1455                 selectedTagGUIDs.add(currentSelection.text(2));
1456         }
1457         if (selections.size() > 0) {
1458                 menuBar.tagEditAction.setEnabled(true);
1459                 menuBar.tagDeleteAction.setEnabled(true);
1460         }
1461         else {
1462                 menuBar.tagEditAction.setEnabled(false);
1463                 menuBar.tagDeleteAction.setEnabled(false);
1464         }
1465         listManager.setSelectedTags(selectedTagGUIDs);
1466         listManager.loadNotesIndex();
1467         noteIndexUpdated(false);
1468         logger.log(logger.HIGH, "Leaving NeverNote.tagTreeSelection");
1469     }
1470     // trigger the tag index to be refreshed
1471     @SuppressWarnings("unused")
1472         private void tagIndexUpdated() {
1473         tagIndexUpdated(true);
1474     }
1475     private void tagIndexUpdated(boolean reload) {
1476         logger.log(logger.HIGH, "Entering NeverNote.tagIndexUpdated");
1477                 if (selectedTagGUIDs == null)
1478                         selectedTagGUIDs = new ArrayList<String>();
1479 //              selectedTagGUIDs.clear();  // clear out old entries
1480
1481                 tagTree.blockSignals(true);
1482                 if (reload)
1483                         tagTree.load(listManager.getTagIndex());
1484         for (int i=selectedTagGUIDs.size()-1; i>=0; i--) {
1485                 boolean found = tagTree.selectGuid(selectedTagGUIDs.get(i));
1486                 if (!found)
1487                         selectedTagGUIDs.remove(i);
1488         }
1489         tagTree.blockSignals(false);
1490         
1491                 browserWindow.setTag(getTagNamesForNote(currentNote));
1492         logger.log(logger.HIGH, "Leaving NeverNote.tagIndexUpdated");
1493     }   
1494     // Show/Hide note information
1495         private void toggleTagWindow() {
1496                 logger.log(logger.HIGH, "Entering NeverNote.toggleTagWindow");
1497         if (tagTree.isVisible())
1498                 tagTree.hide();
1499         else
1500                 tagTree.show();
1501         menuBar.hideTags.setChecked(tagTree.isVisible());
1502         Global.saveWindowVisible("tagTree", tagTree.isVisible());
1503         logger.log(logger.HIGH, "Leaving NeverNote.toggleTagWindow");
1504     }   
1505         // A note's tags have been updated
1506         @SuppressWarnings("unused")
1507         private void updateNoteTags(String guid, List<String> tags) {
1508                 listManager.saveNoteTags(guid, tags);
1509                 listManager.countTagResults(listManager.getNoteIndex());
1510                 StringBuffer names = new StringBuffer("");
1511                 for (int i=0; i<tags.size(); i++) {
1512                         names = names.append(tags.get(i));
1513                         if (i<tags.size()-1) {
1514                                 names.append(Global.tagDelimeter + " ");
1515                         }
1516                 }
1517                 browserWindow.setTag(names.toString());
1518                 noteDirty = true;
1519 //              tagTree.updateCounts(listManager.getTagCounter());
1520         }
1521         // Get a string containing all tag names for a note
1522         private String getTagNamesForNote(Note n) {
1523                 logger.log(logger.HIGH, "Entering NeverNote.getTagNamesForNote");
1524                 if (n==null || n.getGuid() == null || n.getGuid().equals(""))
1525                         return "";
1526                 StringBuffer buffer = new StringBuffer(100);
1527                 Vector<String> v = new Vector<String>();
1528                 List<String> guids = n.getTagGuids();
1529                 
1530                 if (guids == null) 
1531                         return "";
1532                 
1533                 for (int i=0; i<guids.size(); i++) {
1534                         v.add(listManager.getTagNameByGuid(guids.get(i)));
1535                 }
1536                 Comparator<String> comparator = Collections.reverseOrder();
1537                 Collections.sort(v,comparator);
1538                 Collections.reverse(v);
1539                 
1540                 for (int i = 0; i<v.size(); i++) {
1541                         if (i>0) 
1542                                 buffer.append(", ");
1543                         buffer.append(v.get(i));
1544                 }
1545                 
1546                 logger.log(logger.HIGH, "Leaving NeverNote.getTagNamesForNote");
1547                 return buffer.toString();
1548         }       
1549         // Tags were added via dropping notes from the note list
1550         @SuppressWarnings("unused")
1551         private void tagsAdded(String noteGuid, String tagGuid) {
1552                 String tagName = null;
1553                 for (int i=0; i<listManager.getTagIndex().size(); i++) {
1554                         if (listManager.getTagIndex().get(i).getGuid().equals(tagGuid)) {
1555                                 tagName = listManager.getTagIndex().get(i).getName();
1556                                 i=listManager.getTagIndex().size();
1557                         }
1558                 }
1559                 if (tagName == null)
1560                         return;
1561                 
1562                 for (int i=0; i<noteTableView.model.rowCount(); i++) {
1563                         QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
1564                         if (modelIndex != null) {
1565                                 SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
1566                                 String titleGuid = (String)ix.values().toArray()[0];
1567                                 if (titleGuid.equals(noteGuid)) {
1568                                         String text = (String)noteTableView.model.data(i, Global.noteTableTagPosition);
1569                                         if (!text.trim().equals(""))
1570                                                 text = text + Global.tagDelimeter + " " +tagName;
1571                                         else
1572                                                 text = tagName;
1573                                         noteTableView.model.setData(i, Global.noteTableTagPosition, text);
1574                                         noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
1575                                         if (noteGuid.equals(currentNoteGuid))
1576                                                 browserWindow.setTag(text);
1577                                         i=noteTableView.model.rowCount();
1578                                 }
1579                         }
1580                 }
1581         }
1582         private void clearTagFilter() {
1583                 tagTree.blockSignals(true);
1584                 tagTree.clearSelection();
1585                 menuBar.noteRestoreAction.setVisible(false);
1586                 menuBar.tagEditAction.setEnabled(false);
1587                 menuBar.tagDeleteAction.setEnabled(false);
1588                 selectedTagGUIDs.clear();
1589         listManager.setSelectedTags(selectedTagGUIDs);
1590         tagTree.blockSignals(false);
1591         }
1592         
1593         
1594     //***************************************************************
1595     //***************************************************************
1596     //** These functions deal with Saved Search menu items
1597     //***************************************************************
1598     //***************************************************************
1599         // Add a new notebook
1600         @SuppressWarnings("unused")
1601         private void addSavedSearch() {
1602                 logger.log(logger.HIGH, "Inside NeverNote.addSavedSearch");
1603                 SavedSearchEdit edit = new SavedSearchEdit();
1604                 edit.setSearchList(listManager.getSavedSearchIndex());
1605                 edit.exec();
1606         
1607                 if (!edit.okPressed())
1608                         return;
1609         
1610                 Calendar currentTime = new GregorianCalendar();         
1611                 Long l = new Long(currentTime.getTimeInMillis());
1612                 String randint = new String(Long.toString(l));
1613         
1614                 SavedSearch search = new SavedSearch();
1615                 search.setUpdateSequenceNum(0);
1616                 search.setGuid(randint);
1617                 search.setName(edit.getName());
1618                 search.setQuery(edit.getQuery());
1619                 search.setFormat(QueryFormat.USER);
1620                 listManager.getSavedSearchIndex().add(search);
1621                 conn.getSavedSearchTable().addSavedSearch(search, true);
1622                 savedSearchIndexUpdated();
1623                 logger.log(logger.HIGH, "Leaving NeverNote.addSavedSearch");
1624         }
1625         // Edit an existing tag
1626         @SuppressWarnings("unused")
1627         private void editSavedSearch() {
1628                 logger.log(logger.HIGH, "Entering NeverNote.editSavedSearch");
1629                 SavedSearchEdit edit = new SavedSearchEdit();
1630                 edit.setTitle("Edit Search");
1631                 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
1632                 QTreeWidgetItem currentSelection;
1633                 currentSelection = selections.get(0);
1634                 String guid = currentSelection.text(1);
1635                 SavedSearch s = conn.getSavedSearchTable().getSavedSearch(guid);
1636                 edit.setName(currentSelection.text(0));
1637                 edit.setQuery(s.getQuery());
1638                 edit.setSearchList(listManager.getSavedSearchIndex());
1639                 edit.exec();
1640         
1641                 if (!edit.okPressed())
1642                         return;
1643         
1644                 List<SavedSearch> list = listManager.getSavedSearchIndex();
1645                 SavedSearch search = null;
1646                 boolean found = false;
1647                 for (int i=0; i<list.size(); i++) {
1648                         search = list.get(i);
1649                         if (search.getGuid().equals(guid)) {
1650                                 i=list.size();
1651                                 found = true;
1652                         }
1653                 }
1654                 if (!found)
1655                         return;
1656                 search.setName(edit.getName());
1657                 search.setQuery(edit.getQuery());
1658                 conn.getSavedSearchTable().updateSavedSearch(search, true);
1659                 savedSearchIndexUpdated();
1660                 logger.log(logger.HIGH, "Leaving NeverNote.editSavedSearch");
1661         }
1662         // Delete an existing tag
1663         @SuppressWarnings("unused")
1664         private void deleteSavedSearch() {
1665                 logger.log(logger.HIGH, "Entering NeverNote.deleteSavedSearch");
1666                 
1667                 if (QMessageBox.question(this, "Confirmation", "Delete the selected search?",
1668                         QMessageBox.StandardButton.Yes, 
1669                         QMessageBox.StandardButton.No)==StandardButton.No.value()) {
1670                                                         return;
1671                 }
1672                 
1673                 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
1674         for (int i=selections.size()-1; i>=0; i--) {
1675                 QTreeWidgetItem currentSelection;
1676                 currentSelection = selections.get(i);
1677                 for (int j=0; j<listManager.getSavedSearchIndex().size(); j++) {
1678                         if (listManager.getSavedSearchIndex().get(j).getGuid().equals(currentSelection.text(1))) {
1679                                 conn.getSavedSearchTable().expungeSavedSearch(listManager.getSavedSearchIndex().get(j).getGuid(), true);
1680                                 listManager.getSavedSearchIndex().remove(j);
1681                                 j=listManager.getSavedSearchIndex().size()+1;
1682                         }
1683                 }
1684                 selections.remove(i);
1685         }
1686         savedSearchIndexUpdated();
1687         logger.log(logger.HIGH, "Leaving NeverNote.deleteSavedSearch");
1688         }
1689     // Setup the tree containing the user's tags
1690     private void initializeSavedSearchTree() {
1691         logger.log(logger.HIGH, "Entering NeverNote.initializeSavedSearchTree");
1692         savedSearchTree.itemSelectionChanged.connect(this, "savedSearchTreeSelection()");
1693         logger.log(logger.HIGH, "Leaving NeverNote.initializeSavedSearchTree");
1694     }
1695     // Listener when a tag is selected
1696     @SuppressWarnings("unused")
1697         private void savedSearchTreeSelection() {
1698         logger.log(logger.HIGH, "Entering NeverNote.savedSearchTreeSelection");
1699
1700         clearNotebookFilter();
1701         clearTagFilter();
1702         clearTrashFilter();
1703         clearAttributeFilter();
1704         
1705         String currentGuid = selectedSavedSearchGUID;
1706         menuBar.savedSearchEditAction.setEnabled(true);
1707         menuBar.savedSearchDeleteAction.setEnabled(true);
1708         List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
1709         QTreeWidgetItem currentSelection;
1710         selectedSavedSearchGUID = "";
1711         for (int i=0; i<selections.size(); i++) {
1712                 currentSelection = selections.get(i);
1713                 if (currentSelection.text(1).equals(currentGuid)) {
1714                         currentSelection.setSelected(false);
1715                 } else {
1716                         selectedSavedSearchGUID = currentSelection.text(1);
1717                 }
1718 //              i = selections.size() +1;
1719         }
1720         
1721         // There is the potential for no notebooks to be selected if this 
1722         // happens then we make it look like all notebooks were selecetd.
1723         // If that happens, just select the "all notebooks"
1724         if (selections.size()==0) {
1725                 clearSavedSearchFilter();
1726         }
1727         listManager.setSelectedSavedSearch(selectedSavedSearchGUID);
1728         
1729         logger.log(logger.HIGH, "Leaving NeverNote.savedSearchTreeSelection");
1730     }
1731     private void clearSavedSearchFilter() {
1732         menuBar.savedSearchEditAction.setEnabled(false);
1733         menuBar.savedSearchDeleteAction.setEnabled(false);
1734         savedSearchTree.blockSignals(true);
1735         savedSearchTree.clearSelection();
1736         savedSearchTree.blockSignals(false);
1737         selectedSavedSearchGUID = "";
1738         searchField.setEditText("");
1739         searchPerformed = false;
1740         listManager.setSelectedSavedSearch(selectedSavedSearchGUID);
1741     }
1742     // trigger the tag index to be refreshed
1743         private void savedSearchIndexUpdated() { 
1744                 if (selectedSavedSearchGUID == null)
1745                         selectedSavedSearchGUID = new String();
1746                 savedSearchTree.blockSignals(true);
1747         savedSearchTree.load(listManager.getSavedSearchIndex());
1748         savedSearchTree.selectGuid(selectedSavedSearchGUID);
1749         savedSearchTree.blockSignals(false);
1750     }
1751     // trigger when the saved search selection changes
1752     @SuppressWarnings("unused")
1753         private void updateSavedSearchSelection() {
1754                 logger.log(logger.HIGH, "Entering NeverNote.updateSavedSearchSelection()");
1755                 
1756         menuBar.savedSearchEditAction.setEnabled(true);
1757         menuBar.savedSearchDeleteAction.setEnabled(true);
1758         List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
1759
1760         if (selections.size() > 0) {
1761                 menuBar.savedSearchEditAction.setEnabled(true);
1762                 menuBar.savedSearchDeleteAction.setEnabled(true);
1763                 selectedSavedSearchGUID = selections.get(0).text(1);
1764                 SavedSearch s = conn.getSavedSearchTable().getSavedSearch(selectedSavedSearchGUID);
1765                 searchField.setEditText(s.getQuery());
1766         } else { 
1767                 menuBar.savedSearchEditAction.setEnabled(false);
1768                 menuBar.savedSearchDeleteAction.setEnabled(false);
1769                 selectedSavedSearchGUID = "";
1770                 searchField.setEditText("");
1771         }
1772         searchFieldChanged();
1773         
1774                 logger.log(logger.HIGH, "Leaving NeverNote.updateSavedSearchSelection()");
1775
1776         
1777     }
1778     // Show/Hide note information
1779         private void toggleSavedSearchWindow() {
1780                 logger.log(logger.HIGH, "Entering NeverNote.toggleSavedSearchWindow");
1781         if (savedSearchTree.isVisible())
1782                 savedSearchTree.hide();
1783         else
1784                 savedSearchTree.show();
1785         menuBar.hideSavedSearches.setChecked(savedSearchTree.isVisible());
1786                                 
1787                 Global.saveWindowVisible("savedSearchTree", savedSearchTree.isVisible());
1788         logger.log(logger.HIGH, "Leaving NeverNote.toggleSavedSearchWindow");
1789     }
1790         
1791         
1792         
1793         
1794     //***************************************************************
1795     //***************************************************************
1796     //** These functions deal with Help menu & tool menu items
1797     //***************************************************************
1798     //***************************************************************
1799         // Show database status
1800         @SuppressWarnings("unused")
1801         private void databaseStatus() {
1802                 waitCursor(true);
1803                 int dirty = conn.getNoteTable().getDirtyCount();
1804                 int unindexed = conn.getNoteTable().getUnindexedCount();
1805                 DatabaseStatus status = new DatabaseStatus();
1806                 status.setUnsynchronized(dirty);
1807                 status.setUnindexed(unindexed);
1808                 status.setNoteCount(conn.getNoteTable().getNoteCount());
1809                 status.setNotebookCount(listManager.getNotebookIndex().size());
1810                 status.setSavedSearchCount(listManager.getSavedSearchIndex().size());
1811                 status.setTagCount(listManager.getTagIndex().size());
1812                 status.setResourceCount(conn.getNoteTable().noteResourceTable.getResourceCount());
1813                 status.setWordCount(conn.getWordsTable().getWordCount());
1814                 waitCursor(false);
1815                 status.exec();
1816         }
1817         // Compact the database
1818         @SuppressWarnings("unused")
1819         private void compactDatabase() {
1820         logger.log(logger.HIGH, "Entering NeverNote.compactDatabase");
1821                 if (QMessageBox.question(this, "Confirmation", "This will free unused space in the database, "+
1822                                 "but please be aware that depending upon the size of your database this can be time consuming " +
1823                                 "and NeverNote will be unresponsive until it is complete.  Do you wish to continue?",
1824                                 QMessageBox.StandardButton.Yes, 
1825                                 QMessageBox.StandardButton.No)==StandardButton.No.value() && Global.verifyDelete() == true) {
1826                                                         return;
1827                 }
1828                 setMessage("Compacting database.");
1829                 waitCursor(true);
1830                 listManager.compactDatabase();
1831                 waitCursor(false);
1832                 setMessage("Database compact is complete.");            
1833         logger.log(logger.HIGH, "Leaving NeverNote.compactDatabase");
1834     }
1835         @SuppressWarnings("unused")
1836         private void accountInformation() {
1837                 logger.log(logger.HIGH, "Entering NeverNote.accountInformation");
1838                 AccountDialog dialog = new AccountDialog();
1839                 dialog.show();
1840                 logger.log(logger.HIGH, "Leaving NeverNote.accountInformation");
1841         }
1842         @SuppressWarnings("unused")
1843         private void releaseNotes() {
1844                 logger.log(logger.HIGH, "Entering NeverNote.releaseNotes");
1845                 QDialog dialog = new QDialog(this);
1846                 QHBoxLayout layout = new QHBoxLayout();
1847                 QTextEdit textBox = new QTextEdit();
1848                 layout.addWidget(textBox);
1849                 textBox.setReadOnly(true);
1850                 QFile file = new QFile(Global.getFileManager().getHomeDirPath("release.txt"));
1851                 if (!file.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly,
1852                 QIODevice.OpenModeFlag.Text)))
1853                         return;
1854                 textBox.setText(file.readAll().toString());
1855                 file.close();
1856                 dialog.setWindowTitle("Release Notes");
1857                 dialog.setLayout(layout);
1858                 dialog.show();
1859                 logger.log(logger.HIGH, "Leaving NeverNote.releaseNotes");
1860         }
1861         // Called when user picks Log from the help menu
1862         @SuppressWarnings("unused")
1863         private void logger() {
1864                 logger.log(logger.HIGH, "Entering NeverNote.logger");
1865                 QDialog dialog = new QDialog(this);
1866                 QHBoxLayout layout = new QHBoxLayout();
1867                 QListWidget textBox = new QListWidget();
1868                 layout.addWidget(textBox);
1869                 textBox.addItems(emitLog);
1870                 
1871                 dialog.setLayout(layout);
1872                 dialog.setWindowTitle("Mesasge Log");
1873                 dialog.show();
1874                 logger.log(logger.HIGH, "Leaving NeverNote.logger");
1875         }
1876         // Menu option "help/about" was selected
1877         @SuppressWarnings("unused")
1878         private void about() {
1879                 logger.log(logger.HIGH, "Entering NeverNote.about");
1880                 QMessageBox.about(this, 
1881                                                 tr("About NeverNote"),
1882                                                 tr("<h4><center><b>NeverNote</b></center></h4><hr><center>Version "+Global.version+"<hr></center>Evernote"
1883                                                                 +" Generic client.<br><br>" 
1884                                                                 +"Licensed under GPL v2.  <br><hr><br>"
1885                                                                 +"Evernote is copyright 2001-2010 by Evernote Corporation<br>"
1886                                                                 +"Jambi and QT are the licensed trademark of Nokia Corporation<br>"
1887                                                                 +"PDFRenderer is licened under the LGPL<br>"
1888                                                                 +"Jazzy is licened under the LGPL<br>"
1889                                                                 +"Java is a registered trademark of Sun Microsystems.<br><hr>"));       
1890                 logger.log(logger.HIGH, "Leaving NeverNote.about");
1891         }
1892         // Hide the entire left hand side
1893         @SuppressWarnings("unused")
1894         private void toggleLeftSide() {
1895                 boolean hidden;
1896                 
1897                 hidden = !menuBar.hideLeftSide.isChecked();
1898                 menuBar.hideLeftSide.setChecked(!hidden);
1899                 
1900                 if (notebookTree.isVisible() != hidden)
1901                         toggleNotebookWindow();
1902                 if (savedSearchTree.isVisible() != hidden)
1903                         toggleSavedSearchWindow();
1904                 if (tagTree.isVisible() != hidden)
1905                         toggleTagWindow();
1906                 if (attributeTree.isVisible() != hidden)
1907                         toggleAttributesWindow();
1908                 if (trashTree.isVisible() != hidden)
1909                         toggleTrashWindow();
1910                 
1911                 Global.saveWindowVisible("leftPanel", hidden);
1912                 
1913         }
1914                         
1915         
1916     //***************************************************************
1917     //***************************************************************
1918     //** These functions deal with the Toolbar
1919     //***************************************************************
1920     //***************************************************************  
1921         // Text in the search bar has been cleared
1922         private void searchFieldCleared() {
1923                 searchField.setEditText("");
1924                 saveNoteIndexWidth();
1925         }
1926         // text in the search bar changed.  We only use this to tell if it was cleared, 
1927         // otherwise we trigger off searchFieldChanged.
1928         @SuppressWarnings("unused")
1929         private void searchFieldTextChanged(String text) {
1930                 if (text.trim().equals("")) {
1931                         searchFieldCleared();
1932                         if (searchPerformed) {
1933                                 noteCache.clear();
1934                                 listManager.setEnSearch("");
1935 /////                           listManager.clearNoteIndexSearch();
1936                                 //noteIndexUpdated(true);
1937                                 listManager.loadNotesIndex();
1938                                 refreshEvernoteNote(true);
1939                                 noteIndexUpdated(false);
1940                         }
1941                         searchPerformed = false;
1942                 }
1943         }
1944     // Text in the toolbar has changed
1945     private void searchFieldChanged() {
1946         logger.log(logger.HIGH, "Entering NeverNote.searchFieldChanged");
1947         noteCache.clear();
1948         saveNoteIndexWidth();
1949         String text = searchField.currentText();
1950         listManager.setEnSearch(text.trim());
1951         listManager.loadNotesIndex();
1952 //--->>>        noteIndexUpdated(true);
1953         noteIndexUpdated(false);
1954         refreshEvernoteNote(true);
1955         searchPerformed = true;
1956         logger.log(logger.HIGH, "Leaving NeverNote.searchFieldChanged");
1957     }
1958     // Build the window tool bar
1959     private void setupToolBar() {
1960         logger.log(logger.HIGH, "Entering NeverNote.setupToolBar");
1961         toolBar = addToolBar(tr("toolBar"));    
1962
1963         prevButton = toolBar.addAction("Previous");
1964         QIcon prevIcon = new QIcon(iconPath+"back.png");
1965         prevButton.setIcon(prevIcon);
1966         prevButton.triggered.connect(this, "previousViewedAction()");   
1967         
1968         nextButton = toolBar.addAction("Next");
1969         QIcon nextIcon = new QIcon(iconPath+"forward.png");
1970         nextButton.setIcon(nextIcon);
1971         nextButton.triggered.connect(this, "nextViewedAction()");       
1972         
1973         upButton = toolBar.addAction("Up");
1974         QIcon upIcon = new QIcon(iconPath+"up.png");
1975         upButton.setIcon(upIcon);
1976         upButton.triggered.connect(this, "upAction()");         
1977         
1978         downButton = toolBar.addAction("Down");
1979         QIcon downIcon = new QIcon(iconPath+"down.png");
1980         downButton.setIcon(downIcon);
1981         downButton.triggered.connect(this, "downAction()");
1982         
1983         synchronizeButton = toolBar.addAction("Synchronize");
1984         synchronizeAnimation = new ArrayList<QIcon>();
1985         synchronizeAnimation.add(new QIcon(iconPath+"synchronize-0.png"));
1986         synchronizeAnimation.add(new QIcon(iconPath+"synchronize-1.png"));
1987         synchronizeAnimation.add(new QIcon(iconPath+"synchronize-2.png"));
1988         synchronizeAnimation.add(new QIcon(iconPath+"synchronize-3.png"));
1989         synchronizeButton.setIcon(synchronizeAnimation.get(0));
1990         synchronizeFrame = 0;
1991         synchronizeButton.triggered.connect(this, "evernoteSync()");
1992         
1993         printButton = toolBar.addAction("Print");
1994         QIcon printIcon = new QIcon(iconPath+"print.png");
1995         printButton.setIcon(printIcon);
1996         printButton.triggered.connect(this, "printNote()");
1997         
1998         tagButton = toolBar.addAction("Tag"); 
1999         QIcon tagIcon = new QIcon(iconPath+"tag.png");
2000         tagButton.setIcon(tagIcon);
2001         tagButton.triggered.connect(browserWindow, "modifyTags()");
2002         
2003         attributeButton = toolBar.addAction("Attributes"); 
2004         QIcon attributeIcon = new QIcon(iconPath+"attribute.png");
2005         attributeButton.setIcon(attributeIcon);
2006         attributeButton.triggered.connect(this, "toggleNoteInformation()");
2007                 
2008         emailButton = toolBar.addAction("Email");
2009         QIcon emailIcon = new QIcon(iconPath+"email.png");
2010         emailButton.setIcon(emailIcon);
2011         emailButton.triggered.connect(this, "emailNote()");
2012         
2013         deleteButton = toolBar.addAction("Delete");     
2014         QIcon deleteIcon = new QIcon(iconPath+"delete.png");
2015         deleteButton.setIcon(deleteIcon);
2016         deleteButton.triggered.connect(this, "deleteNote()");
2017                 
2018         newButton = toolBar.addAction("New");
2019         QIcon newIcon = new QIcon(iconPath+"new.png");
2020         newButton.triggered.connect(this, "addNote()");
2021         newButton.setIcon(newIcon);
2022         toolBar.addSeparator();
2023         toolBar.addWidget(new QLabel("Quota:"));
2024         toolBar.addWidget(quotaBar);
2025         //quotaBar.setSizePolicy(Policy.Minimum, Policy.Minimum);
2026         updateQuotaBar();
2027         
2028         // Setup the zoom
2029         zoomSpinner = new QSpinBox();
2030         zoomSpinner.setMinimum(10);
2031         zoomSpinner.setMaximum(1000);
2032         zoomSpinner.setAccelerated(true);
2033         zoomSpinner.setSingleStep(10);
2034         zoomSpinner.setValue(100);
2035         zoomSpinner.valueChanged.connect(this, "zoomChanged()");
2036         toolBar.addWidget(new QLabel("Zoom"));
2037         toolBar.addWidget(zoomSpinner);
2038         
2039         //toolBar.addWidget(new QLabel("                    "));
2040         toolBar.addSeparator();
2041         toolBar.addWidget(new QLabel("  Search:"));
2042         toolBar.addWidget(searchField);
2043         QSizePolicy sizePolicy = new QSizePolicy();
2044         sizePolicy.setHorizontalPolicy(Policy.MinimumExpanding);
2045         searchField.setSizePolicy(sizePolicy);
2046         searchField.setInsertPolicy(InsertPolicy.InsertAtTop);
2047
2048         searchClearButton = toolBar.addAction("Search Clear");
2049         QIcon searchClearIcon = new QIcon(iconPath+"searchclear.png");
2050         searchClearButton.setIcon(searchClearIcon);
2051         searchClearButton.triggered.connect(this, "searchFieldCleared()");
2052         
2053         logger.log(logger.HIGH, "Leaving NeverNote.setupToolBar");
2054     }
2055     // Update the sychronize button picture
2056     @SuppressWarnings("unused")
2057         private void updateSyncButton() {
2058         synchronizeFrame++;
2059         if (synchronizeFrame == 4) 
2060                 synchronizeFrame = 0;
2061         synchronizeButton.setIcon(synchronizeAnimation.get(synchronizeFrame));
2062     }
2063     // Synchronize with Evernote
2064         @SuppressWarnings("unused")
2065         private void evernoteSync() {
2066         logger.log(logger.HIGH, "Entering NeverNote.evernoteSync");
2067         if (!Global.isConnected)
2068                 remoteConnect();
2069         if (Global.isConnected)
2070                 synchronizeAnimationTimer.start(200);
2071         syncTimer();
2072         logger.log(logger.HIGH, "Leaving NeverNote.evernoteSync");
2073     }
2074     private void updateQuotaBar() {
2075         long limit = Global.getUploadLimit();
2076         long amount = Global.getUploadAmount();
2077         if (amount>0 && limit>0) {
2078                 int percent =(int)(amount*100/limit);
2079                 quotaBar.setValue(percent);
2080         } else 
2081                 quotaBar.setValue(0);
2082     }
2083         // Zoom changed
2084     @SuppressWarnings("unused")
2085         private void zoomChanged() {
2086         browserWindow.getBrowser().setZoomFactor(new Double(zoomSpinner.value())/100);
2087     }
2088
2089     //****************************************************************
2090     //****************************************************************
2091     //* System Tray functions
2092     //****************************************************************
2093     //****************************************************************
2094         private void trayToggleVisible() {
2095         if (isVisible()) {
2096                 hide();
2097         } else {
2098                 show();
2099                 raise();
2100         }
2101     }
2102     @SuppressWarnings("unused")
2103         private void trayActivated(QSystemTrayIcon.ActivationReason reason) {
2104         if (reason == QSystemTrayIcon.ActivationReason.DoubleClick) {
2105                 String name = QSystemTrayIcon.MessageIcon.resolve(reason.value()).name();
2106                 trayToggleVisible();
2107         }
2108     }
2109     
2110     
2111     //***************************************************************
2112     //***************************************************************
2113     //** These functions deal with the trash tree
2114     //***************************************************************
2115     //***************************************************************    
2116     // Setup the tree containing the trash.
2117     @SuppressWarnings("unused")
2118         private void trashTreeSelection() {     
2119         logger.log(logger.HIGH, "Entering NeverNote.trashTreeSelection");
2120         
2121         clearNotebookFilter();
2122         clearTagFilter();
2123         clearAttributeFilter();
2124         clearSavedSearchFilter();
2125         
2126         String tempGuid = currentNoteGuid;
2127         
2128 //      currentNoteGuid = "";
2129         currentNote = new Note();
2130         selectedNoteGUIDs.clear();
2131         listManager.getSelectedNotebooks().clear();
2132         listManager.getSelectedTags().clear();
2133         listManager.setSelectedSavedSearch("");
2134         browserWindow.clear();
2135     
2136         // toggle the add buttons
2137         newButton.setEnabled(!newButton.isEnabled());
2138         menuBar.noteAdd.setEnabled(newButton.isEnabled());
2139         menuBar.noteAdd.setVisible(true);
2140         
2141         List<QTreeWidgetItem> selections = trashTree.selectedItems();
2142         if (selections.size() == 0) {
2143                 currentNoteGuid = trashNoteGuid;
2144                         trashNoteGuid = tempGuid;
2145                 Global.showDeleted = false;
2146                 menuBar.noteRestoreAction.setEnabled(false);
2147                 menuBar.noteRestoreAction.setVisible(false);
2148         }
2149         else {
2150                 currentNoteGuid = trashNoteGuid;
2151                         trashNoteGuid = tempGuid;
2152                 menuBar.noteRestoreAction.setEnabled(true);
2153                 menuBar.noteRestoreAction.setVisible(true);
2154                 Global.showDeleted = true;
2155         }
2156         listManager.loadNotesIndex();
2157         noteIndexUpdated(false);
2158 ////            browserWindow.setEnabled(newButton.isEnabled());
2159         browserWindow.setReadOnly(!newButton.isEnabled());
2160         logger.log(logger.HIGH, "Leaving NeverNote.trashTreeSelection");
2161     }
2162     // Empty the trash file
2163     @SuppressWarnings("unused")
2164         private void emptyTrash() {
2165 //      browserWindow.clear();
2166         listManager.emptyTrash();
2167         if (trashTree.selectedItems().size() > 0) {
2168                 listManager.getSelectedNotebooks().clear();
2169                 listManager.getSelectedTags().clear();
2170                 listManager.setSelectedSavedSearch("");
2171                 newButton.setEnabled(!newButton.isEnabled());
2172                 menuBar.noteAdd.setEnabled(newButton.isEnabled());
2173                 menuBar.noteAdd.setVisible(true);
2174                 browserWindow.clear();
2175                 
2176                 clearTagFilter();
2177                 clearNotebookFilter();
2178                 clearSavedSearchFilter();
2179                 clearAttributeFilter();
2180                         
2181                 Global.showDeleted = false;
2182                 menuBar.noteRestoreAction.setEnabled(false);
2183                 menuBar.noteRestoreAction.setVisible(false);
2184                 
2185                 listManager.loadNotesIndex();
2186 //--->>>                noteIndexUpdated(true);
2187                 noteIndexUpdated(false);
2188         }       
2189    }
2190     // Show/Hide trash window
2191         private void toggleTrashWindow() {
2192                 logger.log(logger.HIGH, "Entering NeverNote.toggleTrashWindow");
2193         if (trashTree.isVisible())
2194                 trashTree.hide();
2195         else
2196                 trashTree.show();
2197         menuBar.hideTrash.setChecked(trashTree.isVisible());
2198         
2199                 Global.saveWindowVisible("trashTree", trashTree.isVisible());
2200         logger.log(logger.HIGH, "Leaving NeverNote.trashWindow");
2201     }    
2202         private void clearTrashFilter() {
2203                 Global.showDeleted = false;
2204         newButton.setEnabled(true);
2205         menuBar.noteAdd.setEnabled(true);
2206         menuBar.noteAdd.setVisible(true);
2207                 trashTree.blockSignals(true);
2208                 trashTree.clearSelection();
2209                 trashTree.blockSignals(false);
2210                 
2211         }
2212     
2213    
2214     //***************************************************************
2215     //***************************************************************
2216     //** These functions deal with connection settings
2217     //***************************************************************
2218     //***************************************************************
2219         // SyncRunner had a problem and things are disconnected
2220         @SuppressWarnings("unused")
2221         private void remoteErrorDisconnect() {
2222                 menuBar.connectAction.setText("Connect");
2223                 menuBar.connectAction.setToolTip("Connect to Evernote");
2224                 menuBar.synchronizeAction.setEnabled(false);
2225                 synchronizeAnimationTimer.stop();
2226                 return;
2227         }
2228         // Do a manual connect/disconnect
2229     private void remoteConnect() {
2230         logger.log(logger.HIGH, "Entering NeverNote.remoteConnect");
2231
2232         if (Global.isConnected) {
2233                 Global.isConnected = false;
2234                 syncRunner.enDisconnect();
2235                 setupConnectMenuOptions();
2236                 setupOnlineMenu();
2237                 return;
2238         }
2239         
2240         AESEncrypter aes = new AESEncrypter();
2241         try {
2242                         aes.decrypt(new FileInputStream(Global.getFileManager().getHomeDirFile("secure.txt")));
2243                 } catch (FileNotFoundException e) {
2244                         // File not found, so we'll just get empty strings anyway. 
2245                 }
2246                 String userid = aes.getUserid();
2247                 String password = aes.getPassword();
2248                 if (!userid.equals("") && !password.equals("")) {
2249                 Global.username = userid;
2250                 Global.password = password;
2251                 }               
2252
2253         // Show the login dialog box
2254                 if (!Global.automaticLogin() || userid.equals("")|| password.equals("")) {
2255                         LoginDialog login = new LoginDialog();
2256                         login.exec();
2257                 
2258                         if (!login.okPressed()) {
2259                                 return;
2260                         }
2261         
2262                         Global.username = login.getUserid();
2263                         Global.password = login.getPassword();
2264                 }
2265                 syncRunner.username = Global.username;
2266                 syncRunner.password = Global.password;
2267                 syncRunner.userStoreUrl = Global.userStoreUrl;
2268                 syncRunner.noteStoreUrl = Global.noteStoreUrl;
2269                 syncRunner.noteStoreUrlBase = Global.noteStoreUrlBase;
2270                 syncRunner.enConnect();
2271                 Global.isConnected = syncRunner.isConnected;
2272                 setupOnlineMenu();
2273                 setupConnectMenuOptions();
2274                 logger.log(logger.HIGH, "Leaving NeverNote.remoteConnect");
2275     }
2276     private void setupConnectMenuOptions() {
2277         logger.log(logger.HIGH, "entering NeverNote.setupConnectMenuOptions");
2278                 if (!Global.isConnected) {
2279                         menuBar.connectAction.setText("Connect");
2280                         menuBar.connectAction.setToolTip("Connect to Evernote");
2281                         menuBar.synchronizeAction.setEnabled(false);
2282                 } else {
2283                         menuBar.connectAction.setText("Disconnect");
2284                         menuBar.connectAction.setToolTip("Disconnect from Evernote");
2285                         menuBar.synchronizeAction.setEnabled(true);
2286                 }
2287                 logger.log(logger.HIGH, "Leaving NeverNote.setupConnectionMenuOptions");
2288     }
2289     
2290     
2291     
2292     //***************************************************************
2293     //***************************************************************
2294     //** These functions deal with the GUI Attribute tree
2295     //***************************************************************
2296     //***************************************************************    
2297     @SuppressWarnings("unused")
2298         private void attributeTreeClicked(QTreeWidgetItem item, Integer integer) {
2299         
2300         clearTagFilter();
2301         clearNotebookFilter();
2302         clearTrashFilter();
2303         clearSavedSearchFilter();
2304
2305         if (attributeTreeSelected == null || item.nativeId() != attributeTreeSelected.nativeId()) {
2306                 if (item.childCount() > 0) {
2307                         item.setSelected(false);
2308                 } else {
2309                 Global.createdBeforeFilter.reset();
2310                 Global.createdSinceFilter.reset();
2311                 Global.changedBeforeFilter.reset();
2312                 Global.changedSinceFilter.reset();
2313                 Global.containsFilter.reset();
2314                         attributeTreeSelected = item;
2315                         DateAttributeFilterTable f = null;
2316                         f = findDateAttributeFilterTable(item.parent());
2317                         if (f!=null)
2318                                 f.select(item.text(0));
2319                         else {
2320                                 String text = item.text(0);
2321                                 Global.containsFilter.select(text);
2322                         }
2323                 }
2324                 listManager.loadNotesIndex();
2325                 noteIndexUpdated(false);
2326                 return;
2327         }
2328                 attributeTreeSelected = null;
2329                 item.setSelected(false);
2330         Global.createdBeforeFilter.reset();
2331         Global.createdSinceFilter.reset();
2332         Global.changedBeforeFilter.reset();
2333         Global.changedSinceFilter.reset();
2334         Global.containsFilter.reset();
2335         listManager.loadNotesIndex();
2336                 noteIndexUpdated(false); 
2337     }
2338     // This determines what attribute filter we need, depending upon the selection
2339     private DateAttributeFilterTable findDateAttributeFilterTable(QTreeWidgetItem w) {
2340                 if (w.parent() != null && w.childCount() > 0) {
2341                         QTreeWidgetItem parent = w.parent();
2342                         if (parent.text(0).equalsIgnoreCase("created") && 
2343                                 w.text(0).equalsIgnoreCase("since"))
2344                                         return Global.createdSinceFilter;
2345                         if (parent.text(0).equalsIgnoreCase("created") && 
2346                         w.text(0).equalsIgnoreCase("before"))
2347                                         return Global.createdBeforeFilter;
2348                         if (parent.text(0).equalsIgnoreCase("last modified") && 
2349                         w.text(0).equalsIgnoreCase("since"))
2350                                         return Global.changedSinceFilter;
2351                 if (parent.text(0).equalsIgnoreCase("last modified") && 
2352                         w.text(0).equalsIgnoreCase("before"))
2353                                                 return Global.changedBeforeFilter;
2354                 }
2355                 return null;
2356     }
2357     // Show/Hide attribute search window
2358         private void toggleAttributesWindow() {
2359                 logger.log(logger.HIGH, "Entering NeverNote.toggleAttributesWindow");
2360         if (attributeTree.isVisible())
2361                 attributeTree.hide();
2362         else
2363                 attributeTree.show();
2364         menuBar.hideAttributes.setChecked(attributeTree.isVisible());
2365         
2366                 Global.saveWindowVisible("attributeTree", attributeTree.isVisible());
2367         logger.log(logger.HIGH, "Leaving NeverNote.toggleAttributeWindow");
2368     }    
2369         private void clearAttributeFilter() {
2370         Global.createdBeforeFilter.reset();
2371         Global.createdSinceFilter.reset();
2372         Global.changedBeforeFilter.reset();
2373         Global.changedSinceFilter.reset();
2374         Global.containsFilter.reset();
2375         attributeTreeSelected = null;
2376                 attributeTree.blockSignals(true);
2377                 attributeTree.clearSelection();
2378                 attributeTree.blockSignals(false);
2379         }
2380     
2381         
2382     //***************************************************************
2383     //***************************************************************
2384     //** These functions deal with the GUI Note index table
2385     //***************************************************************
2386     //***************************************************************    
2387     // Initialize the note list table
2388         private void initializeNoteTable() {
2389                 logger.log(logger.HIGH, "Entering NeverNote.initializeNoteTable");
2390                 noteTableView.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection);
2391                 noteTableView.selectionModel().selectionChanged.connect(this, "noteTableSelection()");
2392                 logger.log(logger.HIGH, "Leaving NeverNote.initializeNoteTable");
2393         }       
2394     // Show/Hide trash window
2395         @SuppressWarnings("unused")
2396         private void toggleNoteListWindow() {
2397                 logger.log(logger.HIGH, "Entering NeverNote.toggleNoteListWindow");
2398         if (noteTableView.isVisible())
2399                 noteTableView.hide();
2400         else
2401                 noteTableView.show();
2402         menuBar.hideNoteList.setChecked(noteTableView.isVisible());
2403         
2404                 Global.saveWindowVisible("noteList", noteTableView.isVisible());
2405         logger.log(logger.HIGH, "Leaving NeverNote.toggleNoteListWindow");
2406     }   
2407         // Handle the event that a user selects a note from the table
2408     @SuppressWarnings("unused")
2409         private void noteTableSelection() {
2410                 logger.log(logger.HIGH, "Entering NeverNote.noteTableSelection");
2411                 saveNote();
2412                 if (historyGuids.size() == 0) {
2413                         historyGuids.add(currentNoteGuid);
2414                         historyPosition = 1;
2415                 }
2416         noteTableView.showColumn(Global.noteTableGuidPosition);
2417         
2418         List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
2419         noteTableView.hideColumn(Global.noteTableGuidPosition);
2420         
2421         if (selections.size() > 0) {
2422                 QModelIndex index;
2423                 menuBar.noteDuplicateAction.setEnabled(true);
2424                 menuBar.noteOnlineHistoryAction.setEnabled(true);
2425                 menuBar.noteMergeAction.setEnabled(true);
2426                 selectedNoteGUIDs.clear();
2427                 if (selections.size() != 1 || Global.showDeleted) {
2428                         menuBar.noteDuplicateAction.setEnabled(false);
2429                 }
2430                 if (selections.size() != 1 || !Global.isConnected) {
2431                         menuBar.noteOnlineHistoryAction.setEnabled(false);
2432                 }
2433                 if (selections.size() == 1) {
2434                         menuBar.noteMergeAction.setEnabled(false);
2435                 }
2436                 for (int i=0; i<selections.size(); i++) {
2437                         int row = selections.get(i).row();
2438                         if (row == 0) 
2439                                 upButton.setEnabled(false);
2440                         else
2441                                 upButton.setEnabled(true);
2442                         if (row < noteTableView.model.rowCount()-1)
2443                                 downButton.setEnabled(true);
2444                         else
2445                                 downButton.setEnabled(false);
2446                         index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition);
2447                         SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
2448                         currentNoteGuid = (String)ix.values().toArray()[0];
2449                         selectedNoteGUIDs.add(currentNoteGuid);
2450                 }
2451         }
2452         
2453         nextButton.setEnabled(true);
2454                 prevButton.setEnabled(true);
2455         if (!fromHistory) {
2456                 int endPosition = historyGuids.size()-1;
2457                 for (int j=historyPosition; j<=endPosition; j++) {
2458                         historyGuids.remove(historyGuids.size()-1);
2459                 }
2460                 historyGuids.add(currentNoteGuid);
2461                 historyPosition = historyGuids.size();
2462         } 
2463         if (historyPosition <= 1)
2464                 prevButton.setEnabled(false);
2465         if (historyPosition == historyGuids.size())
2466                 nextButton.setEnabled(false);
2467                 
2468         fromHistory = false;
2469         scrollToGuid(currentNoteGuid);
2470         refreshEvernoteNote(true);
2471                 logger.log(logger.HIGH, "Leaving NeverNote.noteTableSelection");
2472     }    
2473         // Trigger a refresh when the note db has been updated
2474         private void noteIndexUpdated(boolean reload) {
2475                 logger.log(logger.HIGH, "Entering NeverNote.noteIndexUpdated");
2476                 Global.traceReset();  
2477                 saveNote();
2478         refreshEvernoteNoteList();
2479         logger.log(logger.HIGH, "Calling note table reload in NeverNote.noteIndexUpdated() - "+reload);
2480         noteTableView.load(listManager, reload);
2481         scrollToGuid(currentNoteGuid);
2482                 logger.log(logger.HIGH, "Leaving NeverNote.noteIndexUpdated");
2483     }
2484         // Called when the list of notes is updated
2485     private void refreshEvernoteNoteList() {
2486         logger.log(logger.HIGH, "Entering NeverNote.refreshEvernoteNoteList");
2487         browserWindow.setDisabled(false);
2488                 if (selectedNoteGUIDs == null)
2489                         selectedNoteGUIDs = new ArrayList<String>();
2490                 selectedNoteGUIDs.clear();  // clear out old entries
2491                 
2492                 String saveCurrentNoteGuid = new String();
2493                 String tempNoteGuid = new String();
2494                                 
2495                 historyGuids.clear();
2496                 historyPosition = 0;
2497                 prevButton.setEnabled(false);
2498                 nextButton.setEnabled(false);
2499                 
2500                 if (currentNoteGuid == null) 
2501                         currentNoteGuid = new String();
2502                 
2503                 for (Note note : listManager.getNoteIndex()) {
2504                         tempNoteGuid = note.getGuid();
2505                         if (currentNoteGuid.equals(tempNoteGuid)) {
2506                                 saveCurrentNoteGuid = new String(tempNoteGuid);
2507                         }
2508                 }
2509                 
2510                 if (listManager.getNoteIndex().size() == 0) {
2511                         currentNoteGuid = "";
2512                         currentNote = null;
2513                         browserWindow.clear();
2514                         browserWindow.setDisabled(true);
2515                 } 
2516                 
2517                 if (saveCurrentNoteGuid.equals("") && listManager.getNoteIndex().size() >0) {
2518                         currentNoteGuid = listManager.getNoteIndex().get(listManager.getNoteIndex().size()-1).getGuid();
2519                         currentNote = listManager.getNoteIndex().get(listManager.getNoteIndex().size()-1);
2520                         refreshEvernoteNote(true);
2521                 } else {
2522                         refreshEvernoteNote(false);
2523                 }
2524                 reloadTagTree();
2525
2526                 logger.log(logger.HIGH, "Leaving NeverNote.refreshEvernoteNoteList");
2527         } 
2528     // Called when the previous arrow button is clicked 
2529     @SuppressWarnings("unused")
2530         private void previousViewedAction() {
2531         if (!prevButton.isEnabled())
2532                 return;
2533         if (historyPosition == 0)
2534                 return;
2535                 historyPosition--;
2536         if (historyPosition <= 0)
2537                 return;
2538         String historyGuid = historyGuids.get(historyPosition-1);
2539         fromHistory = true;
2540         for (int i=0; i<noteTableView.model().rowCount(); i++) {
2541                 QModelIndex modelIndex =  noteTableView.model().index(i, Global.noteTableGuidPosition);
2542                 if (modelIndex != null) {
2543                         SortedMap<Integer, Object> ix = noteTableView.model().itemData(modelIndex);
2544                         String tableGuid =  (String)ix.values().toArray()[0];
2545                         if (tableGuid.equals(historyGuid)) {
2546                                 noteTableView.selectRow(i);
2547                                 return;
2548                         }       
2549                 }
2550         }
2551     }
2552     @SuppressWarnings("unused")
2553         private void nextViewedAction() {
2554         if (!nextButton.isEnabled())
2555                 return;
2556         String historyGuid = historyGuids.get(historyPosition);
2557         historyPosition++;
2558         fromHistory = true;
2559         for (int i=0; i<noteTableView.model().rowCount(); i++) {
2560                 QModelIndex modelIndex =  noteTableView.model().index(i, Global.noteTableGuidPosition);
2561                 if (modelIndex != null) {
2562                         SortedMap<Integer, Object> ix = noteTableView.model().itemData(modelIndex);
2563                         String tableGuid =  (String)ix.values().toArray()[0];
2564                         if (tableGuid.equals(historyGuid)) {
2565                                 noteTableView.selectRow(i);
2566                                 return;
2567                         }       
2568                 }
2569         }       
2570     }
2571     // Called when the up arrow is clicked 
2572     @SuppressWarnings("unused")
2573         private void upAction() {
2574         List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
2575         int row = selections.get(0).row();
2576         if (row > 0) {
2577                 noteTableView.selectRow(row-1);
2578         }
2579     }
2580     // Called when the down arrow is clicked 
2581     @SuppressWarnings("unused")
2582         private void downAction() {
2583         List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
2584         int row = selections.get(0).row();
2585         int max = noteTableView.model.rowCount();
2586         if (row < max-1) {
2587                 noteTableView.selectRow(row+1);
2588         }
2589     }
2590     // Update a tag string for a specific note in the list
2591     @SuppressWarnings("unused")
2592         private void updateListTags(String guid, List<String> tags) {
2593         logger.log(logger.HIGH, "Entering NeverNote.updateListTags");
2594         StringBuffer tagBuffer = new StringBuffer();
2595         for (int i=0; i<tags.size(); i++) {
2596                 tagBuffer.append(tags.get(i));
2597                 if (i<tags.size()-1)
2598                         tagBuffer.append(", ");
2599         }
2600         
2601         for (int i=0; i<noteTableView.model.rowCount(); i++) {
2602                 QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
2603                 if (modelIndex != null) {
2604                         SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
2605                         String tableGuid =  (String)ix.values().toArray()[0];
2606                         if (tableGuid.equals(guid)) {
2607                                 noteTableView.model.setData(i, Global.noteTableTagPosition,tagBuffer.toString());
2608                                 noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
2609                                 return;
2610                         }
2611                 }
2612         }
2613         logger.log(logger.HIGH, "Leaving NeverNote.updateListTags");
2614     }
2615     // Update a title for a specific note in the list
2616     @SuppressWarnings("unused")
2617         private void updateListTitle(String guid, String title) {
2618         logger.log(logger.HIGH, "Entering NeverNote.updateListTitle");
2619
2620         for (int i=0; i<noteTableView.model.rowCount(); i++) {
2621                 //QModelIndex modelIndex =  noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
2622                 QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
2623                 if (modelIndex != null) {
2624 //                      SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(modelIndex);
2625                         SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
2626                         String tableGuid =  (String)ix.values().toArray()[0];
2627                         if (tableGuid.equals(guid)) {
2628                                 noteTableView.model.setData(i, Global.noteTableTitlePosition,title);
2629                                 noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
2630                                 return;
2631                         }       
2632                 }
2633         }
2634         logger.log(logger.HIGH, "Leaving NeverNote.updateListTitle");
2635     }
2636     // Update a title for a specific note in the list
2637     @SuppressWarnings("unused")
2638         private void updateListAuthor(String guid, String author) {
2639         logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
2640
2641         for (int i=0; i<noteTableView.model.rowCount(); i++) {
2642                 //QModelIndex modelIndex =  noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
2643                 QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
2644                 if (modelIndex != null) {
2645 //                      SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(modelIndex);
2646                         SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
2647                         String tableGuid =  (String)ix.values().toArray()[0];
2648                         if (tableGuid.equals(guid)) {
2649                                 noteTableView.model.setData(i, Global.noteTableAuthorPosition,author);
2650                                 noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
2651                                 return;
2652                         }       
2653                 }
2654         }
2655         logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
2656     }
2657         private void updateListNoteNotebook(String guid, String notebook) {
2658         logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
2659
2660         for (int i=0; i<noteTableView.model.rowCount(); i++) {
2661                 //QModelIndex modelIndex =  noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
2662                 QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
2663                 if (modelIndex != null) {
2664 //                      SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(modelIndex);
2665                         SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
2666                         String tableGuid =  (String)ix.values().toArray()[0];
2667                         if (tableGuid.equals(guid)) {
2668                                 noteTableView.model.setData(i, Global.noteTableNotebookPosition,notebook);
2669                                 noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
2670                                 return;
2671                         }       
2672                 }
2673         }
2674         logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
2675     }
2676     // Update a title for a specific note in the list
2677     @SuppressWarnings("unused")
2678         private void updateListSourceUrl(String guid, String url) {
2679         logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
2680
2681         for (int i=0; i<noteTableView.model.rowCount(); i++) {
2682                 //QModelIndex modelIndex =  noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
2683                 QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
2684                 if (modelIndex != null) {
2685 //                      SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(modelIndex);
2686                         SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
2687                         String tableGuid =  (String)ix.values().toArray()[0];
2688                         if (tableGuid.equals(guid)) {
2689                                 noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
2690                                 noteTableView.model.setData(i, Global.noteTableSourceUrlPosition,url);
2691                                 return;
2692                         }       
2693                 }
2694         }
2695         logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
2696     }
2697         private void updateListGuid(String oldGuid, String newGuid) {
2698         logger.log(logger.HIGH, "Entering NeverNote.updateListTitle");
2699
2700         for (int i=0; i<noteTableView.model.rowCount(); i++) {
2701                 QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
2702                 if (modelIndex != null) {
2703                         SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
2704                         String tableGuid =  (String)ix.values().toArray()[0];
2705                         if (tableGuid.equals(oldGuid)) {
2706                                 noteTableView.model.setData(i, Global.noteTableGuidPosition,newGuid);
2707                                 //noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
2708                                 return;
2709                         }       
2710                 }
2711         }
2712         logger.log(logger.HIGH, "Leaving NeverNote.updateListTitle");
2713     }
2714         private void updateListTagName(String guid) {
2715         logger.log(logger.HIGH, "Entering NeverNote.updateTagName");
2716                 
2717                 for (int j=0; j<listManager.getNoteIndex().size(); j++) {
2718                         if (listManager.getNoteIndex().get(j).getTagGuids().contains(guid)) {
2719                                 String newName = listManager.getTagNamesForNote(listManager.getNoteIndex().get(j));
2720
2721                                 for (int i=0; i<noteTableView.model.rowCount(); i++) {
2722                                         QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
2723                                         if (modelIndex != null) {
2724                                                 SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
2725                                                 String noteGuid = (String)ix.values().toArray()[0];
2726                                                 if (noteGuid.equalsIgnoreCase(listManager.getNoteIndex().get(j).getGuid())) {
2727                                                         noteTableView.model.setData(i, Global.noteTableTagPosition, newName);
2728                                                         //noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
2729                                                         i=noteTableView.model.rowCount();
2730                                                 }
2731                                         }
2732                                 }
2733                         }
2734                 }       
2735         logger.log(logger.HIGH, "Leaving NeverNote.updateListNotebook");
2736     }
2737         private void removeListTagName(String guid) {
2738         logger.log(logger.HIGH, "Entering NeverNote.updateTagName");
2739                 
2740                 for (int j=0; j<listManager.getNoteIndex().size(); j++) {
2741                         if (listManager.getNoteIndex().get(j).getTagGuids().contains(guid)) {
2742                                 for (int i=listManager.getNoteIndex().get(j).getTagGuids().size()-1; i>=0; i--) {
2743                                         if (listManager.getNoteIndex().get(j).getTagGuids().get(i).equals(guid))
2744                                                 listManager.getNoteIndex().get(j).getTagGuids().remove(i);
2745                                 }
2746                                 
2747                                 String newName = listManager.getTagNamesForNote(listManager.getNoteIndex().get(j));
2748                                 for (int i=0; i<noteTableView.model.rowCount(); i++) {
2749                                         QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
2750                                         if (modelIndex != null) {
2751                                                 SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
2752                                                 String noteGuid = (String)ix.values().toArray()[0];
2753                                                 if (noteGuid.equalsIgnoreCase(listManager.getNoteIndex().get(j).getGuid())) {
2754                                                         noteTableView.model.setData(i, Global.noteTableTagPosition, newName);
2755 //                                                      noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
2756                                                         i=noteTableView.model.rowCount();
2757                                                 }
2758                                         }
2759                                 }
2760                         }
2761                 }       
2762         logger.log(logger.HIGH, "Leaving NeverNote.updateListNotebook");
2763     }
2764     private void updateListNotebookName(String oldName, String newName) {
2765         logger.log(logger.HIGH, "Entering NeverNote.updateListNotebookName");
2766
2767         for (int i=0; i<noteTableView.model.rowCount(); i++) {
2768                 QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableNotebookPosition); 
2769                 if (modelIndex != null) {
2770                         SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
2771                         String tableName =  (String)ix.values().toArray()[0];
2772                         if (tableName.equalsIgnoreCase(oldName)) {
2773 //                              noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
2774                                 noteTableView.model.setData(i, Global.noteTableNotebookPosition, newName);
2775                         }
2776                 }
2777         }
2778         logger.log(logger.HIGH, "Leaving NeverNote.updateListNotebookName");
2779     }
2780     @SuppressWarnings("unused")
2781         private void updateListDateCreated(String guid, QDateTime date) {
2782         logger.log(logger.HIGH, "Entering NeverNote.updateListDateCreated");
2783
2784         for (int i=0; i<noteTableView.model.rowCount(); i++) {
2785                 QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
2786                 if (modelIndex != null) {
2787                         SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
2788                         String tableGuid =  (String)ix.values().toArray()[0];
2789                         if (tableGuid.equals(guid)) {
2790                                 noteTableView.model.setData(i, Global.noteTableCreationPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
2791                                 return;
2792                         }
2793                 }
2794         }
2795         logger.log(logger.HIGH, "Leaving NeverNote.updateListDateCreated");
2796     }
2797     @SuppressWarnings("unused")
2798         private void updateListDateSubject(String guid, QDateTime date) {
2799         logger.log(logger.HIGH, "Entering NeverNote.updateListDateSubject");
2800
2801         for (int i=0; i<noteTableView.model.rowCount(); i++) {
2802                 QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
2803                 if (modelIndex != null) {
2804                         SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
2805                         String tableGuid =  (String)ix.values().toArray()[0];
2806                         if (tableGuid.equals(guid)) {
2807                                 noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
2808                                 noteTableView.model.setData(i, Global.noteTableSubjectDatePosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
2809                                 return;
2810                         }
2811                 }
2812         }
2813         logger.log(logger.HIGH, "Leaving NeverNote.updateListDateCreated");
2814     }
2815     @SuppressWarnings("unused")
2816         private void updateListDateChanged(String guid, QDateTime date) {
2817         logger.log(logger.HIGH, "Entering NeverNote.updateListDateChanged");
2818
2819         for (int i=0; i<noteTableView.model.rowCount(); i++) {
2820                 QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
2821                 if (modelIndex != null) {
2822                         SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
2823                         String tableGuid =  (String)ix.values().toArray()[0];
2824                         if (tableGuid.equals(guid)) {
2825                                 noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
2826                                 noteTableView.model.setData(i, Global.noteTableChangedPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
2827                                 return;
2828                         }
2829                 }
2830         }
2831         logger.log(logger.HIGH, "Leaving NeverNote.updateListDateChanged");
2832     }
2833     private void updateListDateChanged() {
2834         logger.log(logger.HIGH, "Entering NeverNote.updateListDateChanged");
2835         QDateTime date = new QDateTime(QDateTime.currentDateTime());
2836         for (int i=0; i<noteTableView.model.rowCount(); i++) {
2837                 QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
2838                 if (modelIndex != null) {
2839                         SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
2840                         String tableGuid =  (String)ix.values().toArray()[0];
2841                         if (tableGuid.equals(currentNoteGuid)) {
2842                                 noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
2843                                 noteTableView.model.setData(i, Global.noteTableChangedPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
2844                                 return;
2845                         }
2846                 }
2847         }
2848         logger.log(logger.HIGH, "Leaving NeverNote.updateListDateChanged");
2849     }  
2850     // Redo scroll
2851     @SuppressWarnings("unused")
2852         private void scrollToCurrentGuid() {
2853         //scrollToGuid(currentNoteGuid);
2854         List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
2855         if (selections.size() == 0)
2856                 return;
2857         QModelIndex index = selections.get(0);
2858         int row = selections.get(0).row();
2859         String guid = (String)index.model().index(row, Global.noteTableGuidPosition).data();
2860         scrollToGuid(guid);
2861     }
2862     // Scroll to a particular index item
2863     private void scrollToGuid(String guid) {
2864         if (currentNote == null || guid == null) 
2865                 return;
2866         if (currentNote.isActive() && Global.showDeleted) {
2867                 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
2868                         if (!listManager.getNoteIndex().get(i).isActive()) {
2869                                 currentNote = listManager.getNoteIndex().get(i);
2870                                 currentNoteGuid =  currentNote.getGuid();
2871                                 i = listManager.getNoteIndex().size();
2872                         }
2873                 }
2874         }
2875         
2876         if (!currentNote.isActive() && !Global.showDeleted) {
2877                 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
2878                         if (listManager.getNoteIndex().get(i).isActive()) {
2879                                 currentNote = listManager.getNoteIndex().get(i);
2880                                 currentNoteGuid =  currentNote.getGuid();
2881                                 i = listManager.getNoteIndex().size();
2882                         }
2883                 }
2884         }
2885         
2886         QModelIndex index; 
2887         for (int i=0; i<noteTableView.model().rowCount(); i++) {
2888                 index = noteTableView.model().index(i, Global.noteTableGuidPosition);
2889                 if (currentNoteGuid.equals(index.data())) {
2890 //                      noteTableView.setCurrentIndex(index);
2891                         noteTableView.selectRow(i);
2892                         noteTableView.scrollTo(index, ScrollHint.EnsureVisible);  // This should work, but it doesn't
2893                                 i=noteTableView.model.rowCount();
2894                 }
2895         }
2896     }
2897     // Show/Hide columns
2898     private void showColumns() {
2899                 noteTableView.setColumnHidden(Global.noteTableCreationPosition, !Global.isColumnVisible("dateCreated"));
2900                 noteTableView.setColumnHidden(Global.noteTableChangedPosition, !Global.isColumnVisible("dateChanged"));
2901                 noteTableView.setColumnHidden(Global.noteTableSubjectDatePosition, !Global.isColumnVisible("dateSubject"));
2902                 noteTableView.setColumnHidden(Global.noteTableAuthorPosition, !Global.isColumnVisible("author"));
2903                 noteTableView.setColumnHidden(Global.noteTableSourceUrlPosition, !Global.isColumnVisible("sourceUrl"));
2904                 noteTableView.setColumnHidden(Global.noteTableTagPosition, !Global.isColumnVisible("tags"));
2905                 noteTableView.setColumnHidden(Global.noteTableNotebookPosition, !Global.isColumnVisible("notebook"));
2906                 noteTableView.setColumnHidden(Global.noteTableSynchronizedPosition, !Global.isColumnVisible("synchronized"));
2907     }
2908     // Open a separate window
2909     @SuppressWarnings("unused")
2910         private void listDoubleClick() {
2911
2912     }
2913     // Title color has changed
2914     @SuppressWarnings("unused")
2915         private void titleColorChanged(Integer color) {
2916         logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
2917
2918         QColor backgroundColor = new QColor();
2919                 QColor foregroundColor = new QColor(QColor.black);
2920                 backgroundColor.setRgb(color);
2921                 
2922                 if (backgroundColor.rgb() == QColor.black.rgb() || backgroundColor.rgb() == QColor.blue.rgb())
2923                         foregroundColor.setRgb(QColor.white.rgb());
2924         
2925                 if (selectedNoteGUIDs.size() == 0)
2926                         selectedNoteGUIDs.add(currentNoteGuid);
2927                 
2928         for (int j=0; j<selectedNoteGUIDs.size(); j++) {
2929                 for (int i=0; i<noteTableView.model.rowCount(); i++) {
2930                         QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
2931                         if (modelIndex != null) {
2932                                 SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
2933                                 String tableGuid =  (String)ix.values().toArray()[0];
2934                                 if (tableGuid.equals(selectedNoteGUIDs.get(j))) {
2935                                         for (int k=0; k<Global.noteTableColumnCount; k++) {
2936                                                 noteTableView.model.setData(i, k, backgroundColor, Qt.ItemDataRole.BackgroundRole);
2937                                                 noteTableView.model.setData(i, k, foregroundColor, Qt.ItemDataRole.ForegroundRole);
2938                                                 listManager.updateNoteTitleColor(selectedNoteGUIDs.get(j), backgroundColor.rgb());
2939                                         }
2940                                         i=noteTableView.model.rowCount();
2941                                 }
2942                         }
2943                 }
2944         }
2945         logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
2946     }
2947     
2948     
2949     //***************************************************************
2950     //***************************************************************
2951     //** These functions deal with Note specific things
2952     //***************************************************************
2953     //***************************************************************    
2954     @SuppressWarnings("unused")
2955         private void setNoteDirty() {
2956                 logger.log(logger.EXTREME, "Entering NeverNote.setNoteDirty()");
2957         noteDirty = true;
2958
2959         listManager.getUnsynchronizedNotes().add(currentNoteGuid);
2960         for (int i=0; i<noteTableView.model.rowCount(); i++) {
2961                 QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
2962                 if (modelIndex != null) {
2963                         SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
2964                         String tableGuid =  (String)ix.values().toArray()[0];
2965                         if (tableGuid.equals(currentNoteGuid)) {
2966                                 noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
2967                                 return;
2968                         }
2969                 }
2970         }
2971                 logger.log(logger.EXTREME, "Leaving NeverNote.setNoteDirty()");
2972     }
2973     private void saveNote() {
2974                 logger.log(logger.EXTREME, "Inside NeverNote.saveNote()");
2975         if (noteDirty) {
2976                         logger.log(logger.EXTREME, "Note is dirty.");
2977                 waitCursor(true);
2978                 
2979                         preview = new Thumbnailer(currentNoteGuid, new QSize(1024,768));
2980                         preview.finished.connect(this, "saveThumbnail(String)");
2981                         preview.setContent(browserWindow.getContent());
2982                 
2983                         logger.log(logger.EXTREME, "Saving to cache");
2984                         QTextCodec codec = QTextCodec.codecForLocale();
2985 //              QTextDecoder decoder = codec.makeDecoder();
2986                         codec = QTextCodec.codecForName("UTF-8");
2987                 QByteArray unicode =  codec.fromUnicode(browserWindow.getContent());
2988                 noteCache.put(currentNoteGuid, unicode.toString());
2989                         
2990                 logger.log(logger.EXTREME, "updating list manager");
2991                 listManager.updateNoteContent(currentNoteGuid, browserWindow.getContent());
2992                         logger.log(logger.EXTREME, "Updating title");
2993                 listManager.updateNoteTitle(currentNoteGuid, browserWindow.getTitle());
2994                 updateListDateChanged();
2995
2996                         logger.log(logger.EXTREME, "Looking through note index for refreshed note");
2997                 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
2998                         if (listManager.getNoteIndex().get(i).getGuid().equals(currentNoteGuid)) {
2999                                 currentNote = listManager.getNoteIndex().get(i);
3000                                 i = listManager.getNoteIndex().size();
3001                         }
3002                 }
3003                 noteDirty = false;
3004                 waitCursor(false);
3005         }
3006     }
3007     // Get a note from Evernote (and put it in the browser)
3008         private void refreshEvernoteNote(boolean reload) {
3009                 logger.log(logger.HIGH, "Entering NeverNote.refreshEvernoteNote");
3010                 if (Global.getDisableViewing()) {
3011                         browserWindow.setEnabled(false);
3012                         return;
3013                 }
3014                 inkNote = false;
3015                 if (!Global.showDeleted)
3016                         browserWindow.setReadOnly(false);
3017                 Global.cryptCounter =0;
3018                 if (currentNoteGuid.equals("")) {
3019                         browserWindow.setReadOnly(true);
3020                         return;
3021                 }
3022                 if (!reload)
3023                         return;
3024                 
3025                 waitCursor(true);
3026                 browserWindow.loadingData(true);
3027
3028                 currentNote = conn.getNoteTable().getNote(currentNoteGuid, true,true,false,false,true);
3029                 if (currentNote == null) 
3030                         return;
3031
3032                 if (!noteCache.containsKey(currentNoteGuid) || conn.getNoteTable().isThumbnailNeeded(currentNoteGuid)) {
3033                         QByteArray js = new QByteArray();
3034                         // We need to prepend the note with <HEAD></HEAD> or encoded characters are ugly 
3035                         js.append("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">");               
3036                         js.append("<style type=\"text/css\">en-crypt-temp { border-style:solid; border-color:blue; padding:0.5mm 0.5mm 0.5mm 0.5mm; }</style>");
3037                         js.append("<style type=\"text/css\">en-hilight { background-color: rgb(255,255,0) }</style>");
3038                         js.append("<style type=\"text/css\">en-spell { text-decoration: none; border-bottom: dotted 1px #cc0000; }</style>");
3039                         js.append("</head>");
3040                         js.append(rebuildNoteHTML(currentNoteGuid, currentNote.getContent()));
3041                         js.append("</HTML>");
3042                         js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml.dtd'>", "");
3043                         js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml2.dtd'>", "");
3044                         js.replace("<?xml version='1.0' encoding='UTF-8'?>", "");
3045                         browserWindow.getBrowser().setContent(js);
3046                         noteCache.put(currentNoteGuid, js.toString());
3047                         if (conn.getNoteTable().isThumbnailNeeded(currentNoteGuid)) {
3048                                 preview = new Thumbnailer(currentNoteGuid, new QSize(1024,768));
3049                                 preview.finished.connect(this, "saveThumbnail(String)");
3050                                 preview.setContent(js.toString());
3051                         }
3052                 } else {
3053                         logger.log(logger.HIGH, "Note content is being pulled from the cache");
3054                         String cachedContent = modifyCachedTodoTags(noteCache.get(currentNoteGuid));
3055                         browserWindow.getBrowser().setContent(new QByteArray(cachedContent));
3056                 }
3057                 
3058                 browserWindow.getBrowser().page().setContentEditable(!inkNote);  // We don't allow editing of ink notes
3059                 browserWindow.setNote(currentNote);
3060                 
3061                 // Build a list of non-closed notebooks
3062                 List<Notebook> nbooks = new ArrayList<Notebook>();
3063                 for (int i=0; i