2 * This file is part of NeverNote
3 * Copyright 2009 Randy Baumgarte
5 * This file may be licensed under the terms of of the
6 * GNU General Public License Version 2 (the ``GPL'').
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.
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.
19 package cx.fbn.nevernote;
20 import java.awt.Desktop;
22 import java.io.FileInputStream;
23 import java.io.FileNotFoundException;
24 import java.security.MessageDigest;
25 import java.security.NoSuchAlgorithmException;
26 import java.sql.Connection;
27 import java.sql.DriverManager;
28 import java.sql.SQLException;
29 import java.sql.Statement;
30 import java.text.SimpleDateFormat;
31 import java.util.ArrayList;
32 import java.util.Calendar;
33 import java.util.Collections;
34 import java.util.Comparator;
35 import java.util.Date;
36 import java.util.GregorianCalendar;
37 import java.util.HashMap;
38 import java.util.List;
39 import java.util.SortedMap;
40 import java.util.Vector;
42 import org.apache.thrift.TException;
43 import org.h2.tools.ChangeFileEncryption;
45 import com.evernote.edam.error.EDAMNotFoundException;
46 import com.evernote.edam.error.EDAMSystemException;
47 import com.evernote.edam.error.EDAMUserException;
48 import com.evernote.edam.notestore.NoteFilter;
49 import com.evernote.edam.notestore.NoteVersionId;
50 import com.evernote.edam.type.Data;
51 import com.evernote.edam.type.Note;
52 import com.evernote.edam.type.NoteAttributes;
53 import com.evernote.edam.type.Notebook;
54 import com.evernote.edam.type.QueryFormat;
55 import com.evernote.edam.type.Resource;
56 import com.evernote.edam.type.SavedSearch;
57 import com.evernote.edam.type.Tag;
58 import com.evernote.edam.type.User;
59 import com.trolltech.qt.QThread;
60 import com.trolltech.qt.core.QByteArray;
61 import com.trolltech.qt.core.QDataStream;
62 import com.trolltech.qt.core.QDateTime;
63 import com.trolltech.qt.core.QDir;
64 import com.trolltech.qt.core.QFile;
65 import com.trolltech.qt.core.QFileInfo;
66 import com.trolltech.qt.core.QFileSystemWatcher;
67 import com.trolltech.qt.core.QIODevice;
68 import com.trolltech.qt.core.QIODevice.OpenModeFlag;
69 import com.trolltech.qt.core.QLocale;
70 import com.trolltech.qt.core.QModelIndex;
71 import com.trolltech.qt.core.QSize;
72 import com.trolltech.qt.core.QTemporaryFile;
73 import com.trolltech.qt.core.QTextCodec;
74 import com.trolltech.qt.core.QThreadPool;
75 import com.trolltech.qt.core.QTimer;
76 import com.trolltech.qt.core.QTranslator;
77 import com.trolltech.qt.core.QUrl;
78 import com.trolltech.qt.core.Qt;
79 import com.trolltech.qt.core.Qt.ItemDataRole;
80 import com.trolltech.qt.core.Qt.SortOrder;
81 import com.trolltech.qt.core.Qt.WidgetAttribute;
82 import com.trolltech.qt.gui.QAbstractItemView;
83 import com.trolltech.qt.gui.QAbstractItemView.ScrollHint;
84 import com.trolltech.qt.gui.QAction;
85 import com.trolltech.qt.gui.QApplication;
86 import com.trolltech.qt.gui.QCloseEvent;
87 import com.trolltech.qt.gui.QColor;
88 import com.trolltech.qt.gui.QComboBox;
89 import com.trolltech.qt.gui.QComboBox.InsertPolicy;
90 import com.trolltech.qt.gui.QDesktopServices;
91 import com.trolltech.qt.gui.QDialog;
92 import com.trolltech.qt.gui.QFileDialog;
93 import com.trolltech.qt.gui.QFileDialog.AcceptMode;
94 import com.trolltech.qt.gui.QFileDialog.FileMode;
95 import com.trolltech.qt.gui.QGridLayout;
96 import com.trolltech.qt.gui.QHBoxLayout;
97 import com.trolltech.qt.gui.QIcon;
98 import com.trolltech.qt.gui.QImage;
99 import com.trolltech.qt.gui.QLabel;
100 import com.trolltech.qt.gui.QListWidget;
101 import com.trolltech.qt.gui.QMainWindow;
102 import com.trolltech.qt.gui.QMenu;
103 import com.trolltech.qt.gui.QMessageBox;
104 import com.trolltech.qt.gui.QMessageBox.StandardButton;
105 import com.trolltech.qt.gui.QPixmap;
106 import com.trolltech.qt.gui.QPrintDialog;
107 import com.trolltech.qt.gui.QPrinter;
108 import com.trolltech.qt.gui.QProgressBar;
109 import com.trolltech.qt.gui.QSizePolicy;
110 import com.trolltech.qt.gui.QSizePolicy.Policy;
111 import com.trolltech.qt.gui.QSpinBox;
112 import com.trolltech.qt.gui.QSplashScreen;
113 import com.trolltech.qt.gui.QSplitter;
114 import com.trolltech.qt.gui.QStatusBar;
115 import com.trolltech.qt.gui.QSystemTrayIcon;
116 import com.trolltech.qt.gui.QTableWidgetItem;
117 import com.trolltech.qt.gui.QTextEdit;
118 import com.trolltech.qt.gui.QToolBar;
119 import com.trolltech.qt.gui.QTreeWidgetItem;
120 import com.trolltech.qt.webkit.QWebPage.WebAction;
121 import com.trolltech.qt.webkit.QWebSettings;
122 import com.trolltech.qt.xml.QDomAttr;
123 import com.trolltech.qt.xml.QDomDocument;
124 import com.trolltech.qt.xml.QDomElement;
125 import com.trolltech.qt.xml.QDomNodeList;
127 import cx.fbn.nevernote.config.FileManager;
128 import cx.fbn.nevernote.config.InitializationException;
129 import cx.fbn.nevernote.config.StartupConfig;
130 import cx.fbn.nevernote.dialog.AccountDialog;
131 import cx.fbn.nevernote.dialog.ConfigDialog;
132 import cx.fbn.nevernote.dialog.DBEncryptDialog;
133 import cx.fbn.nevernote.dialog.DatabaseLoginDialog;
134 import cx.fbn.nevernote.dialog.DatabaseStatus;
135 import cx.fbn.nevernote.dialog.FindDialog;
136 import cx.fbn.nevernote.dialog.LoginDialog;
137 import cx.fbn.nevernote.dialog.NotebookArchive;
138 import cx.fbn.nevernote.dialog.NotebookEdit;
139 import cx.fbn.nevernote.dialog.OnlineNoteHistory;
140 import cx.fbn.nevernote.dialog.SavedSearchEdit;
141 import cx.fbn.nevernote.dialog.TagEdit;
142 import cx.fbn.nevernote.dialog.ThumbnailViewer;
143 import cx.fbn.nevernote.dialog.WatchFolder;
144 import cx.fbn.nevernote.filters.EnSearch;
145 import cx.fbn.nevernote.gui.AttributeTreeWidget;
146 import cx.fbn.nevernote.gui.BrowserWindow;
147 import cx.fbn.nevernote.gui.DateAttributeFilterTable;
148 import cx.fbn.nevernote.gui.MainMenuBar;
149 import cx.fbn.nevernote.gui.NotebookTreeWidget;
150 import cx.fbn.nevernote.gui.PDFPreview;
151 import cx.fbn.nevernote.gui.SavedSearchTreeWidget;
152 import cx.fbn.nevernote.gui.TableView;
153 import cx.fbn.nevernote.gui.TagTreeWidget;
154 import cx.fbn.nevernote.gui.Thumbnailer;
155 import cx.fbn.nevernote.gui.TrashTreeWidget;
156 import cx.fbn.nevernote.sql.DatabaseConnection;
157 import cx.fbn.nevernote.sql.WatchFolderRecord;
158 import cx.fbn.nevernote.threads.IndexRunner;
159 import cx.fbn.nevernote.threads.SyncRunner;
160 import cx.fbn.nevernote.utilities.AESEncrypter;
161 import cx.fbn.nevernote.utilities.ApplicationLogger;
162 import cx.fbn.nevernote.utilities.FileImporter;
163 import cx.fbn.nevernote.utilities.FileUtils;
164 import cx.fbn.nevernote.utilities.ListManager;
165 import cx.fbn.nevernote.utilities.SyncTimes;
166 import cx.fbn.nevernote.xml.ExportData;
167 import cx.fbn.nevernote.xml.ImportData;
168 import cx.fbn.nevernote.xml.XMLInsertHilight;
171 public class NeverNote extends QMainWindow{
173 QStatusBar statusBar; // Application status bar
175 DatabaseConnection conn;
177 MainMenuBar menuBar; // Main menu bar
178 FindDialog find; // Text search in note dialog
179 List<String> emitLog; // Messages displayed in the status bar;
180 QSystemTrayIcon trayIcon; // little tray icon
181 QMenu trayMenu; // System tray menu
182 QAction trayExitAction; // Exit the application
183 QAction trayShowAction; // toggle the show/hide action
184 QAction trayAddNoteAction; // Add a note from the system tray
186 NotebookTreeWidget notebookTree; // List of notebooks
187 AttributeTreeWidget attributeTree; // List of note attributes
188 TagTreeWidget tagTree; // list of user created tags
189 SavedSearchTreeWidget savedSearchTree; // list of saved searches
190 TrashTreeWidget trashTree; // Trashcan
191 TableView noteTableView; // List of notes (the widget).
193 public BrowserWindow browserWindow; // Window containing browser & labels
194 public QToolBar toolBar; // The tool bar under the menu
195 // QLineEdit searchField; // The search filter bar on the toolbar
196 QComboBox searchField; // search filter bar on the toolbar;
197 boolean searchPerformed = false; // Search was done?
198 QProgressBar quotaBar; // The current quota usage
200 ApplicationLogger logger;
201 List<String> selectedNotebookGUIDs; // List of notebook GUIDs
202 List<String> selectedTagGUIDs; // List of selected tag GUIDs
203 List<String> selectedNoteGUIDs; // List of selected notes
204 String selectedSavedSearchGUID; // Currently selected saved searches
206 NoteFilter filter; // Note filter
207 String currentNoteGuid; // GUID of the current note
208 Note currentNote; // The currently viewed note
209 boolean noteDirty; // Has the note been changed?
210 boolean inkNote; // if this is an ink note, it is read only
212 ListManager listManager; // DB runnable task
214 List<QTemporaryFile> tempFiles; // Array of temporary files;
216 QTimer indexTimer; // timer to start the index thread
217 IndexRunner indexRunner; // thread to index notes
220 QTimer syncTimer; // Sync on an interval
221 QTimer syncDelayTimer; // Sync delay to free up database
222 SyncRunner syncRunner; // thread to do a sync.
224 QTimer saveTimer; // Timer to save note contents
226 QTimer authTimer; // Refresh authentication
227 QTimer externalFileSaveTimer; // Save files altered externally
228 List<String> externalFiles; // External files to save later
229 List<String> importFilesKeep; // Auto-import files to save later
230 List<String> importFilesDelete; // Auto-import files to save later
232 int indexTime; // how often to try and index
233 boolean indexRunning; // Is indexing running?
234 boolean indexDisabled; // Is indexing disabled?
236 int syncThreadsReady; // number of sync threads that are free
237 int syncTime; // Sync interval
238 boolean syncRunning; // Is sync running?
239 boolean automaticSync; // do sync automatically?
240 QTreeWidgetItem attributeTreeSelected;
242 QAction prevButton; // Go to the previous item viewed
243 QAction nextButton; // Go to the next item in the history
244 QAction downButton; // Go to the next item in the list
245 QAction upButton; // Go to the prev. item in the list;
246 QAction synchronizeButton; // Synchronize with Evernote
247 List<QIcon> synchronizeAnimation; // Synchronize movie
248 QTimer synchronizeAnimationTimer; // Timer to change animation button
249 int synchronizeFrame; // Current frame being viewed
250 QAction printButton; // Print Button
251 QAction tagButton; // Tag edit button
252 QAction attributeButton; // Attribute information button
253 QAction emailButton; // Email button
254 QAction deleteButton; // Delete button
255 QAction newButton; // new Note Button;
256 QSpinBox zoomSpinner; // Zoom zoom
257 QAction searchClearButton; // Clear the search field
259 QSplitter mainLeftRightSplitter; // main splitter for left/right side
260 QSplitter leftSplitter1; // first left hand splitter
261 QSplitter browserIndexSplitter; // splitter between note index & note text
263 QFileSystemWatcher importKeepWatcher; // Watch & keep auto-import
264 QFileSystemWatcher importDeleteWatcher; // Watch & Delete auto-import
265 List<String> importedFiles; // History of imported files (so we don't import twice)
267 OnlineNoteHistory historyWindow; // online history window
268 List<NoteVersionId> versions; // history versions
270 QTimer threadMonitorTimer; // Timer to watch threads.
271 int dbThreadDeadCount=0; // number of consecutive dead times for the db thread
272 int syncThreadDeadCount=0; // number of consecutive dead times for the sync thread
273 int indexThreadDeadCount=0; // number of consecutive dead times for the index thread
274 int notebookThreadDeadCount=0; // number of consecutive dead times for the notebook thread
275 int tagDeadCount=0; // number of consecutive dead times for the tag thread
276 int trashDeadCount=0; // number of consecutive dead times for the trash thread
277 int saveThreadDeadCount=0; // number of consecutive dead times for the save thread
279 HashMap<String, String> noteCache; // Cash of note content
280 List<String> historyGuids; // GUIDs of previously viewed items
281 int historyPosition; // Position within the viewed items
282 boolean fromHistory; // Is this from the history queue?
283 String trashNoteGuid; // Guid to restore / set into or out of trash to save position
284 Thumbnailer preview; // generate preview image
285 ThumbnailViewer thumbnailViewer; // View preview thumbnail;
286 boolean encryptOnShutdown; // should I encrypt when I close?
287 boolean decryptOnShutdown; // should I decrypt on shutdown;
288 String encryptCipher; // What cipher should I use?
290 String iconPath = new String("classpath:cx/fbn/nevernote/icons/");
293 //***************************************************************
294 //***************************************************************
295 //** Constructor & main entry point
296 //***************************************************************
297 //***************************************************************
298 // Application Constructor
299 public NeverNote(DatabaseConnection dbConn) {
302 thread().setPriority(Thread.MAX_PRIORITY);
304 logger = new ApplicationLogger("nevernote.log");
305 logger.log(logger.HIGH, "Starting Application");
307 decryptOnShutdown = false;
308 encryptOnShutdown = false;
309 conn.checkDatabaseVersion();
313 // Start building the invalid XML tables
314 Global.invalidElements = conn.getInvalidXMLTable().getInvalidElements();
315 List<String> elements = conn.getInvalidXMLTable().getInvalidAttributeElements();
317 for (int i=0; i<elements.size(); i++) {
318 Global.invalidAttributes.put(elements.get(i), conn.getInvalidXMLTable().getInvalidAttributes(elements.get(i)));
321 logger.log(logger.EXTREME, "Starting GUI build");
323 QTranslator qtTranslator = new QTranslator();
324 qtTranslator.load("classpath:/translations/qt_" + QLocale.system().name() + ".qm");
325 QApplication.instance().installTranslator(qtTranslator);
327 QTranslator nevernoteTranslator = new QTranslator();
328 nevernoteTranslator.load("classpath:/translations/nevernote_"+QLocale.system().name()+ ".qm");
329 QApplication.instance().installTranslator(nevernoteTranslator);
331 Global.originalPalette = QApplication.palette();
332 QApplication.setStyle(Global.getStyle());
333 if (Global.useStandardPalette())
334 QApplication.setPalette(QApplication.style().standardPalette());
335 setWindowTitle("NeverNote");
337 mainLeftRightSplitter = new QSplitter();
338 setCentralWidget(mainLeftRightSplitter);
339 leftSplitter1 = new QSplitter();
340 leftSplitter1.setOrientation(Qt.Orientation.Vertical);
342 browserIndexSplitter = new QSplitter();
343 browserIndexSplitter.setOrientation(Qt.Orientation.Vertical);
345 //* Setup threads & thread timers
346 int indexRunnerCount = Global.getIndexThreads();
347 indexRunnerCount = 1;
348 QThreadPool.globalInstance().setMaxThreadCount(indexRunnerCount+5); // increase max thread count
350 logger.log(logger.EXTREME, "Building list manager");
351 listManager = new ListManager(conn, logger);
353 logger.log(logger.EXTREME, "Building index runners & timers");
354 indexRunner = new IndexRunner("indexRunner.log", Global.getDatabaseUrl(), Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
355 indexThread = new QThread(indexRunner, "Index Thread");
358 synchronizeAnimationTimer = new QTimer();
359 synchronizeAnimationTimer.timeout.connect(this, "updateSyncButton()");
361 indexTimer = new QTimer();
362 indexTime = 1000*Global.getIndexThreadSleepInterval();
363 indexTimer.start(indexTime); // Start indexing timer
364 indexTimer.timeout.connect(this, "indexTimer()");
365 indexDisabled = false;
366 indexRunning = false;
368 logger.log(logger.EXTREME, "Setting sync thread & timers");
370 syncRunner = new SyncRunner("syncRunner.log", Global.getDatabaseUrl(), Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
371 syncTime = new SyncTimes().timeValue(Global.getSyncInterval());
372 syncTimer = new QTimer();
373 syncTimer.timeout.connect(this, "syncTimer()");
374 syncRunner.status.message.connect(this, "setMessage(String)");
375 syncRunner.syncSignal.finished.connect(this, "syncThreadComplete(Boolean)");
376 syncRunner.syncSignal.errorDisconnect.connect(this, "remoteErrorDisconnect()");
379 automaticSync = true;
380 syncTimer.start(syncTime*60*1000);
382 automaticSync = false;
385 syncRunner.setEvernoteUpdateCount(Global.getEvernoteUpdateCount());
386 syncThread = new QThread(syncRunner, "Synchronization Thread");
390 logger.log(logger.EXTREME, "Starting authentication timer");
391 authTimer = new QTimer();
392 authTimer.timeout.connect(this, "authTimer()");
393 authTimer.start(1000*60*15);
394 syncRunner.syncSignal.authRefreshComplete.connect(this, "authRefreshComplete(boolean)");
396 logger.log(logger.EXTREME, "Setting save note timer");
397 saveTimer = new QTimer();
398 saveTimer.timeout.connect(this, "saveNote()");
399 if (Global.getAutoSaveInterval() > 0) {
400 saveTimer.setInterval(1000*60*Global.getAutoSaveInterval());
401 // saveTimer.setInterval(1000*10); // auto save every 20 seconds;
404 listManager.saveRunner.noteSignals.noteSaveRunnerError.connect(this, "saveRunnerError(String, String)");
406 logger.log(logger.EXTREME, "Starting external file monitor timer");
407 externalFileSaveTimer = new QTimer();
408 externalFileSaveTimer.timeout.connect(this, "externalFileEditedSaver()");
409 externalFileSaveTimer.setInterval(1000*5); // save every 5 seconds;
410 externalFiles = new ArrayList<String>();
411 importFilesDelete = new ArrayList<String>();
412 importFilesKeep = new ArrayList<String>();
413 externalFileSaveTimer.start();
415 notebookTree = new NotebookTreeWidget();
416 attributeTree = new AttributeTreeWidget();
417 tagTree = new TagTreeWidget(conn);
418 savedSearchTree = new SavedSearchTreeWidget();
419 trashTree = new TrashTreeWidget();
420 noteTableView = new TableView(logger, listManager);
422 QGridLayout leftGrid = new QGridLayout();
423 leftSplitter1.setLayout(leftGrid);
424 leftGrid.addWidget(notebookTree, 1, 1);
425 leftGrid.addWidget(tagTree,2,1);
426 leftGrid.addWidget(attributeTree,3,1);
427 leftGrid.addWidget(savedSearchTree,4,1);
428 leftGrid.addWidget(trashTree, 5, 1);
430 // Setup the browser window
431 noteCache = new HashMap<String,String>();
432 browserWindow = new BrowserWindow(conn);
434 browserIndexSplitter.addWidget(noteTableView);
435 browserIndexSplitter.addWidget(browserWindow);
437 mainLeftRightSplitter.addWidget(leftSplitter1);
438 mainLeftRightSplitter.addWidget(browserIndexSplitter);
440 searchField = new QComboBox();
441 searchField.setEditable(true);
442 searchField.activatedIndex.connect(this, "searchFieldChanged()");
443 searchField.setDuplicatesEnabled(false);
444 searchField.editTextChanged.connect(this,"searchFieldTextChanged(String)");
446 quotaBar = new QProgressBar();
448 // Setup the thumbnail viewer
449 thumbnailViewer = new ThumbnailViewer();
450 thumbnailViewer.upArrow.connect(this, "upAction()");
451 thumbnailViewer.downArrow.connect(this, "downAction()");
452 thumbnailViewer.leftArrow.connect(this, "nextViewedAction()");
453 thumbnailViewer.rightArrow.connect(this, "previousViewedAction()");
455 listManager.loadNotesIndex();
456 initializeNotebookTree();
458 initializeSavedSearchTree();
459 attributeTree.itemClicked.connect(this, "attributeTreeClicked(QTreeWidgetItem, Integer)");
460 attributeTreeSelected = null;
461 initializeNoteTable();
463 selectedNoteGUIDs = new ArrayList<String>();
464 statusBar = new QStatusBar();
465 setStatusBar(statusBar);
466 menuBar = new MainMenuBar(this);
467 emitLog = new ArrayList<String>();
469 tagTree.setDeleteAction(menuBar.tagDeleteAction);
470 tagTree.setEditAction(menuBar.tagEditAction);
471 tagTree.setAddAction(menuBar.tagAddAction);
472 tagTree.setVisible(Global.isWindowVisible("tagTree"));
473 tagTree.noteSignal.tagsAdded.connect(this, "tagsAdded(String, String)");
474 menuBar.hideTags.setChecked(Global.isWindowVisible("tagTree"));
475 listManager.tagSignal.listChanged.connect(this, "reloadTagTree()");
477 notebookTree.setDeleteAction(menuBar.notebookDeleteAction);
478 notebookTree.setEditAction(menuBar.notebookEditAction);
479 notebookTree.setAddAction(menuBar.notebookAddAction);
480 notebookTree.setVisible(Global.isWindowVisible("notebookTree"));
481 notebookTree.noteSignal.notebookChanged.connect(this, "updateNoteNotebook(String, String)");
482 menuBar.hideNotebooks.setChecked(Global.isWindowVisible("notebookTree"));
484 savedSearchTree.setAddAction(menuBar.savedSearchAddAction);
485 savedSearchTree.setEditAction(menuBar.savedSearchEditAction);
486 savedSearchTree.setDeleteAction(menuBar.savedSearchDeleteAction);
487 savedSearchTree.itemSelectionChanged.connect(this, "updateSavedSearchSelection()");
488 savedSearchTree.setVisible(Global.isWindowVisible("savedSearchTree"));
489 menuBar.hideSavedSearches.setChecked(Global.isWindowVisible("savedSearchTree"));
491 noteTableView.setAddAction(menuBar.noteAdd);
492 noteTableView.setDeleteAction(menuBar.noteDelete);
493 noteTableView.setRestoreAction(menuBar.noteRestoreAction);
494 noteTableView.setNoteDuplicateAction(menuBar.noteDuplicateAction);
495 noteTableView.setNoteHistoryAction(menuBar.noteOnlineHistoryAction);
496 noteTableView.noteSignal.titleColorChanged.connect(this, "titleColorChanged(Integer)");
497 noteTableView.setMergeNotesAction(menuBar.noteMergeAction);
498 noteTableView.rowChanged.connect(this, "scrollToGuid(String)");
499 noteTableView.resetViewport.connect(this, "scrollToCurrentGuid()");
500 noteTableView.doubleClicked.connect(this, "listDoubleClick()");
501 listManager.trashSignal.countChanged.connect(trashTree, "updateCounts(Integer)");
503 trashTree.itemSelectionChanged.connect(this, "trashTreeSelection()");
504 trashTree.setEmptyAction(menuBar.emptyTrashAction);
505 trashTree.setVisible(Global.isWindowVisible("trashTree"));
506 menuBar.hideTrash.setChecked(Global.isWindowVisible("trashTree"));
507 trashTree.updateCounts(listManager.getTrashCount());
509 attributeTree.setVisible(Global.isWindowVisible("attributeTree"));
510 menuBar.hideAttributes.setChecked(Global.isWindowVisible("attributeTree"));
512 noteTableView.setVisible(Global.isWindowVisible("noteList"));
513 menuBar.hideNoteList.setChecked(Global.isWindowVisible("noteList"));
515 if (!Global.isWindowVisible("editorButtonBar"))
516 toggleEditorButtonBar();
517 if (!Global.isWindowVisible("leftPanel"))
518 menuBar.hideLeftSide.setChecked(true);
522 find = new FindDialog();
523 find.getOkButton().clicked.connect(this, "doFindText()");
525 // Setup the tray icon menu bar
526 trayShowAction = new QAction("Show/Hide", this);
527 trayExitAction = new QAction("Exit", this);
528 trayAddNoteAction = new QAction("Add Note", this);
530 trayExitAction.triggered.connect(this, "close()");
531 trayAddNoteAction.triggered.connect(this, "addNote()");
532 trayShowAction.triggered.connect(this, "trayToggleVisible()");
534 trayMenu = new QMenu(this);
535 trayMenu.addAction(trayAddNoteAction);
536 trayMenu.addAction(trayShowAction);
537 trayMenu.addAction(trayExitAction);
540 trayIcon = new QSystemTrayIcon(this);
541 trayIcon.setToolTip("NeverNote");
542 trayIcon.setContextMenu(trayMenu);
543 trayIcon.activated.connect(this, "trayActivated(com.trolltech.qt.gui.QSystemTrayIcon$ActivationReason)");
546 currentNoteGuid = Global.getLastViewedNoteGuid();
547 historyGuids = new ArrayList<String>();
551 if (!currentNoteGuid.trim().equals("")) {
552 currentNote = conn.getNoteTable().getNote(currentNoteGuid, true,true,false,false,true);
555 noteIndexUpdated(true);
557 menuBar.showEditorBar.setChecked(Global.isWindowVisible("editorButtonBar"));
558 if (menuBar.showEditorBar.isChecked())
560 tagIndexUpdated(true);
561 savedSearchIndexUpdated();
562 notebookIndexUpdated();
564 setupSyncSignalListeners();
565 setupBrowserSignalListeners();
566 setupIndexListeners();
569 tagTree.tagSignal.listChanged.connect(this, "tagIndexUpdated()");
570 tagTree.showAllTags(true);
572 QIcon appIcon = new QIcon(iconPath+"nevernote.png");
573 setWindowIcon(appIcon);
574 trayIcon.setIcon(appIcon);
575 if (Global.showTrayIcon())
580 scrollToGuid(currentNoteGuid);
581 if (Global.automaticLogin()) {
583 if (Global.isConnected)
586 setupFolderImports();
589 restoreWindowState();
591 if (Global.mimicEvernoteInterface) {
592 notebookTree.selectGuid("");
595 threadMonitorTimer = new QTimer();
596 threadMonitorTimer.timeout.connect(this, "threadMonitorCheck()");
597 threadMonitorTimer.start(1000*10); // Check for threads every 10 seconds;
599 historyGuids.add(currentNoteGuid);
602 int sortCol = Global.getSortColumn();
603 int sortOrder = Global.getSortOrder();
604 noteTableView.sortByColumn(sortCol, SortOrder.resolve(sortOrder));
609 public static void main(String[] args) {
610 QApplication.initialize(args);
611 QPixmap pixmap = new QPixmap("classpath:cx/fbn/nevernote/icons/splash_logo.png");
612 QSplashScreen splash = new QSplashScreen(pixmap);
615 DatabaseConnection dbConn;
618 initializeGlobalSettings(args);
620 showSplash = Global.isWindowVisible("SplashScreen");
624 dbConn = setupDatabaseConnection();
626 // Must be last stage of setup - only safe once DB is open hence we know we are the only instance running
627 Global.getFileManager().purgeResDirectory();
629 } catch (InitializationException e) {
632 QMessageBox.critical(null, "Startup error", "Aborting: " + e.getMessage());
636 NeverNote application = new NeverNote(dbConn);
638 application.setAttribute(WidgetAttribute.WA_DeleteOnClose, true);
639 if (Global.wasWindowMaximized())
640 application.showMaximized();
644 splash.finish(application);
646 System.out.println("Goodbye.");
651 * Open the internal database, or create if not present
653 * @throws InitializationException when opening the database fails, e.g. because another process has it locked
655 private static DatabaseConnection setupDatabaseConnection() throws InitializationException {
656 ApplicationLogger logger = new ApplicationLogger("nevernote-database.log");
658 File f = Global.getFileManager().getDbDirFile(Global.databaseName + ".h2.db");
659 boolean dbExists = f.exists();
661 Global.setDatabaseUrl("");
663 if (Global.getDatabaseUrl().toUpperCase().indexOf("CIPHER=") > -1) {
664 boolean goodCheck = false;
666 DatabaseLoginDialog dialog = new DatabaseLoginDialog();
668 if (!dialog.okPressed())
670 Global.cipherPassword = dialog.getPassword();
671 goodCheck = databaseCheck(Global.getDatabaseUrl(), Global.getDatabaseUserid(),
672 Global.getDatabaseUserPassword(), Global.cipherPassword);
675 DatabaseConnection dbConn = new DatabaseConnection(logger,Global.getDatabaseUrl(), Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
679 // Encrypt the database upon shutdown
680 private void encryptOnShutdown() {
681 String dbPath= Global.getFileManager().getDbDirPath("");
682 String dbName = "NeverNote";
684 Statement st = conn.getConnection().createStatement();
685 st.execute("shutdown");
686 QMessageBox box = new QMessageBox();
687 box.setText("Encrypting Database");
689 ChangeFileEncryption.execute(dbPath, dbName, encryptCipher, null, Global.cipherPassword.toCharArray(), true);
690 Global.setDatabaseUrl(Global.getDatabaseUrl() + ";CIPHER="+encryptCipher);
691 box.setText("Encryption Complete");
693 } catch (SQLException e) {
698 // Decrypt the database upon shutdown
699 private void decryptOnShutdown() {
700 String dbPath= Global.getFileManager().getDbDirPath("");
701 String dbName = "NeverNote";
703 Statement st = conn.getConnection().createStatement();
704 st.execute("shutdown");
705 if (Global.getDatabaseUrl().toUpperCase().indexOf(";CIPHER=AES") > -1)
706 encryptCipher = "AES";
708 encryptCipher = "XTEA";
709 QMessageBox box = new QMessageBox();
710 box.setText("Decrypting Database");
712 ChangeFileEncryption.execute(dbPath, dbName, encryptCipher, Global.cipherPassword.toCharArray(), null, true);
713 Global.setDatabaseUrl("");
714 box.setText("Decryption Complete");
716 } catch (SQLException e) {
721 * Encrypt/Decrypt the local database
723 public void doDatabaseEncrypt() {
724 // The database is not currently encrypted
725 if (Global.getDatabaseUrl().toUpperCase().indexOf("CIPHER=") == -1) {
726 if (QMessageBox.question(this, tr("Confirmation"), tr("Encrypting the database is used" +
727 "to enhance security and is performed\nupon shutdown, but please be aware that if"+
728 " you lose the password your\nis lost forever.\n\nIt is highly recommended you " +
729 "perform a backup and/or fully synchronize\n prior to executing this funtction.\n\n" +
730 "Do you wish to proceed?"),
731 QMessageBox.StandardButton.Yes,
732 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
735 DBEncryptDialog dialog = new DBEncryptDialog();
737 if (dialog.okPressed()) {
738 Global.cipherPassword = dialog.getPassword();
739 encryptOnShutdown = true;
740 encryptCipher = "AES";
743 DBEncryptDialog dialog = new DBEncryptDialog();
744 dialog.setWindowTitle("Database Decryption");
746 if (dialog.okPressed()) {
747 if (!dialog.getPassword().equals(Global.cipherPassword)) {
748 QMessageBox.critical(null, "Incorrect Password", "Incorrect Password");
751 decryptOnShutdown = true;
758 private static void initializeGlobalSettings(String[] args) throws InitializationException {
759 StartupConfig startupConfig = new StartupConfig();
761 for (String arg : args) {
762 String lower = arg.toLowerCase();
763 if (lower.startsWith("--name="))
764 startupConfig.setName(arg.substring(arg.indexOf('=') + 1));
765 if (lower.startsWith("--home="))
766 startupConfig.setHomeDirPath(arg.substring(arg.indexOf('=') + 1));
767 if (lower.startsWith("--disable-viewing"))
768 startupConfig.setDisableViewing(true);
770 Global.setup(startupConfig);
775 public void closeEvent(QCloseEvent event) {
776 logger.log(logger.HIGH, "Entering NeverNote.closeEvent");
779 if (currentNote!= null & browserWindow!=null) {
780 if (!currentNote.getTitle().equals(browserWindow.getTitle()))
781 conn.getNoteTable().updateNoteTitle(currentNote.getGuid(), browserWindow.getTitle());
784 setMessage(tr("Beginning shutdown."));
786 externalFileEditedSaver();
787 if (Global.isConnected && Global.synchronizeOnClose()) {
788 setMessage(tr("Performing synchronization before closing."));
789 syncRunner.addWork("SYNC");
791 setMessage("Closing Program.");
792 threadMonitorTimer.stop();
794 syncRunner.addWork("STOP");
795 indexRunner.addWork("STOP");
800 if (tempFiles != null)
803 browserWindow.noteSignal.tagsChanged.disconnect();
804 browserWindow.noteSignal.titleChanged.disconnect();
805 browserWindow.noteSignal.noteChanged.disconnect();
806 browserWindow.noteSignal.notebookChanged.disconnect();
807 browserWindow.noteSignal.createdDateChanged.disconnect();
808 browserWindow.noteSignal.alteredDateChanged.disconnect();
809 syncRunner.searchSignal.listChanged.disconnect();
810 syncRunner.tagSignal.listChanged.disconnect();
811 syncRunner.notebookSignal.listChanged.disconnect();
812 syncRunner.noteIndexSignal.listChanged.disconnect();
815 int position = noteTableView.header.visualIndex(Global.noteTableCreationPosition);
816 Global.setColumnPosition("noteTableCreationPosition", position);
817 position = noteTableView.header.visualIndex(Global.noteTableTagPosition);
818 Global.setColumnPosition("noteTableTagPosition", position);
819 position = noteTableView.header.visualIndex(Global.noteTableNotebookPosition);
820 Global.setColumnPosition("noteTableNotebookPosition", position);
821 position = noteTableView.header.visualIndex(Global.noteTableChangedPosition);
822 Global.setColumnPosition("noteTableChangedPosition", position);
823 position = noteTableView.header.visualIndex(Global.noteTableAuthorPosition);
824 Global.setColumnPosition("noteTableAuthorPosition", position);
825 position = noteTableView.header.visualIndex(Global.noteTableSourceUrlPosition);
826 Global.setColumnPosition("noteTableSourceUrlPosition", position);
827 position = noteTableView.header.visualIndex(Global.noteTableSubjectDatePosition);
828 Global.setColumnPosition("noteTableSubjectDatePosition", position);
829 position = noteTableView.header.visualIndex(Global.noteTableTitlePosition);
830 Global.setColumnPosition("noteTableTitlePosition", position);
831 position = noteTableView.header.visualIndex(Global.noteTableSynchronizedPosition);
832 Global.setColumnPosition("noteTableSynchronizedPosition", position);
834 Global.saveWindowVisible("toolBar", toolBar.isVisible());
835 saveNoteIndexWidth();
837 int width = notebookTree.columnWidth(0);
838 Global.setColumnWidth("notebookTreeName", width);
839 width = tagTree.columnWidth(0);
840 Global.setColumnWidth("tagTreeName", width);
842 Global.saveWindowMaximized(isMaximized());
843 Global.saveCurrentNoteGuid(currentNoteGuid);
845 int sortCol = noteTableView.proxyModel.sortColumn();
846 int sortOrder = noteTableView.proxyModel.sortOrder().value();
847 Global.setSortColumn(sortCol);
848 Global.setSortOrder(sortOrder);
852 Global.keepRunning = false;
854 logger.log(logger.MEDIUM, "Waiting for indexThread to stop");
855 indexRunner.thread().join(50);
856 logger.log(logger.MEDIUM, "Index thread has stopped");
857 } catch (InterruptedException e1) {
858 e1.printStackTrace();
860 if (!syncRunner.isIdle()) {
862 logger.log(logger.MEDIUM, "Waiting for syncThread to stop");
864 logger.log(logger.MEDIUM, "Sync thread has stopped");
865 } catch (InterruptedException e1) {
866 e1.printStackTrace();
870 if (encryptOnShutdown) {
873 if (decryptOnShutdown) {
876 logger.log(logger.HIGH, "Leaving NeverNote.closeEvent");
879 public void setMessage(String s) {
880 logger.log(logger.HIGH, "Entering NeverNote.setMessage");
881 logger.log(logger.HIGH, "Message: " +s);
882 statusBar.showMessage(s);
884 logger.log(logger.HIGH, "Leaving NeverNote.setMessage");
887 private void waitCursor(boolean wait) {
889 // QApplication.setOverrideCursor(new QCursor(Qt.CursorShape.WaitCursor));
891 // QApplication.restoreOverrideCursor();
894 private void setupIndexListeners() {
895 indexRunner.noteSignal.noteIndexed.connect(this, "indexThreadComplete(String)");
896 indexRunner.resourceSignal.resourceIndexed.connect(this, "indexThreadComplete(String)");
897 // indexRunner.threadSignal.indexNeeded.connect(listManager, "setIndexNeeded(String, String, Boolean)");
899 private void setupSyncSignalListeners() {
900 syncRunner.tagSignal.listChanged.connect(this, "tagIndexUpdated()");
901 syncRunner.searchSignal.listChanged.connect(this, "savedSearchIndexUpdated()");
902 syncRunner.notebookSignal.listChanged.connect(this, "notebookIndexUpdated()");
903 syncRunner.noteIndexSignal.listChanged.connect(this, "noteIndexUpdated(boolean)");
904 syncRunner.noteSignal.quotaChanged.connect(this, "updateQuotaBar()");
906 syncRunner.syncSignal.saveUploadAmount.connect(this,"saveUploadAmount(long)");
907 syncRunner.syncSignal.saveUserInformation.connect(this,"saveUserInformation(User)");
908 syncRunner.syncSignal.saveEvernoteUpdateCount.connect(this,"saveEvernoteUpdateCount(int)");
910 syncRunner.noteSignal.guidChanged.connect(this, "noteGuidChanged(String, String)");
911 syncRunner.noteSignal.noteChanged.connect(this, "invalidateNoteCache(String, String)");
912 syncRunner.resourceSignal.resourceGuidChanged.connect(this, "noteResourceGuidChanged(String,String,String)");
913 syncRunner.noteSignal.noteDownloaded.connect(listManager, "noteDownloaded(Note)");
915 syncRunner.syncSignal.refreshLists.connect(this, "refreshLists()");
918 private void setupBrowserSignalListeners() {
920 browserWindow.fileWatcher.fileChanged.connect(this, "externalFileEdited(String)");
921 browserWindow.noteSignal.tagsChanged.connect(this, "updateNoteTags(String, List)");
922 browserWindow.noteSignal.tagsChanged.connect(this, "updateListTags(String, List)");
923 //browserWindow.noteSignal.noteChanged.connect(this, "invalidateNoteCache(String, String)");
924 browserWindow.noteSignal.noteChanged.connect(this, "setNoteDirty()");
925 browserWindow.noteSignal.titleChanged.connect(listManager, "updateNoteTitle(String, String)");
926 browserWindow.noteSignal.notebookChanged.connect(this, "updateNoteNotebook(String, String)");
927 browserWindow.noteSignal.createdDateChanged.connect(listManager, "updateNoteCreatedDate(String, QDateTime)");
928 browserWindow.noteSignal.alteredDateChanged.connect(listManager, "updateNoteAlteredDate(String, QDateTime)");
929 browserWindow.noteSignal.subjectDateChanged.connect(listManager, "updateNoteSubjectDate(String, QDateTime)");
930 browserWindow.noteSignal.authorChanged.connect(listManager, "updateNoteAuthor(String, String)");
931 browserWindow.noteSignal.geoChanged.connect(listManager, "updateNoteGeoTag(String, Double,Double,Double)");
932 browserWindow.noteSignal.geoChanged.connect(this, "setNoteDirty()");
933 browserWindow.noteSignal.sourceUrlChanged.connect(listManager, "updateNoteSourceUrl(String, String)");
934 browserWindow.focusLost.connect(this, "saveNote()");
935 browserWindow.resourceSignal.contentChanged.connect(this, "externalFileEdited(String)");
940 //***************************************************************
941 //***************************************************************
942 //* Settings and look & feel
943 //***************************************************************
944 //***************************************************************
945 @SuppressWarnings("unused")
946 private void settings() {
947 logger.log(logger.HIGH, "Entering NeverNote.settings");
948 ConfigDialog settings = new ConfigDialog(this);
949 String dateFormat = Global.getDateFormat();
950 String timeFormat = Global.getTimeFormat();
952 indexTime = 1000*Global.getIndexThreadSleepInterval();
953 indexTimer.start(indexTime); // reset indexing timer
956 if (Global.showTrayIcon())
961 if (menuBar.showEditorBar.isChecked())
964 // Reset the save timer
965 if (Global.getAutoSaveInterval() > 0)
966 saveTimer.setInterval(1000*60*Global.getAutoSaveInterval());
970 // This is a hack to force a reload of the index in case the date or time changed.
971 // if (!dateFormat.equals(Global.getDateFormat()) ||
972 // !timeFormat.equals(Global.getTimeFormat())) {
974 noteIndexUpdated(true);
977 logger.log(logger.HIGH, "Leaving NeverNote.settings");
979 // Restore things to the way they were
980 private void restoreWindowState() {
981 // We need to name things or this doesn't work.
982 setObjectName("NeverNote");
983 mainLeftRightSplitter.setObjectName("mainLeftRightSplitter");
984 browserIndexSplitter.setObjectName("browserIndexSplitter");
985 leftSplitter1.setObjectName("leftSplitter1");
987 // Restore the actual positions.
988 restoreGeometry(Global.restoreGeometry(objectName()));
989 mainLeftRightSplitter.restoreState(Global.restoreState(mainLeftRightSplitter.objectName()));
990 browserIndexSplitter.restoreState(Global.restoreState(browserIndexSplitter.objectName()));
991 leftSplitter1.restoreState(Global.restoreState(leftSplitter1.objectName()));
994 // Save window positions for the next start
995 private void saveWindowState() {
996 Global.saveGeometry(objectName(), saveGeometry());
997 Global.saveState(mainLeftRightSplitter.objectName(), mainLeftRightSplitter.saveState());
998 Global.saveState(browserIndexSplitter.objectName(), browserIndexSplitter.saveState());
999 Global.saveState(leftSplitter1.objectName(), leftSplitter1.saveState());
1001 // Load the style sheet
1002 private void loadStyleSheet() {
1003 String fileName = Global.getFileManager().getQssDirPath("default.qss");
1004 QFile file = new QFile(fileName);
1005 file.open(OpenModeFlag.ReadOnly);
1006 String styleSheet = file.readAll().toString();
1008 setStyleSheet(styleSheet);
1010 // Save column widths for the next time
1011 private void saveNoteIndexWidth() {
1013 width = noteTableView.getColumnWidth(Global.noteTableCreationPosition);
1014 Global.setColumnWidth("noteTableCreationPosition", width);
1015 width = noteTableView.getColumnWidth(Global.noteTableChangedPosition);
1016 Global.setColumnWidth("noteTableChangedPosition", width);
1017 width = noteTableView.getColumnWidth(Global.noteTableGuidPosition);
1018 Global.setColumnWidth("noteTableGuidPosition", width);
1019 width = noteTableView.getColumnWidth(Global.noteTableNotebookPosition);
1020 Global.setColumnWidth("noteTableNotebookPosition", width);
1021 width = noteTableView.getColumnWidth(Global.noteTableTagPosition);
1022 Global.setColumnWidth("noteTableTagPosition", width);
1023 width = noteTableView.getColumnWidth(Global.noteTableTitlePosition);
1024 Global.setColumnWidth("noteTableTitlePosition", width);
1025 width = noteTableView.getColumnWidth(Global.noteTableSourceUrlPosition);
1026 Global.setColumnWidth("noteTableSourceUrlPosition", width);
1027 width = noteTableView.getColumnWidth(Global.noteTableAuthorPosition);
1028 Global.setColumnWidth("noteTableAuthorPosition", width);
1029 width = noteTableView.getColumnWidth(Global.noteTableSubjectDatePosition);
1030 Global.setColumnWidth("noteTableSubjectDatePosition", width);
1031 width = noteTableView.getColumnWidth(Global.noteTableSynchronizedPosition);
1032 Global.setColumnWidth("noteTableSynchronizedPosition", width);
1036 //***************************************************************
1037 //***************************************************************
1038 //** These functions deal with Notebook menu items
1039 //***************************************************************
1040 //***************************************************************
1041 // Setup the tree containing the user's notebooks.
1042 private void initializeNotebookTree() {
1043 logger.log(logger.HIGH, "Entering NeverNote.initializeNotebookTree");
1044 notebookTree.itemSelectionChanged.connect(this, "notebookTreeSelection()");
1045 listManager.notebookSignal.refreshNotebookTreeCounts.connect(notebookTree, "updateCounts(List, List)");
1046 // notebookTree.resize(Global.getSize("notebookTree"));
1047 logger.log(logger.HIGH, "Leaving NeverNote.initializeNotebookTree");
1049 // Listener when a notebook is selected
1050 private void notebookTreeSelection() {
1051 logger.log(logger.HIGH, "Entering NeverNote.notebookTreeSelection");
1054 clearAttributeFilter();
1055 clearSavedSearchFilter();
1056 if (Global.mimicEvernoteInterface) {
1058 searchField.clear();
1060 menuBar.noteRestoreAction.setVisible(false);
1061 menuBar.notebookEditAction.setEnabled(true);
1062 menuBar.notebookDeleteAction.setEnabled(true);
1063 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1064 QTreeWidgetItem currentSelection;
1065 selectedNotebookGUIDs.clear();
1066 if (!Global.mimicEvernoteInterface) {
1067 for (int i=0; i<selections.size(); i++) {
1068 currentSelection = selections.get(i);
1069 selectedNotebookGUIDs.add(currentSelection.text(2));
1073 // There is the potential for no notebooks to be selected if this
1074 // happens then we make it look like all notebooks were selecetd.
1075 // If that happens, just select the "all notebooks"
1076 selections = notebookTree.selectedItems();
1077 if (selections.size()==0) {
1078 selectedNotebookGUIDs.clear();
1079 menuBar.notebookEditAction.setEnabled(false);
1080 menuBar.notebookDeleteAction.setEnabled(false);
1084 if (selections.size() > 0)
1085 guid = (selections.get(0).text(2));
1086 if (!guid.equals(""))
1087 selectedNotebookGUIDs.add(guid);
1089 listManager.setSelectedNotebooks(selectedNotebookGUIDs);
1090 listManager.loadNotesIndex();
1091 noteIndexUpdated(false);
1092 logger.log(logger.HIGH, "Leaving NeverNote.notebookTreeSelection");
1095 private void clearNotebookFilter() {
1096 notebookTree.blockSignals(true);
1097 notebookTree.clearSelection();
1098 menuBar.noteRestoreAction.setVisible(false);
1099 menuBar.notebookEditAction.setEnabled(false);
1100 menuBar.notebookDeleteAction.setEnabled(false);
1101 selectedNotebookGUIDs.clear();
1102 listManager.setSelectedNotebooks(selectedNotebookGUIDs);
1103 notebookTree.blockSignals(false);
1105 // Triggered when the notebook DB has been updated
1106 private void notebookIndexUpdated() {
1107 logger.log(logger.HIGH, "Entering NeverNote.notebookIndexUpdated");
1108 if (selectedNotebookGUIDs == null)
1109 selectedNotebookGUIDs = new ArrayList<String>();
1110 List<Notebook> books = conn.getNotebookTable().getAll();
1111 for (int i=books.size()-1; i>=0; i--) {
1112 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
1113 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(books.get(i).getGuid())) {
1115 j=listManager.getArchiveNotebookIndex().size();
1121 listManager.countNotebookResults(listManager.getNoteIndex());
1122 notebookTree.blockSignals(true);
1123 notebookTree.load(books, listManager.getLocalNotebooks());
1124 for (int i=selectedNotebookGUIDs.size()-1; i>=0; i--) {
1125 boolean found = notebookTree.selectGuid(selectedNotebookGUIDs.get(i));
1127 selectedNotebookGUIDs.remove(i);
1129 notebookTree.blockSignals(false);
1131 logger.log(logger.HIGH, "Leaving NeverNote.notebookIndexUpdated");
1133 // Show/Hide note information
1134 private void toggleNotebookWindow() {
1135 logger.log(logger.HIGH, "Entering NeverNote.toggleNotebookWindow");
1136 if (notebookTree.isVisible())
1137 notebookTree.hide();
1139 notebookTree.show();
1140 menuBar.hideNotebooks.setChecked(notebookTree.isVisible());
1141 Global.saveWindowVisible("notebookTree", notebookTree.isVisible());
1142 logger.log(logger.HIGH, "Leaving NeverNote.toggleNotebookWindow");
1144 // Add a new notebook
1145 @SuppressWarnings("unused")
1146 private void addNotebook() {
1147 logger.log(logger.HIGH, "Inside NeverNote.addNotebook");
1148 NotebookEdit edit = new NotebookEdit();
1149 edit.setNotebooks(listManager.getNotebookIndex());
1152 if (!edit.okPressed())
1155 Calendar currentTime = new GregorianCalendar();
1156 Long l = new Long(currentTime.getTimeInMillis());
1157 String randint = new String(Long.toString(l));
1159 Notebook newBook = new Notebook();
1160 newBook.setUpdateSequenceNum(0);
1161 newBook.setGuid(randint);
1162 newBook.setName(edit.getNotebook());
1163 newBook.setServiceCreated(new Date().getTime());
1164 newBook.setServiceUpdated(new Date().getTime());
1165 newBook.setDefaultNotebook(false);
1166 newBook.setPublished(false);
1168 listManager.getNotebookIndex().add(newBook);
1170 listManager.getLocalNotebooks().add(newBook.getGuid());
1171 conn.getNotebookTable().addNotebook(newBook, true, edit.isLocal());
1172 notebookIndexUpdated();
1173 listManager.countNotebookResults(listManager.getNoteIndex());
1174 // notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
1175 logger.log(logger.HIGH, "Leaving NeverNote.addNotebook");
1177 // Edit an existing notebook
1178 @SuppressWarnings("unused")
1179 private void editNotebook() {
1180 logger.log(logger.HIGH, "Entering NeverNote.editNotebook");
1181 NotebookEdit edit = new NotebookEdit();
1182 edit.setTitle(tr("Edit Notebook"));
1183 edit.setLocalCheckboxEnabled(false);
1184 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1185 QTreeWidgetItem currentSelection;
1186 currentSelection = selections.get(0);
1187 edit.setNotebook(currentSelection.text(0));
1188 edit.setNotebooks(listManager.getNotebookIndex());
1191 if (!edit.okPressed())
1194 String guid = currentSelection.text(2);
1195 updateListNotebookName(currentSelection.text(0), edit.getNotebook());
1196 currentSelection.setText(0, edit.getNotebook());
1198 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1199 if (listManager.getNotebookIndex().get(i).getGuid().equals(guid)) {
1200 listManager.getNotebookIndex().get(i).setName(edit.getNotebook());
1201 conn.getNotebookTable().updateNotebook(listManager.getNotebookIndex().get(i), true);
1202 i=listManager.getNotebookIndex().size();
1206 // Build a list of non-closed notebooks
1207 List<Notebook> nbooks = new ArrayList<Notebook>();
1208 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1209 boolean found=false;
1210 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
1211 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid()))
1215 nbooks.add(listManager.getNotebookIndex().get(i));
1218 browserWindow.setNotebookList(nbooks);
1219 logger.log(logger.HIGH, "Leaving NeverNote.editNotebook");
1221 // Delete an existing notebook
1222 @SuppressWarnings("unused")
1223 private void deleteNotebook() {
1224 logger.log(logger.HIGH, "Entering NeverNote.deleteNotebook");
1225 boolean assigned = false;
1226 // Check if any notes have this notebook
1227 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1228 for (int i=0; i<selections.size(); i++) {
1229 QTreeWidgetItem currentSelection;
1230 currentSelection = selections.get(i);
1231 String guid = currentSelection.text(2);
1232 for (int j=0; j<listManager.getNoteIndex().size(); j++) {
1233 String noteGuid = listManager.getNoteIndex().get(j).getNotebookGuid();
1234 if (noteGuid.equals(guid)) {
1236 j=listManager.getNoteIndex().size();
1237 i=selections.size();
1242 QMessageBox.information(this, tr("Unable to Delete"), tr("Some of the selected notebook(s) contain notes.\n"+
1243 "Please delete the notes or move them to another notebook before deleting any notebooks."));
1247 if (conn.getNotebookTable().getAll().size() == 1) {
1248 QMessageBox.information(this, tr("Unable to Delete"), tr("You must have at least one notebook."));
1252 // If all notebooks are clear, verify the delete
1253 if (QMessageBox.question(this, tr("Confirmation"), tr("Delete the selected notebooks?"),
1254 QMessageBox.StandardButton.Yes,
1255 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
1259 // If confirmed, delete the notebook
1260 for (int i=selections.size()-1; i>=0; i--) {
1261 QTreeWidgetItem currentSelection;
1262 currentSelection = selections.get(i);
1263 String guid = currentSelection.text(2);
1264 conn.getNotebookTable().expungeNotebook(guid, true);
1265 listManager.deleteNotebook(guid);
1267 // for (int i=<dbRunner.getLocalNotebooks().size()-1; i>=0; i--) {
1268 // if (dbRunner.getLocalNotebooks().get(i).equals(arg0))
1270 notebookTreeSelection();
1271 notebookTree.load(listManager.getNotebookIndex(), listManager.getLocalNotebooks());
1272 listManager.countNotebookResults(listManager.getNoteIndex());
1273 // notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
1274 logger.log(logger.HIGH, "Entering NeverNote.deleteNotebook");
1276 // A note's notebook has been updated
1277 @SuppressWarnings("unused")
1278 private void updateNoteNotebook(String guid, String notebookGuid) {
1280 // Update the list manager
1281 listManager.updateNoteNotebook(guid, notebookGuid);
1282 listManager.countNotebookResults(listManager.getNoteIndex());
1283 // notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
1285 // Find the name of the notebook
1286 String notebookName = null;
1287 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1288 if (listManager.getNotebookIndex().get(i).getGuid().equals(notebookGuid)) {
1289 notebookName = listManager.getNotebookIndex().get(i).getName();
1294 // If we found the name, update the browser window
1295 if (notebookName != null) {
1296 updateListNoteNotebook(guid, notebookName);
1297 if (guid.equals(currentNoteGuid)) {
1298 int pos = browserWindow.notebookBox.findText(notebookName);
1300 browserWindow.notebookBox.setCurrentIndex(pos);
1304 // If we're dealing with the current note, then we need to be sure and update the notebook there
1305 if (guid.equals(currentNoteGuid)) {
1306 if (currentNote != null) {
1307 currentNote.setNotebookGuid(notebookGuid);
1311 // Open/close notebooks
1312 @SuppressWarnings("unused")
1313 private void closeNotebooks() {
1314 NotebookArchive na = new NotebookArchive(listManager.getNotebookIndex(), listManager.getArchiveNotebookIndex());
1316 if (!na.okClicked())
1320 listManager.getArchiveNotebookIndex().clear();
1322 for (int i=na.getClosedBookList().count()-1; i>=0; i--) {
1323 String text = na.getClosedBookList().takeItem(i).text();
1324 for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1325 if (listManager.getNotebookIndex().get(j).getName().equalsIgnoreCase(text)) {
1326 Notebook n = listManager.getNotebookIndex().get(j);
1327 conn.getNotebookTable().setArchived(n.getGuid(),true);
1328 listManager.getArchiveNotebookIndex().add(n);
1329 j=listManager.getNotebookIndex().size();
1334 for (int i=na.getOpenBookList().count()-1; i>=0; i--) {
1335 String text = na.getOpenBookList().takeItem(i).text();
1336 for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1337 if (listManager.getNotebookIndex().get(j).getName().equalsIgnoreCase(text)) {
1338 Notebook n = listManager.getNotebookIndex().get(j);
1339 conn.getNotebookTable().setArchived(n.getGuid(),false);
1340 j=listManager.getNotebookIndex().size();
1344 notebookTreeSelection();
1345 listManager.loadNotesIndex();
1346 notebookIndexUpdated();
1347 noteIndexUpdated(false);
1348 // noteIndexUpdated(false);
1350 // Build a list of non-closed notebooks
1351 List<Notebook> nbooks = new ArrayList<Notebook>();
1352 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1353 boolean found=false;
1354 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
1355 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid()))
1359 nbooks.add(listManager.getNotebookIndex().get(i));
1362 browserWindow.setNotebookList(nbooks);
1369 //***************************************************************
1370 //***************************************************************
1371 //** These functions deal with Tag menu items
1372 //***************************************************************
1373 //***************************************************************
1374 // Add a new notebook
1375 @SuppressWarnings("unused")
1376 private void addTag() {
1377 logger.log(logger.HIGH, "Inside NeverNote.addTag");
1378 TagEdit edit = new TagEdit();
1379 edit.setTagList(listManager.getTagIndex());
1382 if (!edit.okPressed())
1385 Calendar currentTime = new GregorianCalendar();
1386 Long l = new Long(currentTime.getTimeInMillis());
1387 String randint = new String(Long.toString(l));
1389 Tag newTag = new Tag();
1390 newTag.setUpdateSequenceNum(0);
1391 newTag.setGuid(randint);
1392 newTag.setName(edit.getTag());
1393 conn.getTagTable().addTag(newTag, true);
1394 listManager.getTagIndex().add(newTag);
1397 logger.log(logger.HIGH, "Leaving NeverNote.addTag");
1399 private void reloadTagTree() {
1400 logger.log(logger.HIGH, "Entering NeverNote.reloadTagTree");
1401 tagIndexUpdated(false);
1402 boolean filter = false;
1403 listManager.countTagResults(listManager.getNoteIndex());
1404 if (notebookTree.selectedItems().size() > 0
1405 && !notebookTree.selectedItems().get(0).text(0).equalsIgnoreCase("All Notebooks"))
1407 if (tagTree.selectedItems().size() > 0)
1409 tagTree.showAllTags(!filter);
1410 logger.log(logger.HIGH, "Leaving NeverNote.reloadTagTree");
1412 // Edit an existing tag
1413 @SuppressWarnings("unused")
1414 private void editTag() {
1415 logger.log(logger.HIGH, "Entering NeverNote.editTag");
1416 TagEdit edit = new TagEdit();
1417 edit.setTitle("Edit Tag");
1418 List<QTreeWidgetItem> selections = tagTree.selectedItems();
1419 QTreeWidgetItem currentSelection;
1420 currentSelection = selections.get(0);
1421 edit.setTag(currentSelection.text(0));
1422 edit.setTagList(listManager.getTagIndex());
1425 if (!edit.okPressed())
1428 String guid = currentSelection.text(2);
1429 currentSelection.setText(0,edit.getTag());
1431 for (int i=0; i<listManager.getTagIndex().size(); i++) {
1432 if (listManager.getTagIndex().get(i).getGuid().equals(guid)) {
1433 listManager.getTagIndex().get(i).setName(edit.getTag());
1434 conn.getTagTable().updateTag(listManager.getTagIndex().get(i), true);
1435 updateListTagName(guid);
1436 if (currentNote != null && currentNote.getTagGuids().contains(guid))
1437 browserWindow.setTag(getTagNamesForNote(currentNote));
1438 logger.log(logger.HIGH, "Leaving NeverNote.editTag");
1442 browserWindow.setTag(getTagNamesForNote(currentNote));
1443 logger.log(logger.HIGH, "Leaving NeverNote.editTag...");
1445 // Delete an existing tag
1446 @SuppressWarnings("unused")
1447 private void deleteTag() {
1448 logger.log(logger.HIGH, "Entering NeverNote.deleteTag");
1450 if (QMessageBox.question(this, tr("Confirmation"), tr("Delete the selected tags?"),
1451 QMessageBox.StandardButton.Yes,
1452 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
1456 List<QTreeWidgetItem> selections = tagTree.selectedItems();
1457 for (int i=selections.size()-1; i>=0; i--) {
1458 QTreeWidgetItem currentSelection;
1459 currentSelection = selections.get(i);
1460 removeTagItem(currentSelection.text(2));
1462 tagIndexUpdated(true);
1464 listManager.countTagResults(listManager.getNoteIndex());
1465 // tagTree.updateCounts(listManager.getTagCounter());
1466 logger.log(logger.HIGH, "Leaving NeverNote.deleteTag");
1468 // Remove a tag tree item. Go recursively down & remove the children too
1469 private void removeTagItem(String guid) {
1470 for (int j=listManager.getTagIndex().size()-1; j>=0; j--) {
1471 String parent = listManager.getTagIndex().get(j).getParentGuid();
1472 if (parent != null && parent.equals(guid)) {
1473 //Remove this tag's children
1474 removeTagItem(listManager.getTagIndex().get(j).getGuid());
1477 //Now, remove this tag
1478 removeListTagName(guid);
1479 conn.getTagTable().expungeTag(guid, true);
1480 for (int a=0; a<listManager.getTagIndex().size(); a++) {
1481 if (listManager.getTagIndex().get(a).getGuid().equals(guid)) {
1482 listManager.getTagIndex().remove(a);
1487 // Setup the tree containing the user's tags
1488 private void initializeTagTree() {
1489 logger.log(logger.HIGH, "Entering NeverNote.initializeTagTree");
1490 tagTree.itemSelectionChanged.connect(this, "tagTreeSelection()");
1491 listManager.tagSignal.refreshTagTreeCounts.connect(tagTree, "updateCounts(List)");
1492 logger.log(logger.HIGH, "Leaving NeverNote.initializeTagTree");
1494 // Listener when a tag is selected
1495 private void tagTreeSelection() {
1496 logger.log(logger.HIGH, "Entering NeverNote.tagTreeSelection");
1499 clearAttributeFilter();
1500 clearSavedSearchFilter();
1502 menuBar.noteRestoreAction.setVisible(false);
1504 List<QTreeWidgetItem> selections = tagTree.selectedItems();
1505 QTreeWidgetItem currentSelection;
1506 selectedTagGUIDs.clear();
1507 for (int i=0; i<selections.size(); i++) {
1508 currentSelection = selections.get(i);
1509 selectedTagGUIDs.add(currentSelection.text(2));
1511 if (selections.size() > 0) {
1512 menuBar.tagEditAction.setEnabled(true);
1513 menuBar.tagDeleteAction.setEnabled(true);
1516 menuBar.tagEditAction.setEnabled(false);
1517 menuBar.tagDeleteAction.setEnabled(false);
1519 listManager.setSelectedTags(selectedTagGUIDs);
1520 listManager.loadNotesIndex();
1521 noteIndexUpdated(false);
1522 logger.log(logger.HIGH, "Leaving NeverNote.tagTreeSelection");
1524 // trigger the tag index to be refreshed
1525 @SuppressWarnings("unused")
1526 private void tagIndexUpdated() {
1527 tagIndexUpdated(true);
1529 private void tagIndexUpdated(boolean reload) {
1530 logger.log(logger.HIGH, "Entering NeverNote.tagIndexUpdated");
1531 if (selectedTagGUIDs == null)
1532 selectedTagGUIDs = new ArrayList<String>();
1533 // selectedTagGUIDs.clear(); // clear out old entries
1535 tagTree.blockSignals(true);
1537 tagTree.load(listManager.getTagIndex());
1538 for (int i=selectedTagGUIDs.size()-1; i>=0; i--) {
1539 boolean found = tagTree.selectGuid(selectedTagGUIDs.get(i));
1541 selectedTagGUIDs.remove(i);
1543 tagTree.blockSignals(false);
1545 browserWindow.setTag(getTagNamesForNote(currentNote));
1546 logger.log(logger.HIGH, "Leaving NeverNote.tagIndexUpdated");
1548 // Show/Hide note information
1549 private void toggleTagWindow() {
1550 logger.log(logger.HIGH, "Entering NeverNote.toggleTagWindow");
1551 if (tagTree.isVisible())
1555 menuBar.hideTags.setChecked(tagTree.isVisible());
1556 Global.saveWindowVisible("tagTree", tagTree.isVisible());
1557 logger.log(logger.HIGH, "Leaving NeverNote.toggleTagWindow");
1559 // A note's tags have been updated
1560 @SuppressWarnings("unused")
1561 private void updateNoteTags(String guid, List<String> tags) {
1562 // Save any new tags. We'll need them later.
1563 List<String> newTags = new ArrayList<String>();
1564 for (int i=0; i<tags.size(); i++) {
1565 if (conn.getTagTable().findTagByName(tags.get(i))==null)
1566 newTags.add(tags.get(i));
1569 listManager.saveNoteTags(guid, tags);
1570 listManager.countTagResults(listManager.getNoteIndex());
1571 StringBuffer names = new StringBuffer("");
1572 for (int i=0; i<tags.size(); i++) {
1573 names = names.append(tags.get(i));
1574 if (i<tags.size()-1) {
1575 names.append(Global.tagDelimeter + " ");
1578 browserWindow.setTag(names.toString());
1581 // Now, we need to add any new tags to the tag tree
1582 for (int i=0; i<newTags.size(); i++)
1583 tagTree.insertTag(newTags.get(i), conn.getTagTable().findTagByName(newTags.get(i)));
1585 // Get a string containing all tag names for a note
1586 private String getTagNamesForNote(Note n) {
1587 logger.log(logger.HIGH, "Entering NeverNote.getTagNamesForNote");
1588 if (n==null || n.getGuid() == null || n.getGuid().equals(""))
1590 StringBuffer buffer = new StringBuffer(100);
1591 Vector<String> v = new Vector<String>();
1592 List<String> guids = n.getTagGuids();
1597 for (int i=0; i<guids.size(); i++) {
1598 v.add(listManager.getTagNameByGuid(guids.get(i)));
1600 Comparator<String> comparator = Collections.reverseOrder();
1601 Collections.sort(v,comparator);
1602 Collections.reverse(v);
1604 for (int i = 0; i<v.size(); i++) {
1606 buffer.append(", ");
1607 buffer.append(v.get(i));
1610 logger.log(logger.HIGH, "Leaving NeverNote.getTagNamesForNote");
1611 return buffer.toString();
1613 // Tags were added via dropping notes from the note list
1614 @SuppressWarnings("unused")
1615 private void tagsAdded(String noteGuid, String tagGuid) {
1616 String tagName = null;
1617 for (int i=0; i<listManager.getTagIndex().size(); i++) {
1618 if (listManager.getTagIndex().get(i).getGuid().equals(tagGuid)) {
1619 tagName = listManager.getTagIndex().get(i).getName();
1620 i=listManager.getTagIndex().size();
1623 if (tagName == null)
1626 for (int i=0; i<listManager.getMasterNoteIndex().size(); i++) {
1627 if (listManager.getMasterNoteIndex().get(i).getGuid().equals(noteGuid)) {
1628 List<String> tagNames = new ArrayList<String>();
1629 tagNames.add(new String(tagName));
1630 Note n = listManager.getMasterNoteIndex().get(i);
1631 for (int j=0; j<n.getTagNames().size(); j++) {
1632 tagNames.add(new String(n.getTagNames().get(j)));
1634 listManager.getNoteTableModel().updateNoteTags(noteGuid, n.getTagGuids(), tagNames);
1635 if (n.getGuid().equals(currentNoteGuid)) {
1636 Collections.sort(tagNames);
1637 String display = "";
1638 for (int j=0; j<tagNames.size(); j++) {
1639 display = display+tagNames.get(j);
1640 if (j+2<tagNames.size())
1641 display = display+Global.tagDelimeter+" ";
1643 browserWindow.setTag(display);
1645 i=listManager.getMasterNoteIndex().size();
1650 listManager.getNoteTableModel().updateNoteSyncStatus(noteGuid, false);
1652 private void clearTagFilter() {
1653 tagTree.blockSignals(true);
1654 tagTree.clearSelection();
1655 menuBar.noteRestoreAction.setVisible(false);
1656 menuBar.tagEditAction.setEnabled(false);
1657 menuBar.tagDeleteAction.setEnabled(false);
1658 selectedTagGUIDs.clear();
1659 listManager.setSelectedTags(selectedTagGUIDs);
1660 tagTree.blockSignals(false);
1664 //***************************************************************
1665 //***************************************************************
1666 //** These functions deal with Saved Search menu items
1667 //***************************************************************
1668 //***************************************************************
1669 // Add a new notebook
1670 @SuppressWarnings("unused")
1671 private void addSavedSearch() {
1672 logger.log(logger.HIGH, "Inside NeverNote.addSavedSearch");
1673 SavedSearchEdit edit = new SavedSearchEdit();
1674 edit.setSearchList(listManager.getSavedSearchIndex());
1677 if (!edit.okPressed())
1680 Calendar currentTime = new GregorianCalendar();
1681 Long l = new Long(currentTime.getTimeInMillis());
1682 String randint = new String(Long.toString(l));
1684 SavedSearch search = new SavedSearch();
1685 search.setUpdateSequenceNum(0);
1686 search.setGuid(randint);
1687 search.setName(edit.getName());
1688 search.setQuery(edit.getQuery());
1689 search.setFormat(QueryFormat.USER);
1690 listManager.getSavedSearchIndex().add(search);
1691 conn.getSavedSearchTable().addSavedSearch(search, true);
1692 savedSearchIndexUpdated();
1693 logger.log(logger.HIGH, "Leaving NeverNote.addSavedSearch");
1695 // Edit an existing tag
1696 @SuppressWarnings("unused")
1697 private void editSavedSearch() {
1698 logger.log(logger.HIGH, "Entering NeverNote.editSavedSearch");
1699 SavedSearchEdit edit = new SavedSearchEdit();
1700 edit.setTitle(tr("Edit Search"));
1701 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
1702 QTreeWidgetItem currentSelection;
1703 currentSelection = selections.get(0);
1704 String guid = currentSelection.text(1);
1705 SavedSearch s = conn.getSavedSearchTable().getSavedSearch(guid);
1706 edit.setName(currentSelection.text(0));
1707 edit.setQuery(s.getQuery());
1708 edit.setSearchList(listManager.getSavedSearchIndex());
1711 if (!edit.okPressed())
1714 List<SavedSearch> list = listManager.getSavedSearchIndex();
1715 SavedSearch search = null;
1716 boolean found = false;
1717 for (int i=0; i<list.size(); i++) {
1718 search = list.get(i);
1719 if (search.getGuid().equals(guid)) {
1726 search.setName(edit.getName());
1727 search.setQuery(edit.getQuery());
1728 conn.getSavedSearchTable().updateSavedSearch(search, true);
1729 savedSearchIndexUpdated();
1730 logger.log(logger.HIGH, "Leaving NeverNote.editSavedSearch");
1732 // Delete an existing tag
1733 @SuppressWarnings("unused")
1734 private void deleteSavedSearch() {
1735 logger.log(logger.HIGH, "Entering NeverNote.deleteSavedSearch");
1737 if (QMessageBox.question(this, "Confirmation", "Delete the selected search?",
1738 QMessageBox.StandardButton.Yes,
1739 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
1743 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
1744 for (int i=selections.size()-1; i>=0; i--) {
1745 QTreeWidgetItem currentSelection;
1746 currentSelection = selections.get(i);
1747 for (int j=0; j<listManager.getSavedSearchIndex().size(); j++) {
1748 if (listManager.getSavedSearchIndex().get(j).getGuid().equals(currentSelection.text(1))) {
1749 conn.getSavedSearchTable().expungeSavedSearch(listManager.getSavedSearchIndex().get(j).getGuid(), true);
1750 listManager.getSavedSearchIndex().remove(j);
1751 j=listManager.getSavedSearchIndex().size()+1;
1754 selections.remove(i);
1756 savedSearchIndexUpdated();
1757 logger.log(logger.HIGH, "Leaving NeverNote.deleteSavedSearch");
1759 // Setup the tree containing the user's tags
1760 private void initializeSavedSearchTree() {
1761 logger.log(logger.HIGH, "Entering NeverNote.initializeSavedSearchTree");
1762 savedSearchTree.itemSelectionChanged.connect(this, "savedSearchTreeSelection()");
1763 logger.log(logger.HIGH, "Leaving NeverNote.initializeSavedSearchTree");
1765 // Listener when a tag is selected
1766 @SuppressWarnings("unused")
1767 private void savedSearchTreeSelection() {
1768 logger.log(logger.HIGH, "Entering NeverNote.savedSearchTreeSelection");
1770 clearNotebookFilter();
1773 clearAttributeFilter();
1775 String currentGuid = selectedSavedSearchGUID;
1776 menuBar.savedSearchEditAction.setEnabled(true);
1777 menuBar.savedSearchDeleteAction.setEnabled(true);
1778 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
1779 QTreeWidgetItem currentSelection;
1780 selectedSavedSearchGUID = "";
1781 for (int i=0; i<selections.size(); i++) {
1782 currentSelection = selections.get(i);
1783 if (currentSelection.text(1).equals(currentGuid)) {
1784 currentSelection.setSelected(false);
1786 selectedSavedSearchGUID = currentSelection.text(1);
1788 // i = selections.size() +1;
1791 // There is the potential for no notebooks to be selected if this
1792 // happens then we make it look like all notebooks were selecetd.
1793 // If that happens, just select the "all notebooks"
1794 if (selections.size()==0) {
1795 clearSavedSearchFilter();
1797 listManager.setSelectedSavedSearch(selectedSavedSearchGUID);
1799 logger.log(logger.HIGH, "Leaving NeverNote.savedSearchTreeSelection");
1801 private void clearSavedSearchFilter() {
1802 menuBar.savedSearchEditAction.setEnabled(false);
1803 menuBar.savedSearchDeleteAction.setEnabled(false);
1804 savedSearchTree.blockSignals(true);
1805 savedSearchTree.clearSelection();
1806 savedSearchTree.blockSignals(false);
1807 selectedSavedSearchGUID = "";
1808 searchField.setEditText("");
1809 searchPerformed = false;
1810 listManager.setSelectedSavedSearch(selectedSavedSearchGUID);
1812 // trigger the tag index to be refreshed
1813 private void savedSearchIndexUpdated() {
1814 if (selectedSavedSearchGUID == null)
1815 selectedSavedSearchGUID = new String();
1816 savedSearchTree.blockSignals(true);
1817 savedSearchTree.load(listManager.getSavedSearchIndex());
1818 savedSearchTree.selectGuid(selectedSavedSearchGUID);
1819 savedSearchTree.blockSignals(false);
1821 // trigger when the saved search selection changes
1822 @SuppressWarnings("unused")
1823 private void updateSavedSearchSelection() {
1824 logger.log(logger.HIGH, "Entering NeverNote.updateSavedSearchSelection()");
1826 menuBar.savedSearchEditAction.setEnabled(true);
1827 menuBar.savedSearchDeleteAction.setEnabled(true);
1828 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
1830 if (selections.size() > 0) {
1831 menuBar.savedSearchEditAction.setEnabled(true);
1832 menuBar.savedSearchDeleteAction.setEnabled(true);
1833 selectedSavedSearchGUID = selections.get(0).text(1);
1834 SavedSearch s = conn.getSavedSearchTable().getSavedSearch(selectedSavedSearchGUID);
1835 searchField.setEditText(s.getQuery());
1837 menuBar.savedSearchEditAction.setEnabled(false);
1838 menuBar.savedSearchDeleteAction.setEnabled(false);
1839 selectedSavedSearchGUID = "";
1840 searchField.setEditText("");
1842 searchFieldChanged();
1844 logger.log(logger.HIGH, "Leaving NeverNote.updateSavedSearchSelection()");
1848 // Show/Hide note information
1849 private void toggleSavedSearchWindow() {
1850 logger.log(logger.HIGH, "Entering NeverNote.toggleSavedSearchWindow");
1851 if (savedSearchTree.isVisible())
1852 savedSearchTree.hide();
1854 savedSearchTree.show();
1855 menuBar.hideSavedSearches.setChecked(savedSearchTree.isVisible());
1857 Global.saveWindowVisible("savedSearchTree", savedSearchTree.isVisible());
1858 logger.log(logger.HIGH, "Leaving NeverNote.toggleSavedSearchWindow");
1864 //***************************************************************
1865 //***************************************************************
1866 //** These functions deal with Help menu & tool menu items
1867 //***************************************************************
1868 //***************************************************************
1869 // Show database status
1870 @SuppressWarnings("unused")
1871 private void databaseStatus() {
1873 int dirty = conn.getNoteTable().getDirtyCount();
1874 int unindexed = conn.getNoteTable().getUnindexedCount();
1875 DatabaseStatus status = new DatabaseStatus();
1876 status.setUnsynchronized(dirty);
1877 status.setUnindexed(unindexed);
1878 status.setNoteCount(conn.getNoteTable().getNoteCount());
1879 status.setNotebookCount(listManager.getNotebookIndex().size());
1880 status.setSavedSearchCount(listManager.getSavedSearchIndex().size());
1881 status.setTagCount(listManager.getTagIndex().size());
1882 status.setResourceCount(conn.getNoteTable().noteResourceTable.getResourceCount());
1883 status.setWordCount(conn.getWordsTable().getWordCount());
1887 // Compact the database
1888 @SuppressWarnings("unused")
1889 private void compactDatabase() {
1890 logger.log(logger.HIGH, "Entering NeverNote.compactDatabase");
1891 if (QMessageBox.question(this, tr("Confirmation"), tr("This will free unused space in the database, "+
1892 "but please be aware that depending upon the size of your database this can be time consuming " +
1893 "and NeverNote will be unresponsive until it is complete. Do you wish to continue?"),
1894 QMessageBox.StandardButton.Yes,
1895 QMessageBox.StandardButton.No)==StandardButton.No.value() && Global.verifyDelete() == true) {
1898 setMessage("Compacting database.");
1900 listManager.compactDatabase();
1902 setMessage("Database compact is complete.");
1903 logger.log(logger.HIGH, "Leaving NeverNote.compactDatabase");
1905 @SuppressWarnings("unused")
1906 private void accountInformation() {
1907 logger.log(logger.HIGH, "Entering NeverNote.accountInformation");
1908 AccountDialog dialog = new AccountDialog();
1910 logger.log(logger.HIGH, "Leaving NeverNote.accountInformation");
1912 @SuppressWarnings("unused")
1913 private void releaseNotes() {
1914 logger.log(logger.HIGH, "Entering NeverNote.releaseNotes");
1915 QDialog dialog = new QDialog(this);
1916 QHBoxLayout layout = new QHBoxLayout();
1917 QTextEdit textBox = new QTextEdit();
1918 layout.addWidget(textBox);
1919 textBox.setReadOnly(true);
1920 QFile file = new QFile(Global.getFileManager().getHomeDirPath("release.txt"));
1921 if (!file.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly,
1922 QIODevice.OpenModeFlag.Text)))
1924 textBox.setText(file.readAll().toString());
1926 dialog.setWindowTitle(tr("Release Notes"));
1927 dialog.setLayout(layout);
1929 logger.log(logger.HIGH, "Leaving NeverNote.releaseNotes");
1931 // Called when user picks Log from the help menu
1932 @SuppressWarnings("unused")
1933 private void logger() {
1934 logger.log(logger.HIGH, "Entering NeverNote.logger");
1935 QDialog dialog = new QDialog(this);
1936 QHBoxLayout layout = new QHBoxLayout();
1937 QListWidget textBox = new QListWidget();
1938 layout.addWidget(textBox);
1939 textBox.addItems(emitLog);
1941 dialog.setLayout(layout);
1942 dialog.setWindowTitle(tr("Mesasge Log"));
1944 logger.log(logger.HIGH, "Leaving NeverNote.logger");
1946 // Menu option "help/about" was selected
1947 @SuppressWarnings("unused")
1948 private void about() {
1949 logger.log(logger.HIGH, "Entering NeverNote.about");
1950 QMessageBox.about(this,
1951 tr("About NeverNote"),
1952 tr("<h4><center><b>NeverNote</b></center></h4><hr><center>Version ")
1954 +tr("<hr></center>Evernote"
1955 +"An Open Source Evernote Client.<br><br>"
1956 +"Licensed under GPL v2. <br><hr><br>"
1957 +"Evernote is copyright 2001-2010 by Evernote Corporation<br>"
1958 +"Jambi and QT are the licensed trademark of Nokia Corporation<br>"
1959 +"PDFRenderer is licened under the LGPL<br>"
1960 +"JTidy is copyrighted under the World Wide Web Consortium<br>"
1961 +"Apache Common Utilities licensed under the Apache License Version 2.0<br>"
1962 +"Jazzy is licened under the LGPL<br>"
1963 +"Java is a registered trademark of Oracle Corporation.<br><hr>"));
1964 logger.log(logger.HIGH, "Leaving NeverNote.about");
1966 // Hide the entire left hand side
1967 @SuppressWarnings("unused")
1968 private void toggleLeftSide() {
1971 hidden = !menuBar.hideLeftSide.isChecked();
1972 menuBar.hideLeftSide.setChecked(!hidden);
1974 if (notebookTree.isVisible() != hidden)
1975 toggleNotebookWindow();
1976 if (savedSearchTree.isVisible() != hidden)
1977 toggleSavedSearchWindow();
1978 if (tagTree.isVisible() != hidden)
1980 if (attributeTree.isVisible() != hidden)
1981 toggleAttributesWindow();
1982 if (trashTree.isVisible() != hidden)
1983 toggleTrashWindow();
1985 Global.saveWindowVisible("leftPanel", hidden);
1990 //***************************************************************
1991 //***************************************************************
1992 //** These functions deal with the Toolbar
1993 //***************************************************************
1994 //***************************************************************
1995 // Text in the search bar has been cleared
1996 private void searchFieldCleared() {
1997 searchField.setEditText("");
1998 saveNoteIndexWidth();
2000 // text in the search bar changed. We only use this to tell if it was cleared,
2001 // otherwise we trigger off searchFieldChanged.
2002 @SuppressWarnings("unused")
2003 private void searchFieldTextChanged(String text) {
2004 if (text.trim().equals("")) {
2005 searchFieldCleared();
2006 if (searchPerformed) {
2008 listManager.setEnSearch("");
2009 ///// listManager.clearNoteIndexSearch();
2010 //noteIndexUpdated(true);
2011 listManager.loadNotesIndex();
2012 refreshEvernoteNote(true);
2013 noteIndexUpdated(false);
2015 searchPerformed = false;
2018 // Text in the toolbar has changed
2019 private void searchFieldChanged() {
2020 logger.log(logger.HIGH, "Entering NeverNote.searchFieldChanged");
2022 saveNoteIndexWidth();
2023 String text = searchField.currentText();
2024 listManager.setEnSearch(text.trim());
2025 listManager.loadNotesIndex();
2026 //--->>> noteIndexUpdated(true);
2027 noteIndexUpdated(false);
2028 refreshEvernoteNote(true);
2029 searchPerformed = true;
2030 logger.log(logger.HIGH, "Leaving NeverNote.searchFieldChanged");
2033 // Build the window tool bar
2034 private void setupToolBar() {
2035 logger.log(logger.HIGH, "Entering NeverNote.setupToolBar");
2036 toolBar = addToolBar(tr("Tool Bar"));
2037 menuBar.setupToolBarVisible();
2038 if (!Global.isWindowVisible("toolBar"))
2039 toolBar.setVisible(false);
2041 toolBar.setVisible(true);
2043 prevButton = toolBar.addAction("Previous");
2044 QIcon prevIcon = new QIcon(iconPath+"back.png");
2045 prevButton.setIcon(prevIcon);
2046 prevButton.triggered.connect(this, "previousViewedAction()");
2048 nextButton = toolBar.addAction("Next");
2049 QIcon nextIcon = new QIcon(iconPath+"forward.png");
2050 nextButton.setIcon(nextIcon);
2051 nextButton.triggered.connect(this, "nextViewedAction()");
2053 upButton = toolBar.addAction("Up");
2054 QIcon upIcon = new QIcon(iconPath+"up.png");
2055 upButton.setIcon(upIcon);
2056 upButton.triggered.connect(this, "upAction()");
2058 downButton = toolBar.addAction("Down");
2059 QIcon downIcon = new QIcon(iconPath+"down.png");
2060 downButton.setIcon(downIcon);
2061 downButton.triggered.connect(this, "downAction()");
2063 synchronizeButton = toolBar.addAction("Synchronize");
2064 synchronizeAnimation = new ArrayList<QIcon>();
2065 synchronizeAnimation.add(new QIcon(iconPath+"synchronize-0.png"));
2066 synchronizeAnimation.add(new QIcon(iconPath+"synchronize-1.png"));
2067 synchronizeAnimation.add(new QIcon(iconPath+"synchronize-2.png"));
2068 synchronizeAnimation.add(new QIcon(iconPath+"synchronize-3.png"));
2069 synchronizeButton.setIcon(synchronizeAnimation.get(0));
2070 synchronizeFrame = 0;
2071 synchronizeButton.triggered.connect(this, "evernoteSync()");
2073 printButton = toolBar.addAction("Print");
2074 QIcon printIcon = new QIcon(iconPath+"print.png");
2075 printButton.setIcon(printIcon);
2076 printButton.triggered.connect(this, "printNote()");
2078 tagButton = toolBar.addAction("Tag");
2079 QIcon tagIcon = new QIcon(iconPath+"tag.png");
2080 tagButton.setIcon(tagIcon);
2081 tagButton.triggered.connect(browserWindow, "modifyTags()");
2083 attributeButton = toolBar.addAction("Attributes");
2084 QIcon attributeIcon = new QIcon(iconPath+"attribute.png");
2085 attributeButton.setIcon(attributeIcon);
2086 attributeButton.triggered.connect(this, "toggleNoteInformation()");
2088 emailButton = toolBar.addAction("Email");
2089 QIcon emailIcon = new QIcon(iconPath+"email.png");
2090 emailButton.setIcon(emailIcon);
2091 emailButton.triggered.connect(this, "emailNote()");
2093 deleteButton = toolBar.addAction("Delete");
2094 QIcon deleteIcon = new QIcon(iconPath+"delete.png");
2095 deleteButton.setIcon(deleteIcon);
2096 deleteButton.triggered.connect(this, "deleteNote()");
2098 newButton = toolBar.addAction("New");
2099 QIcon newIcon = new QIcon(iconPath+"new.png");
2100 newButton.triggered.connect(this, "addNote()");
2101 newButton.setIcon(newIcon);
2102 toolBar.addSeparator();
2103 toolBar.addWidget(new QLabel(tr("Quota:")));
2104 toolBar.addWidget(quotaBar);
2105 //quotaBar.setSizePolicy(Policy.Minimum, Policy.Minimum);
2109 zoomSpinner = new QSpinBox();
2110 zoomSpinner.setMinimum(10);
2111 zoomSpinner.setMaximum(1000);
2112 zoomSpinner.setAccelerated(true);
2113 zoomSpinner.setSingleStep(10);
2114 zoomSpinner.setValue(100);
2115 zoomSpinner.valueChanged.connect(this, "zoomChanged()");
2116 toolBar.addWidget(new QLabel(tr("Zoom")));
2117 toolBar.addWidget(zoomSpinner);
2119 //toolBar.addWidget(new QLabel(" "));
2120 toolBar.addSeparator();
2121 toolBar.addWidget(new QLabel(tr(" Search:")));
2122 toolBar.addWidget(searchField);
2123 QSizePolicy sizePolicy = new QSizePolicy();
2124 sizePolicy.setHorizontalPolicy(Policy.MinimumExpanding);
2125 searchField.setSizePolicy(sizePolicy);
2126 searchField.setInsertPolicy(InsertPolicy.InsertAtTop);
2128 searchClearButton = toolBar.addAction("Search Clear");
2129 QIcon searchClearIcon = new QIcon(iconPath+"searchclear.png");
2130 searchClearButton.setIcon(searchClearIcon);
2131 searchClearButton.triggered.connect(this, "searchFieldCleared()");
2133 logger.log(logger.HIGH, "Leaving NeverNote.setupToolBar");
2135 // Update the sychronize button picture
2136 @SuppressWarnings("unused")
2137 private void updateSyncButton() {
2139 if (synchronizeFrame == 4)
2140 synchronizeFrame = 0;
2141 synchronizeButton.setIcon(synchronizeAnimation.get(synchronizeFrame));
2143 // Synchronize with Evernote
2144 @SuppressWarnings("unused")
2145 private void evernoteSync() {
2146 logger.log(logger.HIGH, "Entering NeverNote.evernoteSync");
2147 if (!Global.isConnected)
2149 if (Global.isConnected)
2150 synchronizeAnimationTimer.start(200);
2152 logger.log(logger.HIGH, "Leaving NeverNote.evernoteSync");
2154 private void updateQuotaBar() {
2155 long limit = Global.getUploadLimit();
2156 long amount = Global.getUploadAmount();
2157 if (amount>0 && limit>0) {
2158 int percent =(int)(amount*100/limit);
2159 quotaBar.setValue(percent);
2161 quotaBar.setValue(0);
2164 @SuppressWarnings("unused")
2165 private void zoomChanged() {
2166 browserWindow.getBrowser().setZoomFactor(new Double(zoomSpinner.value())/100);
2169 //****************************************************************
2170 //****************************************************************
2171 //* System Tray functions
2172 //****************************************************************
2173 //****************************************************************
2174 private void trayToggleVisible() {
2182 @SuppressWarnings("unused")
2183 private void trayActivated(QSystemTrayIcon.ActivationReason reason) {
2184 if (reason == QSystemTrayIcon.ActivationReason.DoubleClick) {
2185 String name = QSystemTrayIcon.MessageIcon.resolve(reason.value()).name();
2186 trayToggleVisible();
2191 //***************************************************************
2192 //***************************************************************
2193 //** These functions deal with the trash tree
2194 //***************************************************************
2195 //***************************************************************
2196 // Setup the tree containing the trash.
2197 @SuppressWarnings("unused")
2198 private void trashTreeSelection() {
2199 logger.log(logger.HIGH, "Entering NeverNote.trashTreeSelection");
2201 clearNotebookFilter();
2203 clearAttributeFilter();
2204 clearSavedSearchFilter();
2206 String tempGuid = currentNoteGuid;
2208 // currentNoteGuid = "";
2209 currentNote = new Note();
2210 selectedNoteGUIDs.clear();
2211 listManager.getSelectedNotebooks().clear();
2212 listManager.getSelectedTags().clear();
2213 listManager.setSelectedSavedSearch("");
2214 browserWindow.clear();
2216 // toggle the add buttons
2217 newButton.setEnabled(!newButton.isEnabled());
2218 menuBar.noteAdd.setEnabled(newButton.isEnabled());
2219 menuBar.noteAdd.setVisible(true);
2221 List<QTreeWidgetItem> selections = trashTree.selectedItems();
2222 if (selections.size() == 0) {
2223 currentNoteGuid = trashNoteGuid;
2224 trashNoteGuid = tempGuid;
2225 Global.showDeleted = false;
2226 menuBar.noteRestoreAction.setEnabled(false);
2227 menuBar.noteRestoreAction.setVisible(false);
2230 currentNoteGuid = trashNoteGuid;
2231 trashNoteGuid = tempGuid;
2232 menuBar.noteRestoreAction.setEnabled(true);
2233 menuBar.noteRestoreAction.setVisible(true);
2234 Global.showDeleted = true;
2236 listManager.loadNotesIndex();
2237 noteIndexUpdated(false);
2238 //// browserWindow.setEnabled(newButton.isEnabled());
2239 browserWindow.setReadOnly(!newButton.isEnabled());
2240 logger.log(logger.HIGH, "Leaving NeverNote.trashTreeSelection");
2242 // Empty the trash file
2243 @SuppressWarnings("unused")
2244 private void emptyTrash() {
2245 // browserWindow.clear();
2246 listManager.emptyTrash();
2247 if (trashTree.selectedItems().size() > 0) {
2248 listManager.getSelectedNotebooks().clear();
2249 listManager.getSelectedTags().clear();
2250 listManager.setSelectedSavedSearch("");
2251 newButton.setEnabled(!newButton.isEnabled());
2252 menuBar.noteAdd.setEnabled(newButton.isEnabled());
2253 menuBar.noteAdd.setVisible(true);
2254 browserWindow.clear();
2257 clearNotebookFilter();
2258 clearSavedSearchFilter();
2259 clearAttributeFilter();
2261 Global.showDeleted = false;
2262 menuBar.noteRestoreAction.setEnabled(false);
2263 menuBar.noteRestoreAction.setVisible(false);
2265 listManager.loadNotesIndex();
2266 //--->>> noteIndexUpdated(true);
2267 noteIndexUpdated(false);
2270 // Show/Hide trash window
2271 private void toggleTrashWindow() {
2272 logger.log(logger.HIGH, "Entering NeverNote.toggleTrashWindow");
2273 if (trashTree.isVisible())
2277 menuBar.hideTrash.setChecked(trashTree.isVisible());
2279 Global.saveWindowVisible("trashTree", trashTree.isVisible());
2280 logger.log(logger.HIGH, "Leaving NeverNote.trashWindow");
2282 private void clearTrashFilter() {
2283 Global.showDeleted = false;
2284 newButton.setEnabled(true);
2285 menuBar.noteAdd.setEnabled(true);
2286 menuBar.noteAdd.setVisible(true);
2287 trashTree.blockSignals(true);
2288 trashTree.clearSelection();
2289 trashTree.blockSignals(false);
2294 //***************************************************************
2295 //***************************************************************
2296 //** These functions deal with connection settings
2297 //***************************************************************
2298 //***************************************************************
2299 // SyncRunner had a problem and things are disconnected
2300 @SuppressWarnings("unused")
2301 private void remoteErrorDisconnect() {
2302 menuBar.connectAction.setText(tr("Connect"));
2303 menuBar.connectAction.setToolTip(tr("Connect to Evernote"));
2304 menuBar.synchronizeAction.setEnabled(false);
2305 synchronizeAnimationTimer.stop();
2308 // Do a manual connect/disconnect
2309 private void remoteConnect() {
2310 logger.log(logger.HIGH, "Entering NeverNote.remoteConnect");
2312 if (Global.isConnected) {
2313 Global.isConnected = false;
2314 syncRunner.enDisconnect();
2315 setupConnectMenuOptions();
2320 AESEncrypter aes = new AESEncrypter();
2322 aes.decrypt(new FileInputStream(Global.getFileManager().getHomeDirFile("secure.txt")));
2323 } catch (FileNotFoundException e) {
2324 // File not found, so we'll just get empty strings anyway.
2326 String userid = aes.getUserid();
2327 String password = aes.getPassword();
2328 if (!userid.equals("") && !password.equals("")) {
2329 Global.username = userid;
2330 Global.password = password;
2333 // Show the login dialog box
2334 if (!Global.automaticLogin() || userid.equals("")|| password.equals("")) {
2335 LoginDialog login = new LoginDialog();
2338 if (!login.okPressed()) {
2342 Global.username = login.getUserid();
2343 Global.password = login.getPassword();
2345 syncRunner.username = Global.username;
2346 syncRunner.password = Global.password;
2347 syncRunner.userStoreUrl = Global.userStoreUrl;
2348 syncRunner.noteStoreUrl = Global.noteStoreUrl;
2349 syncRunner.noteStoreUrlBase = Global.noteStoreUrlBase;
2350 syncRunner.enConnect();
2351 Global.isConnected = syncRunner.isConnected;
2353 setupConnectMenuOptions();
2354 logger.log(logger.HIGH, "Leaving NeverNote.remoteConnect");
2356 private void setupConnectMenuOptions() {
2357 logger.log(logger.HIGH, "entering NeverNote.setupConnectMenuOptions");
2358 if (!Global.isConnected) {
2359 menuBar.connectAction.setText(tr("Connect"));
2360 menuBar.connectAction.setToolTip(tr("Connect to Evernote"));
2361 menuBar.synchronizeAction.setEnabled(false);
2363 menuBar.connectAction.setText(tr("Disconnect"));
2364 menuBar.connectAction.setToolTip(tr("Disconnect from Evernote"));
2365 menuBar.synchronizeAction.setEnabled(true);
2367 logger.log(logger.HIGH, "Leaving NeverNote.setupConnectionMenuOptions");
2372 //***************************************************************
2373 //***************************************************************
2374 //** These functions deal with the GUI Attribute tree
2375 //***************************************************************
2376 //***************************************************************
2377 @SuppressWarnings("unused")
2378 private void attributeTreeClicked(QTreeWidgetItem item, Integer integer) {
2381 clearNotebookFilter();
2383 clearSavedSearchFilter();
2385 if (attributeTreeSelected == null || item.nativeId() != attributeTreeSelected.nativeId()) {
2386 if (item.childCount() > 0) {
2387 item.setSelected(false);
2389 Global.createdBeforeFilter.reset();
2390 Global.createdSinceFilter.reset();
2391 Global.changedBeforeFilter.reset();
2392 Global.changedSinceFilter.reset();
2393 Global.containsFilter.reset();
2394 attributeTreeSelected = item;
2395 DateAttributeFilterTable f = null;
2396 f = findDateAttributeFilterTable(item.parent());
2398 f.select(item.parent().indexOfChild(item));
2400 Global.containsFilter.select(item.parent().indexOfChild(item));
2403 listManager.loadNotesIndex();
2404 noteIndexUpdated(false);
2407 attributeTreeSelected = null;
2408 item.setSelected(false);
2409 Global.createdBeforeFilter.reset();
2410 Global.createdSinceFilter.reset();
2411 Global.changedBeforeFilter.reset();
2412 Global.changedSinceFilter.reset();
2413 Global.containsFilter.reset();
2414 listManager.loadNotesIndex();
2415 noteIndexUpdated(false);
2417 // This determines what attribute filter we need, depending upon the selection
2418 private DateAttributeFilterTable findDateAttributeFilterTable(QTreeWidgetItem w) {
2419 if (w.parent() != null && w.childCount() > 0) {
2420 QTreeWidgetItem parent = w.parent();
2421 if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Created &&
2422 w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Since)
2423 return Global.createdSinceFilter;
2424 if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Created &&
2425 w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Before)
2426 return Global.createdBeforeFilter;
2427 if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.LastModified &&
2428 w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Since)
2429 return Global.changedSinceFilter;
2430 if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.LastModified &&
2431 w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Before)
2432 return Global.changedBeforeFilter;
2437 // Show/Hide attribute search window
2438 private void toggleAttributesWindow() {
2439 logger.log(logger.HIGH, "Entering NeverNote.toggleAttributesWindow");
2440 if (attributeTree.isVisible())
2441 attributeTree.hide();
2443 attributeTree.show();
2444 menuBar.hideAttributes.setChecked(attributeTree.isVisible());
2446 Global.saveWindowVisible("attributeTree", attributeTree.isVisible());
2447 logger.log(logger.HIGH, "Leaving NeverNote.toggleAttributeWindow");
2449 private void clearAttributeFilter() {
2450 Global.createdBeforeFilter.reset();
2451 Global.createdSinceFilter.reset();
2452 Global.changedBeforeFilter.reset();
2453 Global.changedSinceFilter.reset();
2454 Global.containsFilter.reset();
2455 attributeTreeSelected = null;
2456 attributeTree.blockSignals(true);
2457 attributeTree.clearSelection();
2458 attributeTree.blockSignals(false);
2462 //***************************************************************
2463 //***************************************************************
2464 //** These functions deal with the GUI Note index table
2465 //***************************************************************
2466 //***************************************************************
2467 // Initialize the note list table
2468 private void initializeNoteTable() {
2469 logger.log(logger.HIGH, "Entering NeverNote.initializeNoteTable");
2470 noteTableView.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection);
2471 noteTableView.selectionModel().selectionChanged.connect(this, "noteTableSelection()");
2472 logger.log(logger.HIGH, "Leaving NeverNote.initializeNoteTable");
2474 // Show/Hide trash window
2475 @SuppressWarnings("unused")
2476 private void toggleNoteListWindow() {
2477 logger.log(logger.HIGH, "Entering NeverNote.toggleNoteListWindow");
2478 if (noteTableView.isVisible())
2479 noteTableView.hide();
2481 noteTableView.show();
2482 menuBar.hideNoteList.setChecked(noteTableView.isVisible());
2484 Global.saveWindowVisible("noteList", noteTableView.isVisible());
2485 logger.log(logger.HIGH, "Leaving NeverNote.toggleNoteListWindow");
2487 // Handle the event that a user selects a note from the table
2488 @SuppressWarnings("unused")
2489 private void noteTableSelection() {
2490 logger.log(logger.HIGH, "Entering NeverNote.noteTableSelection");
2492 if (historyGuids.size() == 0) {
2493 historyGuids.add(currentNoteGuid);
2494 historyPosition = 1;
2496 noteTableView.showColumn(Global.noteTableGuidPosition);
2498 List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
2499 noteTableView.hideColumn(Global.noteTableGuidPosition);
2501 if (selections.size() > 0) {
2503 menuBar.noteDuplicateAction.setEnabled(true);
2504 menuBar.noteOnlineHistoryAction.setEnabled(true);
2505 menuBar.noteMergeAction.setEnabled(true);
2506 selectedNoteGUIDs.clear();
2507 if (selections.size() != 1 || Global.showDeleted) {
2508 menuBar.noteDuplicateAction.setEnabled(false);
2510 if (selections.size() != 1 || !Global.isConnected) {
2511 menuBar.noteOnlineHistoryAction.setEnabled(false);
2513 if (selections.size() == 1) {
2514 menuBar.noteMergeAction.setEnabled(false);
2516 for (int i=0; i<selections.size(); i++) {
2517 int row = selections.get(i).row();
2519 upButton.setEnabled(false);
2521 upButton.setEnabled(true);
2522 if (row < listManager.getNoteTableModel().rowCount()-1)
2523 downButton.setEnabled(true);
2525 downButton.setEnabled(false);
2526 index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition);
2527 SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
2528 currentNoteGuid = (String)ix.values().toArray()[0];
2529 selectedNoteGUIDs.add(currentNoteGuid);
2533 nextButton.setEnabled(true);
2534 prevButton.setEnabled(true);
2536 int endPosition = historyGuids.size()-1;
2537 for (int j=historyPosition; j<=endPosition; j++) {
2538 historyGuids.remove(historyGuids.size()-1);
2540 historyGuids.add(currentNoteGuid);
2541 historyPosition = historyGuids.size();
2543 if (historyPosition <= 1)
2544 prevButton.setEnabled(false);
2545 if (historyPosition == historyGuids.size())
2546 nextButton.setEnabled(false);
2548 fromHistory = false;
2549 scrollToGuid(currentNoteGuid);
2550 refreshEvernoteNote(true);
2551 logger.log(logger.HIGH, "Leaving NeverNote.noteTableSelection");
2553 // Trigger a refresh when the note db has been updated
2554 private void noteIndexUpdated(boolean reload) {
2555 logger.log(logger.HIGH, "Entering NeverNote.noteIndexUpdated");
2557 refreshEvernoteNoteList();
2558 logger.log(logger.HIGH, "Calling note table reload in NeverNote.noteIndexUpdated() - "+reload);
2559 noteTableView.load(reload);
2560 scrollToGuid(currentNoteGuid);
2561 logger.log(logger.HIGH, "Leaving NeverNote.noteIndexUpdated");
2563 // Called when the list of notes is updated
2564 private void refreshEvernoteNoteList() {
2565 logger.log(logger.HIGH, "Entering NeverNote.refreshEvernoteNoteList");
2566 browserWindow.setDisabled(false);
2567 if (selectedNoteGUIDs == null)
2568 selectedNoteGUIDs = new ArrayList<String>();
2569 selectedNoteGUIDs.clear(); // clear out old entries
2571 String saveCurrentNoteGuid = new String();
2572 String tempNoteGuid = new String();
2574 historyGuids.clear();
2575 historyPosition = 0;
2576 prevButton.setEnabled(false);
2577 nextButton.setEnabled(false);
2579 if (currentNoteGuid == null)
2580 currentNoteGuid = new String();
2582 for (Note note : listManager.getNoteIndex()) {
2583 tempNoteGuid = note.getGuid();
2584 if (currentNoteGuid.equals(tempNoteGuid)) {
2585 saveCurrentNoteGuid = new String(tempNoteGuid);
2589 if (listManager.getNoteIndex().size() == 0) {
2590 currentNoteGuid = "";
2592 browserWindow.clear();
2593 browserWindow.setDisabled(true);
2596 if (saveCurrentNoteGuid.equals("") && listManager.getNoteIndex().size() >0) {
2597 currentNoteGuid = listManager.getNoteIndex().get(listManager.getNoteIndex().size()-1).getGuid();
2598 currentNote = listManager.getNoteIndex().get(listManager.getNoteIndex().size()-1);
2599 refreshEvernoteNote(true);
2601 refreshEvernoteNote(false);
2605 logger.log(logger.HIGH, "Leaving NeverNote.refreshEvernoteNoteList");
2607 // Called when the previous arrow button is clicked
2608 @SuppressWarnings("unused")
2609 private void previousViewedAction() {
2610 if (!prevButton.isEnabled())
2612 if (historyPosition == 0)
2615 if (historyPosition <= 0)
2617 String historyGuid = historyGuids.get(historyPosition-1);
2619 for (int i=0; i<noteTableView.model().rowCount(); i++) {
2620 QModelIndex modelIndex = noteTableView.model().index(i, Global.noteTableGuidPosition);
2621 if (modelIndex != null) {
2622 SortedMap<Integer, Object> ix = noteTableView.model().itemData(modelIndex);
2623 String tableGuid = (String)ix.values().toArray()[0];
2624 if (tableGuid.equals(historyGuid)) {
2625 noteTableView.selectRow(i);
2631 @SuppressWarnings("unused")
2632 private void nextViewedAction() {
2633 if (!nextButton.isEnabled())
2635 String historyGuid = historyGuids.get(historyPosition);
2638 for (int i=0; i<noteTableView.model().rowCount(); i++) {
2639 QModelIndex modelIndex = noteTableView.model().index(i, Global.noteTableGuidPosition);
2640 if (modelIndex != null) {
2641 SortedMap<Integer, Object> ix = noteTableView.model().itemData(modelIndex);
2642 String tableGuid = (String)ix.values().toArray()[0];
2643 if (tableGuid.equals(historyGuid)) {
2644 noteTableView.selectRow(i);
2650 // Called when the up arrow is clicked
2651 @SuppressWarnings("unused")
2652 private void upAction() {
2653 List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
2654 int row = selections.get(0).row();
2656 noteTableView.selectRow(row-1);
2659 // Called when the down arrow is clicked
2660 @SuppressWarnings("unused")
2661 private void downAction() {
2662 List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
2663 int row = selections.get(0).row();
2664 int max = listManager.getNoteTableModel().rowCount();
2666 noteTableView.selectRow(row+1);
2669 // Update a tag string for a specific note in the list
2670 @SuppressWarnings("unused")
2671 private void updateListTags(String guid, List<String> tags) {
2672 logger.log(logger.HIGH, "Entering NeverNote.updateListTags");
2673 StringBuffer tagBuffer = new StringBuffer();
2674 for (int i=0; i<tags.size(); i++) {
2675 tagBuffer.append(tags.get(i));
2676 if (i<tags.size()-1)
2677 tagBuffer.append(", ");
2680 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
2681 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
2682 if (modelIndex != null) {
2683 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
2684 String tableGuid = (String)ix.values().toArray()[0];
2685 if (tableGuid.equals(guid)) {
2686 listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition,tagBuffer.toString());
2687 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
2692 logger.log(logger.HIGH, "Leaving NeverNote.updateListTags");
2694 // Update a title for a specific note in the list
2695 @SuppressWarnings("unused")
2696 private void updateListAuthor(String guid, String author) {
2697 logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
2699 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
2700 //QModelIndex modelIndex = noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
2701 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
2702 if (modelIndex != null) {
2703 // SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(modelIndex);
2704 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
2705 String tableGuid = (String)ix.values().toArray()[0];
2706 if (tableGuid.equals(guid)) {
2707 listManager.getNoteTableModel().setData(i, Global.noteTableAuthorPosition,author);
2708 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
2713 logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
2715 private void updateListNoteNotebook(String guid, String notebook) {
2716 logger.log(logger.HIGH, "Entering NeverNote.updateListNoteNotebook");
2717 listManager.getNoteTableModel().updateNoteSyncStatus(guid, false);
2718 logger.log(logger.HIGH, "Leaving NeverNote.updateListNoteNotebook");
2720 // Update a title for a specific note in the list
2721 @SuppressWarnings("unused")
2722 private void updateListSourceUrl(String guid, String url) {
2723 logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
2725 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
2726 //QModelIndex modelIndex = noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
2727 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
2728 if (modelIndex != null) {
2729 // SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(modelIndex);
2730 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
2731 String tableGuid = (String)ix.values().toArray()[0];
2732 if (tableGuid.equals(guid)) {
2733 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
2734 listManager.getNoteTableModel().setData(i, Global.noteTableSourceUrlPosition,url);
2739 logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
2741 private void updateListGuid(String oldGuid, String newGuid) {
2742 logger.log(logger.HIGH, "Entering NeverNote.updateListTitle");
2744 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
2745 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
2746 if (modelIndex != null) {
2747 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
2748 String tableGuid = (String)ix.values().toArray()[0];
2749 if (tableGuid.equals(oldGuid)) {
2750 listManager.getNoteTableModel().setData(i, Global.noteTableGuidPosition,newGuid);
2751 //listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
2756 logger.log(logger.HIGH, "Leaving NeverNote.updateListTitle");
2758 private void updateListTagName(String guid) {
2759 logger.log(logger.HIGH, "Entering NeverNote.updateTagName");
2761 for (int j=0; j<listManager.getNoteIndex().size(); j++) {