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.QMainWindow;
111 import com.trolltech.qt.gui.QMenu;
112 import com.trolltech.qt.gui.QMessageBox;
113 import com.trolltech.qt.gui.QMessageBox.StandardButton;
114 import com.trolltech.qt.gui.QPainter;
115 import com.trolltech.qt.gui.QPalette.ColorRole;
116 import com.trolltech.qt.gui.QPixmap;
117 import com.trolltech.qt.gui.QPrintDialog;
118 import com.trolltech.qt.gui.QPrinter;
119 import com.trolltech.qt.gui.QSizePolicy;
120 import com.trolltech.qt.gui.QSizePolicy.Policy;
121 import com.trolltech.qt.gui.QSpinBox;
122 import com.trolltech.qt.gui.QSplashScreen;
123 import com.trolltech.qt.gui.QSplitter;
124 import com.trolltech.qt.gui.QStatusBar;
125 import com.trolltech.qt.gui.QSystemTrayIcon;
126 import com.trolltech.qt.gui.QTableWidgetItem;
127 import com.trolltech.qt.gui.QTextEdit;
128 import com.trolltech.qt.gui.QToolBar;
129 import com.trolltech.qt.gui.QTreeWidgetItem;
130 import com.trolltech.qt.network.QNetworkAccessManager;
131 import com.trolltech.qt.network.QNetworkReply;
132 import com.trolltech.qt.network.QNetworkRequest;
133 import com.trolltech.qt.webkit.QWebPage.WebAction;
134 import com.trolltech.qt.webkit.QWebSettings;
136 import cx.fbn.nevernote.config.InitializationException;
137 import cx.fbn.nevernote.config.StartupConfig;
138 import cx.fbn.nevernote.dialog.AccountDialog;
139 import cx.fbn.nevernote.dialog.ConfigDialog;
140 import cx.fbn.nevernote.dialog.DBEncryptDialog;
141 import cx.fbn.nevernote.dialog.DatabaseLoginDialog;
142 import cx.fbn.nevernote.dialog.DatabaseStatus;
143 import cx.fbn.nevernote.dialog.FindDialog;
144 import cx.fbn.nevernote.dialog.IgnoreSync;
145 import cx.fbn.nevernote.dialog.LogFileDialog;
146 import cx.fbn.nevernote.dialog.LoginDialog;
147 import cx.fbn.nevernote.dialog.NotebookArchive;
148 import cx.fbn.nevernote.dialog.NotebookEdit;
149 import cx.fbn.nevernote.dialog.OnlineNoteHistory;
150 import cx.fbn.nevernote.dialog.PublishNotebook;
151 import cx.fbn.nevernote.dialog.SavedSearchEdit;
152 import cx.fbn.nevernote.dialog.SetIcon;
153 import cx.fbn.nevernote.dialog.ShareNotebook;
154 import cx.fbn.nevernote.dialog.StackNotebook;
155 import cx.fbn.nevernote.dialog.TagEdit;
156 import cx.fbn.nevernote.dialog.ThumbnailViewer;
157 import cx.fbn.nevernote.dialog.UpgradeAvailableDialog;
158 import cx.fbn.nevernote.dialog.WatchFolder;
159 import cx.fbn.nevernote.filters.FilterEditorNotebooks;
160 import cx.fbn.nevernote.filters.FilterEditorTags;
161 import cx.fbn.nevernote.gui.AttributeTreeWidget;
162 import cx.fbn.nevernote.gui.BrowserWindow;
163 import cx.fbn.nevernote.gui.DateAttributeFilterTable;
164 import cx.fbn.nevernote.gui.ExternalBrowse;
165 import cx.fbn.nevernote.gui.MainMenuBar;
166 import cx.fbn.nevernote.gui.NotebookTreeWidget;
167 import cx.fbn.nevernote.gui.SavedSearchTreeWidget;
168 import cx.fbn.nevernote.gui.TableView;
169 import cx.fbn.nevernote.gui.TagTreeWidget;
170 import cx.fbn.nevernote.gui.Thumbnailer;
171 import cx.fbn.nevernote.gui.TrashTreeWidget;
172 import cx.fbn.nevernote.gui.controls.QuotaProgressBar;
173 import cx.fbn.nevernote.sql.DatabaseConnection;
174 import cx.fbn.nevernote.sql.WatchFolderRecord;
175 import cx.fbn.nevernote.threads.IndexRunner;
176 import cx.fbn.nevernote.threads.SyncRunner;
177 import cx.fbn.nevernote.threads.ThumbnailRunner;
178 import cx.fbn.nevernote.utilities.AESEncrypter;
179 import cx.fbn.nevernote.utilities.ApplicationLogger;
180 import cx.fbn.nevernote.utilities.FileImporter;
181 import cx.fbn.nevernote.utilities.FileUtils;
182 import cx.fbn.nevernote.utilities.ListManager;
183 import cx.fbn.nevernote.utilities.SyncTimes;
184 import cx.fbn.nevernote.xml.ExportData;
185 import cx.fbn.nevernote.xml.ImportData;
186 import cx.fbn.nevernote.xml.NoteFormatter;
189 public class NeverNote extends QMainWindow{
191 QStatusBar statusBar; // Application status bar
193 DatabaseConnection conn;
195 MainMenuBar menuBar; // Main menu bar
196 FindDialog find; // Text search in note dialog
197 List<String> emitLog; // Messages displayed in the status bar;
198 QSystemTrayIcon trayIcon; // little tray icon
199 QMenu trayMenu; // System tray menu
200 QAction trayExitAction; // Exit the application
201 QAction trayShowAction; // toggle the show/hide action
202 QAction trayAddNoteAction; // Add a note from the system tray
203 QNetworkAccessManager versionChecker; // Used when checking for new versions
205 NotebookTreeWidget notebookTree; // List of notebooks
206 AttributeTreeWidget attributeTree; // List of note attributes
207 TagTreeWidget tagTree; // list of user created tags
208 SavedSearchTreeWidget savedSearchTree; // list of saved searches
209 TrashTreeWidget trashTree; // Trashcan
210 TableView noteTableView; // List of notes (the widget).
212 public BrowserWindow browserWindow; // Window containing browser & labels
213 public QToolBar toolBar; // The tool bar under the menu
214 QComboBox searchField; // search filter bar on the toolbar;
215 boolean searchPerformed = false; // Search was done?
216 QuotaProgressBar quotaBar; // The current quota usage
218 ApplicationLogger logger;
219 List<String> selectedNotebookGUIDs; // List of notebook GUIDs
220 List<String> selectedTagGUIDs; // List of selected tag GUIDs
221 List<String> selectedNoteGUIDs; // List of selected notes
222 String selectedSavedSearchGUID; // Currently selected saved searches
223 private final HashMap<String, ExternalBrowse> externalWindows; // Notes being edited by an external window;
225 NoteFilter filter; // Note filter
226 String currentNoteGuid; // GUID of the current note
227 Note currentNote; // The currently viewed note
228 boolean noteDirty; // Has the note been changed?
229 boolean inkNote; // if this is an ink note, it is read only
230 boolean readOnly; // Is this note read-only?
233 ListManager listManager; // DB runnable task
235 List<QTemporaryFile> tempFiles; // Array of temporary files;
237 QTimer indexTimer; // timer to start the index thread
238 IndexRunner indexRunner; // thread to index notes
241 QTimer syncTimer; // Sync on an interval
242 QTimer syncDelayTimer; // Sync delay to free up database
243 SyncRunner syncRunner; // thread to do a sync.
244 QThread syncThread; // Thread which talks to evernote
245 ThumbnailRunner thumbnailRunner; // Runner for thumbnail thread
246 QThread thumbnailThread; // Thread that generates pretty pictures
247 QTimer saveTimer; // Timer to save note contents
249 QTimer authTimer; // Refresh authentication
250 QTimer externalFileSaveTimer; // Save files altered externally
251 QTimer thumbnailTimer; // Wakeup & scan for thumbnails
252 List<String> externalFiles; // External files to save later
253 List<String> importFilesKeep; // Auto-import files to save later
254 List<String> importFilesDelete; // Auto-import files to save later
256 int indexTime; // how often to try and index
257 boolean indexRunning; // Is indexing running?
258 boolean indexDisabled; // Is indexing disabled?
260 int syncThreadsReady; // number of sync threads that are free
261 int syncTime; // Sync interval
262 boolean syncRunning; // Is sync running?
263 boolean automaticSync; // do sync automatically?
264 QTreeWidgetItem attributeTreeSelected;
266 QAction prevButton; // Go to the previous item viewed
267 QAction nextButton; // Go to the next item in the history
268 QAction downButton; // Go to the next item in the list
269 QAction upButton; // Go to the prev. item in the list;
270 QAction synchronizeButton; // Synchronize with Evernote
271 QAction allNotesButton; // Reset & view all notes
272 QTimer synchronizeAnimationTimer; // Timer to change animation button
273 int synchronizeIconAngle; // Used to rotate sync icon
274 QAction printButton; // Print Button
275 QAction tagButton; // Tag edit button
276 QAction attributeButton; // Attribute information button
277 QAction emailButton; // Email button
278 QAction deleteButton; // Delete button
279 QAction newButton; // new Note Button;
280 QSpinBox zoomSpinner; // Zoom zoom
281 QAction searchClearButton; // Clear the search field
283 QSplitter mainLeftRightSplitter; // main splitter for left/right side
284 QSplitter leftSplitter1; // first left hand splitter
285 QSplitter browserIndexSplitter; // splitter between note index & note text
287 QFileSystemWatcher importKeepWatcher; // Watch & keep auto-import
288 QFileSystemWatcher importDeleteWatcher; // Watch & Delete auto-import
289 List<String> importedFiles; // History of imported files (so we don't import twice)
291 OnlineNoteHistory historyWindow; // online history window
292 List<NoteVersionId> versions; // history versions
294 QTimer threadMonitorTimer; // Timer to watch threads.
295 int dbThreadDeadCount=0; // number of consecutive dead times for the db thread
296 int syncThreadDeadCount=0; // number of consecutive dead times for the sync thread
297 int indexThreadDeadCount=0; // number of consecutive dead times for the index thread
298 int notebookThreadDeadCount=0; // number of consecutive dead times for the notebook thread
299 int tagDeadCount=0; // number of consecutive dead times for the tag thread
300 int trashDeadCount=0; // number of consecutive dead times for the trash thread
301 int saveThreadDeadCount=0; // number of consecutive dead times for the save thread
302 boolean disableTagThreadCheck=false;
303 boolean disableNotebookThreadCheck=false;
304 boolean disableTrashThreadCheck=false;
305 boolean disableSaveThreadCheck=false;
306 boolean disableSyncThreadCheck=false;
307 boolean disableIndexThreadCheck=false;
309 HashMap<String, String> noteCache; // Cash of note content
310 HashMap<String, Boolean> readOnlyCache; // List of cashe notes that are read-only
311 HashMap<String, Boolean> inkNoteCache; // List of cache notes that are ink notes
312 List<String> historyGuids; // GUIDs of previously viewed items
313 int historyPosition; // Position within the viewed items
314 boolean fromHistory; // Is this from the history queue?
315 String trashNoteGuid; // Guid to restore / set into or out of trash to save position
316 List<Thumbnailer> thumbGenerators; // generate preview image
317 ThumbnailViewer thumbnailViewer; // View preview thumbnail;
318 boolean encryptOnShutdown; // should I encrypt when I close?
319 boolean decryptOnShutdown; // should I decrypt on shutdown;
320 String encryptCipher; // What cipher should I use?
321 Signal0 minimizeToTray;
322 boolean windowMaximized = false; // Keep track of the window state for restores
323 List<String> pdfReadyQueue; // Queue of PDFs that are ready to be rendered.
324 List<QPixmap> syncIcons; // Array of icons used in sync animation
325 private boolean closeAction = false; // Used to say when to close or when to minimize
326 private static Logger log = Logger.getLogger(NeverNote.class);
327 private String saveLastPath; // last path we used
330 String iconPath = new String("classpath:cx/fbn/nevernote/icons/");
333 //***************************************************************
334 //***************************************************************
335 //** Constructor & main entry point
336 //***************************************************************
337 //***************************************************************
338 // Application Constructor
339 @SuppressWarnings("static-access")
340 public NeverNote(DatabaseConnection dbConn) {
342 if (conn.getConnection() == null) {
343 String msg = new String(tr("Unable to connect to the database.\n\nThe most probable reason is that some other process\n" +
344 "is accessing the database or NeverNote is already running.\n\n" +
345 "Please end any other process or shutdown the other NeverNote before starting.\n\nExiting program."));
347 QMessageBox.critical(null, tr("Database Connection Error") ,msg);
351 thread().setPriority(Thread.MAX_PRIORITY);
353 logger = new ApplicationLogger("nevernote.log");
354 logger.log(logger.HIGH, "Starting Application");
356 decryptOnShutdown = false;
357 encryptOnShutdown = false;
358 conn.checkDatabaseVersion();
362 // Start building the invalid XML tables
363 Global.invalidElements = conn.getInvalidXMLTable().getInvalidElements();
364 List<String> elements = conn.getInvalidXMLTable().getInvalidAttributeElements();
366 for (int i=0; i<elements.size(); i++) {
367 Global.invalidAttributes.put(elements.get(i), conn.getInvalidXMLTable().getInvalidAttributes(elements.get(i)));
370 logger.log(logger.EXTREME, "Starting GUI build");
372 QTranslator nevernoteTranslator = new QTranslator();
373 nevernoteTranslator.load(Global.getFileManager().getTranslateFilePath("nevernote_" + QLocale.system().name() + ".qm"));
374 QApplication.instance().installTranslator(nevernoteTranslator);
376 Global.originalPalette = QApplication.palette();
377 QApplication.setStyle(Global.getStyle());
378 if (Global.useStandardPalette())
379 QApplication.setPalette(QApplication.style().standardPalette());
380 setWindowTitle("NeverNote");
382 mainLeftRightSplitter = new QSplitter();
383 setCentralWidget(mainLeftRightSplitter);
384 leftSplitter1 = new QSplitter();
385 leftSplitter1.setOrientation(Qt.Orientation.Vertical);
387 browserIndexSplitter = new QSplitter();
388 browserIndexSplitter.setOrientation(Qt.Orientation.Vertical);
390 //* Setup threads & thread timers
391 int indexRunnerCount = Global.getIndexThreads();
392 indexRunnerCount = 1;
393 QThreadPool.globalInstance().setMaxThreadCount(indexRunnerCount+5); // increase max thread count
395 logger.log(logger.EXTREME, "Building list manager");
396 listManager = new ListManager(conn, logger);
398 logger.log(logger.EXTREME, "Building index runners & timers");
399 indexRunner = new IndexRunner("indexRunner.log",
400 Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(),
401 Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
402 indexThread = new QThread(indexRunner, "Index Thread");
403 indexRunner.indexAttachmentsLocally = Global.indexAttachmentsLocally();
406 synchronizeAnimationTimer = new QTimer();
407 synchronizeAnimationTimer.timeout.connect(this, "updateSyncButton()");
409 indexTimer = new QTimer();
410 indexTime = 1000*Global.getIndexThreadSleepInterval();
411 indexTimer.start(indexTime); // Start indexing timer
412 indexTimer.timeout.connect(this, "indexTimer()");
413 indexDisabled = false;
414 indexRunning = false;
416 logger.log(logger.EXTREME, "Setting sync thread & timers");
418 syncRunner = new SyncRunner("syncRunner.log",
419 Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(),
420 Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
421 syncTime = new SyncTimes().timeValue(Global.getSyncInterval());
422 syncTimer = new QTimer();
423 syncTimer.timeout.connect(this, "syncTimer()");
424 syncRunner.status.message.connect(this, "setMessage(String)");
425 syncRunner.syncSignal.finished.connect(this, "syncThreadComplete(Boolean)");
426 syncRunner.syncSignal.errorDisconnect.connect(this, "remoteErrorDisconnect()");
429 automaticSync = true;
430 syncTimer.start(syncTime*60*1000);
432 automaticSync = false;
435 syncRunner.setEvernoteUpdateCount(Global.getEvernoteUpdateCount());
436 syncThread = new QThread(syncRunner, "Synchronization Thread");
440 logger.log(logger.EXTREME, "Starting thumnail thread");
441 pdfReadyQueue = new ArrayList<String>();
442 thumbnailRunner = new ThumbnailRunner("thumbnailRunner.log",
443 Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(),
444 Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
445 thumbnailThread = new QThread(thumbnailRunner, "Thumbnail Thread");
446 thumbnailRunner.noteSignal.thumbnailPageReady.connect(this, "thumbnailHTMLReady(String,QByteArray,Integer)");
447 thumbnailThread.start();
448 thumbGenerators = new ArrayList<Thumbnailer>();
449 thumbnailTimer = new QTimer();
450 thumbnailTimer.timeout.connect(this, "thumbnailTimer()");
452 thumbnailTimer.setInterval(500*1000); // Thumbnail every minute
453 thumbnailTimer.start();
455 logger.log(logger.EXTREME, "Starting authentication timer");
456 authTimer = new QTimer();
457 authTimer.timeout.connect(this, "authTimer()");
458 authTimer.start(1000*60*15);
459 syncRunner.syncSignal.authRefreshComplete.connect(this, "authRefreshComplete(boolean)");
461 logger.log(logger.EXTREME, "Setting save note timer");
462 saveTimer = new QTimer();
463 saveTimer.timeout.connect(this, "saveNote()");
464 if (Global.getAutoSaveInterval() > 0) {
465 saveTimer.setInterval(1000*60*Global.getAutoSaveInterval());
468 listManager.saveRunner.noteSignals.noteSaveRunnerError.connect(this, "saveRunnerError(String, String)");
470 logger.log(logger.EXTREME, "Starting external file monitor timer");
471 externalFileSaveTimer = new QTimer();
472 externalFileSaveTimer.timeout.connect(this, "externalFileEditedSaver()");
473 externalFileSaveTimer.setInterval(1000*5); // save every 5 seconds;
474 externalFiles = new ArrayList<String>();
475 importFilesDelete = new ArrayList<String>();
476 importFilesKeep = new ArrayList<String>();
477 externalFileSaveTimer.start();
479 notebookTree = new NotebookTreeWidget(conn);
480 attributeTree = new AttributeTreeWidget();
481 tagTree = new TagTreeWidget(conn);
482 savedSearchTree = new SavedSearchTreeWidget();
483 trashTree = new TrashTreeWidget();
484 noteTableView = new TableView(logger, listManager);
486 QGridLayout leftGrid = new QGridLayout();
487 leftSplitter1.setLayout(leftGrid);
488 leftGrid.addWidget(notebookTree, 1, 1);
489 leftGrid.addWidget(tagTree,2,1);
490 leftGrid.addWidget(attributeTree,3,1);
491 leftGrid.addWidget(savedSearchTree,4,1);
492 leftGrid.addWidget(trashTree, 5, 1);
494 // Setup the browser window
495 noteCache = new HashMap<String,String>();
496 readOnlyCache = new HashMap<String, Boolean>();
497 inkNoteCache = new HashMap<String, Boolean>();
498 browserWindow = new BrowserWindow(conn);
500 mainLeftRightSplitter.addWidget(leftSplitter1);
501 mainLeftRightSplitter.addWidget(browserIndexSplitter);
503 if (Global.getListView() == Global.View_List_Wide) {
504 browserIndexSplitter.addWidget(noteTableView);
505 browserIndexSplitter.addWidget(browserWindow);
507 mainLeftRightSplitter.addWidget(noteTableView);
508 mainLeftRightSplitter.addWidget(browserWindow);
511 searchField = new QComboBox();
512 searchField.setEditable(true);
513 searchField.activatedIndex.connect(this, "searchFieldChanged()");
514 searchField.setDuplicatesEnabled(false);
515 searchField.editTextChanged.connect(this,"searchFieldTextChanged(String)");
517 quotaBar = new QuotaProgressBar();
519 // Setup the thumbnail viewer
520 thumbnailViewer = new ThumbnailViewer();
521 thumbnailViewer.upArrow.connect(this, "upAction()");
522 thumbnailViewer.downArrow.connect(this, "downAction()");
523 thumbnailViewer.leftArrow.connect(this, "nextViewedAction()");
524 thumbnailViewer.rightArrow.connect(this, "previousViewedAction()");
526 //Setup external browser manager
527 externalWindows = new HashMap<String, ExternalBrowse>();
529 listManager.loadNotesIndex();
530 initializeNotebookTree();
532 initializeSavedSearchTree();
533 attributeTree.itemClicked.connect(this, "attributeTreeClicked(QTreeWidgetItem, Integer)");
534 attributeTreeSelected = null;
535 initializeNoteTable();
537 selectedNoteGUIDs = new ArrayList<String>();
538 statusBar = new QStatusBar();
539 setStatusBar(statusBar);
540 menuBar = new MainMenuBar(this);
541 emitLog = new ArrayList<String>();
543 tagTree.setDeleteAction(menuBar.tagDeleteAction);
544 tagTree.setEditAction(menuBar.tagEditAction);
545 tagTree.setAddAction(menuBar.tagAddAction);
546 tagTree.setIconAction(menuBar.tagIconAction);
547 tagTree.setVisible(Global.isWindowVisible("tagTree"));
548 tagTree.noteSignal.tagsAdded.connect(this, "tagsAdded(String, String)");
549 menuBar.hideTags.setChecked(Global.isWindowVisible("tagTree"));
550 listManager.tagSignal.listChanged.connect(this, "reloadTagTree()");
552 notebookTree.setDeleteAction(menuBar.notebookDeleteAction);
553 notebookTree.setEditAction(menuBar.notebookEditAction);
554 notebookTree.setAddAction(menuBar.notebookAddAction);
555 notebookTree.setIconAction(menuBar.notebookIconAction);
556 notebookTree.setStackAction(menuBar.notebookStackAction);
557 notebookTree.setPublishAction(menuBar.notebookPublishAction);
558 notebookTree.setShareAction(menuBar.notebookShareAction);
559 notebookTree.setVisible(Global.isWindowVisible("notebookTree"));
560 notebookTree.noteSignal.notebookChanged.connect(this, "updateNoteNotebook(String, String)");
561 notebookTree.noteSignal.tagsChanged.connect(this, "updateNoteTags(String, List)");
562 notebookTree.noteSignal.tagsChanged.connect(this, "updateListTags(String, List)");
563 menuBar.hideNotebooks.setChecked(Global.isWindowVisible("notebookTree"));
565 savedSearchTree.setAddAction(menuBar.savedSearchAddAction);
566 savedSearchTree.setEditAction(menuBar.savedSearchEditAction);
567 savedSearchTree.setDeleteAction(menuBar.savedSearchDeleteAction);
568 savedSearchTree.setIconAction(menuBar.savedSearchIconAction);
569 savedSearchTree.itemSelectionChanged.connect(this, "updateSavedSearchSelection()");
570 savedSearchTree.setVisible(Global.isWindowVisible("savedSearchTree"));
571 menuBar.hideSavedSearches.setChecked(Global.isWindowVisible("savedSearchTree"));
573 noteTableView.setAddAction(menuBar.noteAdd);
574 noteTableView.setDeleteAction(menuBar.noteDelete);
575 noteTableView.setRestoreAction(menuBar.noteRestoreAction);
576 noteTableView.setNoteDuplicateAction(menuBar.noteDuplicateAction);
577 noteTableView.setNoteHistoryAction(menuBar.noteOnlineHistoryAction);
578 noteTableView.noteSignal.titleColorChanged.connect(this, "titleColorChanged(Integer)");
579 noteTableView.setMergeNotesAction(menuBar.noteMergeAction);
580 noteTableView.rowChanged.connect(this, "scrollToGuid(String)");
581 noteTableView.resetViewport.connect(this, "scrollToCurrentGuid()");
582 noteTableView.doubleClicked.connect(this, "listDoubleClick()");
583 listManager.trashSignal.countChanged.connect(trashTree, "updateCounts(Integer)");
585 quotaBar.setMouseClickAction(menuBar.accountAction);
588 trashTree.itemSelectionChanged.connect(this, "trashTreeSelection()");
589 trashTree.setEmptyAction(menuBar.emptyTrashAction);
590 trashTree.setVisible(Global.isWindowVisible("trashTree"));
591 menuBar.hideTrash.setChecked(Global.isWindowVisible("trashTree"));
592 trashTree.updateCounts(listManager.getTrashCount());
593 attributeTree.setVisible(Global.isWindowVisible("attributeTree"));
594 menuBar.hideAttributes.setChecked(Global.isWindowVisible("attributeTree"));
596 noteTableView.setVisible(Global.isWindowVisible("noteList"));
597 menuBar.hideNoteList.setChecked(Global.isWindowVisible("noteList"));
599 if (!Global.isWindowVisible("editorButtonBar"))
600 toggleEditorButtonBar();
601 if (!Global.isWindowVisible("leftPanel"))
602 menuBar.hideLeftSide.setChecked(true);
603 if (Global.isWindowVisible("noteInformation"))
604 toggleNoteInformation();
608 find = new FindDialog();
609 find.getOkButton().clicked.connect(this, "doFindText()");
611 // Setup the tray icon menu bar
612 trayShowAction = new QAction("Show/Hide", this);
613 trayExitAction = new QAction("Exit", this);
614 trayAddNoteAction = new QAction("Add Note", this);
616 trayExitAction.triggered.connect(this, "closeNeverNote()");
617 trayAddNoteAction.triggered.connect(this, "addNote()");
618 trayShowAction.triggered.connect(this, "trayToggleVisible()");
620 trayMenu = new QMenu(this);
621 trayMenu.addAction(trayAddNoteAction);
622 trayMenu.addAction(trayShowAction);
623 trayMenu.addAction(trayExitAction);
626 trayIcon = new QSystemTrayIcon(this);
627 trayIcon.setToolTip("NeverNote");
628 trayIcon.setContextMenu(trayMenu);
629 trayIcon.activated.connect(this, "trayActivated(com.trolltech.qt.gui.QSystemTrayIcon$ActivationReason)");
632 currentNoteGuid = Global.getLastViewedNoteGuid();
633 historyGuids = new ArrayList<String>();
637 if (!currentNoteGuid.trim().equals("")) {
638 currentNote = conn.getNoteTable().getNote(currentNoteGuid, true,true,false,false,true);
641 noteIndexUpdated(true);
643 menuBar.showEditorBar.setChecked(Global.isWindowVisible("editorButtonBar"));
644 if (menuBar.showEditorBar.isChecked())
645 showEditorButtons(browserWindow);
646 tagIndexUpdated(true);
647 savedSearchIndexUpdated();
648 notebookIndexUpdated();
650 setupSyncSignalListeners();
651 setupBrowserSignalListeners();
652 setupIndexListeners();
655 tagTree.tagSignal.listChanged.connect(this, "tagIndexUpdated()");
656 tagTree.showAllTags(true);
658 QIcon appIcon = new QIcon(iconPath+"nevernote.png");
659 setWindowIcon(appIcon);
660 trayIcon.setIcon(appIcon);
661 if (Global.showTrayIcon())
666 scrollToGuid(currentNoteGuid);
667 if (Global.automaticLogin()) {
669 if (Global.isConnected)
672 setupFolderImports();
675 restoreWindowState(true);
677 if (Global.mimicEvernoteInterface) {
678 notebookTree.selectGuid("");
681 threadMonitorTimer = new QTimer();
682 threadMonitorTimer.timeout.connect(this, "threadMonitorCheck()");
683 threadMonitorTimer.start(1000*10); // Check for threads every 10 seconds;
685 historyGuids.add(currentNoteGuid);
688 menuBar.blockSignals(true);
689 menuBar.narrowListView.blockSignals(true);
690 menuBar.wideListView.blockSignals(true);
691 if (Global.getListView() == Global.View_List_Narrow) {
692 menuBar.narrowListView.setChecked(true);
695 menuBar.wideListView.setChecked(true);
697 menuBar.blockSignals(false);
698 menuBar.narrowListView.blockSignals(false);
699 menuBar.wideListView.blockSignals(false);
701 if (Global.getListView() == Global.View_List_Wide) {
702 browserIndexSplitter.addWidget(noteTableView);
703 browserIndexSplitter.addWidget(browserWindow);
705 mainLeftRightSplitter.addWidget(noteTableView);
706 mainLeftRightSplitter.addWidget(browserWindow);
709 int sortCol = Global.getSortColumn();
710 int sortOrder = Global.getSortOrder();
711 noteTableView.sortByColumn(sortCol, SortOrder.resolve(sortOrder));
712 if (Global.checkVersionUpgrade())
717 public static void main(String[] args) {
718 log.setLevel(Level.FATAL);
719 QApplication.initialize(args);
720 QPixmap pixmap = new QPixmap("classpath:cx/fbn/nevernote/icons/splash_logo.png");
721 QSplashScreen splash = new QSplashScreen(pixmap);
724 DatabaseConnection dbConn;
727 initializeGlobalSettings(args);
729 showSplash = Global.isWindowVisible("SplashScreen");
733 dbConn = setupDatabaseConnection();
735 // Must be last stage of setup - only safe once DB is open hence we know we are the only instance running
736 Global.getFileManager().purgeResDirectory(true);
738 } catch (InitializationException e) {
741 QMessageBox.critical(null, "Startup error", "Aborting: " + e.getMessage());
745 NeverNote application = new NeverNote(dbConn);
747 application.setAttribute(WidgetAttribute.WA_DeleteOnClose, true);
748 if (Global.startMinimized())
749 application.showMinimized();
751 if (Global.wasWindowMaximized())
752 application.showMaximized();
758 splash.finish(application);
760 System.out.println("Goodbye.");
765 * Open the internal database, or create if not present
767 * @throws InitializationException when opening the database fails, e.g. because another process has it locked
769 private static DatabaseConnection setupDatabaseConnection() throws InitializationException {
770 ApplicationLogger logger = new ApplicationLogger("nevernote-database.log");
772 File f = Global.getFileManager().getDbDirFile(Global.databaseName + ".h2.db");
773 boolean dbExists = f.exists();
775 Global.setDatabaseUrl("");
777 if (Global.getDatabaseUrl().toUpperCase().indexOf("CIPHER=") > -1) {
778 boolean goodCheck = false;
780 DatabaseLoginDialog dialog = new DatabaseLoginDialog();
782 if (!dialog.okPressed())
784 Global.cipherPassword = dialog.getPassword();
785 goodCheck = databaseCheck(Global.getDatabaseUrl(), Global.getDatabaseUserid(),
786 Global.getDatabaseUserPassword(), Global.cipherPassword);
789 DatabaseConnection dbConn = new DatabaseConnection(logger,Global.getDatabaseUrl(),
790 Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(),
791 Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword, 0);
795 // Encrypt the database upon shutdown
796 private void encryptOnShutdown() {
797 String dbPath= Global.getFileManager().getDbDirPath("");
798 String dbName = "NeverNote";
800 Statement st = conn.getConnection().createStatement();
801 st.execute("shutdown");
802 if (QMessageBox.question(this, tr("Are you sure"),
803 tr("Are you sure you wish to encrypt the database?"),
804 QMessageBox.StandardButton.Yes,
805 QMessageBox.StandardButton.No) == StandardButton.Yes.value()) {
806 ChangeFileEncryption.execute(dbPath, dbName, encryptCipher, null, Global.cipherPassword.toCharArray(), true);
807 Global.setDatabaseUrl(Global.getDatabaseUrl() + ";CIPHER="+encryptCipher);
808 QMessageBox.information(this, "Encryption Complete", "Encryption is complete");
810 } catch (SQLException e) {
815 // Decrypt the database upon shutdown
816 private void decryptOnShutdown() {
817 String dbPath= Global.getFileManager().getDbDirPath("");
818 String dbName = "NeverNote";
820 Statement st = conn.getConnection().createStatement();
821 st.execute("shutdown");
822 if (Global.getDatabaseUrl().toUpperCase().indexOf(";CIPHER=AES") > -1)
823 encryptCipher = "AES";
825 encryptCipher = "XTEA";
826 if (QMessageBox.question(this, tr("Confirmation"), tr("Are you sure",
827 "Are you sure you wish to decrypt the database?"),
828 QMessageBox.StandardButton.Yes,
829 QMessageBox.StandardButton.No) == StandardButton.Yes.value()) {
831 ChangeFileEncryption.execute(dbPath, dbName, encryptCipher, Global.cipherPassword.toCharArray(), null, true);
832 Global.setDatabaseUrl("");
833 QMessageBox.information(this, tr("Decryption Complete"), tr("Decryption is complete"));
835 } catch (SQLException e) {
840 * Encrypt/Decrypt the local database
842 public void doDatabaseEncrypt() {
843 // The database is not currently encrypted
844 if (Global.getDatabaseUrl().toUpperCase().indexOf("CIPHER=") == -1) {
845 if (QMessageBox.question(this, tr("Confirmation"), tr("Encrypting the database is used" +
846 "to enhance security and is performed\nupon shutdown, but please be aware that if"+
847 " you lose the password your\nis lost forever.\n\nIt is highly recommended you " +
848 "perform a backup and/or fully synchronize\n prior to executing this funtction.\n\n" +
849 "Do you wish to proceed?"),
850 QMessageBox.StandardButton.Yes,
851 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
854 DBEncryptDialog dialog = new DBEncryptDialog();
856 if (dialog.okPressed()) {
857 Global.cipherPassword = dialog.getPassword();
858 encryptOnShutdown = true;
859 encryptCipher = dialog.getEncryptionMethod();
862 DBEncryptDialog dialog = new DBEncryptDialog();
863 dialog.setWindowTitle("Database Decryption");
864 dialog.hideEncryption();
866 if (dialog.okPressed()) {
867 if (!dialog.getPassword().equals(Global.cipherPassword)) {
868 QMessageBox.critical(null, tr("Incorrect Password"), tr("Incorrect Password"));
871 decryptOnShutdown = true;
878 private static void initializeGlobalSettings(String[] args) throws InitializationException {
879 StartupConfig startupConfig = new StartupConfig();
881 for (String arg : args) {
882 String lower = arg.toLowerCase();
883 if (lower.startsWith("--name="))
884 startupConfig.setName(arg.substring(arg.indexOf('=') + 1));
885 if (lower.startsWith("--home="))
886 startupConfig.setHomeDirPath(arg.substring(arg.indexOf('=') + 1));
887 if (lower.startsWith("--disable-viewing"))
888 startupConfig.setDisableViewing(true);
890 Global.setup(startupConfig);
895 public void closeEvent(QCloseEvent event) {
896 if (Global.minimizeOnClose() && !closeAction && Global.showTrayIcon()) {
901 logger.log(logger.HIGH, "Entering NeverNote.closeEvent");
904 if (currentNote!= null & browserWindow!=null) {
905 if (!currentNote.getTitle().equals(browserWindow.getTitle()))
906 conn.getNoteTable().updateNoteTitle(currentNote.getGuid(), browserWindow.getTitle());
909 setMessage(tr("Beginning shutdown."));
911 // Close down external windows
912 Collection<ExternalBrowse> windows = externalWindows.values();
913 Iterator<ExternalBrowse> iterator = windows.iterator();
914 while (iterator.hasNext()) {
915 ExternalBrowse browser = iterator.next();
916 browser.windowClosing.disconnect();
921 externalFileEditedSaver();
922 if (Global.isConnected && Global.synchronizeOnClose()) {
923 setMessage(tr("Performing synchronization before closing."));
924 syncRunner.syncNeeded = true;
925 syncRunner.addWork("SYNC");
926 syncRunner.addWork("STOP");
928 syncRunner.addWork("STOP");
929 syncRunner.keepRunning = false;
931 setMessage("Closing Program.");
932 threadMonitorTimer.stop();
934 thumbnailRunner.addWork("STOP");
935 indexRunner.addWork("STOP");
940 if (tempFiles != null)
943 browserWindow.noteSignal.tagsChanged.disconnect();
944 browserWindow.noteSignal.titleChanged.disconnect();
945 browserWindow.noteSignal.noteChanged.disconnect();
946 browserWindow.noteSignal.notebookChanged.disconnect();
947 browserWindow.noteSignal.createdDateChanged.disconnect();
948 browserWindow.noteSignal.alteredDateChanged.disconnect();
949 syncRunner.searchSignal.listChanged.disconnect();
950 syncRunner.tagSignal.listChanged.disconnect();
951 syncRunner.notebookSignal.listChanged.disconnect();
952 syncRunner.noteIndexSignal.listChanged.disconnect();
955 Global.saveWindowVisible("toolBar", toolBar.isVisible());
956 saveNoteColumnPositions();
957 saveNoteIndexWidth();
959 int width = notebookTree.columnWidth(0);
960 Global.setColumnWidth("notebookTreeName", width);
961 width = tagTree.columnWidth(0);
962 Global.setColumnWidth("tagTreeName", width);
964 Global.saveWindowMaximized(isMaximized());
965 Global.saveCurrentNoteGuid(currentNoteGuid);
967 int sortCol = noteTableView.proxyModel.sortColumn();
968 int sortOrder = noteTableView.proxyModel.sortOrder().value();
969 Global.setSortColumn(sortCol);
970 Global.setSortOrder(sortOrder);
974 Global.keepRunning = false;
976 logger.log(logger.MEDIUM, "Waiting for indexThread to stop");
977 if (indexRunner.thread().isAlive())
978 indexRunner.thread().join(50);
979 if (!indexRunner.thread().isAlive())
980 logger.log(logger.MEDIUM, "Index thread has stopped");
982 logger.log(logger.MEDIUM, "Index thread still running - interrupting");
983 indexRunner.thread().interrupt();
985 } catch (InterruptedException e1) {
986 e1.printStackTrace();
988 if (!syncRunner.isIdle()) {
990 logger.log(logger.MEDIUM, "Waiting for syncThread to stop");
991 System.out.println(tr("Synchronizing. Please be patient."));
993 logger.log(logger.MEDIUM, "Sync thread has stopped");
994 } catch (InterruptedException e1) {
995 e1.printStackTrace();
999 if (encryptOnShutdown) {
1000 encryptOnShutdown();
1002 if (decryptOnShutdown) {
1003 decryptOnShutdown();
1006 Global.getFileManager().purgeResDirectory(false);
1007 } catch (InitializationException e) {
1008 System.out.println(tr("Empty res directory purge failed"));
1009 e.printStackTrace();
1011 logger.log(logger.HIGH, "Leaving NeverNote.closeEvent");
1014 @SuppressWarnings("unused")
1015 private void closeNeverNote() {
1019 public void setMessage(String s) {
1020 logger.log(logger.HIGH, "Entering NeverNote.setMessage");
1021 logger.log(logger.HIGH, "Message: " +s);
1022 statusBar.showMessage(s);
1024 logger.log(logger.HIGH, "Leaving NeverNote.setMessage");
1027 private void waitCursor(boolean wait) {
1029 if (QApplication.overrideCursor() == null)
1030 QApplication.setOverrideCursor(new QCursor(Qt.CursorShape.WaitCursor));
1033 while (QApplication.overrideCursor() != null)
1034 QApplication.restoreOverrideCursor();
1038 private void setupIndexListeners() {
1039 // indexRunner.noteSignal.noteIndexed.connect(this, "indexThreadComplete(String)");
1040 // indexRunner.resourceSignal.resourceIndexed.connect(this, "indexThreadComplete(String)");
1041 indexRunner.signal.indexStarted.connect(this, "indexStarted()");
1042 indexRunner.signal.indexFinished.connect(this, "indexComplete()");
1044 private void setupSyncSignalListeners() {
1045 syncRunner.tagSignal.listChanged.connect(this, "tagIndexUpdated()");
1046 syncRunner.searchSignal.listChanged.connect(this, "savedSearchIndexUpdated()");
1047 syncRunner.notebookSignal.listChanged.connect(this, "notebookIndexUpdated()");
1048 syncRunner.noteIndexSignal.listChanged.connect(this, "noteIndexUpdated(boolean)");
1049 syncRunner.noteSignal.quotaChanged.connect(this, "updateQuotaBar()");
1051 syncRunner.syncSignal.saveUploadAmount.connect(this,"saveUploadAmount(long)");
1052 syncRunner.syncSignal.saveUserInformation.connect(this,"saveUserInformation(User)");
1053 syncRunner.syncSignal.saveEvernoteUpdateCount.connect(this,"saveEvernoteUpdateCount(int)");
1055 syncRunner.noteSignal.guidChanged.connect(this, "noteGuidChanged(String, String)");
1056 syncRunner.noteSignal.noteChanged.connect(this, "invalidateNoteCache(String, String)");
1057 syncRunner.resourceSignal.resourceGuidChanged.connect(this, "noteResourceGuidChanged(String,String,String)");
1058 syncRunner.noteSignal.noteDownloaded.connect(listManager, "noteDownloaded(Note)");
1059 syncRunner.noteSignal.notebookChanged.connect(this, "updateNoteNotebook(String, String)");
1061 syncRunner.syncSignal.refreshLists.connect(this, "refreshLists()");
1064 private void setupBrowserSignalListeners() {
1065 setupBrowserWindowListeners(browserWindow, true);
1068 private void setupBrowserWindowListeners(BrowserWindow browser, boolean master) {
1069 browser.fileWatcher.fileChanged.connect(this, "externalFileEdited(String)");
1070 browser.noteSignal.tagsChanged.connect(this, "updateNoteTags(String, List)");
1071 browser.noteSignal.tagsChanged.connect(this, "updateListTags(String, List)");
1072 if (master) browser.noteSignal.noteChanged.connect(this, "setNoteDirty()");
1073 browser.noteSignal.titleChanged.connect(listManager, "updateNoteTitle(String, String)");
1074 browser.noteSignal.titleChanged.connect(this, "updateNoteTitle(String, String)");
1075 browser.noteSignal.notebookChanged.connect(this, "updateNoteNotebook(String, String)");
1076 browser.noteSignal.createdDateChanged.connect(listManager, "updateNoteCreatedDate(String, QDateTime)");
1077 browser.noteSignal.alteredDateChanged.connect(listManager, "updateNoteAlteredDate(String, QDateTime)");
1078 browser.noteSignal.subjectDateChanged.connect(listManager, "updateNoteSubjectDate(String, QDateTime)");
1079 browser.noteSignal.authorChanged.connect(listManager, "updateNoteAuthor(String, String)");
1080 browser.noteSignal.geoChanged.connect(listManager, "updateNoteGeoTag(String, Double,Double,Double)");
1081 browser.noteSignal.geoChanged.connect(this, "setNoteDirty()");
1082 browser.noteSignal.sourceUrlChanged.connect(listManager, "updateNoteSourceUrl(String, String)");
1083 if (master) browser.focusLost.connect(this, "saveNote()");
1084 browser.resourceSignal.contentChanged.connect(this, "externalFileEdited(String)");
1087 //***************************************************************
1088 //***************************************************************
1089 //* Settings and look & feel
1090 //***************************************************************
1091 //***************************************************************
1092 @SuppressWarnings("unused")
1093 private void settings() {
1094 logger.log(logger.HIGH, "Entering NeverNote.settings");
1095 saveNoteColumnPositions();
1096 saveNoteIndexWidth();
1098 ConfigDialog settings = new ConfigDialog(this);
1099 String dateFormat = Global.getDateFormat();
1100 String timeFormat = Global.getTimeFormat();
1102 indexTime = 1000*Global.getIndexThreadSleepInterval();
1103 indexTimer.start(indexTime); // reset indexing timer
1106 indexRunner.indexAttachmentsLocally = Global.indexAttachmentsLocally();
1107 if (Global.showTrayIcon())
1112 if (menuBar.showEditorBar.isChecked())
1113 showEditorButtons(browserWindow);
1115 // Reset the save timer
1116 if (Global.getAutoSaveInterval() > 0)
1117 saveTimer.setInterval(1000*60*Global.getAutoSaveInterval());
1121 // This is a hack to force a reload of the index in case the date or time changed.
1122 // if (!dateFormat.equals(Global.getDateFormat()) ||
1123 // !timeFormat.equals(Global.getTimeFormat())) {
1125 readOnlyCache.clear();
1126 inkNoteCache.clear();
1127 noteIndexUpdated(true);
1130 logger.log(logger.HIGH, "Leaving NeverNote.settings");
1132 // Restore things to the way they were
1133 private void restoreWindowState(boolean mainWindow) {
1134 // We need to name things or this doesn't work.
1135 setObjectName("NeverNote");
1136 mainLeftRightSplitter.setObjectName("mainLeftRightSplitter");
1137 browserIndexSplitter.setObjectName("browserIndexSplitter");
1138 leftSplitter1.setObjectName("leftSplitter1");
1140 // Restore the actual positions.
1142 restoreGeometry(Global.restoreGeometry(objectName()));
1143 mainLeftRightSplitter.restoreState(Global.restoreState(mainLeftRightSplitter.objectName()));
1144 browserIndexSplitter.restoreState(Global.restoreState(browserIndexSplitter.objectName()));
1145 leftSplitter1.restoreState(Global.restoreState(leftSplitter1.objectName()));
1148 // Save window positions for the next start
1149 private void saveWindowState() {
1150 Global.saveGeometry(objectName(), saveGeometry());
1151 Global.saveState(mainLeftRightSplitter.objectName(), mainLeftRightSplitter.saveState());
1152 Global.saveState(browserIndexSplitter.objectName(), browserIndexSplitter.saveState());
1153 Global.saveState(leftSplitter1.objectName(), leftSplitter1.saveState());
1155 // Load the style sheet
1156 private void loadStyleSheet() {
1157 String fileName = Global.getFileManager().getQssDirPathUser("default.qss");
1158 fileName = Global.getFileManager().getQssDirPath("default.qss");
1159 QFile file = new QFile(fileName);
1161 // If a user default.qss doesn't exist, we use the one shipped with NeverNote
1162 if (!file.exists()) {
1163 fileName = Global.getFileManager().getQssDirPath("default.qss");
1164 file = new QFile(fileName);
1166 file.open(OpenModeFlag.ReadOnly);
1167 String styleSheet = file.readAll().toString();
1169 setStyleSheet(styleSheet);
1171 // Save column positions for the next time
1172 private void saveNoteColumnPositions() {
1173 int position = noteTableView.header.visualIndex(Global.noteTableCreationPosition);
1174 Global.setColumnPosition("noteTableCreationPosition", position);
1175 position = noteTableView.header.visualIndex(Global.noteTableTagPosition);
1176 Global.setColumnPosition("noteTableTagPosition", position);
1177 position = noteTableView.header.visualIndex(Global.noteTableNotebookPosition);
1178 Global.setColumnPosition("noteTableNotebookPosition", position);
1179 position = noteTableView.header.visualIndex(Global.noteTableChangedPosition);
1180 Global.setColumnPosition("noteTableChangedPosition", position);
1181 position = noteTableView.header.visualIndex(Global.noteTableAuthorPosition);
1182 Global.setColumnPosition("noteTableAuthorPosition", position);
1183 position = noteTableView.header.visualIndex(Global.noteTableSourceUrlPosition);
1184 Global.setColumnPosition("noteTableSourceUrlPosition", position);
1185 position = noteTableView.header.visualIndex(Global.noteTableSubjectDatePosition);
1186 Global.setColumnPosition("noteTableSubjectDatePosition", position);
1187 position = noteTableView.header.visualIndex(Global.noteTableTitlePosition);
1188 Global.setColumnPosition("noteTableTitlePosition", position);
1189 position = noteTableView.header.visualIndex(Global.noteTableSynchronizedPosition);
1190 Global.setColumnPosition("noteTableSynchronizedPosition", position);
1191 position = noteTableView.header.visualIndex(Global.noteTableGuidPosition);
1192 Global.setColumnPosition("noteTableGuidPosition", position);
1193 position = noteTableView.header.visualIndex(Global.noteTableThumbnailPosition);
1194 Global.setColumnPosition("noteTableThumbnailPosition", position);
1197 // Save column widths for the next time
1198 private void saveNoteIndexWidth() {
1200 width = noteTableView.getColumnWidth(Global.noteTableCreationPosition);
1201 Global.setColumnWidth("noteTableCreationPosition", width);
1202 width = noteTableView.getColumnWidth(Global.noteTableChangedPosition);
1203 Global.setColumnWidth("noteTableChangedPosition", width);
1204 width = noteTableView.getColumnWidth(Global.noteTableGuidPosition);
1205 Global.setColumnWidth("noteTableGuidPosition", width);
1206 width = noteTableView.getColumnWidth(Global.noteTableNotebookPosition);
1207 Global.setColumnWidth("noteTableNotebookPosition", width);
1208 width = noteTableView.getColumnWidth(Global.noteTableTagPosition);
1209 Global.setColumnWidth("noteTableTagPosition", width);
1210 width = noteTableView.getColumnWidth(Global.noteTableTitlePosition);
1211 Global.setColumnWidth("noteTableTitlePosition", width);
1212 width = noteTableView.getColumnWidth(Global.noteTableSourceUrlPosition);
1213 Global.setColumnWidth("noteTableSourceUrlPosition", width);
1214 width = noteTableView.getColumnWidth(Global.noteTableAuthorPosition);
1215 Global.setColumnWidth("noteTableAuthorPosition", width);
1216 width = noteTableView.getColumnWidth(Global.noteTableSubjectDatePosition);
1217 Global.setColumnWidth("noteTableSubjectDatePosition", width);
1218 width = noteTableView.getColumnWidth(Global.noteTableSynchronizedPosition);
1219 Global.setColumnWidth("noteTableSynchronizedPosition", width);
1220 width = noteTableView.getColumnWidth(Global.noteTableThumbnailPosition);
1221 Global.setColumnWidth("noteTableThumbnailPosition", width);
1222 width = noteTableView.getColumnWidth(Global.noteTableGuidPosition);
1223 Global.setColumnWidth("noteTableGuidPosition", width);
1227 //***************************************************************
1228 //***************************************************************
1229 //** These functions deal with Notebook menu items
1230 //***************************************************************
1231 //***************************************************************
1232 // Setup the tree containing the user's notebooks.
1233 private void initializeNotebookTree() {
1234 logger.log(logger.HIGH, "Entering NeverNote.initializeNotebookTree");
1235 // notebookTree.itemClicked.connect(this, "notebookTreeSelection()");
1236 notebookTree.selectionSignal.connect(this, "notebookTreeSelection()");
1237 listManager.notebookSignal.refreshNotebookTreeCounts.connect(notebookTree, "updateCounts(List, List)");
1238 logger.log(logger.HIGH, "Leaving NeverNote.initializeNotebookTree");
1240 // Listener when a notebook is selected
1241 private void notebookTreeSelection() {
1242 logger.log(logger.HIGH, "Entering NeverNote.notebookTreeSelection");
1245 clearAttributeFilter();
1246 clearSavedSearchFilter();
1247 if (Global.mimicEvernoteInterface) {
1249 searchField.clear();
1251 menuBar.noteRestoreAction.setVisible(false);
1252 menuBar.notebookEditAction.setEnabled(true);
1253 menuBar.notebookDeleteAction.setEnabled(true);
1254 menuBar.notebookPublishAction.setEnabled(true);
1255 menuBar.notebookShareAction.setEnabled(true);
1256 menuBar.notebookIconAction.setEnabled(true);
1257 menuBar.notebookStackAction.setEnabled(true);
1258 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1259 selectedNotebookGUIDs.clear();
1261 String stackName = "";
1262 if (selections.size() > 0) {
1263 guid = (selections.get(0).text(2));
1264 stackName = selections.get(0).text(0);
1266 if (!Global.mimicEvernoteInterface) {
1267 // If no notebooks are selected, we make it look like the "all notebooks" one was selected
1268 if (selections.size()==0) {
1269 selectedNotebookGUIDs.clear();
1270 for (int i=0; i < listManager.getNotebookIndex().size(); i++) {
1271 selectedNotebookGUIDs.add(listManager.getNotebookIndex().get(i).getGuid());
1273 menuBar.notebookEditAction.setEnabled(false);
1274 menuBar.notebookDeleteAction.setEnabled(false);
1275 menuBar.notebookStackAction.setEnabled(false);
1276 menuBar.notebookIconAction.setEnabled(false);
1279 if (!guid.equals("") && !guid.equals("STACK")) {
1280 selectedNotebookGUIDs.add(guid);
1281 menuBar.notebookIconAction.setEnabled(true);
1283 menuBar.notebookIconAction.setEnabled(true);
1284 for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1285 Notebook book = listManager.getNotebookIndex().get(j);
1286 if (book.getStack() != null && book.getStack().equalsIgnoreCase(stackName))
1287 selectedNotebookGUIDs.add(book.getGuid());
1290 listManager.setSelectedNotebooks(selectedNotebookGUIDs);
1291 listManager.loadNotesIndex();
1292 noteIndexUpdated(false);
1293 logger.log(logger.HIGH, "Leaving NeverNote.notebookTreeSelection");
1296 private void clearNotebookFilter() {
1297 notebookTree.blockSignals(true);
1298 notebookTree.clearSelection();
1299 menuBar.noteRestoreAction.setVisible(false);
1300 menuBar.notebookEditAction.setEnabled(false);
1301 menuBar.notebookDeleteAction.setEnabled(false);
1302 selectedNotebookGUIDs.clear();
1303 listManager.setSelectedNotebooks(selectedNotebookGUIDs);
1304 notebookTree.blockSignals(false);
1306 // Triggered when the notebook DB has been updated
1307 private void notebookIndexUpdated() {
1308 logger.log(logger.HIGH, "Entering NeverNote.notebookIndexUpdated");
1310 // Get the possible icons
1311 HashMap<String, QIcon> icons = conn.getNotebookTable().getAllIcons();
1312 notebookTree.setIcons(icons);
1314 if (selectedNotebookGUIDs == null)
1315 selectedNotebookGUIDs = new ArrayList<String>();
1316 List<Notebook> books = conn.getNotebookTable().getAll();
1317 for (int i=books.size()-1; i>=0; i--) {
1318 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
1319 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(books.get(i).getGuid())) {
1321 j=listManager.getArchiveNotebookIndex().size();
1327 listManager.countNotebookResults(listManager.getNoteIndex());
1328 notebookTree.blockSignals(true);
1329 notebookTree.load(books, listManager.getLocalNotebooks());
1330 for (int i=selectedNotebookGUIDs.size()-1; i>=0; i--) {
1331 boolean found = notebookTree.selectGuid(selectedNotebookGUIDs.get(i));
1333 selectedNotebookGUIDs.remove(i);
1335 notebookTree.blockSignals(false);
1337 logger.log(logger.HIGH, "Leaving NeverNote.notebookIndexUpdated");
1339 // Show/Hide note information
1340 private void toggleNotebookWindow() {
1341 logger.log(logger.HIGH, "Entering NeverNote.toggleNotebookWindow");
1342 if (notebookTree.isVisible())
1343 notebookTree.hide();
1345 notebookTree.show();
1346 menuBar.hideNotebooks.setChecked(notebookTree.isVisible());
1347 Global.saveWindowVisible("notebookTree", notebookTree.isVisible());
1348 logger.log(logger.HIGH, "Leaving NeverNote.toggleNotebookWindow");
1350 // Add a new notebook
1351 @SuppressWarnings("unused")
1352 private void addNotebook() {
1353 logger.log(logger.HIGH, "Inside NeverNote.addNotebook");
1354 NotebookEdit edit = new NotebookEdit();
1355 edit.setNotebooks(listManager.getNotebookIndex());
1358 if (!edit.okPressed())
1361 Calendar currentTime = new GregorianCalendar();
1362 Long l = new Long(currentTime.getTimeInMillis());
1363 String randint = new String(Long.toString(l));
1365 Notebook newBook = new Notebook();
1366 newBook.setUpdateSequenceNum(0);
1367 newBook.setGuid(randint);
1368 newBook.setName(edit.getNotebook());
1369 newBook.setServiceCreated(new Date().getTime());
1370 newBook.setServiceUpdated(new Date().getTime());
1371 newBook.setDefaultNotebook(false);
1372 newBook.setPublished(false);
1374 listManager.getNotebookIndex().add(newBook);
1376 listManager.getLocalNotebooks().add(newBook.getGuid());
1377 conn.getNotebookTable().addNotebook(newBook, true, edit.isLocal());
1378 notebookIndexUpdated();
1379 listManager.countNotebookResults(listManager.getNoteIndex());
1380 // notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
1381 logger.log(logger.HIGH, "Leaving NeverNote.addNotebook");
1383 // Edit an existing notebook
1384 @SuppressWarnings("unused")
1385 private void stackNotebook() {
1386 logger.log(logger.HIGH, "Entering NeverNote.stackNotebook");
1387 StackNotebook edit = new StackNotebook();
1389 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1390 QTreeWidgetItem currentSelection;
1391 for (int i=0; i<selections.size(); i++) {
1392 currentSelection = selections.get(0);
1393 String guid = currentSelection.text(2);
1394 if (guid.equalsIgnoreCase("")) {
1395 QMessageBox.critical(this, tr("Unable To Stack") ,tr("You can't stack the \"All Notebooks\" item."));
1398 if (guid.equalsIgnoreCase("STACK")) {
1399 QMessageBox.critical(this, tr("Unable To Stack") ,tr("You can't stack a stack."));
1404 edit.setStackNames(conn.getNotebookTable().getAllStackNames());
1409 if (!edit.okPressed())
1412 String stack = edit.getStackName();
1414 for (int i=0; i<selections.size(); i++) {
1415 currentSelection = selections.get(i);
1416 String guid = currentSelection.text(2);
1417 listManager.updateNotebookStack(guid, stack);
1419 notebookIndexUpdated();
1420 logger.log(logger.HIGH, "Leaving NeverNote.stackNotebook");
1422 // Edit an existing notebook
1423 @SuppressWarnings("unused")
1424 private void editNotebook() {
1425 logger.log(logger.HIGH, "Entering NeverNote.editNotebook");
1426 NotebookEdit edit = new NotebookEdit();
1428 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1429 QTreeWidgetItem currentSelection;
1430 currentSelection = selections.get(0);
1431 edit.setNotebook(currentSelection.text(0));
1433 String guid = currentSelection.text(2);
1434 if (!guid.equalsIgnoreCase("STACK")) {
1435 edit.setTitle(tr("Edit Notebook"));
1436 edit.setNotebooks(listManager.getNotebookIndex());
1437 edit.setLocalCheckboxEnabled(false);
1438 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1439 if (listManager.getNotebookIndex().get(i).getGuid().equals(guid)) {
1440 edit.setDefaultNotebook(listManager.getNotebookIndex().get(i).isDefaultNotebook());
1441 i=listManager.getNotebookIndex().size();
1445 edit.setTitle(tr("Edit Stack"));
1446 edit.setStacks(conn.getNotebookTable().getAllStackNames());
1447 edit.hideLocalCheckbox();
1448 edit.hideDefaultCheckbox();
1453 if (!edit.okPressed())
1457 if (guid.equalsIgnoreCase("STACK")) {
1458 conn.getNotebookTable().renameStacks(currentSelection.text(0), edit.getNotebook());
1459 for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1460 if (listManager.getNotebookIndex().get(j).getStack() != null &&
1461 listManager.getNotebookIndex().get(j).getStack().equalsIgnoreCase(currentSelection.text(0)))
1462 listManager.getNotebookIndex().get(j).setStack(edit.getNotebook());
1464 conn.getNotebookTable().renameStacks(currentSelection.text(0), edit.getNotebook());
1465 currentSelection.setText(0, edit.getNotebook());
1469 updateListNotebookName(currentSelection.text(0), edit.getNotebook());
1470 currentSelection.setText(0, edit.getNotebook());
1472 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1473 if (listManager.getNotebookIndex().get(i).getGuid().equals(guid)) {
1474 listManager.getNotebookIndex().get(i).setName(edit.getNotebook());
1475 if (!listManager.getNotebookIndex().get(i).isDefaultNotebook() && edit.isDefaultNotebook()) {
1476 for (int j=0; j<listManager.getNotebookIndex().size(); j++)
1477 listManager.getNotebookIndex().get(j).setDefaultNotebook(false);
1478 listManager.getNotebookIndex().get(i).setDefaultNotebook(true);
1479 conn.getNotebookTable().setDefaultNotebook(listManager.getNotebookIndex().get(i).getGuid());
1481 conn.getNotebookTable().updateNotebook(listManager.getNotebookIndex().get(i), true);
1482 if (conn.getNotebookTable().isLinked(listManager.getNotebookIndex().get(i).getGuid())) {
1483 LinkedNotebook linkedNotebook = conn.getLinkedNotebookTable().getByNotebookGuid(listManager.getNotebookIndex().get(i).getGuid());
1484 linkedNotebook.setShareName(edit.getNotebook());
1485 conn.getLinkedNotebookTable().updateNotebook(linkedNotebook, true);
1487 i=listManager.getNotebookIndex().size();
1491 // Build a list of non-closed notebooks
1492 List<Notebook> nbooks = new ArrayList<Notebook>();
1493 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1494 boolean found=false;
1495 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
1496 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid()))
1500 nbooks.add(listManager.getNotebookIndex().get(i));
1504 FilterEditorNotebooks notebookFilter = new FilterEditorNotebooks(conn, logger);
1505 List<Notebook> filteredBooks = notebookFilter.getValidNotebooks(currentNote, listManager.getNotebookIndex());
1506 browserWindow.setNotebookList(filteredBooks);
1507 Iterator<String> set = externalWindows.keySet().iterator();
1508 while(set.hasNext())
1509 externalWindows.get(set.next()).getBrowserWindow().setNotebookList(filteredBooks);
1510 logger.log(logger.HIGH, "Leaving NeverNote.editNotebook");
1512 // Publish a notebook
1513 @SuppressWarnings("unused")
1514 private void publishNotebook() {
1515 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1516 QTreeWidgetItem currentSelection;
1517 currentSelection = selections.get(0);
1518 String guid = currentSelection.text(2);
1520 if (guid.equalsIgnoreCase("STACK") || guid.equalsIgnoreCase(""))
1525 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1526 if (guid.equals(listManager.getNotebookIndex().get(i).getGuid())) {
1527 n = listManager.getNotebookIndex().get(i);
1529 i = listManager.getNotebookIndex().size();
1535 PublishNotebook publish = new PublishNotebook(Global.username, Global.getServer(), n);
1538 if (!publish.okClicked())
1541 Publishing p = publish.getPublishing();
1542 boolean isPublished = !publish.isStopPressed();
1543 conn.getNotebookTable().setPublishing(n.getGuid(), isPublished, p);
1544 n.setPublished(isPublished);
1546 listManager.getNotebookIndex().set(position, n);
1547 notebookIndexUpdated();
1549 // Publish a notebook
1550 @SuppressWarnings("unused")
1551 private void shareNotebook() {
1552 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1553 QTreeWidgetItem currentSelection;
1554 currentSelection = selections.get(0);
1555 String guid = currentSelection.text(2);
1557 if (guid.equalsIgnoreCase("STACK") || guid.equalsIgnoreCase(""))
1561 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1562 if (guid.equals(listManager.getNotebookIndex().get(i).getGuid())) {
1563 n = listManager.getNotebookIndex().get(i);
1564 i = listManager.getNotebookIndex().size();
1568 String authToken = null;
1569 if (syncRunner.isConnected)
1570 authToken = syncRunner.authToken;
1571 ShareNotebook share = new ShareNotebook(n.getName(), conn, n, syncRunner);
1576 // Delete an existing notebook
1577 @SuppressWarnings("unused")
1578 private void deleteNotebook() {
1579 logger.log(logger.HIGH, "Entering NeverNote.deleteNotebook");
1580 boolean stacksFound = false;
1581 boolean notebooksFound = false;
1582 boolean assigned = false;
1583 // Check if any notes have this notebook
1584 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1585 for (int i=0; i<selections.size(); i++) {
1586 QTreeWidgetItem currentSelection;
1587 currentSelection = selections.get(i);
1588 String guid = currentSelection.text(2);
1589 if (!guid.equalsIgnoreCase("STACK")) {
1590 notebooksFound = true;
1591 for (int j=0; j<listManager.getNoteIndex().size(); j++) {
1592 String noteGuid = listManager.getNoteIndex().get(j).getNotebookGuid();
1593 if (noteGuid.equals(guid)) {
1595 j=listManager.getNoteIndex().size();
1596 i=selections.size();
1604 QMessageBox.information(this, tr("Unable to Delete"), tr("Some of the selected notebook(s) contain notes.\n"+
1605 "Please delete the notes or move them to another notebook before deleting any notebooks."));
1609 if (conn.getNotebookTable().getAll().size() == 1) {
1610 QMessageBox.information(this, tr("Unable to Delete"), tr("You must have at least one notebook."));
1614 // If all notebooks are clear, verify the delete
1615 String msg1 = new String(tr("Delete selected notebooks?"));
1616 String msg2 = new String(tr("Remove selected stacks (notebooks will not be deleted)?"));
1617 String msg3 = new String(tr("Delete selected notebooks & remove stacks? Notebooks under the stacks are" +
1618 " not deleted unless selected?"));
1620 if (stacksFound && notebooksFound)
1622 if (!stacksFound && notebooksFound)
1624 if (stacksFound && !notebooksFound)
1626 if (QMessageBox.question(this, tr("Confirmation"), msg,
1627 QMessageBox.StandardButton.Yes,
1628 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
1632 // If confirmed, delete the notebook
1633 for (int i=selections.size()-1; i>=0; i--) {
1634 QTreeWidgetItem currentSelection;
1635 currentSelection = selections.get(i);
1636 String guid = currentSelection.text(2);
1637 if (currentSelection.text(2).equalsIgnoreCase("STACK")) {
1638 conn.getNotebookTable().renameStacks(currentSelection.text(0), "");
1639 listManager.renameStack(currentSelection.text(0), "");
1641 conn.getNotebookTable().expungeNotebook(guid, true);
1642 listManager.deleteNotebook(guid);
1646 notebookIndexUpdated();
1647 // notebookTreeSelection();
1648 // notebookTree.load(listManager.getNotebookIndex(), listManager.getLocalNotebooks());
1649 // listManager.countNotebookResults(listManager.getNoteIndex());
1650 logger.log(logger.HIGH, "Entering NeverNote.deleteNotebook");
1652 // A note's notebook has been updated
1653 @SuppressWarnings("unused")
1654 private void updateNoteNotebook(String guid, String notebookGuid) {
1656 // Update the list manager
1657 listManager.updateNoteNotebook(guid, notebookGuid);
1658 listManager.countNotebookResults(listManager.getNoteIndex());
1659 // notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
1661 // Find the name of the notebook
1662 String notebookName = null;
1663 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1664 if (listManager.getNotebookIndex().get(i).getGuid().equals(notebookGuid)) {
1665 notebookName = listManager.getNotebookIndex().get(i).getName();
1670 // If we found the name, update the browser window
1671 if (notebookName != null) {
1672 updateListNoteNotebook(guid, notebookName);
1673 if (guid.equals(currentNoteGuid)) {
1674 int pos = browserWindow.notebookBox.findText(notebookName);
1676 browserWindow.notebookBox.setCurrentIndex(pos);
1680 // If we're dealing with the current note, then we need to be sure and update the notebook there
1681 if (guid.equals(currentNoteGuid)) {
1682 if (currentNote != null) {
1683 currentNote.setNotebookGuid(notebookGuid);
1687 // Open/close notebooks
1688 @SuppressWarnings("unused")
1689 private void closeNotebooks() {
1690 NotebookArchive na = new NotebookArchive(listManager.getNotebookIndex(), listManager.getArchiveNotebookIndex());
1692 if (!na.okClicked())
1696 listManager.getArchiveNotebookIndex().clear();
1698 for (int i=na.getClosedBookList().count()-1; i>=0; i--) {
1699 String text = na.getClosedBookList().takeItem(i).text();
1700 for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1701 if (listManager.getNotebookIndex().get(j).getName().equalsIgnoreCase(text)) {
1702 Notebook n = listManager.getNotebookIndex().get(j);
1703 conn.getNotebookTable().setArchived(n.getGuid(),true);
1704 listManager.getArchiveNotebookIndex().add(n);
1705 j=listManager.getNotebookIndex().size();
1710 for (int i=na.getOpenBookList().count()-1; i>=0; i--) {
1711 String text = na.getOpenBookList().takeItem(i).text();
1712 for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1713 if (listManager.getNotebookIndex().get(j).getName().equalsIgnoreCase(text)) {
1714 Notebook n = listManager.getNotebookIndex().get(j);
1715 conn.getNotebookTable().setArchived(n.getGuid(),false);
1716 j=listManager.getNotebookIndex().size();
1720 notebookTreeSelection();
1721 listManager.loadNotesIndex();
1722 notebookIndexUpdated();
1723 noteIndexUpdated(false);
1724 reloadTagTree(true);
1725 // noteIndexUpdated(false);
1727 // Build a list of non-closed notebooks
1728 List<Notebook> nbooks = new ArrayList<Notebook>();
1729 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1730 boolean found=false;
1731 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
1732 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid()))
1736 nbooks.add(listManager.getNotebookIndex().get(i));
1739 FilterEditorNotebooks notebookFilter = new FilterEditorNotebooks(conn, logger);
1740 List<Notebook> filteredBooks = notebookFilter.getValidNotebooks(currentNote, listManager.getNotebookIndex());
1741 browserWindow.setNotebookList(filteredBooks);
1743 // Update any external windows
1744 Iterator<String> set = externalWindows.keySet().iterator();
1745 while(set.hasNext())
1746 externalWindows.get(set.next()).getBrowserWindow().setNotebookList(filteredBooks);
1750 // Change the notebook's icon
1751 @SuppressWarnings("unused")
1752 private void setNotebookIcon() {
1753 boolean stackSelected = false;
1754 boolean allNotebookSelected = false;
1756 QTreeWidgetItem currentSelection;
1757 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1758 if (selections.size() == 0)
1761 currentSelection = selections.get(0);
1762 String guid = currentSelection.text(2);
1763 if (guid.equalsIgnoreCase(""))
1764 allNotebookSelected = true;
1765 if (guid.equalsIgnoreCase("STACK"))
1766 stackSelected = true;
1768 QIcon currentIcon = currentSelection.icon(0);
1772 if (!stackSelected && !allNotebookSelected) {
1773 icon = conn.getNotebookTable().getIcon(guid);
1775 dialog = new SetIcon(currentIcon, saveLastPath);
1776 dialog.setUseDefaultIcon(true);
1778 dialog = new SetIcon(icon, saveLastPath);
1779 dialog.setUseDefaultIcon(false);
1782 if (stackSelected) {
1783 icon = conn.getSystemIconTable().getIcon(currentSelection.text(0), "STACK");
1785 icon = conn.getSystemIconTable().getIcon(currentSelection.text(0), "ALLNOTEBOOK");
1788 dialog = new SetIcon(currentIcon, saveLastPath);
1789 dialog.setUseDefaultIcon(true);
1791 dialog = new SetIcon(icon, saveLastPath);
1792 dialog.setUseDefaultIcon(false);
1796 if (dialog.okPressed()) {
1797 saveLastPath = dialog.getPath();
1799 QIcon newIcon = dialog.getIcon();
1800 if (stackSelected) {
1801 conn.getSystemIconTable().setIcon(currentSelection.text(0), "STACK", newIcon, dialog.getFileType());
1802 if (newIcon == null) {
1803 newIcon = new QIcon(iconPath+"books2.png");
1805 currentSelection.setIcon(0,newIcon);
1808 if (allNotebookSelected) {
1809 conn.getSystemIconTable().setIcon(currentSelection.text(0), "ALLNOTEBOOK", newIcon, dialog.getFileType());
1810 if (newIcon == null) {
1811 newIcon = new QIcon(iconPath+"notebook-green.png");
1813 currentSelection.setIcon(0,newIcon);
1816 conn.getNotebookTable().setIcon(guid, newIcon, dialog.getFileType());
1817 if (newIcon == null) {
1818 boolean isPublished = false;;
1819 boolean found = false;
1820 for (int i=0; i<listManager.getNotebookIndex().size() && !found; i++) {
1821 if (listManager.getNotebookIndex().get(i).getGuid().equals(guid)) {
1822 isPublished = listManager.getNotebookIndex().get(i).isPublished();
1826 newIcon = notebookTree.findDefaultIcon(guid, currentSelection.text(1), listManager.getLocalNotebooks(), isPublished);
1828 currentSelection.setIcon(0, newIcon);
1834 //***************************************************************
1835 //***************************************************************
1836 //** These functions deal with Tag menu items
1837 //***************************************************************
1838 //***************************************************************
1839 // Add a new notebook
1840 @SuppressWarnings("unused")
1841 private void addTag() {
1842 logger.log(logger.HIGH, "Inside NeverNote.addTag");
1843 TagEdit edit = new TagEdit();
1844 edit.setTagList(listManager.getTagIndex());
1847 if (!edit.okPressed())
1850 Calendar currentTime = new GregorianCalendar();
1851 Long l = new Long(currentTime.getTimeInMillis());
1852 String randint = new String(Long.toString(l));
1854 Tag newTag = new Tag();
1855 newTag.setUpdateSequenceNum(0);
1856 newTag.setGuid(randint);
1857 newTag.setName(edit.getTag());
1858 conn.getTagTable().addTag(newTag, true);
1859 listManager.getTagIndex().add(newTag);
1860 reloadTagTree(true);
1862 logger.log(logger.HIGH, "Leaving NeverNote.addTag");
1864 @SuppressWarnings("unused")
1865 private void reloadTagTree() {
1866 reloadTagTree(false);
1868 private void reloadTagTree(boolean reload) {
1869 logger.log(logger.HIGH, "Entering NeverNote.reloadTagTree");
1870 tagIndexUpdated(reload);
1871 boolean filter = false;
1872 listManager.countTagResults(listManager.getNoteIndex());
1873 if (notebookTree.selectedItems().size() > 0
1874 && !notebookTree.selectedItems().get(0).text(0).equalsIgnoreCase("All Notebooks"))
1876 if (tagTree.selectedItems().size() > 0)
1878 tagTree.showAllTags(!filter);
1879 logger.log(logger.HIGH, "Leaving NeverNote.reloadTagTree");
1881 // Edit an existing tag
1882 @SuppressWarnings("unused")
1883 private void editTag() {
1884 logger.log(logger.HIGH, "Entering NeverNote.editTag");
1885 TagEdit edit = new TagEdit();
1886 edit.setTitle("Edit Tag");
1887 List<QTreeWidgetItem> selections = tagTree.selectedItems();
1888 QTreeWidgetItem currentSelection;
1889 currentSelection = selections.get(0);
1890 edit.setTag(currentSelection.text(0));
1891 edit.setTagList(listManager.getTagIndex());
1894 if (!edit.okPressed())
1897 String guid = currentSelection.text(2);
1898 currentSelection.setText(0,edit.getTag());
1900 for (int i=0; i<listManager.getTagIndex().size(); i++) {
1901 if (listManager.getTagIndex().get(i).getGuid().equals(guid)) {
1902 listManager.getTagIndex().get(i).setName(edit.getTag());
1903 conn.getTagTable().updateTag(listManager.getTagIndex().get(i), true);
1904 updateListTagName(guid);
1905 if (currentNote != null && currentNote.getTagGuids().contains(guid))
1906 browserWindow.setTag(getTagNamesForNote(currentNote));
1907 logger.log(logger.HIGH, "Leaving NeverNote.editTag");
1911 browserWindow.setTag(getTagNamesForNote(currentNote));
1912 logger.log(logger.HIGH, "Leaving NeverNote.editTag...");
1914 // Delete an existing tag
1915 @SuppressWarnings("unused")
1916 private void deleteTag() {
1917 logger.log(logger.HIGH, "Entering NeverNote.deleteTag");
1919 if (QMessageBox.question(this, tr("Confirmation"), tr("Delete the selected tags?"),
1920 QMessageBox.StandardButton.Yes,
1921 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
1925 List<QTreeWidgetItem> selections = tagTree.selectedItems();
1926 for (int i=selections.size()-1; i>=0; i--) {
1927 QTreeWidgetItem currentSelection;
1928 currentSelection = selections.get(i);
1929 removeTagItem(currentSelection.text(2));
1931 tagIndexUpdated(true);
1933 listManager.countTagResults(listManager.getNoteIndex());
1934 // tagTree.updateCounts(listManager.getTagCounter());
1935 logger.log(logger.HIGH, "Leaving NeverNote.deleteTag");
1937 // Remove a tag tree item. Go recursively down & remove the children too
1938 private void removeTagItem(String guid) {
1939 for (int j=listManager.getTagIndex().size()-1; j>=0; j--) {
1940 String parent = listManager.getTagIndex().get(j).getParentGuid();
1941 if (parent != null && parent.equals(guid)) {
1942 //Remove this tag's children
1943 removeTagItem(listManager.getTagIndex().get(j).getGuid());
1946 //Now, remove this tag
1947 removeListTagName(guid);
1948 conn.getTagTable().expungeTag(guid, true);
1949 for (int a=0; a<listManager.getTagIndex().size(); a++) {
1950 if (listManager.getTagIndex().get(a).getGuid().equals(guid)) {
1951 listManager.getTagIndex().remove(a);
1956 // Setup the tree containing the user's tags
1957 private void initializeTagTree() {
1958 logger.log(logger.HIGH, "Entering NeverNote.initializeTagTree");
1959 // tagTree.itemSelectionChanged.connect(this, "tagTreeSelection()");
1960 // tagTree.itemClicked.connect(this, "tagTreeSelection()");
1961 tagTree.selectionSignal.connect(this, "tagTreeSelection()");
1962 listManager.tagSignal.refreshTagTreeCounts.connect(tagTree, "updateCounts(List)");
1963 logger.log(logger.HIGH, "Leaving NeverNote.initializeTagTree");
1965 // Listener when a tag is selected
1966 private void tagTreeSelection() {
1967 logger.log(logger.HIGH, "Entering NeverNote.tagTreeSelection");
1970 clearAttributeFilter();
1971 clearSavedSearchFilter();
1973 menuBar.noteRestoreAction.setVisible(false);
1975 List<QTreeWidgetItem> selections = tagTree.selectedItems();
1976 QTreeWidgetItem currentSelection;
1977 selectedTagGUIDs.clear();
1978 for (int i=0; i<selections.size(); i++) {
1979 currentSelection = selections.get(i);
1980 selectedTagGUIDs.add(currentSelection.text(2));
1982 if (selections.size() > 0) {
1983 menuBar.tagEditAction.setEnabled(true);
1984 menuBar.tagDeleteAction.setEnabled(true);
1985 menuBar.tagIconAction.setEnabled(true);
1988 menuBar.tagEditAction.setEnabled(false);
1989 menuBar.tagDeleteAction.setEnabled(false);
1990 menuBar.tagIconAction.setEnabled(true);
1992 listManager.setSelectedTags(selectedTagGUIDs);
1993 listManager.loadNotesIndex();
1994 noteIndexUpdated(false);
1995 logger.log(logger.HIGH, "Leaving NeverNote.tagTreeSelection");
1997 // trigger the tag index to be refreshed
1998 @SuppressWarnings("unused")
1999 private void tagIndexUpdated() {
2000 tagIndexUpdated(true);
2002 private void tagIndexUpdated(boolean reload) {
2003 logger.log(logger.HIGH, "Entering NeverNote.tagIndexUpdated");
2004 if (selectedTagGUIDs == null)
2005 selectedTagGUIDs = new ArrayList<String>();
2007 listManager.reloadTagIndex();
2009 tagTree.blockSignals(true);
2011 tagTree.setIcons(conn.getTagTable().getAllIcons());
2012 tagTree.load(listManager.getTagIndex());
2014 for (int i=selectedTagGUIDs.size()-1; i>=0; i--) {
2015 boolean found = tagTree.selectGuid(selectedTagGUIDs.get(i));
2017 selectedTagGUIDs.remove(i);
2019 tagTree.blockSignals(false);
2021 browserWindow.setTag(getTagNamesForNote(currentNote));
2022 logger.log(logger.HIGH, "Leaving NeverNote.tagIndexUpdated");
2024 // Show/Hide note information
2025 private void toggleTagWindow() {
2026 logger.log(logger.HIGH, "Entering NeverNote.toggleTagWindow");
2027 if (tagTree.isVisible())
2031 menuBar.hideTags.setChecked(tagTree.isVisible());
2032 Global.saveWindowVisible("tagTree", tagTree.isVisible());
2033 logger.log(logger.HIGH, "Leaving NeverNote.toggleTagWindow");
2035 // A note's tags have been updated
2036 @SuppressWarnings("unused")
2037 private void updateNoteTags(String guid, List<String> tags) {
2038 // Save any new tags. We'll need them later.
2039 List<String> newTags = new ArrayList<String>();
2040 for (int i=0; i<tags.size(); i++) {
2041 if (conn.getTagTable().findTagByName(tags.get(i))==null)
2042 newTags.add(tags.get(i));
2045 listManager.saveNoteTags(guid, tags);
2046 listManager.countTagResults(listManager.getNoteIndex());
2047 StringBuffer names = new StringBuffer("");
2048 for (int i=0; i<tags.size(); i++) {
2049 names = names.append(tags.get(i));
2050 if (i<tags.size()-1) {
2051 names.append(Global.tagDelimeter + " ");
2054 browserWindow.setTag(names.toString());
2057 // Now, we need to add any new tags to the tag tree
2058 for (int i=0; i<newTags.size(); i++)
2059 tagTree.insertTag(newTags.get(i), conn.getTagTable().findTagByName(newTags.get(i)));
2061 // Get a string containing all tag names for a note
2062 private String getTagNamesForNote(Note n) {
2063 logger.log(logger.HIGH, "Entering NeverNote.getTagNamesForNote");
2064 if (n==null || n.getGuid() == null || n.getGuid().equals(""))
2066 StringBuffer buffer = new StringBuffer(100);
2067 Vector<String> v = new Vector<String>();
2068 List<String> guids = n.getTagGuids();
2073 for (int i=0; i<guids.size(); i++) {
2074 v.add(listManager.getTagNameByGuid(guids.get(i)));
2076 Comparator<String> comparator = Collections.reverseOrder();
2077 Collections.sort(v,comparator);
2078 Collections.reverse(v);
2080 for (int i = 0; i<v.size(); i++) {
2082 buffer.append(", ");
2083 buffer.append(v.get(i));
2086 logger.log(logger.HIGH, "Leaving NeverNote.getTagNamesForNote");
2087 return buffer.toString();
2089 // Tags were added via dropping notes from the note list
2090 @SuppressWarnings("unused")
2091 private void tagsAdded(String noteGuid, String tagGuid) {
2092 String tagName = null;
2093 for (int i=0; i<listManager.getTagIndex().size(); i++) {
2094 if (listManager.getTagIndex().get(i).getGuid().equals(tagGuid)) {
2095 tagName = listManager.getTagIndex().get(i).getName();
2096 i=listManager.getTagIndex().size();
2099 if (tagName == null)
2102 for (int i=0; i<listManager.getMasterNoteIndex().size(); i++) {
2103 if (listManager.getMasterNoteIndex().get(i).getGuid().equals(noteGuid)) {
2104 List<String> tagNames = new ArrayList<String>();
2105 tagNames.add(new String(tagName));
2106 Note n = listManager.getMasterNoteIndex().get(i);
2107 for (int j=0; j<n.getTagNames().size(); j++) {
2108 tagNames.add(new String(n.getTagNames().get(j)));
2110 listManager.getNoteTableModel().updateNoteTags(noteGuid, n.getTagGuids(), tagNames);
2111 if (n.getGuid().equals(currentNoteGuid)) {
2112 Collections.sort(tagNames);
2113 String display = "";
2114 for (int j=0; j<tagNames.size(); j++) {
2115 display = display+tagNames.get(j);
2116 if (j+2<tagNames.size())
2117 display = display+Global.tagDelimeter+" ";
2119 browserWindow.setTag(display);
2121 i=listManager.getMasterNoteIndex().size();
2126 listManager.getNoteTableModel().updateNoteSyncStatus(noteGuid, false);
2128 private void clearTagFilter() {
2129 tagTree.blockSignals(true);
2130 tagTree.clearSelection();
2131 menuBar.noteRestoreAction.setVisible(false);
2132 menuBar.tagEditAction.setEnabled(false);
2133 menuBar.tagDeleteAction.setEnabled(false);
2134 menuBar.tagIconAction.setEnabled(false);
2135 selectedTagGUIDs.clear();
2136 listManager.setSelectedTags(selectedTagGUIDs);
2137 tagTree.blockSignals(false);
2139 // Change the icon for a tag
2140 @SuppressWarnings("unused")
2141 private void setTagIcon() {
2142 QTreeWidgetItem currentSelection;
2143 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2144 if (selections.size() == 0)
2147 currentSelection = selections.get(0);
2148 String guid = currentSelection.text(2);
2150 QIcon currentIcon = currentSelection.icon(0);
2151 QIcon icon = conn.getTagTable().getIcon(guid);
2154 dialog = new SetIcon(currentIcon, saveLastPath);
2155 dialog.setUseDefaultIcon(true);
2157 dialog = new SetIcon(icon, saveLastPath);
2158 dialog.setUseDefaultIcon(false);
2161 if (dialog.okPressed()) {
2162 saveLastPath = dialog.getPath();
2163 QIcon newIcon = dialog.getIcon();
2164 conn.getTagTable().setIcon(guid, newIcon, dialog.getFileType());
2165 if (newIcon == null)
2166 newIcon = new QIcon(iconPath+"tag.png");
2167 currentSelection.setIcon(0, newIcon);
2173 //***************************************************************
2174 //***************************************************************
2175 //** These functions deal with Saved Search menu items
2176 //***************************************************************
2177 //***************************************************************
2178 // Add a new notebook
2179 @SuppressWarnings("unused")
2180 private void addSavedSearch() {
2181 logger.log(logger.HIGH, "Inside NeverNote.addSavedSearch");
2182 SavedSearchEdit edit = new SavedSearchEdit();
2183 edit.setSearchList(listManager.getSavedSearchIndex());
2186 if (!edit.okPressed())
2189 Calendar currentTime = new GregorianCalendar();
2190 Long l = new Long(currentTime.getTimeInMillis());
2191 String randint = new String(Long.toString(l));
2193 SavedSearch search = new SavedSearch();
2194 search.setUpdateSequenceNum(0);
2195 search.setGuid(randint);
2196 search.setName(edit.getName());
2197 search.setQuery(edit.getQuery());
2198 search.setFormat(QueryFormat.USER);
2199 listManager.getSavedSearchIndex().add(search);
2200 conn.getSavedSearchTable().addSavedSearch(search, true);
2201 savedSearchIndexUpdated();
2202 logger.log(logger.HIGH, "Leaving NeverNote.addSavedSearch");
2204 // Edit an existing tag
2205 @SuppressWarnings("unused")
2206 private void editSavedSearch() {
2207 logger.log(logger.HIGH, "Entering NeverNote.editSavedSearch");
2208 SavedSearchEdit edit = new SavedSearchEdit();
2209 edit.setTitle(tr("Edit Search"));
2210 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2211 QTreeWidgetItem currentSelection;
2212 currentSelection = selections.get(0);
2213 String guid = currentSelection.text(1);
2214 SavedSearch s = conn.getSavedSearchTable().getSavedSearch(guid);
2215 edit.setName(currentSelection.text(0));
2216 edit.setQuery(s.getQuery());
2217 edit.setSearchList(listManager.getSavedSearchIndex());
2220 if (!edit.okPressed())
2223 List<SavedSearch> list = listManager.getSavedSearchIndex();
2224 SavedSearch search = null;
2225 boolean found = false;
2226 for (int i=0; i<list.size(); i++) {
2227 search = list.get(i);
2228 if (search.getGuid().equals(guid)) {
2235 search.setName(edit.getName());
2236 search.setQuery(edit.getQuery());
2237 conn.getSavedSearchTable().updateSavedSearch(search, true);
2238 savedSearchIndexUpdated();
2239 logger.log(logger.HIGH, "Leaving NeverNote.editSavedSearch");
2241 // Delete an existing tag
2242 @SuppressWarnings("unused")
2243 private void deleteSavedSearch() {
2244 logger.log(logger.HIGH, "Entering NeverNote.deleteSavedSearch");
2246 if (QMessageBox.question(this, "Confirmation", "Delete the selected search?",
2247 QMessageBox.StandardButton.Yes,
2248 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
2252 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2253 for (int i=selections.size()-1; i>=0; i--) {
2254 QTreeWidgetItem currentSelection;
2255 currentSelection = selections.get(i);
2256 for (int j=0; j<listManager.getSavedSearchIndex().size(); j++) {
2257 if (listManager.getSavedSearchIndex().get(j).getGuid().equals(currentSelection.text(1))) {
2258 conn.getSavedSearchTable().expungeSavedSearch(listManager.getSavedSearchIndex().get(j).getGuid(), true);
2259 listManager.getSavedSearchIndex().remove(j);
2260 j=listManager.getSavedSearchIndex().size()+1;
2263 selections.remove(i);
2265 savedSearchIndexUpdated();
2266 logger.log(logger.HIGH, "Leaving NeverNote.deleteSavedSearch");
2268 // Setup the tree containing the user's tags
2269 private void initializeSavedSearchTree() {
2270 logger.log(logger.HIGH, "Entering NeverNote.initializeSavedSearchTree");
2271 savedSearchTree.itemSelectionChanged.connect(this, "savedSearchTreeSelection()");
2272 logger.log(logger.HIGH, "Leaving NeverNote.initializeSavedSearchTree");
2274 // Listener when a tag is selected
2275 @SuppressWarnings("unused")
2276 private void savedSearchTreeSelection() {
2277 logger.log(logger.HIGH, "Entering NeverNote.savedSearchTreeSelection");
2279 clearNotebookFilter();
2282 clearAttributeFilter();
2284 String currentGuid = selectedSavedSearchGUID;
2285 menuBar.savedSearchEditAction.setEnabled(true);
2286 menuBar.savedSearchDeleteAction.setEnabled(true);
2287 menuBar.savedSearchIconAction.setEnabled(true);
2288 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2289 QTreeWidgetItem currentSelection;
2290 selectedSavedSearchGUID = "";
2291 for (int i=0; i<selections.size(); i++) {
2292 currentSelection = selections.get(i);
2293 if (currentSelection.text(1).equals(currentGuid)) {
2294 currentSelection.setSelected(false);
2296 selectedSavedSearchGUID = currentSelection.text(1);
2298 // i = selections.size() +1;
2301 // There is the potential for no notebooks to be selected if this
2302 // happens then we make it look like all notebooks were selecetd.
2303 // If that happens, just select the "all notebooks"
2304 if (selections.size()==0) {
2305 clearSavedSearchFilter();
2307 listManager.setSelectedSavedSearch(selectedSavedSearchGUID);
2309 logger.log(logger.HIGH, "Leaving NeverNote.savedSearchTreeSelection");
2311 private void clearSavedSearchFilter() {
2312 menuBar.savedSearchEditAction.setEnabled(false);
2313 menuBar.savedSearchDeleteAction.setEnabled(false);
2314 menuBar.savedSearchIconAction.setEnabled(false);
2315 savedSearchTree.blockSignals(true);
2316 savedSearchTree.clearSelection();
2317 savedSearchTree.blockSignals(false);
2318 selectedSavedSearchGUID = "";
2319 searchField.setEditText("");
2320 searchPerformed = false;
2321 listManager.setSelectedSavedSearch(selectedSavedSearchGUID);
2323 // trigger the tag index to be refreshed
2324 private void savedSearchIndexUpdated() {
2325 if (selectedSavedSearchGUID == null)
2326 selectedSavedSearchGUID = new String();
2327 savedSearchTree.blockSignals(true);
2328 savedSearchTree.setIcons(conn.getSavedSearchTable().getAllIcons());
2329 savedSearchTree.load(listManager.getSavedSearchIndex());
2330 savedSearchTree.selectGuid(selectedSavedSearchGUID);
2331 savedSearchTree.blockSignals(false);
2333 // trigger when the saved search selection changes
2334 @SuppressWarnings("unused")
2335 private void updateSavedSearchSelection() {
2336 logger.log(logger.HIGH, "Entering NeverNote.updateSavedSearchSelection()");
2338 menuBar.savedSearchEditAction.setEnabled(true);
2339 menuBar.savedSearchDeleteAction.setEnabled(true);
2340 menuBar.savedSearchIconAction.setEnabled(true);
2341 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2343 if (selections.size() > 0) {
2344 menuBar.savedSearchEditAction.setEnabled(true);
2345 menuBar.savedSearchDeleteAction.setEnabled(true);
2346 menuBar.savedSearchIconAction.setEnabled(true);
2347 selectedSavedSearchGUID = selections.get(0).text(1);
2348 SavedSearch s = conn.getSavedSearchTable().getSavedSearch(selectedSavedSearchGUID);
2349 searchField.setEditText(s.getQuery());
2351 menuBar.savedSearchEditAction.setEnabled(false);
2352 menuBar.savedSearchDeleteAction.setEnabled(false);
2353 menuBar.savedSearchIconAction.setEnabled(false);
2354 selectedSavedSearchGUID = "";
2355 searchField.setEditText("");
2357 searchFieldChanged();
2359 logger.log(logger.HIGH, "Leaving NeverNote.updateSavedSearchSelection()");
2363 // Show/Hide note information
2364 private void toggleSavedSearchWindow() {
2365 logger.log(logger.HIGH, "Entering NeverNote.toggleSavedSearchWindow");
2366 if (savedSearchTree.isVisible())
2367 savedSearchTree.hide();
2369 savedSearchTree.show();
2370 menuBar.hideSavedSearches.setChecked(savedSearchTree.isVisible());
2372 Global.saveWindowVisible("savedSearchTree", savedSearchTree.isVisible());
2373 logger.log(logger.HIGH, "Leaving NeverNote.toggleSavedSearchWindow");
2375 // Change the icon for a saved search
2376 @SuppressWarnings("unused")
2377 private void setSavedSearchIcon() {
2378 QTreeWidgetItem currentSelection;
2379 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2380 if (selections.size() == 0)
2383 currentSelection = selections.get(0);
2384 String guid = currentSelection.text(1);
2386 QIcon currentIcon = currentSelection.icon(0);
2387 QIcon icon = conn.getSavedSearchTable().getIcon(guid);
2390 dialog = new SetIcon(currentIcon, saveLastPath);
2391 dialog.setUseDefaultIcon(true);
2393 dialog = new SetIcon(icon, saveLastPath);
2394 dialog.setUseDefaultIcon(false);
2397 if (dialog.okPressed()) {
2398 saveLastPath = dialog.getPath();
2399 QIcon newIcon = dialog.getIcon();
2400 conn.getSavedSearchTable().setIcon(guid, newIcon, dialog.getFileType());
2401 if (newIcon == null)
2402 newIcon = new QIcon(iconPath+"search.png");
2403 currentSelection.setIcon(0, newIcon);
2411 //***************************************************************
2412 //***************************************************************
2413 //** These functions deal with Help menu & tool menu items
2414 //***************************************************************
2415 //***************************************************************
2416 // Show database status
2417 @SuppressWarnings("unused")
2418 private void databaseStatus() {
2420 indexRunner.interrupt = true;
2421 int dirty = conn.getNoteTable().getDirtyCount();
2422 int unindexed = conn.getNoteTable().getUnindexedCount();
2423 DatabaseStatus status = new DatabaseStatus();
2424 status.setUnsynchronized(dirty);
2425 status.setUnindexed(unindexed);
2426 status.setNoteCount(conn.getNoteTable().getNoteCount());
2427 status.setNotebookCount(listManager.getNotebookIndex().size());
2428 status.setUnindexedResourceCount(conn.getNoteTable().noteResourceTable.getUnindexedCount());
2429 status.setSavedSearchCount(listManager.getSavedSearchIndex().size());
2430 status.setTagCount(listManager.getTagIndex().size());
2431 status.setResourceCount(conn.getNoteTable().noteResourceTable.getResourceCount());
2432 status.setWordCount(conn.getWordsTable().getWordCount());
2436 // Compact the database
2437 @SuppressWarnings("unused")
2438 private void compactDatabase() {
2439 logger.log(logger.HIGH, "Entering NeverNote.compactDatabase");
2440 if (QMessageBox.question(this, tr("Confirmation"), tr("This will free unused space in the database, "+
2441 "but please be aware that depending upon the size of your database this can be time consuming " +
2442 "and NeverNote will be unresponsive until it is complete. Do you wish to continue?"),
2443 QMessageBox.StandardButton.Yes,
2444 QMessageBox.StandardButton.No)==StandardButton.No.value() && Global.verifyDelete() == true) {
2447 setMessage("Compacting database.");
2449 listManager.compactDatabase();
2451 setMessage("Database compact is complete.");
2452 logger.log(logger.HIGH, "Leaving NeverNote.compactDatabase");
2454 @SuppressWarnings("unused")
2455 private void accountInformation() {
2456 logger.log(logger.HIGH, "Entering NeverNote.accountInformation");
2457 AccountDialog dialog = new AccountDialog();
2459 logger.log(logger.HIGH, "Leaving NeverNote.accountInformation");
2461 @SuppressWarnings("unused")
2462 private void releaseNotes() {
2463 logger.log(logger.HIGH, "Entering NeverNote.releaseNotes");
2464 QDialog dialog = new QDialog(this);
2465 QHBoxLayout layout = new QHBoxLayout();
2466 QTextEdit textBox = new QTextEdit();
2467 layout.addWidget(textBox);
2468 textBox.setReadOnly(true);
2469 QFile file = new QFile(Global.getFileManager().getHomeDirPath("release.txt"));
2470 if (!file.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly,
2471 QIODevice.OpenModeFlag.Text)))
2473 textBox.setText(file.readAll().toString());
2475 dialog.setWindowTitle(tr("Release Notes"));
2476 dialog.setLayout(layout);
2478 logger.log(logger.HIGH, "Leaving NeverNote.releaseNotes");
2480 // Called when user picks Log from the help menu
2481 @SuppressWarnings("unused")
2482 private void logger() {
2483 logger.log(logger.HIGH, "Entering NeverNote.logger");
2484 LogFileDialog dialog = new LogFileDialog(emitLog);
2486 logger.log(logger.HIGH, "Leaving NeverNote.logger");
2488 // Menu option "help/about" was selected
2489 @SuppressWarnings("unused")
2490 private void about() {
2491 logger.log(logger.HIGH, "Entering NeverNote.about");
2492 QMessageBox.about(this,
2493 tr("About NeverNote"),
2494 tr("<h4><center><b>NeverNote</b></center></h4><hr><center>Version ")
2496 +tr("<hr></center>Evernote"
2497 +"An Open Source Evernote Client.<br><br>"
2498 +"Licensed under GPL v2. <br><hr><br>"
2499 +"Evernote is copyright 2001-2010 by Evernote Corporation<br>"
2500 +"Jambi and QT are the licensed trademark of Nokia Corporation<br>"
2501 +"PDFRenderer is licened under the LGPL<br>"
2502 +"JTidy is copyrighted under the World Wide Web Consortium<br>"
2503 +"Apache Common Utilities licensed under the Apache License Version 2.0<br>"
2504 +"Jazzy is licened under the LGPL<br>"
2505 +"Java is a registered trademark of Oracle Corporation.<br><hr>"));
2506 logger.log(logger.HIGH, "Leaving NeverNote.about");
2508 // Hide the entire left hand side
2509 @SuppressWarnings("unused")
2510 private void toggleLeftSide() {
2513 hidden = !menuBar.hideLeftSide.isChecked();
2514 menuBar.hideLeftSide.setChecked(!hidden);
2516 if (notebookTree.isVisible() != hidden)
2517 toggleNotebookWindow();
2518 if (savedSearchTree.isVisible() != hidden)
2519 toggleSavedSearchWindow();
2520 if (tagTree.isVisible() != hidden)
2522 if (attributeTree.isVisible() != hidden)
2523 toggleAttributesWindow();
2524 if (trashTree.isVisible() != hidden)
2525 toggleTrashWindow();
2527 Global.saveWindowVisible("leftPanel", hidden);
2530 public void checkForUpdates() {
2531 // Send off thread to check for a new version
2532 versionChecker = new QNetworkAccessManager(this);
2533 versionChecker.finished.connect(this, "upgradeFileRead(QNetworkReply)");
2534 QNetworkRequest request = new QNetworkRequest();
2535 request.setUrl(new QUrl(Global.getUpdatesAvailableUrl()));
2536 versionChecker.get(request);
2538 @SuppressWarnings("unused")
2539 private void upgradeFileRead(QNetworkReply reply) {
2540 if (!reply.isReadable())
2543 String winVersion = Global.version;
2544 String osxVersion = Global.version;
2545 String linuxVersion = Global.version;
2546 String linux64Version = Global.version;
2547 String version = Global.version;
2549 // Determine the versions available
2550 QByteArray data = reply.readLine();
2551 while (data != null && !reply.atEnd()) {
2552 String line = data.toString();
2554 if (line.contains(":"))
2555 lineVersion = line.substring(line.indexOf(":")+1).replace(" ", "").replace("\n", "");
2558 if (line.toLowerCase().contains("windows"))
2559 winVersion = lineVersion;
2560 else if (line.toLowerCase().contains("os-x"))
2561 osxVersion = lineVersion;
2562 else if (line.toLowerCase().contains("linux amd64"))
2563 linux64Version = lineVersion;
2564 else if (line.toLowerCase().contains("linux i386"))
2565 linuxVersion = lineVersion;
2566 else if (line.toLowerCase().contains("default"))
2567 version = lineVersion;
2569 // Read the next line
2570 data = reply.readLine();
2573 // Now we need to determine what system we are on.
2574 if (System.getProperty("os.name").toLowerCase().contains("windows"))
2575 version = winVersion;
2576 if (System.getProperty("os.name").toLowerCase().contains("mac os"))
2577 version = osxVersion;
2578 if (System.getProperty("os.name").toLowerCase().contains("Linux")) {
2579 if (System.getProperty("os.arch").contains("amd64") ||
2580 System.getProperty("os.arch").contains("x86_64"))
2581 version = linux64Version;
2583 version = linuxVersion;
2587 for (String validVersion : Global.validVersions) {
2588 if (version.equals(validVersion))
2592 UpgradeAvailableDialog dialog = new UpgradeAvailableDialog();
2594 if (dialog.remindMe())
2595 Global.setCheckVersionUpgrade(true);
2597 Global.setCheckVersionUpgrade(false);
2601 //***************************************************************
2602 //***************************************************************
2603 //** These functions deal with the Toolbar
2604 //***************************************************************
2605 //***************************************************************
2606 // Text in the search bar has been cleared
2607 private void searchFieldCleared() {
2610 // This is done because we want to force a reload of
2611 // images. Some images we may want to highlight the text.
2612 readOnlyCache.clear();
2613 inkNoteCache.clear();
2615 QWebSettings.setMaximumPagesInCache(0);
2616 QWebSettings.setObjectCacheCapacities(0, 0, 0);
2618 searchField.setEditText("");
2619 saveNoteColumnPositions();
2620 saveNoteIndexWidth();
2621 noteIndexUpdated(true);
2622 if (currentNote == null && listManager.getNoteIndex().size() > 0) {
2623 currentNote = listManager.getNoteIndex().get(0);
2624 currentNoteGuid = currentNote.getGuid();
2626 if (currentNote != null)
2627 loadNoteBrowserInformation(browserWindow);
2629 // text in the search bar changed. We only use this to tell if it was cleared,
2630 // otherwise we trigger off searchFieldChanged.
2631 @SuppressWarnings("unused")
2632 private void searchFieldTextChanged(String text) {
2633 QWebSettings.setMaximumPagesInCache(0);
2634 QWebSettings.setObjectCacheCapacities(0, 0, 0);
2636 if (text.trim().equals("")) {
2637 searchFieldCleared();
2638 if (searchPerformed) {
2640 // This is done because we want to force a reload of
2641 // images. Some images we may want to highlight the text.
2643 readOnlyCache.clear();
2644 inkNoteCache.clear();
2646 listManager.setEnSearch("");
2647 listManager.loadNotesIndex();
2648 refreshEvernoteNote(true);
2649 noteIndexUpdated(false);
2651 searchPerformed = false;
2654 // Text in the toolbar has changed
2655 private void searchFieldChanged() {
2656 logger.log(logger.HIGH, "Entering NeverNote.searchFieldChanged");
2658 readOnlyCache.clear();
2659 inkNoteCache.clear();
2660 saveNoteColumnPositions();
2661 saveNoteIndexWidth();
2662 String text = searchField.currentText();
2663 listManager.setEnSearch(text.trim());
2664 listManager.loadNotesIndex();
2665 //--->>> noteIndexUpdated(true);
2666 noteIndexUpdated(false);
2667 refreshEvernoteNote(true);
2668 searchPerformed = true;
2669 logger.log(logger.HIGH, "Leaving NeverNote.searchFieldChanged");
2672 // Build the window tool bar
2673 private void setupToolBar() {
2674 logger.log(logger.HIGH, "Entering NeverNote.setupToolBar");
2675 toolBar = addToolBar(tr("Tool Bar"));
2676 menuBar.setupToolBarVisible();
2677 if (!Global.isWindowVisible("toolBar"))
2678 toolBar.setVisible(false);
2680 toolBar.setVisible(true);
2682 prevButton = toolBar.addAction("Previous");
2683 QIcon prevIcon = new QIcon(iconPath+"back.png");
2684 prevButton.setIcon(prevIcon);
2685 prevButton.triggered.connect(this, "previousViewedAction()");
2686 togglePrevArrowButton(Global.isToolbarButtonVisible("prevArrow"));
2688 nextButton = toolBar.addAction("Next");
2689 QIcon nextIcon = new QIcon(iconPath+"forward.png");
2690 nextButton.setIcon(nextIcon);
2691 nextButton.triggered.connect(this, "nextViewedAction()");
2692 toggleNextArrowButton(Global.isToolbarButtonVisible("nextArrow"));
2694 upButton = toolBar.addAction("Up");
2695 QIcon upIcon = new QIcon(iconPath+"up.png");
2696 upButton.setIcon(upIcon);
2697 upButton.triggered.connect(this, "upAction()");
2698 toggleUpArrowButton(Global.isToolbarButtonVisible("upArrow"));
2701 downButton = toolBar.addAction("Down");
2702 QIcon downIcon = new QIcon(iconPath+"down.png");
2703 downButton.setIcon(downIcon);
2704 downButton.triggered.connect(this, "downAction()");
2705 toggleDownArrowButton(Global.isToolbarButtonVisible("downArrow"));
2707 synchronizeButton = toolBar.addAction("Synchronize");
2708 synchronizeButton.setIcon(new QIcon(iconPath+"synchronize.png"));
2709 synchronizeIconAngle = 0;
2710 synchronizeButton.triggered.connect(this, "evernoteSync()");
2711 toggleSynchronizeButton(Global.isToolbarButtonVisible("synchronize"));
2713 printButton = toolBar.addAction("Print");
2714 QIcon printIcon = new QIcon(iconPath+"print.png");
2715 printButton.setIcon(printIcon);
2716 printButton.triggered.connect(this, "printNote()");
2717 togglePrintButton(Global.isToolbarButtonVisible("print"));
2719 tagButton = toolBar.addAction("Tag");
2720 QIcon tagIcon = new QIcon(iconPath+"tag.png");
2721 tagButton.setIcon(tagIcon);
2722 tagButton.triggered.connect(browserWindow, "modifyTags()");
2723 toggleTagButton(Global.isToolbarButtonVisible("tag"));
2725 attributeButton = toolBar.addAction("Attributes");
2726 QIcon attributeIcon = new QIcon(iconPath+"attribute.png");
2727 attributeButton.setIcon(attributeIcon);
2728 attributeButton.triggered.connect(this, "toggleNoteInformation()");
2729 toggleAttributeButton(Global.isToolbarButtonVisible("attribute"));
2731 emailButton = toolBar.addAction("Email");
2732 QIcon emailIcon = new QIcon(iconPath+"email.png");
2733 emailButton.setIcon(emailIcon);
2734 emailButton.triggered.connect(this, "emailNote()");
2735 toggleEmailButton(Global.isToolbarButtonVisible("email"));
2737 deleteButton = toolBar.addAction("Delete");
2738 QIcon deleteIcon = new QIcon(iconPath+"delete.png");
2739 deleteButton.setIcon(deleteIcon);
2740 deleteButton.triggered.connect(this, "deleteNote()");
2741 toggleDeleteButton(Global.isToolbarButtonVisible("delete"));
2743 newButton = toolBar.addAction("New");
2744 QIcon newIcon = new QIcon(iconPath+"new.png");
2745 newButton.triggered.connect(this, "addNote()");
2746 newButton.setIcon(newIcon);
2747 toggleNewButton(Global.isToolbarButtonVisible("new"));
2749 allNotesButton = toolBar.addAction("All Notes");
2750 QIcon allIcon = new QIcon(iconPath+"books.png");
2751 allNotesButton.triggered.connect(this, "allNotes()");
2752 allNotesButton.setIcon(allIcon);
2753 toggleAllNotesButton(Global.isToolbarButtonVisible("allNotes"));
2755 toolBar.addSeparator();
2756 toolBar.addWidget(new QLabel(tr("Quota:")));
2757 toolBar.addWidget(quotaBar);
2758 //quotaBar.setSizePolicy(Policy.Minimum, Policy.Minimum);
2760 toolBar.addSeparator();
2763 zoomSpinner = new QSpinBox();
2764 zoomSpinner.setMinimum(10);
2765 zoomSpinner.setMaximum(1000);
2766 zoomSpinner.setAccelerated(true);
2767 zoomSpinner.setSingleStep(10);
2768 zoomSpinner.setValue(100);
2769 zoomSpinner.valueChanged.connect(this, "zoomChanged()");
2770 toolBar.addWidget(new QLabel(tr("Zoom")));
2771 toolBar.addWidget(zoomSpinner);
2773 //toolBar.addWidget(new QLabel(" "));
2774 toolBar.addSeparator();
2775 toolBar.addWidget(new QLabel(tr(" Search:")));
2776 toolBar.addWidget(searchField);
2777 QSizePolicy sizePolicy = new QSizePolicy();
2778 sizePolicy.setHorizontalPolicy(Policy.MinimumExpanding);
2779 searchField.setSizePolicy(sizePolicy);
2780 searchField.setInsertPolicy(InsertPolicy.InsertAtTop);
2782 searchClearButton = toolBar.addAction("Search Clear");
2783 QIcon searchClearIcon = new QIcon(iconPath+"searchclear.png");
2784 searchClearButton.setIcon(searchClearIcon);
2785 searchClearButton.triggered.connect(this, "searchFieldCleared()");
2786 toggleSearchClearButton(Global.isToolbarButtonVisible("searchClear"));
2788 logger.log(logger.HIGH, "Leaving NeverNote.setupToolBar");
2790 // Update the sychronize button picture
2792 public QMenu createPopupMenu() {
2793 QMenu contextMenu = super.createPopupMenu();
2795 contextMenu.addSeparator();
2796 QAction prevAction = addContextAction("prevArrow", tr("Previous Arrow"));
2797 contextMenu.addAction(prevAction);
2798 prevAction.triggered.connect(this, "togglePrevArrowButton(Boolean)");
2800 QAction nextAction = addContextAction("nextArrow", tr("Next Arrow"));
2801 contextMenu.addAction(nextAction);
2802 nextAction.triggered.connect(this, "toggleNextArrowButton(Boolean)");
2804 QAction upAction = addContextAction("upArrow", tr("Up Arrow"));
2805 contextMenu.addAction(upAction);
2806 upAction.triggered.connect(this, "toggleUpArrowButton(Boolean)");
2808 QAction downAction = addContextAction("downArrow", tr("Down Arrow"));
2809 contextMenu.addAction(downAction);
2810 downAction.triggered.connect(this, "toggleDownArrowButton(Boolean)");
2812 QAction synchronizeAction = addContextAction("synchronize", tr("Synchronize"));
2813 contextMenu.addAction(synchronizeAction);
2814 synchronizeAction.triggered.connect(this, "toggleSynchronizeButton(Boolean)");
2816 QAction printAction = addContextAction("print", tr("Print"));
2817 contextMenu.addAction(printAction);
2818 printAction.triggered.connect(this, "togglePrintButton(Boolean)");
2820 QAction tagAction = addContextAction("tag", tr("Tag"));
2821 contextMenu.addAction(tagAction);
2822 tagAction.triggered.connect(this, "toggleTagButton(Boolean)");
2824 QAction attributeAction = addContextAction("attribute", tr("Attribute"));
2825 contextMenu.addAction(attributeAction);
2826 attributeAction.triggered.connect(this, "toggleAttributeButton(Boolean)");
2828 QAction emailAction = addContextAction("email", tr("Email"));
2829 contextMenu.addAction(emailAction);
2830 emailAction.triggered.connect(this, "toggleEmailButton(Boolean)");
2832 QAction deleteAction = addContextAction("delete", tr("Delete"));
2833 contextMenu.addAction(deleteAction);
2834 deleteAction.triggered.connect(this, "toggleDeleteButton(Boolean)");
2836 QAction newAction = addContextAction("new", tr("Add"));
2837 contextMenu.addAction(newAction);
2838 newAction.triggered.connect(this, "toggleNewButton(Boolean)");
2840 QAction allNotesAction = addContextAction("allNotes", tr("All Notes"));
2841 contextMenu.addAction(allNotesAction);
2842 allNotesAction.triggered.connect(this, "toggleAllNotesButton(Boolean)");
2844 QAction searchClearAction = addContextAction("searchClear", tr("Search Clear"));
2845 contextMenu.addAction(searchClearAction);
2846 searchClearAction.triggered.connect(this, "toggleSearchClearButton(Boolean)");
2851 private QAction addContextAction(String config, String name) {
2852 QAction newAction = new QAction(this);
2853 newAction.setText(name);
2854 newAction.setCheckable(true);
2855 newAction.setChecked(Global.isToolbarButtonVisible(config));
2858 private void togglePrevArrowButton(Boolean toggle) {
2859 prevButton.setVisible(toggle);
2860 Global.saveToolbarButtonsVisible("prevArrow", toggle);
2862 private void toggleNextArrowButton(Boolean toggle) {
2863 nextButton.setVisible(toggle);
2864 Global.saveToolbarButtonsVisible("nextArrow", toggle);
2866 private void toggleUpArrowButton(Boolean toggle) {
2867 upButton.setVisible(toggle);
2868 Global.saveToolbarButtonsVisible("upArrow", toggle);
2870 private void toggleDownArrowButton(Boolean toggle) {
2871 downButton.setVisible(toggle);
2872 Global.saveToolbarButtonsVisible("downArrow", toggle);
2874 private void toggleSynchronizeButton(Boolean toggle) {
2875 synchronizeButton.setVisible(toggle);
2876 Global.saveToolbarButtonsVisible("synchronize", toggle);
2878 private void togglePrintButton(Boolean toggle) {
2879 printButton.setVisible(toggle);
2880 Global.saveToolbarButtonsVisible("print", toggle);
2882 private void toggleTagButton(Boolean toggle) {
2883 tagButton.setVisible(toggle);
2884 Global.saveToolbarButtonsVisible("tag", toggle);
2886 private void toggleAttributeButton(Boolean toggle) {
2887 attributeButton.setVisible(toggle);
2888 Global.saveToolbarButtonsVisible("attribute", toggle);
2890 private void toggleEmailButton(Boolean toggle) {
2891 emailButton.setVisible(toggle);
2892 Global.saveToolbarButtonsVisible("email", toggle);
2894 private void toggleDeleteButton(Boolean toggle) {
2895 deleteButton.setVisible(toggle);
2896 Global.saveToolbarButtonsVisible("delete", toggle);
2898 private void toggleNewButton(Boolean toggle) {
2899 newButton.setVisible(toggle);
2900 Global.saveToolbarButtonsVisible("new", toggle);
2902 private void toggleAllNotesButton(Boolean toggle) {
2903 allNotesButton.setVisible(toggle);
2904 Global.saveToolbarButtonsVisible("allNotes", toggle);
2906 private void toggleSearchClearButton(Boolean toggle) {
2907 searchClearButton.setVisible(toggle);
2908 Global.saveToolbarButtonsVisible("searchClear", toggle);
2915 @SuppressWarnings("unused")
2916 private void updateSyncButton() {
2918 if (syncIcons == null) {
2919 syncIcons = new ArrayList<QPixmap>();
2921 synchronizeIconAngle = 0;
2922 QPixmap pix = new QPixmap(iconPath+"synchronize.png");
2924 for (int i=0; i<=360; i++) {
2925 QPixmap rotatedPix = new QPixmap(pix.size());
2926 QPainter p = new QPainter(rotatedPix);
2927 rotatedPix.fill(toolBar.palette().color(ColorRole.Button));
2928 QSize size = pix.size();
2929 p.translate(size.width()/2, size.height()/2);
2932 p.setBackgroundMode(BGMode.OpaqueMode);
2933 p.translate(-size.width()/2, -size.height()/2);
2934 p.drawPixmap(0,0, pix);
2936 syncIcons.add(rotatedPix);
2940 synchronizeIconAngle++;
2941 if (synchronizeIconAngle > 359)
2942 synchronizeIconAngle=0;
2943 synchronizeButton.setIcon(syncIcons.get(synchronizeIconAngle));
2946 // Synchronize with Evernote
2947 @SuppressWarnings("unused")
2948 private void evernoteSync() {
2949 logger.log(logger.HIGH, "Entering NeverNote.evernoteSync");
2950 if (!Global.isConnected)
2952 if (Global.isConnected)
2953 synchronizeAnimationTimer.start(5);
2954 // synchronizeAnimationTimer.start(200);
2956 logger.log(logger.HIGH, "Leaving NeverNote.evernoteSync");
2958 private void updateQuotaBar() {
2959 long limit = Global.getUploadLimit();
2960 long amount = Global.getUploadAmount();
2961 if (amount>0 && limit>0) {
2962 int percent =(int)(amount*100/limit);
2963 quotaBar.setValue(percent);
2965 quotaBar.setValue(0);
2968 @SuppressWarnings("unused")
2969 private void zoomChanged() {
2970 browserWindow.getBrowser().setZoomFactor(new Double(zoomSpinner.value())/100);
2973 //****************************************************************
2974 //****************************************************************
2975 //* System Tray functions
2976 //****************************************************************
2977 //****************************************************************
2978 private void trayToggleVisible() {
2983 if (windowMaximized)
2990 @SuppressWarnings("unused")
2991 private void trayActivated(QSystemTrayIcon.ActivationReason reason) {
2992 if (reason == QSystemTrayIcon.ActivationReason.DoubleClick) {
2993 String name = QSystemTrayIcon.MessageIcon.resolve(reason.value()).name();
2994 trayToggleVisible();
2999 //***************************************************************
3000 //***************************************************************
3001 //** These functions deal with the trash tree
3002 //***************************************************************
3003 //***************************************************************
3004 // Setup the tree containing the trash.
3005 @SuppressWarnings("unused")
3006 private void trashTreeSelection() {
3007 logger.log(logger.HIGH, "Entering NeverNote.trashTreeSelection");
3009 clearNotebookFilter();
3011 clearAttributeFilter();
3012 clearSavedSearchFilter();
3014 String tempGuid = currentNoteGuid;
3016 // currentNoteGuid = "";
3017 currentNote = new Note();
3018 selectedNoteGUIDs.clear();
3019 listManager.getSelectedNotebooks().clear();
3020 listManager.getSelectedTags().clear();
3021 listManager.setSelectedSavedSearch("");
3022 browserWindow.clear();
3024 // toggle the add buttons
3025 newButton.setEnabled(!newButton.isEnabled());
3026 menuBar.noteAdd.setEnabled(newButton.isEnabled());
3027 menuBar.noteAdd.setVisible(true);
3029 List<QTreeWidgetItem> selections = trashTree.selectedItems();
3030 if (selections.size() == 0) {
3031 currentNoteGuid = trashNoteGuid;
3032 trashNoteGuid = tempGuid;
3033 Global.showDeleted = false;
3034 menuBar.noteRestoreAction.setEnabled(false);
3035 menuBar.noteRestoreAction.setVisible(false);
3038 currentNoteGuid = trashNoteGuid;
3039 trashNoteGuid = tempGuid;
3040 menuBar.noteRestoreAction.setEnabled(true);
3041 menuBar.noteRestoreAction.setVisible(true);
3042 Global.showDeleted = true;
3044 listManager.loadNotesIndex();
3045 noteIndexUpdated(false);
3046 //// browserWindow.setEnabled(newButton.isEnabled());
3047 browserWindow.setReadOnly(!newButton.isEnabled());
3048 logger.log(logger.HIGH, "Leaving NeverNote.trashTreeSelection");
3050 // Empty the trash file
3051 @SuppressWarnings("unused")
3052 private void emptyTrash() {
3053 // browserWindow.clear();
3054 listManager.emptyTrash();
3055 if (trashTree.selectedItems().size() > 0) {
3056 listManager.getSelectedNotebooks().clear();
3057 listManager.getSelectedTags().clear();
3058 listManager.setSelectedSavedSearch("");
3059 newButton.setEnabled(!newButton.isEnabled());
3060 menuBar.noteAdd.setEnabled(newButton.isEnabled());
3061 menuBar.noteAdd.setVisible(true);
3062 browserWindow.clear();
3065 clearNotebookFilter();
3066 clearSavedSearchFilter();
3067 clearAttributeFilter();
3069 Global.showDeleted = false;
3070 menuBar.noteRestoreAction.setEnabled(false);
3071 menuBar.noteRestoreAction.setVisible(false);
3073 listManager.loadNotesIndex();
3074 //--->>> noteIndexUpdated(true);
3075 noteIndexUpdated(false);
3078 // Show/Hide trash window
3079 private void toggleTrashWindow() {
3080 logger.log(logger.HIGH, "Entering NeverNote.toggleTrashWindow");
3081 if (trashTree.isVisible())
3085 menuBar.hideTrash.setChecked(trashTree.isVisible());
3087 Global.saveWindowVisible("trashTree", trashTree.isVisible());
3088 logger.log(logger.HIGH, "Leaving NeverNote.trashWindow");
3090 private void clearTrashFilter() {
3091 Global.showDeleted = false;
3092 newButton.setEnabled(true);
3093 menuBar.noteAdd.setEnabled(true);
3094 menuBar.noteAdd.setVisible(true);
3095 trashTree.blockSignals(true);
3096 trashTree.clearSelection();
3097 trashTree.blockSignals(false);
3102 //***************************************************************
3103 //***************************************************************
3104 //** These functions deal with connection settings
3105 //***************************************************************
3106 //***************************************************************
3107 // SyncRunner had a problem and things are disconnected
3108 @SuppressWarnings("unused")
3109 private void remoteErrorDisconnect() {
3110 menuBar.connectAction.setText(tr("Connect"));
3111 menuBar.connectAction.setToolTip(tr("Connect to Evernote"));
3112 menuBar.synchronizeAction.setEnabled(false);
3113 Global.isConnected = false;
3114 synchronizeAnimationTimer.stop();
3117 // Do a manual connect/disconnect
3118 private void remoteConnect() {
3119 logger.log(logger.HIGH, "Entering NeverNote.remoteConnect");
3121 if (Global.isConnected) {
3122 Global.isConnected = false;
3123 syncRunner.enDisconnect();
3124 setupConnectMenuOptions();
3129 AESEncrypter aes = new AESEncrypter();
3131 aes.decrypt(new FileInputStream(Global.getFileManager().getHomeDirFile("secure.txt")));
3132 } catch (FileNotFoundException e) {
3133 // File not found, so we'll just get empty strings anyway.
3136 if (Global.getProxyValue("url").equals("")) {
3137 System.setProperty("http.proxyHost","") ;
3138 System.setProperty("http.proxyPort", "") ;
3139 System.setProperty("https.proxyHost","") ;
3140 System.setProperty("https.proxyPort", "") ;
3143 System.setProperty("http.proxyHost",Global.getProxyValue("url")) ;
3144 System.setProperty("http.proxyPort", Global.getProxyValue("port")) ;
3145 System.setProperty("https.proxyHost",Global.getProxyValue("url")) ;
3146 System.setProperty("https.proxyPort", Global.getProxyValue("port")) ;
3148 if (Global.getProxyValue("userid").equals("")) {
3149 Authenticator.setDefault(new Authenticator() {
3151 protected PasswordAuthentication getPasswordAuthentication() {
3153 PasswordAuthentication(Global.getProxyValue("userid"),Global.getProxyValue("password").toCharArray());
3159 syncRunner.userStoreUrl = Global.userStoreUrl;
3160 syncRunner.noteStoreUrl = Global.noteStoreUrl;
3161 syncRunner.noteStoreUrlBase = Global.noteStoreUrlBase;
3163 String userid = aes.getUserid();
3164 String password = aes.getPassword();
3165 if (!userid.equals("") && !password.equals("")) {
3166 Global.username = userid;
3167 Global.password = password;
3168 syncRunner.username = Global.username;
3169 syncRunner.password = Global.password;
3170 syncRunner.enConnect();
3173 Global.isConnected = syncRunner.isConnected;
3175 if (!Global.isConnected) {
3176 // Show the login dialog box
3177 if (!Global.automaticLogin() || userid.equals("")|| password.equals("")) {
3178 LoginDialog login = new LoginDialog();
3181 if (!login.okPressed()) {
3185 Global.username = login.getUserid();
3186 Global.password = login.getPassword();
3188 syncRunner.username = Global.username;
3189 syncRunner.password = Global.password;
3190 syncRunner.enConnect();
3191 Global.isConnected = syncRunner.isConnected;
3194 if (!Global.isConnected)
3197 setupConnectMenuOptions();
3198 logger.log(logger.HIGH, "Leaving NeverNote.remoteConnect");
3200 private void setupConnectMenuOptions() {
3201 logger.log(logger.HIGH, "entering NeverNote.setupConnectMenuOptions");
3202 if (!Global.isConnected) {
3203 menuBar.connectAction.setText(tr("Connect"));
3204 menuBar.connectAction.setToolTip(tr("Connect to Evernote"));
3205 menuBar.synchronizeAction.setEnabled(false);
3207 menuBar.connectAction.setText(tr("Disconnect"));
3208 menuBar.connectAction.setToolTip(tr("Disconnect from Evernote"));
3209 menuBar.synchronizeAction.setEnabled(true);
3211 logger.log(logger.HIGH, "Leaving NeverNote.setupConnectionMenuOptions");
3216 //***************************************************************
3217 //***************************************************************
3218 //** These functions deal with the GUI Attribute tree
3219 //***************************************************************
3220 //***************************************************************
3221 @SuppressWarnings("unused")
3222 private void attributeTreeClicked(QTreeWidgetItem item, Integer integer) {
3224 // clearTagFilter();
3225 // clearNotebookFilter();
3227 // clearSavedSearchFilter();
3229 if (attributeTreeSelected == null || item.nativeId() != attributeTreeSelected.nativeId()) {
3230 if (item.childCount() > 0) {
3231 item.setSelected(false);
3233 Global.createdBeforeFilter.reset();
3234 Global.createdSinceFilter.reset();
3235 Global.changedBeforeFilter.reset();
3236 Global.changedSinceFilter.reset();
3237 Global.containsFilter.reset();
3238 attributeTreeSelected = item;
3239 DateAttributeFilterTable f = null;
3240 f = findDateAttributeFilterTable(item.parent());
3242 f.select(item.parent().indexOfChild(item));
3244 Global.containsFilter.select(item.parent().indexOfChild(item));
3247 listManager.loadNotesIndex();
3248 noteIndexUpdated(false);
3251 attributeTreeSelected = null;
3252 item.setSelected(false);
3253 Global.createdBeforeFilter.reset();
3254 Global.createdSinceFilter.reset();
3255 Global.changedBeforeFilter.reset();
3256 Global.changedSinceFilter.reset();
3257 Global.containsFilter.reset();
3258 listManager.loadNotesIndex();
3259 noteIndexUpdated(false);
3261 // This determines what attribute filter we need, depending upon the selection
3262 private DateAttributeFilterTable findDateAttributeFilterTable(QTreeWidgetItem w) {
3263 if (w.parent() != null && w.childCount() > 0) {
3264 QTreeWidgetItem parent = w.parent();
3265 if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Created &&
3266 w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Since)
3267 return Global.createdSinceFilter;
3268 if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Created &&
3269 w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Before)
3270 return Global.createdBeforeFilter;
3271 if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.LastModified &&
3272 w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Since)
3273 return Global.changedSinceFilter;
3274 if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.LastModified &&
3275 w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Before)
3276 return Global.changedBeforeFilter;
3281 // Show/Hide attribute search window
3282 private void toggleAttributesWindow() {
3283 logger.log(logger.HIGH, "Entering NeverNote.toggleAttributesWindow");
3284 if (attributeTree.isVisible())
3285 attributeTree.hide();
3287 attributeTree.show();
3288 menuBar.hideAttributes.setChecked(attributeTree.isVisible());
3290 Global.saveWindowVisible("attributeTree", attributeTree.isVisible());
3291 logger.log(logger.HIGH, "Leaving NeverNote.toggleAttributeWindow");
3293 private void clearAttributeFilter() {
3294 Global.createdBeforeFilter.reset();
3295 Global.createdSinceFilter.reset();
3296 Global.changedBeforeFilter.reset();
3297 Global.changedSinceFilter.reset();
3298 Global.containsFilter.reset();
3299 attributeTreeSelected = null;
3300 attributeTree.blockSignals(true);
3301 attributeTree.clearSelection();
3302 attributeTree.blockSignals(false);
3306 //***************************************************************
3307 //***************************************************************
3308 //** These functions deal with the GUI Note index table
3309 //***************************************************************
3310 //***************************************************************
3311 // Initialize the note list table
3312 private void initializeNoteTable() {
3313 logger.log(logger.HIGH, "Entering NeverNote.initializeNoteTable");
3314 noteTableView.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection);
3315 noteTableView.selectionModel().selectionChanged.connect(this, "noteTableSelection()");
3316 logger.log(logger.HIGH, "Leaving NeverNote.initializeNoteTable");
3318 // Show/Hide trash window
3319 @SuppressWarnings("unused")
3320 private void toggleNoteListWindow() {
3321 logger.log(logger.HIGH, "Entering NeverNote.toggleNoteListWindow");
3322 if (noteTableView.isVisible())
3323 noteTableView.hide();
3325 noteTableView.show();
3326 menuBar.hideNoteList.setChecked(noteTableView.isVisible());
3328 Global.saveWindowVisible("noteList", noteTableView.isVisible());
3329 logger.log(logger.HIGH, "Leaving NeverNote.toggleNoteListWindow");
3331 // Handle the event that a user selects a note from the table
3332 @SuppressWarnings("unused")
3333 private void noteTableSelection() {
3334 logger.log(logger.HIGH, "Entering NeverNote.noteTableSelection");
3336 if (historyGuids.size() == 0) {
3337 historyGuids.add(currentNoteGuid);
3338 historyPosition = 1;
3340 noteTableView.showColumn(Global.noteTableGuidPosition);
3342 List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
3343 if (!Global.isColumnVisible("guid"))
3344 noteTableView.hideColumn(Global.noteTableGuidPosition);
3346 if (selections.size() > 0) {
3348 menuBar.noteDuplicateAction.setEnabled(true);
3349 menuBar.noteOnlineHistoryAction.setEnabled(true);
3350 menuBar.noteMergeAction.setEnabled(true);
3351 selectedNoteGUIDs.clear();
3352 if (selections.size() != 1 || Global.showDeleted) {
3353 menuBar.noteDuplicateAction.setEnabled(false);
3355 if (selections.size() != 1 || !Global.isConnected) {
3356 menuBar.noteOnlineHistoryAction.setEnabled(false);
3358 if (selections.size() == 1) {
3359 menuBar.noteMergeAction.setEnabled(false);
3361 for (int i=0; i<selections.size(); i++) {
3362 int row = selections.get(i).row();
3364 upButton.setEnabled(false);
3366 upButton.setEnabled(true);
3367 if (row < listManager.getNoteTableModel().rowCount()-1)
3368 downButton.setEnabled(true);
3370 downButton.setEnabled(false);
3371 index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition);
3372 SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
3373 currentNoteGuid = (String)ix.values().toArray()[0];
3374 selectedNoteGUIDs.add(currentNoteGuid);
3378 nextButton.setEnabled(true);
3379 prevButton.setEnabled(true);
3381 int endPosition = historyGuids.size()-1;
3382 for (int j=historyPosition; j<=endPosition; j++) {
3383 historyGuids.remove(historyGuids.size()-1);
3385 historyGuids.add(currentNoteGuid);
3386 historyPosition = historyGuids.size();
3388 if (historyPosition <= 1)
3389 prevButton.setEnabled(false);
3390 if (historyPosition == historyGuids.size())
3391 nextButton.setEnabled(false);
3393 fromHistory = false;
3394 scrollToGuid(currentNoteGuid);
3395 refreshEvernoteNote(true);
3396 logger.log(logger.HIGH, "Leaving NeverNote.noteTableSelection");
3398 // Trigger a refresh when the note db has been updated
3399 private void noteIndexUpdated(boolean reload) {
3400 logger.log(logger.HIGH, "Entering NeverNote.noteIndexUpdated");
3402 refreshEvernoteNoteList();
3403 logger.log(logger.HIGH, "Calling note table reload in NeverNote.noteIndexUpdated() - "+reload);
3404 noteTableView.load(reload);
3405 if (currentNoteGuid == null || currentNoteGuid.equals("")) {
3407 if (noteTableView.proxyModel.sortOrder() == SortOrder.AscendingOrder)
3408 pos = noteTableView.proxyModel.rowCount();
3411 if (noteTableView.proxyModel.rowCount() == 0)
3414 QModelIndex i = noteTableView.proxyModel.index(pos-1, Global.noteTableGuidPosition);
3416 currentNoteGuid = (String)i.data();
3417 noteTableView.selectRow(pos-1);
3422 scrollToGuid(currentNoteGuid);
3423 logger.log(logger.HIGH, "Leaving NeverNote.noteIndexUpdated");
3425 // Called when the list of notes is updated
3426 private void refreshEvernoteNoteList() {
3427 logger.log(logger.HIGH, "Entering NeverNote.refreshEvernoteNoteList");
3428 browserWindow.setDisabled(false);
3429 if (selectedNoteGUIDs == null)
3430 selectedNoteGUIDs = new ArrayList<String>();
3431 selectedNoteGUIDs.clear(); // clear out old entries
3433 String saveCurrentNoteGuid = new String();
3434 String tempNoteGuid = new String();
3436 historyGuids.clear();
3437 historyPosition = 0;
3438 prevButton.setEnabled(false);
3439 nextButton.setEnabled(false);
3441 if (currentNoteGuid == null)
3442 currentNoteGuid = new String();
3444 //determine current note guid
3445 for (Note note : listManager.getNoteIndex()) {
3446 tempNoteGuid = note.getGuid();
3447 if (currentNoteGuid.equals(tempNoteGuid)) {
3448 saveCurrentNoteGuid = tempNoteGuid;
3452 if (listManager.getNoteIndex().size() == 0) {
3453 currentNoteGuid = "";
3455 browserWindow.clear();
3456 browserWindow.setDisabled(true);
3459 if (!saveCurrentNoteGuid.equals("")) {
3460 refreshEvernoteNote(false);
3462 currentNoteGuid = "";
3464 reloadTagTree(false);
3466 logger.log(logger.HIGH, "Leaving NeverNote.refreshEvernoteNoteList");
3468 // Called when the previous arrow button is clicked
3469 @SuppressWarnings("unused")
3470 private void previousViewedAction() {
3471 if (!prevButton.isEnabled())
3473 if (historyPosition == 0)
3476 if (historyPosition <= 0)
3478 String historyGuid = historyGuids.get(historyPosition-1);
3480 for (int i=0; i<noteTableView.model().rowCount(); i++) {
3481 QModelIndex modelIndex = noteTableView.model().index(i, Global.noteTableGuidPosition);
3482 if (modelIndex != null) {
3483 SortedMap<Integer, Object> ix = noteTableView.model().itemData(modelIndex);
3484 String tableGuid = (String)ix.values().toArray()[0];
3485 if (tableGuid.equals(historyGuid)) {
3486 noteTableView.selectRow(i);
3492 @SuppressWarnings("unused")
3493 private void nextViewedAction() {
3494 if (!nextButton.isEnabled())
3496 String historyGuid = historyGuids.get(historyPosition);
3499 for (int i=0; i<noteTableView.model().rowCount(); i++) {
3500 QModelIndex modelIndex = noteTableView.model().index(i, Global.noteTableGuidPosition);
3501 if (modelIndex != null) {
3502 SortedMap<Integer, Object> ix = noteTableView.model().itemData(modelIndex);
3503 String tableGuid = (String)ix.values().toArray()[0];
3504 if (tableGuid.equals(historyGuid)) {
3505 noteTableView.selectRow(i);
3511 // Called when the up arrow is clicked
3512 @SuppressWarnings("unused")
3513 private void upAction() {
3514 List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
3515 int row = selections.get(0).row();
3517 noteTableView.selectRow(row-1);
3520 // Called when the down arrow is clicked
3521 @SuppressWarnings("unused")
3522 private void downAction() {
3523 List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
3524 int row = selections.get(0).row();
3525 int max = listManager.getNoteTableModel().rowCount();
3527 noteTableView.selectRow(row+1);
3530 // Update a tag string for a specific note in the list
3531 @SuppressWarnings("unused")
3532 private void updateListTags(String guid, List<String> tags) {
3533 logger.log(logger.HIGH, "Entering NeverNote.updateListTags");
3534 StringBuffer tagBuffer = new StringBuffer();
3535 for (int i=0; i<tags.size(); i++) {
3536 tagBuffer.append(tags.get(i));
3537 if (i<tags.size()-1)
3538 tagBuffer.append(", ");
3541 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3542 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3543 if (modelIndex != null) {
3544 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3545 String tableGuid = (String)ix.values().toArray()[0];
3546 if (tableGuid.equals(guid)) {
3547 listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition,tagBuffer.toString());
3548 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
3549 noteTableView.proxyModel.invalidate();
3554 logger.log(logger.HIGH, "Leaving NeverNote.updateListTags");
3556 // Update a title for a specific note in the list
3557 @SuppressWarnings("unused")
3558 private void updateListAuthor(String guid, String author) {
3559 logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
3561 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3562 //QModelIndex modelIndex = noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
3563 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3564 if (modelIndex != null) {
3565 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3566 String tableGuid = (String)ix.values().toArray()[0];
3567 if (tableGuid.equals(guid)) {
3568 listManager.getNoteTableModel().setData(i, Global.noteTableAuthorPosition,author);
3569 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
3570 noteTableView.proxyModel.invalidate();
3576 logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
3578 private void updateListNoteNotebook(String guid, String notebook) {
3579 logger.log(logger.HIGH, "Entering NeverNote.updateListNoteNotebook");
3580 listManager.getNoteTableModel().updateNoteSyncStatus(guid, false);
3581 logger.log(logger.HIGH, "Leaving NeverNote.updateListNoteNotebook");
3583 // Update a title for a specific note in the list
3584 @SuppressWarnings("unused")
3585 private void updateListSourceUrl(String guid, String url) {
3586 logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
3588 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3589 //QModelIndex modelIndex = noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
3590 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3591 if (modelIndex != null) {
3592 // SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(modelIndex);
3593 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3594 String tableGuid = (String)ix.values().toArray()[0];
3595 if (tableGuid.equals(guid)) {
3596 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
3597 listManager.getNoteTableModel().setData(i, Global.noteTableSourceUrlPosition,url);
3598 noteTableView.proxyModel.invalidate();
3603 logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
3605 @SuppressWarnings("unused")
3606 private void updateListGuid(String oldGuid, String newGuid) {
3607 logger.log(logger.HIGH, "Entering NeverNote.updateListTitle");
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(oldGuid)) {
3615 listManager.getNoteTableModel().setData(i, Global.noteTableGuidPosition,newGuid);
3616 //listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
3621 logger.log(logger.HIGH, "Leaving NeverNote.updateListTitle");
3623 private void updateListTagName(String guid) {
3624 logger.log(logger.HIGH, "Entering NeverNote.updateTagName");
3626 for (int j=0; j<listManager.getNoteIndex().size(); j++) {
3627 if (listManager.getNoteIndex().get(j).getTagGuids().contains(guid)) {
3628 String newName = listManager.getTagNamesForNote(listManager.getNoteIndex().get(j));
3630 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3631 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3632 if (modelIndex != null) {
3633 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3634 String noteGuid = (String)ix.values().toArray()[0];
3635 if (noteGuid.equalsIgnoreCase(listManager.getNoteIndex().get(j).getGuid())) {
3636 listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition, newName);
3637 i=listManager.getNoteTableModel().rowCount();
3643 logger.log(logger.HIGH, "Leaving NeverNote.updateListNotebook");
3645 private void removeListTagName(String guid) {
3646 logger.log(logger.HIGH, "Entering NeverNote.updateTagName");
3648 for (int j=0; j<listManager.getNoteIndex().size(); j++) {
3649 if (listManager.getNoteIndex().get(j).getTagGuids().contains(guid)) {
3650 for (int i=listManager.getNoteIndex().get(j).getTagGuids().size()-1; i>=0; i--) {
3651 if (listManager.getNoteIndex().get(j).getTagGuids().get(i).equals(guid))
3652 listManager.getNoteIndex().get(j).getTagGuids().remove(i);
3655 String newName = listManager.getTagNamesForNote(listManager.getNoteIndex().get(j));
3656 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3657 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3658 if (modelIndex != null) {
3659 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3660 String noteGuid = (String)ix.values().toArray()[0];
3661 if (noteGuid.equalsIgnoreCase(listManager.getNoteIndex().get(j).getGuid())) {
3662 listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition, newName);
3663 i=listManager.getNoteTableModel().rowCount();
3669 logger.log(logger.HIGH, "Leaving NeverNote.updateListNotebook");
3671 private void updateListNotebookName(String oldName, String newName) {
3672 logger.log(logger.HIGH, "Entering NeverNote.updateListNotebookName");
3674 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3675 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableNotebookPosition);
3676 if (modelIndex != null) {
3677 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3678 String tableName = (String)ix.values().toArray()[0];
3679 if (tableName.equalsIgnoreCase(oldName)) {
3680 listManager.getNoteTableModel().setData(i, Global.noteTableNotebookPosition, newName);
3684 logger.log(logger.HIGH, "Leaving NeverNote.updateListNotebookName");
3686 @SuppressWarnings("unused")
3687 private void updateListDateCreated(String guid, QDateTime date) {
3688 logger.log(logger.HIGH, "Entering NeverNote.updateListDateCreated");
3690 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3691 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3692 if (modelIndex != null) {
3693 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3694 String tableGuid = (String)ix.values().toArray()[0];
3695 if (tableGuid.equals(guid)) {
3696 listManager.getNoteTableModel().setData(i, Global.noteTableCreationPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
3697 noteTableView.proxyModel.invalidate();
3702 logger.log(logger.HIGH, "Leaving NeverNote.updateListDateCreated");
3704 @SuppressWarnings("unused")
3705 private void updateListDateSubject(String guid, QDateTime date) {
3706 logger.log(logger.HIGH, "Entering NeverNote.updateListDateSubject");
3708 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3709 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3710 if (modelIndex != null) {
3711 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3712 String tableGuid = (String)ix.values().toArray()[0];
3713 if (tableGuid.equals(guid)) {
3714 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
3715 listManager.getNoteTableModel().setData(i, Global.noteTableSubjectDatePosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
3716 noteTableView.proxyModel.invalidate();
3721 logger.log(logger.HIGH, "Leaving NeverNote.updateListDateCreated");
3723 private void updateListDateChanged(String guid, QDateTime date) {
3724 logger.log(logger.HIGH, "Entering NeverNote.updateListDateChanged");
3726 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3727 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3728 if (modelIndex != null) {
3729 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3730 String tableGuid = (String)ix.values().toArray()[0];
3731 if (tableGuid.equals(guid)) {
3732 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
3733 listManager.getNoteTableModel().setData(i, Global.noteTableChangedPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
3738 logger.log(logger.HIGH, "Leaving NeverNote.updateListDateChanged");
3740 private void updateListDateChanged() {
3741 logger.log(logger.HIGH, "Entering NeverNote.updateListDateChanged");
3742 QDateTime date = new QDateTime(QDateTime.currentDateTime());
3743 updateListDateChanged(currentNoteGuid, date);
3744 logger.log(logger.HIGH, "Leaving NeverNote.updateListDateChanged");
3747 private void scrollToCurrentGuid() {
3748 //scrollToGuid(currentNoteGuid);
3749 List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
3750 if (selections.size() == 0)
3752 QModelIndex index = selections.get(0);
3753 int row = selections.get(0).row();
3754 String guid = (String)index.model().index(row, Global.noteTableGuidPosition).data();
3757 // Scroll to a particular index item
3758 private void scrollToGuid(String guid) {
3759 if (currentNote == null || guid == null)
3761 if (currentNote.isActive() && Global.showDeleted) {
3762 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
3763 if (!listManager.getNoteIndex().get(i).isActive()) {
3764 currentNote = listManager.getNoteIndex().get(i);
3765 currentNoteGuid = currentNote.getGuid();
3766 i = listManager.getNoteIndex().size();
3771 if (!currentNote.isActive() && !Global.showDeleted) {
3772 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
3773 if (listManager.getNoteIndex().get(i).isActive()) {
3774 currentNote = listManager.getNoteIndex().get(i);
3775 currentNoteGuid = currentNote.getGuid();
3776 i = listManager.getNoteIndex().size();
3782 for (int i=0; i<noteTableView.model().rowCount(); i++) {
3783 index = noteTableView.model().index(i, Global.noteTableGuidPosition);
3784 if (currentNoteGuid.equals(index.data())) {
3785 // noteTableView.setCurrentIndex(index);
3786 noteTableView.selectRow(i);
3787 noteTableView.scrollTo(index, ScrollHint.EnsureVisible); // This should work, but it doesn't
3788 i=listManager.getNoteTableModel().rowCount();
3791 noteTableView.repaint();
3793 // Show/Hide columns
3794 private void showColumns() {
3795 noteTableView.setColumnHidden(Global.noteTableCreationPosition, !Global.isColumnVisible("dateCreated"));
3796 noteTableView.setColumnHidden(Global.noteTableChangedPosition, !Global.isColumnVisible("dateChanged"));
3797 noteTableView.setColumnHidden(Global.noteTableSubjectDatePosition, !Global.isColumnVisible("dateSubject"));
3798 noteTableView.setColumnHidden(Global.noteTableAuthorPosition, !Global.isColumnVisible("author"));
3799 noteTableView.setColumnHidden(Global.noteTableSourceUrlPosition, !Global.isColumnVisible("sourceUrl"));
3800 noteTableView.setColumnHidden(Global.noteTableTagPosition, !Global.isColumnVisible("tags"));
3801 noteTableView.setColumnHidden(Global.noteTableNotebookPosition, !Global.isColumnVisible("notebook"));
3802 noteTableView.setColumnHidden(Global.noteTableSynchronizedPosition, !Global.isColumnVisible("synchronized"));
3803 noteTableView.setColumnHidden(Global.noteTableGuidPosition, !Global.isColumnVisible("guid"));
3804 noteTableView.setColumnHidden(Global.noteTableThumbnailPosition, !Global.isColumnVisible("thumbnail"));
3805 noteTableView.setColumnHidden(Global.noteTableTitlePosition, !Global.isColumnVisible("title"));
3807 // Title color has changed
3808 @SuppressWarnings("unused")
3809 private void titleColorChanged(Integer color) {
3810 logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
3812 QColor backgroundColor = new QColor();
3813 QColor foregroundColor = new QColor(QColor.black);
3814 backgroundColor.setRgb(color);
3816 if (backgroundColor.rgb() == QColor.black.rgb() || backgroundColor.rgb() == QColor.blue.rgb())
3817 foregroundColor.setRgb(QColor.white.rgb());
3819 if (selectedNoteGUIDs.size() == 0)
3820 selectedNoteGUIDs.add(currentNoteGuid);
3822 for (int j=0; j<selectedNoteGUIDs.size(); j++) {
3823 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3824 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3825 if (modelIndex != null) {
3826 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3827 String tableGuid = (String)ix.values().toArray()[0];
3828 if (tableGuid.equals(selectedNoteGUIDs.get(j))) {
3829 for (int k=0; k<Global.noteTableColumnCount; k++) {
3830 listManager.getNoteTableModel().setData(i, k, backgroundColor, Qt.ItemDataRole.BackgroundRole);
3831 listManager.getNoteTableModel().setData(i, k, foregroundColor, Qt.ItemDataRole.ForegroundRole);
3832 listManager.updateNoteTitleColor(selectedNoteGUIDs.get(j), backgroundColor.rgb());
3834 i=listManager.getNoteTableModel().rowCount();
3839 logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
3841 // Wide list was chosen
3842 public void narrowListView() {
3843 saveNoteColumnPositions();
3844 saveNoteIndexWidth();
3846 int sortCol = noteTableView.proxyModel.sortColumn();
3847 int sortOrder = noteTableView.proxyModel.sortOrder().value();
3848 Global.setSortColumn(sortCol);
3849 Global.setSortOrder(sortOrder);
3851 Global.setListView(Global.View_List_Narrow);
3853 menuBar.wideListView.blockSignals(true);
3854 menuBar.narrowListView.blockSignals(true);
3856 menuBar.wideListView.setChecked(false);
3857 menuBar.narrowListView.setChecked(true);
3859 menuBar.wideListView.blockSignals(false);
3860 menuBar.narrowListView.blockSignals(false);
3862 mainLeftRightSplitter.addWidget(noteTableView);
3863 mainLeftRightSplitter.addWidget(browserWindow);
3864 restoreWindowState(false);
3865 noteTableView.repositionColumns();
3866 noteTableView.resizeColumnWidths();
3867 noteTableView.resizeRowHeights();
3869 sortCol = Global.getSortColumn();
3870 sortOrder = Global.getSortOrder();
3871 noteTableView.sortByColumn(sortCol, SortOrder.resolve(sortOrder));
3874 noteTableView.load(false);
3875 scrollToCurrentGuid();
3877 public void wideListView() {
3878 int sortCol = noteTableView.proxyModel.sortColumn();
3879 int sortOrder = noteTableView.proxyModel.sortOrder().value();
3880 Global.setSortColumn(sortCol);
3881 Global.setSortOrder(sortOrder);
3884 saveNoteColumnPositions();
3885 saveNoteIndexWidth();
3886 Global.setListView(Global.View_List_Wide);
3888 menuBar.wideListView.blockSignals(true);
3889 menuBar.narrowListView.blockSignals(true);
3891 menuBar.wideListView.setChecked(true);
3892 menuBar.narrowListView.setChecked(false);
3894 menuBar.wideListView.blockSignals(false);
3895 menuBar.narrowListView.blockSignals(false);
3896 browserIndexSplitter.setVisible(true);
3897 browserIndexSplitter.addWidget(noteTableView);
3898 browserIndexSplitter.addWidget(browserWindow);
3899 restoreWindowState(false);
3900 noteTableView.repositionColumns();
3901 noteTableView.resizeColumnWidths();
3902 noteTableView.resizeRowHeights();
3904 sortCol = Global.getSortColumn();
3905 sortOrder = Global.getSortOrder();
3906 noteTableView.sortByColumn(sortCol, SortOrder.resolve(sortOrder));
3909 noteTableView.load(false);
3910 scrollToCurrentGuid();
3914 //***************************************************************
3915 //***************************************************************
3916 //** External editor window functions
3917 //***************************************************************
3918 //***************************************************************
3919 private void listDoubleClick() {
3921 if (externalWindows.containsKey(currentNoteGuid)) {
3922 externalWindows.get(currentNoteGuid).raise();
3925 // We have a new external editor to create
3926 QIcon appIcon = new QIcon(iconPath+"nevernote.png");
3927 ExternalBrowse newBrowser = new ExternalBrowse(conn);
3928 newBrowser.setWindowIcon(appIcon);
3929 externalWindows.put(currentNoteGuid, newBrowser);
3930 showEditorButtons(newBrowser.getBrowserWindow());
3931 loadNoteBrowserInformation(newBrowser.getBrowserWindow());
3932 setupBrowserWindowListeners(newBrowser.getBrowserWindow(), false);
3933 newBrowser.windowClosing.connect(this, "externalWindowClosing(String)");
3934 newBrowser.getBrowserWindow().noteSignal.titleChanged.connect(this, "externalWindowTitleEdited(String, String)");
3935 newBrowser.getBrowserWindow().noteSignal.tagsChanged.connect(this, "externalWindowTagsEdited(String, List)");
3936 newBrowser.contentsChanged.connect(this, "saveNoteExternalBrowser(String, String, Boolean, BrowserWindow)");
3938 browserWindow.noteSignal.tagsChanged.connect(newBrowser, "updateTags(String, List)");
3939 browserWindow.noteSignal.titleChanged.connect(newBrowser, "updateTitle(String, String)");
3940 browserWindow.noteSignal.notebookChanged.connect(newBrowser, "updateNotebook(String, String)");
3944 @SuppressWarnings("unused")
3945 private void externalWindowTitleEdited(String guid, String text) {
3946 if (guid.equals(currentNoteGuid)) {
3947 browserWindow.setTitle(text);
3950 @SuppressWarnings({ "rawtypes", "unused" })
3951 private void externalWindowTagsEdited(String guid, List values) {
3952 StringBuffer line = new StringBuffer(100);
3953 for (int i=0; i<values.size(); i++) {
3955 line.append(Global.tagDelimeter+" ");
3956 line.append(values.get(i));
3958 if (guid.equals(currentNoteGuid)) {
3959 browserWindow.setTag(line.toString());
3962 @SuppressWarnings("unused")
3963 private void externalWindowClosing(String guid) {
3964 externalWindows.remove(guid);
3969 //***************************************************************
3970 //***************************************************************
3971 //** These functions deal with Note specific things
3972 //***************************************************************
3973 //***************************************************************
3974 @SuppressWarnings("unused")
3975 private void setNoteDirty() {
3976 logger.log(logger.EXTREME, "Entering NeverNote.setNoteDirty()");
3978 // Find if the note is being edited externally. If it is, update it.
3979 if (externalWindows.containsKey(currentNoteGuid)) {
3980 QTextCodec codec = QTextCodec.codecForName("UTF-8");
3981 QByteArray unicode = codec.fromUnicode(browserWindow.getContent());
3982 ExternalBrowse window = externalWindows.get(currentNoteGuid);
3983 window.getBrowserWindow().getBrowser().setContent(unicode);
3986 // If the note is dirty, then it is unsynchronized by default.
3990 // Set the note as dirty and check if its status is synchronized in the display table
3992 for (int i=0; i<listManager.getUnsynchronizedNotes().size(); i++) {
3993 if (listManager.getUnsynchronizedNotes().get(i).equals(currentNoteGuid))
3997 // If this wasn't already marked as unsynchronized, then we need to update the table
3998 listManager.getNoteTableModel().updateNoteSyncStatus(currentNoteGuid, false);
3999 /* listManager.getUnsynchronizedNotes().add(currentNoteGuid);
4000 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4001 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4002 if (modelIndex != null) {
4003 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4004 String tableGuid = (String)ix.values().toArray()[0];
4005 if (tableGuid.equals(currentNoteGuid)) {
4006 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
4012 logger.log(logger.EXTREME, "Leaving NeverNote.setNoteDirty()");
4014 @SuppressWarnings("unused")
4015 private void saveNoteExternalBrowser(String guid, String content, Boolean save, BrowserWindow browser) {
4016 QTextCodec codec = QTextCodec.codecForName("UTF-8");
4017 QByteArray unicode = codec.fromUnicode(content);
4018 noteCache.remove(guid);
4019 noteCache.put(guid, unicode.toString());
4020 if (guid.equals(currentNoteGuid)) {
4022 browserWindow.getBrowser().setContent(unicode);
4025 thumbnailRunner.addWork("GENERATE "+ guid);
4026 saveNote(guid, browser);
4030 private void saveNote() {
4032 saveNote(currentNoteGuid, browserWindow);
4033 thumbnailRunner.addWork("GENERATE "+ currentNoteGuid);
4037 private void saveNote(String guid, BrowserWindow window) {
4038 logger.log(logger.EXTREME, "Inside NeverNote.saveNote()");
4039 logger.log(logger.EXTREME, "Note is dirty.");
4042 logger.log(logger.EXTREME, "Saving to cache");
4043 QTextCodec codec = QTextCodec.codecForLocale();
4044 // QTextDecoder decoder = codec.makeDecoder();
4045 codec = QTextCodec.codecForName("UTF-8");
4046 QByteArray unicode = codec.fromUnicode(window.getContent());
4047 noteCache.put(guid, unicode.toString());
4049 logger.log(logger.EXTREME, "updating list manager");
4050 listManager.updateNoteContent(guid, window.getContent());
4051 logger.log(logger.EXTREME, "Updating title");
4052 listManager.updateNoteTitle(guid, window.getTitle());
4053 updateListDateChanged();
4055 logger.log(logger.EXTREME, "Looking through note index for refreshed note");
4056 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
4057 if (listManager.getNoteIndex().get(i).getGuid().equals(guid)) {
4058 currentNote = listManager.getNoteIndex().get(i);
4059 i = listManager.getNoteIndex().size();
4064 // Get a note from Evernote (and put it in the browser)
4065 private void refreshEvernoteNote(boolean reload) {
4066 logger.log(logger.HIGH, "Entering NeverNote.refreshEvernoteNote");
4068 if (Global.disableViewing) {
4069 browserWindow.setEnabled(false);
4074 if (Global.showDeleted)
4076 Global.cryptCounter =0;
4077 if (currentNoteGuid.equals("")) {
4078 browserWindow.setReadOnly(true);
4086 browserWindow.loadingData(true);
4088 currentNote = conn.getNoteTable().getNote(currentNoteGuid, true,true,false,false,true);
4089 if (currentNote == null)
4092 loadNoteBrowserInformation(browserWindow);
4095 private void loadNoteBrowserInformation(BrowserWindow browser) {
4096 NoteFormatter formatter = new NoteFormatter(logger, conn, tempFiles);
4097 formatter.setNote(currentNote, Global.pdfPreview());
4098 formatter.setHighlight(listManager.getEnSearch());
4100 if (!noteCache.containsKey(currentNoteGuid) || conn.getNoteTable().isThumbnailNeeded(currentNoteGuid)) {
4101 js = new QByteArray();
4102 // We need to prepend the note with <HEAD></HEAD> or encoded characters are ugly
4103 js.append("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">");
4104 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>");
4105 js.append("<style type=\"text/css\">en-hilight { background-color: rgb(255,255,0) }</style>");
4106 js.append("<style> img { max-width:100%; }</style>");
4107 js.append("<style type=\"text/css\">en-spell { text-decoration: none; border-bottom: dotted 1px #cc0000; }</style>");
4108 js.append("</head>");
4109 formatter.setNote(currentNote, Global.pdfPreview());
4110 js.append(formatter.rebuildNoteHTML());
4111 js.append("</HTML>");
4112 js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml.dtd'>", "");
4113 js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml2.dtd'>", "");
4114 js.replace("<?xml version='1.0' encoding='UTF-8'?>", "");
4115 browser.getBrowser().setContent(js);
4116 noteCache.put(currentNoteGuid, js.toString());
4118 if (formatter.resourceError)
4119 resourceErrorMessage();
4120 readOnly = formatter.readOnly;
4121 inkNote = formatter.inkNote;
4123 readOnlyCache.put(currentNoteGuid, true);
4125 inkNoteCache.put(currentNoteGuid, true);
4127 logger.log(logger.HIGH, "Note content is being pulled from the cache");
4128 String cachedContent = formatter.modifyCachedTodoTags(noteCache.get(currentNoteGuid));
4129 js = new QByteArray(cachedContent);
4130 browser.getBrowser().setContent(js);
4131 if (readOnlyCache.containsKey(currentNoteGuid))
4133 if (inkNoteCache.containsKey(currentNoteGuid))
4136 if (conn.getNoteTable().isThumbnailNeeded(currentNoteGuid)) {
4137 thumbnailHTMLReady(currentNoteGuid, js, Global.calculateThumbnailZoom(js.toString()));
4140 if (readOnly || inkNote)
4141 browser.getBrowser().page().setContentEditable(false); // We don't allow editing of ink notes
4143 browser.getBrowser().page().setContentEditable(true);
4144 browser.setReadOnly(readOnly);
4145 deleteButton.setEnabled(!readOnly);
4146 tagButton.setEnabled(!readOnly);
4147 menuBar.noteDelete.setEnabled(!readOnly);
4148 menuBar.noteTags.setEnabled(!readOnly);
4149 browser.setNote(currentNote);
4151 if (conn.getNotebookTable().isLinked(currentNote.getNotebookGuid())) {
4152 deleteButton.setEnabled(false);
4153 menuBar.notebookDeleteAction.setEnabled(false);
4155 deleteButton.setEnabled(true);
4156 menuBar.notebookDeleteAction.setEnabled(true);
4159 // Build a list of non-closed notebooks
4160 List<Notebook> nbooks = new ArrayList<Notebook>();
4161 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
4162 boolean found=false;
4163 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
4164 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid()))
4168 nbooks.add(listManager.getNotebookIndex().get(i));
4171 browser.setTitle(currentNote.getTitle());
4172 browser.setTag(getTagNamesForNote(currentNote));
4173 browser.setAuthor(currentNote.getAttributes().getAuthor());
4175 browser.setAltered(currentNote.getUpdated());
4176 browser.setCreation(currentNote.getCreated());
4177 if (currentNote.getAttributes().getSubjectDate() > 0)
4178 browser.setSubjectDate(currentNote.getAttributes().getSubjectDate());
4180 browser.setSubjectDate(currentNote.getCreated());
4181 browser.setUrl(currentNote.getAttributes().getSourceURL());
4183 FilterEditorTags tagFilter = new FilterEditorTags(conn, logger);
4184 List<Tag> tagList = tagFilter.getValidTags(currentNote);
4185 browser.setAllTags(tagList);
4187 browser.setCurrentTags(currentNote.getTagNames());
4189 scrollToGuid(currentNoteGuid);
4191 browser.loadingData(false);
4192 if (thumbnailViewer.isActiveWindow())
4195 FilterEditorNotebooks notebookFilter = new FilterEditorNotebooks(conn, logger);
4196 browser.setNotebookList(notebookFilter.getValidNotebooks(currentNote, listManager.getNotebookIndex()));
4199 logger.log(logger.HIGH, "Leaving NeverNote.refreshEvernoteNote");
4201 // Save a generated thumbnail
4202 private void toggleNoteInformation() {
4203 logger.log(logger.HIGH, "Entering NeverNote.toggleNoteInformation");
4204 browserWindow.toggleInformation();
4205 menuBar.noteAttributes.setChecked(browserWindow.isExtended());
4206 Global.saveWindowVisible("noteInformation", browserWindow.isExtended());
4207 logger.log(logger.HIGH, "Leaving NeverNote.toggleNoteInformation");
4209 // Listener triggered when a print button is pressed
4210 @SuppressWarnings("unused")
4211 private void printNote() {
4212 logger.log(logger.HIGH, "Entering NeverNote.printNote");
4214 QPrintDialog dialog = new QPrintDialog();
4215 if (dialog.exec() == QDialog.DialogCode.Accepted.value()) {
4216 QPrinter printer = dialog.printer();
4217 browserWindow.getBrowser().print(printer);
4219 logger.log(logger.HIGH, "Leaving NeverNote.printNote");
4222 // Listener triggered when the email button is pressed
4223 @SuppressWarnings("unused")
4224 private void emailNote() {
4225 logger.log(logger.HIGH, "Entering NeverNote.emailNote");
4227 if (Desktop.isDesktopSupported()) {
4228 Desktop desktop = Desktop.getDesktop();
4230 String text2 = browserWindow.getContentsToEmail();
4231 QUrl url = new QUrl("mailto:");
4232 url.addQueryItem("subject", currentNote.getTitle());
4233 // url.addQueryItem("body", QUrl.toPercentEncoding(text2).toString());
4234 url.addQueryItem("body", text2);
4235 QDesktopServices.openUrl(url);
4239 if (desktop.isSupported(Desktop.Action.MAIL)) {
4240 URI uriMailTo = null;
4242 //String text = browserWindow.getBrowser().page().currentFrame().toPlainText();
4243 String text = browserWindow.getContentsToEmail();
4244 //text = "<b>" +text +"</b>";
4245 uriMailTo = new URI("mailto", "&SUBJECT="+currentNote.getTitle()
4246 +"&BODY=" +text, null);
4247 uriMailTo = new URI("mailto", "&SUBJECT="+currentNote.getTitle()
4248 +"&ATTACHMENT=d:/test.pdf", null);
4249 desktop.mail(uriMailTo);
4250 } catch (URISyntaxException e) {
4251 e.printStackTrace();
4252 } catch (IOException e) {
4253 e.printStackTrace();
4260 logger.log(logger.HIGH, "Leaving NeverNote.emailNote");
4262 // Reindex all notes
4263 @SuppressWarnings("unused")
4264 private void fullReindex() {
4265 logger.log(logger.HIGH, "Entering NeverNote.fullReindex");
4266 indexRunner.addWork("REINDEXALL");
4267 setMessage(tr("Database will be reindexed."));
4268 logger.log(logger.HIGH, "Leaving NeverNote.fullReindex");
4270 // Listener when a user wants to reindex a specific note
4271 @SuppressWarnings("unused")
4272 private void reindexNote() {
4273 logger.log(logger.HIGH, "Entering NeverNote.reindexNote");
4274 for (int i=0; i<selectedNoteGUIDs.size(); i++) {
4275 indexRunner.addWork("REINDEXNOTE "+selectedNoteGUIDs.get(i));
4277 if (selectedNotebookGUIDs.size() > 1)
4278 setMessage(tr("Notes will be reindexed."));
4280 setMessage(tr("Note will be reindexed."));
4281 logger.log(logger.HIGH, "Leaving NeverNote.reindexNote");
4284 @SuppressWarnings("unused")
4285 private void deleteNote() {
4286 logger.log(logger.HIGH, "Entering NeverNote.deleteNote");
4287 if (currentNote == null)
4289 if (currentNoteGuid.equals(""))
4292 // If we are deleting non-trash notes
4293 if (currentNote.isActive()) {
4294 if (Global.verifyDelete()) {
4295 if (QMessageBox.question(this, tr("Confirmation"), tr("Delete selected note(s)?"),
4296 QMessageBox.StandardButton.Yes,
4297 QMessageBox.StandardButton.No)==StandardButton.No.value() && Global.verifyDelete() == true) {
4301 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
4302 selectedNoteGUIDs.add(currentNoteGuid);
4303 for (int i=0; i<selectedNoteGUIDs.size(); i++) {
4304 listManager.deleteNote(selectedNoteGUIDs.get(i));
4307 // If we are deleting from the trash.
4308 if (Global.verifyDelete()) {
4309 if (QMessageBox.question(this, "Confirmation", "Permanently delete selected note(s)?",
4310 QMessageBox.StandardButton.Yes,
4311 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
4315 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
4316 selectedNoteGUIDs.add(currentNoteGuid);
4317 for (int i=selectedNoteGUIDs.size()-1; i>=0; i--) {
4318 for (int j=listManager.getNoteTableModel().rowCount()-1; j>=0; j--) {
4319 QModelIndex modelIndex = listManager.getNoteTableModel().index(j, Global.noteTableGuidPosition);
4320 if (modelIndex != null) {
4321 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4322 String tableGuid = (String)ix.values().toArray()[0];
4323 if (tableGuid.equals(selectedNoteGUIDs.get(i))) {
4324 listManager.getNoteTableModel().removeRow(j);
4329 listManager.expungeNote(selectedNoteGUIDs.get(i));
4332 currentNoteGuid = "";
4333 listManager.loadNotesIndex();
4334 noteIndexUpdated(false);
4335 refreshEvernoteNote(true);
4336 scrollToGuid(currentNoteGuid);
4337 logger.log(logger.HIGH, "Leaving NeverNote.deleteNote");
4340 @SuppressWarnings("unused")
4341 private void addNote() {
4342 logger.log(logger.HIGH, "Inside NeverNote.addNote");
4343 // browserWindow.setEnabled(true);
4344 browserWindow.setReadOnly(false);
4346 Calendar currentTime = new GregorianCalendar();
4347 StringBuffer noteString = new StringBuffer(100);
4348 noteString.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
4349 "<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">\n" +
4352 if (Global.overrideDefaultFont()) {
4353 noteString.append("<font face=\"" +Global.getDefaultFont() +"\" >");
4354 noteString.append("<span style=\"font-size:" +Global.getDefaultFontSize() +"pt;\">");
4355 noteString.append("<br clear=\"none\" />\n");
4356 noteString.append("</span>\n</font>\n");
4358 noteString.append("<br clear=\"none\" />\n");
4359 noteString.append("</en-note>");
4361 Long l = new Long(currentTime.getTimeInMillis());
4362 String randint = new String(Long.toString(l));
4364 // Find a notebook. We first look for a selected notebook (the "All Notebooks" one doesn't count).
4366 // for the first non-archived notebook. Finally, if nothing else we
4367 // pick the first notebook in the list.
4368 String notebook = null;
4369 listManager.getNotebookIndex().get(0).getGuid();
4370 List<QTreeWidgetItem> selectedNotebook = notebookTree.selectedItems();
4371 if (selectedNotebook.size() > 0 && !selectedNotebook.get(0).text(0).equalsIgnoreCase("All Notebooks")) {
4372 QTreeWidgetItem currentSelectedNotebook = selectedNotebook.get(0);
4373 notebook = currentSelectedNotebook.text(2);
4375 boolean found = false;
4376 List<Notebook> goodNotebooks = new ArrayList<Notebook>();
4377 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
4378 boolean match = false;
4379 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
4380 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid())) {
4382 j = listManager.getArchiveNotebookIndex().size();
4386 goodNotebooks.add(listManager.getNotebookIndex().get(i).deepCopy());
4388 // Now we have a list of good notebooks, so we can look for the default
4390 for (int i=0; i<goodNotebooks.size(); i++) {
4391 if (goodNotebooks.get(i).isDefaultNotebook()) {
4392 notebook = goodNotebooks.get(i).getGuid();
4394 i = goodNotebooks.size();
4398 if (goodNotebooks.size() > 0 && !found)
4399 notebook = goodNotebooks.get(0).getGuid();
4402 notebook = listManager.getNotebookIndex().get(0).getGuid();
4405 Note newNote = new Note();
4406 newNote.setUpdateSequenceNum(0);
4407 newNote.setGuid(randint);
4408 newNote.setNotebookGuid(notebook);
4409 newNote.setTitle("");
4410 newNote.setContent(noteString.toString());
4411 newNote.setDeleted(0);
4412 newNote.setCreated(System.currentTimeMillis());
4413 newNote.setUpdated(System.currentTimeMillis());
4414 newNote.setActive(true);
4415 NoteAttributes na = new NoteAttributes();
4416 na.setLatitude(0.0);
4417 na.setLongitude(0.0);
4418 na.setAltitude(0.0);
4419 newNote.setAttributes(new NoteAttributes());
4420 newNote.setTagGuids(new ArrayList<String>());
4421 newNote.setTagNames(new ArrayList<String>());
4423 // If new notes are to be created based upon the selected tags, then we need to assign the tags
4424 if (Global.newNoteWithSelectedTags()) {
4425 List<QTreeWidgetItem> selections = tagTree.selectedItems();
4426 QTreeWidgetItem currentSelection;
4427 for (int i=0; i<selections.size(); i++) {
4428 currentSelection = selections.get(i);
4429 newNote.getTagGuids().add(currentSelection.text(2));
4430 newNote.getTagNames().add(currentSelection.text(0));
4434 conn.getNoteTable().addNote(newNote, true);
4435 listManager.getUnsynchronizedNotes().add(newNote.getGuid());
4436 listManager.addNote(newNote);
4437 // noteTableView.insertRow(newNote, true, -1);
4439 currentNote = newNote;
4440 currentNoteGuid = currentNote.getGuid();
4441 refreshEvernoteNote(true);
4442 listManager.countNotebookResults(listManager.getNoteIndex());
4443 browserWindow.titleLabel.setFocus();
4444 browserWindow.titleLabel.selectAll();
4445 // notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
4447 // If the window is hidden, then we want to popup this in an external window &
4450 logger.log(logger.HIGH, "Leaving NeverNote.addNote");
4452 // Restore a note from the trash;
4453 @SuppressWarnings("unused")
4454 private void restoreNote() {
4456 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
4457 selectedNoteGUIDs.add(currentNoteGuid);
4458 for (int i=0; i<selectedNoteGUIDs.size(); i++) {
4459 listManager.restoreNote(selectedNoteGUIDs.get(i));
4461 currentNoteGuid = "";
4462 listManager.loadNotesIndex();
4463 noteIndexUpdated(false);
4466 // Search a note for specific txt
4467 @SuppressWarnings("unused")
4468 private void findText() {
4470 find.setFocusOnTextField();
4472 @SuppressWarnings("unused")
4473 private void doFindText() {
4474 browserWindow.getBrowser().page().findText(find.getText(), find.getFlags());
4477 @SuppressWarnings("unused")
4478 private void updateNoteTitle(String guid, String title) {
4479 listManager.setNoteSynchronized(guid, false);
4481 // Signal received that note content has changed. Normally we just need the guid to remove
4482 // it from the cache.
4483 @SuppressWarnings("unused")
4484 private void invalidateNoteCache(String guid, String content) {
4485 String v = noteCache.remove(guid);
4486 // if (guid.equals(currentNoteGuid) && !noteDirty)
4487 refreshEvernoteNote(true);
4489 // Signal received that a note guid has changed
4490 @SuppressWarnings("unused")
4491 private void noteGuidChanged(String oldGuid, String newGuid) {
4492 if (noteCache.containsKey(oldGuid)) {
4493 if (!oldGuid.equals(currentNoteGuid)) {
4494 String cache = noteCache.get(oldGuid);
4495 noteCache.put(newGuid, cache);
4496 noteCache.remove(oldGuid);
4498 noteCache.remove(oldGuid);
4499 noteCache.put(newGuid, browserWindow.getContent());
4503 listManager.updateNoteGuid(oldGuid, newGuid, false);
4504 if (currentNoteGuid.equals(oldGuid)) {
4505 if (currentNote != null)
4506 currentNote.setGuid(newGuid);
4507 currentNoteGuid = newGuid;
4510 if (externalWindows.containsKey(oldGuid)) {
4511 ExternalBrowse b = externalWindows.get(oldGuid);
4512 externalWindows.remove(oldGuid);
4513 b.getBrowserWindow().getNote().setGuid(newGuid);
4514 externalWindows.put(newGuid, b);
4517 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
4518 if (listManager.getNoteIndex().get(i).getGuid().equals(newGuid)) {
4519 noteTableView.proxyModel.addGuid(newGuid);
4520 i=listManager.getNoteIndex().size();
4524 if (listManager.getNoteTableModel().titleColors.containsKey(oldGuid)) {
4525 int color = listManager.getNoteTableModel().titleColors.get(oldGuid);
4526 listManager.getNoteTableModel().titleColors.put(newGuid, color);
4527 listManager.getNoteTableModel().titleColors.remove(oldGuid);
4531 // Toggle the note editor button bar
4532 private void toggleEditorButtonBar() {
4533 if (browserWindow.buttonsVisible) {
4534 browserWindow.hideButtons();
4535 menuBar.showEditorBar.setChecked(browserWindow.buttonsVisible);
4536 // Global.saveWindowVisible("editorButtonBar", browserWindow.buttonsVisible);
4538 browserWindow.buttonsVisible = true;
4539 showEditorButtons(browserWindow);
4541 Global.saveWindowVisible("editorButtonBar", browserWindow.buttonsVisible);
4543 // Show editor buttons
4544 private void showEditorButtons(BrowserWindow browser) {
4545 browser.buttonLayout.setVisible(true);
4546 browser.undoAction.setVisible(false);
4548 browser.undoButton.setVisible(false);
4550 browser.undoAction.setVisible(Global.isEditorButtonVisible("undo"));
4551 browser.redoAction.setVisible(Global.isEditorButtonVisible("redo"));
4552 browser.cutAction.setVisible(Global.isEditorButtonVisible("cut"));
4553 browser.copyAction.setVisible(Global.isEditorButtonVisible("copy"));
4554 browser.pasteAction.setVisible(Global.isEditorButtonVisible("paste"));
4555 browser.strikethroughAction.setVisible(Global.isEditorButtonVisible("strikethrough"));
4556 browser.underlineAction.setVisible(Global.isEditorButtonVisible("underline"));
4557 browser.boldAction.setVisible(Global.isEditorButtonVisible("bold"));
4558 browser.italicAction.setVisible(Global.isEditorButtonVisible("italic"));
4559 browser.hlineAction.setVisible(Global.isEditorButtonVisible("hline"));
4560 browser.indentAction.setVisible(Global.isEditorButtonVisible("indent"));
4561 browser.outdentAction.setVisible(Global.isEditorButtonVisible("outdent"));
4562 browser.bulletListAction.setVisible(Global.isEditorButtonVisible("bulletList"));
4563 browser.numberListAction.setVisible(Global.isEditorButtonVisible("numberList"));
4564 browser.fontListAction.setVisible(Global.isEditorButtonVisible("font"));
4565 browser.fontSizeAction.setVisible(Global.isEditorButtonVisible("fontSize"));
4566 browser.fontColorAction.setVisible(Global.isEditorButtonVisible("fontColor"));
4567 browser.fontHilightAction.setVisible(Global.isEditorButtonVisible("fontHilight"));
4568 browser.leftAlignAction.setVisible(Global.isEditorButtonVisible("alignLeft"));
4569 browser.centerAlignAction.setVisible(Global.isEditorButtonVisible("alignCenter"));
4570 browser.rightAlignAction.setVisible(Global.isEditorButtonVisible("alignRight"));
4571 browser.spellCheckAction.setVisible(Global.isEditorButtonVisible("spellCheck"));
4572 browser.todoAction.setVisible(Global.isEditorButtonVisible("todo"));
4574 private void duplicateNote(String guid) {
4576 Note oldNote = conn.getNoteTable().getNote(guid, true, true, false, false, false);
4577 List<Resource> resList = conn.getNoteTable().noteResourceTable.getNoteResources(guid, true);
4578 oldNote.setContent(conn.getNoteTable().getNoteContentBinary(guid));
4579 oldNote.setResources(resList);
4580 duplicateNote(oldNote);
4582 private void duplicateNote(Note oldNote) {
4584 // Now that we have a good notebook guid, we need to move the conflicting note
4585 // to the local notebook
4586 Calendar currentTime = new GregorianCalendar();
4587 Long l = new Long(currentTime.getTimeInMillis());
4588 String newGuid = new String(Long.toString(l));
4590 Note newNote = oldNote.deepCopy();
4591 newNote.setUpdateSequenceNum(0);
4592 newNote.setGuid(newGuid);
4593 newNote.setDeleted(0);
4594 newNote.setActive(true);
4595 List<Resource> resList = oldNote.getResources();
4596 if (resList == null)
4597 resList = new ArrayList<Resource>();
4599 for (int i=0; i<resList.size(); i++) {
4601 while (l == prevGuid) {
4602 currentTime = new GregorianCalendar();
4603 l = new Long(currentTime.getTimeInMillis());
4606 String newResGuid = new String(Long.toString(l));
4607 resList.get(i).setNoteGuid(newGuid);
4608 resList.get(i).setGuid(newResGuid);
4609 resList.get(i).setUpdateSequenceNum(0);
4610 resList.get(i).setActive(true);
4611 conn.getNoteTable().noteResourceTable.saveNoteResource(new Resource(resList.get(i).deepCopy()), true);
4613 newNote.setResources(resList);
4614 listManager.addNote(newNote);
4615 conn.getNoteTable().addNote(newNote, true);
4616 listManager.getUnsynchronizedNotes().add(newNote.getGuid());
4617 noteTableView.insertRow(newNote, true, -1);
4618 listManager.countNotebookResults(listManager.getNoteIndex());
4622 @SuppressWarnings("unused")
4623 private void allNotes() {
4624 clearAttributeFilter();
4625 clearNotebookFilter();
4626 clearSavedSearchFilter();
4629 searchField.clear();
4630 if (Global.mimicEvernoteInterface) {
4631 notebookTree.selectGuid("");
4633 notebookTreeSelection();
4636 @SuppressWarnings("unused")
4637 private void mergeNotes() {
4638 logger.log(logger.HIGH, "Merging notes");
4641 String masterGuid = null;
4642 List<String> sources = new ArrayList<String>();
4644 for (int i=0; i<noteTableView.selectionModel().selectedRows().size(); i++) {
4645 int r = noteTableView.selectionModel().selectedRows().get(i).row();
4646 index = noteTableView.proxyModel.index(r, Global.noteTableGuidPosition);
4647 SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
4649 masterGuid = (String)ix.values().toArray()[0];
4651 sources.add((String)ix.values().toArray()[0]);
4654 logger.log(logger.EXTREME, "Master guid=" +masterGuid);
4655 logger.log(logger.EXTREME, "Children count: "+sources.size());
4656 mergeNoteContents(masterGuid, sources);
4657 currentNoteGuid = masterGuid;
4658 noteIndexUpdated(false);
4659 refreshEvernoteNote(true);
4662 private void mergeNoteContents(String targetGuid, List<String> sources) {
4663 Note target = conn.getNoteTable().getNote(targetGuid, true, false, false, false, false);
4664 String newContent = target.getContent();
4665 newContent = newContent.replace("</en-note>", "<br></br>");
4667 for (int i=0; i<sources.size(); i++) {
4668 Note source = conn.getNoteTable().getNote(sources.get(i), true, true, false, false, false);
4669 if (source.isSetTitle()) {
4670 newContent = newContent +("<table bgcolor=\"lightgrey\"><tr><td><font size=\"6\"><b>" +source.getTitle() +"</b></font></td></tr></table>");
4672 String sourceContent = source.getContent();
4673 logger.log(logger.EXTREME, "Merging contents into note");
4674 logger.log(logger.EXTREME, sourceContent);
4675 logger.log(logger.EXTREME, "End of content");
4676 int startOfNote = sourceContent.indexOf("<en-note>");
4677 sourceContent = sourceContent.substring(startOfNote+9);
4678 int endOfNote = sourceContent.indexOf("</en-note>");
4679 sourceContent = sourceContent.substring(0,endOfNote);
4680 newContent = newContent + sourceContent;
4681 logger.log(logger.EXTREME, "New note content");
4682 logger.log(logger.EXTREME, newContent);
4683 logger.log(logger.EXTREME, "End of content");
4684 for (int j=0; j<source.getResourcesSize(); j++) {
4685 logger.log(logger.EXTREME, "Reassigning resource: "+source.getResources().get(j).getGuid());
4686 Resource r = source.getResources().get(j);
4687 Resource newRes = conn.getNoteTable().noteResourceTable.getNoteResource(r.getGuid(), true);
4689 Calendar currentTime = new GregorianCalendar();
4690 Long l = new Long(currentTime.getTimeInMillis());
4694 while (l == prevGuid) {
4695 currentTime = new GregorianCalendar();
4696 l = new Long(currentTime.getTimeInMillis());
4698 String newResGuid = new String(Long.toString(l));
4699 newRes.setNoteGuid(targetGuid);
4700 newRes.setGuid(newResGuid);
4701 newRes.setUpdateSequenceNum(0);
4702 newRes.setActive(true);
4703 conn.getNoteTable().noteResourceTable.saveNoteResource(newRes, true);
4706 logger.log(logger.EXTREME, "Updating note");
4707 conn.getNoteTable().updateNoteContent(targetGuid, newContent +"</en-note>");
4708 for (int i=0; i<sources.size(); i++) {
4709 logger.log(logger.EXTREME, "Deleting note " +sources.get(i));
4710 listManager.deleteNote(sources.get(i));
4712 logger.log(logger.EXTREME, "Exiting merge note");
4714 // A resource within a note has had a guid change
4715 @SuppressWarnings("unused")
4716 private void noteResourceGuidChanged(String noteGuid, String oldGuid, String newGuid) {
4717 if (!oldGuid.equals(newGuid))
4718 Global.resourceMap.put(oldGuid, newGuid);
4720 // View a thumbnail of the note
4721 public void thumbnailView() {
4723 String thumbnailName = Global.getFileManager().getResDirPath("thumbnail-" + currentNoteGuid + ".png");
4724 QFile thumbnail = new QFile(thumbnailName);
4725 if (!thumbnail.exists()) {
4727 QImage img = new QImage();
4728 img.loadFromData(conn.getNoteTable().getThumbnail(currentNoteGuid));
4729 thumbnailViewer.setThumbnail(img);
4731 thumbnailViewer.setThumbnail(thumbnailName);
4732 if (!thumbnailViewer.isVisible())
4733 thumbnailViewer.showFullScreen();
4735 // An error happened while saving a note. Inform the user
4736 @SuppressWarnings("unused")
4737 private void saveRunnerError(String guid, String msg) {
4739 String title = "*Unknown*";
4740 for (int i=0; i<listManager.getMasterNoteIndex().size(); i++) {
4741 if (listManager.getMasterNoteIndex().get(i).getGuid().equals(guid)) {
4742 title = listManager.getMasterNoteIndex().get(i).getTitle();
4743 i=listManager.getMasterNoteIndex().size();
4746 msg = "An error has happened while saving the note \"" +title+
4747 "\".\n\nThis is probably due to a document that is too complex for Nevernote to process. "+
4748 "As a result, changes to the note may not be saved properly in the database."+
4749 "\n\nA cached copy is being preserved so you can recover any data, but data may" +
4750 "\nbe lost. Please review the note to recover any critical data before restarting.";
4752 QMessageBox.information(this, tr("Error Saving Note"), tr(msg));
4755 private void thumbnailHTMLReady(String guid, QByteArray html, Integer zoom) {
4756 logger.log(logger.HIGH, "Entering thumnailHTMLReady()");
4757 logger.log(logger.HIGH, "Thumbnail ready for " +guid);
4758 // Find an idle preview object
4759 for (int i=0; i<thumbGenerators.size(); i++) {
4760 if (thumbGenerators.get(i).mutex.tryLock()) {
4761 logger.log(logger.EXTREME, "Idle generator found - loading thumbnail for " +guid);
4762 thumbGenerators.get(i).loadContent(guid, html, zoom);
4766 if (thumbGenerators.size() >= 1) {
4767 logger.log(logger.EXTREME, "No available thumbnail generators. Aborting " +guid);
4771 logger.log(logger.EXTREME, "Creating new thumbnail generator " +guid);
4772 Thumbnailer preview = new Thumbnailer(logger, conn, listManager, thumbnailRunner);
4773 thumbGenerators.add(preview);
4775 if (preview.mutex.tryLock()) {
4776 logger.log(logger.EXTREME, "Loading thumbnail for " +guid);
4777 preview.loadContent(guid, html, zoom);
4779 logger.log(logger.HIGH, "Exiting thumnailHTMLReady()");
4784 //**********************************************************
4785 //**********************************************************
4786 //* Online user actions
4787 //**********************************************************
4788 //**********************************************************
4789 private void setupOnlineMenu() {
4790 if (!Global.isConnected) {
4791 menuBar.noteOnlineHistoryAction.setEnabled(false);
4792 menuBar.selectiveSyncAction.setEnabled(false);
4795 menuBar.noteOnlineHistoryAction.setEnabled(true);
4796 menuBar.selectiveSyncAction.setEnabled(true);
4799 @SuppressWarnings("unused")
4800 private void viewNoteHistory() {
4801 if (currentNoteGuid == null || currentNoteGuid.equals(""))
4803 if (currentNote.getUpdateSequenceNum() == 0) {
4804 setMessage(tr("Note has never been synchronized."));
4805 QMessageBox.information(this, tr("Error"), tr("This note has never been sent to Evernote, so there is no history."));
4809 setMessage(tr("Getting Note History"));
4811 Note currentOnlineNote = null;
4814 if (Global.isPremium())
4815 versions = syncRunner.noteStore.listNoteVersions(syncRunner.authToken, currentNoteGuid);
4817 versions = new ArrayList<NoteVersionId>();
4818 currentOnlineNote = syncRunner.noteStore.getNote(syncRunner.authToken, currentNoteGuid, true, true, false, false);
4819 } catch (EDAMUserException e) {
4820 setMessage("EDAMUserException: " +e.getMessage());
4822 } catch (EDAMSystemException e) {
4823 setMessage("EDAMSystemException: " +e.getMessage());
4825 } catch (EDAMNotFoundException e) {
4826 setMessage(tr("Note not found on server."));
4827 QMessageBox.information(this, "Error", "This note could not be found on Evernote's servers.");
4829 } catch (TException e) {
4830 setMessage("EDAMTransactionException: " +e.getMessage());
4834 // If we've gotten this far, we have a good note.
4835 if (historyWindow == null) {
4836 historyWindow = new OnlineNoteHistory(logger, conn);
4837 historyWindow.historyCombo.activated.connect(this, "reloadHistoryWindow(String)");
4838 historyWindow.restoreAsNew.clicked.connect(this, "restoreHistoryNoteAsNew()");
4839 historyWindow.restore.clicked.connect(this, "restoreHistoryNote()");
4841 historyWindow.historyCombo.clear();
4843 boolean isDirty = conn.getNoteTable().isNoteDirty(currentNoteGuid);
4844 if (currentNote.getUpdateSequenceNum() != currentOnlineNote.getUpdateSequenceNum())
4846 historyWindow.setCurrent(isDirty);
4848 loadHistoryWindowContent(currentOnlineNote);
4849 historyWindow.load(versions);
4850 setMessage(tr("History retrieved"));
4852 historyWindow.exec();
4854 private Note reloadHistoryWindow(String selection) {
4856 String fmt = Global.getDateFormat() + " " + Global.getTimeFormat();
4857 String dateTimeFormat = new String(fmt);
4858 SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);
4862 for (int i=0; i<versions.size(); i++) {
4863 StringBuilder versionDate = new StringBuilder(simple.format(versions.get(i).getSaved()));
4864 if (versionDate.toString().equals(selection))
4868 if (index > -1 || selection.indexOf("Current") > -1) {
4869 Note historyNote = null;
4872 usn = versions.get(index).getUpdateSequenceNum();
4873 historyNote = syncRunner.noteStore.getNoteVersion(syncRunner.authToken, currentNoteGuid, usn, true, true, true);
4875 historyNote = syncRunner.noteStore.getNote(syncRunner.authToken, currentNoteGuid, true,true,true,true);
4876 } catch (EDAMUserException e) {
4877 setMessage("EDAMUserException: " +e.getMessage());
4880 } catch (EDAMSystemException e) {
4881 setMessage("EDAMSystemException: " +e.getMessage());
4884 } catch (EDAMNotFoundException e) {
4885 setMessage("EDAMNotFoundException: " +e.getMessage());
4888 } catch (TException e) {
4889 setMessage("EDAMTransactionException: " +e.getMessage());
4895 if (historyNote != null)
4896 historyWindow.setContent(historyNote);
4902 private void loadHistoryWindowContent(Note note) {
4903 note.setUpdateSequenceNum(0);
4904 historyWindow.setContent(note);
4906 @SuppressWarnings("unused")
4907 private void restoreHistoryNoteAsNew() {
4908 setMessage(tr("Restoring as new note."));
4909 duplicateNote(reloadHistoryWindow(historyWindow.historyCombo.currentText()));
4910 setMessage(tr("Note has been restored as a new note."));
4912 @SuppressWarnings("unused")
4913 private void restoreHistoryNote() {
4914 setMessage(tr("Restoring note."));
4915 Note n = reloadHistoryWindow(historyWindow.historyCombo.currentText());
4916 conn.getNoteTable().expungeNote(n.getGuid(), true, false);
4919 for (int i=0; i<n.getResourcesSize(); i++) {
4920 n.getResources().get(i).setActive(true);
4921 conn.getNoteTable().noteResourceTable.saveNoteResource(n.getResources().get(i), true);
4923 listManager.addNote(n);
4924 conn.getNoteTable().addNote(n, true);
4925 refreshEvernoteNote(true);
4926 setMessage(tr("Note has been restored."));
4928 @SuppressWarnings("unused")
4929 private void setupSelectiveSync() {
4931 // Get a list of valid notebooks
4932 List<Notebook> notebooks = null;
4933 List<Tag> tags = null;
4934 List<LinkedNotebook> linkedNotebooks = null;
4936 notebooks = syncRunner.noteStore.listNotebooks(syncRunner.authToken);
4937 tags = syncRunner.noteStore.listTags(syncRunner.authToken);
4938 linkedNotebooks = syncRunner.noteStore.listLinkedNotebooks(syncRunner.authToken);
4939 } catch (EDAMUserException e) {
4940 setMessage("EDAMUserException: " +e.getMessage());
4942 } catch (EDAMSystemException e) {
4943 setMessage("EDAMSystemException: " +e.getMessage());
4945 } catch (TException e) {
4946 setMessage("EDAMTransactionException: " +e.getMessage());
4948 } catch (EDAMNotFoundException e) {
4949 setMessage("EDAMNotFoundException: " +e.getMessage());
4953 // Split up notebooks into synchronized & non-synchronized
4954 List<Notebook> ignoredBooks = new ArrayList<Notebook>();
4955 List<String> dbIgnoredNotebooks = conn.getSyncTable().getIgnoreRecords("NOTEBOOK");
4957 for (int i=notebooks.size()-1; i>=0; i--) {
4958 for (int j=0; j<dbIgnoredNotebooks.size(); j++) {
4959 if (notebooks.get(i).getGuid().equalsIgnoreCase(dbIgnoredNotebooks.get(j))) {
4960 ignoredBooks.add(notebooks.get(i));
4961 j=dbIgnoredNotebooks.size();
4966 // split up tags into synchronized & non-synchronized
4967 List<Tag> ignoredTags = new ArrayList<Tag>();
4968 List<String> dbIgnoredTags = conn.getSyncTable().getIgnoreRecords("TAG");
4970 for (int i=tags.size()-1; i>=0; i--) {
4971 for (int j=0; j<dbIgnoredTags.size(); j++) {
4972 if (tags.get(i).getGuid().equalsIgnoreCase(dbIgnoredTags.get(j))) {
4973 ignoredTags.add(tags.get(i));
4974 j=dbIgnoredTags.size();
4979 // split up linked notebooks into synchronized & non-synchronized
4980 List<LinkedNotebook> ignoredLinkedNotebooks = new ArrayList<LinkedNotebook>();
4981 List<String> dbIgnoredLinkedNotebooks = conn.getSyncTable().getIgnoreRecords("LINKEDNOTEBOOK");
4982 for (int i=linkedNotebooks.size()-1; i>=0; i--) {
4983 String notebookGuid = linkedNotebooks.get(i).getGuid();
4984 for (int j=0; j<dbIgnoredLinkedNotebooks.size(); j++) {
4985 if (notebookGuid.equalsIgnoreCase(dbIgnoredLinkedNotebooks.get(j))) {
4986 ignoredLinkedNotebooks.add(linkedNotebooks.get(i));
4987 j=dbIgnoredLinkedNotebooks.size();
4992 IgnoreSync ignore = new IgnoreSync(notebooks, ignoredBooks, tags, ignoredTags, linkedNotebooks, ignoredLinkedNotebooks);
4994 if (!ignore.okClicked())
4999 // Clear out old notebooks & add the new ones
5000 List<String> oldIgnoreNotebooks = conn.getSyncTable().getIgnoreRecords("NOTEBOOK");
5001 for (int i=0; i<oldIgnoreNotebooks.size(); i++) {
5002 conn.getSyncTable().deleteRecord("IGNORENOTEBOOK-"+oldIgnoreNotebooks.get(i));
5005 List<String> newNotebooks = new ArrayList<String>();
5006 for (int i=ignore.getIgnoredBookList().count()-1; i>=0; i--) {
5007 String text = ignore.getIgnoredBookList().takeItem(i).text();
5008 for (int j=0; j<notebooks.size(); j++) {
5009 if (notebooks.get(j).getName().equalsIgnoreCase(text)) {
5010 Notebook n = notebooks.get(j);
5011 conn.getSyncTable().addRecord("IGNORENOTEBOOK-"+n.getGuid(), n.getGuid());
5013 newNotebooks.add(n.getGuid());
5018 // Clear out old tags & add new ones
5019 List<String> oldIgnoreTags = conn.getSyncTable().getIgnoreRecords("TAG");
5020 for (int i=0; i<oldIgnoreTags.size(); i++) {
5021 conn.getSyncTable().deleteRecord("IGNORETAG-"+oldIgnoreTags.get(i));
5024 List<String> newTags = new ArrayList<String>();
5025 for (int i=ignore.getIgnoredTagList().count()-1; i>=0; i--) {
5026 String text = ignore.getIgnoredTagList().takeItem(i).text();
5027 for (int j=0; j<tags.size(); j++) {
5028 if (tags.get(j).getName().equalsIgnoreCase(text)) {
5029 Tag t = tags.get(j);
5030 conn.getSyncTable().addRecord("IGNORETAG-"+t.getGuid(), t.getGuid());
5031 newTags.add(t.getGuid());
5037 // Clear out old tags & add new ones
5038 List<String> oldIgnoreLinkedNotebooks = conn.getSyncTable().getIgnoreRecords("LINKEDNOTEBOOK");
5039 for (int i=0; i<oldIgnoreLinkedNotebooks.size(); i++) {
5040 conn.getSyncTable().deleteRecord("IGNORELINKEDNOTEBOOK-"+oldIgnoreLinkedNotebooks.get(i));
5043 List<String> newLinked = new ArrayList<String>();
5044 for (int i=ignore.getIgnoredLinkedNotebookList().count()-1; i>=0; i--) {
5045 String text = ignore.getIgnoredLinkedNotebookList().takeItem(i).text();
5046 for (int j=0; j<linkedNotebooks.size(); j++) {
5047 if (linkedNotebooks.get(j).getShareName().equalsIgnoreCase(text)) {
5048 LinkedNotebook t = linkedNotebooks.get(j);
5049 conn.getSyncTable().addRecord("IGNORELINKEDNOTEBOOK-"+t.getGuid(), t.getGuid());
5050 newLinked.add(t.getGuid());
5051 j=linkedNotebooks.size();
5056 conn.getNoteTable().expungeIgnoreSynchronizedNotes(newNotebooks, newTags, newLinked);
5062 //**********************************************************
5063 //**********************************************************
5064 //* XML Modifying methods
5065 //**********************************************************
5066 //**********************************************************
5067 // An error has happended fetching a resource. let the user know
5068 private void resourceErrorMessage() {
5071 QMessageBox.information(this, tr("DOUGH!!!"), tr("Well, this is embarrassing."+
5072 "\n\nSome attachments or images for this note appear to be missing from my database.\n"+
5073 "In a perfect world this wouldn't happen, but it has.\n" +
5074 "It is embarasing when a program like me, designed to save all your\n"+
5075 "precious data, has a problem finding data.\n\n" +
5076 "I guess life isn't fair, but I'll survive. Somehow...\n\n" +
5077 "In the mean time, I'm not going to let you make changes to this note.\n" +
5078 "Don't get angry. I'm doing it to prevent you from messing up\n"+
5079 "this note on the Evernote servers. Sorry."+
5080 "\n\nP.S. You might want to re-synchronize to see if it corrects this problem.\nWho knows, you might get lucky."));
5082 browserWindow.setReadOnly(true);
5088 //**********************************************************
5089 //**********************************************************
5091 //**********************************************************
5092 //**********************************************************
5093 // We should now do a sync with Evernote
5094 private void syncTimer() {
5095 logger.log(logger.EXTREME, "Entering NeverNote.syncTimer()");
5096 syncRunner.syncNeeded = true;
5097 syncRunner.disableUploads = Global.disableUploads;
5099 logger.log(logger.EXTREME, "Leaving NeverNote.syncTimer()");
5101 private void syncStart() {
5102 logger.log(logger.EXTREME, "Entering NeverNote.syncStart()");
5104 if (!syncRunning && Global.isConnected) {
5105 syncRunner.setConnected(true);
5106 syncRunner.setKeepRunning(Global.keepRunning);
5107 syncRunner.syncDeletedContent = Global.synchronizeDeletedContent();
5109 if (syncThreadsReady > 0) {
5110 thumbnailRunner.interrupt = true;
5111 saveNoteIndexWidth();
5112 saveNoteColumnPositions();
5113 if (syncRunner.addWork("SYNC")) {
5115 syncRunner.syncNeeded = true;
5120 logger.log(logger.EXTREME, "Leaving NeverNote.syncStart");
5122 @SuppressWarnings("unused")
5123 private void syncThreadComplete(Boolean refreshNeeded) {
5124 setMessage(tr("Finalizing Synchronization"));
5126 syncRunning = false;
5127 syncRunner.syncNeeded = false;
5128 synchronizeAnimationTimer.stop();
5129 synchronizeButton.setIcon(new QIcon(iconPath+"synchronize.png"));
5131 if (currentNote == null) {
5132 currentNote = conn.getNoteTable().getNote(currentNoteGuid, false, false, false, false, true);
5134 listManager.setUnsynchronizedNotes(conn.getNoteTable().getUnsynchronizedGUIDs());
5135 noteIndexUpdated(false);
5136 noteTableView.selectionModel().blockSignals(true);
5137 scrollToGuid(currentNoteGuid);
5138 noteTableView.selectionModel().blockSignals(false);
5139 refreshEvernoteNote(false);
5140 scrollToGuid(currentNoteGuid);
5142 if (!syncRunner.error)
5143 setMessage(tr("Synchronization Complete"));
5145 setMessage(tr("Synchronization completed with errors. Please check the log for details."));
5146 logger.log(logger.MEDIUM, "Sync complete.");
5148 public void saveUploadAmount(long t) {
5149 Global.saveUploadAmount(t);
5151 public void saveUserInformation(User user) {
5152 Global.saveUserInformation(user);
5154 public void saveEvernoteUpdateCount(int i) {
5155 Global.saveEvernoteUpdateCount(i);
5157 public void refreshLists() {
5158 logger.log(logger.EXTREME, "Entering NeverNote.refreshLists");
5160 listManager.refreshLists(currentNote, noteDirty, browserWindow.getContent());
5161 tagIndexUpdated(true);
5162 notebookIndexUpdated();
5163 savedSearchIndexUpdated();
5164 listManager.loadNotesIndex();
5166 noteTableView.selectionModel().blockSignals(true);
5167 noteIndexUpdated(true);
5168 noteTableView.selectionModel().blockSignals(false);
5169 logger.log(logger.EXTREME, "Leaving NeverNote.refreshLists");
5173 @SuppressWarnings("unused")
5174 private void authTimer() {
5175 Calendar cal = Calendar.getInstance();
5177 // If we are not connected let's get out of here
5178 if (!Global.isConnected)
5181 // If this is the first time through, then we need to set this
5182 // if (syncRunner.authRefreshTime == 0 || cal.getTimeInMillis() > syncRunner.authRefreshTime)
5183 // syncRunner.authRefreshTime = cal.getTimeInMillis();
5185 // long now = new Date().getTime();
5186 // if (now > Global.authRefreshTime && Global.isConnected) {
5187 syncRunner.authRefreshNeeded = true;
5191 @SuppressWarnings("unused")
5192 private void authRefreshComplete(boolean goodSync) {
5193 logger.log(logger.EXTREME, "Entering NeverNote.authRefreshComplete");
5194 Global.isConnected = syncRunner.isConnected;
5196 // authTimer.start((int)syncRunner.authTimeRemaining/4);
5197 authTimer.start(1000*60*15);
5198 logger.log(logger.LOW, "Authentication token has been renewed");
5199 // setMessage("Authentication token has been renewed.");
5201 authTimer.start(1000*60*5);
5202 logger.log(logger.LOW, "Authentication token renew has failed - retry in 5 minutes.");
5203 // setMessage("Authentication token renew has failed - retry in 5 minutes.");
5205 logger.log(logger.EXTREME, "Leaving NeverNote.authRefreshComplete");
5209 @SuppressWarnings("unused")
5210 private synchronized void indexTimer() {
5211 logger.log(logger.EXTREME, "Index timer activated. Sync running="+syncRunning);
5214 if (!indexDisabled && indexRunner.idle) {
5215 thumbnailRunner.interrupt = true;
5216 indexRunner.addWork("SCAN");
5218 logger.log(logger.EXTREME, "Leaving neverNote index timer");
5221 @SuppressWarnings("unused")
5222 private void indexStarted() {
5223 setMessage(tr("Indexing notes"));
5225 @SuppressWarnings("unused")
5226 private void indexComplete() {
5227 setMessage(tr("Index complete"));
5229 @SuppressWarnings("unused")
5230 private synchronized void toggleNoteIndexing() {
5231 logger.log(logger.HIGH, "Entering NeverNote.toggleIndexing");
5232 indexDisabled = !indexDisabled;
5234 setMessage(tr("Indexing is now enabled."));
5236 setMessage(tr("Indexing is now disabled."));
5237 menuBar.disableIndexing.setChecked(indexDisabled);
5238 logger.log(logger.HIGH, "Leaving NeverNote.toggleIndexing");
5241 @SuppressWarnings("unused")
5242 private void threadMonitorCheck() {
5247 alive = listManager.threadCheck(Global.tagCounterThreadId);
5250 if (tagDeadCount > MAX && !disableTagThreadCheck) {
5251 QMessageBox.information(this, tr("A thread his died."), tr("It appears as the tag counter thread has died. I recommend "+
5252 "checking stopping NeverNote, saving the logs for later viewing, and restarting. Sorry."));
5253 disableTagThreadCheck = true;
5258 alive = listManager.threadCheck(Global.notebookCounterThreadId);
5260 notebookThreadDeadCount++;
5261 if (notebookThreadDeadCount > MAX && !disableNotebookThreadCheck) {
5262 QMessageBox.information(this, tr("A thread his died."), tr("It appears as the notebook counter thread has died. I recommend "+
5263 "checking stopping NeverNote, saving the logs for later viewing, and restarting. Sorry."));
5264 disableNotebookThreadCheck=true;
5267 notebookThreadDeadCount=0;
5269 alive = listManager.threadCheck(Global.trashCounterThreadId);
5272 if (trashDeadCount > MAX && !disableTrashThreadCheck) {
5273 QMessageBox.information(this, tr("A thread his died."), ("It appears as the trash counter thread has died. I recommend "+
5274 "checking stopping NeverNote, saving the logs for later viewing, and restarting. Sorry."));
5275 disableTrashThreadCheck = true;
5280 alive = listManager.threadCheck(Global.saveThreadId);
5282 saveThreadDeadCount++;
5283 if (saveThreadDeadCount > MAX && !disableSaveThreadCheck) {
5284 QMessageBox.information(this, tr("A thread his died."), tr("It appears as the note saver thread has died. I recommend "+
5285 "checking stopping NeverNote, saving the logs for later viewing, and restarting. Sorry."));
5286 disableSaveThreadCheck = true;
5289 saveThreadDeadCount=0;
5291 if (!syncThread.isAlive()) {
5292 syncThreadDeadCount++;
5293 if (syncThreadDeadCount > MAX && !disableSyncThreadCheck) {
5294 QMessageBox.information(this, tr("A thread his died."), tr("It appears as the synchronization thread has died. I recommend "+
5295 "checking stopping NeverNote, saving the logs for later viewing, and restarting. Sorry."));
5296 disableSyncThreadCheck = true;
5299 syncThreadDeadCount=0;
5301 if (!indexThread.isAlive()) {
5302 indexThreadDeadCount++;
5303 if (indexThreadDeadCount > MAX && !disableIndexThreadCheck) {
5304 QMessageBox.information(this, tr("A thread his died."), tr("It appears as the index thread has died. I recommend "+
5305 "checking stopping NeverNote, saving the logs for later viewing, and restarting. Sorry."));
5306 disableIndexThreadCheck = true;
5309 indexThreadDeadCount=0;
5314 private void thumbnailTimer() {
5315 if (Global.enableThumbnails() && !syncRunning && indexRunner.idle) {
5316 thumbnailRunner.addWork("SCAN");
5320 //**************************************************
5321 //* Backup & Restore
5322 //**************************************************
5323 @SuppressWarnings("unused")
5324 private void databaseBackup() {
5325 QFileDialog fd = new QFileDialog(this);
5326 fd.setFileMode(FileMode.AnyFile);
5327 fd.setConfirmOverwrite(true);
5328 fd.setWindowTitle(tr("Backup Database"));
5329 fd.setFilter(tr("NeverNote Export (*.nnex);;All Files (*.*)"));
5330 fd.setAcceptMode(AcceptMode.AcceptSave);
5331 if (saveLastPath == null || saveLastPath.equals(""))
5332 fd.setDirectory(System.getProperty("user.home"));
5334 fd.setDirectory(saveLastPath);
5335 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
5341 saveLastPath = fd.selectedFiles().get(0);
5342 saveLastPath = saveLastPath.substring(0,saveLastPath.lastIndexOf("/"));
5343 setMessage(tr("Backing up database"));
5345 // conn.backupDatabase(Global.getUpdateSequenceNumber(), Global.getSequenceDate());
5347 ExportData noteWriter = new ExportData(conn, true);
5348 String fileName = fd.selectedFiles().get(0);
5350 if (!fileName.endsWith(".nnex"))
5351 fileName = fileName +".nnex";
5352 noteWriter.exportData(fileName);
5353 setMessage(tr("Database backup completed."));
5358 @SuppressWarnings("unused")
5359 private void databaseRestore() {
5360 if (QMessageBox.question(this, tr("Confirmation"),
5361 tr("This is used to restore a database from backups.\n" +
5362 "It is HIGHLY recommened that this only be used to populate\n" +
5363 "an empty database. Restoring into a database that\n already has data" +
5364 " can cause problems.\n\nAre you sure you want to continue?"),
5365 QMessageBox.StandardButton.Yes,
5366 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
5371 QFileDialog fd = new QFileDialog(this);
5372 fd.setFileMode(FileMode.ExistingFile);
5373 fd.setConfirmOverwrite(true);
5374 fd.setWindowTitle(tr("Restore Database"));
5375 fd.setFilter(tr("NeverNote Export (*.nnex);;All Files (*.*)"));
5376 fd.setAcceptMode(AcceptMode.AcceptOpen);
5377 if (saveLastPath == null || saveLastPath.equals(""))
5378 fd.setDirectory(System.getProperty("user.home"));
5380 fd.setDirectory(saveLastPath);
5381 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
5387 saveLastPath = fd.selectedFiles().get(0);
5388 saveLastPath = saveLastPath.substring(0,saveLastPath.lastIndexOf("/"));
5390 setMessage(tr("Restoring database"));
5391 ImportData noteReader = new ImportData(conn, true);
5392 noteReader.importData(fd.selectedFiles().get(0));
5394 if (noteReader.lastError != 0) {
5395 setMessage(noteReader.getErrorMessage());
5396 logger.log(logger.LOW, "Restore problem: " +noteReader.lastError);
5401 listManager.loadNoteTitleColors();
5403 refreshEvernoteNote(true);
5404 setMessage(tr("Database has been restored."));
5407 @SuppressWarnings("unused")
5408 private void exportNotes() {
5409 QFileDialog fd = new QFileDialog(this);
5410 fd.setFileMode(FileMode.AnyFile);
5411 fd.setConfirmOverwrite(true);
5412 fd.setWindowTitle(tr("Backup Database"));
5413 fd.setFilter(tr("NeverNote Export (*.nnex);;All Files (*.*)"));
5414 fd.setAcceptMode(AcceptMode.AcceptSave);
5415 fd.setDirectory(System.getProperty("user.home"));
5416 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
5422 setMessage(tr("Exporting Notes"));
5425 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
5426 selectedNoteGUIDs.add(currentNoteGuid);
5428 ExportData noteWriter = new ExportData(conn, false, selectedNoteGUIDs);
5429 String fileName = fd.selectedFiles().get(0);
5431 if (!fileName.endsWith(".nnex"))
5432 fileName = fileName +".nnex";
5433 noteWriter.exportData(fileName);
5434 setMessage(tr("Export completed."));
5440 @SuppressWarnings("unused")
5441 private void importNotes() {
5442 QFileDialog fd = new QFileDialog(this);
5443 fd.setFileMode(FileMode.ExistingFile);
5444 fd.setConfirmOverwrite(true);
5445 fd.setWindowTitle(tr("Import Notes"));
5446 fd.setFilter(tr("NeverNote Export (*.nnex);;All Files (*.*)"));
5447 fd.setAcceptMode(AcceptMode.AcceptOpen);
5448 if (saveLastPath == null || saveLastPath.equals(""))
5449 fd.setDirectory(System.getProperty("user.home"));
5451 fd.setDirectory(saveLastPath);
5452 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
5458 setMessage("Importing Notes");
5461 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
5462 selectedNoteGUIDs.add(currentNoteGuid);
5464 ImportData noteReader = new ImportData(conn, false);
5465 String fileName = fd.selectedFiles().get(0);
5466 // saveLastPath.substring(0,fileName.lastIndexOf("/"));
5468 if (!fileName.endsWith(".nnex"))
5469 fileName = fileName +".nnex";
5470 if (selectedNotebookGUIDs != null && selectedNotebookGUIDs.size() > 0)
5471 noteReader.setNotebookGuid(selectedNotebookGUIDs.get(0));
5473 noteReader.setNotebookGuid(listManager.getNotebookIndex().get(0).getGuid());
5475 noteReader.importData(fileName);
5477 if (noteReader.lastError != 0) {
5478 setMessage(noteReader.getErrorMessage());
5479 logger.log(logger.LOW, "Import problem: " +noteReader.lastError);
5484 listManager.loadNoteTitleColors();
5486 refreshEvernoteNote(false);
5487 setMessage(tr("Notes have been imported."));
5490 setMessage("Import completed.");
5497 //**************************************************
5498 //* Duplicate a note
5499 //**************************************************
5500 @SuppressWarnings("unused")
5501 private void duplicateNote() {
5503 duplicateNote(currentNoteGuid);
5508 //**************************************************
5510 //**************************************************
5511 public void setupFolderImports() {
5512 List<WatchFolderRecord> records = conn.getWatchFolderTable().getAll();
5514 if (importKeepWatcher == null)
5515 importKeepWatcher = new QFileSystemWatcher();
5516 if (importDeleteWatcher == null) {
5517 importDeleteWatcher = new QFileSystemWatcher();
5518 for (int i=0; i<records.size(); i++) {
5519 if (!records.get(i).keep)
5520 folderImportDelete(records.get(i).folder);
5526 // importKeepWatcher.addPath(records.get(i).folder.replace('\\', '/'));
5527 for (int i=0; i<records.size(); i++) {
5528 if (records.get(i).keep)
5529 importKeepWatcher.addPath(records.get(i).folder);
5531 importDeleteWatcher.addPath(records.get(i).folder);
5534 importKeepWatcher.directoryChanged.connect(this, "folderImportKeep(String)");
5535 importDeleteWatcher.directoryChanged.connect(this, "folderImportDelete(String)");
5537 // Look at the files already there so we don't import them again if a new file is created
5538 if (importedFiles == null) {
5539 importedFiles = new ArrayList<String>();
5540 for (int j=0; j<records.size(); j++) {
5541 QDir dir = new QDir(records.get(j).folder);
5542 List<QFileInfo> list = dir.entryInfoList();
5543 for (int k=0; k<list.size(); k++) {
5544 if (list.get(k).isFile())
5545 importedFiles.add(list.get(k).absoluteFilePath());
5550 public void folderImport() {
5551 List<WatchFolderRecord> recs = conn.getWatchFolderTable().getAll();
5552 WatchFolder dialog = new WatchFolder(recs, listManager.getNotebookIndex());
5554 if (!dialog.okClicked())
5557 // We have some sort of update.
5558 if (importKeepWatcher.directories().size() > 0)
5559 importKeepWatcher.removePaths(importKeepWatcher.directories());
5560 if (importDeleteWatcher.directories().size() > 0)
5561 importDeleteWatcher.removePaths(importDeleteWatcher.directories());
5563 conn.getWatchFolderTable().expungeAll();
5564 // Start building from the table
5565 for (int i=0; i<dialog.table.rowCount(); i++) {
5566 QTableWidgetItem item = dialog.table.item(i, 0);
5567 String dir = item.text();
5568 item = dialog.table.item(i, 1);
5569 String notebook = item.text();
5570 item = dialog.table.item(i, 2);
5572 if (item.text().equalsIgnoreCase("Keep"))
5577 String guid = conn.getNotebookTable().findNotebookByName(notebook);
5578 conn.getWatchFolderTable().addWatchFolder(dir, guid, keep, 0);
5580 setupFolderImports();
5583 public void folderImportKeep(String dirName) throws NoSuchAlgorithmException {
5585 String whichOS = System.getProperty("os.name");
5586 if (whichOS.contains("Windows"))
5587 dirName = dirName.replace('/','\\');
5589 FileImporter importer = new FileImporter(logger, conn);
5591 QDir dir = new QDir(dirName);
5592 List<QFileInfo> list = dir.entryInfoList();
5593 String notebook = conn.getWatchFolderTable().getNotebook(dirName);
5595 for (int i=0; i<list.size(); i++){
5597 boolean redundant = false;
5598 // Check if we've already imported this one or if it existed before
5599 for (int j=0; j<importedFiles.size(); j++) {
5600 if (importedFiles.get(j).equals(list.get(i).absoluteFilePath()))
5605 importer.setFileInfo(list.get(i));
5606 importer.setFileName(list.get(i).absoluteFilePath());
5609 if (list.get(i).isFile() && importer.isValidType()) {
5611 if (!importer.importFile()) {
5612 // If we can't get to the file, it is probably locked. We'll try again later.
5613 logger.log(logger.LOW, "Unable to save externally edited file. Saving for later.");
5614 importFilesKeep.add(list.get(i).absoluteFilePath());
5618 Note newNote = importer.getNote();
5619 newNote.setNotebookGuid(notebook);
5620 newNote.setTitle(dir.at(i));
5621 listManager.addNote(newNote);
5622 conn.getNoteTable().addNote(newNote, true);
5623 listManager.getUnsynchronizedNotes().add(newNote.getGuid());
5624 noteTableView.insertRow(newNote, true, -1);
5625 listManager.updateNoteContent(newNote.getGuid(), importer.getNoteContent());
5626 listManager.countNotebookResults(listManager.getNoteIndex());
5627 importedFiles.add(list.get(i).absoluteFilePath());
5635 public void folderImportDelete(String dirName) {
5637 String whichOS = System.getProperty("os.name");
5638 if (whichOS.contains("Windows"))
5639 dirName = dirName.replace('/','\\');
5641 FileImporter importer = new FileImporter(logger, conn);
5642 QDir dir = new QDir(dirName);
5643 List<QFileInfo> list = dir.entryInfoList();
5644 String notebook = conn.getWatchFolderTable().getNotebook(dirName);
5646 for (int i=0; i<list.size(); i++){
5647 importer.setFileInfo(list.get(i));
5648 importer.setFileName(list.get(i).absoluteFilePath());
5650 if (list.get(i).isFile() && importer.isValidType()) {
5652 if (!importer.importFile()) {
5653 // If we can't get to the file, it is probably locked. We'll try again later.
5654 logger.log(logger.LOW, "Unable to save externally edited file. Saving for later.");
5655 importFilesKeep.add(list.get(i).absoluteFilePath());
5659 Note newNote = importer.getNote();
5660 newNote.setNotebookGuid(notebook);
5661 newNote.setTitle(dir.at(i));
5662 listManager.addNote(newNote);
5663 conn.getNoteTable().addNote(newNote, true);
5664 listManager.getUnsynchronizedNotes().add(newNote.getGuid());
5665 noteTableView.insertRow(newNote, true, -1);
5666 listManager.updateNoteContent(newNote.getGuid(), importer.getNoteContent());
5667 listManager.countNotebookResults(listManager.getNoteIndex());
5668 dir.remove(dir.at(i));
5674 //**************************************************
5676 //**************************************************
5677 private void externalFileEdited(String fileName) throws NoSuchAlgorithmException {
5678 logger.log(logger.HIGH, "Entering exernalFileEdited");
5680 // Strip URL prefix and base dir path
5681 String dPath = FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath());
5682 String name = fileName.replace(dPath, "");
5683 int pos = name.lastIndexOf('.');
5686 guid = guid.substring(0,pos);
5688 pos = name.lastIndexOf(Global.attachmentNameDelimeter);
5690 guid = name.substring(0, pos);
5693 QFile file = new QFile(fileName);
5694 if (!file.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly))) {
5695 // If we can't get to the file, it is probably locked. We'll try again later.
5696 logger.log(logger.LOW, "Unable to save externally edited file. Saving for later.");
5697 externalFiles.add(fileName);
5700 QByteArray binData = file.readAll();
5702 if (binData.size() == 0) {
5703 // If we can't get to the file, it is probably locked. We'll try again later.
5704 logger.log(logger.LOW, "Unable to save externally edited file. Saving for later.");
5705 externalFiles.add(fileName);
5709 Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
5711 r = conn.getNoteTable().noteResourceTable.getNoteResource(Global.resourceMap.get(guid), true);
5712 if (r == null || r.getData() == null || r.getData().getBody() == null)
5714 String oldHash = Global.byteArrayToHexString(r.getData().getBodyHash());
5715 MessageDigest md = MessageDigest.getInstance("MD5");
5716 md.update(binData.toByteArray());
5717 byte[] hash = md.digest();
5718 String newHash = Global.byteArrayToHexString(hash);
5719 if (r.getNoteGuid().equalsIgnoreCase(currentNoteGuid)) {
5720 updateResourceContentHash(browserWindow, r.getGuid(), oldHash, newHash);
5722 if (externalWindows.containsKey(r.getNoteGuid())) {
5723 updateResourceContentHash(externalWindows.get(r.getNoteGuid()).getBrowserWindow(),
5724 r.getGuid(), oldHash, newHash);
5726 conn.getNoteTable().updateResourceContentHash(r.getNoteGuid(), oldHash, newHash);
5727 Data data = r.getData();
5728 data.setBody(binData.toByteArray());
5729 data.setBodyHash(hash);
5730 logger.log(logger.LOW, "externalFileEdited: " +data.getSize() +" bytes");
5732 conn.getNoteTable().noteResourceTable.updateNoteResource(r,true);
5734 if (r.getNoteGuid().equals(currentNoteGuid)) {
5735 QWebSettings.setMaximumPagesInCache(0);
5736 QWebSettings.setObjectCacheCapacities(0, 0, 0);
5737 refreshEvernoteNote(true);
5738 browserWindow.getBrowser().triggerPageAction(WebAction.Reload);
5741 if (externalWindows.containsKey(r.getNoteGuid())) {
5742 QWebSettings.setMaximumPagesInCache(0);
5743 QWebSettings.setObjectCacheCapacities(0, 0, 0);
5744 externalWindows.get(r.getNoteGuid()).getBrowserWindow().getBrowser().triggerPageAction(WebAction.Reload);
5748 logger.log(logger.HIGH, "Exiting externalFielEdited");
5750 // This is a timer event that tries to save any external files that were edited. This
5751 // is only needed if we couldn't save a file earlier.
5752 public void externalFileEditedSaver() {
5753 for (int i=externalFiles.size()-1; i>=0; i--) {
5755 logger.log(logger.MEDIUM, "Trying to save " +externalFiles.get(i));
5756 externalFileEdited(externalFiles.get(i));
5757 externalFiles.remove(i);
5758 } catch (NoSuchAlgorithmException e) {e.printStackTrace();}
5760 for (int i=0; i<importFilesKeep.size(); i++) {
5762 logger.log(logger.MEDIUM, "Trying to save " +importFilesKeep.get(i));
5763 folderImportKeep(importFilesKeep.get(i));
5764 importFilesKeep.remove(i);
5765 } catch (NoSuchAlgorithmException e) {e.printStackTrace();}
5767 for (int i=0; i<importFilesDelete.size(); i++) {
5768 logger.log(logger.MEDIUM, "Trying to save " +importFilesDelete.get(i));
5769 folderImportDelete(importFilesDelete.get(i));
5770 importFilesDelete.remove(i);
5777 // If an attachment on the current note was edited, we need to update the current notes's hash
5778 // Update a note content's hash. This happens if a resource is edited outside of NN
5779 public void updateResourceContentHash(BrowserWindow browser, String guid, String oldHash, String newHash) {
5780 int position = browserWindow.getContent().indexOf("en-tag=\"en-media\" guid=\""+guid+"\" type=");
5782 for (;position>-1;) {
5783 endPos = browser.getContent().indexOf(">", position+1);
5784 String oldSegment = browser.getContent().substring(position,endPos);
5785 int hashPos = oldSegment.indexOf("hash=\"");
5786 int hashEnd = oldSegment.indexOf("\"", hashPos+7);
5787 String hash = oldSegment.substring(hashPos+6, hashEnd);
5788 if (hash.equalsIgnoreCase(oldHash)) {
5789 String newSegment = oldSegment.replace(oldHash, newHash);
5790 String content = browser.getContent().substring(0,position) +
5792 browser.getContent().substring(endPos);
5793 browser.getBrowser().setContent(new QByteArray(content));;
5796 position = browser.getContent().indexOf("en-tag=\"en-media\" guid=\""+guid+"\" type=", position+1);
5801 //*************************************************
5802 //* Minimize to tray
5803 //*************************************************
5805 public void changeEvent(QEvent e) {
5806 if (e.type() == QEvent.Type.WindowStateChange) {
5807 if (isMinimized() && Global.showTrayIcon()) {
5809 QTimer.singleShot(10, this, "hide()");
5813 windowMaximized = true;
5815 windowMaximized = false;
5819 //*************************************************
5820 //* Check database userid & passwords
5821 //*************************************************
5822 private static boolean databaseCheck(String url,String userid, String userPassword, String cypherPassword) {
5823 Connection connection;
5826 Class.forName("org.h2.Driver");
5827 } catch (ClassNotFoundException e1) {
5828 e1.printStackTrace();
5833 String passwordString = null;
5834 if (cypherPassword==null || cypherPassword.trim().equals(""))
5835 passwordString = userPassword;
5837 passwordString = cypherPassword+" "+userPassword;
5838 connection = DriverManager.getConnection(url,userid,passwordString);
5839 } catch (SQLException e) {
5844 } catch (SQLException e) {
5845 e.printStackTrace();