OSDN Git Service

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