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.net.Authenticator;
25 import java.net.PasswordAuthentication;
26 import java.security.MessageDigest;
27 import java.security.NoSuchAlgorithmException;
28 import java.sql.Connection;
29 import java.sql.DriverManager;
30 import java.sql.SQLException;
31 import java.sql.Statement;
32 import java.text.SimpleDateFormat;
33 import java.util.ArrayList;
34 import java.util.Calendar;
35 import java.util.Collection;
36 import java.util.Collections;
37 import java.util.Comparator;
38 import java.util.Date;
39 import java.util.GregorianCalendar;
40 import java.util.HashMap;
41 import java.util.Iterator;
42 import java.util.List;
43 import java.util.SortedMap;
44 import java.util.Vector;
46 import org.apache.log4j.Level;
47 import org.apache.log4j.Logger;
48 import org.apache.thrift.TException;
49 import org.h2.tools.ChangeFileEncryption;
51 import com.evernote.edam.error.EDAMNotFoundException;
52 import com.evernote.edam.error.EDAMSystemException;
53 import com.evernote.edam.error.EDAMUserException;
54 import com.evernote.edam.notestore.NoteFilter;
55 import com.evernote.edam.notestore.NoteVersionId;
56 import com.evernote.edam.type.Data;
57 import com.evernote.edam.type.LinkedNotebook;
58 import com.evernote.edam.type.Note;
59 import com.evernote.edam.type.NoteAttributes;
60 import com.evernote.edam.type.Notebook;
61 import com.evernote.edam.type.Publishing;
62 import com.evernote.edam.type.QueryFormat;
63 import com.evernote.edam.type.Resource;
64 import com.evernote.edam.type.SavedSearch;
65 import com.evernote.edam.type.Tag;
66 import com.evernote.edam.type.User;
67 import com.trolltech.qt.QThread;
68 import com.trolltech.qt.core.QByteArray;
69 import com.trolltech.qt.core.QDateTime;
70 import com.trolltech.qt.core.QDir;
71 import com.trolltech.qt.core.QEvent;
72 import com.trolltech.qt.core.QFile;
73 import com.trolltech.qt.core.QFileInfo;
74 import com.trolltech.qt.core.QFileSystemWatcher;
75 import com.trolltech.qt.core.QIODevice;
76 import com.trolltech.qt.core.QIODevice.OpenModeFlag;
77 import com.trolltech.qt.core.QLocale;
78 import com.trolltech.qt.core.QModelIndex;
79 import com.trolltech.qt.core.QSize;
80 import com.trolltech.qt.core.QTemporaryFile;
81 import com.trolltech.qt.core.QTextCodec;
82 import com.trolltech.qt.core.QThreadPool;
83 import com.trolltech.qt.core.QTimer;
84 import com.trolltech.qt.core.QTranslator;
85 import com.trolltech.qt.core.QUrl;
86 import com.trolltech.qt.core.Qt;
87 import com.trolltech.qt.core.Qt.BGMode;
88 import com.trolltech.qt.core.Qt.ItemDataRole;
89 import com.trolltech.qt.core.Qt.SortOrder;
90 import com.trolltech.qt.core.Qt.WidgetAttribute;
91 import com.trolltech.qt.gui.QAbstractItemView;
92 import com.trolltech.qt.gui.QAbstractItemView.ScrollHint;
93 import com.trolltech.qt.gui.QAction;
94 import com.trolltech.qt.gui.QApplication;
95 import com.trolltech.qt.gui.QCloseEvent;
96 import com.trolltech.qt.gui.QColor;
97 import com.trolltech.qt.gui.QComboBox;
98 import com.trolltech.qt.gui.QComboBox.InsertPolicy;
99 import com.trolltech.qt.gui.QCursor;
100 import com.trolltech.qt.gui.QDesktopServices;
101 import com.trolltech.qt.gui.QDialog;
102 import com.trolltech.qt.gui.QFileDialog;
103 import com.trolltech.qt.gui.QFileDialog.AcceptMode;
104 import com.trolltech.qt.gui.QFileDialog.FileMode;
105 import com.trolltech.qt.gui.QGridLayout;
106 import com.trolltech.qt.gui.QHBoxLayout;
107 import com.trolltech.qt.gui.QIcon;
108 import com.trolltech.qt.gui.QImage;
109 import com.trolltech.qt.gui.QLabel;
110 import com.trolltech.qt.gui.QListWidget;
111 import com.trolltech.qt.gui.QMainWindow;
112 import com.trolltech.qt.gui.QMenu;
113 import com.trolltech.qt.gui.QMessageBox;
114 import com.trolltech.qt.gui.QMessageBox.StandardButton;
115 import com.trolltech.qt.gui.QPainter;
116 import com.trolltech.qt.gui.QPalette.ColorRole;
117 import com.trolltech.qt.gui.QPixmap;
118 import com.trolltech.qt.gui.QPrintDialog;
119 import com.trolltech.qt.gui.QPrinter;
120 import com.trolltech.qt.gui.QSizePolicy;
121 import com.trolltech.qt.gui.QSizePolicy.Policy;
122 import com.trolltech.qt.gui.QSpinBox;
123 import com.trolltech.qt.gui.QSplashScreen;
124 import com.trolltech.qt.gui.QSplitter;
125 import com.trolltech.qt.gui.QStatusBar;
126 import com.trolltech.qt.gui.QSystemTrayIcon;
127 import com.trolltech.qt.gui.QTableWidgetItem;
128 import com.trolltech.qt.gui.QTextEdit;
129 import com.trolltech.qt.gui.QToolBar;
130 import com.trolltech.qt.gui.QTreeWidgetItem;
131 import com.trolltech.qt.webkit.QWebPage.WebAction;
132 import com.trolltech.qt.webkit.QWebSettings;
134 import cx.fbn.nevernote.config.InitializationException;
135 import cx.fbn.nevernote.config.StartupConfig;
136 import cx.fbn.nevernote.dialog.AccountDialog;
137 import cx.fbn.nevernote.dialog.ConfigDialog;
138 import cx.fbn.nevernote.dialog.DBEncryptDialog;
139 import cx.fbn.nevernote.dialog.DatabaseLoginDialog;
140 import cx.fbn.nevernote.dialog.DatabaseStatus;
141 import cx.fbn.nevernote.dialog.FindDialog;
142 import cx.fbn.nevernote.dialog.LoginDialog;
143 import cx.fbn.nevernote.dialog.NotebookArchive;
144 import cx.fbn.nevernote.dialog.NotebookEdit;
145 import cx.fbn.nevernote.dialog.OnlineNoteHistory;
146 import cx.fbn.nevernote.dialog.PublishNotebook;
147 import cx.fbn.nevernote.dialog.SavedSearchEdit;
148 import cx.fbn.nevernote.dialog.SetIcon;
149 import cx.fbn.nevernote.dialog.ShareNotebook;
150 import cx.fbn.nevernote.dialog.StackNotebook;
151 import cx.fbn.nevernote.dialog.TagEdit;
152 import cx.fbn.nevernote.dialog.ThumbnailViewer;
153 import cx.fbn.nevernote.dialog.WatchFolder;
154 import cx.fbn.nevernote.filters.FilterEditorNotebooks;
155 import cx.fbn.nevernote.filters.FilterEditorTags;
156 import cx.fbn.nevernote.gui.AttributeTreeWidget;
157 import cx.fbn.nevernote.gui.BrowserWindow;
158 import cx.fbn.nevernote.gui.DateAttributeFilterTable;
159 import cx.fbn.nevernote.gui.ExternalBrowse;
160 import cx.fbn.nevernote.gui.MainMenuBar;
161 import cx.fbn.nevernote.gui.NotebookTreeWidget;
162 import cx.fbn.nevernote.gui.SavedSearchTreeWidget;
163 import cx.fbn.nevernote.gui.TableView;
164 import cx.fbn.nevernote.gui.TagTreeWidget;
165 import cx.fbn.nevernote.gui.Thumbnailer;
166 import cx.fbn.nevernote.gui.TrashTreeWidget;
167 import cx.fbn.nevernote.gui.controls.QuotaProgressBar;
168 import cx.fbn.nevernote.sql.DatabaseConnection;
169 import cx.fbn.nevernote.sql.WatchFolderRecord;
170 import cx.fbn.nevernote.threads.IndexRunner;
171 import cx.fbn.nevernote.threads.SyncRunner;
172 import cx.fbn.nevernote.threads.ThumbnailRunner;
173 import cx.fbn.nevernote.utilities.AESEncrypter;
174 import cx.fbn.nevernote.utilities.ApplicationLogger;
175 import cx.fbn.nevernote.utilities.FileImporter;
176 import cx.fbn.nevernote.utilities.FileUtils;
177 import cx.fbn.nevernote.utilities.ListManager;
178 import cx.fbn.nevernote.utilities.SyncTimes;
179 import cx.fbn.nevernote.xml.ExportData;
180 import cx.fbn.nevernote.xml.ImportData;
181 import cx.fbn.nevernote.xml.NoteFormatter;
184 public class NeverNote extends QMainWindow{
186 QStatusBar statusBar; // Application status bar
188 DatabaseConnection conn;
190 MainMenuBar menuBar; // Main menu bar
191 FindDialog find; // Text search in note dialog
192 List<String> emitLog; // Messages displayed in the status bar;
193 QSystemTrayIcon trayIcon; // little tray icon
194 QMenu trayMenu; // System tray menu
195 QAction trayExitAction; // Exit the application
196 QAction trayShowAction; // toggle the show/hide action
197 QAction trayAddNoteAction; // Add a note from the system tray
199 NotebookTreeWidget notebookTree; // List of notebooks
200 AttributeTreeWidget attributeTree; // List of note attributes
201 TagTreeWidget tagTree; // list of user created tags
202 SavedSearchTreeWidget savedSearchTree; // list of saved searches
203 TrashTreeWidget trashTree; // Trashcan
204 TableView noteTableView; // List of notes (the widget).
206 public BrowserWindow browserWindow; // Window containing browser & labels
207 public QToolBar toolBar; // The tool bar under the menu
208 QComboBox searchField; // search filter bar on the toolbar;
209 boolean searchPerformed = false; // Search was done?
210 QuotaProgressBar quotaBar; // The current quota usage
212 ApplicationLogger logger;
213 List<String> selectedNotebookGUIDs; // List of notebook GUIDs
214 List<String> selectedTagGUIDs; // List of selected tag GUIDs
215 String previousSelectedTag; // Tag that was selected last time
216 List<String> selectedNoteGUIDs; // List of selected notes
217 String previousSelectedNotebook; // Notebook selected last time
218 String selectedSavedSearchGUID; // Currently selected saved searches
219 private final HashMap<String, ExternalBrowse> externalWindows; // Notes being edited by an external window;
221 NoteFilter filter; // Note filter
222 String currentNoteGuid; // GUID of the current note
223 Note currentNote; // The currently viewed note
224 boolean noteDirty; // Has the note been changed?
225 boolean inkNote; // if this is an ink note, it is read only
226 boolean readOnly; // Is this note read-only?
229 ListManager listManager; // DB runnable task
231 List<QTemporaryFile> tempFiles; // Array of temporary files;
233 QTimer indexTimer; // timer to start the index thread
234 IndexRunner indexRunner; // thread to index notes
237 QTimer syncTimer; // Sync on an interval
238 QTimer syncDelayTimer; // Sync delay to free up database
239 SyncRunner syncRunner; // thread to do a sync.
240 QThread syncThread; // Thread which talks to evernote
241 ThumbnailRunner thumbnailRunner; // Runner for thumbnail thread
242 QThread thumbnailThread; // Thread that generates pretty pictures
243 QTimer saveTimer; // Timer to save note contents
245 QTimer authTimer; // Refresh authentication
246 QTimer externalFileSaveTimer; // Save files altered externally
247 QTimer thumbnailTimer; // Wakeup & scan for thumbnails
248 List<String> externalFiles; // External files to save later
249 List<String> importFilesKeep; // Auto-import files to save later
250 List<String> importFilesDelete; // Auto-import files to save later
252 int indexTime; // how often to try and index
253 boolean indexRunning; // Is indexing running?
254 boolean indexDisabled; // Is indexing disabled?
256 int syncThreadsReady; // number of sync threads that are free
257 int syncTime; // Sync interval
258 boolean syncRunning; // Is sync running?
259 boolean automaticSync; // do sync automatically?
260 QTreeWidgetItem attributeTreeSelected;
262 QAction prevButton; // Go to the previous item viewed
263 QAction nextButton; // Go to the next item in the history
264 QAction downButton; // Go to the next item in the list
265 QAction upButton; // Go to the prev. item in the list;
266 QAction synchronizeButton; // Synchronize with Evernote
267 QAction allNotesButton; // Reset & view all notes
268 QTimer synchronizeAnimationTimer; // Timer to change animation button
269 int synchronizeIconAngle; // Used to rotate sync icon
270 QAction printButton; // Print Button
271 QAction tagButton; // Tag edit button
272 QAction attributeButton; // Attribute information button
273 QAction emailButton; // Email button
274 QAction deleteButton; // Delete button
275 QAction newButton; // new Note Button;
276 QSpinBox zoomSpinner; // Zoom zoom
277 QAction searchClearButton; // Clear the search field
279 QSplitter mainLeftRightSplitter; // main splitter for left/right side
280 QSplitter leftSplitter1; // first left hand splitter
281 QSplitter browserIndexSplitter; // splitter between note index & note text
283 QFileSystemWatcher importKeepWatcher; // Watch & keep auto-import
284 QFileSystemWatcher importDeleteWatcher; // Watch & Delete auto-import
285 List<String> importedFiles; // History of imported files (so we don't import twice)
287 OnlineNoteHistory historyWindow; // online history window
288 List<NoteVersionId> versions; // history versions
290 QTimer threadMonitorTimer; // Timer to watch threads.
291 int dbThreadDeadCount=0; // number of consecutive dead times for the db thread
292 int syncThreadDeadCount=0; // number of consecutive dead times for the sync thread
293 int indexThreadDeadCount=0; // number of consecutive dead times for the index thread
294 int notebookThreadDeadCount=0; // number of consecutive dead times for the notebook thread
295 int tagDeadCount=0; // number of consecutive dead times for the tag thread
296 int trashDeadCount=0; // number of consecutive dead times for the trash thread
297 int saveThreadDeadCount=0; // number of consecutive dead times for the save thread
299 HashMap<String, String> noteCache; // Cash of note content
300 HashMap<String, Boolean> readOnlyCache; // List of cashe notes that are read-only
301 HashMap<String, Boolean> inkNoteCache; // List of cache notes that are ink notes
302 List<String> historyGuids; // GUIDs of previously viewed items
303 int historyPosition; // Position within the viewed items
304 boolean fromHistory; // Is this from the history queue?
305 String trashNoteGuid; // Guid to restore / set into or out of trash to save position
306 List<Thumbnailer> thumbGenerators; // generate preview image
307 ThumbnailViewer thumbnailViewer; // View preview thumbnail;
308 boolean encryptOnShutdown; // should I encrypt when I close?
309 boolean decryptOnShutdown; // should I decrypt on shutdown;
310 String encryptCipher; // What cipher should I use?
311 Signal0 minimizeToTray;
312 boolean windowMaximized = false; // Keep track of the window state for restores
313 List<String> pdfReadyQueue; // Queue of PDFs that are ready to be rendered.
314 List<QPixmap> syncIcons; // Array of icons used in sync animation
315 private boolean closeAction = false; // Used to say when to close or when to minimize
316 private static Logger log = Logger.getLogger(NeverNote.class);
319 String iconPath = new String("classpath:cx/fbn/nevernote/icons/");
322 //***************************************************************
323 //***************************************************************
324 //** Constructor & main entry point
325 //***************************************************************
326 //***************************************************************
327 // Application Constructor
328 @SuppressWarnings("static-access")
329 public NeverNote(DatabaseConnection dbConn) {
331 if (conn.getConnection() == null) {
332 String msg = new String(tr("Unable to connect to the database.\n\nThe most probable reason is that some other process\n" +
333 "is accessing the database or NeverNote is already running.\n\n" +
334 "Please end any other process or shutdown the other NeverNote before starting.\n\nExiting program."));
336 QMessageBox.critical(null, tr("Database Connection Error") ,msg);
340 thread().setPriority(Thread.MAX_PRIORITY);
342 logger = new ApplicationLogger("nevernote.log");
343 logger.log(logger.HIGH, "Starting Application");
345 decryptOnShutdown = false;
346 encryptOnShutdown = false;
347 conn.checkDatabaseVersion();
351 // Start building the invalid XML tables
352 Global.invalidElements = conn.getInvalidXMLTable().getInvalidElements();
353 List<String> elements = conn.getInvalidXMLTable().getInvalidAttributeElements();
355 for (int i=0; i<elements.size(); i++) {
356 Global.invalidAttributes.put(elements.get(i), conn.getInvalidXMLTable().getInvalidAttributes(elements.get(i)));
359 logger.log(logger.EXTREME, "Starting GUI build");
361 QTranslator nevernoteTranslator = new QTranslator();
362 nevernoteTranslator.load(Global.getFileManager().getTranslateFilePath("nevernote_" + QLocale.system().name() + ".qm"));
363 QApplication.instance().installTranslator(nevernoteTranslator);
365 Global.originalPalette = QApplication.palette();
366 QApplication.setStyle(Global.getStyle());
367 if (Global.useStandardPalette())
368 QApplication.setPalette(QApplication.style().standardPalette());
369 setWindowTitle("NeverNote");
371 mainLeftRightSplitter = new QSplitter();
372 setCentralWidget(mainLeftRightSplitter);
373 leftSplitter1 = new QSplitter();
374 leftSplitter1.setOrientation(Qt.Orientation.Vertical);
376 browserIndexSplitter = new QSplitter();
377 browserIndexSplitter.setOrientation(Qt.Orientation.Vertical);
379 //* Setup threads & thread timers
380 int indexRunnerCount = Global.getIndexThreads();
381 indexRunnerCount = 1;
382 QThreadPool.globalInstance().setMaxThreadCount(indexRunnerCount+5); // increase max thread count
384 logger.log(logger.EXTREME, "Building list manager");
385 listManager = new ListManager(conn, logger);
387 logger.log(logger.EXTREME, "Building index runners & timers");
388 indexRunner = new IndexRunner("indexRunner.log", Global.getDatabaseUrl(), Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
389 indexThread = new QThread(indexRunner, "Index Thread");
390 indexRunner.indexAttachmentsLocally = Global.indexAttachmentsLocally();
393 synchronizeAnimationTimer = new QTimer();
394 synchronizeAnimationTimer.timeout.connect(this, "updateSyncButton()");
396 indexTimer = new QTimer();
397 indexTime = 1000*Global.getIndexThreadSleepInterval();
398 indexTimer.start(indexTime); // Start indexing timer
399 indexTimer.timeout.connect(this, "indexTimer()");
400 indexDisabled = false;
401 indexRunning = false;
403 logger.log(logger.EXTREME, "Setting sync thread & timers");
405 syncRunner = new SyncRunner("syncRunner.log", Global.getDatabaseUrl(), Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
406 syncTime = new SyncTimes().timeValue(Global.getSyncInterval());
407 syncTimer = new QTimer();
408 syncTimer.timeout.connect(this, "syncTimer()");
409 syncRunner.status.message.connect(this, "setMessage(String)");
410 syncRunner.syncSignal.finished.connect(this, "syncThreadComplete(Boolean)");
411 syncRunner.syncSignal.errorDisconnect.connect(this, "remoteErrorDisconnect()");
414 automaticSync = true;
415 syncTimer.start(syncTime*60*1000);
417 automaticSync = false;
420 syncRunner.setEvernoteUpdateCount(Global.getEvernoteUpdateCount());
421 syncThread = new QThread(syncRunner, "Synchronization Thread");
425 logger.log(logger.EXTREME, "Starting thumnail thread");
426 pdfReadyQueue = new ArrayList<String>();
427 thumbnailRunner = new ThumbnailRunner("thumbnailRunner.log", Global.getDatabaseUrl(), Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
428 thumbnailThread = new QThread(thumbnailRunner, "Thumbnail Thread");
429 thumbnailRunner.noteSignal.thumbnailPageReady.connect(this, "thumbnailHTMLReady(String,QByteArray,Integer)");
430 thumbnailThread.start();
431 thumbGenerators = new ArrayList<Thumbnailer>();
432 thumbnailTimer = new QTimer();
433 thumbnailTimer.timeout.connect(this, "thumbnailTimer()");
435 thumbnailTimer.setInterval(60*1000); // Thumbnail every minute
436 thumbnailTimer.start();
438 logger.log(logger.EXTREME, "Starting authentication timer");
439 authTimer = new QTimer();
440 authTimer.timeout.connect(this, "authTimer()");
441 authTimer.start(1000*60*15);
442 syncRunner.syncSignal.authRefreshComplete.connect(this, "authRefreshComplete(boolean)");
444 logger.log(logger.EXTREME, "Setting save note timer");
445 saveTimer = new QTimer();
446 saveTimer.timeout.connect(this, "saveNote()");
447 if (Global.getAutoSaveInterval() > 0) {
448 saveTimer.setInterval(1000*60*Global.getAutoSaveInterval());
451 listManager.saveRunner.noteSignals.noteSaveRunnerError.connect(this, "saveRunnerError(String, String)");
453 logger.log(logger.EXTREME, "Starting external file monitor timer");
454 externalFileSaveTimer = new QTimer();
455 externalFileSaveTimer.timeout.connect(this, "externalFileEditedSaver()");
456 externalFileSaveTimer.setInterval(1000*5); // save every 5 seconds;
457 externalFiles = new ArrayList<String>();
458 importFilesDelete = new ArrayList<String>();
459 importFilesKeep = new ArrayList<String>();
460 externalFileSaveTimer.start();
462 notebookTree = new NotebookTreeWidget(conn);
463 attributeTree = new AttributeTreeWidget();
464 tagTree = new TagTreeWidget(conn);
465 savedSearchTree = new SavedSearchTreeWidget();
466 trashTree = new TrashTreeWidget();
467 noteTableView = new TableView(logger, listManager);
469 QGridLayout leftGrid = new QGridLayout();
470 leftSplitter1.setLayout(leftGrid);
471 leftGrid.addWidget(notebookTree, 1, 1);
472 leftGrid.addWidget(tagTree,2,1);
473 leftGrid.addWidget(attributeTree,3,1);
474 leftGrid.addWidget(savedSearchTree,4,1);
475 leftGrid.addWidget(trashTree, 5, 1);
477 // Setup the browser window
478 noteCache = new HashMap<String,String>();
479 readOnlyCache = new HashMap<String, Boolean>();
480 inkNoteCache = new HashMap<String, Boolean>();
481 browserWindow = new BrowserWindow(conn);
483 mainLeftRightSplitter.addWidget(leftSplitter1);
484 mainLeftRightSplitter.addWidget(browserIndexSplitter);
486 if (Global.getListView() == Global.View_List_Wide) {
487 browserIndexSplitter.addWidget(noteTableView);
488 browserIndexSplitter.addWidget(browserWindow);
490 mainLeftRightSplitter.addWidget(noteTableView);
491 mainLeftRightSplitter.addWidget(browserWindow);
494 searchField = new QComboBox();
495 searchField.setEditable(true);
496 searchField.activatedIndex.connect(this, "searchFieldChanged()");
497 searchField.setDuplicatesEnabled(false);
498 searchField.editTextChanged.connect(this,"searchFieldTextChanged(String)");
500 quotaBar = new QuotaProgressBar();
502 // Setup the thumbnail viewer
503 thumbnailViewer = new ThumbnailViewer();
504 thumbnailViewer.upArrow.connect(this, "upAction()");
505 thumbnailViewer.downArrow.connect(this, "downAction()");
506 thumbnailViewer.leftArrow.connect(this, "nextViewedAction()");
507 thumbnailViewer.rightArrow.connect(this, "previousViewedAction()");
509 //Setup external browser manager
510 externalWindows = new HashMap<String, ExternalBrowse>();
512 listManager.loadNotesIndex();
513 initializeNotebookTree();
515 initializeSavedSearchTree();
516 attributeTree.itemClicked.connect(this, "attributeTreeClicked(QTreeWidgetItem, Integer)");
517 attributeTreeSelected = null;
518 initializeNoteTable();
520 selectedNoteGUIDs = new ArrayList<String>();
521 statusBar = new QStatusBar();
522 setStatusBar(statusBar);
523 menuBar = new MainMenuBar(this);
524 emitLog = new ArrayList<String>();
526 tagTree.setDeleteAction(menuBar.tagDeleteAction);
527 tagTree.setEditAction(menuBar.tagEditAction);
528 tagTree.setAddAction(menuBar.tagAddAction);
529 tagTree.setIconAction(menuBar.tagIconAction);
530 tagTree.setVisible(Global.isWindowVisible("tagTree"));
531 tagTree.noteSignal.tagsAdded.connect(this, "tagsAdded(String, String)");
532 menuBar.hideTags.setChecked(Global.isWindowVisible("tagTree"));
533 listManager.tagSignal.listChanged.connect(this, "reloadTagTree()");
535 notebookTree.setDeleteAction(menuBar.notebookDeleteAction);
536 notebookTree.setEditAction(menuBar.notebookEditAction);
537 notebookTree.setAddAction(menuBar.notebookAddAction);
538 notebookTree.setIconAction(menuBar.notebookIconAction);
539 notebookTree.setStackAction(menuBar.notebookStackAction);
540 notebookTree.setPublishAction(menuBar.notebookPublishAction);
541 notebookTree.setShareAction(menuBar.notebookShareAction);
542 notebookTree.setVisible(Global.isWindowVisible("notebookTree"));
543 notebookTree.noteSignal.notebookChanged.connect(this, "updateNoteNotebook(String, String)");
544 notebookTree.noteSignal.tagsChanged.connect(this, "updateNoteTags(String, List)");
545 notebookTree.noteSignal.tagsChanged.connect(this, "updateListTags(String, List)");
546 menuBar.hideNotebooks.setChecked(Global.isWindowVisible("notebookTree"));
548 savedSearchTree.setAddAction(menuBar.savedSearchAddAction);
549 savedSearchTree.setEditAction(menuBar.savedSearchEditAction);
550 savedSearchTree.setDeleteAction(menuBar.savedSearchDeleteAction);
551 savedSearchTree.setIconAction(menuBar.savedSearchIconAction);
552 savedSearchTree.itemSelectionChanged.connect(this, "updateSavedSearchSelection()");
553 savedSearchTree.setVisible(Global.isWindowVisible("savedSearchTree"));
554 menuBar.hideSavedSearches.setChecked(Global.isWindowVisible("savedSearchTree"));
556 noteTableView.setAddAction(menuBar.noteAdd);
557 noteTableView.setDeleteAction(menuBar.noteDelete);
558 noteTableView.setRestoreAction(menuBar.noteRestoreAction);
559 noteTableView.setNoteDuplicateAction(menuBar.noteDuplicateAction);
560 noteTableView.setNoteHistoryAction(menuBar.noteOnlineHistoryAction);
561 noteTableView.noteSignal.titleColorChanged.connect(this, "titleColorChanged(Integer)");
562 noteTableView.setMergeNotesAction(menuBar.noteMergeAction);
563 noteTableView.rowChanged.connect(this, "scrollToGuid(String)");
564 noteTableView.resetViewport.connect(this, "scrollToCurrentGuid()");
565 noteTableView.doubleClicked.connect(this, "listDoubleClick()");
566 listManager.trashSignal.countChanged.connect(trashTree, "updateCounts(Integer)");
568 quotaBar.setMouseClickAction(menuBar.accountAction);
571 trashTree.itemSelectionChanged.connect(this, "trashTreeSelection()");
572 trashTree.setEmptyAction(menuBar.emptyTrashAction);
573 trashTree.setVisible(Global.isWindowVisible("trashTree"));
574 menuBar.hideTrash.setChecked(Global.isWindowVisible("trashTree"));
575 trashTree.updateCounts(listManager.getTrashCount());
576 attributeTree.setVisible(Global.isWindowVisible("attributeTree"));
577 menuBar.hideAttributes.setChecked(Global.isWindowVisible("attributeTree"));
579 noteTableView.setVisible(Global.isWindowVisible("noteList"));
580 menuBar.hideNoteList.setChecked(Global.isWindowVisible("noteList"));
582 if (!Global.isWindowVisible("editorButtonBar"))
583 toggleEditorButtonBar();
584 if (!Global.isWindowVisible("leftPanel"))
585 menuBar.hideLeftSide.setChecked(true);
586 if (Global.isWindowVisible("noteInformation"))
587 toggleNoteInformation();
591 find = new FindDialog();
592 find.getOkButton().clicked.connect(this, "doFindText()");
594 // Setup the tray icon menu bar
595 trayShowAction = new QAction("Show/Hide", this);
596 trayExitAction = new QAction("Exit", this);
597 trayAddNoteAction = new QAction("Add Note", this);
599 trayExitAction.triggered.connect(this, "closeNeverNote()");
600 trayAddNoteAction.triggered.connect(this, "addNote()");
601 trayShowAction.triggered.connect(this, "trayToggleVisible()");
603 trayMenu = new QMenu(this);
604 trayMenu.addAction(trayAddNoteAction);
605 trayMenu.addAction(trayShowAction);
606 trayMenu.addAction(trayExitAction);
609 trayIcon = new QSystemTrayIcon(this);
610 trayIcon.setToolTip("NeverNote");
611 trayIcon.setContextMenu(trayMenu);
612 trayIcon.activated.connect(this, "trayActivated(com.trolltech.qt.gui.QSystemTrayIcon$ActivationReason)");
615 currentNoteGuid = Global.getLastViewedNoteGuid();
616 historyGuids = new ArrayList<String>();
620 if (!currentNoteGuid.trim().equals("")) {
621 currentNote = conn.getNoteTable().getNote(currentNoteGuid, true,true,false,false,true);
624 noteIndexUpdated(true);
626 menuBar.showEditorBar.setChecked(Global.isWindowVisible("editorButtonBar"));
627 if (menuBar.showEditorBar.isChecked())
628 showEditorButtons(browserWindow);
629 tagIndexUpdated(true);
630 savedSearchIndexUpdated();
631 notebookIndexUpdated();
633 setupSyncSignalListeners();
634 setupBrowserSignalListeners();
635 setupIndexListeners();
638 tagTree.tagSignal.listChanged.connect(this, "tagIndexUpdated()");
639 tagTree.showAllTags(true);
641 QIcon appIcon = new QIcon(iconPath+"nevernote.png");
642 setWindowIcon(appIcon);
643 trayIcon.setIcon(appIcon);
644 if (Global.showTrayIcon())
649 scrollToGuid(currentNoteGuid);
650 if (Global.automaticLogin()) {
652 if (Global.isConnected)
655 setupFolderImports();
658 restoreWindowState(true);
660 if (Global.mimicEvernoteInterface) {
661 notebookTree.selectGuid("");
664 threadMonitorTimer = new QTimer();
665 threadMonitorTimer.timeout.connect(this, "threadMonitorCheck()");
666 threadMonitorTimer.start(1000*10); // Check for threads every 10 seconds;
668 historyGuids.add(currentNoteGuid);
671 if (Global.getListView() == Global.View_List_Narrow) {
672 menuBar.narrowListView.setChecked(true);
676 menuBar.wideListView.setChecked(true);
680 if (Global.getListView() == Global.View_List_Wide) {
681 browserIndexSplitter.addWidget(noteTableView);
682 browserIndexSplitter.addWidget(browserWindow);
684 mainLeftRightSplitter.addWidget(noteTableView);
685 mainLeftRightSplitter.addWidget(browserWindow);
688 int sortCol = Global.getSortColumn();
689 int sortOrder = Global.getSortOrder();
690 noteTableView.sortByColumn(sortCol, SortOrder.resolve(sortOrder));
696 public static void main(String[] args) {
697 log.setLevel(Level.FATAL);
698 QApplication.initialize(args);
699 QPixmap pixmap = new QPixmap("classpath:cx/fbn/nevernote/icons/splash_logo.png");
700 QSplashScreen splash = new QSplashScreen(pixmap);
703 DatabaseConnection dbConn;
706 initializeGlobalSettings(args);
708 showSplash = Global.isWindowVisible("SplashScreen");
712 dbConn = setupDatabaseConnection();
714 // Must be last stage of setup - only safe once DB is open hence we know we are the only instance running
715 Global.getFileManager().purgeResDirectory(true);
717 } catch (InitializationException e) {
720 QMessageBox.critical(null, "Startup error", "Aborting: " + e.getMessage());
724 NeverNote application = new NeverNote(dbConn);
726 application.setAttribute(WidgetAttribute.WA_DeleteOnClose, true);
727 if (Global.startMinimized())
728 application.showMinimized();
730 if (Global.wasWindowMaximized())
731 application.showMaximized();
737 splash.finish(application);
739 System.out.println("Goodbye.");
744 * Open the internal database, or create if not present
746 * @throws InitializationException when opening the database fails, e.g. because another process has it locked
748 private static DatabaseConnection setupDatabaseConnection() throws InitializationException {
749 ApplicationLogger logger = new ApplicationLogger("nevernote-database.log");
751 File f = Global.getFileManager().getDbDirFile(Global.databaseName + ".h2.db");
752 boolean dbExists = f.exists();
754 Global.setDatabaseUrl("");
756 if (Global.getDatabaseUrl().toUpperCase().indexOf("CIPHER=") > -1) {
757 boolean goodCheck = false;
759 DatabaseLoginDialog dialog = new DatabaseLoginDialog();
761 if (!dialog.okPressed())
763 Global.cipherPassword = dialog.getPassword();
764 goodCheck = databaseCheck(Global.getDatabaseUrl(), Global.getDatabaseUserid(),
765 Global.getDatabaseUserPassword(), Global.cipherPassword);
768 DatabaseConnection dbConn = new DatabaseConnection(logger,Global.getDatabaseUrl(), Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
772 // Encrypt the database upon shutdown
773 private void encryptOnShutdown() {
774 String dbPath= Global.getFileManager().getDbDirPath("");
775 String dbName = "NeverNote";
777 Statement st = conn.getConnection().createStatement();
778 st.execute("shutdown");
779 if (QMessageBox.question(this, "Are you sure",
780 "Are you sure you wish to encrypt the database?",
781 QMessageBox.StandardButton.Yes,
782 QMessageBox.StandardButton.No) == StandardButton.Yes.value()) {
783 ChangeFileEncryption.execute(dbPath, dbName, encryptCipher, null, Global.cipherPassword.toCharArray(), true);
784 Global.setDatabaseUrl(Global.getDatabaseUrl() + ";CIPHER="+encryptCipher);
785 QMessageBox.information(this, "Encryption Complete", "Encryption is complete");
787 } catch (SQLException e) {
792 // Decrypt the database upon shutdown
793 private void decryptOnShutdown() {
794 String dbPath= Global.getFileManager().getDbDirPath("");
795 String dbName = "NeverNote";
797 Statement st = conn.getConnection().createStatement();
798 st.execute("shutdown");
799 if (Global.getDatabaseUrl().toUpperCase().indexOf(";CIPHER=AES") > -1)
800 encryptCipher = "AES";
802 encryptCipher = "XTEA";
803 if (QMessageBox.question(this, tr("Confirmation"), tr("Are you sure",
804 "Are you sure you wish to decrypt the database?"),
805 QMessageBox.StandardButton.Yes,
806 QMessageBox.StandardButton.No) == StandardButton.Yes.value()) {
808 ChangeFileEncryption.execute(dbPath, dbName, encryptCipher, Global.cipherPassword.toCharArray(), null, true);
809 Global.setDatabaseUrl("");
810 QMessageBox.information(this, tr("Decryption Complete"), tr("Decryption is complete"));
812 } catch (SQLException e) {
817 * Encrypt/Decrypt the local database
819 public void doDatabaseEncrypt() {
820 // The database is not currently encrypted
821 if (Global.getDatabaseUrl().toUpperCase().indexOf("CIPHER=") == -1) {
822 if (QMessageBox.question(this, tr("Confirmation"), tr("Encrypting the database is used" +
823 "to enhance security and is performed\nupon shutdown, but please be aware that if"+
824 " you lose the password your\nis lost forever.\n\nIt is highly recommended you " +
825 "perform a backup and/or fully synchronize\n prior to executing this funtction.\n\n" +
826 "Do you wish to proceed?"),
827 QMessageBox.StandardButton.Yes,
828 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
831 DBEncryptDialog dialog = new DBEncryptDialog();
833 if (dialog.okPressed()) {
834 Global.cipherPassword = dialog.getPassword();
835 encryptOnShutdown = true;
836 encryptCipher = dialog.getEncryptionMethod();
839 DBEncryptDialog dialog = new DBEncryptDialog();
840 dialog.setWindowTitle("Database Decryption");
841 dialog.hideEncryption();
843 if (dialog.okPressed()) {
844 if (!dialog.getPassword().equals(Global.cipherPassword)) {
845 QMessageBox.critical(null, tr("Incorrect Password"), tr("Incorrect Password"));
848 decryptOnShutdown = true;
855 private static void initializeGlobalSettings(String[] args) throws InitializationException {
856 StartupConfig startupConfig = new StartupConfig();
858 for (String arg : args) {
859 String lower = arg.toLowerCase();
860 if (lower.startsWith("--name="))
861 startupConfig.setName(arg.substring(arg.indexOf('=') + 1));
862 if (lower.startsWith("--home="))
863 startupConfig.setHomeDirPath(arg.substring(arg.indexOf('=') + 1));
864 if (lower.startsWith("--disable-viewing"))
865 startupConfig.setDisableViewing(true);
867 Global.setup(startupConfig);
872 public void closeEvent(QCloseEvent event) {
873 if (Global.minimizeOnClose() && !closeAction && Global.showTrayIcon()) {
878 logger.log(logger.HIGH, "Entering NeverNote.closeEvent");
881 if (currentNote!= null & browserWindow!=null) {
882 if (!currentNote.getTitle().equals(browserWindow.getTitle()))
883 conn.getNoteTable().updateNoteTitle(currentNote.getGuid(), browserWindow.getTitle());
886 setMessage(tr("Beginning shutdown."));
888 // Close down external windows
889 Collection<ExternalBrowse> windows = externalWindows.values();
890 Iterator<ExternalBrowse> iterator = windows.iterator();
891 while (iterator.hasNext()) {
892 ExternalBrowse browser = iterator.next();
893 browser.windowClosing.disconnect();
898 externalFileEditedSaver();
899 if (Global.isConnected && Global.synchronizeOnClose()) {
900 setMessage(tr("Performing synchronization before closing."));
901 syncRunner.addWork("SYNC");
903 setMessage("Closing Program.");
904 threadMonitorTimer.stop();
906 syncRunner.addWork("STOP");
907 syncRunner.keepRunning = false;
908 thumbnailRunner.addWork("STOP");
909 syncRunner.keepRunning = false;
910 indexRunner.addWork("STOP");
911 syncRunner.keepRunning = false;
916 if (tempFiles != null)
919 browserWindow.noteSignal.tagsChanged.disconnect();
920 browserWindow.noteSignal.titleChanged.disconnect();
921 browserWindow.noteSignal.noteChanged.disconnect();
922 browserWindow.noteSignal.notebookChanged.disconnect();
923 browserWindow.noteSignal.createdDateChanged.disconnect();
924 browserWindow.noteSignal.alteredDateChanged.disconnect();
925 syncRunner.searchSignal.listChanged.disconnect();
926 syncRunner.tagSignal.listChanged.disconnect();
927 syncRunner.notebookSignal.listChanged.disconnect();
928 syncRunner.noteIndexSignal.listChanged.disconnect();
931 Global.saveWindowVisible("toolBar", toolBar.isVisible());
932 saveNoteColumnPositions();
933 saveNoteIndexWidth();
935 int width = notebookTree.columnWidth(0);
936 Global.setColumnWidth("notebookTreeName", width);
937 width = tagTree.columnWidth(0);
938 Global.setColumnWidth("tagTreeName", width);
940 Global.saveWindowMaximized(isMaximized());
941 Global.saveCurrentNoteGuid(currentNoteGuid);
943 int sortCol = noteTableView.proxyModel.sortColumn();
944 int sortOrder = noteTableView.proxyModel.sortOrder().value();
945 Global.setSortColumn(sortCol);
946 Global.setSortOrder(sortOrder);
950 Global.keepRunning = false;
952 logger.log(logger.MEDIUM, "Waiting for indexThread to stop");
953 indexRunner.thread().join(50);
954 logger.log(logger.MEDIUM, "Index thread has stopped");
955 } catch (InterruptedException e1) {
956 e1.printStackTrace();
958 if (!syncRunner.isIdle()) {
960 logger.log(logger.MEDIUM, "Waiting for syncThread to stop");
962 logger.log(logger.MEDIUM, "Sync thread has stopped");
963 } catch (InterruptedException e1) {
964 e1.printStackTrace();
968 if (encryptOnShutdown) {
971 if (decryptOnShutdown) {
974 logger.log(logger.HIGH, "Leaving NeverNote.closeEvent");
977 @SuppressWarnings("unused")
978 private void closeNeverNote() {
982 public void setMessage(String s) {
983 logger.log(logger.HIGH, "Entering NeverNote.setMessage");
984 logger.log(logger.HIGH, "Message: " +s);
985 statusBar.showMessage(s);
987 logger.log(logger.HIGH, "Leaving NeverNote.setMessage");
990 private void waitCursor(boolean wait) {
992 if (QApplication.overrideCursor() == null)
993 QApplication.setOverrideCursor(new QCursor(Qt.CursorShape.WaitCursor));
996 while (QApplication.overrideCursor() != null)
997 QApplication.restoreOverrideCursor();
1001 private void setupIndexListeners() {
1002 // indexRunner.noteSignal.noteIndexed.connect(this, "indexThreadComplete(String)");
1003 // indexRunner.resourceSignal.resourceIndexed.connect(this, "indexThreadComplete(String)");
1004 indexRunner.signal.indexStarted.connect(this, "indexStarted()");
1005 indexRunner.signal.indexFinished.connect(this, "indexComplete()");
1007 private void setupSyncSignalListeners() {
1008 syncRunner.tagSignal.listChanged.connect(this, "tagIndexUpdated()");
1009 syncRunner.searchSignal.listChanged.connect(this, "savedSearchIndexUpdated()");
1010 syncRunner.notebookSignal.listChanged.connect(this, "notebookIndexUpdated()");
1011 syncRunner.noteIndexSignal.listChanged.connect(this, "noteIndexUpdated(boolean)");
1012 syncRunner.noteSignal.quotaChanged.connect(this, "updateQuotaBar()");
1014 syncRunner.syncSignal.saveUploadAmount.connect(this,"saveUploadAmount(long)");
1015 syncRunner.syncSignal.saveUserInformation.connect(this,"saveUserInformation(User)");
1016 syncRunner.syncSignal.saveEvernoteUpdateCount.connect(this,"saveEvernoteUpdateCount(int)");
1018 syncRunner.noteSignal.guidChanged.connect(this, "noteGuidChanged(String, String)");
1019 syncRunner.noteSignal.noteChanged.connect(this, "invalidateNoteCache(String, String)");
1020 syncRunner.resourceSignal.resourceGuidChanged.connect(this, "noteResourceGuidChanged(String,String,String)");
1021 syncRunner.noteSignal.noteDownloaded.connect(listManager, "noteDownloaded(Note)");
1023 syncRunner.syncSignal.refreshLists.connect(this, "refreshLists()");
1026 private void setupBrowserSignalListeners() {
1027 setupBrowserWindowListeners(browserWindow, true);
1030 private void setupBrowserWindowListeners(BrowserWindow browser, boolean master) {
1031 browser.fileWatcher.fileChanged.connect(this, "externalFileEdited(String)");
1032 browser.noteSignal.tagsChanged.connect(this, "updateNoteTags(String, List)");
1033 browser.noteSignal.tagsChanged.connect(this, "updateListTags(String, List)");
1034 if (master) browser.noteSignal.noteChanged.connect(this, "setNoteDirty()");
1035 browser.noteSignal.titleChanged.connect(listManager, "updateNoteTitle(String, String)");
1036 browser.noteSignal.titleChanged.connect(this, "updateNoteTitle(String, String)");
1037 browser.noteSignal.notebookChanged.connect(this, "updateNoteNotebook(String, String)");
1038 browser.noteSignal.createdDateChanged.connect(listManager, "updateNoteCreatedDate(String, QDateTime)");
1039 browser.noteSignal.alteredDateChanged.connect(listManager, "updateNoteAlteredDate(String, QDateTime)");
1040 browser.noteSignal.subjectDateChanged.connect(listManager, "updateNoteSubjectDate(String, QDateTime)");
1041 browser.noteSignal.authorChanged.connect(listManager, "updateNoteAuthor(String, String)");
1042 browser.noteSignal.geoChanged.connect(listManager, "updateNoteGeoTag(String, Double,Double,Double)");
1043 browser.noteSignal.geoChanged.connect(this, "setNoteDirty()");
1044 browser.noteSignal.sourceUrlChanged.connect(listManager, "updateNoteSourceUrl(String, String)");
1045 if (master) browser.focusLost.connect(this, "saveNote()");
1046 browser.resourceSignal.contentChanged.connect(this, "externalFileEdited(String)");
1049 //***************************************************************
1050 //***************************************************************
1051 //* Settings and look & feel
1052 //***************************************************************
1053 //***************************************************************
1054 @SuppressWarnings("unused")
1055 private void settings() {
1056 logger.log(logger.HIGH, "Entering NeverNote.settings");
1057 saveNoteColumnPositions();
1058 saveNoteIndexWidth();
1060 ConfigDialog settings = new ConfigDialog(this);
1061 String dateFormat = Global.getDateFormat();
1062 String timeFormat = Global.getTimeFormat();
1064 indexTime = 1000*Global.getIndexThreadSleepInterval();
1065 indexTimer.start(indexTime); // reset indexing timer
1068 indexRunner.indexAttachmentsLocally = Global.indexAttachmentsLocally();
1069 if (Global.showTrayIcon())
1074 if (menuBar.showEditorBar.isChecked())
1075 showEditorButtons(browserWindow);
1077 // Reset the save timer
1078 if (Global.getAutoSaveInterval() > 0)
1079 saveTimer.setInterval(1000*60*Global.getAutoSaveInterval());
1083 // This is a hack to force a reload of the index in case the date or time changed.
1084 // if (!dateFormat.equals(Global.getDateFormat()) ||
1085 // !timeFormat.equals(Global.getTimeFormat())) {
1087 readOnlyCache.clear();
1088 inkNoteCache.clear();
1089 noteIndexUpdated(true);
1092 logger.log(logger.HIGH, "Leaving NeverNote.settings");
1094 // Restore things to the way they were
1095 private void restoreWindowState(boolean mainWindow) {
1096 // We need to name things or this doesn't work.
1097 setObjectName("NeverNote");
1098 mainLeftRightSplitter.setObjectName("mainLeftRightSplitter");
1099 browserIndexSplitter.setObjectName("browserIndexSplitter");
1100 leftSplitter1.setObjectName("leftSplitter1");
1102 // Restore the actual positions.
1104 restoreGeometry(Global.restoreGeometry(objectName()));
1105 mainLeftRightSplitter.restoreState(Global.restoreState(mainLeftRightSplitter.objectName()));
1106 browserIndexSplitter.restoreState(Global.restoreState(browserIndexSplitter.objectName()));
1107 leftSplitter1.restoreState(Global.restoreState(leftSplitter1.objectName()));
1110 // Save window positions for the next start
1111 private void saveWindowState() {
1112 Global.saveGeometry(objectName(), saveGeometry());
1113 Global.saveState(mainLeftRightSplitter.objectName(), mainLeftRightSplitter.saveState());
1114 Global.saveState(browserIndexSplitter.objectName(), browserIndexSplitter.saveState());
1115 Global.saveState(leftSplitter1.objectName(), leftSplitter1.saveState());
1117 // Load the style sheet
1118 private void loadStyleSheet() {
1119 String fileName = Global.getFileManager().getQssDirPath("default.qss");
1120 QFile file = new QFile(fileName);
1121 file.open(OpenModeFlag.ReadOnly);
1122 String styleSheet = file.readAll().toString();
1124 setStyleSheet(styleSheet);
1126 // Save column positions for the next time
1127 private void saveNoteColumnPositions() {
1128 int position = noteTableView.header.visualIndex(Global.noteTableCreationPosition);
1129 Global.setColumnPosition("noteTableCreationPosition", position);
1130 position = noteTableView.header.visualIndex(Global.noteTableTagPosition);
1131 Global.setColumnPosition("noteTableTagPosition", position);
1132 position = noteTableView.header.visualIndex(Global.noteTableNotebookPosition);
1133 Global.setColumnPosition("noteTableNotebookPosition", position);
1134 position = noteTableView.header.visualIndex(Global.noteTableChangedPosition);
1135 Global.setColumnPosition("noteTableChangedPosition", position);
1136 position = noteTableView.header.visualIndex(Global.noteTableAuthorPosition);
1137 Global.setColumnPosition("noteTableAuthorPosition", position);
1138 position = noteTableView.header.visualIndex(Global.noteTableSourceUrlPosition);
1139 Global.setColumnPosition("noteTableSourceUrlPosition", position);
1140 position = noteTableView.header.visualIndex(Global.noteTableSubjectDatePosition);
1141 Global.setColumnPosition("noteTableSubjectDatePosition", position);
1142 position = noteTableView.header.visualIndex(Global.noteTableTitlePosition);
1143 Global.setColumnPosition("noteTableTitlePosition", position);
1144 position = noteTableView.header.visualIndex(Global.noteTableSynchronizedPosition);
1145 Global.setColumnPosition("noteTableSynchronizedPosition", position);
1146 position = noteTableView.header.visualIndex(Global.noteTableGuidPosition);
1147 Global.setColumnPosition("noteTableGuidPosition", position);
1148 position = noteTableView.header.visualIndex(Global.noteTableThumbnailPosition);
1149 Global.setColumnPosition("noteTableThumbnailPosition", position);
1152 // Save column widths for the next time
1153 private void saveNoteIndexWidth() {
1155 width = noteTableView.getColumnWidth(Global.noteTableCreationPosition);
1156 Global.setColumnWidth("noteTableCreationPosition", width);
1157 width = noteTableView.getColumnWidth(Global.noteTableChangedPosition);
1158 Global.setColumnWidth("noteTableChangedPosition", width);
1159 width = noteTableView.getColumnWidth(Global.noteTableGuidPosition);
1160 Global.setColumnWidth("noteTableGuidPosition", width);
1161 width = noteTableView.getColumnWidth(Global.noteTableNotebookPosition);
1162 Global.setColumnWidth("noteTableNotebookPosition", width);
1163 width = noteTableView.getColumnWidth(Global.noteTableTagPosition);
1164 Global.setColumnWidth("noteTableTagPosition", width);
1165 width = noteTableView.getColumnWidth(Global.noteTableTitlePosition);
1166 Global.setColumnWidth("noteTableTitlePosition", width);
1167 width = noteTableView.getColumnWidth(Global.noteTableSourceUrlPosition);
1168 Global.setColumnWidth("noteTableSourceUrlPosition", width);
1169 width = noteTableView.getColumnWidth(Global.noteTableAuthorPosition);
1170 Global.setColumnWidth("noteTableAuthorPosition", width);
1171 width = noteTableView.getColumnWidth(Global.noteTableSubjectDatePosition);
1172 Global.setColumnWidth("noteTableSubjectDatePosition", width);
1173 width = noteTableView.getColumnWidth(Global.noteTableSynchronizedPosition);
1174 Global.setColumnWidth("noteTableSynchronizedPosition", width);
1175 width = noteTableView.getColumnWidth(Global.noteTableThumbnailPosition);
1176 Global.setColumnWidth("noteTableThumbnailPosition", width);
1177 width = noteTableView.getColumnWidth(Global.noteTableGuidPosition);
1178 Global.setColumnWidth("noteTableGuidPosition", width);
1182 //***************************************************************
1183 //***************************************************************
1184 //** These functions deal with Notebook menu items
1185 //***************************************************************
1186 //***************************************************************
1187 // Setup the tree containing the user's notebooks.
1188 private void initializeNotebookTree() {
1189 logger.log(logger.HIGH, "Entering NeverNote.initializeNotebookTree");
1190 notebookTree.itemClicked.connect(this, "notebookTreeSelection()");
1191 listManager.notebookSignal.refreshNotebookTreeCounts.connect(notebookTree, "updateCounts(List, List)");
1192 logger.log(logger.HIGH, "Leaving NeverNote.initializeNotebookTree");
1194 // Listener when a notebook is selected
1195 private void notebookTreeSelection() {
1196 logger.log(logger.HIGH, "Entering NeverNote.notebookTreeSelection");
1199 clearAttributeFilter();
1200 clearSavedSearchFilter();
1201 if (Global.mimicEvernoteInterface) {
1203 searchField.clear();
1205 menuBar.noteRestoreAction.setVisible(false);
1206 menuBar.notebookEditAction.setEnabled(true);
1207 menuBar.notebookDeleteAction.setEnabled(true);
1208 menuBar.notebookPublishAction.setEnabled(true);
1209 menuBar.notebookShareAction.setEnabled(true);
1210 menuBar.notebookIconAction.setEnabled(true);
1211 menuBar.notebookStackAction.setEnabled(true);
1212 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1213 QTreeWidgetItem currentSelection;
1214 selectedNotebookGUIDs.clear();
1215 if (!Global.mimicEvernoteInterface) {
1216 for (int i=0; i<selections.size(); i++) {
1217 currentSelection = selections.get(i);
1218 if (!currentSelection.text(2).equals("STACK"))
1219 selectedNotebookGUIDs.add(currentSelection.text(2));
1221 String stackName = currentSelection.text(0);
1222 for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1223 Notebook book = listManager.getNotebookIndex().get(j);
1224 if (book.getStack()!=null && book.getStack().equalsIgnoreCase(stackName))
1225 selectedNotebookGUIDs.add(book.getGuid());
1231 // There is the potential for no notebooks to be selected if this
1232 // happens then we make it look like all notebooks were selecetd.
1233 // If that happens, just select the "all notebooks"
1234 selections = notebookTree.selectedItems();
1235 if (selections.size()==0) {
1236 selectedNotebookGUIDs.clear();
1237 menuBar.notebookEditAction.setEnabled(false);
1238 menuBar.notebookDeleteAction.setEnabled(false);
1239 menuBar.notebookIconAction.setEnabled(false);
1240 menuBar.notebookStackAction.setEnabled(false);
1242 if (selectedNotebookGUIDs.size() == 1 && selectedNotebookGUIDs.get(0).equals(previousSelectedNotebook)) {
1243 previousSelectedNotebook = selectedNotebookGUIDs.get(0);
1244 previousSelectedNotebook = "";
1245 notebookTree.clearSelection();
1246 notebookTreeSelection();
1249 if (selectedNotebookGUIDs.size() == 1)
1250 previousSelectedNotebook = selectedNotebookGUIDs.get(0);
1251 if (selectedNotebookGUIDs.size() > 1)
1252 previousSelectedNotebook = "";
1255 String stackName = "";
1256 if (selections.size() > 0) {
1257 guid = (selections.get(0).text(2));
1258 stackName = selections.get(0).text(0);
1260 if (!guid.equals("") && !guid.equals("STACK")) {
1261 selectedNotebookGUIDs.add(guid);
1262 menuBar.notebookIconAction.setEnabled(true);
1265 menuBar.notebookIconAction.setEnabled(true);
1266 for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1267 Notebook book = listManager.getNotebookIndex().get(j);
1268 if (book.getStack() != null && book.getStack().equalsIgnoreCase(stackName))
1269 selectedNotebookGUIDs.add(book.getGuid());
1273 listManager.setSelectedNotebooks(selectedNotebookGUIDs);
1274 listManager.loadNotesIndex();
1275 noteIndexUpdated(false);
1276 logger.log(logger.HIGH, "Leaving NeverNote.notebookTreeSelection");
1279 private void clearNotebookFilter() {
1280 notebookTree.blockSignals(true);
1281 notebookTree.clearSelection();
1282 menuBar.noteRestoreAction.setVisible(false);
1283 menuBar.notebookEditAction.setEnabled(false);
1284 menuBar.notebookDeleteAction.setEnabled(false);
1285 selectedNotebookGUIDs.clear();
1286 listManager.setSelectedNotebooks(selectedNotebookGUIDs);
1287 notebookTree.blockSignals(false);
1289 // Triggered when the notebook DB has been updated
1290 private void notebookIndexUpdated() {
1291 logger.log(logger.HIGH, "Entering NeverNote.notebookIndexUpdated");
1293 // Get the possible icons
1294 HashMap<String, QIcon> icons = conn.getNotebookTable().getAllIcons();
1295 notebookTree.setIcons(icons);
1297 if (selectedNotebookGUIDs == null)
1298 selectedNotebookGUIDs = new ArrayList<String>();
1299 List<Notebook> books = conn.getNotebookTable().getAll();
1300 for (int i=books.size()-1; i>=0; i--) {
1301 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
1302 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(books.get(i).getGuid())) {
1304 j=listManager.getArchiveNotebookIndex().size();
1310 listManager.countNotebookResults(listManager.getNoteIndex());
1311 notebookTree.blockSignals(true);
1312 notebookTree.load(books, listManager.getLocalNotebooks());
1313 for (int i=selectedNotebookGUIDs.size()-1; i>=0; i--) {
1314 boolean found = notebookTree.selectGuid(selectedNotebookGUIDs.get(i));
1316 selectedNotebookGUIDs.remove(i);
1318 notebookTree.blockSignals(false);
1320 logger.log(logger.HIGH, "Leaving NeverNote.notebookIndexUpdated");
1322 // Show/Hide note information
1323 private void toggleNotebookWindow() {
1324 logger.log(logger.HIGH, "Entering NeverNote.toggleNotebookWindow");
1325 if (notebookTree.isVisible())
1326 notebookTree.hide();
1328 notebookTree.show();
1329 menuBar.hideNotebooks.setChecked(notebookTree.isVisible());
1330 Global.saveWindowVisible("notebookTree", notebookTree.isVisible());
1331 logger.log(logger.HIGH, "Leaving NeverNote.toggleNotebookWindow");
1333 // Add a new notebook
1334 @SuppressWarnings("unused")
1335 private void addNotebook() {
1336 logger.log(logger.HIGH, "Inside NeverNote.addNotebook");
1337 NotebookEdit edit = new NotebookEdit();
1338 edit.setNotebooks(listManager.getNotebookIndex());
1341 if (!edit.okPressed())
1344 Calendar currentTime = new GregorianCalendar();
1345 Long l = new Long(currentTime.getTimeInMillis());
1346 String randint = new String(Long.toString(l));
1348 Notebook newBook = new Notebook();
1349 newBook.setUpdateSequenceNum(0);
1350 newBook.setGuid(randint);
1351 newBook.setName(edit.getNotebook());
1352 newBook.setServiceCreated(new Date().getTime());
1353 newBook.setServiceUpdated(new Date().getTime());
1354 newBook.setDefaultNotebook(false);
1355 newBook.setPublished(false);
1357 listManager.getNotebookIndex().add(newBook);
1359 listManager.getLocalNotebooks().add(newBook.getGuid());
1360 conn.getNotebookTable().addNotebook(newBook, true, edit.isLocal());
1361 notebookIndexUpdated();
1362 listManager.countNotebookResults(listManager.getNoteIndex());
1363 // notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
1364 logger.log(logger.HIGH, "Leaving NeverNote.addNotebook");
1366 // Edit an existing notebook
1367 @SuppressWarnings("unused")
1368 private void stackNotebook() {
1369 logger.log(logger.HIGH, "Entering NeverNote.stackNotebook");
1370 StackNotebook edit = new StackNotebook();
1372 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1373 QTreeWidgetItem currentSelection;
1374 for (int i=0; i<selections.size(); i++) {
1375 currentSelection = selections.get(0);
1376 String guid = currentSelection.text(2);
1377 if (guid.equalsIgnoreCase("")) {
1378 QMessageBox.critical(this, tr("Unable To Stack") ,tr("You can't stack the \"All Notebooks\" item."));
1381 if (guid.equalsIgnoreCase("STACK")) {
1382 QMessageBox.critical(this, tr("Unable To Stack") ,tr("You can't stack a stack."));
1387 edit.setStackNames(conn.getNotebookTable().getAllStackNames());
1392 if (!edit.okPressed())
1395 String stack = edit.getStackName();
1397 for (int i=0; i<selections.size(); i++) {
1398 currentSelection = selections.get(i);
1399 String guid = currentSelection.text(2);
1400 listManager.updateNotebookStack(guid, stack);
1402 notebookIndexUpdated();
1403 logger.log(logger.HIGH, "Leaving NeverNote.stackNotebook");
1405 // Edit an existing notebook
1406 @SuppressWarnings("unused")
1407 private void editNotebook() {
1408 logger.log(logger.HIGH, "Entering NeverNote.editNotebook");
1409 NotebookEdit edit = new NotebookEdit();
1411 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1412 QTreeWidgetItem currentSelection;
1413 currentSelection = selections.get(0);
1414 edit.setNotebook(currentSelection.text(0));
1416 String guid = currentSelection.text(2);
1417 if (!guid.equalsIgnoreCase("STACK")) {
1418 edit.setTitle(tr("Edit Notebook"));
1419 edit.setNotebooks(listManager.getNotebookIndex());
1420 edit.setLocalCheckboxEnabled(false);
1421 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1422 if (listManager.getNotebookIndex().get(i).getGuid().equals(guid)) {
1423 edit.setDefaultNotebook(listManager.getNotebookIndex().get(i).isDefaultNotebook());
1424 i=listManager.getNotebookIndex().size();
1428 edit.setTitle(tr("Edit Stack"));
1429 edit.setStacks(conn.getNotebookTable().getAllStackNames());
1430 edit.hideLocalCheckbox();
1431 edit.hideDefaultCheckbox();
1436 if (!edit.okPressed())
1440 if (guid.equalsIgnoreCase("STACK")) {
1441 conn.getNotebookTable().renameStacks(currentSelection.text(0), edit.getNotebook());
1442 for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1443 if (listManager.getNotebookIndex().get(j).getStack().equalsIgnoreCase(currentSelection.text(0)))
1444 listManager.getNotebookIndex().get(j).setStack(edit.getNotebook());
1446 conn.getNotebookTable().renameStacks(currentSelection.text(0), edit.getNotebook());
1447 currentSelection.setText(0, edit.getNotebook());
1451 updateListNotebookName(currentSelection.text(0), edit.getNotebook());
1452 currentSelection.setText(0, edit.getNotebook());
1454 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1455 if (listManager.getNotebookIndex().get(i).getGuid().equals(guid)) {
1456 listManager.getNotebookIndex().get(i).setName(edit.getNotebook());
1457 if (!listManager.getNotebookIndex().get(i).isDefaultNotebook() && edit.isDefaultNotebook()) {
1458 for (int j=0; j<listManager.getNotebookIndex().size(); j++)
1459 listManager.getNotebookIndex().get(j).setDefaultNotebook(false);
1460 listManager.getNotebookIndex().get(i).setDefaultNotebook(true);
1461 conn.getNotebookTable().setDefaultNotebook(listManager.getNotebookIndex().get(i).getGuid());
1463 conn.getNotebookTable().updateNotebook(listManager.getNotebookIndex().get(i), true);
1464 if (conn.getNotebookTable().isLinked(listManager.getNotebookIndex().get(i).getGuid())) {
1465 LinkedNotebook linkedNotebook = conn.getLinkedNotebookTable().getByNotebookGuid(listManager.getNotebookIndex().get(i).getGuid());
1466 linkedNotebook.setShareName(edit.getNotebook());
1467 conn.getLinkedNotebookTable().updateNotebook(linkedNotebook, true);
1469 i=listManager.getNotebookIndex().size();
1473 // Build a list of non-closed notebooks
1474 List<Notebook> nbooks = new ArrayList<Notebook>();
1475 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1476 boolean found=false;
1477 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
1478 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid()))
1482 nbooks.add(listManager.getNotebookIndex().get(i));
1485 browserWindow.setNotebookList(nbooks);
1486 logger.log(logger.HIGH, "Leaving NeverNote.editNotebook");
1488 // Publish a notebook
1489 @SuppressWarnings("unused")
1490 private void publishNotebook() {
1491 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1492 QTreeWidgetItem currentSelection;
1493 currentSelection = selections.get(0);
1494 String guid = currentSelection.text(2);
1496 if (guid.equalsIgnoreCase("STACK") || guid.equalsIgnoreCase(""))
1501 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1502 if (guid.equals(listManager.getNotebookIndex().get(i).getGuid())) {
1503 n = listManager.getNotebookIndex().get(i);
1505 i = listManager.getNotebookIndex().size();
1511 PublishNotebook publish = new PublishNotebook(Global.username, Global.getServer(), n);
1514 if (!publish.okClicked())
1517 Publishing p = publish.getPublishing();
1518 boolean isPublished = !publish.isStopPressed();
1519 conn.getNotebookTable().setPublishing(n.getGuid(), isPublished, p);
1520 n.setPublished(isPublished);
1522 listManager.getNotebookIndex().set(position, n);
1523 notebookIndexUpdated();
1525 // Publish a notebook
1526 @SuppressWarnings("unused")
1527 private void shareNotebook() {
1528 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1529 QTreeWidgetItem currentSelection;
1530 currentSelection = selections.get(0);
1531 String guid = currentSelection.text(2);
1533 if (guid.equalsIgnoreCase("STACK") || guid.equalsIgnoreCase(""))
1537 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1538 if (guid.equals(listManager.getNotebookIndex().get(i).getGuid())) {
1539 n = listManager.getNotebookIndex().get(i);
1540 i = listManager.getNotebookIndex().size();
1544 String authToken = null;
1545 if (syncRunner.isConnected)
1546 authToken = syncRunner.authToken;
1547 ShareNotebook share = new ShareNotebook(n.getName(), conn, n, syncRunner);
1552 // Delete an existing notebook
1553 @SuppressWarnings("unused")
1554 private void deleteNotebook() {
1555 logger.log(logger.HIGH, "Entering NeverNote.deleteNotebook");
1556 boolean stacksFound = false;
1557 boolean notebooksFound = false;
1558 boolean assigned = false;
1559 // Check if any notes have this notebook
1560 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1561 for (int i=0; i<selections.size(); i++) {
1562 QTreeWidgetItem currentSelection;
1563 currentSelection = selections.get(i);
1564 String guid = currentSelection.text(2);
1565 if (!guid.equalsIgnoreCase("STACK")) {
1566 notebooksFound = true;
1567 for (int j=0; j<listManager.getNoteIndex().size(); j++) {
1568 String noteGuid = listManager.getNoteIndex().get(j).getNotebookGuid();
1569 if (noteGuid.equals(guid)) {
1571 j=listManager.getNoteIndex().size();
1572 i=selections.size();
1580 QMessageBox.information(this, tr("Unable to Delete"), tr("Some of the selected notebook(s) contain notes.\n"+
1581 "Please delete the notes or move them to another notebook before deleting any notebooks."));
1585 if (conn.getNotebookTable().getAll().size() == 1) {
1586 QMessageBox.information(this, tr("Unable to Delete"), tr("You must have at least one notebook."));
1590 // If all notebooks are clear, verify the delete
1591 String msg1 = new String(tr("Delete selected notebooks?"));
1592 String msg2 = new String(tr("Remove selected stacks (notebooks will not be deleted)?"));
1593 String msg3 = new String(tr("Delete selected notebooks & remove stacks? Notebooks under the stacks are" +
1594 " not deleted unless selected?"));
1596 if (stacksFound && notebooksFound)
1598 if (!stacksFound && notebooksFound)
1600 if (stacksFound && !notebooksFound)
1602 if (QMessageBox.question(this, tr("Confirmation"), msg,
1603 QMessageBox.StandardButton.Yes,
1604 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
1608 // If confirmed, delete the notebook
1609 for (int i=selections.size()-1; i>=0; i--) {
1610 QTreeWidgetItem currentSelection;
1611 currentSelection = selections.get(i);
1612 String guid = currentSelection.text(2);
1613 if (currentSelection.text(2).equalsIgnoreCase("STACK")) {
1614 conn.getNotebookTable().renameStacks(currentSelection.text(0), "");
1615 listManager.renameStack(currentSelection.text(0), "");
1617 conn.getNotebookTable().expungeNotebook(guid, true);
1618 listManager.deleteNotebook(guid);
1622 notebookTreeSelection();
1623 notebookTree.load(listManager.getNotebookIndex(), listManager.getLocalNotebooks());
1624 listManager.countNotebookResults(listManager.getNoteIndex());
1625 logger.log(logger.HIGH, "Entering NeverNote.deleteNotebook");
1627 // A note's notebook has been updated
1628 @SuppressWarnings("unused")
1629 private void updateNoteNotebook(String guid, String notebookGuid) {
1631 // Update the list manager
1632 listManager.updateNoteNotebook(guid, notebookGuid);
1633 listManager.countNotebookResults(listManager.getNoteIndex());
1634 // notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
1636 // Find the name of the notebook
1637 String notebookName = null;
1638 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1639 if (listManager.getNotebookIndex().get(i).getGuid().equals(notebookGuid)) {
1640 notebookName = listManager.getNotebookIndex().get(i).getName();
1645 // If we found the name, update the browser window
1646 if (notebookName != null) {
1647 updateListNoteNotebook(guid, notebookName);
1648 if (guid.equals(currentNoteGuid)) {
1649 int pos = browserWindow.notebookBox.findText(notebookName);
1651 browserWindow.notebookBox.setCurrentIndex(pos);
1655 // If we're dealing with the current note, then we need to be sure and update the notebook there
1656 if (guid.equals(currentNoteGuid)) {
1657 if (currentNote != null) {
1658 currentNote.setNotebookGuid(notebookGuid);
1662 // Open/close notebooks
1663 @SuppressWarnings("unused")
1664 private void closeNotebooks() {
1665 NotebookArchive na = new NotebookArchive(listManager.getNotebookIndex(), listManager.getArchiveNotebookIndex());
1667 if (!na.okClicked())
1671 listManager.getArchiveNotebookIndex().clear();
1673 for (int i=na.getClosedBookList().count()-1; i>=0; i--) {
1674 String text = na.getClosedBookList().takeItem(i).text();
1675 for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1676 if (listManager.getNotebookIndex().get(j).getName().equalsIgnoreCase(text)) {
1677 Notebook n = listManager.getNotebookIndex().get(j);
1678 conn.getNotebookTable().setArchived(n.getGuid(),true);
1679 listManager.getArchiveNotebookIndex().add(n);
1680 j=listManager.getNotebookIndex().size();
1685 for (int i=na.getOpenBookList().count()-1; i>=0; i--) {
1686 String text = na.getOpenBookList().takeItem(i).text();
1687 for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1688 if (listManager.getNotebookIndex().get(j).getName().equalsIgnoreCase(text)) {
1689 Notebook n = listManager.getNotebookIndex().get(j);
1690 conn.getNotebookTable().setArchived(n.getGuid(),false);
1691 j=listManager.getNotebookIndex().size();
1695 notebookTreeSelection();
1696 listManager.loadNotesIndex();
1697 notebookIndexUpdated();
1698 noteIndexUpdated(false);
1699 reloadTagTree(true);
1700 // noteIndexUpdated(false);
1702 // Build a list of non-closed notebooks
1703 List<Notebook> nbooks = new ArrayList<Notebook>();
1704 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1705 boolean found=false;
1706 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
1707 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid()))
1711 nbooks.add(listManager.getNotebookIndex().get(i));
1714 browserWindow.setNotebookList(nbooks);
1716 // Change the notebook's icon
1717 @SuppressWarnings("unused")
1718 private void setNotebookIcon() {
1719 boolean stackSelected = false;
1720 boolean allNotebookSelected = false;
1722 QTreeWidgetItem currentSelection;
1723 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1724 if (selections.size() == 0)
1727 currentSelection = selections.get(0);
1728 String guid = currentSelection.text(2);
1729 if (guid.equalsIgnoreCase(""))
1730 allNotebookSelected = true;
1731 if (guid.equalsIgnoreCase("STACK"))
1732 stackSelected = true;
1734 QIcon currentIcon = currentSelection.icon(0);
1738 if (!stackSelected && !allNotebookSelected) {
1739 icon = conn.getNotebookTable().getIcon(guid);
1741 dialog = new SetIcon(currentIcon);
1742 dialog.setUseDefaultIcon(true);
1744 dialog = new SetIcon(icon);
1745 dialog.setUseDefaultIcon(false);
1748 if (stackSelected) {
1749 icon = conn.getSystemIconTable().getIcon(currentSelection.text(0), "STACK");
1751 icon = conn.getSystemIconTable().getIcon(currentSelection.text(0), "ALLNOTEBOOK");
1754 dialog = new SetIcon(currentIcon);
1755 dialog.setUseDefaultIcon(true);
1757 dialog = new SetIcon(icon);
1758 dialog.setUseDefaultIcon(false);
1762 if (dialog.okPressed()) {
1763 QIcon newIcon = dialog.getIcon();
1764 if (stackSelected) {
1765 conn.getSystemIconTable().setIcon(currentSelection.text(0), "STACK", newIcon, dialog.getFileType());
1766 if (newIcon == null) {
1767 newIcon = new QIcon(iconPath+"books2.png");
1769 currentSelection.setIcon(0,newIcon);
1772 if (allNotebookSelected) {
1773 conn.getSystemIconTable().setIcon(currentSelection.text(0), "ALLNOTEBOOK", newIcon, dialog.getFileType());
1774 if (newIcon == null) {
1775 newIcon = new QIcon(iconPath+"notebook-green.png");
1777 currentSelection.setIcon(0,newIcon);
1780 conn.getNotebookTable().setIcon(guid, newIcon, dialog.getFileType());
1781 if (newIcon == null) {
1782 boolean isPublished = false;;
1783 boolean found = false;
1784 for (int i=0; i<listManager.getNotebookIndex().size() && !found; i++) {
1785 if (listManager.getNotebookIndex().get(i).getGuid().equals(guid)) {
1786 isPublished = listManager.getNotebookIndex().get(i).isPublished();
1790 newIcon = notebookTree.findDefaultIcon(guid, currentSelection.text(1), listManager.getLocalNotebooks(), isPublished);
1792 currentSelection.setIcon(0, newIcon);
1798 //***************************************************************
1799 //***************************************************************
1800 //** These functions deal with Tag menu items
1801 //***************************************************************
1802 //***************************************************************
1803 // Add a new notebook
1804 @SuppressWarnings("unused")
1805 private void addTag() {
1806 logger.log(logger.HIGH, "Inside NeverNote.addTag");
1807 TagEdit edit = new TagEdit();
1808 edit.setTagList(listManager.getTagIndex());
1811 if (!edit.okPressed())
1814 Calendar currentTime = new GregorianCalendar();
1815 Long l = new Long(currentTime.getTimeInMillis());
1816 String randint = new String(Long.toString(l));
1818 Tag newTag = new Tag();
1819 newTag.setUpdateSequenceNum(0);
1820 newTag.setGuid(randint);
1821 newTag.setName(edit.getTag());
1822 conn.getTagTable().addTag(newTag, true);
1823 listManager.getTagIndex().add(newTag);
1824 reloadTagTree(true);
1826 logger.log(logger.HIGH, "Leaving NeverNote.addTag");
1828 @SuppressWarnings("unused")
1829 private void reloadTagTree() {
1830 reloadTagTree(false);
1832 private void reloadTagTree(boolean reload) {
1833 logger.log(logger.HIGH, "Entering NeverNote.reloadTagTree");
1834 tagIndexUpdated(reload);
1835 boolean filter = false;
1836 listManager.countTagResults(listManager.getNoteIndex());
1837 if (notebookTree.selectedItems().size() > 0
1838 && !notebookTree.selectedItems().get(0).text(0).equalsIgnoreCase("All Notebooks"))
1840 if (tagTree.selectedItems().size() > 0)
1842 tagTree.showAllTags(!filter);
1843 logger.log(logger.HIGH, "Leaving NeverNote.reloadTagTree");
1845 // Edit an existing tag
1846 @SuppressWarnings("unused")
1847 private void editTag() {
1848 logger.log(logger.HIGH, "Entering NeverNote.editTag");
1849 TagEdit edit = new TagEdit();
1850 edit.setTitle("Edit Tag");
1851 List<QTreeWidgetItem> selections = tagTree.selectedItems();
1852 QTreeWidgetItem currentSelection;
1853 currentSelection = selections.get(0);
1854 edit.setTag(currentSelection.text(0));
1855 edit.setTagList(listManager.getTagIndex());
1858 if (!edit.okPressed())
1861 String guid = currentSelection.text(2);
1862 currentSelection.setText(0,edit.getTag());
1864 for (int i=0; i<listManager.getTagIndex().size(); i++) {
1865 if (listManager.getTagIndex().get(i).getGuid().equals(guid)) {
1866 listManager.getTagIndex().get(i).setName(edit.getTag());
1867 conn.getTagTable().updateTag(listManager.getTagIndex().get(i), true);
1868 updateListTagName(guid);
1869 if (currentNote != null && currentNote.getTagGuids().contains(guid))
1870 browserWindow.setTag(getTagNamesForNote(currentNote));
1871 logger.log(logger.HIGH, "Leaving NeverNote.editTag");
1875 browserWindow.setTag(getTagNamesForNote(currentNote));
1876 logger.log(logger.HIGH, "Leaving NeverNote.editTag...");
1878 // Delete an existing tag
1879 @SuppressWarnings("unused")
1880 private void deleteTag() {
1881 logger.log(logger.HIGH, "Entering NeverNote.deleteTag");
1883 if (QMessageBox.question(this, tr("Confirmation"), tr("Delete the selected tags?"),
1884 QMessageBox.StandardButton.Yes,
1885 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
1889 List<QTreeWidgetItem> selections = tagTree.selectedItems();
1890 for (int i=selections.size()-1; i>=0; i--) {
1891 QTreeWidgetItem currentSelection;
1892 currentSelection = selections.get(i);
1893 removeTagItem(currentSelection.text(2));
1895 tagIndexUpdated(true);
1897 listManager.countTagResults(listManager.getNoteIndex());
1898 // tagTree.updateCounts(listManager.getTagCounter());
1899 logger.log(logger.HIGH, "Leaving NeverNote.deleteTag");
1901 // Remove a tag tree item. Go recursively down & remove the children too
1902 private void removeTagItem(String guid) {
1903 for (int j=listManager.getTagIndex().size()-1; j>=0; j--) {
1904 String parent = listManager.getTagIndex().get(j).getParentGuid();
1905 if (parent != null && parent.equals(guid)) {
1906 //Remove this tag's children
1907 removeTagItem(listManager.getTagIndex().get(j).getGuid());
1910 //Now, remove this tag
1911 removeListTagName(guid);
1912 conn.getTagTable().expungeTag(guid, true);
1913 for (int a=0; a<listManager.getTagIndex().size(); a++) {
1914 if (listManager.getTagIndex().get(a).getGuid().equals(guid)) {
1915 listManager.getTagIndex().remove(a);
1920 // Setup the tree containing the user's tags
1921 private void initializeTagTree() {
1922 logger.log(logger.HIGH, "Entering NeverNote.initializeTagTree");
1923 // tagTree.itemSelectionChanged.connect(this, "tagTreeSelection()");
1924 tagTree.itemClicked.connect(this, "tagTreeSelection()");
1925 listManager.tagSignal.refreshTagTreeCounts.connect(tagTree, "updateCounts(List)");
1926 logger.log(logger.HIGH, "Leaving NeverNote.initializeTagTree");
1928 // Listener when a tag is selected
1929 private void tagTreeSelection() {
1930 logger.log(logger.HIGH, "Entering NeverNote.tagTreeSelection");
1933 clearAttributeFilter();
1934 clearSavedSearchFilter();
1936 menuBar.noteRestoreAction.setVisible(false);
1938 List<QTreeWidgetItem> selections = tagTree.selectedItems();
1939 QTreeWidgetItem currentSelection;
1940 selectedTagGUIDs.clear();
1941 for (int i=0; i<selections.size(); i++) {
1942 currentSelection = selections.get(i);
1943 selectedTagGUIDs.add(currentSelection.text(2));
1945 if (selections.size() > 0) {
1946 menuBar.tagEditAction.setEnabled(true);
1947 menuBar.tagDeleteAction.setEnabled(true);
1948 menuBar.tagIconAction.setEnabled(true);
1951 menuBar.tagEditAction.setEnabled(false);
1952 menuBar.tagDeleteAction.setEnabled(false);
1953 menuBar.tagIconAction.setEnabled(true);
1955 if (selectedTagGUIDs.size() == 1 && selectedTagGUIDs.get(0).equals(previousSelectedTag)) {
1956 previousSelectedTag = selectedTagGUIDs.get(0);
1957 previousSelectedTag = "";
1958 tagTree.clearSelection();
1962 if (selectedTagGUIDs.size() == 1)
1963 previousSelectedTag = selectedTagGUIDs.get(0);
1964 if (selectedTagGUIDs.size() > 1)
1965 previousSelectedTag = "";
1966 listManager.setSelectedTags(selectedTagGUIDs);
1967 listManager.loadNotesIndex();
1968 noteIndexUpdated(false);
1969 logger.log(logger.HIGH, "Leaving NeverNote.tagTreeSelection");
1971 // trigger the tag index to be refreshed
1972 @SuppressWarnings("unused")
1973 private void tagIndexUpdated() {
1974 tagIndexUpdated(true);
1976 private void tagIndexUpdated(boolean reload) {
1977 logger.log(logger.HIGH, "Entering NeverNote.tagIndexUpdated");
1978 if (selectedTagGUIDs == null)
1979 selectedTagGUIDs = new ArrayList<String>();
1981 listManager.reloadTagIndex();
1983 tagTree.blockSignals(true);
1985 tagTree.setIcons(conn.getTagTable().getAllIcons());
1986 tagTree.load(listManager.getTagIndex());
1988 for (int i=selectedTagGUIDs.size()-1; i>=0; i--) {
1989 boolean found = tagTree.selectGuid(selectedTagGUIDs.get(i));
1991 selectedTagGUIDs.remove(i);
1993 tagTree.blockSignals(false);
1995 browserWindow.setTag(getTagNamesForNote(currentNote));
1996 logger.log(logger.HIGH, "Leaving NeverNote.tagIndexUpdated");
1998 // Show/Hide note information
1999 private void toggleTagWindow() {
2000 logger.log(logger.HIGH, "Entering NeverNote.toggleTagWindow");
2001 if (tagTree.isVisible())
2005 menuBar.hideTags.setChecked(tagTree.isVisible());
2006 Global.saveWindowVisible("tagTree", tagTree.isVisible());
2007 logger.log(logger.HIGH, "Leaving NeverNote.toggleTagWindow");
2009 // A note's tags have been updated
2010 @SuppressWarnings("unused")
2011 private void updateNoteTags(String guid, List<String> tags) {
2012 // Save any new tags. We'll need them later.
2013 List<String> newTags = new ArrayList<String>();
2014 for (int i=0; i<tags.size(); i++) {
2015 if (conn.getTagTable().findTagByName(tags.get(i))==null)
2016 newTags.add(tags.get(i));
2019 listManager.saveNoteTags(guid, tags);
2020 listManager.countTagResults(listManager.getNoteIndex());
2021 StringBuffer names = new StringBuffer("");
2022 for (int i=0; i<tags.size(); i++) {
2023 names = names.append(tags.get(i));
2024 if (i<tags.size()-1) {
2025 names.append(Global.tagDelimeter + " ");
2028 browserWindow.setTag(names.toString());
2031 // Now, we need to add any new tags to the tag tree
2032 for (int i=0; i<newTags.size(); i++)
2033 tagTree.insertTag(newTags.get(i), conn.getTagTable().findTagByName(newTags.get(i)));
2035 // Get a string containing all tag names for a note
2036 private String getTagNamesForNote(Note n) {
2037 logger.log(logger.HIGH, "Entering NeverNote.getTagNamesForNote");
2038 if (n==null || n.getGuid() == null || n.getGuid().equals(""))
2040 StringBuffer buffer = new StringBuffer(100);
2041 Vector<String> v = new Vector<String>();
2042 List<String> guids = n.getTagGuids();
2047 for (int i=0; i<guids.size(); i++) {
2048 v.add(listManager.getTagNameByGuid(guids.get(i)));
2050 Comparator<String> comparator = Collections.reverseOrder();
2051 Collections.sort(v,comparator);
2052 Collections.reverse(v);
2054 for (int i = 0; i<v.size(); i++) {
2056 buffer.append(", ");
2057 buffer.append(v.get(i));
2060 logger.log(logger.HIGH, "Leaving NeverNote.getTagNamesForNote");
2061 return buffer.toString();
2063 // Tags were added via dropping notes from the note list
2064 @SuppressWarnings("unused")
2065 private void tagsAdded(String noteGuid, String tagGuid) {
2066 String tagName = null;
2067 for (int i=0; i<listManager.getTagIndex().size(); i++) {
2068 if (listManager.getTagIndex().get(i).getGuid().equals(tagGuid)) {
2069 tagName = listManager.getTagIndex().get(i).getName();
2070 i=listManager.getTagIndex().size();
2073 if (tagName == null)
2076 for (int i=0; i<listManager.getMasterNoteIndex().size(); i++) {
2077 if (listManager.getMasterNoteIndex().get(i).getGuid().equals(noteGuid)) {
2078 List<String> tagNames = new ArrayList<String>();
2079 tagNames.add(new String(tagName));
2080 Note n = listManager.getMasterNoteIndex().get(i);
2081 for (int j=0; j<n.getTagNames().size(); j++) {
2082 tagNames.add(new String(n.getTagNames().get(j)));
2084 listManager.getNoteTableModel().updateNoteTags(noteGuid, n.getTagGuids(), tagNames);
2085 if (n.getGuid().equals(currentNoteGuid)) {
2086 Collections.sort(tagNames);
2087 String display = "";
2088 for (int j=0; j<tagNames.size(); j++) {
2089 display = display+tagNames.get(j);
2090 if (j+2<tagNames.size())
2091 display = display+Global.tagDelimeter+" ";
2093 browserWindow.setTag(display);
2095 i=listManager.getMasterNoteIndex().size();
2100 listManager.getNoteTableModel().updateNoteSyncStatus(noteGuid, false);
2102 private void clearTagFilter() {
2103 tagTree.blockSignals(true);
2104 tagTree.clearSelection();
2105 menuBar.noteRestoreAction.setVisible(false);
2106 menuBar.tagEditAction.setEnabled(false);
2107 menuBar.tagDeleteAction.setEnabled(false);
2108 menuBar.tagIconAction.setEnabled(false);
2109 selectedTagGUIDs.clear();
2110 listManager.setSelectedTags(selectedTagGUIDs);
2111 tagTree.blockSignals(false);
2113 // Change the icon for a tag
2114 @SuppressWarnings("unused")
2115 private void setTagIcon() {
2116 QTreeWidgetItem currentSelection;
2117 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2118 if (selections.size() == 0)
2121 currentSelection = selections.get(0);
2122 String guid = currentSelection.text(2);
2124 QIcon currentIcon = currentSelection.icon(0);
2125 QIcon icon = conn.getTagTable().getIcon(guid);
2128 dialog = new SetIcon(currentIcon);
2129 dialog.setUseDefaultIcon(true);
2131 dialog = new SetIcon(icon);
2132 dialog.setUseDefaultIcon(false);
2135 if (dialog.okPressed()) {
2136 QIcon newIcon = dialog.getIcon();
2137 conn.getTagTable().setIcon(guid, newIcon, dialog.getFileType());
2138 if (newIcon == null)
2139 newIcon = new QIcon(iconPath+"tag.png");
2140 currentSelection.setIcon(0, newIcon);
2146 //***************************************************************
2147 //***************************************************************
2148 //** These functions deal with Saved Search menu items
2149 //***************************************************************
2150 //***************************************************************
2151 // Add a new notebook
2152 @SuppressWarnings("unused")
2153 private void addSavedSearch() {
2154 logger.log(logger.HIGH, "Inside NeverNote.addSavedSearch");
2155 SavedSearchEdit edit = new SavedSearchEdit();
2156 edit.setSearchList(listManager.getSavedSearchIndex());
2159 if (!edit.okPressed())
2162 Calendar currentTime = new GregorianCalendar();
2163 Long l = new Long(currentTime.getTimeInMillis());
2164 String randint = new String(Long.toString(l));
2166 SavedSearch search = new SavedSearch();
2167 search.setUpdateSequenceNum(0);
2168 search.setGuid(randint);
2169 search.setName(edit.getName());
2170 search.setQuery(edit.getQuery());
2171 search.setFormat(QueryFormat.USER);
2172 listManager.getSavedSearchIndex().add(search);
2173 conn.getSavedSearchTable().addSavedSearch(search, true);
2174 savedSearchIndexUpdated();
2175 logger.log(logger.HIGH, "Leaving NeverNote.addSavedSearch");
2177 // Edit an existing tag
2178 @SuppressWarnings("unused")
2179 private void editSavedSearch() {
2180 logger.log(logger.HIGH, "Entering NeverNote.editSavedSearch");
2181 SavedSearchEdit edit = new SavedSearchEdit();
2182 edit.setTitle(tr("Edit Search"));
2183 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2184 QTreeWidgetItem currentSelection;
2185 currentSelection = selections.get(0);
2186 String guid = currentSelection.text(1);
2187 SavedSearch s = conn.getSavedSearchTable().getSavedSearch(guid);
2188 edit.setName(currentSelection.text(0));
2189 edit.setQuery(s.getQuery());
2190 edit.setSearchList(listManager.getSavedSearchIndex());
2193 if (!edit.okPressed())
2196 List<SavedSearch> list = listManager.getSavedSearchIndex();
2197 SavedSearch search = null;
2198 boolean found = false;
2199 for (int i=0; i<list.size(); i++) {
2200 search = list.get(i);
2201 if (search.getGuid().equals(guid)) {
2208 search.setName(edit.getName());
2209 search.setQuery(edit.getQuery());
2210 conn.getSavedSearchTable().updateSavedSearch(search, true);
2211 savedSearchIndexUpdated();
2212 logger.log(logger.HIGH, "Leaving NeverNote.editSavedSearch");
2214 // Delete an existing tag
2215 @SuppressWarnings("unused")
2216 private void deleteSavedSearch() {
2217 logger.log(logger.HIGH, "Entering NeverNote.deleteSavedSearch");
2219 if (QMessageBox.question(this, "Confirmation", "Delete the selected search?",
2220 QMessageBox.StandardButton.Yes,
2221 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
2225 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2226 for (int i=selections.size()-1; i>=0; i--) {
2227 QTreeWidgetItem currentSelection;
2228 currentSelection = selections.get(i);
2229 for (int j=0; j<listManager.getSavedSearchIndex().size(); j++) {
2230 if (listManager.getSavedSearchIndex().get(j).getGuid().equals(currentSelection.text(1))) {
2231 conn.getSavedSearchTable().expungeSavedSearch(listManager.getSavedSearchIndex().get(j).getGuid(), true);
2232 listManager.getSavedSearchIndex().remove(j);
2233 j=listManager.getSavedSearchIndex().size()+1;
2236 selections.remove(i);
2238 savedSearchIndexUpdated();
2239 logger.log(logger.HIGH, "Leaving NeverNote.deleteSavedSearch");
2241 // Setup the tree containing the user's tags
2242 private void initializeSavedSearchTree() {
2243 logger.log(logger.HIGH, "Entering NeverNote.initializeSavedSearchTree");
2244 savedSearchTree.itemSelectionChanged.connect(this, "savedSearchTreeSelection()");
2245 logger.log(logger.HIGH, "Leaving NeverNote.initializeSavedSearchTree");
2247 // Listener when a tag is selected
2248 @SuppressWarnings("unused")
2249 private void savedSearchTreeSelection() {
2250 logger.log(logger.HIGH, "Entering NeverNote.savedSearchTreeSelection");
2252 clearNotebookFilter();
2255 clearAttributeFilter();
2257 String currentGuid = selectedSavedSearchGUID;
2258 menuBar.savedSearchEditAction.setEnabled(true);
2259 menuBar.savedSearchDeleteAction.setEnabled(true);
2260 menuBar.savedSearchIconAction.setEnabled(true);
2261 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2262 QTreeWidgetItem currentSelection;
2263 selectedSavedSearchGUID = "";
2264 for (int i=0; i<selections.size(); i++) {
2265 currentSelection = selections.get(i);
2266 if (currentSelection.text(1).equals(currentGuid)) {
2267 currentSelection.setSelected(false);
2269 selectedSavedSearchGUID = currentSelection.text(1);
2271 // i = selections.size() +1;
2274 // There is the potential for no notebooks to be selected if this
2275 // happens then we make it look like all notebooks were selecetd.
2276 // If that happens, just select the "all notebooks"
2277 if (selections.size()==0) {
2278 clearSavedSearchFilter();
2280 listManager.setSelectedSavedSearch(selectedSavedSearchGUID);
2282 logger.log(logger.HIGH, "Leaving NeverNote.savedSearchTreeSelection");
2284 private void clearSavedSearchFilter() {
2285 menuBar.savedSearchEditAction.setEnabled(false);
2286 menuBar.savedSearchDeleteAction.setEnabled(false);
2287 menuBar.savedSearchIconAction.setEnabled(false);
2288 savedSearchTree.blockSignals(true);
2289 savedSearchTree.clearSelection();
2290 savedSearchTree.blockSignals(false);
2291 selectedSavedSearchGUID = "";
2292 searchField.setEditText("");
2293 searchPerformed = false;
2294 listManager.setSelectedSavedSearch(selectedSavedSearchGUID);
2296 // trigger the tag index to be refreshed
2297 private void savedSearchIndexUpdated() {
2298 if (selectedSavedSearchGUID == null)
2299 selectedSavedSearchGUID = new String();
2300 savedSearchTree.blockSignals(true);
2301 savedSearchTree.setIcons(conn.getSavedSearchTable().getAllIcons());
2302 savedSearchTree.load(listManager.getSavedSearchIndex());
2303 savedSearchTree.selectGuid(selectedSavedSearchGUID);
2304 savedSearchTree.blockSignals(false);
2306 // trigger when the saved search selection changes
2307 @SuppressWarnings("unused")
2308 private void updateSavedSearchSelection() {
2309 logger.log(logger.HIGH, "Entering NeverNote.updateSavedSearchSelection()");
2311 menuBar.savedSearchEditAction.setEnabled(true);
2312 menuBar.savedSearchDeleteAction.setEnabled(true);
2313 menuBar.savedSearchIconAction.setEnabled(true);
2314 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2316 if (selections.size() > 0) {
2317 menuBar.savedSearchEditAction.setEnabled(true);
2318 menuBar.savedSearchDeleteAction.setEnabled(true);
2319 menuBar.savedSearchIconAction.setEnabled(true);
2320 selectedSavedSearchGUID = selections.get(0).text(1);
2321 SavedSearch s = conn.getSavedSearchTable().getSavedSearch(selectedSavedSearchGUID);
2322 searchField.setEditText(s.getQuery());
2324 menuBar.savedSearchEditAction.setEnabled(false);
2325 menuBar.savedSearchDeleteAction.setEnabled(false);
2326 menuBar.savedSearchIconAction.setEnabled(false);
2327 selectedSavedSearchGUID = "";
2328 searchField.setEditText("");
2330 searchFieldChanged();
2332 logger.log(logger.HIGH, "Leaving NeverNote.updateSavedSearchSelection()");
2336 // Show/Hide note information
2337 private void toggleSavedSearchWindow() {
2338 logger.log(logger.HIGH, "Entering NeverNote.toggleSavedSearchWindow");
2339 if (savedSearchTree.isVisible())
2340 savedSearchTree.hide();
2342 savedSearchTree.show();
2343 menuBar.hideSavedSearches.setChecked(savedSearchTree.isVisible());
2345 Global.saveWindowVisible("savedSearchTree", savedSearchTree.isVisible());
2346 logger.log(logger.HIGH, "Leaving NeverNote.toggleSavedSearchWindow");
2348 // Change the icon for a saved search
2349 @SuppressWarnings("unused")
2350 private void setSavedSearchIcon() {
2351 QTreeWidgetItem currentSelection;
2352 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2353 if (selections.size() == 0)
2356 currentSelection = selections.get(0);
2357 String guid = currentSelection.text(1);
2359 QIcon currentIcon = currentSelection.icon(0);
2360 QIcon icon = conn.getSavedSearchTable().getIcon(guid);
2363 dialog = new SetIcon(currentIcon);
2364 dialog.setUseDefaultIcon(true);
2366 dialog = new SetIcon(icon);
2367 dialog.setUseDefaultIcon(false);
2370 if (dialog.okPressed()) {
2371 QIcon newIcon = dialog.getIcon();
2372 conn.getSavedSearchTable().setIcon(guid, newIcon, dialog.getFileType());
2373 if (newIcon == null)
2374 newIcon = new QIcon(iconPath+"search.png");
2375 currentSelection.setIcon(0, newIcon);
2383 //***************************************************************
2384 //***************************************************************
2385 //** These functions deal with Help menu & tool menu items
2386 //***************************************************************
2387 //***************************************************************
2388 // Show database status
2389 @SuppressWarnings("unused")
2390 private void databaseStatus() {
2392 int dirty = conn.getNoteTable().getDirtyCount();
2393 int unindexed = conn.getNoteTable().getUnindexedCount();
2394 DatabaseStatus status = new DatabaseStatus();
2395 status.setUnsynchronized(dirty);
2396 status.setUnindexed(unindexed);
2397 status.setNoteCount(conn.getNoteTable().getNoteCount());
2398 status.setNotebookCount(listManager.getNotebookIndex().size());
2399 status.setUnindexedResourceCount(conn.getNoteTable().noteResourceTable.getUnindexedCount());
2400 status.setSavedSearchCount(listManager.getSavedSearchIndex().size());
2401 status.setTagCount(listManager.getTagIndex().size());
2402 status.setResourceCount(conn.getNoteTable().noteResourceTable.getResourceCount());
2403 status.setWordCount(conn.getWordsTable().getWordCount());
2407 // Compact the database
2408 @SuppressWarnings("unused")
2409 private void compactDatabase() {
2410 logger.log(logger.HIGH, "Entering NeverNote.compactDatabase");
2411 if (QMessageBox.question(this, tr("Confirmation"), tr("This will free unused space in the database, "+
2412 "but please be aware that depending upon the size of your database this can be time consuming " +
2413 "and NeverNote will be unresponsive until it is complete. Do you wish to continue?"),
2414 QMessageBox.StandardButton.Yes,
2415 QMessageBox.StandardButton.No)==StandardButton.No.value() && Global.verifyDelete() == true) {
2418 setMessage("Compacting database.");
2420 listManager.compactDatabase();
2422 setMessage("Database compact is complete.");
2423 logger.log(logger.HIGH, "Leaving NeverNote.compactDatabase");
2425 @SuppressWarnings("unused")
2426 private void accountInformation() {
2427 logger.log(logger.HIGH, "Entering NeverNote.accountInformation");
2428 AccountDialog dialog = new AccountDialog();
2430 logger.log(logger.HIGH, "Leaving NeverNote.accountInformation");
2432 @SuppressWarnings("unused")
2433 private void releaseNotes() {
2434 logger.log(logger.HIGH, "Entering NeverNote.releaseNotes");
2435 QDialog dialog = new QDialog(this);
2436 QHBoxLayout layout = new QHBoxLayout();
2437 QTextEdit textBox = new QTextEdit();
2438 layout.addWidget(textBox);
2439 textBox.setReadOnly(true);
2440 QFile file = new QFile(Global.getFileManager().getHomeDirPath("release.txt"));
2441 if (!file.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly,
2442 QIODevice.OpenModeFlag.Text)))
2444 textBox.setText(file.readAll().toString());
2446 dialog.setWindowTitle(tr("Release Notes"));
2447 dialog.setLayout(layout);
2449 logger.log(logger.HIGH, "Leaving NeverNote.releaseNotes");
2451 // Called when user picks Log from the help menu
2452 @SuppressWarnings("unused")
2453 private void logger() {
2454 logger.log(logger.HIGH, "Entering NeverNote.logger");
2455 QDialog dialog = new QDialog(this);
2456 QHBoxLayout layout = new QHBoxLayout();
2457 QListWidget textBox = new QListWidget();
2458 layout.addWidget(textBox);
2459 textBox.addItems(emitLog);
2461 dialog.setLayout(layout);
2462 dialog.setWindowTitle(tr("Mesasge Log"));
2464 logger.log(logger.HIGH, "Leaving NeverNote.logger");
2466 // Menu option "help/about" was selected
2467 @SuppressWarnings("unused")
2468 private void about() {
2469 logger.log(logger.HIGH, "Entering NeverNote.about");
2470 QMessageBox.about(this,
2471 tr("About NeverNote"),
2472 tr("<h4><center><b>NeverNote</b></center></h4><hr><center>Version ")
2474 +tr("<hr></center>Evernote"
2475 +"An Open Source Evernote Client.<br><br>"
2476 +"Licensed under GPL v2. <br><hr><br>"
2477 +"Evernote is copyright 2001-2010 by Evernote Corporation<br>"
2478 +"Jambi and QT are the licensed trademark of Nokia Corporation<br>"
2479 +"PDFRenderer is licened under the LGPL<br>"
2480 +"JTidy is copyrighted under the World Wide Web Consortium<br>"
2481 +"Apache Common Utilities licensed under the Apache License Version 2.0<br>"
2482 +"Jazzy is licened under the LGPL<br>"
2483 +"Java is a registered trademark of Oracle Corporation.<br><hr>"));
2484 logger.log(logger.HIGH, "Leaving NeverNote.about");
2486 // Hide the entire left hand side
2487 @SuppressWarnings("unused")
2488 private void toggleLeftSide() {
2491 hidden = !menuBar.hideLeftSide.isChecked();
2492 menuBar.hideLeftSide.setChecked(!hidden);
2494 if (notebookTree.isVisible() != hidden)
2495 toggleNotebookWindow();
2496 if (savedSearchTree.isVisible() != hidden)
2497 toggleSavedSearchWindow();
2498 if (tagTree.isVisible() != hidden)
2500 if (attributeTree.isVisible() != hidden)
2501 toggleAttributesWindow();
2502 if (trashTree.isVisible() != hidden)
2503 toggleTrashWindow();
2505 Global.saveWindowVisible("leftPanel", hidden);
2510 //***************************************************************
2511 //***************************************************************
2512 //** These functions deal with the Toolbar
2513 //***************************************************************
2514 //***************************************************************
2515 // Text in the search bar has been cleared
2516 private void searchFieldCleared() {
2519 // This is done because we want to force a reload of
2520 // images. Some images we may want to highlight the text.
2521 readOnlyCache.clear();
2522 inkNoteCache.clear();
2524 QWebSettings.setMaximumPagesInCache(0);
2525 QWebSettings.setObjectCacheCapacities(0, 0, 0);
2527 searchField.setEditText("");
2528 saveNoteColumnPositions();
2529 saveNoteIndexWidth();
2530 noteIndexUpdated(true);
2531 if (currentNote == null && listManager.getNoteIndex().size() > 0) {
2532 currentNote = listManager.getNoteIndex().get(0);
2533 currentNoteGuid = currentNote.getGuid();
2535 if (currentNote != null)
2536 loadNoteBrowserInformation(browserWindow);
2538 // text in the search bar changed. We only use this to tell if it was cleared,
2539 // otherwise we trigger off searchFieldChanged.
2540 @SuppressWarnings("unused")
2541 private void searchFieldTextChanged(String text) {
2542 if (text.trim().equals("")) {
2543 searchFieldCleared();
2544 if (searchPerformed) {
2546 // This is done because we want to force a reload of
2547 // images. Some images we may want to highlight the text.
2549 readOnlyCache.clear();
2550 inkNoteCache.clear();
2551 QWebSettings.setMaximumPagesInCache(0);
2552 QWebSettings.setObjectCacheCapacities(0, 0, 0);
2554 listManager.setEnSearch("");
2555 listManager.loadNotesIndex();
2556 refreshEvernoteNote(true);
2557 noteIndexUpdated(false);
2559 searchPerformed = false;
2562 // Text in the toolbar has changed
2563 private void searchFieldChanged() {
2564 logger.log(logger.HIGH, "Entering NeverNote.searchFieldChanged");
2566 readOnlyCache.clear();
2567 inkNoteCache.clear();
2568 saveNoteColumnPositions();
2569 saveNoteIndexWidth();
2570 String text = searchField.currentText();
2571 listManager.setEnSearch(text.trim());
2572 listManager.loadNotesIndex();
2573 //--->>> noteIndexUpdated(true);
2574 noteIndexUpdated(false);
2575 refreshEvernoteNote(true);
2576 searchPerformed = true;
2577 logger.log(logger.HIGH, "Leaving NeverNote.searchFieldChanged");
2580 // Build the window tool bar
2581 private void setupToolBar() {
2582 logger.log(logger.HIGH, "Entering NeverNote.setupToolBar");
2583 toolBar = addToolBar(tr("Tool Bar"));
2584 menuBar.setupToolBarVisible();
2585 if (!Global.isWindowVisible("toolBar"))
2586 toolBar.setVisible(false);
2588 toolBar.setVisible(true);
2590 prevButton = toolBar.addAction("Previous");
2591 QIcon prevIcon = new QIcon(iconPath+"back.png");
2592 prevButton.setIcon(prevIcon);
2593 prevButton.triggered.connect(this, "previousViewedAction()");
2594 togglePrevArrowButton(Global.isToolbarButtonVisible("prevArrow"));
2596 nextButton = toolBar.addAction("Next");
2597 QIcon nextIcon = new QIcon(iconPath+"forward.png");
2598 nextButton.setIcon(nextIcon);
2599 nextButton.triggered.connect(this, "nextViewedAction()");
2600 toggleNextArrowButton(Global.isToolbarButtonVisible("nextArrow"));
2602 upButton = toolBar.addAction("Up");
2603 QIcon upIcon = new QIcon(iconPath+"up.png");
2604 upButton.setIcon(upIcon);
2605 upButton.triggered.connect(this, "upAction()");
2606 toggleUpArrowButton(Global.isToolbarButtonVisible("upArrow"));
2609 downButton = toolBar.addAction("Down");
2610 QIcon downIcon = new QIcon(iconPath+"down.png");
2611 downButton.setIcon(downIcon);
2612 downButton.triggered.connect(this, "downAction()");
2613 toggleDownArrowButton(Global.isToolbarButtonVisible("downArrow"));
2615 synchronizeButton = toolBar.addAction("Synchronize");
2616 synchronizeButton.setIcon(new QIcon(iconPath+"synchronize.png"));
2617 synchronizeIconAngle = 0;
2618 synchronizeButton.triggered.connect(this, "evernoteSync()");
2619 toggleSynchronizeButton(Global.isToolbarButtonVisible("synchronize"));
2621 printButton = toolBar.addAction("Print");
2622 QIcon printIcon = new QIcon(iconPath+"print.png");
2623 printButton.setIcon(printIcon);
2624 printButton.triggered.connect(this, "printNote()");
2625 togglePrintButton(Global.isToolbarButtonVisible("print"));
2627 tagButton = toolBar.addAction("Tag");
2628 QIcon tagIcon = new QIcon(iconPath+"tag.png");
2629 tagButton.setIcon(tagIcon);
2630 tagButton.triggered.connect(browserWindow, "modifyTags()");
2631 toggleTagButton(Global.isToolbarButtonVisible("tag"));
2633 attributeButton = toolBar.addAction("Attributes");
2634 QIcon attributeIcon = new QIcon(iconPath+"attribute.png");
2635 attributeButton.setIcon(attributeIcon);
2636 attributeButton.triggered.connect(this, "toggleNoteInformation()");
2637 toggleAttributeButton(Global.isToolbarButtonVisible("attribute"));
2639 emailButton = toolBar.addAction("Email");
2640 QIcon emailIcon = new QIcon(iconPath+"email.png");
2641 emailButton.setIcon(emailIcon);
2642 emailButton.triggered.connect(this, "emailNote()");
2643 toggleEmailButton(Global.isToolbarButtonVisible("email"));
2645 deleteButton = toolBar.addAction("Delete");
2646 QIcon deleteIcon = new QIcon(iconPath+"delete.png");
2647 deleteButton.setIcon(deleteIcon);
2648 deleteButton.triggered.connect(this, "deleteNote()");
2649 toggleDeleteButton(Global.isToolbarButtonVisible("delete"));
2651 newButton = toolBar.addAction("New");
2652 QIcon newIcon = new QIcon(iconPath+"new.png");
2653 newButton.triggered.connect(this, "addNote()");
2654 newButton.setIcon(newIcon);
2655 toggleNewButton(Global.isToolbarButtonVisible("new"));
2657 allNotesButton = toolBar.addAction("All Notes");
2658 QIcon allIcon = new QIcon(iconPath+"books.png");
2659 allNotesButton.triggered.connect(this, "allNotes()");
2660 allNotesButton.setIcon(allIcon);
2661 toggleAllNotesButton(Global.isToolbarButtonVisible("allNotes"));
2663 toolBar.addSeparator();
2664 toolBar.addWidget(new QLabel(tr("Quota:")));
2665 toolBar.addWidget(quotaBar);
2666 //quotaBar.setSizePolicy(Policy.Minimum, Policy.Minimum);
2668 toolBar.addSeparator();
2671 zoomSpinner = new QSpinBox();
2672 zoomSpinner.setMinimum(10);
2673 zoomSpinner.setMaximum(1000);
2674 zoomSpinner.setAccelerated(true);
2675 zoomSpinner.setSingleStep(10);
2676 zoomSpinner.setValue(100);
2677 zoomSpinner.valueChanged.connect(this, "zoomChanged()");
2678 toolBar.addWidget(new QLabel(tr("Zoom")));
2679 toolBar.addWidget(zoomSpinner);
2681 //toolBar.addWidget(new QLabel(" "));
2682 toolBar.addSeparator();
2683 toolBar.addWidget(new QLabel(tr(" Search:")));
2684 toolBar.addWidget(searchField);
2685 QSizePolicy sizePolicy = new QSizePolicy();
2686 sizePolicy.setHorizontalPolicy(Policy.MinimumExpanding);
2687 searchField.setSizePolicy(sizePolicy);
2688 searchField.setInsertPolicy(InsertPolicy.InsertAtTop);
2690 searchClearButton = toolBar.addAction("Search Clear");
2691 QIcon searchClearIcon = new QIcon(iconPath+"searchclear.png");
2692 searchClearButton.setIcon(searchClearIcon);
2693 searchClearButton.triggered.connect(this, "searchFieldCleared()");
2694 toggleSearchClearButton(Global.isToolbarButtonVisible("searchClear"));
2696 logger.log(logger.HIGH, "Leaving NeverNote.setupToolBar");
2698 // Update the sychronize button picture
2700 public QMenu createPopupMenu() {
2701 QMenu contextMenu = super.createPopupMenu();
2703 contextMenu.addSeparator();
2704 QAction prevAction = addContextAction("prevArrow", tr("Previous Arrow"));
2705 contextMenu.addAction(prevAction);
2706 prevAction.triggered.connect(this, "togglePrevArrowButton(Boolean)");
2708 QAction nextAction = addContextAction("nextArrow", tr("Next Arrow"));
2709 contextMenu.addAction(nextAction);
2710 nextAction.triggered.connect(this, "toggleNextArrowButton(Boolean)");
2712 QAction upAction = addContextAction("upArrow", tr("Up Arrow"));
2713 contextMenu.addAction(upAction);
2714 upAction.triggered.connect(this, "toggleUpArrowButton(Boolean)");
2716 QAction downAction = addContextAction("downArrow", tr("Down Arrow"));
2717 contextMenu.addAction(downAction);
2718 downAction.triggered.connect(this, "toggleDownArrowButton(Boolean)");
2720 QAction synchronizeAction = addContextAction("synchronize", tr("Synchronize"));
2721 contextMenu.addAction(synchronizeAction);
2722 synchronizeAction.triggered.connect(this, "toggleSynchronizeButton(Boolean)");
2724 QAction printAction = addContextAction("print", tr("Print"));
2725 contextMenu.addAction(printAction);
2726 printAction.triggered.connect(this, "togglePrintButton(Boolean)");
2728 QAction tagAction = addContextAction("tag", tr("Tag"));
2729 contextMenu.addAction(tagAction);
2730 tagAction.triggered.connect(this, "toggleTagButton(Boolean)");
2732 QAction attributeAction = addContextAction("attribute", tr("Attribute"));
2733 contextMenu.addAction(attributeAction);
2734 attributeAction.triggered.connect(this, "toggleAttributeButton(Boolean)");
2736 QAction emailAction = addContextAction("email", tr("Email"));
2737 contextMenu.addAction(emailAction);
2738 emailAction.triggered.connect(this, "toggleEmailButton(Boolean)");
2740 QAction deleteAction = addContextAction("delete", tr("Delete"));
2741 contextMenu.addAction(deleteAction);
2742 deleteAction.triggered.connect(this, "toggleDeleteButton(Boolean)");
2744 QAction newAction = addContextAction("new", tr("Add"));
2745 contextMenu.addAction(newAction);
2746 newAction.triggered.connect(this, "toggleNewButton(Boolean)");
2748 QAction allNotesAction = addContextAction("allNotes", tr("All Notes"));
2749 contextMenu.addAction(allNotesAction);
2750 allNotesAction.triggered.connect(this, "toggleAllNotesButton(Boolean)");
2752 QAction searchClearAction = addContextAction("searchClear", tr("Search Clear"));
2753 contextMenu.addAction(searchClearAction);
2754 searchClearAction.triggered.connect(this, "toggleSearchClearButton(Boolean)");
2759 private QAction addContextAction(String config, String name) {
2760 QAction newAction = new QAction(this);
2761 newAction.setText(name);
2762 newAction.setCheckable(true);
2763 newAction.setChecked(Global.isToolbarButtonVisible(config));
2766 private void togglePrevArrowButton(Boolean toggle) {
2767 prevButton.setVisible(toggle);
2768 Global.saveToolbarButtonsVisible("prevArrow", toggle);
2770 private void toggleNextArrowButton(Boolean toggle) {
2771 nextButton.setVisible(toggle);
2772 Global.saveToolbarButtonsVisible("nextArrow", toggle);
2774 private void toggleUpArrowButton(Boolean toggle) {
2775 upButton.setVisible(toggle);
2776 Global.saveToolbarButtonsVisible("upArrow", toggle);
2778 private void toggleDownArrowButton(Boolean toggle) {
2779 downButton.setVisible(toggle);
2780 Global.saveToolbarButtonsVisible("downArrow", toggle);
2782 private void toggleSynchronizeButton(Boolean toggle) {
2783 synchronizeButton.setVisible(toggle);
2784 Global.saveToolbarButtonsVisible("synchronize", toggle);
2786 private void togglePrintButton(Boolean toggle) {
2787 printButton.setVisible(toggle);
2788 Global.saveToolbarButtonsVisible("print", toggle);
2790 private void toggleTagButton(Boolean toggle) {
2791 tagButton.setVisible(toggle);
2792 Global.saveToolbarButtonsVisible("tag", toggle);
2794 private void toggleAttributeButton(Boolean toggle) {
2795 attributeButton.setVisible(toggle);
2796 Global.saveToolbarButtonsVisible("attribute", toggle);
2798 private void toggleEmailButton(Boolean toggle) {
2799 emailButton.setVisible(toggle);
2800 Global.saveToolbarButtonsVisible("email", toggle);
2802 private void toggleDeleteButton(Boolean toggle) {
2803 deleteButton.setVisible(toggle);
2804 Global.saveToolbarButtonsVisible("delete", toggle);
2806 private void toggleNewButton(Boolean toggle) {
2807 newButton.setVisible(toggle);
2808 Global.saveToolbarButtonsVisible("new", toggle);
2810 private void toggleAllNotesButton(Boolean toggle) {
2811 allNotesButton.setVisible(toggle);
2812 Global.saveToolbarButtonsVisible("allNotes", toggle);
2814 private void toggleSearchClearButton(Boolean toggle) {
2815 searchClearButton.setVisible(toggle);
2816 Global.saveToolbarButtonsVisible("searchClear", toggle);
2823 @SuppressWarnings("unused")
2824 private void updateSyncButton() {
2826 if (syncIcons == null) {
2827 syncIcons = new ArrayList<QPixmap>();
2829 synchronizeIconAngle = 0;
2830 QPixmap pix = new QPixmap(iconPath+"synchronize.png");
2832 for (int i=0; i<=360; i++) {
2833 QPixmap rotatedPix = new QPixmap(pix.size());
2834 QPainter p = new QPainter(rotatedPix);
2835 rotatedPix.fill(toolBar.palette().color(ColorRole.Button));
2836 QSize size = pix.size();
2837 p.translate(size.width()/2, size.height()/2);
2840 p.setBackgroundMode(BGMode.OpaqueMode);
2841 p.translate(-size.width()/2, -size.height()/2);
2842 p.drawPixmap(0,0, pix);
2844 syncIcons.add(rotatedPix);
2848 synchronizeIconAngle++;
2849 if (synchronizeIconAngle > 359)
2850 synchronizeIconAngle=0;
2851 synchronizeButton.setIcon(syncIcons.get(synchronizeIconAngle));
2854 // Synchronize with Evernote
2855 @SuppressWarnings("unused")
2856 private void evernoteSync() {
2857 logger.log(logger.HIGH, "Entering NeverNote.evernoteSync");
2858 if (!Global.isConnected)
2860 if (Global.isConnected)
2861 synchronizeAnimationTimer.start(5);
2862 // synchronizeAnimationTimer.start(200);
2864 logger.log(logger.HIGH, "Leaving NeverNote.evernoteSync");
2866 private void updateQuotaBar() {
2867 long limit = Global.getUploadLimit();
2868 long amount = Global.getUploadAmount();
2869 if (amount>0 && limit>0) {
2870 int percent =(int)(amount*100/limit);
2871 quotaBar.setValue(percent);
2873 quotaBar.setValue(0);
2876 @SuppressWarnings("unused")
2877 private void zoomChanged() {
2878 browserWindow.getBrowser().setZoomFactor(new Double(zoomSpinner.value())/100);
2881 //****************************************************************
2882 //****************************************************************
2883 //* System Tray functions
2884 //****************************************************************
2885 //****************************************************************
2886 private void trayToggleVisible() {
2891 if (windowMaximized)
2898 @SuppressWarnings("unused")
2899 private void trayActivated(QSystemTrayIcon.ActivationReason reason) {
2900 if (reason == QSystemTrayIcon.ActivationReason.DoubleClick) {
2901 String name = QSystemTrayIcon.MessageIcon.resolve(reason.value()).name();
2902 trayToggleVisible();
2907 //***************************************************************
2908 //***************************************************************
2909 //** These functions deal with the trash tree
2910 //***************************************************************
2911 //***************************************************************
2912 // Setup the tree containing the trash.
2913 @SuppressWarnings("unused")
2914 private void trashTreeSelection() {
2915 logger.log(logger.HIGH, "Entering NeverNote.trashTreeSelection");
2917 clearNotebookFilter();
2919 clearAttributeFilter();
2920 clearSavedSearchFilter();
2922 String tempGuid = currentNoteGuid;
2924 // currentNoteGuid = "";
2925 currentNote = new Note();
2926 selectedNoteGUIDs.clear();
2927 listManager.getSelectedNotebooks().clear();
2928 listManager.getSelectedTags().clear();
2929 listManager.setSelectedSavedSearch("");
2930 browserWindow.clear();
2932 // toggle the add buttons
2933 newButton.setEnabled(!newButton.isEnabled());
2934 menuBar.noteAdd.setEnabled(newButton.isEnabled());
2935 menuBar.noteAdd.setVisible(true);
2937 List<QTreeWidgetItem> selections = trashTree.selectedItems();
2938 if (selections.size() == 0) {
2939 currentNoteGuid = trashNoteGuid;
2940 trashNoteGuid = tempGuid;
2941 Global.showDeleted = false;
2942 menuBar.noteRestoreAction.setEnabled(false);
2943 menuBar.noteRestoreAction.setVisible(false);
2946 currentNoteGuid = trashNoteGuid;
2947 trashNoteGuid = tempGuid;
2948 menuBar.noteRestoreAction.setEnabled(true);
2949 menuBar.noteRestoreAction.setVisible(true);
2950 Global.showDeleted = true;
2952 listManager.loadNotesIndex();
2953 noteIndexUpdated(false);
2954 //// browserWindow.setEnabled(newButton.isEnabled());
2955 browserWindow.setReadOnly(!newButton.isEnabled());
2956 logger.log(logger.HIGH, "Leaving NeverNote.trashTreeSelection");
2958 // Empty the trash file
2959 @SuppressWarnings("unused")
2960 private void emptyTrash() {
2961 // browserWindow.clear();
2962 listManager.emptyTrash();
2963 if (trashTree.selectedItems().size() > 0) {
2964 listManager.getSelectedNotebooks().clear();
2965 listManager.getSelectedTags().clear();
2966 listManager.setSelectedSavedSearch("");
2967 newButton.setEnabled(!newButton.isEnabled());
2968 menuBar.noteAdd.setEnabled(newButton.isEnabled());
2969 menuBar.noteAdd.setVisible(true);
2970 browserWindow.clear();
2973 clearNotebookFilter();
2974 clearSavedSearchFilter();
2975 clearAttributeFilter();
2977 Global.showDeleted = false;
2978 menuBar.noteRestoreAction.setEnabled(false);
2979 menuBar.noteRestoreAction.setVisible(false);
2981 listManager.loadNotesIndex();
2982 //--->>> noteIndexUpdated(true);
2983 noteIndexUpdated(false);
2986 // Show/Hide trash window
2987 private void toggleTrashWindow() {
2988 logger.log(logger.HIGH, "Entering NeverNote.toggleTrashWindow");
2989 if (trashTree.isVisible())
2993 menuBar.hideTrash.setChecked(trashTree.isVisible());
2995 Global.saveWindowVisible("trashTree", trashTree.isVisible());
2996 logger.log(logger.HIGH, "Leaving NeverNote.trashWindow");
2998 private void clearTrashFilter() {
2999 Global.showDeleted = false;
3000 newButton.setEnabled(true);
3001 menuBar.noteAdd.setEnabled(true);
3002 menuBar.noteAdd.setVisible(true);
3003 trashTree.blockSignals(true);
3004 trashTree.clearSelection();
3005 trashTree.blockSignals(false);
3010 //***************************************************************
3011 //***************************************************************
3012 //** These functions deal with connection settings
3013 //***************************************************************
3014 //***************************************************************
3015 // SyncRunner had a problem and things are disconnected
3016 @SuppressWarnings("unused")
3017 private void remoteErrorDisconnect() {
3018 menuBar.connectAction.setText(tr("Connect"));
3019 menuBar.connectAction.setToolTip(tr("Connect to Evernote"));
3020 menuBar.synchronizeAction.setEnabled(false);
3021 synchronizeAnimationTimer.stop();
3024 // Do a manual connect/disconnect
3025 private void remoteConnect() {
3026 logger.log(logger.HIGH, "Entering NeverNote.remoteConnect");
3028 if (Global.isConnected) {
3029 Global.isConnected = false;
3030 syncRunner.enDisconnect();
3031 setupConnectMenuOptions();
3036 AESEncrypter aes = new AESEncrypter();
3038 aes.decrypt(new FileInputStream(Global.getFileManager().getHomeDirFile("secure.txt")));
3039 } catch (FileNotFoundException e) {
3040 // File not found, so we'll just get empty strings anyway.
3042 String userid = aes.getUserid();
3043 String password = aes.getPassword();
3044 if (!userid.equals("") && !password.equals("")) {
3045 Global.username = userid;
3046 Global.password = password;
3049 // Show the login dialog box
3050 if (!Global.automaticLogin() || userid.equals("")|| password.equals("")) {
3051 LoginDialog login = new LoginDialog();
3054 if (!login.okPressed()) {
3058 Global.username = login.getUserid();
3059 Global.password = login.getPassword();
3061 syncRunner.username = Global.username;
3062 syncRunner.password = Global.password;
3063 syncRunner.userStoreUrl = Global.userStoreUrl;
3064 syncRunner.noteStoreUrl = Global.noteStoreUrl;
3065 syncRunner.noteStoreUrlBase = Global.noteStoreUrlBase;
3067 if (Global.getProxyValue("url").equals("")) {
3068 System.setProperty("http.proxyHost","") ;
3069 System.setProperty("http.proxyPort", "") ;
3070 System.setProperty("https.proxyHost","") ;
3071 System.setProperty("https.proxyPort", "") ;
3074 System.setProperty("http.proxyHost",Global.getProxyValue("url")) ;
3075 System.setProperty("http.proxyPort", Global.getProxyValue("port")) ;
3076 System.setProperty("https.proxyHost",Global.getProxyValue("url")) ;
3077 System.setProperty("https.proxyPort", Global.getProxyValue("port")) ;
3079 if (Global.getProxyValue("userid").equals("")) {
3080 Authenticator.setDefault(new Authenticator() {
3082 protected PasswordAuthentication getPasswordAuthentication() {
3084 PasswordAuthentication(Global.getProxyValue("userid"),Global.getProxyValue("password").toCharArray());
3090 syncRunner.enConnect();
3091 Global.isConnected = syncRunner.isConnected;
3093 setupConnectMenuOptions();
3094 logger.log(logger.HIGH, "Leaving NeverNote.remoteConnect");
3096 private void setupConnectMenuOptions() {
3097 logger.log(logger.HIGH, "entering NeverNote.setupConnectMenuOptions");
3098 if (!Global.isConnected) {
3099 menuBar.connectAction.setText(tr("Connect"));
3100 menuBar.connectAction.setToolTip(tr("Connect to Evernote"));
3101 menuBar.synchronizeAction.setEnabled(false);
3103 menuBar.connectAction.setText(tr("Disconnect"));
3104 menuBar.connectAction.setToolTip(tr("Disconnect from Evernote"));
3105 menuBar.synchronizeAction.setEnabled(true);
3107 logger.log(logger.HIGH, "Leaving NeverNote.setupConnectionMenuOptions");
3112 //***************************************************************
3113 //***************************************************************
3114 //** These functions deal with the GUI Attribute tree
3115 //***************************************************************
3116 //***************************************************************
3117 @SuppressWarnings("unused")
3118 private void attributeTreeClicked(QTreeWidgetItem item, Integer integer) {
3120 // clearTagFilter();
3121 // clearNotebookFilter();
3123 // clearSavedSearchFilter();
3125 if (attributeTreeSelected == null || item.nativeId() != attributeTreeSelected.nativeId()) {
3126 if (item.childCount() > 0) {
3127 item.setSelected(false);
3129 Global.createdBeforeFilter.reset();
3130 Global.createdSinceFilter.reset();
3131 Global.changedBeforeFilter.reset();
3132 Global.changedSinceFilter.reset();
3133 Global.containsFilter.reset();
3134 attributeTreeSelected = item;
3135 DateAttributeFilterTable f = null;
3136 f = findDateAttributeFilterTable(item.parent());
3138 f.select(item.parent().indexOfChild(item));
3140 Global.containsFilter.select(item.parent().indexOfChild(item));
3143 listManager.loadNotesIndex();
3144 noteIndexUpdated(false);
3147 attributeTreeSelected = null;
3148 item.setSelected(false);
3149 Global.createdBeforeFilter.reset();
3150 Global.createdSinceFilter.reset();
3151 Global.changedBeforeFilter.reset();
3152 Global.changedSinceFilter.reset();
3153 Global.containsFilter.reset();
3154 listManager.loadNotesIndex();
3155 noteIndexUpdated(false);
3157 // This determines what attribute filter we need, depending upon the selection
3158 private DateAttributeFilterTable findDateAttributeFilterTable(QTreeWidgetItem w) {
3159 if (w.parent() != null && w.childCount() > 0) {
3160 QTreeWidgetItem parent = w.parent();
3161 if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Created &&
3162 w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Since)
3163 return Global.createdSinceFilter;
3164 if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Created &&
3165 w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Before)
3166 return Global.createdBeforeFilter;
3167 if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.LastModified &&
3168 w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Since)
3169 return Global.changedSinceFilter;
3170 if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.LastModified &&
3171 w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Before)
3172 return Global.changedBeforeFilter;
3177 // Show/Hide attribute search window
3178 private void toggleAttributesWindow() {
3179 logger.log(logger.HIGH, "Entering NeverNote.toggleAttributesWindow");
3180 if (attributeTree.isVisible())
3181 attributeTree.hide();
3183 attributeTree.show();
3184 menuBar.hideAttributes.setChecked(attributeTree.isVisible());
3186 Global.saveWindowVisible("attributeTree", attributeTree.isVisible());
3187 logger.log(logger.HIGH, "Leaving NeverNote.toggleAttributeWindow");
3189 private void clearAttributeFilter() {
3190 Global.createdBeforeFilter.reset();
3191 Global.createdSinceFilter.reset();
3192 Global.changedBeforeFilter.reset();
3193 Global.changedSinceFilter.reset();
3194 Global.containsFilter.reset();
3195 attributeTreeSelected = null;
3196 attributeTree.blockSignals(true);
3197 attributeTree.clearSelection();
3198 attributeTree.blockSignals(false);
3202 //***************************************************************
3203 //***************************************************************
3204 //** These functions deal with the GUI Note index table
3205 //***************************************************************
3206 //***************************************************************
3207 // Initialize the note list table
3208 private void initializeNoteTable() {
3209 logger.log(logger.HIGH, "Entering NeverNote.initializeNoteTable");
3210 noteTableView.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection);
3211 noteTableView.selectionModel().selectionChanged.connect(this, "noteTableSelection()");
3212 logger.log(logger.HIGH, "Leaving NeverNote.initializeNoteTable");
3214 // Show/Hide trash window
3215 @SuppressWarnings("unused")
3216 private void toggleNoteListWindow() {
3217 logger.log(logger.HIGH, "Entering NeverNote.toggleNoteListWindow");
3218 if (noteTableView.isVisible())
3219 noteTableView.hide();
3221 noteTableView.show();
3222 menuBar.hideNoteList.setChecked(noteTableView.isVisible());
3224 Global.saveWindowVisible("noteList", noteTableView.isVisible());
3225 logger.log(logger.HIGH, "Leaving NeverNote.toggleNoteListWindow");
3227 // Handle the event that a user selects a note from the table
3228 @SuppressWarnings("unused")
3229 private void noteTableSelection() {
3230 logger.log(logger.HIGH, "Entering NeverNote.noteTableSelection");
3232 if (historyGuids.size() == 0) {
3233 historyGuids.add(currentNoteGuid);
3234 historyPosition = 1;
3236 noteTableView.showColumn(Global.noteTableGuidPosition);
3238 List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
3239 if (!Global.isColumnVisible("guid"))
3240 noteTableView.hideColumn(Global.noteTableGuidPosition);
3242 if (selections.size() > 0) {
3244 menuBar.noteDuplicateAction.setEnabled(true);
3245 menuBar.noteOnlineHistoryAction.setEnabled(true);
3246 menuBar.noteMergeAction.setEnabled(true);
3247 selectedNoteGUIDs.clear();
3248 if (selections.size() != 1 || Global.showDeleted) {
3249 menuBar.noteDuplicateAction.setEnabled(false);
3251 if (selections.size() != 1 || !Global.isConnected) {
3252 menuBar.noteOnlineHistoryAction.setEnabled(false);
3254 if (selections.size() == 1) {
3255 menuBar.noteMergeAction.setEnabled(false);
3257 for (int i=0; i<selections.size(); i++) {
3258 int row = selections.get(i).row();
3260 upButton.setEnabled(false);
3262 upButton.setEnabled(true);
3263 if (row < listManager.getNoteTableModel().rowCount()-1)
3264 downButton.setEnabled(true);
3266 downButton.setEnabled(false);
3267 index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition);
3268 SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
3269 currentNoteGuid = (String)ix.values().toArray()[0];
3270 selectedNoteGUIDs.add(currentNoteGuid);
3274 nextButton.setEnabled(true);
3275 prevButton.setEnabled(true);
3277 int endPosition = historyGuids.size()-1;
3278 for (int j=historyPosition; j<=endPosition; j++) {
3279 historyGuids.remove(historyGuids.size()-1);
3281 historyGuids.add(currentNoteGuid);
3282 historyPosition = historyGuids.size();
3284 if (historyPosition <= 1)
3285 prevButton.setEnabled(false);
3286 if (historyPosition == historyGuids.size())
3287 nextButton.setEnabled(false);
3289 fromHistory = false;
3290 scrollToGuid(currentNoteGuid);
3291 refreshEvernoteNote(true);
3292 logger.log(logger.HIGH, "Leaving NeverNote.noteTableSelection");
3294 // Trigger a refresh when the note db has been updated
3295 private void noteIndexUpdated(boolean reload) {
3296 logger.log(logger.HIGH, "Entering NeverNote.noteIndexUpdated");
3298 refreshEvernoteNoteList();
3299 logger.log(logger.HIGH, "Calling note table reload in NeverNote.noteIndexUpdated() - "+reload);
3300 noteTableView.load(reload);
3301 scrollToGuid(currentNoteGuid);
3302 logger.log(logger.HIGH, "Leaving NeverNote.noteIndexUpdated");
3304 // Called when the list of notes is updated
3305 private void refreshEvernoteNoteList() {
3306 logger.log(logger.HIGH, "Entering NeverNote.refreshEvernoteNoteList");
3307 browserWindow.setDisabled(false);
3308 if (selectedNoteGUIDs == null)
3309 selectedNoteGUIDs = new ArrayList<String>();
3310 selectedNoteGUIDs.clear(); // clear out old entries
3312 String saveCurrentNoteGuid = new String();
3313 String tempNoteGuid = new String();
3315 historyGuids.clear();
3316 historyPosition = 0;
3317 prevButton.setEnabled(false);
3318 nextButton.setEnabled(false);
3320 if (currentNoteGuid == null)
3321 currentNoteGuid = new String();
3323 //determine current note guid
3324 for (Note note : listManager.getNoteIndex()) {
3325 tempNoteGuid = note.getGuid();
3326 if (currentNoteGuid.equals(tempNoteGuid)) {
3327 saveCurrentNoteGuid = tempNoteGuid;
3331 if (listManager.getNoteIndex().size() == 0) {
3332 currentNoteGuid = "";
3334 browserWindow.clear();
3335 browserWindow.setDisabled(true);
3338 if (saveCurrentNoteGuid.equals("") && listManager.getNoteIndex().size() > 0) {
3339 currentNote = listManager.getNoteIndex().get(listManager.getNoteIndex().size()-1);
3340 currentNoteGuid = currentNote.getGuid();
3341 refreshEvernoteNote(true);
3343 //we can reload if note not dirty
3344 // refreshEvernoteNote(!noteDirty);
3345 refreshEvernoteNote(false);
3347 reloadTagTree(false);
3349 logger.log(logger.HIGH, "Leaving NeverNote.refreshEvernoteNoteList");
3351 // Called when the previous arrow button is clicked
3352 @SuppressWarnings("unused")
3353 private void previousViewedAction() {
3354 if (!prevButton.isEnabled())
3356 if (historyPosition == 0)
3359 if (historyPosition <= 0)
3361 String historyGuid = historyGuids.get(historyPosition-1);
3363 for (int i=0; i<noteTableView.model().rowCount(); i++) {
3364 QModelIndex modelIndex = noteTableView.model().index(i, Global.noteTableGuidPosition);
3365 if (modelIndex != null) {
3366 SortedMap<Integer, Object> ix = noteTableView.model().itemData(modelIndex);
3367 String tableGuid = (String)ix.values().toArray()[0];
3368 if (tableGuid.equals(historyGuid)) {
3369 noteTableView.selectRow(i);
3375 @SuppressWarnings("unused")
3376 private void nextViewedAction() {
3377 if (!nextButton.isEnabled())
3379 String historyGuid = historyGuids.get(historyPosition);
3382 for (int i=0; i<noteTableView.model().rowCount(); i++) {
3383 QModelIndex modelIndex = noteTableView.model().index(i, Global.noteTableGuidPosition);
3384 if (modelIndex != null) {
3385 SortedMap<Integer, Object> ix = noteTableView.model().itemData(modelIndex);
3386 String tableGuid = (String)ix.values().toArray()[0];
3387 if (tableGuid.equals(historyGuid)) {
3388 noteTableView.selectRow(i);
3394 // Called when the up arrow is clicked
3395 @SuppressWarnings("unused")
3396 private void upAction() {
3397 List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
3398 int row = selections.get(0).row();
3400 noteTableView.selectRow(row-1);
3403 // Called when the down arrow is clicked
3404 @SuppressWarnings("unused")
3405 private void downAction() {
3406 List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
3407 int row = selections.get(0).row();
3408 int max = listManager.getNoteTableModel().rowCount();
3410 noteTableView.selectRow(row+1);
3413 // Update a tag string for a specific note in the list
3414 @SuppressWarnings("unused")
3415 private void updateListTags(String guid, List<String> tags) {
3416 logger.log(logger.HIGH, "Entering NeverNote.updateListTags");
3417 StringBuffer tagBuffer = new StringBuffer();
3418 for (int i=0; i<tags.size(); i++) {
3419 tagBuffer.append(tags.get(i));
3420 if (i<tags.size()-1)
3421 tagBuffer.append(", ");
3424 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3425 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3426 if (modelIndex != null) {
3427 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3428 String tableGuid = (String)ix.values().toArray()[0];
3429 if (tableGuid.equals(guid)) {
3430 listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition,tagBuffer.toString());
3431 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
3432 noteTableView.proxyModel.invalidate();
3437 logger.log(logger.HIGH, "Leaving NeverNote.updateListTags");
3439 // Update a title for a specific note in the list
3440 @SuppressWarnings("unused")
3441 private void updateListAuthor(String guid, String author) {
3442 logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
3444 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3445 //QModelIndex modelIndex = noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
3446 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3447 if (modelIndex != null) {
3448 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3449 String tableGuid = (String)ix.values().toArray()[0];
3450 if (tableGuid.equals(guid)) {
3451 listManager.getNoteTableModel().setData(i, Global.noteTableAuthorPosition,author);
3452 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
3453 noteTableView.proxyModel.invalidate();
3459 logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
3461 private void updateListNoteNotebook(String guid, String notebook) {
3462 logger.log(logger.HIGH, "Entering NeverNote.updateListNoteNotebook");
3463 listManager.getNoteTableModel().updateNoteSyncStatus(guid, false);
3464 logger.log(logger.HIGH, "Leaving NeverNote.updateListNoteNotebook");
3466 // Update a title for a specific note in the list
3467 @SuppressWarnings("unused")
3468 private void updateListSourceUrl(String guid, String url) {
3469 logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
3471 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3472 //QModelIndex modelIndex = noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
3473 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3474 if (modelIndex != null) {
3475 // SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(modelIndex);
3476 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3477 String tableGuid = (String)ix.values().toArray()[0];
3478 if (tableGuid.equals(guid)) {
3479 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
3480 listManager.getNoteTableModel().setData(i, Global.noteTableSourceUrlPosition,url);
3481 noteTableView.proxyModel.invalidate();
3486 logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
3488 @SuppressWarnings("unused")
3489 private void updateListGuid(String oldGuid, String newGuid) {
3490 logger.log(logger.HIGH, "Entering NeverNote.updateListTitle");
3492 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3493 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3494 if (modelIndex != null) {
3495 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3496 String tableGuid = (String)ix.values().toArray()[0];
3497 if (tableGuid.equals(oldGuid)) {
3498 listManager.getNoteTableModel().setData(i, Global.noteTableGuidPosition,newGuid);
3499 //listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
3504 logger.log(logger.HIGH, "Leaving NeverNote.updateListTitle");
3506 private void updateListTagName(String guid) {
3507 logger.log(logger.HIGH, "Entering NeverNote.updateTagName");
3509 for (int j=0; j<listManager.getNoteIndex().size(); j++) {
3510 if (listManager.getNoteIndex().get(j).getTagGuids().contains(guid)) {
3511 String newName = listManager.getTagNamesForNote(listManager.getNoteIndex().get(j));
3513 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3514 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3515 if (modelIndex != null) {
3516 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3517 String noteGuid = (String)ix.values().toArray()[0];
3518 if (noteGuid.equalsIgnoreCase(listManager.getNoteIndex().get(j).getGuid())) {
3519 listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition, newName);
3520 i=listManager.getNoteTableModel().rowCount();
3526 logger.log(logger.HIGH, "Leaving NeverNote.updateListNotebook");
3528 private void removeListTagName(String guid) {
3529 logger.log(logger.HIGH, "Entering NeverNote.updateTagName");
3531 for (int j=0; j<listManager.getNoteIndex().size(); j++) {
3532 if (listManager.getNoteIndex().get(j).getTagGuids().contains(guid)) {
3533 for (int i=listManager.getNoteIndex().get(j).getTagGuids().size()-1; i>=0; i--) {
3534 if (listManager.getNoteIndex().get(j).getTagGuids().get(i).equals(guid))
3535 listManager.getNoteIndex().get(j).getTagGuids().remove(i);
3538 String newName = listManager.getTagNamesForNote(listManager.getNoteIndex().get(j));
3539 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3540 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3541 if (modelIndex != null) {
3542 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3543 String noteGuid = (String)ix.values().toArray()[0];
3544 if (noteGuid.equalsIgnoreCase(listManager.getNoteIndex().get(j).getGuid())) {
3545 listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition, newName);
3546 i=listManager.getNoteTableModel().rowCount();
3552 logger.log(logger.HIGH, "Leaving NeverNote.updateListNotebook");
3554 private void updateListNotebookName(String oldName, String newName) {
3555 logger.log(logger.HIGH, "Entering NeverNote.updateListNotebookName");
3557 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3558 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableNotebookPosition);
3559 if (modelIndex != null) {
3560 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3561 String tableName = (String)ix.values().toArray()[0];
3562 if (tableName.equalsIgnoreCase(oldName)) {
3563 listManager.getNoteTableModel().setData(i, Global.noteTableNotebookPosition, newName);
3567 logger.log(logger.HIGH, "Leaving NeverNote.updateListNotebookName");
3569 @SuppressWarnings("unused")
3570 private void updateListDateCreated(String guid, QDateTime date) {
3571 logger.log(logger.HIGH, "Entering NeverNote.updateListDateCreated");
3573 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3574 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3575 if (modelIndex != null) {
3576 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3577 String tableGuid = (String)ix.values().toArray()[0];
3578 if (tableGuid.equals(guid)) {
3579 listManager.getNoteTableModel().setData(i, Global.noteTableCreationPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
3580 noteTableView.proxyModel.invalidate();
3585 logger.log(logger.HIGH, "Leaving NeverNote.updateListDateCreated");
3587 @SuppressWarnings("unused")
3588 private void updateListDateSubject(String guid, QDateTime date) {
3589 logger.log(logger.HIGH, "Entering NeverNote.updateListDateSubject");
3591 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3592 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3593 if (modelIndex != null) {
3594 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3595 String tableGuid = (String)ix.values().toArray()[0];
3596 if (tableGuid.equals(guid)) {
3597 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
3598 listManager.getNoteTableModel().setData(i, Global.noteTableSubjectDatePosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
3599 noteTableView.proxyModel.invalidate();
3604 logger.log(logger.HIGH, "Leaving NeverNote.updateListDateCreated");
3606 private void updateListDateChanged(String guid, QDateTime date) {
3607 logger.log(logger.HIGH, "Entering NeverNote.updateListDateChanged");
3609 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3610 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3611 if (modelIndex != null) {
3612 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3613 String tableGuid = (String)ix.values().toArray()[0];
3614 if (tableGuid.equals(guid)) {
3615 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
3616 listManager.getNoteTableModel().setData(i, Global.noteTableChangedPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
3621 logger.log(logger.HIGH, "Leaving NeverNote.updateListDateChanged");
3623 private void updateListDateChanged() {
3624 logger.log(logger.HIGH, "Entering NeverNote.updateListDateChanged");
3625 QDateTime date = new QDateTime(QDateTime.currentDateTime());
3626 updateListDateChanged(currentNoteGuid, date);
3627 logger.log(logger.HIGH, "Leaving NeverNote.updateListDateChanged");
3630 private void scrollToCurrentGuid() {
3631 //scrollToGuid(currentNoteGuid);
3632 List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
3633 if (selections.size() == 0)
3635 QModelIndex index = selections.get(0);
3636 int row = selections.get(0).row();
3637 String guid = (String)index.model().index(row, Global.noteTableGuidPosition).data();
3640 // Scroll to a particular index item
3641 private void scrollToGuid(String guid) {
3642 if (currentNote == null || guid == null)
3644 if (currentNote.isActive() && Global.showDeleted) {
3645 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
3646 if (!listManager.getNoteIndex().get(i).isActive()) {
3647 currentNote = listManager.getNoteIndex().get(i);
3648 currentNoteGuid = currentNote.getGuid();
3649 i = listManager.getNoteIndex().size();
3654 if (!currentNote.isActive() && !Global.showDeleted) {
3655 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
3656 if (listManager.getNoteIndex().get(i).isActive()) {
3657 currentNote = listManager.getNoteIndex().get(i);
3658 currentNoteGuid = currentNote.getGuid();
3659 i = listManager.getNoteIndex().size();
3665 for (int i=0; i<noteTableView.model().rowCount(); i++) {
3666 index = noteTableView.model().index(i, Global.noteTableGuidPosition);
3667 if (currentNoteGuid.equals(index.data())) {
3668 // noteTableView.setCurrentIndex(index);
3669 noteTableView.selectRow(i);
3670 noteTableView.scrollTo(index, ScrollHint.EnsureVisible); // This should work, but it doesn't
3671 i=listManager.getNoteTableModel().rowCount();
3674 noteTableView.repaint();
3676 // Show/Hide columns
3677 private void showColumns() {
3678 noteTableView.setColumnHidden(Global.noteTableCreationPosition, !Global.isColumnVisible("dateCreated"));
3679 noteTableView.setColumnHidden(Global.noteTableChangedPosition, !Global.isColumnVisible("dateChanged"));
3680 noteTableView.setColumnHidden(Global.noteTableSubjectDatePosition, !Global.isColumnVisible("dateSubject"));
3681 noteTableView.setColumnHidden(Global.noteTableAuthorPosition, !Global.isColumnVisible("author"));
3682 noteTableView.setColumnHidden(Global.noteTableSourceUrlPosition, !Global.isColumnVisible("sourceUrl"));
3683 noteTableView.setColumnHidden(Global.noteTableTagPosition, !Global.isColumnVisible("tags"));
3684 noteTableView.setColumnHidden(Global.noteTableNotebookPosition, !Global.isColumnVisible("notebook"));
3685 noteTableView.setColumnHidden(Global.noteTableSynchronizedPosition, !Global.isColumnVisible("synchronized"));
3686 noteTableView.setColumnHidden(Global.noteTableGuidPosition, !Global.isColumnVisible("guid"));
3687 noteTableView.setColumnHidden(Global.noteTableThumbnailPosition, !Global.isColumnVisible("thumbnail"));
3688 noteTableView.setColumnHidden(Global.noteTableTitlePosition, !Global.isColumnVisible("title"));
3690 // Title color has changed
3691 @SuppressWarnings("unused")
3692 private void titleColorChanged(Integer color) {
3693 logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
3695 QColor backgroundColor = new QColor();
3696 QColor foregroundColor = new QColor(QColor.black);
3697 backgroundColor.setRgb(color);
3699 if (backgroundColor.rgb() == QColor.black.rgb() || backgroundColor.rgb() == QColor.blue.rgb())
3700 foregroundColor.setRgb(QColor.white.rgb());
3702 if (selectedNoteGUIDs.size() == 0)
3703 selectedNoteGUIDs.add(currentNoteGuid);
3705 for (int j=0; j<selectedNoteGUIDs.size(); j++) {
3706 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3707 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3708 if (modelIndex != null) {
3709 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3710 String tableGuid = (String)ix.values().toArray()[0];
3711 if (tableGuid.equals(selectedNoteGUIDs.get(j))) {
3712 for (int k=0; k<Global.noteTableColumnCount; k++) {
3713 listManager.getNoteTableModel().setData(i, k, backgroundColor, Qt.ItemDataRole.BackgroundRole);
3714 listManager.getNoteTableModel().setData(i, k, foregroundColor, Qt.ItemDataRole.ForegroundRole);
3715 listManager.updateNoteTitleColor(selectedNoteGUIDs.get(j), backgroundColor.rgb());
3717 i=listManager.getNoteTableModel().rowCount();
3722 logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
3724 // Wide list was chosen
3725 public void narrowListView() {
3726 saveNoteColumnPositions();
3727 saveNoteIndexWidth();
3729 Global.setListView(Global.View_List_Narrow);
3731 menuBar.wideListView.blockSignals(true);
3732 menuBar.narrowListView.blockSignals(true);
3734 menuBar.wideListView.setChecked(false);
3735 menuBar.narrowListView.setChecked(true);
3737 menuBar.wideListView.blockSignals(false);
3738 menuBar.narrowListView.blockSignals(false);
3740 mainLeftRightSplitter.addWidget(noteTableView);
3741 mainLeftRightSplitter.addWidget(browserWindow);
3742 restoreWindowState(false);
3743 noteTableView.repositionColumns();
3744 noteTableView.resizeColumnWidths();
3745 noteTableView.resizeRowHeights();
3747 noteTableView.load(false);
3748 scrollToCurrentGuid();
3750 public void wideListView() {
3752 saveNoteColumnPositions();
3753 saveNoteIndexWidth();
3754 Global.setListView(Global.View_List_Wide);
3756 menuBar.wideListView.blockSignals(true);
3757 menuBar.narrowListView.blockSignals(true);
3759 menuBar.wideListView.setChecked(true);
3760 menuBar.narrowListView.setChecked(false);
3762 menuBar.wideListView.blockSignals(false);
3763 menuBar.narrowListView.blockSignals(false);
3764 browserIndexSplitter.setVisible(true);
3765 browserIndexSplitter.addWidget(noteTableView);
3766 browserIndexSplitter.addWidget(browserWindow);
3767 restoreWindowState(false);
3768 noteTableView.repositionColumns();
3769 noteTableView.resizeColumnWidths();
3770 noteTableView.resizeRowHeights();
3772 noteTableView.load(false);
3773 scrollToCurrentGuid();
3777 //***************************************************************
3778 //***************************************************************
3779 //** External editor window functions
3780 //***************************************************************
3781 //***************************************************************
3782 private void listDoubleClick() {
3784 if (externalWindows.containsKey(currentNoteGuid)) {
3785 externalWindows.get(currentNoteGuid).raise();
3788 // We have a new external editor to create
3789 QIcon appIcon = new QIcon(iconPath+"nevernote.png");
3790 ExternalBrowse newBrowser = new ExternalBrowse(conn);
3791 newBrowser.setWindowIcon(appIcon);
3792 externalWindows.put(currentNoteGuid, newBrowser);
3793 showEditorButtons(newBrowser.getBrowserWindow());
3794 loadNoteBrowserInformation(newBrowser.getBrowserWindow());
3795 setupBrowserWindowListeners(newBrowser.getBrowserWindow(), false);
3796 newBrowser.windowClosing.connect(this, "externalWindowClosing(String)");
3797 newBrowser.getBrowserWindow().noteSignal.titleChanged.connect(this, "externalWindowTitleEdited(String, String)");
3798 newBrowser.getBrowserWindow().noteSignal.tagsChanged.connect(this, "externalWindowTagsEdited(String, List)");
3799 newBrowser.contentsChanged.connect(this, "saveNoteExternalBrowser(String, String, Boolean, BrowserWindow)");
3801 browserWindow.noteSignal.tagsChanged.connect(newBrowser, "updateTags(String, List)");
3802 browserWindow.noteSignal.titleChanged.connect(newBrowser, "updateTitle(String, String)");
3803 browserWindow.noteSignal.notebookChanged.connect(newBrowser, "updateNotebook(String, String)");
3807 @SuppressWarnings("unused")
3808 private void externalWindowTitleEdited(String guid, String text) {
3809 if (guid.equals(currentNoteGuid)) {
3810 browserWindow.setTitle(text);
3813 @SuppressWarnings({ "rawtypes", "unused" })
3814 private void externalWindowTagsEdited(String guid, List values) {
3815 StringBuffer line = new StringBuffer(100);
3816 for (int i=0; i<values.size(); i++) {
3818 line.append(Global.tagDelimeter+" ");
3819 line.append(values.get(i));
3821 if (guid.equals(currentNoteGuid)) {
3822 browserWindow.setTag(line.toString());
3825 @SuppressWarnings("unused")
3826 private void externalWindowClosing(String guid) {
3827 externalWindows.remove(guid);
3832 //***************************************************************
3833 //***************************************************************
3834 //** These functions deal with Note specific things
3835 //***************************************************************
3836 //***************************************************************
3837 @SuppressWarnings("unused")
3838 private void setNoteDirty() {
3839 logger.log(logger.EXTREME, "Entering NeverNote.setNoteDirty()");
3840 // Find if the note is being edited externally. If it is, update it.
3841 if (externalWindows.containsKey(currentNoteGuid)) {
3842 QTextCodec codec = QTextCodec.codecForName("UTF-8");
3843 QByteArray unicode = codec.fromUnicode(browserWindow.getContent());
3844 ExternalBrowse window = externalWindows.get(currentNoteGuid);
3845 window.getBrowserWindow().getBrowser().setContent(unicode);
3848 // If the note is dirty, then it is unsynchronized by default.
3852 // Set the note as dirty and check if its status is synchronized in the display table
3854 for (int i=0; i<listManager.getUnsynchronizedNotes().size(); i++) {
3855 if (listManager.getUnsynchronizedNotes().get(i).equals(currentNoteGuid))
3859 // If this wasn't already marked as unsynchronized, then we need to update the table
3860 listManager.getNoteTableModel().updateNoteSyncStatus(currentNoteGuid, false);
3861 /* listManager.getUnsynchronizedNotes().add(currentNoteGuid);
3862 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3863 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3864 if (modelIndex != null) {
3865 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3866 String tableGuid = (String)ix.values().toArray()[0];
3867 if (tableGuid.equals(currentNoteGuid)) {
3868 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
3874 logger.log(logger.EXTREME, "Leaving NeverNote.setNoteDirty()");
3876 @SuppressWarnings("unused")
3877 private void saveNoteExternalBrowser(String guid, String content, Boolean save, BrowserWindow browser) {
3878 QTextCodec codec = QTextCodec.codecForName("UTF-8");
3879 QByteArray unicode = codec.fromUnicode(content);
3880 noteCache.remove(guid);
3881 noteCache.put(guid, unicode.toString());
3882 if (guid.equals(currentNoteGuid)) {
3884 browserWindow.getBrowser().setContent(unicode);
3887 thumbnailRunner.addWork("GENERATE "+ guid);
3888 saveNote(guid, browser);
3892 private void saveNote() {
3894 saveNote(currentNoteGuid, browserWindow);
3895 thumbnailRunner.addWork("GENERATE "+ currentNoteGuid);
3899 private void saveNote(String guid, BrowserWindow window) {
3900 logger.log(logger.EXTREME, "Inside NeverNote.saveNote()");
3901 logger.log(logger.EXTREME, "Note is dirty.");
3904 logger.log(logger.EXTREME, "Saving to cache");
3905 QTextCodec codec = QTextCodec.codecForLocale();
3906 // QTextDecoder decoder = codec.makeDecoder();
3907 codec = QTextCodec.codecForName("UTF-8");
3908 QByteArray unicode = codec.fromUnicode(window.getContent());
3909 noteCache.put(guid, unicode.toString());
3911 logger.log(logger.EXTREME, "updating list manager");
3912 listManager.updateNoteContent(guid, window.getContent());
3913 logger.log(logger.EXTREME, "Updating title");
3914 listManager.updateNoteTitle(guid, window.getTitle());
3915 updateListDateChanged();
3917 logger.log(logger.EXTREME, "Looking through note index for refreshed note");
3918 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
3919 if (listManager.getNoteIndex().get(i).getGuid().equals(guid)) {
3920 currentNote = listManager.getNoteIndex().get(i);
3921 i = listManager.getNoteIndex().size();
3926 // Get a note from Evernote (and put it in the browser)
3927 private void refreshEvernoteNote(boolean reload) {
3928 logger.log(logger.HIGH, "Entering NeverNote.refreshEvernoteNote");
3930 if (Global.disableViewing) {
3931 browserWindow.setEnabled(false);
3936 if (Global.showDeleted)
3938 Global.cryptCounter =0;
3939 if (currentNoteGuid.equals("")) {
3940 browserWindow.setReadOnly(true);
3948 browserWindow.loadingData(true);
3950 currentNote = conn.getNoteTable().getNote(currentNoteGuid, true,true,false,false,true);
3951 if (currentNote == null)
3954 loadNoteBrowserInformation(browserWindow);
3957 private void loadNoteBrowserInformation(BrowserWindow browser) {
3958 NoteFormatter formatter = new NoteFormatter(logger, conn, tempFiles);
3959 formatter.setNote(currentNote, Global.pdfPreview());
3960 formatter.setHighlight(listManager.getEnSearch());
3962 if (!noteCache.containsKey(currentNoteGuid) || conn.getNoteTable().isThumbnailNeeded(currentNoteGuid)) {
3963 js = new QByteArray();
3964 // We need to prepend the note with <HEAD></HEAD> or encoded characters are ugly
3965 js.append("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">");
3966 js.append("<style type=\"text/css\">.en-crypt-temp { border-collapse:collapse; border-style:solid; border-color:blue; padding:0.0mm 0.0mm 0.0mm 0.0mm; }</style>");
3967 js.append("<style type=\"text/css\">en-hilight { background-color: rgb(255,255,0) }</style>");
3968 js.append("<style> img { max-width:100%; }</style>");
3969 js.append("<style type=\"text/css\">en-spell { text-decoration: none; border-bottom: dotted 1px #cc0000; }</style>");
3970 js.append("</head>");
3971 formatter.setNote(currentNote, Global.pdfPreview());
3972 js.append(formatter.rebuildNoteHTML());
3973 js.append("</HTML>");
3974 js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml.dtd'>", "");
3975 js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml2.dtd'>", "");
3976 js.replace("<?xml version='1.0' encoding='UTF-8'?>", "");
3977 browser.getBrowser().setContent(js);
3978 noteCache.put(currentNoteGuid, js.toString());
3980 if (formatter.resourceError)
3981 resourceErrorMessage();
3982 readOnly = formatter.readOnly;
3983 inkNote = formatter.inkNote;
3985 readOnlyCache.put(currentNoteGuid, true);
3987 inkNoteCache.put(currentNoteGuid, true);
3989 logger.log(logger.HIGH, "Note content is being pulled from the cache");
3990 String cachedContent = formatter.modifyCachedTodoTags(noteCache.get(currentNoteGuid));
3991 js = new QByteArray(cachedContent);
3992 browser.getBrowser().setContent(js);
3993 if (readOnlyCache.containsKey(currentNoteGuid))
3995 if (inkNoteCache.containsKey(currentNoteGuid))
3998 if (conn.getNoteTable().isThumbnailNeeded(currentNoteGuid)) {
3999 thumbnailHTMLReady(currentNoteGuid, js, Global.calculateThumbnailZoom(js.toString()));
4002 if (readOnly || inkNote)
4003 browser.getBrowser().page().setContentEditable(false); // We don't allow editing of ink notes
4005 browser.getBrowser().page().setContentEditable(true);
4006 browser.setReadOnly(readOnly);
4007 deleteButton.setEnabled(!readOnly);
4008 tagButton.setEnabled(!readOnly);
4009 menuBar.noteDelete.setEnabled(!readOnly);
4010 menuBar.noteTags.setEnabled(!readOnly);
4011 browser.setNote(currentNote);
4013 if (conn.getNotebookTable().isLinked(currentNote.getNotebookGuid())) {
4014 deleteButton.setEnabled(false);
4015 menuBar.notebookDeleteAction.setEnabled(false);
4017 deleteButton.setEnabled(true);
4018 menuBar.notebookDeleteAction.setEnabled(true);
4021 // Build a list of non-closed notebooks
4022 List<Notebook> nbooks = new ArrayList<Notebook>();
4023 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
4024 boolean found=false;
4025 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
4026 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid()))
4030 nbooks.add(listManager.getNotebookIndex().get(i));
4033 // browser.setNotebookList(nbooks);
4035 FilterEditorNotebooks notebookFilter = new FilterEditorNotebooks(conn, logger);
4036 browserWindow.setNotebookList(notebookFilter.getValidNotebooks(currentNote, listManager.getNotebookIndex()));
4038 browser.setTitle(currentNote.getTitle());
4039 browser.setTag(getTagNamesForNote(currentNote));
4040 browser.setAuthor(currentNote.getAttributes().getAuthor());
4042 browser.setAltered(currentNote.getUpdated());
4043 browser.setCreation(currentNote.getCreated());
4044 if (currentNote.getAttributes().getSubjectDate() > 0)
4045 browser.setSubjectDate(currentNote.getAttributes().getSubjectDate());
4047 browser.setSubjectDate(currentNote.getCreated());
4048 browser.setUrl(currentNote.getAttributes().getSourceURL());
4050 // browser.setAllTags(listManager.getTagIndex());
4051 FilterEditorTags tagFilter = new FilterEditorTags(conn, logger);
4052 List<Tag> tagList = tagFilter.getValidTags(currentNote);
4053 browser.setAllTags(tagList);
4055 browser.setCurrentTags(currentNote.getTagNames());
4057 scrollToGuid(currentNoteGuid);
4059 browser.loadingData(false);
4060 if (thumbnailViewer.isActiveWindow())
4063 logger.log(logger.HIGH, "Leaving NeverNote.refreshEvernoteNote");
4065 // Save a generated thumbnail
4066 private void toggleNoteInformation() {
4067 logger.log(logger.HIGH, "Entering NeverNote.toggleNoteInformation");
4068 browserWindow.toggleInformation();
4069 menuBar.noteAttributes.setChecked(browserWindow.isExtended());
4070 Global.saveWindowVisible("noteInformation", browserWindow.isExtended());
4071 logger.log(logger.HIGH, "Leaving NeverNote.toggleNoteInformation");
4073 // Listener triggered when a print button is pressed
4074 @SuppressWarnings("unused")
4075 private void printNote() {
4076 logger.log(logger.HIGH, "Entering NeverNote.printNote");
4078 QPrintDialog dialog = new QPrintDialog();
4079 if (dialog.exec() == QDialog.DialogCode.Accepted.value()) {
4080 QPrinter printer = dialog.printer();
4081 browserWindow.getBrowser().print(printer);
4083 logger.log(logger.HIGH, "Leaving NeverNote.printNote");
4086 // Listener triggered when the email button is pressed
4087 @SuppressWarnings("unused")
4088 private void emailNote() {
4089 logger.log(logger.HIGH, "Entering NeverNote.emailNote");
4091 if (Desktop.isDesktopSupported()) {
4092 Desktop desktop = Desktop.getDesktop();
4094 String text2 = browserWindow.getContentsToEmail();
4095 QUrl url = new QUrl("mailto:");
4096 url.addQueryItem("subject", currentNote.getTitle());
4097 // url.addQueryItem("body", QUrl.toPercentEncoding(text2).toString());
4098 url.addQueryItem("body", text2);
4099 QDesktopServices.openUrl(url);
4103 if (desktop.isSupported(Desktop.Action.MAIL)) {
4104 URI uriMailTo = null;
4106 //String text = browserWindow.getBrowser().page().currentFrame().toPlainText();
4107 String text = browserWindow.getContentsToEmail();
4108 //text = "<b>" +text +"</b>";
4109 uriMailTo = new URI("mailto", "&SUBJECT="+currentNote.getTitle()
4110 +"&BODY=" +text, null);
4111 uriMailTo = new URI("mailto", "&SUBJECT="+currentNote.getTitle()
4112 +"&ATTACHMENT=d:/test.pdf", null);
4113 desktop.mail(uriMailTo);
4114 } catch (URISyntaxException e) {
4115 e.printStackTrace();
4116 } catch (IOException e) {
4117 e.printStackTrace();
4124 logger.log(logger.HIGH, "Leaving NeverNote.emailNote");
4126 // Reindex all notes
4127 @SuppressWarnings("unused")
4128 private void fullReindex() {
4129 logger.log(logger.HIGH, "Entering NeverNote.fullReindex");
4130 indexRunner.addWork("REINDEXALL");
4131 setMessage(tr("Database will be reindexed."));
4132 logger.log(logger.HIGH, "Leaving NeverNote.fullReindex");
4134 // Listener when a user wants to reindex a specific note
4135 @SuppressWarnings("unused")
4136 private void reindexNote() {
4137 logger.log(logger.HIGH, "Entering NeverNote.reindexNote");
4138 for (int i=0; i<selectedNoteGUIDs.size(); i++) {
4139 indexRunner.addWork("REINDEXNOTE "+selectedNoteGUIDs.get(i));
4141 if (selectedNotebookGUIDs.size() > 1)
4142 setMessage(tr("Notes will be reindexed."));
4144 setMessage(tr("Note will be reindexed."));
4145 logger.log(logger.HIGH, "Leaving NeverNote.reindexNote");
4148 @SuppressWarnings("unused")
4149 private void deleteNote() {
4150 logger.log(logger.HIGH, "Entering NeverNote.deleteNote");
4151 if (currentNote == null)
4153 if (currentNoteGuid.equals(""))
4156 // If we are deleting non-trash notes
4157 if (currentNote.isActive()) {
4158 if (Global.verifyDelete()) {
4159 if (QMessageBox.question(this, tr("Confirmation"), tr("Delete selected note(s)?"),
4160 QMessageBox.StandardButton.Yes,
4161 QMessageBox.StandardButton.No)==StandardButton.No.value() && Global.verifyDelete() == true) {
4165 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
4166 selectedNoteGUIDs.add(currentNoteGuid);
4167 for (int i=0; i<selectedNoteGUIDs.size(); i++) {
4168 listManager.deleteNote(selectedNoteGUIDs.get(i));
4171 // If we are deleting from the trash.
4172 if (Global.verifyDelete()) {
4173 if (QMessageBox.question(this, "Confirmation", "Permanently delete selected note(s)?",
4174 QMessageBox.StandardButton.Yes,
4175 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
4179 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
4180 selectedNoteGUIDs.add(currentNoteGuid);
4181 for (int i=selectedNoteGUIDs.size()-1; i>=0; i--) {
4182 for (int j=listManager.getNoteTableModel().rowCount()-1; j>=0; j--) {
4183 QModelIndex modelIndex = listManager.getNoteTableModel().index(j, Global.noteTableGuidPosition);
4184 if (modelIndex != null) {
4185 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4186 String tableGuid = (String)ix.values().toArray()[0];
4187 if (tableGuid.equals(selectedNoteGUIDs.get(i))) {
4188 listManager.getNoteTableModel().removeRow(j);
4193 listManager.expungeNote(selectedNoteGUIDs.get(i));
4196 currentNoteGuid = "";
4197 listManager.loadNotesIndex();
4198 noteIndexUpdated(false);
4199 refreshEvernoteNote(true);
4200 scrollToGuid(currentNoteGuid);
4201 logger.log(logger.HIGH, "Leaving NeverNote.deleteNote");
4204 @SuppressWarnings("unused")
4205 private void addNote() {
4206 logger.log(logger.HIGH, "Inside NeverNote.addNote");
4207 // browserWindow.setEnabled(true);
4208 browserWindow.setReadOnly(false);
4210 Calendar currentTime = new GregorianCalendar();
4211 StringBuffer noteString = new StringBuffer(100);
4212 noteString.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
4213 "<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">\n" +
4216 if (Global.overrideDefaultFont()) {
4217 noteString.append("<font face=\"" +Global.getDefaultFont() +"\" >");
4218 noteString.append("<span style=\"font-size:" +Global.getDefaultFontSize() +"pt;\">");
4219 noteString.append("<br clear=\"none\" />\n");
4220 noteString.append("</span>\n</font>\n");
4222 noteString.append("<br clear=\"none\" />\n");
4223 noteString.append("</en-note>");
4225 Long l = new Long(currentTime.getTimeInMillis());
4226 String randint = new String(Long.toString(l));
4228 // Find a notebook. We first look for a selected notebook (the "All Notebooks" one doesn't count).
4230 // for the first non-archived notebook. Finally, if nothing else we
4231 // pick the first notebook in the list.
4232 String notebook = null;
4233 listManager.getNotebookIndex().get(0).getGuid();
4234 List<QTreeWidgetItem> selectedNotebook = notebookTree.selectedItems();
4235 if (selectedNotebook.size() > 0 && !selectedNotebook.get(0).text(0).equalsIgnoreCase("All Notebooks")) {
4236 QTreeWidgetItem currentSelectedNotebook = selectedNotebook.get(0);
4237 notebook = currentSelectedNotebook.text(2);
4239 boolean found = false;
4240 List<Notebook> goodNotebooks = new ArrayList<Notebook>();
4241 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
4242 boolean match = false;
4243 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
4244 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid())) {
4246 j = listManager.getArchiveNotebookIndex().size();
4250 goodNotebooks.add(listManager.getNotebookIndex().get(i).deepCopy());
4252 // Now we have a list of good notebooks, so we can look for the default
4254 for (int i=0; i<goodNotebooks.size(); i++) {
4255 if (goodNotebooks.get(i).isDefaultNotebook()) {
4256 notebook = goodNotebooks.get(i).getGuid();
4258 i = goodNotebooks.size();
4262 if (goodNotebooks.size() > 0 && !found)
4263 notebook = goodNotebooks.get(0).getGuid();
4266 notebook = listManager.getNotebookIndex().get(0).getGuid();
4269 Note newNote = new Note();
4270 newNote.setUpdateSequenceNum(0);
4271 newNote.setGuid(randint);
4272 newNote.setNotebookGuid(notebook);
4273 newNote.setTitle("");
4274 newNote.setContent(noteString.toString());
4275 newNote.setDeleted(0);
4276 newNote.setCreated(System.currentTimeMillis());
4277 newNote.setUpdated(System.currentTimeMillis());
4278 newNote.setActive(true);
4279 NoteAttributes na = new NoteAttributes();
4280 na.setLatitude(0.0);
4281 na.setLongitude(0.0);
4282 na.setAltitude(0.0);
4283 newNote.setAttributes(new NoteAttributes());
4284 newNote.setTagGuids(new ArrayList<String>());
4285 newNote.setTagNames(new ArrayList<String>());
4287 // If new notes are to be created based upon the selected tags, then we need to assign the tags
4288 if (Global.newNoteWithSelectedTags()) {
4289 List<QTreeWidgetItem> selections = tagTree.selectedItems();
4290 QTreeWidgetItem currentSelection;
4291 for (int i=0; i<selections.size(); i++) {
4292 currentSelection = selections.get(i);
4293 newNote.getTagGuids().add(currentSelection.text(2));
4294 newNote.getTagNames().add(currentSelection.text(0));
4298 conn.getNoteTable().addNote(newNote, true);
4299 listManager.getUnsynchronizedNotes().add(newNote.getGuid());
4300 listManager.addNote(newNote);
4301 // noteTableView.insertRow(newNote, true, -1);
4303 currentNote = newNote;
4304 currentNoteGuid = currentNote.getGuid();
4305 refreshEvernoteNote(true);
4306 listManager.countNotebookResults(listManager.getNoteIndex());
4307 browserWindow.titleLabel.setFocus();
4308 browserWindow.titleLabel.selectAll();
4309 // notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
4311 // If the window is hidden, then we want to popup this in an external window &
4314 logger.log(logger.HIGH, "Leaving NeverNote.addNote");
4316 // Restore a note from the trash;
4317 @SuppressWarnings("unused")
4318 private void restoreNote() {
4320 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
4321 selectedNoteGUIDs.add(currentNoteGuid);
4322 for (int i=0; i<selectedNoteGUIDs.size(); i++) {
4323 listManager.restoreNote(selectedNoteGUIDs.get(i));
4325 currentNoteGuid = "";
4326 listManager.loadNotesIndex();
4327 noteIndexUpdated(false);
4330 // Search a note for specific txt
4331 @SuppressWarnings("unused")
4332 private void findText() {
4334 find.setFocusOnTextField();
4336 @SuppressWarnings("unused")
4337 private void doFindText() {
4338 browserWindow.getBrowser().page().findText(find.getText(), find.getFlags());
4341 @SuppressWarnings("unused")
4342 private void updateNoteTitle(String guid, String title) {
4343 listManager.setNoteSynchronized(guid, false);
4345 // Signal received that note content has changed. Normally we just need the guid to remove
4346 // it from the cache.
4347 @SuppressWarnings("unused")
4348 private void invalidateNoteCache(String guid, String content) {
4349 String v = noteCache.remove(guid);
4350 if (content != null && !noteDirty) {
4351 //noteCache.put(guid, content);
4353 if (guid.equals(currentNoteGuid) && !noteDirty)
4354 refreshEvernoteNote(true);
4356 // Signal received that a note guid has changed
4357 @SuppressWarnings("unused")
4358 private void noteGuidChanged(String oldGuid, String newGuid) {
4359 if (noteCache.containsKey(oldGuid)) {
4360 String cache = noteCache.get(oldGuid);
4361 noteCache.put(newGuid, cache);
4362 noteCache.remove(oldGuid);
4364 listManager.updateNoteGuid(oldGuid, newGuid, false);
4365 if (currentNoteGuid.equals(oldGuid)) {
4366 if (currentNote != null)
4367 currentNote.setGuid(newGuid);
4368 currentNoteGuid = newGuid;
4370 if (externalWindows.containsKey(oldGuid)) {
4371 ExternalBrowse b = externalWindows.get(oldGuid);
4372 externalWindows.remove(oldGuid);
4373 b.getBrowserWindow().getNote().setGuid(newGuid);
4374 externalWindows.put(newGuid, b);
4376 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
4377 if (listManager.getNoteIndex().get(i).getGuid().equals(newGuid)) {
4378 noteTableView.proxyModel.addGuid(newGuid);
4379 i=listManager.getNoteIndex().size();
4382 if (listManager.getNoteTableModel().titleColors.containsKey(oldGuid)) {
4383 int color = listManager.getNoteTableModel().titleColors.get(oldGuid);
4384 listManager.getNoteTableModel().titleColors.put(newGuid, color);
4385 listManager.getNoteTableModel().titleColors.remove(oldGuid);
4389 // Toggle the note editor button bar
4390 private void toggleEditorButtonBar() {
4391 if (browserWindow.buttonsVisible) {
4392 browserWindow.hideButtons();
4393 menuBar.showEditorBar.setChecked(browserWindow.buttonsVisible);
4394 // Global.saveWindowVisible("editorButtonBar", browserWindow.buttonsVisible);
4396 browserWindow.buttonsVisible = true;
4397 showEditorButtons(browserWindow);
4399 Global.saveWindowVisible("editorButtonBar", browserWindow.buttonsVisible);
4401 // Show editor buttons
4402 private void showEditorButtons(BrowserWindow browser) {
4403 browser.buttonLayout.setVisible(true);
4404 browser.undoAction.setVisible(false);
4406 browser.undoButton.setVisible(false);
4408 browser.undoAction.setVisible(Global.isEditorButtonVisible("undo"));
4409 browser.redoAction.setVisible(Global.isEditorButtonVisible("redo"));
4410 browser.cutAction.setVisible(Global.isEditorButtonVisible("cut"));
4411 browser.copyAction.setVisible(Global.isEditorButtonVisible("copy"));
4412 browser.pasteAction.setVisible(Global.isEditorButtonVisible("paste"));
4413 browser.strikethroughAction.setVisible(Global.isEditorButtonVisible("strikethrough"));
4414 browser.underlineAction.setVisible(Global.isEditorButtonVisible("underline"));
4415 browser.boldAction.setVisible(Global.isEditorButtonVisible("bold"));
4416 browser.italicAction.setVisible(Global.isEditorButtonVisible("italic"));
4417 browser.hlineAction.setVisible(Global.isEditorButtonVisible("hline"));
4418 browser.indentAction.setVisible(Global.isEditorButtonVisible("indent"));
4419 browser.outdentAction.setVisible(Global.isEditorButtonVisible("outdent"));
4420 browser.bulletListAction.setVisible(Global.isEditorButtonVisible("bulletList"));
4421 browser.numberListAction.setVisible(Global.isEditorButtonVisible("numberList"));
4422 browser.fontListAction.setVisible(Global.isEditorButtonVisible("font"));
4423 browser.fontSizeAction.setVisible(Global.isEditorButtonVisible("fontSize"));
4424 browser.fontColorAction.setVisible(Global.isEditorButtonVisible("fontColor"));
4425 browser.fontHilightAction.setVisible(Global.isEditorButtonVisible("fontHilight"));
4426 browser.leftAlignAction.setVisible(Global.isEditorButtonVisible("alignLeft"));
4427 browser.centerAlignAction.setVisible(Global.isEditorButtonVisible("alignCenter"));
4428 browser.rightAlignAction.setVisible(Global.isEditorButtonVisible("alignRight"));
4429 browser.spellCheckAction.setVisible(Global.isEditorButtonVisible("spellCheck"));
4430 browser.todoAction.setVisible(Global.isEditorButtonVisible("todo"));
4432 private void duplicateNote(String guid) {
4434 Note oldNote = conn.getNoteTable().getNote(guid, true, true, false, false, false);
4435 List<Resource> resList = conn.getNoteTable().noteResourceTable.getNoteResources(guid, true);
4436 oldNote.setContent(conn.getNoteTable().getNoteContentBinary(guid));
4437 oldNote.setResources(resList);
4438 duplicateNote(oldNote);
4440 private void duplicateNote(Note oldNote) {
4442 // Now that we have a good notebook guid, we need to move the conflicting note
4443 // to the local notebook
4444 Calendar currentTime = new GregorianCalendar();
4445 Long l = new Long(currentTime.getTimeInMillis());
4446 String newGuid = new String(Long.toString(l));
4448 Note newNote = oldNote.deepCopy();
4449 newNote.setUpdateSequenceNum(0);
4450 newNote.setGuid(newGuid);
4451 newNote.setDeleted(0);
4452 newNote.setActive(true);
4453 List<Resource> resList = oldNote.getResources();
4454 if (resList == null)
4455 resList = new ArrayList<Resource>();
4457 for (int i=0; i<resList.size(); i++) {
4459 while (l == prevGuid) {
4460 currentTime = new GregorianCalendar();
4461 l = new Long(currentTime.getTimeInMillis());
4464 String newResGuid = new String(Long.toString(l));
4465 resList.get(i).setNoteGuid(newGuid);
4466 resList.get(i).setGuid(newResGuid);
4467 resList.get(i).setUpdateSequenceNum(0);
4468 resList.get(i).setActive(true);
4469 conn.getNoteTable().noteResourceTable.saveNoteResource(new Resource(resList.get(i).deepCopy()), true);
4471 newNote.setResources(resList);
4472 listManager.addNote(newNote);
4473 conn.getNoteTable().addNote(newNote, true);
4474 listManager.getUnsynchronizedNotes().add(newNote.getGuid());
4475 noteTableView.insertRow(newNote, true, -1);
4476 listManager.countNotebookResults(listManager.getNoteIndex());
4480 @SuppressWarnings("unused")
4481 private void allNotes() {
4482 clearAttributeFilter();
4483 clearNotebookFilter();
4484 clearSavedSearchFilter();
4487 searchField.clear();
4488 if (Global.mimicEvernoteInterface) {
4489 notebookTree.selectGuid("");
4491 notebookTreeSelection();
4494 @SuppressWarnings("unused")
4495 private void mergeNotes() {
4496 logger.log(logger.HIGH, "Merging notes");
4499 String masterGuid = null;
4500 List<String> sources = new ArrayList<String>();
4502 for (int i=0; i<noteTableView.selectionModel().selectedRows().size(); i++) {
4503 int r = noteTableView.selectionModel().selectedRows().get(i).row();
4504 index = noteTableView.proxyModel.index(r, Global.noteTableGuidPosition);
4505 SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
4507 masterGuid = (String)ix.values().toArray()[0];
4509 sources.add((String)ix.values().toArray()[0]);
4512 logger.log(logger.EXTREME, "Master guid=" +masterGuid);
4513 logger.log(logger.EXTREME, "Children count: "+sources.size());
4514 mergeNoteContents(masterGuid, sources);
4515 currentNoteGuid = masterGuid;
4516 noteIndexUpdated(false);
4517 refreshEvernoteNote(true);
4520 private void mergeNoteContents(String targetGuid, List<String> sources) {
4521 Note target = conn.getNoteTable().getNote(targetGuid, true, false, false, false, false);
4522 String newContent = target.getContent();
4523 newContent = newContent.replace("</en-note>", "<br></br>");
4525 for (int i=0; i<sources.size(); i++) {
4526 Note source = conn.getNoteTable().getNote(sources.get(i), true, true, false, false, false);
4527 if (source.isSetTitle()) {
4528 newContent = newContent +("<table bgcolor=\"lightgrey\"><tr><td><font size=\"6\"><b>" +source.getTitle() +"</b></font></td></tr></table>");
4530 String sourceContent = source.getContent();
4531 logger.log(logger.EXTREME, "Merging contents into note");
4532 logger.log(logger.EXTREME, sourceContent);
4533 logger.log(logger.EXTREME, "End of content");
4534 int startOfNote = sourceContent.indexOf("<en-note>");
4535 sourceContent = sourceContent.substring(startOfNote+9);
4536 int endOfNote = sourceContent.indexOf("</en-note>");
4537 sourceContent = sourceContent.substring(0,endOfNote);
4538 newContent = newContent + sourceContent;
4539 logger.log(logger.EXTREME, "New note content");
4540 logger.log(logger.EXTREME, newContent);
4541 logger.log(logger.EXTREME, "End of content");
4542 for (int j=0; j<source.getResourcesSize(); j++) {
4543 logger.log(logger.EXTREME, "Reassigning resource: "+source.getResources().get(j).getGuid());
4544 Resource r = source.getResources().get(j);
4545 Resource newRes = conn.getNoteTable().noteResourceTable.getNoteResource(r.getGuid(), true);
4547 Calendar currentTime = new GregorianCalendar();
4548 Long l = new Long(currentTime.getTimeInMillis());
4552 while (l == prevGuid) {
4553 currentTime = new GregorianCalendar();
4554 l = new Long(currentTime.getTimeInMillis());
4556 String newResGuid = new String(Long.toString(l));
4557 newRes.setNoteGuid(targetGuid);
4558 newRes.setGuid(newResGuid);
4559 newRes.setUpdateSequenceNum(0);
4560 newRes.setActive(true);
4561 conn.getNoteTable().noteResourceTable.saveNoteResource(newRes, true);
4564 logger.log(logger.EXTREME, "Updating note");
4565 conn.getNoteTable().updateNoteContent(targetGuid, newContent +"</en-note>");
4566 for (int i=0; i<sources.size(); i++) {
4567 logger.log(logger.EXTREME, "Deleting note " +sources.get(i));
4568 listManager.deleteNote(sources.get(i));
4570 logger.log(logger.EXTREME, "Exiting merge note");
4572 // A resource within a note has had a guid change
4573 @SuppressWarnings("unused")
4574 private void noteResourceGuidChanged(String noteGuid, String oldGuid, String newGuid) {
4575 if (!oldGuid.equals(newGuid))
4576 Global.resourceMap.put(oldGuid, newGuid);
4578 // View a thumbnail of the note
4579 public void thumbnailView() {
4581 String thumbnailName = Global.getFileManager().getResDirPath("thumbnail-" + currentNoteGuid + ".png");
4582 QFile thumbnail = new QFile(thumbnailName);
4583 if (!thumbnail.exists()) {
4585 QImage img = new QImage();
4586 img.loadFromData(conn.getNoteTable().getThumbnail(currentNoteGuid));
4587 thumbnailViewer.setThumbnail(img);
4589 thumbnailViewer.setThumbnail(thumbnailName);
4590 if (!thumbnailViewer.isVisible())
4591 thumbnailViewer.showFullScreen();
4593 // An error happened while saving a note. Inform the user
4594 @SuppressWarnings("unused")
4595 private void saveRunnerError(String guid, String msg) {
4597 String title = "*Unknown*";
4598 for (int i=0; i<listManager.getMasterNoteIndex().size(); i++) {
4599 if (listManager.getMasterNoteIndex().get(i).getGuid().equals(guid)) {
4600 title = listManager.getMasterNoteIndex().get(i).getTitle();
4601 i=listManager.getMasterNoteIndex().size();
4604 msg = "An error has happened while saving the note \"" +title+
4605 "\".\n\nThis is probably due to a document that is too complex for Nevernote to process. "+
4606 "As a result, changes to the note may not be saved properly in the database."+
4607 "\n\nA cached copy is being preserved so you can recover any data, but data may" +
4608 "\nbe lost. Please review the note to recover any critical data before restarting.";
4610 QMessageBox.information(this, tr("Error Saving Note"), tr(msg));
4613 private void thumbnailHTMLReady(String guid, QByteArray html, Integer zoom) {
4614 logger.log(logger.HIGH, "Entering thumnailHTMLReady()");
4615 logger.log(logger.HIGH, "Thumbnail ready for " +guid);
4616 // Find an idle preview object
4617 for (int i=0; i<thumbGenerators.size(); i++) {
4618 if (thumbGenerators.get(i).mutex.tryLock()) {
4619 logger.log(logger.EXTREME, "Idle generator found - loading thumbnail for " +guid);
4620 thumbGenerators.get(i).loadContent(guid, html, zoom);
4624 if (thumbGenerators.size() >= 1) {
4625 logger.log(logger.EXTREME, "No available thumbnail generators. Aborting " +guid);
4629 logger.log(logger.EXTREME, "Creating new thumbnail generator " +guid);
4630 Thumbnailer preview = new Thumbnailer(logger, conn, listManager, thumbnailRunner);
4631 thumbGenerators.add(preview);
4633 if (preview.mutex.tryLock()) {
4634 logger.log(logger.EXTREME, "Loading thumbnail for " +guid);
4635 preview.loadContent(guid, html, zoom);
4637 logger.log(logger.HIGH, "Exiting thumnailHTMLReady()");
4642 //**********************************************************
4643 //**********************************************************
4644 //* Online user actions
4645 //**********************************************************
4646 //**********************************************************
4647 private void setupOnlineMenu() {
4648 if (!Global.isConnected) {
4649 menuBar.noteOnlineHistoryAction.setEnabled(false);
4652 menuBar.noteOnlineHistoryAction.setEnabled(true);
4655 @SuppressWarnings("unused")
4656 private void viewNoteHistory() {
4657 if (currentNoteGuid == null || currentNoteGuid.equals(""))
4659 if (currentNote.getUpdateSequenceNum() == 0) {
4660 setMessage(tr("Note has never been synchronized."));
4661 QMessageBox.information(this, tr("Error"), tr("This note has never been sent to Evernote, so there is no history."));
4665 setMessage(tr("Getting Note History"));
4667 Note currentOnlineNote = null;
4670 if (Global.isPremium())
4671 versions = syncRunner.noteStore.listNoteVersions(syncRunner.authToken, currentNoteGuid);
4673 versions = new ArrayList<NoteVersionId>();
4674 currentOnlineNote = syncRunner.noteStore.getNote(syncRunner.authToken, currentNoteGuid, true, true, false, false);
4675 } catch (EDAMUserException e) {
4676 setMessage("EDAMUserException: " +e.getMessage());
4678 } catch (EDAMSystemException e) {
4679 setMessage("EDAMSystemException: " +e.getMessage());
4681 } catch (EDAMNotFoundException e) {
4682 setMessage(tr("Note not found on server."));
4683 QMessageBox.information(this, "Error", "This note could not be found on Evernote's servers.");
4685 } catch (TException e) {
4686 setMessage("EDAMTransactionException: " +e.getMessage());
4690 // If we've gotten this far, we have a good note.
4691 if (historyWindow == null) {
4692 historyWindow = new OnlineNoteHistory(logger, conn);
4693 historyWindow.historyCombo.activated.connect(this, "reloadHistoryWindow(String)");
4694 historyWindow.restoreAsNew.clicked.connect(this, "restoreHistoryNoteAsNew()");
4695 historyWindow.restore.clicked.connect(this, "restoreHistoryNote()");
4697 historyWindow.historyCombo.clear();
4699 boolean isDirty = conn.getNoteTable().isNoteDirty(currentNoteGuid);
4700 if (currentNote.getUpdateSequenceNum() != currentOnlineNote.getUpdateSequenceNum())
4702 historyWindow.setCurrent(isDirty);
4704 loadHistoryWindowContent(currentOnlineNote);
4705 historyWindow.load(versions);
4706 setMessage(tr("History retrieved"));
4708 historyWindow.exec();
4710 private Note reloadHistoryWindow(String selection) {
4712 String fmt = Global.getDateFormat() + " " + Global.getTimeFormat();
4713 String dateTimeFormat = new String(fmt);
4714 SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);
4718 for (int i=0; i<versions.size(); i++) {
4719 StringBuilder versionDate = new StringBuilder(simple.format(versions.get(i).getSaved()));
4720 if (versionDate.toString().equals(selection))
4724 if (index > -1 || selection.indexOf("Current") > -1) {
4725 Note historyNote = null;
4728 usn = versions.get(index).getUpdateSequenceNum();
4729 historyNote = syncRunner.noteStore.getNoteVersion(syncRunner.authToken, currentNoteGuid, usn, true, true, true);
4731 historyNote = syncRunner.noteStore.getNote(syncRunner.authToken, currentNoteGuid, true,true,true,true);
4732 } catch (EDAMUserException e) {
4733 setMessage("EDAMUserException: " +e.getMessage());
4736 } catch (EDAMSystemException e) {
4737 setMessage("EDAMSystemException: " +e.getMessage());
4740 } catch (EDAMNotFoundException e) {
4741 setMessage("EDAMNotFoundException: " +e.getMessage());
4744 } catch (TException e) {
4745 setMessage("EDAMTransactionException: " +e.getMessage());
4751 if (historyNote != null)
4752 historyWindow.setContent(historyNote);
4758 private void loadHistoryWindowContent(Note note) {
4759 note.setUpdateSequenceNum(0);
4760 historyWindow.setContent(note);
4762 @SuppressWarnings("unused")
4763 private void restoreHistoryNoteAsNew() {
4764 setMessage(tr("Restoring as new note."));
4765 duplicateNote(reloadHistoryWindow(historyWindow.historyCombo.currentText()));
4766 setMessage(tr("Note has been restored as a new note."));
4768 @SuppressWarnings("unused")
4769 private void restoreHistoryNote() {
4770 setMessage(tr("Restoring note."));
4771 Note n = reloadHistoryWindow(historyWindow.historyCombo.currentText());
4772 conn.getNoteTable().expungeNote(n.getGuid(), true, false);
4775 for (int i=0; i<n.getResourcesSize(); i++) {
4776 n.getResources().get(i).setActive(true);
4777 conn.getNoteTable().noteResourceTable.saveNoteResource(n.getResources().get(i), true);
4779 listManager.addNote(n);
4780 conn.getNoteTable().addNote(n, true);
4781 refreshEvernoteNote(true);
4782 setMessage(tr("Note has been restored."));
4787 //**********************************************************
4788 //**********************************************************
4789 //* XML Modifying methods
4790 //**********************************************************
4791 //**********************************************************
4792 // An error has happended fetching a resource. let the user know
4793 private void resourceErrorMessage() {
4796 QMessageBox.information(this, tr("DOUGH!!!"), tr("Well, this is embarrassing."+
4797 "\n\nSome attachments or images for this note appear to be missing from my database.\n"+
4798 "In a perfect world this wouldn't happen, but it has.\n" +
4799 "It is embarasing when a program like me, designed to save all your\n"+
4800 "precious data, has a problem finding data.\n\n" +
4801 "I guess life isn't fair, but I'll survive. Somehow...\n\n" +
4802 "In the mean time, I'm not going to let you make changes to this note.\n" +
4803 "Don't get angry. I'm doing it to prevent you from messing up\n"+
4804 "this note on the Evernote servers. Sorry."+
4805 "\n\nP.S. You might want to re-synchronize to see if it corrects this problem.\nWho knows, you might get lucky."));
4807 browserWindow.setReadOnly(true);
4813 //**********************************************************
4814 //**********************************************************
4816 //**********************************************************
4817 //**********************************************************
4818 // We should now do a sync with Evernote
4819 private void syncTimer() {
4820 logger.log(logger.EXTREME, "Entering NeverNote.syncTimer()");
4821 syncRunner.syncNeeded = true;
4822 syncRunner.disableUploads = Global.disableUploads;
4824 logger.log(logger.EXTREME, "Leaving NeverNote.syncTimer()");
4826 private void syncStart() {
4827 logger.log(logger.EXTREME, "Entering NeverNote.syncStart()");
4829 if (!syncRunning && Global.isConnected) {
4830 syncRunner.setConnected(true);
4831 syncRunner.setKeepRunning(Global.keepRunning);
4832 syncRunner.syncDeletedContent = Global.synchronizeDeletedContent();
4834 if (syncThreadsReady > 0) {
4835 indexRunner.interrupt = true;
4836 saveNoteIndexWidth();
4837 saveNoteColumnPositions();
4838 if (syncRunner.addWork("SYNC")) {
4840 syncRunner.syncNeeded = true;
4845 logger.log(logger.EXTREME, "Leaving NeverNote.syncStart");
4847 @SuppressWarnings("unused")
4848 private void syncThreadComplete(Boolean refreshNeeded) {
4849 setMessage(tr("Finalizing Synchronization"));
4851 syncRunning = false;
4852 syncRunner.syncNeeded = false;
4853 synchronizeAnimationTimer.stop();
4854 synchronizeButton.setIcon(new QIcon(iconPath+"synchronize.png"));
4856 if (currentNote == null) {
4857 currentNote = conn.getNoteTable().getNote(currentNoteGuid, false, false, false, false, true);
4859 listManager.setUnsynchronizedNotes(conn.getNoteTable().getUnsynchronizedGUIDs());
4860 noteIndexUpdated(false);
4861 noteTableView.selectionModel().blockSignals(true);
4862 scrollToGuid(currentNoteGuid);
4863 noteTableView.selectionModel().blockSignals(false);
4864 refreshEvernoteNote(false);
4865 scrollToGuid(currentNoteGuid);
4867 if (!syncRunner.error)
4868 setMessage(tr("Synchronization Complete"));
4870 setMessage(tr("Synchronization completed with errors. Please check the log for details."));
4871 logger.log(logger.MEDIUM, "Sync complete.");
4873 public void saveUploadAmount(long t) {
4874 Global.saveUploadAmount(t);
4876 public void saveUserInformation(User user) {
4877 Global.saveUserInformation(user);
4879 public void saveEvernoteUpdateCount(int i) {
4880 Global.saveEvernoteUpdateCount(i);
4882 public void refreshLists() {
4883 logger.log(logger.EXTREME, "Entering NeverNote.refreshLists");
4885 listManager.refreshLists(currentNote, noteDirty, browserWindow.getContent());
4886 tagIndexUpdated(true);
4887 notebookIndexUpdated();
4888 savedSearchIndexUpdated();
4889 listManager.loadNotesIndex();
4891 noteTableView.selectionModel().blockSignals(true);
4892 noteIndexUpdated(true);
4893 noteTableView.selectionModel().blockSignals(false);
4894 logger.log(logger.EXTREME, "Leaving NeverNote.refreshLists");
4898 @SuppressWarnings("unused")
4899 private void authTimer() {
4900 Calendar cal = Calendar.getInstance();
4902 // If we are not connected let's get out of here
4903 if (!Global.isConnected)
4906 // If this is the first time through, then we need to set this
4907 // if (syncRunner.authRefreshTime == 0 || cal.getTimeInMillis() > syncRunner.authRefreshTime)
4908 // syncRunner.authRefreshTime = cal.getTimeInMillis();
4910 // long now = new Date().getTime();
4911 // if (now > Global.authRefreshTime && Global.isConnected) {
4912 syncRunner.authRefreshNeeded = true;
4916 @SuppressWarnings("unused")
4917 private void authRefreshComplete(boolean goodSync) {
4918 logger.log(logger.EXTREME, "Entering NeverNote.authRefreshComplete");
4919 Global.isConnected = syncRunner.isConnected;
4921 // authTimer.start((int)syncRunner.authTimeRemaining/4);
4922 authTimer.start(1000*60*15);
4923 logger.log(logger.LOW, "Authentication token has been renewed");
4924 // setMessage("Authentication token has been renewed.");
4926 authTimer.start(1000*60*5);
4927 logger.log(logger.LOW, "Authentication token renew has failed - retry in 5 minutes.");
4928 // setMessage("Authentication token renew has failed - retry in 5 minutes.");
4930 logger.log(logger.EXTREME, "Leaving NeverNote.authRefreshComplete");
4934 @SuppressWarnings("unused")
4935 private synchronized void indexTimer() {
4936 logger.log(logger.EXTREME, "Index timer activated. Sync running="+syncRunning);
4939 if (!indexDisabled && indexRunner.idle) {
4940 indexRunner.addWork("SCAN");
4942 logger.log(logger.EXTREME, "Leaving neverNote index timer");
4945 @SuppressWarnings("unused")
4946 private void indexStarted() {
4947 setMessage(tr("Indexing notes"));
4949 @SuppressWarnings("unused")
4950 private void indexComplete() {
4951 setMessage(tr("Index complete"));
4953 @SuppressWarnings("unused")
4954 private synchronized void toggleNoteIndexing() {
4955 logger.log(logger.HIGH, "Entering NeverNote.toggleIndexing");
4956 indexDisabled = !indexDisabled;
4958 setMessage(tr("Indexing is now enabled."));
4960 setMessage(tr("Indexing is now disabled."));
4961 menuBar.disableIndexing.setChecked(indexDisabled);
4962 logger.log(logger.HIGH, "Leaving NeverNote.toggleIndexing");
4965 @SuppressWarnings("unused")
4966 private void threadMonitorCheck() {
4971 alive = listManager.threadCheck(Global.tagCounterThreadId);
4974 if (tagDeadCount > MAX)
4975 QMessageBox.information(this, tr("A thread his died."), tr("It appears as the tag counter thread has died. I recommend "+
4976 "checking stopping NeverNote, saving the logs for later viewing, and restarting. Sorry."));
4980 alive = listManager.threadCheck(Global.notebookCounterThreadId);
4982 notebookThreadDeadCount++;
4983 QMessageBox.information(this, tr("A thread his died."), tr("It appears as the notebook counter thread has died. I recommend "+
4984 "checking stopping NeverNote, saving the logs for later viewing, and restarting. Sorry."));
4986 notebookThreadDeadCount=0;
4988 alive = listManager.threadCheck(Global.trashCounterThreadId);
4991 QMessageBox.information(this, tr("A thread his died."), ("It appears as the trash counter thread has died. I recommend "+
4992 "checking stopping NeverNote, saving the logs for later viewing, and restarting. Sorry."));
4996 alive = listManager.threadCheck(Global.saveThreadId);
4998 saveThreadDeadCount++;
4999 QMessageBox.information(this, tr("A thread his died."), tr("It appears as the note saver thread has died. I recommend "+
5000 "checking stopping NeverNote, saving the logs for later viewing, and restarting. Sorry."));
5002 saveThreadDeadCount=0;
5004 if (!syncThread.isAlive()) {
5005 syncThreadDeadCount++;
5006 QMessageBox.information(this, tr("A thread his died."), tr("It appears as the synchronization thread has died. I recommend "+
5007 "checking stopping NeverNote, saving the logs for later viewing, and restarting. Sorry."));
5009 syncThreadDeadCount=0;
5011 if (!indexThread.isAlive()) {
5012 indexThreadDeadCount++;
5013 QMessageBox.information(this, tr("A thread his died."), tr("It appears as the index thread has died. I recommend "+
5014 "checking stopping NeverNote, saving the logs for later viewing, and restarting. Sorry."));
5016 indexThreadDeadCount=0;
5021 private void thumbnailTimer() {
5022 if (Global.enableThumbnails() && conn.getNoteTable().getThumbnailNeededCount() > 1) {
5023 thumbnailTimer.setInterval(10*1000);
5024 thumbnailRunner.addWork("SCAN");
5026 thumbnailTimer.setInterval(60*1000);
5030 //**************************************************
5031 //* Backup & Restore
5032 //**************************************************
5033 @SuppressWarnings("unused")
5034 private void databaseBackup() {
5035 QFileDialog fd = new QFileDialog(this);
5036 fd.setFileMode(FileMode.AnyFile);
5037 fd.setConfirmOverwrite(true);
5038 fd.setWindowTitle(tr("Backup Database"));
5039 fd.setFilter(tr("NeverNote Export (*.nnex);;All Files (*.*)"));
5040 fd.setAcceptMode(AcceptMode.AcceptSave);
5041 fd.setDirectory(System.getProperty("user.home"));
5042 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
5048 setMessage(tr("Backing up database"));
5050 // conn.backupDatabase(Global.getUpdateSequenceNumber(), Global.getSequenceDate());
5052 ExportData noteWriter = new ExportData(conn, true);
5053 String fileName = fd.selectedFiles().get(0);
5055 if (!fileName.endsWith(".nnex"))
5056 fileName = fileName +".nnex";
5057 noteWriter.exportData(fileName);
5058 setMessage(tr("Database backup completed."));
5063 @SuppressWarnings("unused")
5064 private void databaseRestore() {
5065 if (QMessageBox.question(this, tr("Confirmation"),
5066 tr("This is used to restore a database from backups.\n" +
5067 "It is HIGHLY recommened that this only be used to populate\n" +
5068 "an empty database. Restoring into a database that\n already has data" +
5069 " can cause problems.\n\nAre you sure you want to continue?"),
5070 QMessageBox.StandardButton.Yes,
5071 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
5076 QFileDialog fd = new QFileDialog(this);
5077 fd.setFileMode(FileMode.ExistingFile);
5078 fd.setConfirmOverwrite(true);
5079 fd.setWindowTitle(tr("Restore Database"));
5080 fd.setFilter(tr("NeverNote Export (*.nnex);;All Files (*.*)"));
5081 fd.setAcceptMode(AcceptMode.AcceptOpen);
5082 fd.setDirectory(System.getProperty("user.home"));
5083 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
5089 setMessage(tr("Restoring database"));
5090 ImportData noteReader = new ImportData(conn, true);
5091 noteReader.importData(fd.selectedFiles().get(0));
5093 if (noteReader.lastError != 0) {
5094 setMessage(noteReader.getErrorMessage());
5095 logger.log(logger.LOW, "Restore problem: " +noteReader.lastError);
5100 listManager.loadNoteTitleColors();
5102 refreshEvernoteNote(true);
5103 setMessage(tr("Database has been restored."));
5106 @SuppressWarnings("unused")
5107 private void exportNotes() {
5108 QFileDialog fd = new QFileDialog(this);
5109 fd.setFileMode(FileMode.AnyFile);
5110 fd.setConfirmOverwrite(true);
5111 fd.setWindowTitle(tr("Backup Database"));
5112 fd.setFilter(tr("NeverNote Export (*.nnex);;All Files (*.*)"));
5113 fd.setAcceptMode(AcceptMode.AcceptSave);
5114 fd.setDirectory(System.getProperty("user.home"));
5115 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
5121 setMessage(tr("Exporting Notes"));
5124 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
5125 selectedNoteGUIDs.add(currentNoteGuid);
5127 ExportData noteWriter = new ExportData(conn, false, selectedNoteGUIDs);
5128 String fileName = fd.selectedFiles().get(0);
5130 if (!fileName.endsWith(".nnex"))
5131 fileName = fileName +".nnex";
5132 noteWriter.exportData(fileName);
5133 setMessage(tr("Export completed."));
5139 @SuppressWarnings("unused")
5140 private void importNotes() {
5141 QFileDialog fd = new QFileDialog(this);
5142 fd.setFileMode(FileMode.ExistingFile);
5143 fd.setConfirmOverwrite(true);
5144 fd.setWindowTitle(tr("Import Notes"));
5145 fd.setFilter(tr("NeverNote Export (*.nnex);;All Files (*.*)"));
5146 fd.setAcceptMode(AcceptMode.AcceptOpen);
5147 fd.setDirectory(System.getProperty("user.home"));
5148 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
5154 setMessage("Importing Notes");
5157 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
5158 selectedNoteGUIDs.add(currentNoteGuid);
5160 ImportData noteReader = new ImportData(conn, false);
5161 String fileName = fd.selectedFiles().get(0);
5163 if (!fileName.endsWith(".nnex"))
5164 fileName = fileName +".nnex";
5165 if (selectedNotebookGUIDs != null && selectedNotebookGUIDs.size() > 0)
5166 noteReader.setNotebookGuid(selectedNotebookGUIDs.get(0));
5168 noteReader.setNotebookGuid(listManager.getNotebookIndex().get(0).getGuid());
5170 noteReader.importData(fileName);
5172 if (noteReader.lastError != 0) {
5173 setMessage(noteReader.getErrorMessage());
5174 logger.log(logger.LOW, "Import problem: " +noteReader.lastError);
5179 listManager.loadNoteTitleColors();
5181 refreshEvernoteNote(false);
5182 setMessage(tr("Notes have been imported."));
5185 setMessage("Import completed.");
5192 //**************************************************
5193 //* Duplicate a note
5194 //**************************************************
5195 @SuppressWarnings("unused")
5196 private void duplicateNote() {
5198 duplicateNote(currentNoteGuid);
5203 //**************************************************
5205 //**************************************************
5206 public void setupFolderImports() {
5207 List<WatchFolderRecord> records = conn.getWatchFolderTable().getAll();
5209 if (importKeepWatcher == null)
5210 importKeepWatcher = new QFileSystemWatcher();
5211 if (importDeleteWatcher == null) {
5212 importDeleteWatcher = new QFileSystemWatcher();
5213 for (int i=0; i<records.size(); i++) {
5214 if (!records.get(i).keep)
5215 folderImportDelete(records.get(i).folder);
5221 // importKeepWatcher.addPath(records.get(i).folder.replace('\\', '/'));
5222 for (int i=0; i<records.size(); i++) {
5223 if (records.get(i).keep)
5224 importKeepWatcher.addPath(records.get(i).folder);
5226 importDeleteWatcher.addPath(records.get(i).folder);
5229 importKeepWatcher.directoryChanged.connect(this, "folderImportKeep(String)");
5230 importDeleteWatcher.directoryChanged.connect(this, "folderImportDelete(String)");
5232 // Look at the files already there so we don't import them again if a new file is created
5233 if (importedFiles == null) {
5234 importedFiles = new ArrayList<String>();
5235 for (int j=0; j<records.size(); j++) {
5236 QDir dir = new QDir(records.get(j).folder);
5237 List<QFileInfo> list = dir.entryInfoList();
5238 for (int k=0; k<list.size(); k++) {
5239 if (list.get(k).isFile())
5240 importedFiles.add(list.get(k).absoluteFilePath());
5245 public void folderImport() {
5246 List<WatchFolderRecord> recs = conn.getWatchFolderTable().getAll();
5247 WatchFolder dialog = new WatchFolder(recs, listManager.getNotebookIndex());
5249 if (!dialog.okClicked())
5252 // We have some sort of update.
5253 if (importKeepWatcher.directories().size() > 0)
5254 importKeepWatcher.removePaths(importKeepWatcher.directories());
5255 if (importDeleteWatcher.directories().size() > 0)
5256 importDeleteWatcher.removePaths(importDeleteWatcher.directories());
5258 conn.getWatchFolderTable().expungeAll();
5259 // Start building from the table
5260 for (int i=0; i<dialog.table.rowCount(); i++) {
5261 QTableWidgetItem item = dialog.table.item(i, 0);
5262 String dir = item.text();
5263 item = dialog.table.item(i, 1);
5264 String notebook = item.text();
5265 item = dialog.table.item(i, 2);
5267 if (item.text().equalsIgnoreCase("Keep"))
5272 String guid = conn.getNotebookTable().findNotebookByName(notebook);
5273 conn.getWatchFolderTable().addWatchFolder(dir, guid, keep, 0);
5275 setupFolderImports();
5278 public void folderImportKeep(String dirName) throws NoSuchAlgorithmException {
5280 String whichOS = System.getProperty("os.name");
5281 if (whichOS.contains("Windows"))
5282 dirName = dirName.replace('/','\\');
5284 FileImporter importer = new FileImporter(logger, conn);
5286 QDir dir = new QDir(dirName);
5287 List<QFileInfo> list = dir.entryInfoList();
5288 String notebook = conn.getWatchFolderTable().getNotebook(dirName);
5290 for (int i=0; i<list.size(); i++){
5292 boolean redundant = false;
5293 // Check if we've already imported this one or if it existed before
5294 for (int j=0; j<importedFiles.size(); j++) {
5295 if (importedFiles.get(j).equals(list.get(i).absoluteFilePath()))
5300 importer.setFileInfo(list.get(i));
5301 importer.setFileName(list.get(i).absoluteFilePath());
5304 if (list.get(i).isFile() && importer.isValidType()) {
5306 if (!importer.importFile()) {
5307 // If we can't get to the file, it is probably locked. We'll try again later.
5308 logger.log(logger.LOW, "Unable to save externally edited file. Saving for later.");
5309 importFilesKeep.add(list.get(i).absoluteFilePath());
5313 Note newNote = importer.getNote();
5314 newNote.setNotebookGuid(notebook);
5315 newNote.setTitle(dir.at(i));
5316 listManager.addNote(newNote);
5317 conn.getNoteTable().addNote(newNote, true);
5318 listManager.getUnsynchronizedNotes().add(newNote.getGuid());
5319 noteTableView.insertRow(newNote, true, -1);
5320 listManager.updateNoteContent(newNote.getGuid(), importer.getNoteContent());
5321 listManager.countNotebookResults(listManager.getNoteIndex());
5322 importedFiles.add(list.get(i).absoluteFilePath());
5330 public void folderImportDelete(String dirName) {
5332 String whichOS = System.getProperty("os.name");
5333 if (whichOS.contains("Windows"))
5334 dirName = dirName.replace('/','\\');
5336 FileImporter importer = new FileImporter(logger, conn);
5337 QDir dir = new QDir(dirName);
5338 List<QFileInfo> list = dir.entryInfoList();
5339 String notebook = conn.getWatchFolderTable().getNotebook(dirName);
5341 for (int i=0; i<list.size(); i++){
5342 importer.setFileInfo(list.get(i));
5343 importer.setFileName(list.get(i).absoluteFilePath());
5345 if (list.get(i).isFile() && importer.isValidType()) {
5347 if (!importer.importFile()) {
5348 // If we can't get to the file, it is probably locked. We'll try again later.
5349 logger.log(logger.LOW, "Unable to save externally edited file. Saving for later.");
5350 importFilesKeep.add(list.get(i).absoluteFilePath());
5354 Note newNote = importer.getNote();
5355 newNote.setNotebookGuid(notebook);
5356 newNote.setTitle(dir.at(i));
5357 listManager.addNote(newNote);
5358 conn.getNoteTable().addNote(newNote, true);
5359 listManager.getUnsynchronizedNotes().add(newNote.getGuid());
5360 noteTableView.insertRow(newNote, true, -1);
5361 listManager.updateNoteContent(newNote.getGuid(), importer.getNoteContent());
5362 listManager.countNotebookResults(listManager.getNoteIndex());
5363 dir.remove(dir.at(i));
5369 //**************************************************
5371 //**************************************************
5372 private void externalFileEdited(String fileName) throws NoSuchAlgorithmException {
5373 logger.log(logger.HIGH, "Entering exernalFileEdited");
5375 // Strip URL prefix and base dir path
5376 String dPath = FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath());
5377 String name = fileName.replace(dPath, "");
5378 int pos = name.lastIndexOf('.');
5381 guid = guid.substring(0,pos);
5383 pos = name.lastIndexOf(Global.attachmentNameDelimeter);
5385 guid = name.substring(0, pos);
5388 QFile file = new QFile(fileName);
5389 if (!file.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly))) {
5390 // If we can't get to the file, it is probably locked. We'll try again later.
5391 logger.log(logger.LOW, "Unable to save externally edited file. Saving for later.");
5392 externalFiles.add(fileName);
5395 QByteArray binData = file.readAll();
5397 if (binData.size() == 0) {
5398 // If we can't get to the file, it is probably locked. We'll try again later.
5399 logger.log(logger.LOW, "Unable to save externally edited file. Saving for later.");
5400 externalFiles.add(fileName);
5404 Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
5406 r = conn.getNoteTable().noteResourceTable.getNoteResource(Global.resourceMap.get(guid), true);
5407 if (r == null || r.getData() == null || r.getData().getBody() == null)
5409 String oldHash = Global.byteArrayToHexString(r.getData().getBodyHash());
5410 MessageDigest md = MessageDigest.getInstance("MD5");
5411 md.update(binData.toByteArray());
5412 byte[] hash = md.digest();
5413 String newHash = Global.byteArrayToHexString(hash);
5414 if (r.getNoteGuid().equalsIgnoreCase(currentNoteGuid)) {
5415 updateResourceContentHash(browserWindow, r.getGuid(), oldHash, newHash);
5417 if (externalWindows.containsKey(r.getNoteGuid())) {
5418 updateResourceContentHash(externalWindows.get(r.getNoteGuid()).getBrowserWindow(),
5419 r.getGuid(), oldHash, newHash);
5421 conn.getNoteTable().updateResourceContentHash(r.getNoteGuid(), oldHash, newHash);
5422 Data data = r.getData();
5423 data.setBody(binData.toByteArray());
5424 data.setBodyHash(hash);
5425 logger.log(logger.LOW, "externalFileEdited: " +data.getSize() +" bytes");
5427 conn.getNoteTable().noteResourceTable.updateNoteResource(r,true);
5429 if (r.getNoteGuid().equals(currentNoteGuid)) {
5430 QWebSettings.setMaximumPagesInCache(0);
5431 QWebSettings.setObjectCacheCapacities(0, 0, 0);
5432 refreshEvernoteNote(true);
5433 browserWindow.getBrowser().triggerPageAction(WebAction.Reload);
5436 if (externalWindows.containsKey(r.getNoteGuid())) {
5437 QWebSettings.setMaximumPagesInCache(0);
5438 QWebSettings.setObjectCacheCapacities(0, 0, 0);
5439 externalWindows.get(r.getNoteGuid()).getBrowserWindow().getBrowser().triggerPageAction(WebAction.Reload);
5443 logger.log(logger.HIGH, "Exiting externalFielEdited");
5445 // This is a timer event that tries to save any external files that were edited. This
5446 // is only needed if we couldn't save a file earlier.
5447 public void externalFileEditedSaver() {
5448 for (int i=externalFiles.size()-1; i>=0; i--) {
5450 logger.log(logger.MEDIUM, "Trying to save " +externalFiles.get(i));
5451 externalFileEdited(externalFiles.get(i));
5452 externalFiles.remove(i);
5453 } catch (NoSuchAlgorithmException e) {e.printStackTrace();}
5455 for (int i=0; i<importFilesKeep.size(); i++) {
5457 logger.log(logger.MEDIUM, "Trying to save " +importFilesKeep.get(i));
5458 folderImportKeep(importFilesKeep.get(i));
5459 importFilesKeep.remove(i);
5460 } catch (NoSuchAlgorithmException e) {e.printStackTrace();}
5462 for (int i=0; i<importFilesDelete.size(); i++) {
5463 logger.log(logger.MEDIUM, "Trying to save " +importFilesDelete.get(i));
5464 folderImportDelete(importFilesDelete.get(i));
5465 importFilesDelete.remove(i);
5472 // If an attachment on the current note was edited, we need to update the current notes's hash
5473 // Update a note content's hash. This happens if a resource is edited outside of NN
5474 public void updateResourceContentHash(BrowserWindow browser, String guid, String oldHash, String newHash) {
5475 int position = browserWindow.getContent().indexOf("en-tag=\"en-media\" guid=\""+guid+"\" type=");
5477 for (;position>-1;) {
5478 endPos = browser.getContent().indexOf(">", position+1);
5479 String oldSegment = browser.getContent().substring(position,endPos);
5480 int hashPos = oldSegment.indexOf("hash=\"");
5481 int hashEnd = oldSegment.indexOf("\"", hashPos+7);
5482 String hash = oldSegment.substring(hashPos+6, hashEnd);
5483 if (hash.equalsIgnoreCase(oldHash)) {
5484 String newSegment = oldSegment.replace(oldHash, newHash);
5485 String content = browser.getContent().substring(0,position) +
5487 browser.getContent().substring(endPos);
5488 browser.getBrowser().setContent(new QByteArray(content));;
5491 position = browser.getContent().indexOf("en-tag=\"en-media\" guid=\""+guid+"\" type=", position+1);
5496 //*************************************************
5497 //* Minimize to tray
5498 //*************************************************
5500 public void changeEvent(QEvent e) {
5501 if (e.type() == QEvent.Type.WindowStateChange) {
5502 if (isMinimized() && Global.showTrayIcon()) {
5504 QTimer.singleShot(10, this, "hide()");
5508 windowMaximized = true;
5510 windowMaximized = false;
5514 //*************************************************
5515 //* Check database userid & passwords
5516 //*************************************************
5517 private static boolean databaseCheck(String url,String userid, String userPassword, String cypherPassword) {
5518 Connection connection;
5521 Class.forName("org.h2.Driver");
5522 } catch (ClassNotFoundException e1) {
5523 e1.printStackTrace();
5528 String passwordString = null;
5529 if (cypherPassword==null || cypherPassword.trim().equals(""))
5530 passwordString = userPassword;
5532 passwordString = cypherPassword+" "+userPassword;
5533 connection = DriverManager.getConnection(url,userid,passwordString);
5534 } catch (SQLException e) {
5539 } catch (SQLException e) {
5540 e.printStackTrace();