2 * This file is part of NixNote
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.io.FileOutputStream;
25 import java.net.Authenticator;
26 import java.net.PasswordAuthentication;
27 import java.security.MessageDigest;
28 import java.security.NoSuchAlgorithmException;
29 import java.sql.Connection;
30 import java.sql.DriverManager;
31 import java.sql.SQLException;
32 import java.sql.Statement;
33 import java.text.SimpleDateFormat;
34 import java.util.ArrayList;
35 import java.util.Calendar;
36 import java.util.Collection;
37 import java.util.Collections;
38 import java.util.Comparator;
39 import java.util.Date;
40 import java.util.GregorianCalendar;
41 import java.util.HashMap;
42 import java.util.Iterator;
43 import java.util.List;
44 import java.util.SortedMap;
45 import java.util.Vector;
47 import org.apache.log4j.Level;
48 import org.apache.log4j.Logger;
49 import org.apache.thrift.TException;
50 import org.h2.tools.ChangeFileEncryption;
52 import com.evernote.edam.error.EDAMNotFoundException;
53 import com.evernote.edam.error.EDAMSystemException;
54 import com.evernote.edam.error.EDAMUserException;
55 import com.evernote.edam.notestore.NoteFilter;
56 import com.evernote.edam.notestore.NoteVersionId;
57 import com.evernote.edam.type.Data;
58 import com.evernote.edam.type.LinkedNotebook;
59 import com.evernote.edam.type.Note;
60 import com.evernote.edam.type.NoteAttributes;
61 import com.evernote.edam.type.Notebook;
62 import com.evernote.edam.type.Publishing;
63 import com.evernote.edam.type.QueryFormat;
64 import com.evernote.edam.type.Resource;
65 import com.evernote.edam.type.SavedSearch;
66 import com.evernote.edam.type.Tag;
67 import com.evernote.edam.type.User;
68 import com.trolltech.qt.QThread;
69 import com.trolltech.qt.core.QByteArray;
70 import com.trolltech.qt.core.QDateTime;
71 import com.trolltech.qt.core.QDir;
72 import com.trolltech.qt.core.QEvent;
73 import com.trolltech.qt.core.QFile;
74 import com.trolltech.qt.core.QFileInfo;
75 import com.trolltech.qt.core.QFileSystemWatcher;
76 import com.trolltech.qt.core.QIODevice;
77 import com.trolltech.qt.core.QIODevice.OpenModeFlag;
78 import com.trolltech.qt.core.QLocale;
79 import com.trolltech.qt.core.QMimeData;
80 import com.trolltech.qt.core.QModelIndex;
81 import com.trolltech.qt.core.QSize;
82 import com.trolltech.qt.core.QTemporaryFile;
83 import com.trolltech.qt.core.QTextCodec;
84 import com.trolltech.qt.core.QThreadPool;
85 import com.trolltech.qt.core.QTimer;
86 import com.trolltech.qt.core.QTranslator;
87 import com.trolltech.qt.core.QUrl;
88 import com.trolltech.qt.core.Qt;
89 import com.trolltech.qt.core.Qt.BGMode;
90 import com.trolltech.qt.core.Qt.ItemDataRole;
91 import com.trolltech.qt.core.Qt.KeyboardModifier;
92 import com.trolltech.qt.core.Qt.MouseButton;
93 import com.trolltech.qt.core.Qt.SortOrder;
94 import com.trolltech.qt.core.Qt.WidgetAttribute;
95 import com.trolltech.qt.gui.QAbstractItemView;
96 import com.trolltech.qt.gui.QAbstractItemView.ScrollHint;
97 import com.trolltech.qt.gui.QAction;
98 import com.trolltech.qt.gui.QApplication;
99 import com.trolltech.qt.gui.QClipboard;
100 import com.trolltech.qt.gui.QCloseEvent;
101 import com.trolltech.qt.gui.QColor;
102 import com.trolltech.qt.gui.QComboBox;
103 import com.trolltech.qt.gui.QCursor;
104 import com.trolltech.qt.gui.QDesktopServices;
105 import com.trolltech.qt.gui.QDialog;
106 import com.trolltech.qt.gui.QFileDialog;
107 import com.trolltech.qt.gui.QFileDialog.AcceptMode;
108 import com.trolltech.qt.gui.QFileDialog.FileMode;
109 import com.trolltech.qt.gui.QGridLayout;
110 import com.trolltech.qt.gui.QHBoxLayout;
111 import com.trolltech.qt.gui.QIcon;
112 import com.trolltech.qt.gui.QImage;
113 import com.trolltech.qt.gui.QKeySequence;
114 import com.trolltech.qt.gui.QLabel;
115 import com.trolltech.qt.gui.QMainWindow;
116 import com.trolltech.qt.gui.QMenu;
117 import com.trolltech.qt.gui.QMessageBox;
118 import com.trolltech.qt.gui.QMessageBox.StandardButton;
119 import com.trolltech.qt.gui.QPainter;
120 import com.trolltech.qt.gui.QPalette.ColorRole;
121 import com.trolltech.qt.gui.QPixmap;
122 import com.trolltech.qt.gui.QPrintDialog;
123 import com.trolltech.qt.gui.QPrinter;
124 import com.trolltech.qt.gui.QShortcut;
125 import com.trolltech.qt.gui.QSizePolicy;
126 import com.trolltech.qt.gui.QSizePolicy.Policy;
127 import com.trolltech.qt.gui.QSpinBox;
128 import com.trolltech.qt.gui.QSplashScreen;
129 import com.trolltech.qt.gui.QSplitter;
130 import com.trolltech.qt.gui.QStatusBar;
131 import com.trolltech.qt.gui.QSystemTrayIcon;
132 import com.trolltech.qt.gui.QTableWidgetItem;
133 import com.trolltech.qt.gui.QTextEdit;
134 import com.trolltech.qt.gui.QToolBar;
135 import com.trolltech.qt.gui.QTreeWidgetItem;
136 import com.trolltech.qt.network.QNetworkAccessManager;
137 import com.trolltech.qt.network.QNetworkReply;
138 import com.trolltech.qt.network.QNetworkRequest;
139 import com.trolltech.qt.webkit.QWebPage.WebAction;
140 import com.trolltech.qt.webkit.QWebSettings;
142 import cx.fbn.nevernote.config.InitializationException;
143 import cx.fbn.nevernote.config.StartupConfig;
144 import cx.fbn.nevernote.dialog.AccountDialog;
145 import cx.fbn.nevernote.dialog.ConfigDialog;
146 import cx.fbn.nevernote.dialog.DBEncryptDialog;
147 import cx.fbn.nevernote.dialog.DatabaseLoginDialog;
148 import cx.fbn.nevernote.dialog.DatabaseStatus;
149 import cx.fbn.nevernote.dialog.FindDialog;
150 import cx.fbn.nevernote.dialog.IgnoreSync;
151 import cx.fbn.nevernote.dialog.LogFileDialog;
152 import cx.fbn.nevernote.dialog.NotebookArchive;
153 import cx.fbn.nevernote.dialog.NotebookEdit;
154 import cx.fbn.nevernote.dialog.OnlineNoteHistory;
155 import cx.fbn.nevernote.dialog.PublishNotebook;
156 import cx.fbn.nevernote.dialog.SavedSearchEdit;
157 import cx.fbn.nevernote.dialog.SetIcon;
158 import cx.fbn.nevernote.dialog.ShareNotebook;
159 import cx.fbn.nevernote.dialog.SharedNotebookSyncError;
160 import cx.fbn.nevernote.dialog.StackNotebook;
161 import cx.fbn.nevernote.dialog.SynchronizationRequiredWarning;
162 import cx.fbn.nevernote.dialog.TagEdit;
163 import cx.fbn.nevernote.dialog.TagMerge;
164 import cx.fbn.nevernote.dialog.ThumbnailViewer;
165 import cx.fbn.nevernote.dialog.UpgradeAvailableDialog;
166 import cx.fbn.nevernote.dialog.WatchFolder;
167 import cx.fbn.nevernote.evernote.NoteMetadata;
168 import cx.fbn.nevernote.filters.FilterEditorNotebooks;
169 import cx.fbn.nevernote.filters.FilterEditorTags;
170 import cx.fbn.nevernote.gui.AttributeTreeWidget;
171 import cx.fbn.nevernote.gui.BrowserWindow;
172 import cx.fbn.nevernote.gui.DateAttributeFilterTable;
173 import cx.fbn.nevernote.gui.ExternalBrowse;
174 import cx.fbn.nevernote.gui.MainMenuBar;
175 import cx.fbn.nevernote.gui.NotebookTreeWidget;
176 import cx.fbn.nevernote.gui.SavedSearchTreeWidget;
177 import cx.fbn.nevernote.gui.SearchPanel;
178 import cx.fbn.nevernote.gui.TableView;
179 import cx.fbn.nevernote.gui.TagTreeWidget;
180 import cx.fbn.nevernote.gui.Thumbnailer;
181 import cx.fbn.nevernote.gui.TrashTreeWidget;
182 import cx.fbn.nevernote.gui.controls.QuotaProgressBar;
183 import cx.fbn.nevernote.oauth.OAuthTokenizer;
184 import cx.fbn.nevernote.oauth.OAuthWindow;
185 import cx.fbn.nevernote.sql.DatabaseConnection;
186 import cx.fbn.nevernote.sql.WatchFolderRecord;
187 import cx.fbn.nevernote.threads.IndexRunner;
188 import cx.fbn.nevernote.threads.SyncRunner;
189 import cx.fbn.nevernote.threads.ThumbnailRunner;
190 import cx.fbn.nevernote.utilities.AESEncrypter;
191 import cx.fbn.nevernote.utilities.ApplicationLogger;
192 import cx.fbn.nevernote.utilities.FileImporter;
193 import cx.fbn.nevernote.utilities.FileUtils;
194 import cx.fbn.nevernote.utilities.ListManager;
195 import cx.fbn.nevernote.utilities.SyncTimes;
196 import cx.fbn.nevernote.xml.ExportData;
197 import cx.fbn.nevernote.xml.ImportData;
198 import cx.fbn.nevernote.xml.ImportEnex;
199 import cx.fbn.nevernote.xml.NoteFormatter;
202 public class NeverNote extends QMainWindow{
204 QStatusBar statusBar; // Application status bar
206 DatabaseConnection conn;
208 MainMenuBar menuBar; // Main menu bar
209 FindDialog find; // Text search in note dialog
210 List<String> emitLog; // Messages displayed in the status bar;
211 QSystemTrayIcon trayIcon; // little tray icon
212 QMenu trayMenu; // System tray menu
213 QAction trayExitAction; // Exit the application
214 QAction trayShowAction; // toggle the show/hide action
215 QAction trayAddNoteAction; // Add a note from the system tray
216 QNetworkAccessManager versionChecker; // Used when checking for new versions
218 NotebookTreeWidget notebookTree; // List of notebooks
219 AttributeTreeWidget attributeTree; // List of note attributes
220 TagTreeWidget tagTree; // list of user created tags
221 SavedSearchTreeWidget savedSearchTree; // list of saved searches
222 TrashTreeWidget trashTree; // Trashcan
223 TableView noteTableView; // List of notes (the widget).
225 public BrowserWindow browserWindow; // Window containing browser & labels
226 public QToolBar toolBar; // The tool bar under the menu
227 QComboBox searchField; // search filter bar on the toolbar;
228 QShortcut searchShortcut; // Shortcut to search bar
229 boolean searchPerformed = false; // Search was done?
230 QuotaProgressBar quotaBar; // The current quota usage
232 ApplicationLogger logger;
233 List<String> selectedNotebookGUIDs; // List of notebook GUIDs
234 List<String> selectedTagGUIDs; // List of selected tag GUIDs
235 List<String> selectedNoteGUIDs; // List of selected notes
236 String selectedSavedSearchGUID; // Currently selected saved searches
237 private final HashMap<String, ExternalBrowse> externalWindows; // Notes being edited by an external window;
239 NoteFilter filter; // Note filter
240 String currentNoteGuid; // GUID of the current note
241 Note currentNote; // The currently viewed note
242 boolean noteDirty; // Has the note been changed?
243 boolean inkNote; // if this is an ink note, it is read only
244 boolean readOnly; // Is this note read-only?
247 ListManager listManager; // DB runnable task
249 List<QTemporaryFile> tempFiles; // Array of temporary files;
251 QTimer indexTimer; // timer to start the index thread
252 IndexRunner indexRunner; // thread to index notes
255 QTimer syncTimer; // Sync on an interval
256 QTimer syncDelayTimer; // Sync delay to free up database
257 SyncRunner syncRunner; // thread to do a sync.
258 QThread syncThread; // Thread which talks to evernote
259 ThumbnailRunner thumbnailRunner; // Runner for thumbnail thread
260 QThread thumbnailThread; // Thread that generates pretty pictures
261 QTimer saveTimer; // Timer to save note contents
263 QTimer authTimer; // Refresh authentication
264 QTimer externalFileSaveTimer; // Save files altered externally
265 QTimer thumbnailTimer; // Wakeup & scan for thumbnails
266 List<String> externalFiles; // External files to save later
267 List<String> importFilesKeep; // Auto-import files to save later
268 List<String> importFilesDelete; // Auto-import files to save later
270 int indexTime; // how often to try and index
271 boolean indexRunning; // Is indexing running?
272 boolean indexDisabled; // Is indexing disabled?
274 int syncThreadsReady; // number of sync threads that are free
275 int syncTime; // Sync interval
276 boolean syncRunning; // Is sync running?
277 boolean automaticSync; // do sync automatically?
278 QTreeWidgetItem attributeTreeSelected;
280 QAction prevButton; // Go to the previous item viewed
281 QAction nextButton; // Go to the next item in the history
282 QAction downButton; // Go to the next item in the list
283 QAction upButton; // Go to the prev. item in the list;
284 QAction synchronizeButton; // Synchronize with Evernote
285 QAction allNotesButton; // Reset & view all notes
286 QTimer synchronizeAnimationTimer; // Timer to change animation button
287 int synchronizeIconAngle; // Used to rotate sync icon
288 QAction printButton; // Print Button
289 QAction tagButton; // Tag edit button
290 QAction attributeButton; // Attribute information button
291 QAction emailButton; // Email button
292 QAction deleteButton; // Delete button
293 QAction newButton; // new Note Button;
294 QSpinBox zoomSpinner; // Zoom zoom
295 QAction searchClearButton; // Clear the search field
297 SearchPanel searchLayout; // Widget to hold search field, zoom, & quota
299 QSplitter mainLeftRightSplitter; // main splitter for left/right side
300 QSplitter leftSplitter1; // first left hand splitter
301 QSplitter browserIndexSplitter; // splitter between note index & note text
303 QFileSystemWatcher importKeepWatcher; // Watch & keep auto-import
304 QFileSystemWatcher importDeleteWatcher; // Watch & Delete auto-import
305 List<String> importedFiles; // History of imported files (so we don't import twice)
307 OnlineNoteHistory historyWindow; // online history window
308 List<NoteVersionId> versions; // history versions
310 QTimer threadMonitorTimer; // Timer to watch threads.
311 int dbThreadDeadCount=0; // number of consecutive dead times for the db thread
312 int syncThreadDeadCount=0; // number of consecutive dead times for the sync thread
313 int indexThreadDeadCount=0; // number of consecutive dead times for the index thread
314 int notebookThreadDeadCount=0; // number of consecutive dead times for the notebook thread
315 int tagDeadCount=0; // number of consecutive dead times for the tag thread
316 int trashDeadCount=0; // number of consecutive dead times for the trash thread
317 int saveThreadDeadCount=0; // number of consecutive dead times for the save thread
318 boolean disableTagThreadCheck=false;
319 boolean disableNotebookThreadCheck=false;
320 boolean disableTrashThreadCheck=false;
321 boolean disableSaveThreadCheck=false;
322 boolean disableSyncThreadCheck=false;
323 boolean disableIndexThreadCheck=false;
325 HashMap<String, String> noteCache; // Cash of note content
326 HashMap<String, Boolean> readOnlyCache; // List of cashe notes that are read-only
327 HashMap<String, Boolean> inkNoteCache; // List of cache notes that are ink notes
328 List<String> historyGuids; // GUIDs of previously viewed items
329 int historyPosition; // Position within the viewed items
330 boolean fromHistory; // Is this from the history queue?
331 String trashNoteGuid; // Guid to restore / set into or out of trash to save position
332 List<Thumbnailer> thumbGenerators; // generate preview image
333 ThumbnailViewer thumbnailViewer; // View preview thumbnail;
334 boolean encryptOnShutdown; // should I encrypt when I close?
335 boolean decryptOnShutdown; // should I decrypt on shutdown;
336 String encryptCipher; // What cipher should I use?
337 //Signal0 minimizeToTray;
338 boolean windowMaximized = false; // Keep track of the window state for restores
339 List<String> pdfReadyQueue; // Queue of PDFs that are ready to be rendered.
340 List<QPixmap> syncIcons; // Array of icons used in sync animation
341 private boolean closeAction = false; // Used to say when to close or when to minimize
342 private static Logger log = Logger.getLogger(NeverNote.class);
343 private String saveLastPath; // last path we used
344 private final QTimer messageTimer; // Timer to clear the status message.
345 private QTimer blockTimer;
346 BrowserWindow blockingWindow;
348 String iconPath = new String("classpath:cx/fbn/nevernote/icons/");
351 //***************************************************************
352 //***************************************************************
353 //** Constructor & main entry point
354 //***************************************************************
355 //***************************************************************
356 // Application Constructor
357 @SuppressWarnings("static-access")
358 public NeverNote(DatabaseConnection dbConn) {
360 if (conn.getConnection() == null) {
361 String msg = new String(tr("Unable to connect to the database.\n\nThe most probable reason is that some other process\n" +
362 "is accessing the database or NixNote is already running.\n\n" +
363 "Please end any other process or shutdown the other NixNote before starting.\n\nExiting program."));
365 QMessageBox.critical(null, tr("Database Connection Error") ,msg);
368 setObjectName("mainWindow");
369 // thread().setPriority(Thread.MAX_PRIORITY);
371 logger = new ApplicationLogger("nevernote.log");
372 logger.log(logger.HIGH, "Starting Application");
374 decryptOnShutdown = false;
375 encryptOnShutdown = false;
376 conn.checkDatabaseVersion();
380 // Start building the invalid XML tables
381 Global.invalidElements = conn.getInvalidXMLTable().getInvalidElements();
382 List<String> elements = conn.getInvalidXMLTable().getInvalidAttributeElements();
384 for (int i=0; i<elements.size(); i++) {
385 Global.invalidAttributes.put(elements.get(i), conn.getInvalidXMLTable().getInvalidAttributes(elements.get(i)));
388 logger.log(logger.EXTREME, "Starting GUI build");
390 QTranslator nevernoteTranslator = new QTranslator();
391 nevernoteTranslator.load(Global.getFileManager().getTranslateFilePath("nevernote_" + QLocale.system().name() + ".qm"));
392 QApplication.instance().installTranslator(nevernoteTranslator);
394 Global.originalPalette = QApplication.palette();
395 QApplication.setStyle(Global.getStyle());
396 if (Global.useStandardPalette())
397 QApplication.setPalette(QApplication.style().standardPalette());
398 setWindowTitle(tr("NixNote"));
400 mainLeftRightSplitter = new QSplitter();
401 setCentralWidget(mainLeftRightSplitter);
402 leftSplitter1 = new QSplitter();
403 leftSplitter1.setOrientation(Qt.Orientation.Vertical);
405 browserIndexSplitter = new QSplitter();
406 browserIndexSplitter.setOrientation(Qt.Orientation.Vertical);
408 //* Setup threads & thread timers
409 // int indexRunnerCount = Global.getIndexThreads();
410 // indexRunnerCount = 1;
411 QThreadPool.globalInstance().setMaxThreadCount(Global.threadCount); // increase max thread count
413 logger.log(logger.EXTREME, "Building list manager");
414 listManager = new ListManager(conn, logger);
416 logger.log(logger.EXTREME, "Building index runners & timers");
417 indexRunner = new IndexRunner("indexRunner.log",
418 Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(),
419 Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
420 indexThread = new QThread(indexRunner, "Index Thread");
421 indexRunner.indexAttachmentsLocally = Global.indexAttachmentsLocally();
422 indexRunner.indexImageRecognition = Global.indexImageRecognition();
423 indexRunner.indexNoteBody = Global.indexNoteBody();
424 indexRunner.indexNoteTitle = Global.indexNoteTitle();
425 indexRunner.specialIndexCharacters = Global.getSpecialIndexCharacters();
428 synchronizeAnimationTimer = new QTimer();
429 synchronizeAnimationTimer.timeout.connect(this, "updateSyncButton()");
431 indexTimer = new QTimer();
432 indexTime = 1000*Global.getIndexThreadSleepInterval();
433 indexTimer.start(indexTime); // Start indexing timer
434 indexTimer.timeout.connect(this, "indexTimer()");
435 indexDisabled = false;
436 indexRunning = false;
438 logger.log(logger.EXTREME, "Setting sync thread & timers");
440 syncRunner = new SyncRunner("syncRunner.log",
441 Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(),
442 Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
443 syncTime = new SyncTimes().timeValue(Global.getSyncInterval());
444 syncTimer = new QTimer();
445 syncTimer.timeout.connect(this, "syncTimer()");
446 syncRunner.status.message.connect(this, "setMessage(String)");
447 syncRunner.syncSignal.finished.connect(this, "syncThreadComplete(Boolean)");
448 syncRunner.syncSignal.errorDisconnect.connect(this, "remoteErrorDisconnect()");
451 automaticSync = true;
452 syncTimer.start(syncTime*60*1000);
454 automaticSync = false;
457 syncRunner.setEvernoteUpdateCount(Global.getEvernoteUpdateCount());
458 syncThread = new QThread(syncRunner, "Synchronization Thread");
462 logger.log(logger.EXTREME, "Starting thumnail thread");
463 pdfReadyQueue = new ArrayList<String>();
464 thumbnailRunner = new ThumbnailRunner("thumbnailRunner.log",
465 Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(),
466 Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
467 thumbnailThread = new QThread(thumbnailRunner, "Thumbnail Thread");
468 thumbnailRunner.noteSignal.thumbnailPageReady.connect(this, "thumbnailHTMLReady(String,QByteArray,Integer)");
469 thumbnailThread.start();
470 thumbGenerators = new ArrayList<Thumbnailer>();
471 thumbnailTimer = new QTimer();
472 thumbnailTimer.timeout.connect(this, "thumbnailTimer()");
474 thumbnailTimer.setInterval(500*1000); // Thumbnail every minute
475 thumbnailTimer.start();
477 logger.log(logger.EXTREME, "Starting authentication timer");
478 authTimer = new QTimer();
479 authTimer.timeout.connect(this, "authTimer()");
480 authTimer.start(1000*60*15);
481 syncRunner.syncSignal.authRefreshComplete.connect(this, "authRefreshComplete(boolean)");
483 logger.log(logger.EXTREME, "Setting save note timer");
484 saveTimer = new QTimer();
485 saveTimer.timeout.connect(this, "saveNote()");
486 if (Global.getAutoSaveInterval() > 0) {
487 saveTimer.setInterval(1000*60*Global.getAutoSaveInterval());
490 listManager.saveRunner.noteSignals.noteSaveRunnerError.connect(this, "saveRunnerError(String, String)");
492 logger.log(logger.EXTREME, "Starting external file monitor timer");
493 externalFileSaveTimer = new QTimer();
494 externalFileSaveTimer.timeout.connect(this, "externalFileEditedSaver()");
495 externalFileSaveTimer.setInterval(1000*5); // save every 5 seconds;
496 externalFiles = new ArrayList<String>();
497 importFilesDelete = new ArrayList<String>();
498 importFilesKeep = new ArrayList<String>();
499 externalFileSaveTimer.start();
501 notebookTree = new NotebookTreeWidget(conn);
502 attributeTree = new AttributeTreeWidget();
503 tagTree = new TagTreeWidget(conn);
504 savedSearchTree = new SavedSearchTreeWidget();
505 trashTree = new TrashTreeWidget();
506 noteTableView = new TableView(logger, listManager);
508 searchField = new QComboBox();
509 searchField.setObjectName("searchField");
510 //setStyleSheet("QComboBox#searchField { background-color: yellow }");
511 searchField.setEditable(true);
512 searchField.activatedIndex.connect(this, "searchFieldChanged()");
513 searchField.setDuplicatesEnabled(false);
514 searchField.editTextChanged.connect(this,"searchFieldTextChanged(String)");
515 searchShortcut = new QShortcut(this);
516 setupShortcut(searchShortcut, "Focus_Search");
517 searchShortcut.activated.connect(this, "focusSearch()");
519 quotaBar = new QuotaProgressBar();
521 zoomSpinner = new QSpinBox();
522 zoomSpinner.setMinimum(10);
523 zoomSpinner.setMaximum(1000);
524 zoomSpinner.setAccelerated(true);
525 zoomSpinner.setSingleStep(10);
526 zoomSpinner.setValue(100);
527 zoomSpinner.valueChanged.connect(this, "zoomChanged()");
529 searchLayout = new SearchPanel(searchField, quotaBar, notebookTree, zoomSpinner);
532 QGridLayout leftGrid = new QGridLayout();
533 leftSplitter1.setContentsMargins(5, 0, 0, 7);
534 leftSplitter1.setLayout(leftGrid);
535 leftGrid.addWidget(searchLayout,1,1);
536 leftGrid.addWidget(tagTree,2,1);
537 leftGrid.addWidget(attributeTree,3,1);
538 leftGrid.addWidget(savedSearchTree,4,1);
539 leftGrid.addWidget(trashTree,5, 1);
541 // Setup the browser window
542 noteCache = new HashMap<String,String>();
543 readOnlyCache = new HashMap<String, Boolean>();
544 inkNoteCache = new HashMap<String, Boolean>();
545 browserWindow = new BrowserWindow(conn);
547 mainLeftRightSplitter.addWidget(leftSplitter1);
548 mainLeftRightSplitter.addWidget(browserIndexSplitter);
550 if (Global.getListView() == Global.View_List_Wide) {
551 browserIndexSplitter.addWidget(noteTableView);
552 browserIndexSplitter.addWidget(browserWindow);
554 mainLeftRightSplitter.addWidget(noteTableView);
555 mainLeftRightSplitter.addWidget(browserWindow);
558 // Setup the thumbnail viewer
559 thumbnailViewer = new ThumbnailViewer();
560 thumbnailViewer.upArrow.connect(this, "upAction()");
561 thumbnailViewer.downArrow.connect(this, "downAction()");
562 thumbnailViewer.leftArrow.connect(this, "nextViewedAction()");
563 thumbnailViewer.rightArrow.connect(this, "previousViewedAction()");
565 //Setup external browser manager
566 externalWindows = new HashMap<String, ExternalBrowse>();
568 listManager.loadNotesIndex();
569 initializeNotebookTree();
571 initializeSavedSearchTree();
572 attributeTree.itemClicked.connect(this, "attributeTreeClicked(QTreeWidgetItem, Integer)");
573 attributeTreeSelected = null;
574 initializeNoteTable();
576 selectedNoteGUIDs = new ArrayList<String>();
577 statusBar = new QStatusBar();
578 setStatusBar(statusBar);
579 menuBar = new MainMenuBar(this);
580 emitLog = new ArrayList<String>();
582 tagTree.setDeleteAction(menuBar.tagDeleteAction);
583 tagTree.setMergeAction(menuBar.tagMergeAction);
584 tagTree.setEditAction(menuBar.tagEditAction);
585 tagTree.setAddAction(menuBar.tagAddAction);
586 tagTree.setIconAction(menuBar.tagIconAction);
587 tagTree.setVisible(Global.isWindowVisible("tagTree"));
588 leftSplitter1.setVisible(Global.isWindowVisible("leftPanel"));
589 tagTree.noteSignal.tagsAdded.connect(this, "tagsAdded(String, String)");
590 menuBar.hideTags.setChecked(Global.isWindowVisible("tagTree"));
591 listManager.tagSignal.listChanged.connect(this, "reloadTagTree()");
593 if (!Global.isWindowVisible("zoom")) {
594 searchLayout.hideZoom();
595 menuBar.hideZoom.setChecked(false);
598 notebookTree.setDeleteAction(menuBar.notebookDeleteAction);
599 notebookTree.setEditAction(menuBar.notebookEditAction);
600 notebookTree.setAddAction(menuBar.notebookAddAction);
601 notebookTree.setIconAction(menuBar.notebookIconAction);
602 notebookTree.setStackAction(menuBar.notebookStackAction);
603 notebookTree.setPublishAction(menuBar.notebookPublishAction);
604 notebookTree.setShareAction(menuBar.notebookShareAction);
605 notebookTree.setVisible(Global.isWindowVisible("notebookTree"));
606 notebookTree.noteSignal.notebookChanged.connect(this, "updateNoteNotebook(String, String)");
607 notebookTree.noteSignal.tagsChanged.connect(this, "updateNoteTags(String, List)");
608 notebookTree.noteSignal.tagsChanged.connect(this, "updateListTags(String, List)");
609 menuBar.hideNotebooks.setChecked(Global.isWindowVisible("notebookTree"));
611 savedSearchTree.setAddAction(menuBar.savedSearchAddAction);
612 savedSearchTree.setEditAction(menuBar.savedSearchEditAction);
613 savedSearchTree.setDeleteAction(menuBar.savedSearchDeleteAction);
614 savedSearchTree.setIconAction(menuBar.savedSearchIconAction);
615 savedSearchTree.itemSelectionChanged.connect(this, "updateSavedSearchSelection()");
616 savedSearchTree.setVisible(Global.isWindowVisible("savedSearchTree"));
617 menuBar.hideSavedSearches.setChecked(Global.isWindowVisible("savedSearchTree"));
619 noteTableView.setAddAction(menuBar.noteAdd);
620 noteTableView.setDeleteAction(menuBar.noteDelete);
621 noteTableView.setRestoreAction(menuBar.noteRestoreAction);
622 noteTableView.setNoteDuplicateAction(menuBar.noteDuplicateAction);
623 noteTableView.setNoteHistoryAction(menuBar.noteOnlineHistoryAction);
624 noteTableView.noteSignal.titleColorChanged.connect(this, "titleColorChanged(Integer)");
625 noteTableView.noteSignal.notePinned.connect(this, "notePinned()");
626 noteTableView.setMergeNotesAction(menuBar.noteMergeAction);
627 noteTableView.setCopyAsUrlAction(menuBar.noteCopyAsUrlAction);
628 noteTableView.doubleClicked.connect(this, "listDoubleClick()");
629 listManager.trashSignal.countChanged.connect(trashTree, "updateCounts(Integer)");
631 quotaBar.setMouseClickAction(menuBar.accountAction);
634 trashTree.itemSelectionChanged.connect(this, "trashTreeSelection()");
635 trashTree.setEmptyAction(menuBar.emptyTrashAction);
636 trashTree.setVisible(Global.isWindowVisible("trashTree"));
637 menuBar.hideTrash.setChecked(Global.isWindowVisible("trashTree"));
638 trashTree.updateCounts(listManager.getTrashCount());
639 attributeTree.setVisible(Global.isWindowVisible("attributeTree"));
640 menuBar.hideAttributes.setChecked(Global.isWindowVisible("attributeTree"));
642 noteTableView.setVisible(Global.isWindowVisible("noteList"));
643 menuBar.hideNoteList.setChecked(Global.isWindowVisible("noteList"));
645 if (!Global.isWindowVisible("editorButtonBar"))
646 toggleEditorButtonBar();
647 if (!Global.isWindowVisible("leftPanel"))
648 menuBar.hideLeftSide.setChecked(true);
649 if (Global.isWindowVisible("noteInformation"))
650 toggleNoteInformation();
651 quotaBar.setVisible(Global.isWindowVisible("quota"));
652 if (!quotaBar.isVisible())
653 menuBar.hideQuota.setChecked(false);
654 searchField.setVisible(Global.isWindowVisible("searchField"));
655 if (!searchField.isVisible())
656 menuBar.hideSearch.setChecked(false);
658 if (searchField.isHidden() && quotaBar.isHidden() && zoomSpinner.isHidden() && notebookTree.isHidden())
663 find = new FindDialog();
664 find.getOkButton().clicked.connect(this, "doFindText()");
666 // Setup the tray icon menu bar
667 trayShowAction = new QAction(tr("Show/Hide"), this);
668 trayExitAction = new QAction(tr("Exit"), this);
669 trayAddNoteAction = new QAction(tr("Add Note"), this);
671 trayExitAction.triggered.connect(this, "closeNeverNote()");
672 trayAddNoteAction.triggered.connect(this, "addNote()");
673 trayShowAction.triggered.connect(this, "trayToggleVisible()");
675 trayMenu = new QMenu(this);
676 trayMenu.addAction(trayAddNoteAction);
677 trayMenu.addAction(trayShowAction);
678 trayMenu.addAction(trayExitAction);
681 trayIcon = new QSystemTrayIcon(this);
682 trayIcon.setToolTip(tr("NixNote"));
683 trayIcon.setContextMenu(trayMenu);
684 trayIcon.activated.connect(this, "trayActivated(com.trolltech.qt.gui.QSystemTrayIcon$ActivationReason)");
687 currentNoteGuid = Global.getLastViewedNoteGuid();
688 historyGuids = new ArrayList<String>();
692 if (!currentNoteGuid.trim().equals("")) {
693 currentNote = conn.getNoteTable().getNote(currentNoteGuid, true,true,false,false,true);
696 noteIndexUpdated(true);
698 menuBar.showEditorBar.setChecked(Global.isWindowVisible("editorButtonBar"));
699 if (menuBar.showEditorBar.isChecked())
700 showEditorButtons(browserWindow);
701 tagIndexUpdated(true);
702 savedSearchIndexUpdated();
703 notebookIndexUpdated();
705 setupSyncSignalListeners();
706 setupBrowserSignalListeners();
707 setupIndexListeners();
710 tagTree.tagSignal.listChanged.connect(this, "tagIndexUpdated()");
711 tagTree.showAllTags(true);
713 QIcon appIcon = new QIcon(iconPath+"nevernote.png");
714 if (QSystemTrayIcon.isSystemTrayAvailable()) {
715 setWindowIcon(appIcon);
716 trayIcon.setIcon(appIcon);
717 if (Global.showTrayIcon() || Global.minimizeOnClose())
723 scrollToGuid(currentNoteGuid);
724 if (Global.automaticLogin()) {
726 if (Global.isConnected)
729 setupFolderImports();
732 restoreWindowState(true);
734 if (Global.mimicEvernoteInterface) {
735 notebookTree.selectGuid("");
738 threadMonitorTimer = new QTimer();
739 threadMonitorTimer.timeout.connect(this, "threadMonitorCheck()");
740 threadMonitorTimer.start(1000*10); // Check for threads every 10 seconds;
742 historyGuids.add(currentNoteGuid);
745 menuBar.blockSignals(true);
746 menuBar.narrowListView.blockSignals(true);
747 menuBar.wideListView.blockSignals(true);
748 if (Global.getListView() == Global.View_List_Narrow) {
749 menuBar.narrowListView.setChecked(true);
752 menuBar.wideListView.setChecked(true);
754 menuBar.blockSignals(false);
755 menuBar.narrowListView.blockSignals(false);
756 menuBar.wideListView.blockSignals(false);
758 if (Global.getListView() == Global.View_List_Wide) {
759 browserIndexSplitter.addWidget(noteTableView);
760 browserIndexSplitter.addWidget(browserWindow);
762 mainLeftRightSplitter.addWidget(noteTableView);
763 mainLeftRightSplitter.addWidget(browserWindow);
766 messageTimer = new QTimer();
767 messageTimer.timeout.connect(this, "clearMessage()");
768 messageTimer.setInterval(1000*15);
771 int sortCol = Global.getSortColumn();
772 int sortOrder = Global.getSortOrder();
773 noteTableView.proxyModel.blocked = true;
774 noteTableView.sortByColumn(sortCol, SortOrder.resolve(sortOrder));
775 noteTableView.proxyModel.blocked = false;
776 noteTableView.proxyModel.sortChanged.connect(this, "tableSortOrderChanged(Integer,Integer)");
778 // Set the startup notebook
779 String defaultNotebook = Global.getStartupNotebook();
780 if (!defaultNotebook.equals("AllNotebooks") && !defaultNotebook.equals("")) {
781 for (int k=0; k<listManager.getNotebookIndex().size(); k++) {
782 if (listManager.getNotebookIndex().get(k).isDefaultNotebook()) {
783 notebookTree.clearSelection();
784 notebookTree.selectGuid(listManager.getNotebookIndex().get(k).getGuid());
785 notebookTree.selectionSignal.emit();
790 if (Global.checkVersionUpgrade())
795 public static void main(String[] args) {
796 log.setLevel(Level.FATAL);
797 QApplication.initialize(args);
798 QPixmap pixmap = new QPixmap("classpath:cx/fbn/nevernote/icons/splash_logo.png");
799 QSplashScreen splash = new QSplashScreen(pixmap);
802 DatabaseConnection dbConn;
805 initializeGlobalSettings(args);
807 showSplash = Global.isWindowVisible("SplashScreen");
811 dbConn = setupDatabaseConnection();
813 // Must be last stage of setup - only safe once DB is open hence we know we are the only instance running
814 Global.getFileManager().purgeResDirectory(true);
816 } catch (InitializationException e) {
819 QMessageBox.critical(null, "Startup error", "Aborting: " + e.getMessage());
823 NeverNote application = new NeverNote(dbConn);
824 if (Global.syncOnly) {
825 System.out.println("Performing synchronization only.");
826 application.remoteConnect();
827 if (Global.isConnected) {
828 application.syncRunner.syncNeeded = true;
829 application.syncRunner.addWork("SYNC");
830 application.syncRunner.addWork("STOP");
831 while(!application.syncRunner.isIdle());
832 application.closeNeverNote();
837 application.setAttribute(WidgetAttribute.WA_DeleteOnClose, true);
838 if (Global.startMinimized())
839 application.showMinimized();
841 if (Global.wasWindowMaximized())
842 application.showMaximized();
848 splash.finish(application);
850 System.out.println("Goodbye.");
855 * Open the internal database, or create if not present
857 * @throws InitializationException when opening the database fails, e.g. because another process has it locked
859 private static DatabaseConnection setupDatabaseConnection() throws InitializationException {
860 ApplicationLogger logger = new ApplicationLogger("nevernote-database.log");
862 File f = Global.getFileManager().getDbDirFile(Global.databaseName + ".h2.db");
863 File fr = Global.getFileManager().getDbDirFile(Global.resourceDatabaseName + ".h2.db");
864 File fi = Global.getFileManager().getDbDirFile(Global.resourceDatabaseName + ".h2.db");
866 Global.setDatabaseUrl("");
868 Global.setResourceDatabaseUrl("");
870 Global.setIndexDatabaseUrl("");
872 if (Global.getDatabaseUrl().toUpperCase().indexOf("CIPHER=") > -1) {
873 boolean goodCheck = false;
875 DatabaseLoginDialog dialog = new DatabaseLoginDialog();
877 if (!dialog.okPressed())
879 Global.cipherPassword = dialog.getPassword();
880 goodCheck = databaseCheck(Global.getDatabaseUrl(), Global.getDatabaseUserid(),
881 Global.getDatabaseUserPassword(), Global.cipherPassword);
884 DatabaseConnection dbConn = new DatabaseConnection(logger,Global.getDatabaseUrl(),
885 Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(),
886 Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword, 0);
890 // Encrypt the database upon shutdown
891 private void encryptOnShutdown() {
892 String dbPath= Global.getFileManager().getDbDirPath("");
895 Statement st = conn.getConnection().createStatement();
896 st.execute("shutdown");
897 st = conn.getResourceConnection().createStatement();
898 st.execute("shutdown");
899 st = conn.getIndexConnection().createStatement();
900 st.execute("shutdown");
901 if (QMessageBox.question(this, tr("Are you sure"),
902 tr("Are you sure you wish to encrypt the database?"),
903 QMessageBox.StandardButton.Yes,
904 QMessageBox.StandardButton.No) == StandardButton.Yes.value()) {
905 ChangeFileEncryption.execute(dbPath, "NeverNote", encryptCipher, null, Global.cipherPassword.toCharArray(), true);
906 ChangeFileEncryption.execute(dbPath, "Resources", encryptCipher, null, Global.cipherPassword.toCharArray(), true);
907 ChangeFileEncryption.execute(dbPath, "Index", encryptCipher, null, Global.cipherPassword.toCharArray(), true);
908 Global.setDatabaseUrl(Global.getDatabaseUrl() + ";CIPHER="+encryptCipher);
909 Global.setResourceDatabaseUrl(Global.getResourceDatabaseUrl() + ";CIPHER="+encryptCipher);
910 Global.setIndexDatabaseUrl(Global.getIndexDatabaseUrl() + ";CIPHER="+encryptCipher);
912 QMessageBox.information(this, tr("Encryption Complete"), tr("Encryption is complete"));
914 } catch (SQLException e) {
919 // Decrypt the database upon shutdown
920 private void decryptOnShutdown() {
921 String dbPath= Global.getFileManager().getDbDirPath("");
922 String dbName = "NeverNote";
924 Statement st = conn.getConnection().createStatement();
925 st.execute("shutdown");
926 if (Global.getDatabaseUrl().toUpperCase().indexOf(";CIPHER=AES") > -1)
927 encryptCipher = "AES";
929 encryptCipher = "XTEA";
930 if (QMessageBox.question(this, tr("Confirmation"), tr("Are you sure",
931 "Are you sure you wish to decrypt the database?"),
932 QMessageBox.StandardButton.Yes,
933 QMessageBox.StandardButton.No) == StandardButton.Yes.value()) {
935 ChangeFileEncryption.execute(dbPath, dbName, encryptCipher, Global.cipherPassword.toCharArray(), null, true);
936 Global.setDatabaseUrl("");
937 Global.setResourceDatabaseUrl("");
938 Global.setIndexDatabaseUrl("");
939 QMessageBox.information(this, tr("Decryption Complete"), tr("Decryption is complete"));
941 } catch (SQLException e) {
946 * Encrypt/Decrypt the local database
948 public void doDatabaseEncrypt() {
949 // The database is not currently encrypted
950 if (Global.getDatabaseUrl().toUpperCase().indexOf("CIPHER=") == -1) {
951 if (QMessageBox.question(this, tr("Confirmation"), tr("Encrypting the database is used" +
952 "to enhance security and is performed\nupon shutdown, but please be aware that if"+
953 " you lose the password your\nis lost forever.\n\nIt is highly recommended you " +
954 "perform a backup and/or fully synchronize\n prior to executing this funtction.\n\n" +
955 "Do you wish to proceed?"),
956 QMessageBox.StandardButton.Yes,
957 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
960 DBEncryptDialog dialog = new DBEncryptDialog();
962 if (dialog.okPressed()) {
963 Global.cipherPassword = dialog.getPassword();
964 encryptOnShutdown = true;
965 encryptCipher = dialog.getEncryptionMethod();
968 DBEncryptDialog dialog = new DBEncryptDialog();
969 dialog.setWindowTitle(tr("Database Decryption"));
970 dialog.hideEncryption();
972 if (dialog.okPressed()) {
973 if (!dialog.getPassword().equals(Global.cipherPassword)) {
974 QMessageBox.critical(null, tr("Incorrect Password"), tr("Incorrect Password"));
977 decryptOnShutdown = true;
984 private static void initializeGlobalSettings(String[] args) throws InitializationException {
985 StartupConfig startupConfig = new StartupConfig();
987 for (String arg : args) {
988 String lower = arg.toLowerCase();
989 if (lower.startsWith("--name="))
990 startupConfig.setName(arg.substring(arg.indexOf('=') + 1));
991 if (lower.startsWith("--home="))
992 startupConfig.setHomeDirPath(arg.substring(arg.indexOf('=') + 1));
993 if (lower.startsWith("--disable-viewing"))
994 startupConfig.setDisableViewing(true);
995 if (lower.startsWith("--sync-only=true"))
996 startupConfig.setSyncOnly(true);
998 Global.setup(startupConfig);
1004 public void closeEvent(QCloseEvent event) {
1005 if (Global.minimizeOnClose() && !closeAction) {
1010 logger.log(logger.HIGH, "Entering NeverNote.closeEvent");
1013 if (currentNote!= null & browserWindow!=null) {
1014 if (currentNote.getTitle() != null && browserWindow != null
1015 && !currentNote.getTitle().equals(browserWindow.getTitle()))
1016 conn.getNoteTable().updateNoteTitle(currentNote.getGuid(), browserWindow.getTitle());
1019 setMessage(tr("Beginning shutdown."));
1021 // Close down external windows
1022 Collection<ExternalBrowse> windows = externalWindows.values();
1023 Iterator<ExternalBrowse> iterator = windows.iterator();
1024 while (iterator.hasNext()) {
1025 ExternalBrowse browser = iterator.next();
1026 browser.windowClosing.disconnect();
1031 externalFileEditedSaver();
1032 if (Global.isConnected && Global.synchronizeOnClose()) {
1033 setMessage(tr("Performing synchronization before closing."));
1034 syncRunner.syncNeeded = true;
1035 syncRunner.addWork("SYNC");
1037 syncRunner.keepRunning = false;
1039 syncRunner.addWork("STOP");
1040 setMessage("Closing Program.");
1041 threadMonitorTimer.stop();
1043 thumbnailRunner.addWork("STOP");
1044 indexRunner.addWork("STOP");
1049 if (tempFiles != null)
1052 browserWindow.noteSignal.tagsChanged.disconnect();
1053 browserWindow.noteSignal.titleChanged.disconnect();
1054 browserWindow.noteSignal.noteChanged.disconnect();
1055 browserWindow.noteSignal.notebookChanged.disconnect();
1056 browserWindow.noteSignal.createdDateChanged.disconnect();
1057 browserWindow.noteSignal.alteredDateChanged.disconnect();
1058 syncRunner.searchSignal.listChanged.disconnect();
1059 syncRunner.tagSignal.listChanged.disconnect();
1060 syncRunner.notebookSignal.listChanged.disconnect();
1061 syncRunner.noteIndexSignal.listChanged.disconnect();
1064 Global.saveWindowVisible("toolBar", toolBar.isVisible());
1065 saveNoteColumnPositions();
1066 saveNoteIndexWidth();
1068 int width = notebookTree.columnWidth(0);
1069 Global.setColumnWidth("notebookTreeName", width);
1070 width = tagTree.columnWidth(0);
1071 Global.setColumnWidth("tagTreeName", width);
1073 Global.saveWindowMaximized(isMaximized());
1074 Global.saveCurrentNoteGuid(currentNoteGuid);
1076 int sortCol = noteTableView.proxyModel.sortColumn();
1077 int sortOrder = noteTableView.proxyModel.sortOrder().value();
1078 Global.setSortColumn(sortCol);
1079 Global.setSortOrder(sortOrder);
1083 Global.keepRunning = false;
1085 logger.log(logger.MEDIUM, "Waiting for indexThread to stop");
1086 if (indexRunner.thread().isAlive())
1087 indexRunner.thread().join(50);
1088 if (!indexRunner.thread().isAlive())
1089 logger.log(logger.MEDIUM, "Index thread has stopped");
1091 logger.log(logger.MEDIUM, "Index thread still running - interrupting");
1092 indexRunner.thread().interrupt();
1094 } catch (InterruptedException e1) {
1095 e1.printStackTrace();
1098 if (!syncRunner.thread().isAlive()) {
1099 logger.log(logger.MEDIUM, "Waiting for syncThread to stop");
1100 if (syncRunner.thread().isAlive()) {
1101 System.out.println(tr("Synchronizing. Please be patient."));
1102 for(;syncRunner.thread().isAlive();) {
1105 } catch (InterruptedException e) {
1106 e.printStackTrace();
1110 logger.log(logger.MEDIUM, "Sync thread has stopped");
1113 if (encryptOnShutdown) {
1114 encryptOnShutdown();
1116 if (decryptOnShutdown) {
1117 decryptOnShutdown();
1120 Global.getFileManager().purgeResDirectory(false);
1121 } catch (InitializationException e) {
1122 System.out.println(tr("Empty res directory purge failed"));
1123 e.printStackTrace();
1125 logger.log(logger.HIGH, "Leaving NeverNote.closeEvent");
1129 private void closeNeverNote() {
1133 public void setMessage(String s) {
1134 logger.log(logger.HIGH, "Entering NeverNote.setMessage");
1137 logger.log(logger.HIGH, "Message: " +s);
1138 statusBar.showMessage(s);
1142 messageTimer.stop();
1143 messageTimer.setSingleShot(true);
1144 messageTimer.start();
1147 logger.log(logger.HIGH, "Leaving NeverNote.setMessage");
1150 private void clearMessage() {
1151 statusBar.clearMessage();
1155 private void waitCursor(boolean wait) {
1157 if (QApplication.overrideCursor() == null)
1158 QApplication.setOverrideCursor(new QCursor(Qt.CursorShape.WaitCursor));
1161 while (QApplication.overrideCursor() != null)
1162 QApplication.restoreOverrideCursor();
1164 listManager.refreshCounters();
1167 private void setupIndexListeners() {
1168 // indexRunner.noteSignal.noteIndexed.connect(this, "indexThreadComplete(String)");
1169 // indexRunner.resourceSignal.resourceIndexed.connect(this, "indexThreadComplete(String)");
1170 indexRunner.signal.indexStarted.connect(this, "indexStarted()");
1171 indexRunner.signal.indexFinished.connect(this, "indexComplete()");
1173 private void setupSyncSignalListeners() {
1174 syncRunner.tagSignal.listChanged.connect(this, "tagIndexUpdated()");
1175 syncRunner.searchSignal.listChanged.connect(this, "savedSearchIndexUpdated()");
1176 syncRunner.notebookSignal.listChanged.connect(this, "notebookIndexUpdated()");
1177 syncRunner.noteIndexSignal.listChanged.connect(this, "noteIndexUpdated(boolean)");
1178 syncRunner.noteSignal.quotaChanged.connect(this, "updateQuotaBar()");
1180 syncRunner.syncSignal.saveUploadAmount.connect(this,"saveUploadAmount(long)");
1181 syncRunner.syncSignal.saveUserInformation.connect(this,"saveUserInformation(User)");
1182 syncRunner.syncSignal.saveEvernoteUpdateCount.connect(this,"saveEvernoteUpdateCount(int)");
1184 syncRunner.noteSignal.guidChanged.connect(this, "noteGuidChanged(String, String)");
1185 syncRunner.noteSignal.noteChanged.connect(this, "invalidateNoteCache(String, String)");
1186 syncRunner.resourceSignal.resourceGuidChanged.connect(this, "noteResourceGuidChanged(String,String,String)");
1187 syncRunner.noteSignal.noteDownloaded.connect(listManager, "noteDownloaded(Note)");
1188 syncRunner.noteSignal.notebookChanged.connect(this, "updateNoteNotebook(String, String)");
1190 syncRunner.syncSignal.refreshLists.connect(this, "refreshLists()");
1193 private void setupBrowserSignalListeners() {
1194 setupBrowserWindowListeners(browserWindow, true);
1197 private void setupBrowserWindowListeners(BrowserWindow browser, boolean master) {
1198 browser.fileWatcher.fileChanged.connect(this, "externalFileEdited(String)");
1199 browser.noteSignal.tagsChanged.connect(this, "updateNoteTags(String, List)");
1200 browser.noteSignal.tagsChanged.connect(this, "updateListTags(String, List)");
1201 if (master) browser.noteSignal.noteChanged.connect(this, "setNoteDirty()");
1202 browser.noteSignal.titleChanged.connect(listManager, "updateNoteTitle(String, String)");
1203 browser.noteSignal.titleChanged.connect(this, "updateNoteTitle(String, String)");
1204 browser.noteSignal.notebookChanged.connect(this, "updateNoteNotebook(String, String)");
1205 browser.noteSignal.createdDateChanged.connect(listManager, "updateNoteCreatedDate(String, QDateTime)");
1206 browser.noteSignal.alteredDateChanged.connect(listManager, "updateNoteAlteredDate(String, QDateTime)");
1207 browser.noteSignal.subjectDateChanged.connect(listManager, "updateNoteSubjectDate(String, QDateTime)");
1208 browser.noteSignal.authorChanged.connect(listManager, "updateNoteAuthor(String, String)");
1209 browser.noteSignal.geoChanged.connect(listManager, "updateNoteGeoTag(String, Double,Double,Double)");
1210 browser.noteSignal.geoChanged.connect(this, "setNoteDirty()");
1211 browser.noteSignal.sourceUrlChanged.connect(listManager, "updateNoteSourceUrl(String, String)");
1212 browser.blockApplication.connect(this, "blockApplication(BrowserWindow)");
1213 browser.unblockApplication.connect(this, "unblockApplication()");
1214 if (master) browser.focusLost.connect(this, "saveNote()");
1215 browser.resourceSignal.contentChanged.connect(this, "externalFileEdited(String)");
1216 browser.evernoteLinkClicked.connect(this, "evernoteLinkClick(String, String)");
1219 //**************************************************
1221 //**************************************************
1222 private void setupShortcut(QShortcut action, String text) {
1223 if (!Global.shortcutKeys.containsAction(text))
1225 action.setKey(new QKeySequence(Global.shortcutKeys.getShortcut(text)));
1228 //***************************************************************
1229 //***************************************************************
1230 //* Settings and look & feel
1231 //***************************************************************
1232 //***************************************************************
1233 @SuppressWarnings("unused")
1234 private void settings() {
1235 logger.log(logger.HIGH, "Entering NeverNote.settings");
1236 saveNoteColumnPositions();
1237 saveNoteIndexWidth();
1239 ConfigDialog settings = new ConfigDialog(this);
1240 String dateFormat = Global.getDateFormat();
1241 String timeFormat = Global.getTimeFormat();
1243 indexTime = 1000*Global.getIndexThreadSleepInterval();
1244 indexTimer.start(indexTime); // reset indexing timer
1247 indexRunner.indexAttachmentsLocally = Global.indexAttachmentsLocally();
1248 indexRunner.indexNoteBody = Global.indexNoteBody();
1249 indexRunner.indexNoteTitle = Global.indexNoteTitle();
1250 indexRunner.specialIndexCharacters = Global.getSpecialIndexCharacters();
1251 indexRunner.indexImageRecognition = Global.indexImageRecognition();
1252 if (Global.showTrayIcon() || Global.minimizeOnClose())
1257 if (menuBar.showEditorBar.isChecked())
1258 showEditorButtons(browserWindow);
1260 // Reset the save timer
1261 if (Global.getAutoSaveInterval() > 0)
1262 saveTimer.setInterval(1000*60*Global.getAutoSaveInterval());
1267 // Set special reloads
1268 if (settings.getDebugPage().reloadSharedNotebooksClicked()) {
1269 conn.executeSql("Delete from LinkedNotebook");
1270 conn.executeSql("delete from SharedNotebook");
1271 conn.executeSql("Delete from Notebook where linked=true");
1272 conn.executeSql("Insert into Sync (key, value) values ('FullLinkedNotebookSync', 'true')");
1273 conn.executeSql("Insert into Sync (key, value) values ('FullSharedNotebookSync', 'true')");
1278 readOnlyCache.clear();
1279 inkNoteCache.clear();
1280 noteIndexUpdated(true);
1282 logger.log(logger.HIGH, "Leaving NeverNote.settings");
1284 // Restore things to the way they were
1285 private void restoreWindowState(boolean mainWindow) {
1286 // We need to name things or this doesn't work.
1287 setObjectName("NeverNote");
1288 restoreState(Global.restoreState(objectName()));
1289 mainLeftRightSplitter.setObjectName("mainLeftRightSplitter");
1290 browserIndexSplitter.setObjectName("browserIndexSplitter");
1291 leftSplitter1.setObjectName("leftSplitter1");
1293 // Restore the actual positions.
1295 restoreGeometry(Global.restoreGeometry(objectName()));
1296 mainLeftRightSplitter.restoreState(Global.restoreState(mainLeftRightSplitter.objectName()));
1297 browserIndexSplitter.restoreState(Global.restoreState(browserIndexSplitter.objectName()));
1298 leftSplitter1.restoreState(Global.restoreState(leftSplitter1.objectName()));
1301 // Save window positions for the next start
1302 private void saveWindowState() {
1303 Global.saveGeometry(objectName(), saveGeometry());
1304 Global.saveState(mainLeftRightSplitter.objectName(), mainLeftRightSplitter.saveState());
1305 Global.saveState(browserIndexSplitter.objectName(), browserIndexSplitter.saveState());
1306 Global.saveState(leftSplitter1.objectName(), leftSplitter1.saveState());
1307 Global.saveState(objectName(), saveState());
1309 // Load the style sheet
1310 private void loadStyleSheet() {
1311 String styleSheetName = "default.qss";
1312 if (Global.getStyle().equalsIgnoreCase("cleanlooks"))
1313 styleSheetName = "default-cleanlooks.qss";
1314 String fileName = Global.getFileManager().getQssDirPathUser("default.qss");
1315 QFile file = new QFile(fileName);
1317 // If a user default.qss doesn't exist, we use the one shipped with NeverNote
1318 if (!file.exists()) {
1319 fileName = Global.getFileManager().getQssDirPath(styleSheetName);
1320 file = new QFile(fileName);
1322 file.open(OpenModeFlag.ReadOnly);
1323 String styleSheet = file.readAll().toString();
1325 setStyleSheet(styleSheet);
1327 // Save column positions for the next time
1328 private void saveNoteColumnPositions() {
1329 int position = noteTableView.header.visualIndex(Global.noteTableCreationPosition);
1330 Global.setColumnPosition("noteTableCreationPosition", position);
1331 position = noteTableView.header.visualIndex(Global.noteTableTagPosition);
1332 Global.setColumnPosition("noteTableTagPosition", position);
1333 position = noteTableView.header.visualIndex(Global.noteTableNotebookPosition);
1334 Global.setColumnPosition("noteTableNotebookPosition", position);
1335 position = noteTableView.header.visualIndex(Global.noteTableChangedPosition);
1336 Global.setColumnPosition("noteTableChangedPosition", position);
1337 position = noteTableView.header.visualIndex(Global.noteTableAuthorPosition);
1338 Global.setColumnPosition("noteTableAuthorPosition", position);
1339 position = noteTableView.header.visualIndex(Global.noteTableSourceUrlPosition);
1340 Global.setColumnPosition("noteTableSourceUrlPosition", position);
1341 position = noteTableView.header.visualIndex(Global.noteTableSubjectDatePosition);
1342 Global.setColumnPosition("noteTableSubjectDatePosition", position);
1343 position = noteTableView.header.visualIndex(Global.noteTableTitlePosition);
1344 Global.setColumnPosition("noteTableTitlePosition", position);
1345 position = noteTableView.header.visualIndex(Global.noteTableSynchronizedPosition);
1346 Global.setColumnPosition("noteTableSynchronizedPosition", position);
1347 position = noteTableView.header.visualIndex(Global.noteTableGuidPosition);
1348 Global.setColumnPosition("noteTableGuidPosition", position);
1349 position = noteTableView.header.visualIndex(Global.noteTableThumbnailPosition);
1350 Global.setColumnPosition("noteTableThumbnailPosition", position);
1351 position = noteTableView.header.visualIndex(Global.noteTablePinnedPosition);
1352 Global.setColumnPosition("noteTablePinnedPosition", position);
1355 // Save column widths for the next time
1356 private void saveNoteIndexWidth() {
1358 width = noteTableView.getColumnWidth(Global.noteTableCreationPosition);
1359 Global.setColumnWidth("noteTableCreationPosition", width);
1360 width = noteTableView.getColumnWidth(Global.noteTableChangedPosition);
1361 Global.setColumnWidth("noteTableChangedPosition", width);
1362 width = noteTableView.getColumnWidth(Global.noteTableGuidPosition);
1363 Global.setColumnWidth("noteTableGuidPosition", width);
1364 width = noteTableView.getColumnWidth(Global.noteTableNotebookPosition);
1365 Global.setColumnWidth("noteTableNotebookPosition", width);
1366 width = noteTableView.getColumnWidth(Global.noteTableTagPosition);
1367 Global.setColumnWidth("noteTableTagPosition", width);
1368 width = noteTableView.getColumnWidth(Global.noteTableTitlePosition);
1369 Global.setColumnWidth("noteTableTitlePosition", width);
1370 width = noteTableView.getColumnWidth(Global.noteTableSourceUrlPosition);
1371 Global.setColumnWidth("noteTableSourceUrlPosition", width);
1372 width = noteTableView.getColumnWidth(Global.noteTableAuthorPosition);
1373 Global.setColumnWidth("noteTableAuthorPosition", width);
1374 width = noteTableView.getColumnWidth(Global.noteTableSubjectDatePosition);
1375 Global.setColumnWidth("noteTableSubjectDatePosition", width);
1376 width = noteTableView.getColumnWidth(Global.noteTableSynchronizedPosition);
1377 Global.setColumnWidth("noteTableSynchronizedPosition", width);
1378 width = noteTableView.getColumnWidth(Global.noteTableThumbnailPosition);
1379 Global.setColumnWidth("noteTableThumbnailPosition", width);
1380 width = noteTableView.getColumnWidth(Global.noteTableGuidPosition);
1381 Global.setColumnWidth("noteTableGuidPosition", width);
1382 width = noteTableView.getColumnWidth(Global.noteTablePinnedPosition);
1383 Global.setColumnWidth("noteTablePinnedPosition", width);
1386 @SuppressWarnings("unused")
1387 private void toggleSearchWindow() {
1388 logger.log(logger.HIGH, "Entering NeverNote.toggleSearchWindow");
1389 searchLayout.toggleSearchField();
1390 menuBar.hideSearch.setChecked(searchField.isVisible());
1391 Global.saveWindowVisible("searchField", searchField.isVisible());
1392 logger.log(logger.HIGH, "Leaving NeverNote.toggleSearchWindow");
1394 @SuppressWarnings("unused")
1395 private void toggleQuotaWindow() {
1396 logger.log(logger.HIGH, "Entering NeverNote.toggleQuotaWindow");
1397 searchLayout.toggleQuotaBar();
1398 menuBar.hideQuota.setChecked(quotaBar.isVisible());
1399 Global.saveWindowVisible("quota", quotaBar.isVisible());
1400 logger.log(logger.HIGH, "Leaving NeverNote.toggleQuotaWindow");
1402 @SuppressWarnings("unused")
1403 private void toggleZoomWindow() {
1404 logger.log(logger.HIGH, "Entering NeverNote.toggleZoomWindow");
1405 searchLayout.toggleZoom();
1406 menuBar.hideZoom.setChecked(zoomSpinner.isVisible());
1407 Global.saveWindowVisible("zoom", zoomSpinner.isVisible());
1408 logger.log(logger.HIGH, "Leaving NeverNote.toggleZoomWindow");
1413 //***************************************************************
1414 //***************************************************************
1415 //** These functions deal with Notebook menu items
1416 //***************************************************************
1417 //***************************************************************
1418 // Setup the tree containing the user's notebooks.
1419 private void initializeNotebookTree() {
1420 logger.log(logger.HIGH, "Entering NeverNote.initializeNotebookTree");
1421 // notebookTree.itemClicked.connect(this, "notebookTreeSelection()");
1422 notebookTree.selectionSignal.connect(this, "notebookTreeSelection()");
1423 listManager.notebookSignal.refreshNotebookTreeCounts.connect(notebookTree, "updateCounts(List, List)");
1424 logger.log(logger.HIGH, "Leaving NeverNote.initializeNotebookTree");
1426 // Listener when a notebook is selected
1427 private void notebookTreeSelection() {
1428 logger.log(logger.HIGH, "Entering NeverNote.notebookTreeSelection");
1429 noteTableView.proxyModel.blocked = true;
1432 clearAttributeFilter();
1433 clearSavedSearchFilter();
1434 if (Global.mimicEvernoteInterface) {
1436 searchField.clear();
1438 menuBar.noteRestoreAction.setVisible(false);
1439 menuBar.notebookEditAction.setEnabled(true);
1440 menuBar.notebookDeleteAction.setEnabled(true);
1441 menuBar.notebookPublishAction.setEnabled(true);
1442 menuBar.notebookShareAction.setEnabled(true);
1443 menuBar.notebookIconAction.setEnabled(true);
1444 menuBar.notebookStackAction.setEnabled(true);
1445 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1446 selectedNotebookGUIDs.clear();
1448 String stackName = "";
1449 if (selections.size() > 0) {
1450 guid = (selections.get(0).text(2));
1451 stackName = selections.get(0).text(0);
1453 if (!Global.mimicEvernoteInterface) {
1454 // If no notebooks are selected, we make it look like the "all notebooks" one was selected
1455 if (selections.size()==0) {
1456 selectedNotebookGUIDs.clear();
1457 for (int i=0; i < listManager.getNotebookIndex().size(); i++) {
1458 selectedNotebookGUIDs.add(listManager.getNotebookIndex().get(i).getGuid());
1460 menuBar.notebookEditAction.setEnabled(false);
1461 menuBar.notebookDeleteAction.setEnabled(false);
1462 menuBar.notebookStackAction.setEnabled(false);
1463 menuBar.notebookIconAction.setEnabled(false);
1466 if (!guid.equals("") && !guid.equals("STACK")) {
1467 selectedNotebookGUIDs.add(guid);
1468 menuBar.notebookIconAction.setEnabled(true);
1470 menuBar.notebookIconAction.setEnabled(true);
1471 for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1472 Notebook book = listManager.getNotebookIndex().get(j);
1473 if (book.getStack() != null && book.getStack().equalsIgnoreCase(stackName))
1474 selectedNotebookGUIDs.add(book.getGuid());
1477 listManager.setSelectedNotebooks(selectedNotebookGUIDs);
1478 listManager.loadNotesIndex();
1479 noteIndexUpdated(false);
1480 refreshEvernoteNote(true);
1481 listManager.refreshCounters = true;
1482 listManager.refreshCounters();
1483 if (selectedNotebookGUIDs.size() == 1) {
1484 int col = conn.getNotebookTable().getSortColumn(selectedNotebookGUIDs.get(0));
1485 int order = conn.getNotebookTable().getSortOrder(selectedNotebookGUIDs.get(0));
1487 noteTableView.proxyModel.blocked = true;
1489 noteTableView.sortByColumn(col, Qt.SortOrder.DescendingOrder);
1491 noteTableView.sortByColumn(col, Qt.SortOrder.AscendingOrder);
1494 noteTableView.proxyModel.blocked = false;
1495 logger.log(logger.HIGH, "Leaving NeverNote.notebookTreeSelection");
1498 private void clearNotebookFilter() {
1499 notebookTree.blockSignals(true);
1500 notebookTree.clearSelection();
1501 menuBar.noteRestoreAction.setVisible(false);
1502 menuBar.notebookEditAction.setEnabled(false);
1503 menuBar.notebookDeleteAction.setEnabled(false);
1504 selectedNotebookGUIDs.clear();
1505 listManager.setSelectedNotebooks(selectedNotebookGUIDs);
1506 notebookTree.blockSignals(false);
1508 // Triggered when the notebook DB has been updated
1509 private void notebookIndexUpdated() {
1510 logger.log(logger.HIGH, "Entering NeverNote.notebookIndexUpdated");
1512 // Get the possible icons
1513 HashMap<String, QIcon> icons = conn.getNotebookTable().getAllIcons();
1514 notebookTree.setIcons(icons);
1516 if (selectedNotebookGUIDs == null)
1517 selectedNotebookGUIDs = new ArrayList<String>();
1518 List<Notebook> books = conn.getNotebookTable().getAll();
1519 for (int i=books.size()-1; i>=0; i--) {
1520 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
1521 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(books.get(i).getGuid())) {
1523 j=listManager.getArchiveNotebookIndex().size();
1529 listManager.countNotebookResults(listManager.getNoteIndex());
1530 notebookTree.blockSignals(true);
1531 notebookTree.load(books, listManager.getLocalNotebooks());
1532 for (int i=selectedNotebookGUIDs.size()-1; i>=0; i--) {
1533 boolean found = notebookTree.selectGuid(selectedNotebookGUIDs.get(i));
1535 selectedNotebookGUIDs.remove(i);
1537 listManager.refreshCounters = true;
1538 listManager.refreshCounters();
1539 notebookTree.blockSignals(false);
1541 logger.log(logger.HIGH, "Leaving NeverNote.notebookIndexUpdated");
1543 // Show/Hide note information
1544 @SuppressWarnings("unused")
1545 private void toggleNotebookWindow() {
1546 logger.log(logger.HIGH, "Entering NeverNote.toggleNotebookWindow");
1547 searchLayout.toggleNotebook();
1548 menuBar.hideNotebooks.setChecked(notebookTree.isVisible());
1549 Global.saveWindowVisible("notebookTree", notebookTree.isVisible());
1550 logger.log(logger.HIGH, "Leaving NeverNote.toggleNotebookWindow");
1552 // Add a new notebook
1553 @SuppressWarnings("unused")
1554 private void addNotebook() {
1555 logger.log(logger.HIGH, "Inside NeverNote.addNotebook");
1556 NotebookEdit edit = new NotebookEdit();
1557 edit.setNotebooks(listManager.getNotebookIndex());
1560 if (!edit.okPressed())
1563 Calendar currentTime = new GregorianCalendar();
1564 Long l = new Long(currentTime.getTimeInMillis());
1565 String randint = new String(Long.toString(l));
1567 Notebook newBook = new Notebook();
1568 newBook.setUpdateSequenceNum(0);
1569 newBook.setGuid(randint);
1570 newBook.setName(edit.getNotebook());
1571 newBook.setServiceCreated(new Date().getTime());
1572 newBook.setServiceUpdated(new Date().getTime());
1573 newBook.setDefaultNotebook(false);
1574 newBook.setPublished(false);
1576 listManager.getNotebookIndex().add(newBook);
1578 listManager.getLocalNotebooks().add(newBook.getGuid());
1579 conn.getNotebookTable().addNotebook(newBook, true, edit.isLocal());
1580 notebookIndexUpdated();
1581 listManager.countNotebookResults(listManager.getNoteIndex());
1582 // notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
1583 logger.log(logger.HIGH, "Leaving NeverNote.addNotebook");
1585 // Edit an existing notebook
1586 @SuppressWarnings("unused")
1587 private void stackNotebook() {
1588 logger.log(logger.HIGH, "Entering NeverNote.stackNotebook");
1589 StackNotebook edit = new StackNotebook();
1591 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1592 QTreeWidgetItem currentSelection;
1593 for (int i=0; i<selections.size(); i++) {
1594 currentSelection = selections.get(0);
1595 String guid = currentSelection.text(2);
1596 if (guid.equalsIgnoreCase("")) {
1597 QMessageBox.critical(this, tr("Unable To Stack") ,tr("You can't stack the \"All Notebooks\" item."));
1600 if (guid.equalsIgnoreCase("STACK")) {
1601 QMessageBox.critical(this, tr("Unable To Stack") ,tr("You can't stack a stack."));
1606 edit.setStackNames(conn.getNotebookTable().getAllStackNames());
1611 if (!edit.okPressed())
1614 String stack = edit.getStackName();
1616 for (int i=0; i<selections.size(); i++) {
1617 currentSelection = selections.get(i);
1618 String guid = currentSelection.text(2);
1619 listManager.updateNotebookStack(guid, stack);
1621 notebookIndexUpdated();
1622 logger.log(logger.HIGH, "Leaving NeverNote.stackNotebook");
1624 // Edit an existing notebook
1625 @SuppressWarnings("unused")
1626 private void editNotebook() {
1627 logger.log(logger.HIGH, "Entering NeverNote.editNotebook");
1628 NotebookEdit edit = new NotebookEdit();
1630 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1631 QTreeWidgetItem currentSelection;
1632 currentSelection = selections.get(0);
1633 edit.setNotebook(currentSelection.text(0));
1635 String guid = currentSelection.text(2);
1636 if (!guid.equalsIgnoreCase("STACK")) {
1637 edit.setTitle(tr("Edit Notebook"));
1638 edit.setNotebooks(listManager.getNotebookIndex());
1639 edit.setLocalCheckboxEnabled(false);
1640 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1641 if (listManager.getNotebookIndex().get(i).getGuid().equals(guid)) {
1642 edit.setDefaultNotebook(listManager.getNotebookIndex().get(i).isDefaultNotebook());
1643 i=listManager.getNotebookIndex().size();
1647 edit.setTitle(tr("Edit Stack"));
1648 edit.setStacks(conn.getNotebookTable().getAllStackNames());
1649 edit.hideLocalCheckbox();
1650 edit.hideDefaultCheckbox();
1655 if (!edit.okPressed())
1659 if (guid.equalsIgnoreCase("STACK")) {
1660 conn.getNotebookTable().renameStacks(currentSelection.text(0), edit.getNotebook());
1661 for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1662 if (listManager.getNotebookIndex().get(j).getStack() != null &&
1663 listManager.getNotebookIndex().get(j).getStack().equalsIgnoreCase(currentSelection.text(0)))
1664 listManager.getNotebookIndex().get(j).setStack(edit.getNotebook());
1666 conn.getNotebookTable().renameStacks(currentSelection.text(0), edit.getNotebook());
1667 currentSelection.setText(0, edit.getNotebook());
1671 updateListNotebookName(currentSelection.text(0), edit.getNotebook());
1672 currentSelection.setText(0, edit.getNotebook());
1674 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1675 if (listManager.getNotebookIndex().get(i).getGuid().equals(guid)) {
1676 listManager.getNotebookIndex().get(i).setName(edit.getNotebook());
1677 if (!listManager.getNotebookIndex().get(i).isDefaultNotebook() && edit.isDefaultNotebook()) {
1678 for (int j=0; j<listManager.getNotebookIndex().size(); j++)
1679 listManager.getNotebookIndex().get(j).setDefaultNotebook(false);
1680 listManager.getNotebookIndex().get(i).setDefaultNotebook(true);
1681 conn.getNotebookTable().setDefaultNotebook(listManager.getNotebookIndex().get(i).getGuid());
1683 conn.getNotebookTable().updateNotebook(listManager.getNotebookIndex().get(i), true);
1684 if (conn.getNotebookTable().isLinked(listManager.getNotebookIndex().get(i).getGuid())) {
1685 LinkedNotebook linkedNotebook = conn.getLinkedNotebookTable().getByNotebookGuid(listManager.getNotebookIndex().get(i).getGuid());
1686 linkedNotebook.setShareName(edit.getNotebook());
1687 conn.getLinkedNotebookTable().updateNotebook(linkedNotebook, true);
1689 i=listManager.getNotebookIndex().size();
1693 // Build a list of non-closed notebooks
1694 List<Notebook> nbooks = new ArrayList<Notebook>();
1695 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1696 boolean found=false;
1697 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
1698 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid()))
1702 nbooks.add(listManager.getNotebookIndex().get(i));
1706 FilterEditorNotebooks notebookFilter = new FilterEditorNotebooks(conn, logger);
1707 List<Notebook> filteredBooks = notebookFilter.getValidNotebooks(currentNote, listManager.getNotebookIndex());
1708 browserWindow.setNotebookList(filteredBooks);
1709 Iterator<String> set = externalWindows.keySet().iterator();
1710 while(set.hasNext())
1711 externalWindows.get(set.next()).getBrowserWindow().setNotebookList(filteredBooks);
1712 logger.log(logger.HIGH, "Leaving NeverNote.editNotebook");
1714 // Publish a notebook
1715 @SuppressWarnings("unused")
1716 private void publishNotebook() {
1717 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1718 QTreeWidgetItem currentSelection;
1719 currentSelection = selections.get(0);
1720 String guid = currentSelection.text(2);
1722 if (guid.equalsIgnoreCase("STACK") || guid.equalsIgnoreCase(""))
1727 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1728 if (guid.equals(listManager.getNotebookIndex().get(i).getGuid())) {
1729 n = listManager.getNotebookIndex().get(i);
1731 i = listManager.getNotebookIndex().size();
1737 PublishNotebook publish = new PublishNotebook(Global.username, Global.getServer(), n);
1740 if (!publish.okClicked())
1743 Publishing p = publish.getPublishing();
1744 boolean isPublished = !publish.isStopPressed();
1745 conn.getNotebookTable().setPublishing(n.getGuid(), isPublished, p);
1746 n.setPublished(isPublished);
1748 listManager.getNotebookIndex().set(position, n);
1749 notebookIndexUpdated();
1751 // Publish a notebook
1752 @SuppressWarnings("unused")
1753 private void shareNotebook() {
1754 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1755 QTreeWidgetItem currentSelection;
1756 currentSelection = selections.get(0);
1757 String guid = currentSelection.text(2);
1759 if (guid.equalsIgnoreCase("STACK") || guid.equalsIgnoreCase(""))
1763 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1764 if (guid.equals(listManager.getNotebookIndex().get(i).getGuid())) {
1765 n = listManager.getNotebookIndex().get(i);
1766 i = listManager.getNotebookIndex().size();
1770 String authToken = null;
1771 if (syncRunner.isConnected)
1772 authToken = syncRunner.authToken;
1773 ShareNotebook share = new ShareNotebook(n.getName(), conn, n, syncRunner);
1778 // Delete an existing notebook
1779 @SuppressWarnings("unused")
1780 private void deleteNotebook() {
1781 logger.log(logger.HIGH, "Entering NeverNote.deleteNotebook");
1782 boolean stacksFound = false;
1783 boolean notebooksFound = false;
1784 boolean assigned = false;
1785 // Check if any notes have this notebook
1786 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1787 for (int i=0; i<selections.size(); i++) {
1788 QTreeWidgetItem currentSelection;
1789 currentSelection = selections.get(i);
1790 String guid = currentSelection.text(2);
1791 if (!guid.equalsIgnoreCase("STACK")) {
1792 notebooksFound = true;
1793 for (int j=0; j<listManager.getNoteIndex().size(); j++) {
1794 String noteGuid = listManager.getNoteIndex().get(j).getNotebookGuid();
1795 if (noteGuid.equals(guid)) {
1797 j=listManager.getNoteIndex().size();
1798 i=selections.size();
1806 QMessageBox.information(this, tr("Unable to Delete"), tr("Some of the selected notebook(s) contain notes.\n"+
1807 "Please delete the notes or move them to another notebook before deleting any notebooks."));
1811 if (conn.getNotebookTable().getAll().size() == 1) {
1812 QMessageBox.information(this, tr("Unable to Delete"), tr("You must have at least one notebook."));
1816 // If all notebooks are clear, verify the delete
1817 String msg1 = new String(tr("Delete selected notebooks?"));
1818 String msg2 = new String(tr("Remove selected stacks (notebooks will not be deleted)?"));
1819 String msg3 = new String(tr("Delete selected notebooks & remove stacks? Notebooks under the stacks are" +
1820 " not deleted unless selected?"));
1822 if (stacksFound && notebooksFound)
1824 if (!stacksFound && notebooksFound)
1826 if (stacksFound && !notebooksFound)
1828 if (QMessageBox.question(this, tr("Confirmation"), msg,
1829 QMessageBox.StandardButton.Yes,
1830 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
1834 // If confirmed, delete the notebook
1835 for (int i=selections.size()-1; i>=0; i--) {
1836 QTreeWidgetItem currentSelection;
1837 currentSelection = selections.get(i);
1838 String guid = currentSelection.text(2);
1839 if (currentSelection.text(2).equalsIgnoreCase("STACK")) {
1840 conn.getNotebookTable().renameStacks(currentSelection.text(0), "");
1841 listManager.renameStack(currentSelection.text(0), "");
1843 conn.getNotebookTable().expungeNotebook(guid, true);
1844 listManager.deleteNotebook(guid);
1848 notebookIndexUpdated();
1849 // notebookTreeSelection();
1850 // notebookTree.load(listManager.getNotebookIndex(), listManager.getLocalNotebooks());
1851 // listManager.countNotebookResults(listManager.getNoteIndex());
1852 logger.log(logger.HIGH, "Entering NeverNote.deleteNotebook");
1854 // A note's notebook has been updated
1855 @SuppressWarnings("unused")
1856 private void updateNoteNotebook(String guid, String notebookGuid) {
1858 // Update the list manager
1859 listManager.updateNoteNotebook(guid, notebookGuid);
1860 listManager.countNotebookResults(listManager.getNoteIndex());
1861 // notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
1863 // Find the name of the notebook
1864 String notebookName = null;
1865 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1866 if (listManager.getNotebookIndex().get(i).getGuid().equals(notebookGuid)) {
1867 notebookName = listManager.getNotebookIndex().get(i).getName();
1872 // If we found the name, update the browser window
1873 if (notebookName != null) {
1874 updateListNoteNotebook(guid, notebookName);
1875 if (guid.equals(currentNoteGuid)) {
1876 int pos = browserWindow.notebookBox.findText(notebookName);
1878 browserWindow.notebookBox.setCurrentIndex(pos);
1882 // If we're dealing with the current note, then we need to be sure and update the notebook there
1883 if (guid.equals(currentNoteGuid)) {
1884 if (currentNote != null) {
1885 currentNote.setNotebookGuid(notebookGuid);
1889 // Open/close notebooks
1890 @SuppressWarnings("unused")
1891 private void closeNotebooks() {
1892 NotebookArchive na = new NotebookArchive(listManager.getNotebookIndex(), listManager.getArchiveNotebookIndex());
1894 if (!na.okClicked())
1898 listManager.getArchiveNotebookIndex().clear();
1900 for (int i=na.getClosedBookList().count()-1; i>=0; i--) {
1901 String text = na.getClosedBookList().takeItem(i).text();
1902 for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1903 if (listManager.getNotebookIndex().get(j).getName().equalsIgnoreCase(text)) {
1904 Notebook n = listManager.getNotebookIndex().get(j);
1905 conn.getNotebookTable().setArchived(n.getGuid(),true);
1906 listManager.getArchiveNotebookIndex().add(n);
1907 j=listManager.getNotebookIndex().size();
1912 for (int i=na.getOpenBookList().count()-1; i>=0; i--) {
1913 String text = na.getOpenBookList().takeItem(i).text();
1914 for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1915 if (listManager.getNotebookIndex().get(j).getName().equalsIgnoreCase(text)) {
1916 Notebook n = listManager.getNotebookIndex().get(j);
1917 conn.getNotebookTable().setArchived(n.getGuid(),false);
1918 j=listManager.getNotebookIndex().size();
1922 notebookTreeSelection();
1923 listManager.loadNotesIndex();
1924 notebookIndexUpdated();
1925 noteIndexUpdated(false);
1926 reloadTagTree(true);
1927 // noteIndexUpdated(false);
1929 // Build a list of non-closed notebooks
1930 List<Notebook> nbooks = new ArrayList<Notebook>();
1931 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1932 boolean found=false;
1933 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
1934 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid()))
1938 nbooks.add(listManager.getNotebookIndex().get(i));
1941 FilterEditorNotebooks notebookFilter = new FilterEditorNotebooks(conn, logger);
1942 List<Notebook> filteredBooks = notebookFilter.getValidNotebooks(currentNote, listManager.getNotebookIndex());
1943 browserWindow.setNotebookList(filteredBooks);
1945 // Update any external windows
1946 Iterator<String> set = externalWindows.keySet().iterator();
1947 while(set.hasNext())
1948 externalWindows.get(set.next()).getBrowserWindow().setNotebookList(filteredBooks);
1952 // Change the notebook's icon
1953 @SuppressWarnings("unused")
1954 private void setNotebookIcon() {
1955 boolean stackSelected = false;
1956 boolean allNotebookSelected = false;
1958 QTreeWidgetItem currentSelection;
1959 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1960 if (selections.size() == 0)
1963 currentSelection = selections.get(0);
1964 String guid = currentSelection.text(2);
1965 if (guid.equalsIgnoreCase(""))
1966 allNotebookSelected = true;
1967 if (guid.equalsIgnoreCase("STACK"))
1968 stackSelected = true;
1970 QIcon currentIcon = currentSelection.icon(0);
1974 if (!stackSelected && !allNotebookSelected) {
1975 icon = conn.getNotebookTable().getIcon(guid);
1977 dialog = new SetIcon(currentIcon, saveLastPath);
1978 dialog.setUseDefaultIcon(true);
1980 dialog = new SetIcon(icon, saveLastPath);
1981 dialog.setUseDefaultIcon(false);
1984 if (stackSelected) {
1985 icon = conn.getSystemIconTable().getIcon(currentSelection.text(0), "STACK");
1987 icon = conn.getSystemIconTable().getIcon(currentSelection.text(0), "ALLNOTEBOOK");
1990 dialog = new SetIcon(currentIcon, saveLastPath);
1991 dialog.setUseDefaultIcon(true);
1993 dialog = new SetIcon(icon, saveLastPath);
1994 dialog.setUseDefaultIcon(false);
1998 if (dialog.okPressed()) {
1999 saveLastPath = dialog.getPath();
2001 QIcon newIcon = dialog.getIcon();
2002 if (stackSelected) {
2003 conn.getSystemIconTable().setIcon(currentSelection.text(0), "STACK", newIcon, dialog.getFileType());
2004 if (newIcon == null) {
2005 newIcon = new QIcon(iconPath+"books2.png");
2007 currentSelection.setIcon(0,newIcon);
2010 if (allNotebookSelected) {
2011 conn.getSystemIconTable().setIcon(currentSelection.text(0), "ALLNOTEBOOK", newIcon, dialog.getFileType());
2012 if (newIcon == null) {
2013 newIcon = new QIcon(iconPath+"notebook-green.png");
2015 currentSelection.setIcon(0,newIcon);
2018 conn.getNotebookTable().setIcon(guid, newIcon, dialog.getFileType());
2019 if (newIcon == null) {
2020 boolean isPublished = false;;
2021 boolean found = false;
2022 for (int i=0; i<listManager.getNotebookIndex().size() && !found; i++) {
2023 if (listManager.getNotebookIndex().get(i).getGuid().equals(guid)) {
2024 isPublished = listManager.getNotebookIndex().get(i).isPublished();
2028 newIcon = notebookTree.findDefaultIcon(guid, currentSelection.text(1), listManager.getLocalNotebooks(), isPublished);
2030 currentSelection.setIcon(0, newIcon);
2036 //***************************************************************
2037 //***************************************************************
2038 //** These functions deal with Tag menu items
2039 //***************************************************************
2040 //***************************************************************
2041 // Add a new notebook
2042 @SuppressWarnings("unused")
2043 private void addTag() {
2044 logger.log(logger.HIGH, "Inside NeverNote.addTag");
2045 TagEdit edit = new TagEdit();
2046 edit.setTagList(listManager.getTagIndex());
2048 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2049 QTreeWidgetItem currentSelection = null;
2050 if (selections.size() > 0) {
2051 currentSelection = selections.get(0);
2052 edit.setParentTag(currentSelection.text(0));
2057 if (!edit.okPressed())
2060 Calendar currentTime = new GregorianCalendar();
2061 Long l = new Long(currentTime.getTimeInMillis());
2062 String randint = new String(Long.toString(l));
2064 Tag newTag = new Tag();
2065 newTag.setUpdateSequenceNum(0);
2066 newTag.setGuid(randint);
2067 newTag.setName(edit.getTag());
2068 if (edit.getParentTag().isChecked()) {
2069 newTag.setParentGuid(currentSelection.text(2));
2070 newTag.setParentGuidIsSet(true);
2071 currentSelection.setExpanded(true);
2073 conn.getTagTable().addTag(newTag, true);
2074 listManager.getTagIndex().add(newTag);
2075 reloadTagTree(true);
2077 logger.log(logger.HIGH, "Leaving NeverNote.addTag");
2079 @SuppressWarnings("unused")
2080 private void reloadTagTree() {
2081 reloadTagTree(false);
2083 private void reloadTagTree(boolean reload) {
2084 logger.log(logger.HIGH, "Entering NeverNote.reloadTagTree");
2085 tagIndexUpdated(reload);
2086 boolean filter = false;
2088 listManager.countTagResults(listManager.getNoteIndex());
2089 if (notebookTree.selectedItems().size() > 0
2090 && !notebookTree.selectedItems().get(0).text(0).equalsIgnoreCase("All Notebooks"))
2092 if (tagTree.selectedItems().size() > 0)
2094 tagTree.showAllTags(!filter);
2095 tagIndexUpdated(false);
2096 logger.log(logger.HIGH, "Leaving NeverNote.reloadTagTree");
2098 // Edit an existing tag
2099 @SuppressWarnings("unused")
2100 private void editTag() {
2101 logger.log(logger.HIGH, "Entering NeverNote.editTag");
2102 TagEdit edit = new TagEdit();
2103 edit.setTitle("Edit Tag");
2104 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2105 QTreeWidgetItem currentSelection;
2106 currentSelection = selections.get(0);
2107 edit.setTag(currentSelection.text(0));
2108 edit.setTagList(listManager.getTagIndex());
2111 if (!edit.okPressed())
2114 String guid = currentSelection.text(2);
2115 currentSelection.setText(0,edit.getTag());
2117 for (int i=0; i<listManager.getTagIndex().size(); i++) {
2118 if (listManager.getTagIndex().get(i).getGuid().equals(guid)) {
2119 listManager.getTagIndex().get(i).setName(edit.getTag());
2120 conn.getTagTable().updateTag(listManager.getTagIndex().get(i), true);
2121 updateListTagName(guid);
2122 if (currentNote != null && currentNote.getTagGuids().contains(guid))
2123 browserWindow.setTag(getTagNamesForNote(currentNote));
2124 logger.log(logger.HIGH, "Leaving NeverNote.editTag");
2128 listManager.reloadNoteTagNames(guid, edit.getTag());
2129 noteIndexUpdated(true);
2130 refreshEvernoteNote(true);
2131 browserWindow.setTag(getTagNamesForNote(currentNote));
2132 logger.log(logger.HIGH, "Leaving NeverNote.editTag...");
2134 // Delete an existing tag
2135 @SuppressWarnings("unused")
2136 private void deleteTag() {
2137 logger.log(logger.HIGH, "Entering NeverNote.deleteTag");
2139 if (QMessageBox.question(this, tr("Confirmation"), tr("Delete the selected tags?"),
2140 QMessageBox.StandardButton.Yes,
2141 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
2145 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2146 for (int i=selections.size()-1; i>=0; i--) {
2147 QTreeWidgetItem currentSelection;
2148 currentSelection = selections.get(i);
2149 removeTagItem(currentSelection.text(2));
2151 tagIndexUpdated(true);
2153 listManager.countTagResults(listManager.getNoteIndex());
2154 // tagTree.updateCounts(listManager.getTagCounter());
2155 logger.log(logger.HIGH, "Leaving NeverNote.deleteTag");
2157 // Remove a tag tree item. Go recursively down & remove the children too
2158 private void removeTagItem(String guid) {
2159 for (int j=listManager.getTagIndex().size()-1; j>=0; j--) {
2160 String parent = listManager.getTagIndex().get(j).getParentGuid();
2161 if (parent != null && parent.equals(guid)) {
2162 //Remove this tag's children
2163 removeTagItem(listManager.getTagIndex().get(j).getGuid());
2166 //Now, remove this tag
2167 removeListTagName(guid);
2168 conn.getTagTable().expungeTag(guid, true);
2169 for (int a=0; a<listManager.getTagIndex().size(); a++) {
2170 if (listManager.getTagIndex().get(a).getGuid().equals(guid)) {
2171 listManager.getTagIndex().remove(a);
2176 // Setup the tree containing the user's tags
2177 private void initializeTagTree() {
2178 logger.log(logger.HIGH, "Entering NeverNote.initializeTagTree");
2179 // tagTree.itemSelectionChanged.connect(this, "tagTreeSelection()");
2180 // tagTree.itemClicked.connect(this, "tagTreeSelection()");
2181 tagTree.selectionSignal.connect(this, "tagTreeSelection()");
2182 listManager.tagSignal.refreshTagTreeCounts.connect(tagTree, "updateCounts(List)");
2183 logger.log(logger.HIGH, "Leaving NeverNote.initializeTagTree");
2185 // Listener when a tag is selected
2186 private void tagTreeSelection() {
2187 logger.log(logger.HIGH, "Entering NeverNote.tagTreeSelection");
2190 clearAttributeFilter();
2191 clearSavedSearchFilter();
2193 menuBar.noteRestoreAction.setVisible(false);
2195 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2196 QTreeWidgetItem currentSelection;
2197 selectedTagGUIDs.clear();
2198 for (int i=0; i<selections.size(); i++) {
2199 currentSelection = selections.get(i);
2200 selectedTagGUIDs.add(currentSelection.text(2));
2202 if (selections.size() > 0) {
2203 menuBar.tagEditAction.setEnabled(true);
2204 menuBar.tagDeleteAction.setEnabled(true);
2205 menuBar.tagIconAction.setEnabled(true);
2208 menuBar.tagEditAction.setEnabled(false);
2209 menuBar.tagDeleteAction.setEnabled(false);
2210 menuBar.tagIconAction.setEnabled(true);
2212 if (selections.size() > 1)
2213 menuBar.tagMergeAction.setEnabled(true);
2215 menuBar.tagMergeAction.setEnabled(false);
2216 listManager.setSelectedTags(selectedTagGUIDs);
2217 listManager.loadNotesIndex();
2218 noteIndexUpdated(false);
2219 refreshEvernoteNote(true);
2220 listManager.refreshCounters = true;
2221 listManager.refreshCounters();
2222 logger.log(logger.HIGH, "Leaving NeverNote.tagTreeSelection");
2224 // trigger the tag index to be refreshed
2225 @SuppressWarnings("unused")
2226 private void tagIndexUpdated() {
2227 tagIndexUpdated(true);
2229 private void tagIndexUpdated(boolean reload) {
2230 logger.log(logger.HIGH, "Entering NeverNote.tagIndexUpdated");
2231 if (selectedTagGUIDs == null)
2232 selectedTagGUIDs = new ArrayList<String>();
2234 listManager.reloadTagIndex();
2236 tagTree.blockSignals(true);
2238 tagTree.setIcons(conn.getTagTable().getAllIcons());
2239 tagTree.load(listManager.getTagIndex());
2242 for (int i=selectedTagGUIDs.size()-1; i>=0; i--) {
2243 boolean found = tagTree.selectGuid(selectedTagGUIDs.get(i));
2245 selectedTagGUIDs.remove(i);
2247 tagTree.blockSignals(false);
2249 browserWindow.setTag(getTagNamesForNote(currentNote));
2250 logger.log(logger.HIGH, "Leaving NeverNote.tagIndexUpdated");
2252 // Show/Hide note information
2253 @SuppressWarnings("unused")
2254 private void toggleTagWindow() {
2255 logger.log(logger.HIGH, "Entering NeverNote.toggleTagWindow");
2256 if (tagTree.isVisible())
2260 menuBar.hideTags.setChecked(tagTree.isVisible());
2261 Global.saveWindowVisible("tagTree", tagTree.isVisible());
2262 logger.log(logger.HIGH, "Leaving NeverNote.toggleTagWindow");
2264 // A note's tags have been updated
2265 @SuppressWarnings("unused")
2266 private void updateNoteTags(String guid, List<String> tags) {
2267 // Save any new tags. We'll need them later.
2268 List<String> newTags = new ArrayList<String>();
2269 for (int i=0; i<tags.size(); i++) {
2270 if (conn.getTagTable().findTagByName(tags.get(i))==null)
2271 newTags.add(tags.get(i));
2274 listManager.saveNoteTags(guid, tags);
2275 listManager.countTagResults(listManager.getNoteIndex());
2276 StringBuffer names = new StringBuffer("");
2277 for (int i=0; i<tags.size(); i++) {
2278 names = names.append(tags.get(i));
2279 if (i<tags.size()-1) {
2280 names.append(Global.tagDelimeter + " ");
2283 browserWindow.setTag(names.toString());
2286 // Now, we need to add any new tags to the tag tree
2287 for (int i=0; i<newTags.size(); i++)
2288 tagTree.insertTag(newTags.get(i), conn.getTagTable().findTagByName(newTags.get(i)));
2290 // Get a string containing all tag names for a note
2291 private String getTagNamesForNote(Note n) {
2292 logger.log(logger.HIGH, "Entering NeverNote.getTagNamesForNote");
2293 if (n==null || n.getGuid() == null || n.getGuid().equals(""))
2295 StringBuffer buffer = new StringBuffer(100);
2296 Vector<String> v = new Vector<String>();
2297 List<String> guids = n.getTagGuids();
2302 for (int i=0; i<guids.size(); i++) {
2303 v.add(listManager.getTagNameByGuid(guids.get(i)));
2305 Comparator<String> comparator = Collections.reverseOrder();
2306 Collections.sort(v,comparator);
2307 Collections.reverse(v);
2309 for (int i = 0; i<v.size(); i++) {
2311 buffer.append(", ");
2312 buffer.append(v.get(i));
2315 logger.log(logger.HIGH, "Leaving NeverNote.getTagNamesForNote");
2316 return buffer.toString();
2318 // Tags were added via dropping notes from the note list
2319 @SuppressWarnings("unused")
2320 private void tagsAdded(String noteGuid, String tagGuid) {
2321 String tagName = null;
2322 for (int i=0; i<listManager.getTagIndex().size(); i++) {
2323 if (listManager.getTagIndex().get(i).getGuid().equals(tagGuid)) {
2324 tagName = listManager.getTagIndex().get(i).getName();
2325 i=listManager.getTagIndex().size();
2328 if (tagName == null)
2331 for (int i=0; i<listManager.getMasterNoteIndex().size(); i++) {
2332 if (listManager.getMasterNoteIndex().get(i).getGuid().equals(noteGuid)) {
2333 List<String> tagNames = new ArrayList<String>();
2334 tagNames.add(new String(tagName));
2335 Note n = listManager.getMasterNoteIndex().get(i);
2336 for (int j=0; j<n.getTagNames().size(); j++) {
2337 tagNames.add(new String(n.getTagNames().get(j)));
2339 listManager.getNoteTableModel().updateNoteTags(noteGuid, n.getTagGuids(), tagNames);
2340 if (n.getGuid().equals(currentNoteGuid)) {
2341 Collections.sort(tagNames);
2342 String display = "";
2343 for (int j=0; j<tagNames.size(); j++) {
2344 display = display+tagNames.get(j);
2345 if (j+2<tagNames.size())
2346 display = display+Global.tagDelimeter+" ";
2348 browserWindow.setTag(display);
2350 i=listManager.getMasterNoteIndex().size();
2355 listManager.getNoteTableModel().updateNoteSyncStatus(noteGuid, false);
2357 private void clearTagFilter() {
2358 tagTree.blockSignals(true);
2359 tagTree.clearSelection();
2360 menuBar.noteRestoreAction.setVisible(false);
2361 menuBar.tagEditAction.setEnabled(false);
2362 menuBar.tagMergeAction.setEnabled(false);
2363 menuBar.tagDeleteAction.setEnabled(false);
2364 menuBar.tagIconAction.setEnabled(false);
2365 selectedTagGUIDs.clear();
2366 listManager.setSelectedTags(selectedTagGUIDs);
2367 tagTree.blockSignals(false);
2369 // Change the icon for a tag
2370 @SuppressWarnings("unused")
2371 private void setTagIcon() {
2372 QTreeWidgetItem currentSelection;
2373 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2374 if (selections.size() == 0)
2377 currentSelection = selections.get(0);
2378 String guid = currentSelection.text(2);
2380 QIcon currentIcon = currentSelection.icon(0);
2381 QIcon icon = conn.getTagTable().getIcon(guid);
2384 dialog = new SetIcon(currentIcon, saveLastPath);
2385 dialog.setUseDefaultIcon(true);
2387 dialog = new SetIcon(icon, saveLastPath);
2388 dialog.setUseDefaultIcon(false);
2391 if (dialog.okPressed()) {
2392 saveLastPath = dialog.getPath();
2393 QIcon newIcon = dialog.getIcon();
2394 conn.getTagTable().setIcon(guid, newIcon, dialog.getFileType());
2395 if (newIcon == null)
2396 newIcon = new QIcon(iconPath+"tag.png");
2397 currentSelection.setIcon(0, newIcon);
2402 @SuppressWarnings("unused")
2403 private void mergeTags() {
2404 List<Tag> tags = new ArrayList<Tag>();
2405 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2406 for (int i=0; i<selections.size(); i++) {
2407 Tag record = new Tag();
2408 record.setGuid(selections.get(i).text(2));
2409 record.setName(selections.get(i).text(0));
2413 TagMerge mergeDialog = new TagMerge(tags);
2415 if (!mergeDialog.okClicked())
2417 String newGuid = mergeDialog.getNewTagGuid();
2419 for (int i=0; i<tags.size(); i++) {
2420 if (!tags.get(i).getGuid().equals(newGuid)) {
2421 List<String> noteGuids = conn.getNoteTable().noteTagsTable.getTagNotes(tags.get(i).getGuid());
2422 for (int j=0; j<noteGuids.size(); j++) {
2423 String noteGuid = noteGuids.get(j);
2424 conn.getNoteTable().noteTagsTable.deleteNoteTag(noteGuid);
2425 if (!conn.getNoteTable().noteTagsTable.checkNoteNoteTags(noteGuid, newGuid))
2426 conn.getNoteTable().noteTagsTable.saveNoteTag(noteGuid, newGuid);
2430 listManager.reloadIndexes();
2433 //***************************************************************
2434 //***************************************************************
2435 //** These functions deal with Saved Search menu items
2436 //***************************************************************
2437 //***************************************************************
2438 // Add a new notebook
2439 @SuppressWarnings("unused")
2440 private void addSavedSearch() {
2441 logger.log(logger.HIGH, "Inside NeverNote.addSavedSearch");
2442 SavedSearchEdit edit = new SavedSearchEdit();
2443 edit.setSearchList(listManager.getSavedSearchIndex());
2446 if (!edit.okPressed())
2449 Calendar currentTime = new GregorianCalendar();
2450 Long l = new Long(currentTime.getTimeInMillis());
2451 String randint = new String(Long.toString(l));
2453 SavedSearch search = new SavedSearch();
2454 search.setUpdateSequenceNum(0);
2455 search.setGuid(randint);
2456 search.setName(edit.getName());
2457 search.setQuery(edit.getQuery());
2458 search.setFormat(QueryFormat.USER);
2459 listManager.getSavedSearchIndex().add(search);
2460 conn.getSavedSearchTable().addSavedSearch(search, true);
2461 savedSearchIndexUpdated();
2462 logger.log(logger.HIGH, "Leaving NeverNote.addSavedSearch");
2464 // Edit an existing tag
2465 @SuppressWarnings("unused")
2466 private void editSavedSearch() {
2467 logger.log(logger.HIGH, "Entering NeverNote.editSavedSearch");
2468 SavedSearchEdit edit = new SavedSearchEdit();
2469 edit.setTitle(tr("Edit Search"));
2470 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2471 QTreeWidgetItem currentSelection;
2472 currentSelection = selections.get(0);
2473 String guid = currentSelection.text(1);
2474 SavedSearch s = conn.getSavedSearchTable().getSavedSearch(guid);
2475 edit.setName(currentSelection.text(0));
2476 edit.setQuery(s.getQuery());
2477 edit.setSearchList(listManager.getSavedSearchIndex());
2480 if (!edit.okPressed())
2483 List<SavedSearch> list = listManager.getSavedSearchIndex();
2484 SavedSearch search = null;
2485 boolean found = false;
2486 for (int i=0; i<list.size(); i++) {
2487 search = list.get(i);
2488 if (search.getGuid().equals(guid)) {
2495 search.setName(edit.getName());
2496 search.setQuery(edit.getQuery());
2497 conn.getSavedSearchTable().updateSavedSearch(search, true);
2498 savedSearchIndexUpdated();
2499 logger.log(logger.HIGH, "Leaving NeverNote.editSavedSearch");
2501 // Delete an existing tag
2502 @SuppressWarnings("unused")
2503 private void deleteSavedSearch() {
2504 logger.log(logger.HIGH, "Entering NeverNote.deleteSavedSearch");
2506 if (QMessageBox.question(this, tr("Confirmation"), tr("Delete the selected search?"),
2507 QMessageBox.StandardButton.Yes,
2508 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
2512 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2513 for (int i=selections.size()-1; i>=0; i--) {
2514 QTreeWidgetItem currentSelection;
2515 currentSelection = selections.get(i);
2516 for (int j=0; j<listManager.getSavedSearchIndex().size(); j++) {
2517 if (listManager.getSavedSearchIndex().get(j).getGuid().equals(currentSelection.text(1))) {
2518 conn.getSavedSearchTable().expungeSavedSearch(listManager.getSavedSearchIndex().get(j).getGuid(), true);
2519 listManager.getSavedSearchIndex().remove(j);
2520 j=listManager.getSavedSearchIndex().size()+1;
2523 selections.remove(i);
2525 savedSearchIndexUpdated();
2526 logger.log(logger.HIGH, "Leaving NeverNote.deleteSavedSearch");
2528 // Setup the tree containing the user's tags
2529 private void initializeSavedSearchTree() {
2530 logger.log(logger.HIGH, "Entering NeverNote.initializeSavedSearchTree");
2531 savedSearchTree.itemSelectionChanged.connect(this, "savedSearchTreeSelection()");
2532 logger.log(logger.HIGH, "Leaving NeverNote.initializeSavedSearchTree");
2534 // Listener when a tag is selected
2535 @SuppressWarnings("unused")
2536 private void savedSearchTreeSelection() {
2537 logger.log(logger.HIGH, "Entering NeverNote.savedSearchTreeSelection");
2539 clearNotebookFilter();
2542 clearAttributeFilter();
2544 String currentGuid = selectedSavedSearchGUID;
2545 menuBar.savedSearchEditAction.setEnabled(true);
2546 menuBar.savedSearchDeleteAction.setEnabled(true);
2547 menuBar.savedSearchIconAction.setEnabled(true);
2548 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2549 QTreeWidgetItem currentSelection;
2550 selectedSavedSearchGUID = "";
2551 for (int i=0; i<selections.size(); i++) {
2552 currentSelection = selections.get(i);
2553 if (currentSelection.text(1).equals(currentGuid)) {
2554 currentSelection.setSelected(false);
2556 selectedSavedSearchGUID = currentSelection.text(1);
2558 // i = selections.size() +1;
2561 // There is the potential for no notebooks to be selected if this
2562 // happens then we make it look like all notebooks were selecetd.
2563 // If that happens, just select the "all notebooks"
2564 if (selections.size()==0) {
2565 clearSavedSearchFilter();
2567 listManager.setSelectedSavedSearch(selectedSavedSearchGUID);
2569 logger.log(logger.HIGH, "Leaving NeverNote.savedSearchTreeSelection");
2571 private void clearSavedSearchFilter() {
2572 menuBar.savedSearchEditAction.setEnabled(false);
2573 menuBar.savedSearchDeleteAction.setEnabled(false);
2574 menuBar.savedSearchIconAction.setEnabled(false);
2575 savedSearchTree.blockSignals(true);
2576 savedSearchTree.clearSelection();
2577 savedSearchTree.blockSignals(false);
2578 selectedSavedSearchGUID = "";
2579 searchField.setEditText("");
2580 searchPerformed = false;
2581 listManager.setSelectedSavedSearch(selectedSavedSearchGUID);
2583 // trigger the tag index to be refreshed
2584 private void savedSearchIndexUpdated() {
2585 if (selectedSavedSearchGUID == null)
2586 selectedSavedSearchGUID = new String();
2587 savedSearchTree.blockSignals(true);
2588 savedSearchTree.setIcons(conn.getSavedSearchTable().getAllIcons());
2589 savedSearchTree.load(listManager.getSavedSearchIndex());
2590 savedSearchTree.selectGuid(selectedSavedSearchGUID);
2591 savedSearchTree.blockSignals(false);
2593 // trigger when the saved search selection changes
2594 @SuppressWarnings("unused")
2595 private void updateSavedSearchSelection() {
2596 logger.log(logger.HIGH, "Entering NeverNote.updateSavedSearchSelection()");
2598 menuBar.savedSearchEditAction.setEnabled(true);
2599 menuBar.savedSearchDeleteAction.setEnabled(true);
2600 menuBar.savedSearchIconAction.setEnabled(true);
2601 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2603 if (selections.size() > 0) {
2604 menuBar.savedSearchEditAction.setEnabled(true);
2605 menuBar.savedSearchDeleteAction.setEnabled(true);
2606 menuBar.savedSearchIconAction.setEnabled(true);
2607 selectedSavedSearchGUID = selections.get(0).text(1);
2608 SavedSearch s = conn.getSavedSearchTable().getSavedSearch(selectedSavedSearchGUID);
2609 searchField.setEditText(s.getQuery());
2611 menuBar.savedSearchEditAction.setEnabled(false);
2612 menuBar.savedSearchDeleteAction.setEnabled(false);
2613 menuBar.savedSearchIconAction.setEnabled(false);
2614 selectedSavedSearchGUID = "";
2615 searchField.setEditText("");
2617 searchFieldChanged();
2619 logger.log(logger.HIGH, "Leaving NeverNote.updateSavedSearchSelection()");
2623 // Show/Hide note information
2624 @SuppressWarnings("unused")
2625 private void toggleSavedSearchWindow() {
2626 logger.log(logger.HIGH, "Entering NeverNote.toggleSavedSearchWindow");
2627 if (savedSearchTree.isVisible())
2628 savedSearchTree.hide();
2630 savedSearchTree.show();
2631 menuBar.hideSavedSearches.setChecked(savedSearchTree.isVisible());
2633 Global.saveWindowVisible("savedSearchTree", savedSearchTree.isVisible());
2634 logger.log(logger.HIGH, "Leaving NeverNote.toggleSavedSearchWindow");
2636 // Change the icon for a saved search
2637 @SuppressWarnings("unused")
2638 private void setSavedSearchIcon() {
2639 QTreeWidgetItem currentSelection;
2640 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2641 if (selections.size() == 0)
2644 currentSelection = selections.get(0);
2645 String guid = currentSelection.text(1);
2647 QIcon currentIcon = currentSelection.icon(0);
2648 QIcon icon = conn.getSavedSearchTable().getIcon(guid);
2651 dialog = new SetIcon(currentIcon, saveLastPath);
2652 dialog.setUseDefaultIcon(true);
2654 dialog = new SetIcon(icon, saveLastPath);
2655 dialog.setUseDefaultIcon(false);
2658 if (dialog.okPressed()) {
2659 saveLastPath = dialog.getPath();
2660 QIcon newIcon = dialog.getIcon();
2661 conn.getSavedSearchTable().setIcon(guid, newIcon, dialog.getFileType());
2662 if (newIcon == null)
2663 newIcon = new QIcon(iconPath+"search.png");
2664 currentSelection.setIcon(0, newIcon);
2672 //***************************************************************
2673 //***************************************************************
2674 //** These functions deal with Help menu & tool menu items
2675 //***************************************************************
2676 //***************************************************************
2677 // Show database status
2678 @SuppressWarnings("unused")
2679 private void databaseStatus() {
2681 indexRunner.interrupt = true;
2682 int dirty = conn.getNoteTable().getDirtyCount();
2683 int unindexed = conn.getNoteTable().getUnindexedCount();
2684 DatabaseStatus status = new DatabaseStatus();
2685 status.setUnsynchronized(dirty);
2686 status.setUnindexed(unindexed);
2687 status.setNoteCount(conn.getNoteTable().getNoteCount());
2688 status.setNotebookCount(listManager.getNotebookIndex().size());
2689 status.setUnindexedResourceCount(conn.getNoteTable().noteResourceTable.getUnindexedCount());
2690 status.setSavedSearchCount(listManager.getSavedSearchIndex().size());
2691 status.setTagCount(listManager.getTagIndex().size());
2692 status.setResourceCount(conn.getNoteTable().noteResourceTable.getResourceCount());
2693 status.setWordCount(conn.getWordsTable().getWordCount());
2697 // Compact the database
2698 @SuppressWarnings("unused")
2699 private void compactDatabase() {
2700 logger.log(logger.HIGH, "Entering NeverNote.compactDatabase");
2701 if (QMessageBox.question(this, tr("Confirmation"), tr("This will free unused space in the database, "+
2702 "but please be aware that depending upon the size of your database this can be time consuming " +
2703 "and NixNote will be unresponsive until it is complete. Do you wish to continue?"),
2704 QMessageBox.StandardButton.Yes,
2705 QMessageBox.StandardButton.No)==StandardButton.No.value() && Global.verifyDelete() == true) {
2708 setMessage("Compacting database.");
2710 listManager.compactDatabase();
2712 setMessage("Database compact is complete.");
2713 logger.log(logger.HIGH, "Leaving NeverNote.compactDatabase");
2715 @SuppressWarnings("unused")
2716 private void accountInformation() {
2717 logger.log(logger.HIGH, "Entering NeverNote.accountInformation");
2718 AccountDialog dialog = new AccountDialog();
2720 logger.log(logger.HIGH, "Leaving NeverNote.accountInformation");
2722 @SuppressWarnings("unused")
2723 private void releaseNotes() {
2724 logger.log(logger.HIGH, "Entering NeverNote.releaseNotes");
2725 QDialog dialog = new QDialog(this);
2726 QHBoxLayout layout = new QHBoxLayout();
2727 QTextEdit textBox = new QTextEdit();
2728 layout.addWidget(textBox);
2729 textBox.setReadOnly(true);
2730 QFile file = new QFile(Global.getFileManager().getProgramDirPath("release.txt"));
2731 if (!file.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly,
2732 QIODevice.OpenModeFlag.Text)))
2734 textBox.setText(file.readAll().toString());
2736 dialog.setWindowTitle(tr("Release Notes"));
2737 dialog.setLayout(layout);
2739 logger.log(logger.HIGH, "Leaving NeverNote.releaseNotes");
2741 // Called when user picks Log from the help menu
2742 @SuppressWarnings("unused")
2743 private void logger() {
2744 logger.log(logger.HIGH, "Entering NeverNote.logger");
2745 LogFileDialog dialog = new LogFileDialog(emitLog);
2747 logger.log(logger.HIGH, "Leaving NeverNote.logger");
2749 // Menu option "help/about" was selected
2750 @SuppressWarnings("unused")
2751 private void about() {
2752 logger.log(logger.HIGH, "Entering NeverNote.about");
2753 QMessageBox.about(this,
2754 tr("About NixNote"),
2755 tr("<h4><center><b>NixNote</b></center></h4><hr><center>Version ")
2759 +"Open Source Evernote Client.<br><br>"
2760 +"Licensed under GPL v2. <br><hr><br>"
2761 +"</center>Evernote is copyright 2001-2012 by Evernote Corporation<br>"
2762 +"Jambi and QT are the licensed trademark of Nokia Corporation<br>"
2763 +"PDFRenderer is licened under the LGPL<br>"
2764 +"JTidy is copyrighted under the World Wide Web Consortium<br>"
2765 +"Apache Common Utilities licensed under the Apache License Version 2.0<br>"
2766 +"Jazzy is licened under the LGPL<br>"
2767 +"Java is a registered trademark of Oracle Corporation.<br><hr>"
2768 +"Special thanks to:<br>BitRock InstallBuilder for the Windows installer"
2769 +"<br>CodeCogs (www.codecogs.com) for the LaTeX image rendering."));
2770 logger.log(logger.HIGH, "Leaving NeverNote.about");
2772 // Hide the entire left hand side
2773 @SuppressWarnings("unused")
2774 private void toggleLeftSide() {
2777 hidden = !menuBar.hideLeftSide.isChecked();
2778 menuBar.hideLeftSide.setChecked(!hidden);
2781 leftSplitter1.setHidden(true);
2783 leftSplitter1.setHidden(false);
2785 Global.saveWindowVisible("leftPanel", hidden);
2788 public void checkForUpdates() {
2789 // Send off thread to check for a new version
2790 versionChecker = new QNetworkAccessManager(this);
2791 versionChecker.finished.connect(this, "upgradeFileRead(QNetworkReply)");
2792 QNetworkRequest request = new QNetworkRequest();
2793 request.setUrl(new QUrl(Global.getUpdatesAvailableUrl()));
2794 versionChecker.get(request);
2796 @SuppressWarnings("unused")
2797 private void upgradeFileRead(QNetworkReply reply) {
2798 if (!reply.isReadable())
2801 String winVersion = Global.version;
2802 String osxVersion = Global.version;
2803 String linuxVersion = Global.version;
2804 String linux64Version = Global.version;
2805 String version = Global.version;
2807 // Determine the versions available
2808 QByteArray data = reply.readLine();
2809 while (data != null && !reply.atEnd()) {
2810 String line = data.toString();
2812 if (line.contains(":"))
2813 lineVersion = line.substring(line.indexOf(":")+1).replace(" ", "").replace("\n", "");
2816 if (line.toLowerCase().contains("windows"))
2817 winVersion = lineVersion;
2818 else if (line.toLowerCase().contains("os-x"))
2819 osxVersion = lineVersion;
2820 else if (line.toLowerCase().contains("linux amd64"))
2821 linux64Version = lineVersion;
2822 else if (line.toLowerCase().contains("linux i386"))
2823 linuxVersion = lineVersion;
2824 else if (line.toLowerCase().contains("default"))
2825 version = lineVersion;
2827 // Read the next line
2828 data = reply.readLine();
2831 // Now we need to determine what system we are on.
2832 if (System.getProperty("os.name").toLowerCase().contains("windows"))
2833 version = winVersion;
2834 if (System.getProperty("os.name").toLowerCase().contains("mac os"))
2835 version = osxVersion;
2836 if (System.getProperty("os.name").toLowerCase().contains("Linux")) {
2837 if (System.getProperty("os.arch").contains("amd64") ||
2838 System.getProperty("os.arch").contains("x86_64"))
2839 version = linux64Version;
2841 version = linuxVersion;
2845 for (String validVersion : Global.validVersions) {
2846 if (version.equals(validVersion))
2850 UpgradeAvailableDialog dialog = new UpgradeAvailableDialog();
2852 if (dialog.remindMe())
2853 Global.setCheckVersionUpgrade(true);
2855 Global.setCheckVersionUpgrade(false);
2859 //***************************************************************
2860 //***************************************************************
2861 //** These functions deal with the Toolbar
2862 //***************************************************************
2863 //***************************************************************
2864 @SuppressWarnings("unused")
2865 private void focusSearch() {
2866 searchField.setFocus();
2869 // Text in the search bar has been cleared
2870 private void searchFieldCleared() {
2873 // This is done because we want to force a reload of
2874 // images. Some images we may want to highlight the text.
2875 readOnlyCache.clear();
2876 inkNoteCache.clear();
2878 QWebSettings.setMaximumPagesInCache(0);
2879 QWebSettings.setObjectCacheCapacities(0, 0, 0);
2881 searchField.setEditText("");
2882 saveNoteColumnPositions();
2883 saveNoteIndexWidth();
2884 noteIndexUpdated(true);
2885 if (currentNote == null && listManager.getNoteIndex().size() > 0) {
2886 currentNote = listManager.getNoteIndex().get(0);
2887 currentNoteGuid = currentNote.getGuid();
2889 refreshEvernoteNote(true);
2890 if (currentNote != null)
2891 loadNoteBrowserInformation(browserWindow, currentNoteGuid, currentNote);
2893 // text in the search bar changed. We only use this to tell if it was cleared,
2894 // otherwise we trigger off searchFieldChanged.
2895 @SuppressWarnings("unused")
2896 private void searchFieldTextChanged(String text) {
2897 QWebSettings.setMaximumPagesInCache(0);
2898 QWebSettings.setObjectCacheCapacities(0, 0, 0);
2900 if (text.trim().equals("")) {
2901 searchFieldCleared();
2902 if (searchPerformed) {
2904 // This is done because we want to force a reload of
2905 // images. Some images we may want to highlight the text.
2907 readOnlyCache.clear();
2908 inkNoteCache.clear();
2910 listManager.setEnSearch("");
2911 listManager.loadNotesIndex();
2912 refreshEvernoteNote(true);
2913 noteIndexUpdated(false);
2914 refreshEvernoteNote(true);
2916 searchPerformed = false;
2919 // Text in the toolbar has changed
2920 private void searchFieldChanged() {
2921 logger.log(logger.HIGH, "Entering NeverNote.searchFieldChanged");
2923 readOnlyCache.clear();
2924 inkNoteCache.clear();
2925 saveNoteColumnPositions();
2926 saveNoteIndexWidth();
2927 String text = searchField.currentText();
2928 listManager.setEnSearch(text.trim());
2929 listManager.loadNotesIndex();
2930 noteIndexUpdated(false);
2932 refreshEvernoteNote(true);
2933 searchPerformed = true;
2935 logger.log(logger.HIGH, "Leaving NeverNote.searchFieldChanged");
2938 // Build the window tool bar
2939 private void setupToolBar() {
2940 logger.log(logger.HIGH, "Entering NeverNote.setupToolBar");
2941 toolBar = addToolBar(tr("Tool Bar"));
2942 toolBar.setObjectName("toolBar");
2943 menuBar.setupToolBarVisible();
2944 if (!Global.isWindowVisible("toolBar"))
2945 toolBar.setVisible(false);
2947 toolBar.setVisible(true);
2949 // toolBar.addWidget(menuBar);
2950 // menuBar.setSizePolicy(Policy.Minimum, Policy.Minimum);
2951 // toolBar.addSeparator();
2952 prevButton = toolBar.addAction(tr("Previous"));
2953 QIcon prevIcon = new QIcon(iconPath+"back.png");
2954 prevButton.setIcon(prevIcon);
2955 prevButton.triggered.connect(this, "previousViewedAction()");
2956 togglePrevArrowButton(Global.isToolbarButtonVisible("prevArrow"));
2958 nextButton = toolBar.addAction(tr("Next"));
2959 QIcon nextIcon = new QIcon(iconPath+"forward.png");
2960 nextButton.setIcon(nextIcon);
2961 nextButton.triggered.connect(this, "nextViewedAction()");
2962 toggleNextArrowButton(Global.isToolbarButtonVisible("nextArrow"));
2964 upButton = toolBar.addAction(tr("Up"));
2965 QIcon upIcon = new QIcon(iconPath+"up.png");
2966 upButton.setIcon(upIcon);
2967 upButton.triggered.connect(this, "upAction()");
2968 toggleUpArrowButton(Global.isToolbarButtonVisible("upArrow"));
2971 downButton = toolBar.addAction(tr("Down"));
2972 QIcon downIcon = new QIcon(iconPath+"down.png");
2973 downButton.setIcon(downIcon);
2974 downButton.triggered.connect(this, "downAction()");
2975 toggleDownArrowButton(Global.isToolbarButtonVisible("downArrow"));
2977 synchronizeButton = toolBar.addAction(tr("Synchronize"));
2978 synchronizeButton.setIcon(new QIcon(iconPath+"synchronize.png"));
2979 synchronizeIconAngle = 0;
2980 synchronizeButton.triggered.connect(this, "evernoteSync()");
2981 toggleSynchronizeButton(Global.isToolbarButtonVisible("synchronize"));
2983 printButton = toolBar.addAction(tr("Print"));
2984 QIcon printIcon = new QIcon(iconPath+"print.png");
2985 printButton.setIcon(printIcon);
2986 printButton.triggered.connect(this, "printNote()");
2987 togglePrintButton(Global.isToolbarButtonVisible("print"));
2989 tagButton = toolBar.addAction(tr("Tag"));
2990 QIcon tagIcon = new QIcon(iconPath+"tag.png");
2991 tagButton.setIcon(tagIcon);
2992 tagButton.triggered.connect(browserWindow, "modifyTags()");
2993 toggleTagButton(Global.isToolbarButtonVisible("tag"));
2995 attributeButton = toolBar.addAction(tr("Attributes"));
2996 QIcon attributeIcon = new QIcon(iconPath+"attribute.png");
2997 attributeButton.setIcon(attributeIcon);
2998 attributeButton.triggered.connect(this, "toggleNoteInformation()");
2999 toggleAttributeButton(Global.isToolbarButtonVisible("attribute"));
3001 emailButton = toolBar.addAction(tr("Email"));
3002 QIcon emailIcon = new QIcon(iconPath+"email.png");
3003 emailButton.setIcon(emailIcon);
3004 emailButton.triggered.connect(this, "emailNote()");
3005 toggleEmailButton(Global.isToolbarButtonVisible("email"));
3007 deleteButton = toolBar.addAction(tr("Delete"));
3008 QIcon deleteIcon = new QIcon(iconPath+"delete.png");
3009 deleteButton.setIcon(deleteIcon);
3010 deleteButton.triggered.connect(this, "deleteNote()");
3011 toggleDeleteButton(Global.isToolbarButtonVisible("delete"));
3013 newButton = toolBar.addAction(tr("New"));
3014 QIcon newIcon = new QIcon(iconPath+"new.png");
3015 newButton.triggered.connect(this, "addNote()");
3016 newButton.setIcon(newIcon);
3017 toggleNewButton(Global.isToolbarButtonVisible("new"));
3019 allNotesButton = toolBar.addAction(tr("All Notes"));
3020 QIcon allIcon = new QIcon(iconPath+"books.png");
3021 allNotesButton.triggered.connect(this, "allNotes()");
3022 allNotesButton.setIcon(allIcon);
3023 toggleAllNotesButton(Global.isToolbarButtonVisible("allNotes"));
3025 //toolBar.addSeparator();
3026 //toolBar.addWidget(new QLabel(tr("Quota:")));
3027 //toolBar.addWidget(quotaBar);
3028 //quotaBar.setSizePolicy(Policy.Minimum, Policy.Minimum);
3030 //toolBar.addSeparator();
3032 //toolBar.addWidget(new QLabel(tr("Zoom")));
3033 //toolBar.addWidget(zoomSpinner);
3035 //toolBar.addWidget(new QLabel(" "));
3036 //toolBar.addSeparator();
3037 //toolBar.addWidget(new QLabel(tr(" Search:")));
3038 //toolBar.addWidget(searchField);
3039 QSizePolicy sizePolicy = new QSizePolicy();
3040 sizePolicy.setHorizontalPolicy(Policy.MinimumExpanding);
3041 QLabel spacer = new QLabel("");
3042 spacer.setSizePolicy(sizePolicy);
3043 toolBar.addWidget(spacer);
3044 //searchField.setInsertPolicy(InsertPolicy.InsertAtTop);
3046 //searchClearButton = toolBar.addAction("Search Clear");
3047 //QIcon searchClearIcon = new QIcon(iconPath+"searchclear.png");
3048 //searchClearButton.setIcon(searchClearIcon);
3049 //searchClearButton.triggered.connect(this, "searchFieldCleared()");
3050 //toggleSearchClearButton(Global.isToolbarButtonVisible("searchClear"));
3052 logger.log(logger.HIGH, "Leaving NeverNote.setupToolBar");
3054 // Update the sychronize button picture
3056 public QMenu createPopupMenu() {
3057 QMenu contextMenu = super.createPopupMenu();
3059 contextMenu.addSeparator();
3060 QAction prevAction = addContextAction("prevArrow", tr("Previous Arrow"));
3061 contextMenu.addAction(prevAction);
3062 prevAction.triggered.connect(this, "togglePrevArrowButton(Boolean)");
3064 QAction nextAction = addContextAction("nextArrow", tr("Next Arrow"));
3065 contextMenu.addAction(nextAction);
3066 nextAction.triggered.connect(this, "toggleNextArrowButton(Boolean)");
3068 QAction upAction = addContextAction("upArrow", tr("Up Arrow"));
3069 contextMenu.addAction(upAction);
3070 upAction.triggered.connect(this, "toggleUpArrowButton(Boolean)");
3072 QAction downAction = addContextAction("downArrow", tr("Down Arrow"));
3073 contextMenu.addAction(downAction);
3074 downAction.triggered.connect(this, "toggleDownArrowButton(Boolean)");
3076 QAction synchronizeAction = addContextAction("synchronize", tr("Synchronize"));
3077 contextMenu.addAction(synchronizeAction);
3078 synchronizeAction.triggered.connect(this, "toggleSynchronizeButton(Boolean)");
3080 QAction printAction = addContextAction("print", tr("Print"));
3081 contextMenu.addAction(printAction);
3082 printAction.triggered.connect(this, "togglePrintButton(Boolean)");
3084 QAction tagAction = addContextAction("tag", tr("Tag"));
3085 contextMenu.addAction(tagAction);
3086 tagAction.triggered.connect(this, "toggleTagButton(Boolean)");
3088 QAction attributeAction = addContextAction("attribute", tr("Attribute"));
3089 contextMenu.addAction(attributeAction);
3090 attributeAction.triggered.connect(this, "toggleAttributeButton(Boolean)");
3092 QAction emailAction = addContextAction("email", tr("Email"));
3093 contextMenu.addAction(emailAction);
3094 emailAction.triggered.connect(this, "toggleEmailButton(Boolean)");
3096 QAction deleteAction = addContextAction("delete", tr("Delete"));
3097 contextMenu.addAction(deleteAction);
3098 deleteAction.triggered.connect(this, "toggleDeleteButton(Boolean)");
3100 QAction newAction = addContextAction("new", tr("Add"));
3101 contextMenu.addAction(newAction);
3102 newAction.triggered.connect(this, "toggleNewButton(Boolean)");
3104 QAction allNotesAction = addContextAction("allNotes", tr("All Notes"));
3105 contextMenu.addAction(allNotesAction);
3106 allNotesAction.triggered.connect(this, "toggleAllNotesButton(Boolean)");
3108 QAction searchClearAction = addContextAction("searchClear", tr("Search Clear"));
3109 contextMenu.addAction(searchClearAction);
3110 searchClearAction.triggered.connect(this, "toggleSearchClearButton(Boolean)");
3115 private QAction addContextAction(String config, String name) {
3116 QAction newAction = new QAction(this);
3117 newAction.setText(name);
3118 newAction.setCheckable(true);
3119 newAction.setChecked(Global.isToolbarButtonVisible(config));
3122 private void togglePrevArrowButton(Boolean toggle) {
3123 prevButton.setVisible(toggle);
3124 Global.saveToolbarButtonsVisible("prevArrow", toggle);
3126 private void toggleNextArrowButton(Boolean toggle) {
3127 nextButton.setVisible(toggle);
3128 Global.saveToolbarButtonsVisible("nextArrow", toggle);
3130 private void toggleUpArrowButton(Boolean toggle) {
3131 upButton.setVisible(toggle);
3132 Global.saveToolbarButtonsVisible("upArrow", toggle);
3134 private void toggleDownArrowButton(Boolean toggle) {
3135 downButton.setVisible(toggle);
3136 Global.saveToolbarButtonsVisible("downArrow", toggle);
3138 private void toggleSynchronizeButton(Boolean toggle) {
3139 synchronizeButton.setVisible(toggle);
3140 Global.saveToolbarButtonsVisible("synchronize", toggle);
3142 private void togglePrintButton(Boolean toggle) {
3143 printButton.setVisible(toggle);
3144 Global.saveToolbarButtonsVisible("print", toggle);
3146 private void toggleTagButton(Boolean toggle) {
3147 tagButton.setVisible(toggle);
3148 Global.saveToolbarButtonsVisible("tag", toggle);
3150 private void toggleAttributeButton(Boolean toggle) {
3151 attributeButton.setVisible(toggle);
3152 Global.saveToolbarButtonsVisible("attribute", toggle);
3154 private void toggleEmailButton(Boolean toggle) {
3155 emailButton.setVisible(toggle);
3156 Global.saveToolbarButtonsVisible("email", toggle);
3158 private void toggleDeleteButton(Boolean toggle) {
3159 deleteButton.setVisible(toggle);
3160 Global.saveToolbarButtonsVisible("delete", toggle);
3162 private void toggleNewButton(Boolean toggle) {
3163 newButton.setVisible(toggle);
3164 Global.saveToolbarButtonsVisible("new", toggle);
3166 private void toggleAllNotesButton(Boolean toggle) {
3167 allNotesButton.setVisible(toggle);
3168 Global.saveToolbarButtonsVisible("allNotes", toggle);
3170 @SuppressWarnings("unused")
3171 private void toggleSearchClearButton(Boolean toggle) {
3172 searchClearButton.setVisible(toggle);
3173 Global.saveToolbarButtonsVisible("searchClear", toggle);
3180 @SuppressWarnings("unused")
3181 private void updateSyncButton() {
3183 if (syncIcons == null) {
3184 syncIcons = new ArrayList<QPixmap>();
3186 synchronizeIconAngle = 0;
3187 QPixmap pix = new QPixmap(iconPath+"synchronize.png");
3189 for (int i=0; i<=360; i++) {
3190 QPixmap rotatedPix = new QPixmap(pix.size());
3191 QPainter p = new QPainter(rotatedPix);
3192 rotatedPix.fill(toolBar.palette().color(ColorRole.Button));
3193 QSize size = pix.size();
3194 p.translate(size.width()/2, size.height()/2);
3197 p.setBackgroundMode(BGMode.OpaqueMode);
3198 p.translate(-size.width()/2, -size.height()/2);
3199 p.drawPixmap(0,0, pix);
3201 syncIcons.add(rotatedPix);
3205 synchronizeIconAngle++;
3206 if (synchronizeIconAngle > 359)
3207 synchronizeIconAngle=0;
3208 synchronizeButton.setIcon(syncIcons.get(synchronizeIconAngle));
3211 // Synchronize with Evernote
3213 private void evernoteSync() {
3214 logger.log(logger.HIGH, "Entering NeverNote.evernoteSync");
3215 if (!Global.isConnected)
3217 if (Global.isConnected)
3218 synchronizeAnimationTimer.start(5);
3219 // synchronizeAnimationTimer.start(200);
3221 logger.log(logger.HIGH, "Leaving NeverNote.evernoteSync");
3223 private void updateQuotaBar() {
3224 long limit = Global.getUploadLimit();
3225 long amount = Global.getUploadAmount();
3226 if (amount>0 && limit>0) {
3227 int percent =(int)(amount*100/limit);
3228 quotaBar.setValue(percent);
3230 quotaBar.setValue(0);
3233 @SuppressWarnings("unused")
3234 private void zoomChanged() {
3235 browserWindow.getBrowser().setZoomFactor(new Double(zoomSpinner.value())/100);
3238 //****************************************************************
3239 //****************************************************************
3240 //* System Tray functions
3241 //****************************************************************
3242 //****************************************************************
3243 private void trayToggleVisible() {
3248 if (windowMaximized)
3255 @SuppressWarnings("unused")
3256 private void trayActivated(QSystemTrayIcon.ActivationReason reason) {
3257 if (reason == QSystemTrayIcon.ActivationReason.DoubleClick) {
3258 String name = QSystemTrayIcon.MessageIcon.resolve(reason.value()).name();
3259 trayToggleVisible();
3264 //***************************************************************
3265 //***************************************************************
3266 //** These functions deal with the trash tree
3267 //***************************************************************
3268 //***************************************************************
3269 // Setup the tree containing the trash.
3270 @SuppressWarnings("unused")
3271 private void trashTreeSelection() {
3272 logger.log(logger.HIGH, "Entering NeverNote.trashTreeSelection");
3274 clearNotebookFilter();
3276 clearAttributeFilter();
3277 clearSavedSearchFilter();
3279 String tempGuid = currentNoteGuid;
3281 // currentNoteGuid = "";
3282 currentNote = new Note();
3283 selectedNoteGUIDs.clear();
3284 listManager.getSelectedNotebooks().clear();
3285 listManager.getSelectedTags().clear();
3286 listManager.setSelectedSavedSearch("");
3287 browserWindow.clear();
3289 // toggle the add buttons
3290 newButton.setEnabled(!newButton.isEnabled());
3291 menuBar.noteAdd.setEnabled(newButton.isEnabled());
3292 menuBar.noteAdd.setVisible(true);
3294 List<QTreeWidgetItem> selections = trashTree.selectedItems();
3295 if (selections.size() == 0) {
3296 currentNoteGuid = trashNoteGuid;
3297 trashNoteGuid = tempGuid;
3298 Global.showDeleted = false;
3299 menuBar.noteRestoreAction.setEnabled(false);
3300 menuBar.noteRestoreAction.setVisible(false);
3303 trashNoteGuid = tempGuid;
3304 currentNoteGuid = trashNoteGuid;
3305 menuBar.noteRestoreAction.setEnabled(true);
3306 menuBar.noteRestoreAction.setVisible(true);
3307 Global.showDeleted = true;
3309 listManager.loadNotesIndex();
3310 noteIndexUpdated(false);
3311 //// browserWindow.setEnabled(newButton.isEnabled());
3312 browserWindow.setReadOnly(!newButton.isEnabled());
3313 logger.log(logger.HIGH, "Leaving NeverNote.trashTreeSelection");
3315 // Empty the trash file
3316 @SuppressWarnings("unused")
3317 private void emptyTrash() {
3318 // browserWindow.clear();
3319 logger.log(logger.EXTREME, "Emptying Trash");
3320 listManager.emptyTrash();
3321 logger.log(logger.EXTREME, "Resetting view after trash empty");
3322 if (trashTree.selectedItems().size() > 0) {
3323 listManager.getSelectedNotebooks().clear();
3324 listManager.getSelectedTags().clear();
3325 listManager.setSelectedSavedSearch("");
3326 newButton.setEnabled(!newButton.isEnabled());
3327 menuBar.noteAdd.setEnabled(newButton.isEnabled());
3328 menuBar.noteAdd.setVisible(true);
3329 browserWindow.clear();
3332 clearNotebookFilter();
3333 clearSavedSearchFilter();
3334 clearAttributeFilter();
3336 Global.showDeleted = false;
3337 menuBar.noteRestoreAction.setEnabled(false);
3338 menuBar.noteRestoreAction.setVisible(false);
3340 listManager.loadNotesIndex();
3341 noteIndexUpdated(false);
3344 // Show/Hide trash window
3345 @SuppressWarnings("unused")
3346 private void toggleTrashWindow() {
3347 logger.log(logger.HIGH, "Entering NeverNote.toggleTrashWindow");
3348 if (trashTree.isVisible())
3352 menuBar.hideTrash.setChecked(trashTree.isVisible());
3354 Global.saveWindowVisible("trashTree", trashTree.isVisible());
3355 logger.log(logger.HIGH, "Leaving NeverNote.trashWindow");
3357 private void clearTrashFilter() {
3358 Global.showDeleted = false;
3359 newButton.setEnabled(true);
3360 menuBar.noteAdd.setEnabled(true);
3361 menuBar.noteAdd.setVisible(true);
3362 trashTree.blockSignals(true);
3363 trashTree.clearSelection();
3364 trashTree.blockSignals(false);
3369 //***************************************************************
3370 //***************************************************************
3371 //** These functions deal with connection settings
3372 //***************************************************************
3373 //***************************************************************
3374 // SyncRunner had a problem and things are disconnected
3375 @SuppressWarnings("unused")
3376 private void remoteErrorDisconnect() {
3377 menuBar.connectAction.setText(tr("Connect"));
3378 menuBar.connectAction.setToolTip(tr("Connect to Evernote"));
3379 menuBar.synchronizeAction.setEnabled(false);
3380 Global.isConnected = false;
3381 synchronizeAnimationTimer.stop();
3384 // Do a manual connect/disconnect
3385 private void remoteConnect() {
3387 logger.log(logger.HIGH, "Entering NeverNote.remoteConnect");
3389 // If we are already connected, we just disconnect
3390 if (Global.isConnected) {
3391 Global.isConnected = false;
3392 syncRunner.enDisconnect();
3393 setupConnectMenuOptions();
3398 OAuthTokenizer tokenizer = new OAuthTokenizer();
3399 AESEncrypter aes = new AESEncrypter();
3401 aes.decrypt(new FileInputStream(Global.getFileManager().getHomeDirFile("oauth.txt")));
3402 } catch (FileNotFoundException e) {
3403 // File not found, so we'll just get empty strings anyway.
3407 if (Global.getProxyValue("url").equals("")) {
3408 System.setProperty("http.proxyHost","") ;
3409 System.setProperty("http.proxyPort", "") ;
3410 System.setProperty("https.proxyHost","") ;
3411 System.setProperty("https.proxyPort", "") ;
3414 System.setProperty("http.proxyHost",Global.getProxyValue("url")) ;
3415 System.setProperty("http.proxyPort", Global.getProxyValue("port")) ;
3416 System.setProperty("https.proxyHost",Global.getProxyValue("url")) ;
3417 System.setProperty("https.proxyPort", Global.getProxyValue("port")) ;
3419 if (Global.getProxyValue("userid").equals("")) {
3420 Authenticator.setDefault(new Authenticator() {
3422 protected PasswordAuthentication getPasswordAuthentication() {
3424 PasswordAuthentication(Global.getProxyValue("userid"),Global.getProxyValue("password").toCharArray());
3430 syncRunner.userStoreUrl = Global.userStoreUrl;
3431 syncRunner.noteStoreUrl = Global.noteStoreUrl;
3432 syncRunner.noteStoreUrlBase = Global.noteStoreUrlBase;
3436 String authString = aes.getString();
3437 if (!authString.equals("")) {
3438 tokenizer.tokenize(authString);
3439 syncRunner.authToken = tokenizer.oauth_token;
3440 syncRunner.enConnect();
3443 Global.isConnected = syncRunner.isConnected;
3445 if (!Global.isConnected) {
3446 OAuthWindow window = new OAuthWindow(logger);
3448 setMessage(window.errorMessage);
3453 setMessage(window.errorMessage);
3456 tokenizer.tokenize(window.response);
3457 if (tokenizer.oauth_token.equals("")) {
3458 setMessage(tr("Invalid authorization token received."));
3461 aes.setString(window.response);
3463 aes.encrypt(new FileOutputStream(Global.getFileManager().getHomeDirFile("oauth.txt")));
3464 } catch (FileNotFoundException e) {
3465 // TODO Auto-generated catch block
3466 e.printStackTrace();
3468 syncRunner.authToken = tokenizer.oauth_token;
3469 syncRunner.enConnect();
3470 Global.isConnected = syncRunner.isConnected;
3472 Global.username = syncRunner.username;
3474 if (!Global.isConnected)
3477 setupConnectMenuOptions();
3478 logger.log(logger.HIGH, "Leaving NeverNote.remoteConnect");
3482 private void setupConnectMenuOptions() {
3483 logger.log(logger.HIGH, "entering NeverNote.setupConnectMenuOptions");
3484 if (!Global.isConnected) {
3485 menuBar.connectAction.setText(tr("Connect"));
3486 menuBar.connectAction.setToolTip(tr("Connect to Evernote"));
3487 menuBar.synchronizeAction.setEnabled(false);
3489 menuBar.connectAction.setText(tr("Disconnect"));
3490 menuBar.connectAction.setToolTip(tr("Disconnect from Evernote"));
3491 menuBar.synchronizeAction.setEnabled(true);
3493 logger.log(logger.HIGH, "Leaving NeverNote.setupConnectionMenuOptions");
3498 //***************************************************************
3499 //***************************************************************
3500 //** These functions deal with the GUI Attribute tree
3501 //***************************************************************
3502 //***************************************************************
3503 @SuppressWarnings("unused")
3504 private void attributeTreeClicked(QTreeWidgetItem item, Integer integer) {
3506 // clearTagFilter();
3507 // clearNotebookFilter();
3509 // clearSavedSearchFilter();
3511 if (attributeTreeSelected == null || item.nativeId() != attributeTreeSelected.nativeId()) {
3512 if (item.childCount() > 0) {
3513 item.setSelected(false);
3515 Global.createdBeforeFilter.reset();
3516 Global.createdSinceFilter.reset();
3517 Global.changedBeforeFilter.reset();
3518 Global.changedSinceFilter.reset();
3519 Global.containsFilter.reset();
3520 attributeTreeSelected = item;
3521 DateAttributeFilterTable f = null;
3522 f = findDateAttributeFilterTable(item.parent());
3524 f.select(item.parent().indexOfChild(item));
3526 Global.containsFilter.select(item.parent().indexOfChild(item));
3529 listManager.loadNotesIndex();
3530 noteIndexUpdated(false);
3533 attributeTreeSelected = null;
3534 item.setSelected(false);
3535 Global.createdBeforeFilter.reset();
3536 Global.createdSinceFilter.reset();
3537 Global.changedBeforeFilter.reset();
3538 Global.changedSinceFilter.reset();
3539 Global.containsFilter.reset();
3540 listManager.loadNotesIndex();
3541 noteIndexUpdated(false);
3543 // This determines what attribute filter we need, depending upon the selection
3544 private DateAttributeFilterTable findDateAttributeFilterTable(QTreeWidgetItem w) {
3545 if (w.parent() != null && w.childCount() > 0) {
3546 QTreeWidgetItem parent = w.parent();
3547 if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Created &&
3548 w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Since)
3549 return Global.createdSinceFilter;
3550 if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Created &&
3551 w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Before)
3552 return Global.createdBeforeFilter;
3553 if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.LastModified &&
3554 w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Since)
3555 return Global.changedSinceFilter;
3556 if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.LastModified &&
3557 w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Before)
3558 return Global.changedBeforeFilter;
3563 // Show/Hide attribute search window
3564 @SuppressWarnings("unused")
3565 private void toggleAttributesWindow() {
3566 logger.log(logger.HIGH, "Entering NeverNote.toggleAttributesWindow");
3567 if (attributeTree.isVisible())
3568 attributeTree.hide();
3570 attributeTree.show();
3571 menuBar.hideAttributes.setChecked(attributeTree.isVisible());
3573 Global.saveWindowVisible("attributeTree", attributeTree.isVisible());
3574 logger.log(logger.HIGH, "Leaving NeverNote.toggleAttributeWindow");
3576 private void clearAttributeFilter() {
3577 Global.createdBeforeFilter.reset();
3578 Global.createdSinceFilter.reset();
3579 Global.changedBeforeFilter.reset();
3580 Global.changedSinceFilter.reset();
3581 Global.containsFilter.reset();
3582 attributeTreeSelected = null;
3583 attributeTree.blockSignals(true);
3584 attributeTree.clearSelection();
3585 attributeTree.blockSignals(false);
3589 //***************************************************************
3590 //***************************************************************
3591 //** These functions deal with the GUI Note index table
3592 //***************************************************************
3593 //***************************************************************
3594 // Initialize the note list table
3595 private void initializeNoteTable() {
3596 logger.log(logger.HIGH, "Entering NeverNote.initializeNoteTable");
3597 noteTableView.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection);
3598 noteTableView.selectionModel().selectionChanged.connect(this, "noteTableSelection()");
3599 logger.log(logger.HIGH, "Leaving NeverNote.initializeNoteTable");
3601 // Show/Hide trash window
3602 @SuppressWarnings("unused")
3603 private void toggleNoteListWindow() {
3604 logger.log(logger.HIGH, "Entering NeverNote.toggleNoteListWindow");
3605 if (noteTableView.isVisible())
3606 noteTableView.hide();
3608 noteTableView.show();
3609 menuBar.hideNoteList.setChecked(noteTableView.isVisible());
3611 Global.saveWindowVisible("noteList", noteTableView.isVisible());
3612 logger.log(logger.HIGH, "Leaving NeverNote.toggleNoteListWindow");
3614 // Handle the event that a user selects a note from the table
3615 @SuppressWarnings("unused")
3616 private void noteTableSelection() {
3617 logger.log(logger.HIGH, "Entering NeverNote.noteTableSelection");
3621 // If we have more than one selection, then set the merge note action to true.
3622 List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
3623 if (selections.size() > 1)
3624 menuBar.noteMergeAction.setEnabled(true);
3626 menuBar.noteMergeAction.setEnabled(false);
3628 // If the ctrl key is pressed, then they are selecting multiple
3629 // entries and we don't want to change the currently viewed note.
3630 if (QApplication.keyboardModifiers().isSet(KeyboardModifier.ControlModifier) &&
3631 QApplication.mouseButtons().isSet(MouseButton.LeftButton))
3634 if (historyGuids.size() == 0) {
3635 historyGuids.add(currentNoteGuid);
3636 historyPosition = 1;
3638 noteTableView.showColumn(Global.noteTableGuidPosition);
3640 if (!Global.isColumnVisible("guid"))
3641 noteTableView.hideColumn(Global.noteTableGuidPosition);
3643 if (selections.size() > 0) {
3645 menuBar.noteDuplicateAction.setEnabled(true);
3646 menuBar.noteOnlineHistoryAction.setEnabled(true);
3647 menuBar.noteMergeAction.setEnabled(true);
3648 selectedNoteGUIDs.clear();
3649 if (selections.size() != 1 || Global.showDeleted) {
3650 menuBar.noteDuplicateAction.setEnabled(false);
3652 if (selections.size() != 1 || !Global.isConnected) {
3653 menuBar.noteOnlineHistoryAction.setEnabled(false);
3655 if (selections.size() == 1) {
3656 menuBar.noteMergeAction.setEnabled(false);
3658 for (int i=0; i<selections.size(); i++) {
3659 int row = selections.get(i).row();
3661 upButton.setEnabled(false);
3663 upButton.setEnabled(true);
3664 if (row < listManager.getNoteTableModel().rowCount()-1)
3665 downButton.setEnabled(true);
3667 downButton.setEnabled(false);
3668 index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition);
3669 SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
3670 currentNoteGuid = (String)ix.values().toArray()[0];
3671 selectedNoteGUIDs.add(currentNoteGuid);
3675 nextButton.setEnabled(true);
3676 prevButton.setEnabled(true);
3678 int endPosition = historyGuids.size()-1;
3679 for (int j=historyPosition; j<=endPosition; j++) {
3680 historyGuids.remove(historyGuids.size()-1);
3682 historyGuids.add(currentNoteGuid);
3683 historyPosition = historyGuids.size();
3685 if (historyPosition <= 1)
3686 prevButton.setEnabled(false);
3687 if (historyPosition == historyGuids.size())
3688 nextButton.setEnabled(false);
3690 fromHistory = false;
3691 scrollToGuid(currentNoteGuid);
3692 refreshEvernoteNote(true);
3693 logger.log(logger.HIGH, "Leaving NeverNote.noteTableSelection");
3695 // Trigger a refresh when the note db has been updated
3696 private void noteIndexUpdated(boolean reload) {
3697 logger.log(logger.HIGH, "Entering NeverNote.noteIndexUpdated");
3699 refreshEvernoteNoteList();
3700 logger.log(logger.HIGH, "Calling note table reload in NeverNote.noteIndexUpdated() - "+reload);
3701 noteTableView.load(reload);
3702 if (currentNoteGuid == null || currentNoteGuid.equals("")) {
3704 if (noteTableView.proxyModel.sortOrder() == SortOrder.AscendingOrder)
3705 pos = noteTableView.proxyModel.rowCount();
3708 if (noteTableView.proxyModel.rowCount() == 0)
3711 QModelIndex i = noteTableView.proxyModel.index(pos-1, Global.noteTableGuidPosition);
3713 currentNoteGuid = (String)i.data();
3717 if (!noteTableView.isColumnHidden(Global.noteTableGuidPosition))
3719 scrollToGuid(currentNoteGuid);
3720 logger.log(logger.HIGH, "Leaving NeverNote.noteIndexUpdated");
3722 // Called when the list of notes is updated
3723 private void refreshEvernoteNoteList() {
3724 logger.log(logger.HIGH, "Entering NeverNote.refreshEvernoteNoteList");
3725 browserWindow.setDisabled(false);
3726 if (selectedNoteGUIDs == null)
3727 selectedNoteGUIDs = new ArrayList<String>();
3728 selectedNoteGUIDs.clear(); // clear out old entries
3730 String saveCurrentNoteGuid = new String();
3731 String tempNoteGuid = new String();
3733 historyGuids.clear();
3734 historyPosition = 0;
3735 prevButton.setEnabled(false);
3736 nextButton.setEnabled(false);
3738 if (currentNoteGuid == null)
3739 currentNoteGuid = new String();
3741 //determine current note guid
3742 for (Note note : listManager.getNoteIndex()) {
3743 tempNoteGuid = note.getGuid();
3744 if (currentNoteGuid.equals(tempNoteGuid)) {
3745 saveCurrentNoteGuid = tempNoteGuid;
3749 if (listManager.getNoteIndex().size() == 0) {
3750 currentNoteGuid = "";
3752 browserWindow.clear();
3753 browserWindow.setDisabled(true);
3756 if (Global.showDeleted && listManager.getNotebookIndex().size() > 0 && saveCurrentNoteGuid.equals("")) {
3757 currentNoteGuid = listManager.getNoteIndex().get(0).getGuid();
3758 saveCurrentNoteGuid = currentNoteGuid;
3759 refreshEvernoteNote(true);
3762 if (!saveCurrentNoteGuid.equals("")) {
3763 refreshEvernoteNote(false);
3765 currentNoteGuid = "";
3767 reloadTagTree(false);
3769 logger.log(logger.HIGH, "Leaving NeverNote.refreshEvernoteNoteList");
3771 // Called when the previous arrow button is clicked
3772 @SuppressWarnings("unused")
3773 private void previousViewedAction() {
3774 if (!prevButton.isEnabled())
3776 if (historyPosition == 0)
3779 if (historyPosition <= 0)
3781 String historyGuid = historyGuids.get(historyPosition-1);
3783 for (int i=0; i<noteTableView.model().rowCount(); i++) {
3784 QModelIndex modelIndex = noteTableView.model().index(i, Global.noteTableGuidPosition);
3785 if (modelIndex != null) {
3786 SortedMap<Integer, Object> ix = noteTableView.model().itemData(modelIndex);
3787 String tableGuid = (String)ix.values().toArray()[0];
3788 if (tableGuid.equals(historyGuid)) {
3789 noteTableView.selectRow(i);
3795 @SuppressWarnings("unused")
3796 private void nextViewedAction() {
3797 if (!nextButton.isEnabled())
3799 String historyGuid = historyGuids.get(historyPosition);
3802 for (int i=0; i<noteTableView.model().rowCount(); i++) {
3803 QModelIndex modelIndex = noteTableView.model().index(i, Global.noteTableGuidPosition);
3804 if (modelIndex != null) {
3805 SortedMap<Integer, Object> ix = noteTableView.model().itemData(modelIndex);
3806 String tableGuid = (String)ix.values().toArray()[0];
3807 if (tableGuid.equals(historyGuid)) {
3808 noteTableView.selectRow(i);
3814 // Called when the up arrow is clicked
3815 @SuppressWarnings("unused")
3816 private void upAction() {
3817 List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
3818 int row = selections.get(0).row();
3820 noteTableView.selectRow(row-1);
3823 // Called when the down arrow is clicked
3824 @SuppressWarnings("unused")
3825 private void downAction() {
3826 List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
3827 int row = selections.get(0).row();
3828 int max = listManager.getNoteTableModel().rowCount();
3830 noteTableView.selectRow(row+1);
3833 // Update a tag string for a specific note in the list
3834 @SuppressWarnings("unused")
3835 private void updateListTags(String guid, List<String> tags) {
3836 logger.log(logger.HIGH, "Entering NeverNote.updateListTags");
3837 StringBuffer tagBuffer = new StringBuffer();
3838 for (int i=0; i<tags.size(); i++) {
3839 tagBuffer.append(tags.get(i));
3840 if (i<tags.size()-1)
3841 tagBuffer.append(", ");
3844 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3845 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3846 if (modelIndex != null) {
3847 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3848 String tableGuid = (String)ix.values().toArray()[0];
3849 if (tableGuid.equals(guid)) {
3850 listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition,tagBuffer.toString());
3851 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
3852 noteTableView.proxyModel.invalidate();
3857 logger.log(logger.HIGH, "Leaving NeverNote.updateListTags");
3859 // Update a title for a specific note in the list
3860 @SuppressWarnings("unused")
3861 private void updateListAuthor(String guid, String author) {
3862 logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
3864 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3865 //QModelIndex modelIndex = noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
3866 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3867 if (modelIndex != null) {
3868 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3869 String tableGuid = (String)ix.values().toArray()[0];
3870 if (tableGuid.equals(guid)) {
3871 listManager.getNoteTableModel().setData(i, Global.noteTableAuthorPosition,author);
3872 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
3873 noteTableView.proxyModel.invalidate();
3879 logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
3881 private void updateListNoteNotebook(String guid, String notebook) {
3882 logger.log(logger.HIGH, "Entering NeverNote.updateListNoteNotebook");
3883 listManager.getNoteTableModel().updateNoteSyncStatus(guid, false);
3884 logger.log(logger.HIGH, "Leaving NeverNote.updateListNoteNotebook");
3886 // Update a title for a specific note in the list
3887 @SuppressWarnings("unused")
3888 private void updateListSourceUrl(String guid, String url) {
3889 logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
3891 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3892 //QModelIndex modelIndex = noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
3893 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3894 if (modelIndex != null) {
3895 // SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(modelIndex);
3896 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3897 String tableGuid = (String)ix.values().toArray()[0];
3898 if (tableGuid.equals(guid)) {
3899 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
3900 listManager.getNoteTableModel().setData(i, Global.noteTableSourceUrlPosition,url);
3901 noteTableView.proxyModel.invalidate();
3906 logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
3908 @SuppressWarnings("unused")
3909 private void updateListGuid(String oldGuid, String newGuid) {
3910 logger.log(logger.HIGH, "Entering NeverNote.updateListTitle");
3912 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3913 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3914 if (modelIndex != null) {
3915 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3916 String tableGuid = (String)ix.values().toArray()[0];
3917 if (tableGuid.equals(oldGuid)) {
3918 listManager.getNoteTableModel().setData(i, Global.noteTableGuidPosition,newGuid);
3919 //listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
3924 logger.log(logger.HIGH, "Leaving NeverNote.updateListTitle");
3926 private void updateListTagName(String guid) {
3927 logger.log(logger.HIGH, "Entering NeverNote.updateTagName");
3929 for (int j=0; j<listManager.getNoteIndex().size(); j++) {
3930 if (listManager.getNoteIndex().get(j).getTagGuids().contains(guid)) {
3931 String newName = listManager.getTagNamesForNote(listManager.getNoteIndex().get(j));
3933 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3934 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3935 if (modelIndex != null) {
3936 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3937 String noteGuid = (String)ix.values().toArray()[0];
3938 if (noteGuid.equalsIgnoreCase(listManager.getNoteIndex().get(j).getGuid())) {
3939 listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition, newName);
3940 i=listManager.getNoteTableModel().rowCount();
3946 logger.log(logger.HIGH, "Leaving NeverNote.updateListNotebook");
3948 private void removeListTagName(String guid) {
3949 logger.log(logger.HIGH, "Entering NeverNote.updateTagName");
3951 for (int j=0; j<listManager.getNoteIndex().size(); j++) {
3952 if (listManager.getNoteIndex().get(j).getTagGuids().contains(guid)) {
3953 for (int i=listManager.getNoteIndex().get(j).getTagGuids().size()-1; i>=0; i--) {
3954 if (listManager.getNoteIndex().get(j).getTagGuids().get(i).equals(guid))
3955 listManager.getNoteIndex().get(j).getTagGuids().remove(i);
3958 String newName = listManager.getTagNamesForNote(listManager.getNoteIndex().get(j));
3959 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3960 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3961 if (modelIndex != null) {
3962 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3963 String noteGuid = (String)ix.values().toArray()[0];
3964 if (noteGuid.equalsIgnoreCase(listManager.getNoteIndex().get(j).getGuid())) {
3965 listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition, newName);
3966 i=listManager.getNoteTableModel().rowCount();
3972 logger.log(logger.HIGH, "Leaving NeverNote.updateListNotebook");
3974 private void updateListNotebookName(String oldName, String newName) {
3975 logger.log(logger.HIGH, "Entering NeverNote.updateListNotebookName");
3977 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3978 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableNotebookPosition);
3979 if (modelIndex != null) {
3980 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3981 String tableName = (String)ix.values().toArray()[0];
3982 if (tableName.equalsIgnoreCase(oldName)) {
3983 listManager.getNoteTableModel().setData(i, Global.noteTableNotebookPosition, newName);
3987 logger.log(logger.HIGH, "Leaving NeverNote.updateListNotebookName");
3989 @SuppressWarnings("unused")
3990 private void updateListDateCreated(String guid, QDateTime date) {
3991 logger.log(logger.HIGH, "Entering NeverNote.updateListDateCreated");
3993 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3994 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3995 if (modelIndex != null) {
3996 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3997 String tableGuid = (String)ix.values().toArray()[0];
3998 if (tableGuid.equals(guid)) {
3999 listManager.getNoteTableModel().setData(i, Global.noteTableCreationPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
4000 noteTableView.proxyModel.invalidate();
4005 logger.log(logger.HIGH, "Leaving NeverNote.updateListDateCreated");
4007 @SuppressWarnings("unused")
4008 private void updateListDateSubject(String guid, QDateTime date) {
4009 logger.log(logger.HIGH, "Entering NeverNote.updateListDateSubject");
4011 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4012 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4013 if (modelIndex != null) {
4014 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4015 String tableGuid = (String)ix.values().toArray()[0];
4016 if (tableGuid.equals(guid)) {
4017 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
4018 listManager.getNoteTableModel().setData(i, Global.noteTableSubjectDatePosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
4019 noteTableView.proxyModel.invalidate();
4024 logger.log(logger.HIGH, "Leaving NeverNote.updateListDateCreated");
4026 private void updateListDateChanged(String guid, QDateTime date) {
4027 logger.log(logger.HIGH, "Entering NeverNote.updateListDateChanged");
4029 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4030 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4031 if (modelIndex != null) {
4032 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4033 String tableGuid = (String)ix.values().toArray()[0];
4034 if (tableGuid.equals(guid)) {
4035 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
4036 listManager.getNoteTableModel().setData(i, Global.noteTableChangedPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
4041 logger.log(logger.HIGH, "Leaving NeverNote.updateListDateChanged");
4043 private void updateListDateChanged() {
4044 logger.log(logger.HIGH, "Entering NeverNote.updateListDateChanged");
4045 QDateTime date = new QDateTime(QDateTime.currentDateTime());
4046 updateListDateChanged(currentNoteGuid, date);
4047 logger.log(logger.HIGH, "Leaving NeverNote.updateListDateChanged");
4050 private void scrollToCurrentGuid() {
4051 //scrollToGuid(currentNoteGuid);
4052 List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
4053 if (selections.size() == 0)
4055 QModelIndex index = selections.get(0);
4056 int row = selections.get(0).row();
4057 String guid = (String)index.model().index(row, Global.noteTableGuidPosition).data();
4060 // Scroll to the current GUID in tthe list.
4061 // Scroll to a particular index item
4062 private void scrollToGuid(String guid) {
4063 if (currentNote == null || guid == null)
4065 if (currentNote.isActive() && Global.showDeleted) {
4066 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
4067 if (!listManager.getNoteIndex().get(i).isActive()) {
4068 currentNote = listManager.getNoteIndex().get(i);
4069 currentNoteGuid = currentNote.getGuid();
4070 i = listManager.getNoteIndex().size();
4074 if (!currentNote.isActive() && !Global.showDeleted) {
4075 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
4076 if (listManager.getNoteIndex().get(i).isActive()) {
4077 currentNote = listManager.getNoteIndex().get(i);
4078 currentNoteGuid = currentNote.getGuid();
4079 i = listManager.getNoteIndex().size();
4084 for (int i=0; i<noteTableView.model().rowCount(); i++) {
4085 index = noteTableView.model().index(i, Global.noteTableGuidPosition);
4086 if (currentNoteGuid.equals(index.data())) {
4087 // noteTableView.selectionModel().blockSignals(true);
4088 noteTableView.selectRow(i);
4089 // noteTableView.selectionModel().blockSignals(false);
4090 noteTableView.scrollTo(index, ScrollHint.EnsureVisible); // This should work, but it doesn't
4091 i=listManager.getNoteTableModel().rowCount();
4094 noteTableView.repaint();
4096 // Show/Hide columns
4097 private void showColumns() {
4098 noteTableView.setColumnHidden(Global.noteTableCreationPosition, !Global.isColumnVisible("dateCreated"));
4099 noteTableView.setColumnHidden(Global.noteTableChangedPosition, !Global.isColumnVisible("dateChanged"));
4100 noteTableView.setColumnHidden(Global.noteTableSubjectDatePosition, !Global.isColumnVisible("dateSubject"));
4101 noteTableView.setColumnHidden(Global.noteTableAuthorPosition, !Global.isColumnVisible("author"));
4102 noteTableView.setColumnHidden(Global.noteTableSourceUrlPosition, !Global.isColumnVisible("sourceUrl"));
4103 noteTableView.setColumnHidden(Global.noteTableTagPosition, !Global.isColumnVisible("tags"));
4104 noteTableView.setColumnHidden(Global.noteTableNotebookPosition, !Global.isColumnVisible("notebook"));
4105 noteTableView.setColumnHidden(Global.noteTableSynchronizedPosition, !Global.isColumnVisible("synchronized"));
4106 noteTableView.setColumnHidden(Global.noteTableGuidPosition, !Global.isColumnVisible("guid"));
4107 noteTableView.setColumnHidden(Global.noteTableThumbnailPosition, !Global.isColumnVisible("thumbnail"));
4108 noteTableView.setColumnHidden(Global.noteTableTitlePosition, !Global.isColumnVisible("title"));
4109 noteTableView.setColumnHidden(Global.noteTablePinnedPosition, !Global.isColumnVisible("pinned"));
4111 // Title color has changed
4112 @SuppressWarnings("unused")
4113 private void titleColorChanged(Integer color) {
4114 logger.log(logger.HIGH, "Entering NeverNote.titleColorChanged");
4117 QColor backgroundColor = new QColor();
4118 QColor foregroundColor = new QColor(QColor.black);
4119 backgroundColor.setRgb(color);
4121 if (backgroundColor.rgb() == QColor.black.rgb() || backgroundColor.rgb() == QColor.blue.rgb())
4122 foregroundColor.setRgb(QColor.white.rgb());
4124 if (selectedNoteGUIDs.size() == 0)
4125 selectedNoteGUIDs.add(currentNoteGuid);
4127 for (int j=0; j<selectedNoteGUIDs.size(); j++) {
4128 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4129 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4130 if (modelIndex != null) {
4131 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4132 String tableGuid = (String)ix.values().toArray()[0];
4133 if (tableGuid.equals(selectedNoteGUIDs.get(j))) {
4134 for (int k=0; k<Global.noteTableColumnCount; k++) {
4135 listManager.getNoteTableModel().setData(i, k, backgroundColor, Qt.ItemDataRole.BackgroundRole);
4136 listManager.getNoteTableModel().setData(i, k, foregroundColor, Qt.ItemDataRole.ForegroundRole);
4137 listManager.updateNoteTitleColor(selectedNoteGUIDs.get(j), backgroundColor.rgb());
4139 i=listManager.getNoteTableModel().rowCount();
4144 logger.log(logger.HIGH, "Leaving NeverNote.titleColorChanged");
4146 // A note has been pinned or unpinned
4147 @SuppressWarnings("unused")
4148 private void notePinned() {
4149 logger.log(logger.EXTREME, "Entering NeverNote.notePinned()");
4152 for (int j=0; j<selectedNoteGUIDs.size(); j++) {
4153 NoteMetadata meta = listManager.getNoteMetadata().get(selectedNoteGUIDs.get(j));
4154 boolean pinned = !meta.isPinned();
4155 meta.setPinned(pinned); // Toggle the pinned/unpinned
4157 // Update the list & table
4158 listManager.updateNoteMetadata(meta);
4159 noteTableView.proxyModel.addGuid(selectedNoteGUIDs.get(j), meta);
4162 logger.log(logger.EXTREME, "Leaving NeverNote.setNoteDirty()");
4164 // Wide list was chosen
4165 public void narrowListView() {
4166 saveNoteColumnPositions();
4167 saveNoteIndexWidth();
4169 int sortCol = noteTableView.proxyModel.sortColumn();
4170 int sortOrder = noteTableView.proxyModel.sortOrder().value();
4171 Global.setSortColumn(sortCol);
4172 Global.setSortOrder(sortOrder);
4174 Global.setListView(Global.View_List_Narrow);
4176 menuBar.wideListView.blockSignals(true);
4177 menuBar.narrowListView.blockSignals(true);
4179 menuBar.wideListView.setChecked(false);
4180 menuBar.narrowListView.setChecked(true);
4182 menuBar.wideListView.blockSignals(false);
4183 menuBar.narrowListView.blockSignals(false);
4185 mainLeftRightSplitter.addWidget(noteTableView);
4186 mainLeftRightSplitter.addWidget(browserWindow);
4187 restoreWindowState(false);
4188 noteTableView.repositionColumns();
4189 noteTableView.resizeColumnWidths();
4190 noteTableView.resizeRowHeights();
4192 sortCol = Global.getSortColumn();
4193 sortOrder = Global.getSortOrder();
4194 noteTableView.proxyModel.blocked = true;
4195 noteTableView.sortByColumn(sortCol, SortOrder.resolve(sortOrder));
4196 noteTableView.proxyModel.blocked = false;
4200 noteTableView.load(false);
4201 refreshEvernoteNote(true);
4202 scrollToCurrentGuid();
4204 public void wideListView() {
4205 int sortCol = noteTableView.proxyModel.sortColumn();
4206 int sortOrder = noteTableView.proxyModel.sortOrder().value();
4207 Global.setSortColumn(sortCol);
4208 Global.setSortOrder(sortOrder);
4211 saveNoteColumnPositions();
4212 saveNoteIndexWidth();
4213 Global.setListView(Global.View_List_Wide);
4215 menuBar.wideListView.blockSignals(true);
4216 menuBar.narrowListView.blockSignals(true);
4218 menuBar.wideListView.setChecked(true);
4219 menuBar.narrowListView.setChecked(false);
4221 menuBar.wideListView.blockSignals(false);
4222 menuBar.narrowListView.blockSignals(false);
4223 browserIndexSplitter.setVisible(true);
4224 browserIndexSplitter.addWidget(noteTableView);
4225 browserIndexSplitter.addWidget(browserWindow);
4226 restoreWindowState(false);
4227 noteTableView.repositionColumns();
4228 noteTableView.resizeColumnWidths();
4229 noteTableView.resizeRowHeights();
4231 sortCol = Global.getSortColumn();
4232 sortOrder = Global.getSortOrder();
4233 noteTableView.proxyModel.blocked = true;
4234 noteTableView.sortByColumn(sortCol, SortOrder.resolve(sortOrder));
4235 noteTableView.proxyModel.blocked = false;
4238 noteTableView.load(false);
4239 scrollToCurrentGuid();
4241 // Sort order for the notebook has changed
4242 public void tableSortOrderChanged(Integer column, Integer order) {
4244 // Find what notebook (if any) is selected. We ignore stacks & the "All Notebooks".
4245 List<QTreeWidgetItem> selectedNotebook = notebookTree.selectedItems();
4246 if (selectedNotebook.size() > 0 && !selectedNotebook.get(0).text(0).equalsIgnoreCase("All Notebooks") && !selectedNotebook.get(0).text(2).equalsIgnoreCase("STACK")) {
4247 QTreeWidgetItem currentSelectedNotebook = selectedNotebook.get(0);
4249 notebook = currentSelectedNotebook.text(2);
4250 conn.getNotebookTable().setSortOrder(notebook, column, order);
4254 //***************************************************************
4255 @SuppressWarnings("unused")
4256 private void evernoteLinkClick(String syncGuid, String locGuid) {
4258 if (conn.getNoteTable().guidExists(syncGuid)) {
4261 // If we didn't find it via the synchronized guid, look under the local guid
4262 // Iwe don't find it there, look to see if the GUID is posted under the local GUID, but was
4263 // later synchronized (that causes the guid to change so we need to find the new one).
4264 if (conn.getNoteTable().guidExists(locGuid))
4267 guid = conn.getNoteTable().findAlternateGuid(locGuid);
4270 openExternalEditor(guid);
4274 //If we've gotten this far, we can't find the note
4275 QMessageBox.information(this, tr("Note Not Found"), tr("Sorry, but I can't"+
4276 " seem to find that note."));
4278 //***************************************************************
4279 //***************************************************************
4280 //** External editor window functions
4281 //***************************************************************
4282 //***************************************************************
4283 private void listDoubleClick() {
4285 openExternalEditor(currentNoteGuid);
4287 private void openExternalEditor(String guid) {
4289 if (externalWindows.containsKey(guid)) {
4290 externalWindows.get(guid).raise();
4293 Note note = conn.getNoteTable().getNote(guid, true, true, false, true, true);
4294 // We have a new external editor to create
4295 QIcon appIcon = new QIcon(iconPath+"nevernote.png");
4296 ExternalBrowse newBrowser = new ExternalBrowse(conn);
4297 newBrowser.setWindowIcon(appIcon);
4298 externalWindows.put(guid, newBrowser);
4299 showEditorButtons(newBrowser.getBrowserWindow());
4300 loadNoteBrowserInformation(newBrowser.getBrowserWindow(), guid, note);
4301 setupBrowserWindowListeners(newBrowser.getBrowserWindow(), false);
4302 newBrowser.windowClosing.connect(this, "externalWindowClosing(String)");
4303 //newBrowser.getBrowserWindow().noteSignal.titleChanged.connect(this, "externalWindowTitleEdited(String, String)");
4304 newBrowser.getBrowserWindow().noteSignal.tagsChanged.connect(this, "externalWindowTagsEdited(String, List)");
4305 newBrowser.contentsChanged.connect(this, "saveNoteExternalBrowser(String, String, Boolean, BrowserWindow)");
4306 newBrowser.getBrowserWindow().blockApplication.connect(this, "blockApplication(BrowserWindow)");
4307 newBrowser.getBrowserWindow().unblockApplication.connect(this, "unblockApplication()");
4309 browserWindow.noteSignal.tagsChanged.connect(newBrowser, "updateTags(String, List)");
4310 browserWindow.noteSignal.titleChanged.connect(newBrowser, "updateTitle(String, String)");
4311 browserWindow.noteSignal.notebookChanged.connect(newBrowser, "updateNotebook(String, String)");
4315 @SuppressWarnings({ "rawtypes", "unused" })
4316 private void externalWindowTagsEdited(String guid, List values) {
4317 StringBuffer line = new StringBuffer(100);
4318 for (int i=0; i<values.size(); i++) {
4320 line.append(Global.tagDelimeter+" ");
4321 line.append(values.get(i));
4323 if (guid.equals(currentNoteGuid)) {
4324 browserWindow.setTag(line.toString());
4327 @SuppressWarnings("unused")
4328 private void externalWindowClosing(String guid) {
4329 externalWindows.remove(guid);
4334 //***************************************************************
4335 //***************************************************************
4336 //** These functions deal with Note specific things
4337 //***************************************************************
4338 //***************************************************************
4339 private void setNoteDirty() {
4340 logger.log(logger.EXTREME, "Entering NeverNote.setNoteDirty()");
4342 // Find if the note is being edited externally. If it is, update it.
4343 if (externalWindows.containsKey(currentNoteGuid)) {
4344 QTextCodec codec = QTextCodec.codecForName("UTF-8");
4345 QByteArray unicode = codec.fromUnicode(browserWindow.getContent());
4346 ExternalBrowse window = externalWindows.get(currentNoteGuid);
4347 window.getBrowserWindow().setContent(unicode);
4350 // If the note is dirty, then it is unsynchronized by default.
4354 // Set the note as dirty and check if its status is synchronized in the display table
4356 if (listManager.getNoteMetadata().containsKey(currentNoteGuid) &&
4357 listManager.getNoteMetadata().get(currentNoteGuid).isDirty()) {
4361 // If this wasn't already marked as unsynchronized, then we need to update the table
4362 listManager.getNoteTableModel().updateNoteSyncStatus(currentNoteGuid, false);
4363 // listManager.getUnsynchronizedNotes().add(currentNoteGuid);
4364 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4365 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4366 if (modelIndex != null) {
4367 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4368 String tableGuid = (String)ix.values().toArray()[0];
4369 if (tableGuid.equals(currentNoteGuid)) {
4370 listManager.getNoteTableModel().proxyModel.setData(i, Global.noteTableSynchronizedPosition, "false");
4376 logger.log(logger.EXTREME, "Leaving NeverNote.setNoteDirty()");
4378 @SuppressWarnings("unused")
4379 private void saveNoteExternalBrowser(String guid, String content, Boolean save, BrowserWindow browser) {
4380 QTextCodec codec = QTextCodec.codecForName("UTF-8");
4381 QByteArray unicode = codec.fromUnicode(content);
4382 noteCache.remove(guid);
4383 noteCache.put(guid, unicode.toString());
4384 if (guid.equals(currentNoteGuid)) {
4386 browserWindow.setContent(unicode);
4389 thumbnailRunner.addWork("GENERATE "+ guid);
4390 saveNote(guid, browser);
4394 private void saveNote() {
4396 saveNote(currentNoteGuid, browserWindow);
4397 thumbnailRunner.addWork("GENERATE "+ currentNoteGuid);
4401 private void saveNote(String guid, BrowserWindow window) {
4402 logger.log(logger.EXTREME, "Inside NeverNote.saveNote()");
4405 logger.log(logger.EXTREME, "Saving to cache");
4406 QTextCodec codec = QTextCodec.codecForLocale();
4407 // QTextDecoder decoder = codec.makeDecoder();
4408 codec = QTextCodec.codecForName("UTF-8");
4409 QByteArray unicode = codec.fromUnicode(window.getContent());
4410 noteCache.put(guid, unicode.toString());
4412 logger.log(logger.EXTREME, "updating list manager");
4413 listManager.updateNoteContent(guid, window.getContent());
4414 logger.log(logger.EXTREME, "Updating title");
4415 listManager.updateNoteTitle(guid, window.getTitle());
4416 updateListDateChanged();
4418 logger.log(logger.EXTREME, "Looking through note index for refreshed note");
4419 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
4420 if (listManager.getNoteIndex().get(i).getGuid().equals(guid)) {
4421 currentNote = listManager.getNoteIndex().get(i);
4422 i = listManager.getNoteIndex().size();
4427 // Get a note from Evernote (and put it in the browser)
4428 private void refreshEvernoteNote(boolean reload) {
4429 logger.log(logger.HIGH, "Entering NeverNote.refreshEvernoteNote");
4431 if (Global.disableViewing) {
4432 browserWindow.setEnabled(false);
4437 if (Global.showDeleted || currentNoteGuid == null || currentNoteGuid.equals(""))
4439 Global.cryptCounter =0;
4441 browserWindow.setReadOnly(true);
4448 browserWindow.loadingData(true);
4450 currentNote = conn.getNoteTable().getNote(currentNoteGuid, true,true,false,false,true);
4451 if (currentNote == null)
4453 loadNoteBrowserInformation(browserWindow, currentNoteGuid, currentNote);
4456 private void loadNoteBrowserInformation(BrowserWindow browser, String guid, Note note) {
4457 NoteFormatter formatter = new NoteFormatter(logger, conn, tempFiles);
4458 formatter.setNote(note, Global.pdfPreview());
4459 formatter.setHighlight(listManager.getEnSearch());
4461 if (!noteCache.containsKey(guid)) {
4462 js = new QByteArray();
4463 // We need to prepend the note with <HEAD></HEAD> or encoded characters are ugly
4464 js.append("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">");
4465 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>");
4466 js.append("<style type=\"text/css\">en-hilight { background-color: rgb(255,255,0) }</style>");
4467 js.append("<style> img { height:auto; width:auto; max-height:auto; max-width:100%; }</style>");
4468 if (Global.displayRightToLeft())
4469 js.append("<style> body { direction:rtl; }</style>");
4470 js.append("<style type=\"text/css\">en-spell { text-decoration: none; border-bottom: dotted 1px #cc0000; }</style>");
4471 js.append("</head>");
4472 formatter.setNote(note, Global.pdfPreview());
4473 js.append(formatter.rebuildNoteHTML());
4474 js.append("</HTML>");
4475 js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml.dtd'>", "");
4476 js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml2.dtd'>", "");
4477 js.replace("<?xml version='1.0' encoding='UTF-8'?>", "");
4478 // if (Global.enableHTMLEntitiesFix) {
4479 // browser.getBrowser().setContent(new QByteArray(StringEscapeUtils.unescapeHtml(js.toString())));
4481 browser.setContent(js);
4482 noteCache.put(guid, js.toString());
4484 if (formatter.resourceError)
4485 resourceErrorMessage();
4486 if (formatter.formatError) {
4488 QMessageBox.information(this, tr("Error"),
4489 tr("NixNote had issues formatting this note." +
4490 " To protect your data this note is being marked as read-only."));
4493 readOnly = formatter.readOnly;
4494 inkNote = formatter.inkNote;
4496 readOnlyCache.put(guid, true);
4498 inkNoteCache.put(guid, true);
4500 logger.log(logger.HIGH, "Note content is being pulled from the cache");
4501 String cachedContent = formatter.modifyCachedTodoTags(noteCache.get(guid));
4502 js = new QByteArray(cachedContent);
4503 browser.setContent(js);
4504 if (readOnlyCache.containsKey(guid))
4506 if (inkNoteCache.containsKey(guid))
4509 if (conn.getNoteTable().isThumbnailNeeded(guid)) {
4510 thumbnailHTMLReady(guid, js, Global.calculateThumbnailZoom(js.toString()));
4512 if (readOnly || inkNote ||
4513 (note.getAttributes() != null && note.getAttributes().getContentClass() != null && note.getAttributes().getContentClass() != ""))
4514 browser.getBrowser().page().setContentEditable(false); // We don't allow editing of ink notes
4516 browser.getBrowser().page().setContentEditable(true);
4517 browser.setReadOnly(readOnly);
4518 deleteButton.setEnabled(!readOnly);
4519 tagButton.setEnabled(!readOnly);
4520 menuBar.noteDelete.setEnabled(!readOnly);
4521 menuBar.noteTags.setEnabled(!readOnly);
4522 browser.setNote(note);
4524 if (note != null && note.getNotebookGuid() != null &&
4525 conn.getNotebookTable().isLinked(note.getNotebookGuid())) {
4526 deleteButton.setEnabled(false);
4527 menuBar.notebookDeleteAction.setEnabled(false);
4529 deleteButton.setEnabled(true);
4530 menuBar.notebookDeleteAction.setEnabled(true);
4533 // Build a list of non-closed notebooks
4534 List<Notebook> nbooks = new ArrayList<Notebook>();
4535 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
4536 boolean found=false;
4537 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
4538 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid()))
4542 nbooks.add(listManager.getNotebookIndex().get(i));
4545 browser.setTitle(note.getTitle());
4546 browser.setTag(getTagNamesForNote(note));
4547 browser.setAuthor(note.getAttributes().getAuthor());
4549 browser.setAltered(note.getUpdated());
4550 browser.setCreation(note.getCreated());
4551 if (note.getAttributes().getSubjectDate() > 0)
4552 browser.setSubjectDate(note.getAttributes().getSubjectDate());
4554 browser.setSubjectDate(note.getCreated());
4555 browser.setUrl(note.getAttributes().getSourceURL());
4557 FilterEditorTags tagFilter = new FilterEditorTags(conn, logger);
4558 List<Tag> tagList = tagFilter.getValidTags(note);
4559 browser.setAllTags(tagList);
4561 browser.setCurrentTags(note.getTagNames());
4565 browser.loadingData(false);
4566 if (thumbnailViewer.isActiveWindow())
4569 FilterEditorNotebooks notebookFilter = new FilterEditorNotebooks(conn, logger);
4570 browser.setNotebookList(notebookFilter.getValidNotebooks(note, listManager.getNotebookIndex()));
4573 logger.log(logger.HIGH, "Leaving NeverNote.refreshEvernoteNote");
4575 // Save a generated thumbnail
4576 private void toggleNoteInformation() {
4577 logger.log(logger.HIGH, "Entering NeverNote.toggleNoteInformation");
4578 browserWindow.toggleInformation();
4579 menuBar.noteAttributes.setChecked(browserWindow.isExtended());
4580 Global.saveWindowVisible("noteInformation", browserWindow.isExtended());
4581 logger.log(logger.HIGH, "Leaving NeverNote.toggleNoteInformation");
4583 // Listener triggered when a print button is pressed
4584 @SuppressWarnings("unused")
4585 private void printNote() {
4586 logger.log(logger.HIGH, "Entering NeverNote.printNote");
4588 QPrintDialog dialog = new QPrintDialog();
4589 if (dialog.exec() == QDialog.DialogCode.Accepted.value()) {
4590 QPrinter printer = dialog.printer();
4591 browserWindow.getBrowser().print(printer);
4593 logger.log(logger.HIGH, "Leaving NeverNote.printNote");
4596 // Listener triggered when the email button is pressed
4597 @SuppressWarnings("unused")
4598 private void emailNote() {
4599 logger.log(logger.HIGH, "Entering NeverNote.emailNote");
4601 if (Desktop.isDesktopSupported()) {
4602 Desktop desktop = Desktop.getDesktop();
4604 String text2 = browserWindow.getContentsToEmail();
4605 QUrl url = new QUrl("mailto:");
4606 url.addQueryItem("subject", currentNote.getTitle());
4607 // url.addQueryItem("body", QUrl.toPercentEncoding(text2).toString());
4608 url.addQueryItem("body", text2);
4609 QDesktopServices.openUrl(url);
4613 if (desktop.isSupported(Desktop.Action.MAIL)) {
4614 URI uriMailTo = null;
4616 //String text = browserWindow.getBrowser().page().currentFrame().toPlainText();
4617 String text = browserWindow.getContentsToEmail();
4618 //text = "<b>" +text +"</b>";
4619 uriMailTo = new URI("mailto", "&SUBJECT="+currentNote.getTitle()
4620 +"&BODY=" +text, null);
4621 uriMailTo = new URI("mailto", "&SUBJECT="+currentNote.getTitle()
4622 +"&ATTACHMENT=d:/test.pdf", null);
4623 desktop.mail(uriMailTo);
4624 } catch (URISyntaxException e) {
4625 e.printStackTrace();
4626 } catch (IOException e) {
4627 e.printStackTrace();
4634 logger.log(logger.HIGH, "Leaving NeverNote.emailNote");
4636 // Reindex all notes
4637 @SuppressWarnings("unused")
4638 private void fullReindex() {
4639 logger.log(logger.HIGH, "Entering NeverNote.fullReindex");
4640 indexRunner.addWork("REINDEXALL");
4641 setMessage(tr("Database will be reindexed."));
4642 logger.log(logger.HIGH, "Leaving NeverNote.fullReindex");
4644 // Listener when a user wants to reindex a specific note
4645 @SuppressWarnings("unused")
4646 private void reindexNote() {
4647 logger.log(logger.HIGH, "Entering NeverNote.reindexNote");
4648 for (int i=0; i<selectedNoteGUIDs.size(); i++) {
4649 indexRunner.addWork("REINDEXNOTE "+selectedNoteGUIDs.get(i));
4651 if (selectedNotebookGUIDs.size() > 1)
4652 setMessage(tr("Notes will be reindexed."));
4654 setMessage(tr("Note will be reindexed."));
4655 logger.log(logger.HIGH, "Leaving NeverNote.reindexNote");
4658 @SuppressWarnings("unused")
4659 private void deleteNote() {
4660 logger.log(logger.HIGH, "Entering NeverNote.deleteNote");
4661 if (currentNote == null)
4663 if (currentNoteGuid.equals(""))
4665 String title = null;
4666 if (selectedNoteGUIDs.size() == 1)
4667 title = conn.getNoteTable().getNote(selectedNoteGUIDs.get(0),false,false,false,false,false).getTitle();
4669 // If we are deleting non-trash notes
4670 if (currentNote.isActive()) {
4671 if (Global.verifyDelete()) {
4673 if (selectedNoteGUIDs.size() > 1) {
4674 msg = new String(tr("Delete ") +selectedNoteGUIDs.size() +" notes?");
4677 msg = new String(tr("Delete note \"") +title +"\"?");
4679 msg = new String(tr("Delete note selected note?"));
4681 if (QMessageBox.question(this, tr("Confirmation"), msg,
4682 QMessageBox.StandardButton.Yes,
4683 QMessageBox.StandardButton.No)==StandardButton.No.value() && Global.verifyDelete() == true) {
4687 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
4688 selectedNoteGUIDs.add(currentNoteGuid);
4689 for (int i=0; i<selectedNoteGUIDs.size(); i++) {
4690 listManager.deleteNote(selectedNoteGUIDs.get(i));
4693 // If we are deleting from the trash.
4694 if (Global.verifyDelete()) {
4696 if (selectedNoteGUIDs.size() > 1) {
4697 msg = new String(tr("Permanently delete ") +selectedNoteGUIDs.size() +" notes?");
4700 msg = new String(tr("Permanently delete note \"") +title +"\"?");
4702 msg = new String(tr("Permanently delete note selected note?"));
4704 if (QMessageBox.question(this, "Confirmation", msg,
4705 QMessageBox.StandardButton.Yes,
4706 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
4710 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
4711 selectedNoteGUIDs.add(currentNoteGuid);
4712 for (int i=selectedNoteGUIDs.size()-1; i>=0; i--) {
4713 for (int j=listManager.getNoteTableModel().rowCount()-1; j>=0; j--) {
4714 QModelIndex modelIndex = listManager.getNoteTableModel().index(j, Global.noteTableGuidPosition);
4715 if (modelIndex != null) {
4716 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4717 String tableGuid = (String)ix.values().toArray()[0];
4718 if (tableGuid.equals(selectedNoteGUIDs.get(i))) {
4719 listManager.getNoteTableModel().removeRow(j);
4724 listManager.expungeNote(selectedNoteGUIDs.get(i));
4727 currentNoteGuid = "";
4728 listManager.loadNotesIndex();
4729 noteIndexUpdated(false);
4730 refreshEvernoteNote(true);
4731 scrollToGuid(currentNoteGuid);
4732 logger.log(logger.HIGH, "Leaving NeverNote.deleteNote");
4735 @SuppressWarnings("unused")
4736 private void addNote() {
4737 logger.log(logger.HIGH, "Inside NeverNote.addNote");
4738 // browserWindow.setEnabled(true);
4739 browserWindow.setReadOnly(false);
4741 Calendar currentTime = new GregorianCalendar();
4742 StringBuffer noteString = new StringBuffer(100);
4743 noteString.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
4744 "<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">\n" +
4747 if (Global.overrideDefaultFont()) {
4748 noteString.append("<font face=\"" +Global.getDefaultFont() +"\" >");
4749 noteString.append("<span style=\"font-size:" +Global.getDefaultFontSize() +"pt;\">");
4750 noteString.append("<br clear=\"none\" />\n");
4751 noteString.append("</span>\n</font>\n");
4753 noteString.append("<br clear=\"none\" />\n");
4754 noteString.append("</en-note>");
4756 Long l = new Long(currentTime.getTimeInMillis());
4757 String randint = new String(Long.toString(l));
4759 // Find a notebook. We first look for a selected notebook (the "All Notebooks" one doesn't count).
4761 // for the first non-archived notebook. Finally, if nothing else we
4762 // pick the first notebook in the list.
4763 String notebook = null;
4764 listManager.getNotebookIndex().get(0).getGuid();
4765 List<QTreeWidgetItem> selectedNotebook = notebookTree.selectedItems();
4766 if (selectedNotebook.size() > 0 && !selectedNotebook.get(0).text(0).equalsIgnoreCase("All Notebooks") && !selectedNotebook.get(0).text(2).equalsIgnoreCase("STACK")) {
4767 QTreeWidgetItem currentSelectedNotebook = selectedNotebook.get(0);
4768 notebook = currentSelectedNotebook.text(2);
4770 boolean found = false;
4771 List<Notebook> goodNotebooks = new ArrayList<Notebook>();
4772 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
4773 boolean match = false;
4774 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
4775 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid())) {
4777 j = listManager.getArchiveNotebookIndex().size();
4781 //goodNotebooks.add(listManager.getNotebookIndex().get(i).deepCopy());
4782 goodNotebooks.add((Notebook)Global.deepCopy(listManager.getNotebookIndex().get(i)));
4784 // Now we have a list of good notebooks, so we can look for the default
4786 for (int i=0; i<goodNotebooks.size(); i++) {
4787 if (goodNotebooks.get(i).isDefaultNotebook()) {
4788 notebook = goodNotebooks.get(i).getGuid();
4790 i = goodNotebooks.size();
4794 if (goodNotebooks.size() > 0 && !found)
4795 notebook = goodNotebooks.get(0).getGuid();
4798 notebook = listManager.getNotebookIndex().get(0).getGuid();
4801 Note newNote = new Note();
4802 newNote.setUpdateSequenceNum(0);
4803 newNote.setGuid(randint);
4804 newNote.setNotebookGuid(notebook);
4805 newNote.setTitle("Untitled Note");
4806 newNote.setContent(noteString.toString());
4807 newNote.setDeleted(0);
4808 newNote.setCreated(System.currentTimeMillis());
4809 newNote.setUpdated(System.currentTimeMillis());
4810 newNote.setActive(true);
4811 NoteAttributes na = new NoteAttributes();
4812 na.setLatitude(0.0);
4813 na.setLongitude(0.0);
4814 na.setAltitude(0.0);
4815 newNote.setAttributes(new NoteAttributes());
4816 newNote.setTagGuids(new ArrayList<String>());
4817 newNote.setTagNames(new ArrayList<String>());
4819 // If new notes are to be created based upon the selected tags, then we need to assign the tags
4820 if (Global.newNoteWithSelectedTags()) {
4821 List<QTreeWidgetItem> selections = tagTree.selectedItems();
4822 QTreeWidgetItem currentSelection;
4823 for (int i=0; i<selections.size(); i++) {
4824 currentSelection = selections.get(i);
4825 newNote.getTagGuids().add(currentSelection.text(2));
4826 newNote.getTagNames().add(currentSelection.text(0));
4830 conn.getNoteTable().addNote(newNote, true);
4831 NoteMetadata metadata = new NoteMetadata();
4832 metadata.setGuid(newNote.getGuid());
4833 metadata.setDirty(true);
4834 listManager.addNote(newNote, metadata);
4835 // noteTableView.insertRow(newNote, true, -1);
4837 currentNote = newNote;
4838 currentNoteGuid = currentNote.getGuid();
4839 noteTableView.clearSelection();
4840 refreshEvernoteNote(true);
4841 listManager.countNotebookResults(listManager.getNoteIndex());
4842 browserWindow.titleLabel.setFocus();
4843 browserWindow.titleLabel.selectAll();
4844 // notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
4846 // If the window is hidden, then we want to popup this in an external window &
4850 logger.log(logger.HIGH, "Leaving NeverNote.addNote");
4852 // Restore a note from the trash;
4853 @SuppressWarnings("unused")
4854 private void restoreNote() {
4856 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
4857 selectedNoteGUIDs.add(currentNoteGuid);
4858 for (int i=0; i<selectedNoteGUIDs.size(); i++) {
4859 listManager.restoreNote(selectedNoteGUIDs.get(i));
4861 currentNoteGuid = "";
4862 listManager.loadNotesIndex();
4863 noteIndexUpdated(false);
4866 // Search a note for specific txt
4867 @SuppressWarnings("unused")
4868 private void findText() {
4870 find.setFocusOnTextField();
4872 @SuppressWarnings("unused")
4873 private void doFindText() {
4874 browserWindow.getBrowser().page().findText(find.getText(), find.getFlags());
4877 @SuppressWarnings("unused")
4878 private void updateNoteTitle(String guid, String title) {
4879 listManager.setNoteSynchronized(guid, false);
4881 // We do this manually because if we've edited the note in an
4882 // external window we run into the possibility of signal recursion
4884 if (guid.equals(currentNoteGuid)) {
4885 browserWindow.titleLabel.blockSignals(true);
4886 browserWindow.titleLabel.setText(title);
4887 browserWindow.titleLabel.blockSignals(false);
4890 // Signal received that note content has changed. Normally we just need the guid to remove
4891 // it from the cache.
4892 @SuppressWarnings("unused")
4893 private void invalidateNoteCache(String guid, String content) {
4894 noteCache.remove(guid);
4895 refreshEvernoteNote(true);
4897 // Signal received that a note guid has changed
4898 @SuppressWarnings("unused")
4899 private void noteGuidChanged(String oldGuid, String newGuid) {
4900 if (noteCache.containsKey(oldGuid)) {
4901 if (!oldGuid.equals(currentNoteGuid)) {
4902 String cache = noteCache.get(oldGuid);
4903 noteCache.put(newGuid, cache);
4904 noteCache.remove(oldGuid);
4906 noteCache.remove(oldGuid);
4907 noteCache.put(newGuid, browserWindow.getContent());
4911 listManager.updateNoteGuid(oldGuid, newGuid, false);
4912 if (currentNoteGuid.equals(oldGuid)) {
4913 if (currentNote != null)
4914 currentNote.setGuid(newGuid);
4915 currentNoteGuid = newGuid;
4918 if (externalWindows.containsKey(oldGuid)) {
4919 ExternalBrowse b = externalWindows.get(oldGuid);
4920 externalWindows.remove(oldGuid);
4921 b.getBrowserWindow().getNote().setGuid(newGuid);
4922 externalWindows.put(newGuid, b);
4925 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
4926 if (listManager.getNoteIndex().get(i).getGuid().equals(newGuid)) {
4927 noteTableView.proxyModel.addGuid(newGuid, listManager.getNoteMetadata().get(newGuid));
4928 i=listManager.getNoteIndex().size();
4932 if (listManager.getNoteTableModel().metaData.containsKey(oldGuid)) {
4933 NoteMetadata meta = listManager.getNoteTableModel().metaData.get(oldGuid);
4934 listManager.getNoteTableModel().metaData.put(newGuid, meta);
4935 listManager.getNoteTableModel().metaData.remove(oldGuid);
4939 // Toggle the note editor button bar
4940 private void toggleEditorButtonBar() {
4941 if (browserWindow.buttonsVisible) {
4942 browserWindow.hideButtons();
4943 menuBar.showEditorBar.setChecked(browserWindow.buttonsVisible);
4944 // Global.saveWindowVisible("editorButtonBar", browserWindow.buttonsVisible);
4946 browserWindow.buttonsVisible = true;
4947 showEditorButtons(browserWindow);
4949 Global.saveWindowVisible("editorButtonBar", browserWindow.buttonsVisible);
4951 // Show editor buttons
4952 private void showEditorButtons(BrowserWindow browser) {
4953 browser.buttonLayout.setVisible(true);
4954 browser.undoAction.setVisible(false);
4956 browser.undoButton.setVisible(false);
4958 browser.undoAction.setVisible(Global.isEditorButtonVisible("undo"));
4959 browser.redoAction.setVisible(Global.isEditorButtonVisible("redo"));
4960 browser.cutAction.setVisible(Global.isEditorButtonVisible("cut"));
4961 browser.copyAction.setVisible(Global.isEditorButtonVisible("copy"));
4962 browser.pasteAction.setVisible(Global.isEditorButtonVisible("paste"));
4963 browser.strikethroughAction.setVisible(Global.isEditorButtonVisible("strikethrough"));
4964 browser.underlineAction.setVisible(Global.isEditorButtonVisible("underline"));
4965 browser.boldAction.setVisible(Global.isEditorButtonVisible("bold"));
4966 browser.italicAction.setVisible(Global.isEditorButtonVisible("italic"));
4967 browser.hlineAction.setVisible(Global.isEditorButtonVisible("hline"));
4968 browser.indentAction.setVisible(Global.isEditorButtonVisible("indent"));
4969 browser.outdentAction.setVisible(Global.isEditorButtonVisible("outdent"));
4970 browser.bulletListAction.setVisible(Global.isEditorButtonVisible("bulletList"));
4971 browser.numberListAction.setVisible(Global.isEditorButtonVisible("numberList"));
4972 browser.fontListAction.setVisible(Global.isEditorButtonVisible("font"));
4973 browser.fontSizeAction.setVisible(Global.isEditorButtonVisible("fontSize"));
4974 browser.fontColorAction.setVisible(Global.isEditorButtonVisible("fontColor"));
4975 browser.fontHilightAction.setVisible(Global.isEditorButtonVisible("fontHilight"));
4976 browser.leftAlignAction.setVisible(Global.isEditorButtonVisible("alignLeft"));
4977 browser.centerAlignAction.setVisible(Global.isEditorButtonVisible("alignCenter"));
4978 browser.rightAlignAction.setVisible(Global.isEditorButtonVisible("alignRight"));
4979 browser.spellCheckAction.setVisible(Global.isEditorButtonVisible("spellCheck"));
4980 browser.todoAction.setVisible(Global.isEditorButtonVisible("todo"));
4982 private void duplicateNote(String guid) {
4984 Note oldNote = conn.getNoteTable().getNote(guid, true, false,false,false,true);
4985 List<Resource> resList = conn.getNoteTable().noteResourceTable.getNoteResources(guid, true);
4986 oldNote.setContent(conn.getNoteTable().getNoteContentNoUTFConversion(guid));
4987 oldNote.setResources(resList);
4988 duplicateNote(oldNote);
4990 private void duplicateNote(Note oldNote) {
4992 // Now that we have a good notebook guid, we need to move the conflicting note
4993 // to the local notebook
4994 Calendar currentTime = new GregorianCalendar();
4995 Long l = new Long(currentTime.getTimeInMillis());
4996 String newGuid = new String(Long.toString(l));
4998 // Note newNote = oldNote.deepCopy();
4999 Note newNote = (Note)Global.deepCopy(oldNote);
5000 newNote.setUpdateSequenceNum(0);
5001 newNote.setGuid(newGuid);
5002 newNote.setDeleted(0);
5003 newNote.setActive(true);
5006 List<String> tagNames = new ArrayList<String>();
5007 List<String> tagGuids = new ArrayList<String>();;
5008 for (int i=0; i<oldNote.getTagGuidsSize(); i++) {
5009 tagNames.add(oldNote.getTagNames().get(i));
5010 tagGuids.add(oldNote.getTagGuids().get(i));
5013 // Sort note Tags to make them look nice
5014 for (int i=0; i<tagNames.size()-1; i++) {
5015 if (tagNames.get(i).compareTo(tagNames.get(i+1))<0) {
5016 String n1 = tagNames.get(i);
5017 String n2 = tagNames.get(i+1);
5018 tagNames.set(i, n2);
5019 tagNames.set(i+1, n1);
5022 newNote.setTagGuids(tagGuids);
5023 newNote.setTagNames(tagNames);
5025 // Add tag guids to note
5028 // Duplicate resources
5029 List<Resource> resList = oldNote.getResources();
5030 if (resList == null)
5031 resList = new ArrayList<Resource>();
5033 for (int i=0; i<resList.size(); i++) {
5035 while (l == prevGuid) {
5036 currentTime = new GregorianCalendar();
5037 l = new Long(currentTime.getTimeInMillis());
5040 String newResGuid = new String(Long.toString(l));
5041 resList.get(i).setNoteGuid(newGuid);
5042 resList.get(i).setGuid(newResGuid);
5043 resList.get(i).setUpdateSequenceNum(0);
5044 resList.get(i).setActive(true);
5045 conn.getNoteTable().noteResourceTable.saveNoteResource(
5046 (Resource)Global.deepCopy(resList.get(i)), true);
5048 newNote.setResources(resList);
5050 // Add note to the database
5051 conn.getNoteTable().addNote(newNote, true);
5052 NoteMetadata metaData = new NoteMetadata();
5053 NoteMetadata oldMeta = listManager.getNoteMetadata().get(oldNote.getGuid());
5054 metaData.copy(oldMeta);
5055 metaData.setGuid(newNote.getGuid());
5056 listManager.addNote(newNote, metaData);
5057 noteTableView.insertRow(newNote, metaData, true, -1);
5058 currentNoteGuid = newNote.getGuid();
5059 currentNote = newNote;
5060 refreshEvernoteNote(true);
5061 listManager.countNotebookResults(listManager.getNoteIndex());
5065 @SuppressWarnings("unused")
5066 private void allNotes() {
5067 clearAttributeFilter();
5068 clearNotebookFilter();
5069 clearSavedSearchFilter();
5072 searchField.clear();
5073 if (Global.mimicEvernoteInterface) {
5074 notebookTree.selectGuid("");
5076 notebookTreeSelection();
5077 refreshEvernoteNote(true);
5080 @SuppressWarnings("unused")
5081 private void mergeNotes() {
5082 logger.log(logger.HIGH, "Merging notes");
5085 String masterGuid = null;
5086 List<String> sources = new ArrayList<String>();
5088 for (int i=0; i<noteTableView.selectionModel().selectedRows().size(); i++) {
5089 int r = noteTableView.selectionModel().selectedRows().get(i).row();
5090 index = noteTableView.proxyModel.index(r, Global.noteTableGuidPosition);
5091 SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
5093 masterGuid = (String)ix.values().toArray()[0];
5095 sources.add((String)ix.values().toArray()[0]);
5098 logger.log(logger.EXTREME, "Master guid=" +masterGuid);
5099 logger.log(logger.EXTREME, "Children count: "+sources.size());
5100 mergeNoteContents(masterGuid, sources);
5101 currentNoteGuid = masterGuid;
5102 noteIndexUpdated(false);
5103 refreshEvernoteNote(true);
5106 private void mergeNoteContents(String targetGuid, List<String> sources) {
5107 Note target = conn.getNoteTable().getNote(targetGuid, true, false, false, false, false);
5108 String newContent = target.getContent();
5109 newContent = newContent.replace("</en-note>", "<br></br>");
5111 for (int i=0; i<sources.size(); i++) {
5112 Note source = conn.getNoteTable().getNote(sources.get(i), true, true, false, false, false);
5113 if (source.isSetTitle()) {
5114 newContent = newContent +("<table bgcolor=\"lightgrey\"><tr><td><font size=\"6\"><b>" +source.getTitle() +"</b></font></td></tr></table>");
5116 String sourceContent = source.getContent();
5117 logger.log(logger.EXTREME, "Merging contents into note");
5118 logger.log(logger.EXTREME, sourceContent);
5119 logger.log(logger.EXTREME, "End of content");
5120 int startOfNote = sourceContent.indexOf("<en-note>");
5121 sourceContent = sourceContent.substring(startOfNote+9);
5122 int endOfNote = sourceContent.indexOf("</en-note>");
5123 sourceContent = sourceContent.substring(0,endOfNote);
5124 newContent = newContent + sourceContent;
5125 logger.log(logger.EXTREME, "New note content");
5126 logger.log(logger.EXTREME, newContent);
5127 logger.log(logger.EXTREME, "End of content");
5128 for (int j=0; j<source.getResourcesSize(); j++) {
5129 logger.log(logger.EXTREME, "Reassigning resource: "+source.getResources().get(j).getGuid());
5130 Resource r = source.getResources().get(j);
5131 Resource newRes = conn.getNoteTable().noteResourceTable.getNoteResource(r.getGuid(), true);
5133 Calendar currentTime = new GregorianCalendar();
5134 Long l = new Long(currentTime.getTimeInMillis());
5138 while (l == prevGuid) {
5139 currentTime = new GregorianCalendar();
5140 l = new Long(currentTime.getTimeInMillis());
5142 String newResGuid = new String(Long.toString(l));
5143 newRes.setNoteGuid(targetGuid);
5144 newRes.setGuid(newResGuid);
5145 newRes.setUpdateSequenceNum(0);
5146 newRes.setActive(true);
5147 conn.getNoteTable().noteResourceTable.saveNoteResource(newRes, true);
5150 logger.log(logger.EXTREME, "Updating note");
5151 conn.getNoteTable().updateNoteContent(targetGuid, newContent +"</en-note>");
5152 for (int i=0; i<sources.size(); i++) {
5153 logger.log(logger.EXTREME, "Deleting note " +sources.get(i));
5154 listManager.deleteNote(sources.get(i));
5156 logger.log(logger.EXTREME, "Exiting merge note");
5158 // A resource within a note has had a guid change
5159 @SuppressWarnings("unused")
5160 private void noteResourceGuidChanged(String noteGuid, String oldGuid, String newGuid) {
5161 if (oldGuid != null && !oldGuid.equals(newGuid))
5162 Global.resourceMap.put(oldGuid, newGuid);
5164 // View a thumbnail of the note
5165 public void thumbnailView() {
5167 String thumbnailName = Global.getFileManager().getResDirPath("thumbnail-" + currentNoteGuid + ".png");
5168 QFile thumbnail = new QFile(thumbnailName);
5169 if (!thumbnail.exists()) {
5171 QImage img = new QImage();
5172 img.loadFromData(conn.getNoteTable().getThumbnail(currentNoteGuid));
5173 thumbnailViewer.setThumbnail(img);
5175 thumbnailViewer.setThumbnail(thumbnailName);
5176 if (!thumbnailViewer.isVisible())
5177 thumbnailViewer.showFullScreen();
5179 // An error happened while saving a note. Inform the user
5180 @SuppressWarnings("unused")
5181 private void saveRunnerError(String guid, String msg) {
5183 String title = "*Unknown*";
5184 for (int i=0; i<listManager.getMasterNoteIndex().size(); i++) {
5185 if (listManager.getMasterNoteIndex().get(i).getGuid().equals(guid)) {
5186 title = listManager.getMasterNoteIndex().get(i).getTitle();
5187 i=listManager.getMasterNoteIndex().size();
5190 msg = tr("An error has happened while saving the note \"") +title+
5191 tr("\".\n\nThis is probably due to a document that is too complex for NixNote to process. "+
5192 "As a result, changes to the note may not be saved properly in the database."+
5193 "\n\nA cached copy is being preserved so you can recover any data, but data may" +
5194 "\nbe lost. Please review the note to recover any critical data before restarting.");
5196 QMessageBox.information(this, tr("Error Saving Note"), tr(msg));
5199 private void thumbnailHTMLReady(String guid, QByteArray html, Integer zoom) {
5200 logger.log(logger.HIGH, "Entering thumnailHTMLReady()");
5201 logger.log(logger.HIGH, "Thumbnail ready for " +guid);
5202 // Find an idle preview object
5203 for (int i=0; i<thumbGenerators.size(); i++) {
5204 if (thumbGenerators.get(i).mutex.tryLock()) {
5205 logger.log(logger.EXTREME, "Idle generator found - loading thumbnail for " +guid);
5206 thumbGenerators.get(i).loadContent(guid, html, zoom);
5210 if (thumbGenerators.size() >= 1) {
5211 logger.log(logger.EXTREME, "No available thumbnail generators. Aborting " +guid);
5215 logger.log(logger.EXTREME, "Creating new thumbnail generator " +guid);
5216 Thumbnailer preview = new Thumbnailer(logger, conn, listManager, thumbnailRunner);
5217 thumbGenerators.add(preview);
5219 if (preview.mutex.tryLock()) {
5220 logger.log(logger.EXTREME, "Loading thumbnail for " +guid);
5221 preview.loadContent(guid, html, zoom);
5223 logger.log(logger.HIGH, "Exiting thumnailHTMLReady()");
5228 //**********************************************************
5229 //**********************************************************
5230 //* Online user actions
5231 //**********************************************************
5232 //**********************************************************
5233 private void setupOnlineMenu() {
5234 if (!Global.isConnected) {
5235 menuBar.noteOnlineHistoryAction.setEnabled(false);
5236 menuBar.selectiveSyncAction.setEnabled(false);
5239 menuBar.noteOnlineHistoryAction.setEnabled(true);
5240 menuBar.selectiveSyncAction.setEnabled(true);
5243 @SuppressWarnings("unused")
5244 private void viewNoteHistory() {
5245 if (currentNoteGuid == null || currentNoteGuid.equals(""))
5247 if (currentNote.getUpdateSequenceNum() == 0) {
5248 setMessage(tr("Note has never been synchronized."));
5249 QMessageBox.information(this, tr("Error"), tr("This note has never been sent to Evernote, so there is no history."));
5253 setMessage(tr("Getting Note History"));
5255 Note currentOnlineNote = null;
5258 if (Global.isPremium())
5259 versions = syncRunner.localNoteStore.listNoteVersions(syncRunner.authToken, currentNoteGuid);
5261 versions = new ArrayList<NoteVersionId>();
5262 currentOnlineNote = syncRunner.localNoteStore.getNote(syncRunner.authToken, currentNoteGuid, true, true, false, false);
5263 } catch (EDAMUserException e) {
5264 setMessage("EDAMUserException: " +e.getMessage());
5266 } catch (EDAMSystemException e) {
5267 setMessage("EDAMSystemException: " +e.getMessage());
5269 } catch (EDAMNotFoundException e) {
5270 setMessage(tr("Note not found on server."));
5271 QMessageBox.information(this, tr("Error"), tr("This note could not be found on Evernote's servers."));
5273 } catch (TException e) {
5274 setMessage("EDAMTransactionException: " +e.getMessage());
5278 // If we've gotten this far, we have a good note.
5279 if (historyWindow == null) {
5280 historyWindow = new OnlineNoteHistory(logger, conn);
5281 historyWindow.historyCombo.activated.connect(this, "reloadHistoryWindow(String)");
5282 historyWindow.restoreAsNew.clicked.connect(this, "restoreHistoryNoteAsNew()");
5283 historyWindow.restore.clicked.connect(this, "restoreHistoryNote()");
5285 historyWindow.historyCombo.clear();
5287 boolean isDirty = conn.getNoteTable().isNoteDirty(currentNoteGuid);
5288 if (currentNote.getUpdateSequenceNum() != currentOnlineNote.getUpdateSequenceNum())
5290 historyWindow.setCurrent(isDirty);
5292 loadHistoryWindowContent(currentOnlineNote);
5293 historyWindow.load(versions);
5294 setMessage(tr("History retrieved"));
5296 historyWindow.exec();
5298 private Note reloadHistoryWindow(String selection) {
5300 String fmt = Global.getDateFormat() + " " + Global.getTimeFormat();
5301 String dateTimeFormat = new String(fmt);
5302 SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);
5306 for (int i=0; i<versions.size(); i++) {
5307 StringBuilder versionDate = new StringBuilder(simple.format(versions.get(i).getSaved()));
5308 if (versionDate.toString().equals(selection))
5312 if (index > -1 || selection.indexOf("Current") > -1) {
5313 Note historyNote = null;
5316 usn = versions.get(index).getUpdateSequenceNum();
5317 historyNote = syncRunner.localNoteStore.getNoteVersion(syncRunner.authToken, currentNoteGuid, usn, true, true, true);
5319 historyNote = syncRunner.localNoteStore.getNote(syncRunner.authToken, currentNoteGuid, true,true,true,true);
5320 } catch (EDAMUserException e) {
5321 setMessage("EDAMUserException: " +e.getMessage());
5324 } catch (EDAMSystemException e) {
5325 setMessage("EDAMSystemException: " +e.getMessage());
5328 } catch (EDAMNotFoundException e) {
5329 setMessage("EDAMNotFoundException: " +e.getMessage());
5332 } catch (TException e) {
5333 setMessage("EDAMTransactionException: " +e.getMessage());
5339 if (historyNote != null)
5340 historyWindow.setContent(historyNote);
5346 private void loadHistoryWindowContent(Note note) {
5347 note.setUpdateSequenceNum(0);
5348 historyWindow.setContent(note);
5350 @SuppressWarnings("unused")
5351 private void restoreHistoryNoteAsNew() {
5352 setMessage(tr("Restoring as new note."));
5353 duplicateNote(reloadHistoryWindow(historyWindow.historyCombo.currentText()));
5354 setMessage(tr("Note has been restored as a new note."));
5356 @SuppressWarnings("unused")
5357 private void restoreHistoryNote() {
5358 setMessage(tr("Restoring note."));
5359 Note n = reloadHistoryWindow(historyWindow.historyCombo.currentText());
5360 conn.getNoteTable().expungeNote(n.getGuid(), true, false);
5363 for (int i=0; i<n.getResourcesSize(); i++) {
5364 n.getResources().get(i).setActive(true);
5365 conn.getNoteTable().noteResourceTable.saveNoteResource(n.getResources().get(i), true);
5367 NoteMetadata metadata = new NoteMetadata();
5368 metadata.setGuid(n.getGuid());
5369 listManager.addNote(n, metadata);
5370 conn.getNoteTable().addNote(n, true);
5371 refreshEvernoteNote(true);
5372 setMessage(tr("Note has been restored."));
5374 @SuppressWarnings("unused")
5375 private void setupSelectiveSync() {
5377 // Get a list of valid notebooks
5378 List<Notebook> notebooks = null;
5379 List<Tag> tags = null;
5380 List<LinkedNotebook> linkedNotebooks = null;
5382 notebooks = syncRunner.localNoteStore.listNotebooks(syncRunner.authToken);
5383 tags = syncRunner.localNoteStore.listTags(syncRunner.authToken);
5384 linkedNotebooks = syncRunner.localNoteStore.listLinkedNotebooks(syncRunner.authToken);
5385 } catch (EDAMUserException e) {
5386 setMessage("EDAMUserException: " +e.getMessage());
5388 } catch (EDAMSystemException e) {
5389 setMessage("EDAMSystemException: " +e.getMessage());
5391 } catch (TException e) {
5392 setMessage("EDAMTransactionException: " +e.getMessage());
5394 } catch (EDAMNotFoundException e) {
5395 setMessage("EDAMNotFoundException: " +e.getMessage());
5399 // Split up notebooks into synchronized & non-synchronized
5400 List<Notebook> ignoredBooks = new ArrayList<Notebook>();
5401 List<String> dbIgnoredNotebooks = conn.getSyncTable().getIgnoreRecords("NOTEBOOK");
5403 for (int i=notebooks.size()-1; i>=0; i--) {
5404 for (int j=0; j<dbIgnoredNotebooks.size(); j++) {
5405 if (notebooks.get(i).getGuid().equalsIgnoreCase(dbIgnoredNotebooks.get(j))) {
5406 ignoredBooks.add(notebooks.get(i));
5407 j=dbIgnoredNotebooks.size();
5412 // split up tags into synchronized & non-synchronized
5413 List<Tag> ignoredTags = new ArrayList<Tag>();
5414 List<String> dbIgnoredTags = conn.getSyncTable().getIgnoreRecords("TAG");
5416 for (int i=tags.size()-1; i>=0; i--) {
5417 for (int j=0; j<dbIgnoredTags.size(); j++) {
5418 if (tags.get(i).getGuid().equalsIgnoreCase(dbIgnoredTags.get(j))) {
5419 ignoredTags.add(tags.get(i));
5420 j=dbIgnoredTags.size();
5425 // split up linked notebooks into synchronized & non-synchronized
5426 List<LinkedNotebook> ignoredLinkedNotebooks = new ArrayList<LinkedNotebook>();
5427 List<String> dbIgnoredLinkedNotebooks = conn.getSyncTable().getIgnoreRecords("LINKEDNOTEBOOK");
5428 for (int i=linkedNotebooks.size()-1; i>=0; i--) {
5429 String notebookGuid = linkedNotebooks.get(i).getGuid();
5430 for (int j=0; j<dbIgnoredLinkedNotebooks.size(); j++) {
5431 if (notebookGuid.equalsIgnoreCase(dbIgnoredLinkedNotebooks.get(j))) {
5432 ignoredLinkedNotebooks.add(linkedNotebooks.get(i));
5433 j=dbIgnoredLinkedNotebooks.size();
5438 IgnoreSync ignore = new IgnoreSync(notebooks, ignoredBooks, tags, ignoredTags, linkedNotebooks, ignoredLinkedNotebooks);
5440 if (!ignore.okClicked())
5445 // Clear out old notebooks & add the new ones
5446 List<String> oldIgnoreNotebooks = conn.getSyncTable().getIgnoreRecords("NOTEBOOK");
5447 for (int i=0; i<oldIgnoreNotebooks.size(); i++) {
5448 conn.getSyncTable().deleteRecord("IGNORENOTEBOOK-"+oldIgnoreNotebooks.get(i));
5451 List<String> newNotebooks = new ArrayList<String>();
5452 for (int i=ignore.getIgnoredBookList().count()-1; i>=0; i--) {
5453 String text = ignore.getIgnoredBookList().takeItem(i).text();
5454 for (int j=0; j<notebooks.size(); j++) {
5455 if (notebooks.get(j).getName().equalsIgnoreCase(text)) {
5456 Notebook n = notebooks.get(j);
5457 conn.getSyncTable().addRecord("IGNORENOTEBOOK-"+n.getGuid(), n.getGuid());
5459 newNotebooks.add(n.getGuid());
5464 // Clear out old tags & add new ones
5465 List<String> oldIgnoreTags = conn.getSyncTable().getIgnoreRecords("TAG");
5466 for (int i=0; i<oldIgnoreTags.size(); i++) {
5467 conn.getSyncTable().deleteRecord("IGNORETAG-"+oldIgnoreTags.get(i));
5470 List<String> newTags = new ArrayList<String>();
5471 for (int i=ignore.getIgnoredTagList().count()-1; i>=0; i--) {
5472 String text = ignore.getIgnoredTagList().takeItem(i).text();
5473 for (int j=0; j<tags.size(); j++) {
5474 if (tags.get(j).getName().equalsIgnoreCase(text)) {
5475 Tag t = tags.get(j);
5476 conn.getSyncTable().addRecord("IGNORETAG-"+t.getGuid(), t.getGuid());
5477 newTags.add(t.getGuid());
5483 // Clear out old tags & add new ones
5484 List<String> oldIgnoreLinkedNotebooks = conn.getSyncTable().getIgnoreRecords("LINKEDNOTEBOOK");
5485 for (int i=0; i<oldIgnoreLinkedNotebooks.size(); i++) {
5486 conn.getSyncTable().deleteRecord("IGNORELINKEDNOTEBOOK-"+oldIgnoreLinkedNotebooks.get(i));
5489 List<String> newLinked = new ArrayList<String>();
5490 for (int i=ignore.getIgnoredLinkedNotebookList().count()-1; i>=0; i--) {
5491 String text = ignore.getIgnoredLinkedNotebookList().takeItem(i).text();
5492 for (int j=0; j<linkedNotebooks.size(); j++) {
5493 if (linkedNotebooks.get(j).getShareName().equalsIgnoreCase(text)) {
5494 LinkedNotebook t = linkedNotebooks.get(j);
5495 conn.getSyncTable().addRecord("IGNORELINKEDNOTEBOOK-"+t.getGuid(), t.getGuid());
5496 newLinked.add(t.getGuid());
5497 j=linkedNotebooks.size();
5502 conn.getNoteTable().expungeIgnoreSynchronizedNotes(newNotebooks, newTags, newLinked);
5508 //**********************************************************
5509 //**********************************************************
5510 //* XML Modifying methods
5511 //**********************************************************
5512 //**********************************************************
5513 // An error has happended fetching a resource. let the user know
5514 private void resourceErrorMessage() {
5518 QMessageBox.information(this, tr("DOUGH!!!"), tr("Well, this is embarrassing."+
5519 "\n\nSome attachments or images for this note appear to be missing from my database.\n"+
5520 "In a perfect world this wouldn't happen, but it has.\n" +
5521 "It is embarasing when a program like me, designed to save all your\n"+
5522 "precious data, has a problem finding data.\n\n" +
5523 "I guess life isn't fair, but I'll survive. Somehow...\n\n" +
5524 "In the mean time, I'm not going to let you make changes to this note.\n" +
5525 "Don't get angry. I'm doing it to prevent you from messing up\n"+
5526 "this note on the Evernote servers. Sorry."+
5527 "\n\nP.S. You might want to re-synchronize to see if it corrects this problem.\nWho knows, you might get lucky."));
5529 browserWindow.setReadOnly(true);
5536 //**********************************************************
5537 //**********************************************************
5539 //**********************************************************
5540 //**********************************************************
5541 // We should now do a sync with Evernote
5542 private void syncTimer() {
5543 logger.log(logger.EXTREME, "Entering NeverNote.syncTimer()");
5544 syncRunner.syncNeeded = true;
5545 syncRunner.disableUploads = Global.disableUploads;
5547 logger.log(logger.EXTREME, "Leaving NeverNote.syncTimer()");
5549 private void syncStart() {
5550 logger.log(logger.EXTREME, "Entering NeverNote.syncStart()");
5552 if (!syncRunning && Global.isConnected) {
5553 syncRunner.setConnected(true);
5554 syncRunner.setKeepRunning(Global.keepRunning);
5555 syncRunner.syncDeletedContent = Global.synchronizeDeletedContent();
5557 if (syncThreadsReady > 0) {
5558 thumbnailRunner.interrupt = true;
5559 saveNoteIndexWidth();
5560 saveNoteColumnPositions();
5561 if (syncRunner.addWork("SYNC")) {
5563 syncRunner.syncNeeded = true;
5568 logger.log(logger.EXTREME, "Leaving NeverNote.syncStart");
5570 @SuppressWarnings("unused")
5571 private void syncThreadComplete(Boolean refreshNeeded) {
5572 setMessage(tr("Finalizing Synchronization"));
5574 syncRunning = false;
5575 syncRunner.syncNeeded = false;
5576 synchronizeAnimationTimer.stop();
5577 synchronizeButton.setIcon(new QIcon(iconPath+"synchronize.png"));
5579 if (currentNote == null) {
5580 currentNote = conn.getNoteTable().getNote(currentNoteGuid, false, false, false, false, true);
5582 listManager.refreshNoteMetadata();
5583 noteIndexUpdated(true);
5584 noteTableView.selectionModel().blockSignals(true);
5585 scrollToGuid(currentNoteGuid);
5586 noteTableView.selectionModel().blockSignals(false);
5587 refreshEvernoteNote(false);
5588 scrollToGuid(currentNoteGuid);
5591 // Check to see if there were any shared notebook errors
5592 if (syncRunner.error && syncRunner.errorSharedNotebooks.size() > 0) {
5593 String guid = syncRunner.errorSharedNotebooks.get(0);
5594 String notebookGuid = conn.getLinkedNotebookTable().getLocalNotebookGuid(guid);
5595 String localName = listManager.getNotebookNameByGuid(notebookGuid);
5596 SharedNotebookSyncError syncDialog = new SharedNotebookSyncError(localName);
5598 if (syncDialog.okPressed()) {
5599 if (syncDialog.doNothing.isChecked()) {
5600 syncRunner.errorSharedNotebooksIgnored.put(guid, guid);
5603 if (syncDialog.deleteNotebook.isChecked()) {
5604 conn.getNoteTable().expungeNotesByNotebook(notebookGuid, true, false);
5605 conn.getNotebookTable().expungeNotebook(notebookGuid, false);
5606 conn.getLinkedNotebookTable().expungeNotebook(guid, false);
5607 conn.getLinkedNotebookTable().expungeNotebook(guid, false);
5615 // Finalize the synchronization
5616 if (!syncRunner.error)
5617 setMessage(tr("Synchronization Complete"));
5619 setMessage(tr("Synchronization completed with errors. Please check the log for details."));
5620 logger.log(logger.MEDIUM, "Sync complete.");
5622 public void saveUploadAmount(long t) {
5623 Global.saveUploadAmount(t);
5625 public void saveUserInformation(User user) {
5626 Global.saveUserInformation(user);
5628 public void saveEvernoteUpdateCount(int i) {
5629 Global.saveEvernoteUpdateCount(i);
5631 public void refreshLists() {
5632 logger.log(logger.EXTREME, "Entering NeverNote.refreshLists");
5634 listManager.refreshLists(currentNote, noteDirty, browserWindow.getContent());
5635 tagIndexUpdated(true);
5636 notebookIndexUpdated();
5637 savedSearchIndexUpdated();
5638 listManager.loadNotesIndex();
5640 noteTableView.selectionModel().blockSignals(true);
5641 noteIndexUpdated(true);
5642 noteTableView.selectionModel().blockSignals(false);
5643 logger.log(logger.EXTREME, "Leaving NeverNote.refreshLists");
5647 @SuppressWarnings("unused")
5648 private void authTimer() {
5649 Calendar cal = Calendar.getInstance();
5651 // If we are not connected let's get out of here
5652 if (!Global.isConnected)
5655 // If this is the first time through, then we need to set this
5656 // if (syncRunner.authRefreshTime == 0 || cal.getTimeInMillis() > syncRunner.authRefreshTime)
5657 // syncRunner.authRefreshTime = cal.getTimeInMillis();
5659 // long now = new Date().getTime();
5660 // if (now > Global.authRefreshTime && Global.isConnected) {
5661 syncRunner.authRefreshNeeded = true;
5665 @SuppressWarnings("unused")
5666 private void authRefreshComplete(boolean goodSync) {
5667 logger.log(logger.EXTREME, "Entering NeverNote.authRefreshComplete");
5668 Global.isConnected = syncRunner.isConnected;
5670 // authTimer.start((int)syncRunner.authTimeRemaining/4);
5671 authTimer.start(1000*60*15);
5672 logger.log(logger.LOW, "Authentication token has been renewed");
5673 // setMessage("Authentication token has been renewed.");
5675 authTimer.start(1000*60*5);
5676 logger.log(logger.LOW, "Authentication token renew has failed - retry in 5 minutes.");
5677 // setMessage("Authentication token renew has failed - retry in 5 minutes.");
5679 logger.log(logger.EXTREME, "Leaving NeverNote.authRefreshComplete");
5683 @SuppressWarnings("unused")
5684 private synchronized void indexTimer() {
5685 logger.log(logger.EXTREME, "Index timer activated. Sync running="+syncRunning);
5688 if (!indexDisabled && indexRunner.idle) {
5689 thumbnailRunner.interrupt = true;
5690 indexRunner.addWork("SCAN");
5692 logger.log(logger.EXTREME, "Leaving NixNote index timer");
5695 @SuppressWarnings("unused")
5696 private void indexStarted() {
5697 setMessage(tr("Indexing notes"));
5699 @SuppressWarnings("unused")
5700 private void indexComplete() {
5701 setMessage(tr("Index complete"));
5703 @SuppressWarnings("unused")
5704 private synchronized void toggleNoteIndexing() {
5705 logger.log(logger.HIGH, "Entering NeverNote.toggleIndexing");
5706 indexDisabled = !indexDisabled;
5708 setMessage(tr("Indexing is now enabled."));
5710 setMessage(tr("Indexing is now disabled."));
5711 menuBar.disableIndexing.setChecked(indexDisabled);
5712 logger.log(logger.HIGH, "Leaving NeverNote.toggleIndexing");
5715 @SuppressWarnings("unused")
5716 private void threadMonitorCheck() {
5721 alive = listManager.threadCheck(Global.tagCounterThreadId);
5724 if (tagDeadCount > MAX && !disableTagThreadCheck) {
5725 QMessageBox.information(this, tr("A thread has died."), tr("It appears as the tag counter thread has died. I recommend "+
5726 "checking stopping NixNote, saving the logs for later viewing, and restarting. Sorry."));
5727 disableTagThreadCheck = true;
5732 alive = listManager.threadCheck(Global.notebookCounterThreadId);
5734 notebookThreadDeadCount++;
5735 if (notebookThreadDeadCount > MAX && !disableNotebookThreadCheck) {
5736 QMessageBox.information(this, tr("A thread has died."), tr("It appears as the notebook counter thread has died. I recommend "+
5737 "checking stopping NixNote, saving the logs for later viewing, and restarting. Sorry."));
5738 disableNotebookThreadCheck=true;
5741 notebookThreadDeadCount=0;
5743 alive = listManager.threadCheck(Global.trashCounterThreadId);
5746 if (trashDeadCount > MAX && !disableTrashThreadCheck) {
5747 QMessageBox.information(this, tr("A thread has died."), ("It appears as the trash counter thread has died. I recommend "+
5748 "checking stopping NixNote, saving the logs for later viewing, and restarting. Sorry."));
5749 disableTrashThreadCheck = true;
5754 alive = listManager.threadCheck(Global.saveThreadId);
5756 saveThreadDeadCount++;
5757 if (saveThreadDeadCount > MAX && !disableSaveThreadCheck) {
5758 QMessageBox.information(this, tr("A thread has died."), tr("It appears as the note saver thread has died. I recommend "+
5759 "checking stopping NixNote, saving the logs for later viewing, and restarting. Sorry."));
5760 disableSaveThreadCheck = true;
5763 saveThreadDeadCount=0;
5765 if (!syncThread.isAlive()) {
5766 syncThreadDeadCount++;
5767 if (syncThreadDeadCount > MAX && !disableSyncThreadCheck) {
5768 QMessageBox.information(this, tr("A thread has died."), tr("It appears as the synchronization thread has died. I recommend "+
5769 "checking stopping NixNote, saving the logs for later viewing, and restarting. Sorry."));
5770 disableSyncThreadCheck = true;
5773 syncThreadDeadCount=0;
5775 if (!indexThread.isAlive()) {
5776 indexThreadDeadCount++;
5777 if (indexThreadDeadCount > MAX && !disableIndexThreadCheck) {
5778 QMessageBox.information(this, tr("A thread has died."), tr("It appears as the index thread has died. I recommend "+
5779 "checking stopping NixNote, saving the logs for later viewing, and restarting. Sorry."));
5780 disableIndexThreadCheck = true;
5783 indexThreadDeadCount=0;
5788 private void thumbnailTimer() {
5789 if (Global.enableThumbnails() && !syncRunning && indexRunner.idle) {
5790 thumbnailRunner.addWork("SCAN");
5794 //**************************************************
5795 //* Backup & Restore
5796 //**************************************************
5797 @SuppressWarnings("unused")
5798 private void databaseBackup() {
5799 QFileDialog fd = new QFileDialog(this);
5800 fd.setFileMode(FileMode.AnyFile);
5801 fd.setConfirmOverwrite(true);
5802 fd.setWindowTitle(tr("Backup Database"));
5803 fd.setFilter(tr("NixNote Export (*.nnex);;All Files (*.*)"));
5804 fd.setAcceptMode(AcceptMode.AcceptSave);
5805 if (saveLastPath == null || saveLastPath.equals(""))
5806 fd.setDirectory(System.getProperty("user.home"));
5808 fd.setDirectory(saveLastPath);
5809 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
5815 saveLastPath = fd.selectedFiles().get(0);
5816 saveLastPath = saveLastPath.substring(0,saveLastPath.lastIndexOf("/"));
5817 setMessage(tr("Backing up database"));
5819 // conn.backupDatabase(Global.getUpdateSequenceNumber(), Global.getSequenceDate());
5821 ExportData noteWriter = new ExportData(conn, true);
5822 String fileName = fd.selectedFiles().get(0);
5824 if (!fileName.endsWith(".nnex"))
5825 fileName = fileName +".nnex";
5826 noteWriter.exportData(fileName);
5827 setMessage(tr("Database backup completed."));
5832 @SuppressWarnings("unused")
5833 private void databaseRestore() {
5834 if (QMessageBox.question(this, tr("Confirmation"),
5835 tr("This is used to restore a database from backups.\n" +
5836 "It is HIGHLY recommened that this only be used to populate\n" +
5837 "an empty database. Restoring into a database that\n already has data" +
5838 " can cause problems.\n\nAre you sure you want to continue?"),
5839 QMessageBox.StandardButton.Yes,
5840 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
5845 QFileDialog fd = new QFileDialog(this);
5846 fd.setFileMode(FileMode.ExistingFile);
5847 fd.setConfirmOverwrite(true);
5848 fd.setWindowTitle(tr("Restore Database"));
5849 fd.setFilter(tr("NixNote Export (*.nnex);;All Files (*.*)"));
5850 fd.setAcceptMode(AcceptMode.AcceptOpen);
5851 if (saveLastPath == null || saveLastPath.equals(""))
5852 fd.setDirectory(System.getProperty("user.home"));
5854 fd.setDirectory(saveLastPath);
5855 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
5861 saveLastPath = fd.selectedFiles().get(0);
5862 saveLastPath = saveLastPath.substring(0,saveLastPath.lastIndexOf("/"));
5864 setMessage(tr("Restoring database"));
5865 ImportData noteReader = new ImportData(conn, true);
5866 noteReader.importData(fd.selectedFiles().get(0));
5868 if (noteReader.lastError != 0) {
5869 setMessage(noteReader.getErrorMessage());
5870 logger.log(logger.LOW, "Restore problem: " +noteReader.lastError);
5875 listManager.loadNoteTitleColors();
5877 refreshEvernoteNote(true);
5878 setMessage(tr("Database has been restored."));
5881 @SuppressWarnings("unused")
5882 private void exportNotes() {
5883 QFileDialog fd = new QFileDialog(this);
5884 fd.setFileMode(FileMode.AnyFile);
5885 fd.setConfirmOverwrite(true);
5886 fd.setWindowTitle(tr("Backup Database"));
5887 fd.setFilter(tr("NixNote Export (*.nnex);;All Files (*.*)"));
5888 fd.setAcceptMode(AcceptMode.AcceptSave);
5889 fd.setDirectory(System.getProperty("user.home"));
5890 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
5896 setMessage(tr("Exporting Notes"));
5899 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
5900 selectedNoteGUIDs.add(currentNoteGuid);
5902 ExportData noteWriter = new ExportData(conn, false, selectedNoteGUIDs);
5903 String fileName = fd.selectedFiles().get(0);
5905 if (!fileName.endsWith(".nnex"))
5906 fileName = fileName +".nnex";
5907 noteWriter.exportData(fileName);
5908 setMessage(tr("Export completed."));
5914 @SuppressWarnings("unused")
5915 private void importNotes() {
5916 QFileDialog fd = new QFileDialog(this);
5917 fd.setFileMode(FileMode.ExistingFile);
5918 fd.setConfirmOverwrite(true);
5919 fd.setWindowTitle(tr("Import Notes"));
5920 fd.setFilter(tr("NixNote Export (*.nnex);;Evernote Export (*.enex);;All Files (*.*)"));
5921 fd.setAcceptMode(AcceptMode.AcceptOpen);
5922 if (saveLastPath == null || saveLastPath.equals(""))
5923 fd.setDirectory(System.getProperty("user.home"));
5925 fd.setDirectory(saveLastPath);
5926 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
5932 setMessage(tr("Importing Notes"));
5935 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
5936 selectedNoteGUIDs.add(currentNoteGuid);
5938 String fileName = fd.selectedFiles().get(0);
5939 // saveLastPath.substring(0,fileName.lastIndexOf("/"));
5941 if (fileName.endsWith(".nnex")) {
5942 ImportData noteReader = new ImportData(conn, false);
5943 if (selectedNotebookGUIDs != null && selectedNotebookGUIDs.size() > 0)
5944 noteReader.setNotebookGuid(selectedNotebookGUIDs.get(0));
5946 noteReader.setNotebookGuid(listManager.getNotebookIndex().get(0).getGuid());
5948 noteReader.importData(fileName);
5950 if (noteReader.lastError != 0) {
5951 setMessage(noteReader.getErrorMessage());
5952 logger.log(logger.LOW, "Import problem: " +noteReader.lastError);
5957 if (fileName.endsWith(".enex")) {
5958 ImportEnex noteReader = new ImportEnex(conn, false);
5959 if (selectedNotebookGUIDs != null && selectedNotebookGUIDs.size() > 0)
5960 noteReader.setNotebookGuid(selectedNotebookGUIDs.get(0));
5962 noteReader.setNotebookGuid(listManager.getNotebookIndex().get(0).getGuid());
5965 if (QMessageBox.question(this, tr("Confirmation"),
5966 tr("Create new tags from import?"),
5967 QMessageBox.StandardButton.Yes,
5968 QMessageBox.StandardButton.No) == StandardButton.Yes.value()) {
5969 noteReader.createNewTags = true;
5971 noteReader.createNewTags = false;
5973 noteReader.importData(fileName);
5975 if (noteReader.lastError != 0) {
5976 setMessage(noteReader.getErrorMessage());
5977 logger.log(logger.LOW, "Import problem: " +noteReader.lastError);
5984 listManager.loadNoteTitleColors();
5986 refreshEvernoteNote(false);
5987 setMessage(tr("Notes have been imported."));
5990 setMessage(tr("Import completed."));
5997 //**************************************************
5998 //* Duplicate a note
5999 //**************************************************
6000 @SuppressWarnings("unused")
6001 private void duplicateNote() {
6003 duplicateNote(currentNoteGuid);
6006 //**************************************************
6007 //* Action from when a user clicks Copy As URL
6008 //**************************************************
6009 @SuppressWarnings("unused")
6010 private void copyAsUrlClicked() {
6011 QClipboard clipboard = QApplication.clipboard();
6012 QMimeData mime = new QMimeData();
6014 mime.setText(currentNoteGuid);
6015 List<QUrl> urls = new ArrayList<QUrl>();
6017 // Start building the URL
6018 User user = Global.getUserInformation();
6020 // Check that we have everything we need
6021 if ((user.getShardId().equals("") || user.getId() == 0) && !Global.bypassSynchronizationWarning()) {
6022 SynchronizationRequiredWarning warning = new SynchronizationRequiredWarning(this);
6024 if (!warning.neverSynchronize())
6027 Global.setBypassSynchronizationWarning(true);
6028 user.setShardId("s0");
6034 // Start building a list of URLs based upon the selected notes
6035 noteTableView.showColumn(Global.noteTableGuidPosition);
6037 List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
6038 if (!Global.isColumnVisible("guid"))
6039 noteTableView.hideColumn(Global.noteTableGuidPosition);
6041 // Check that the note is either synchronized, or in a local notebook
6042 for (int i=0; i<selections.size(); i++) {
6044 int row = selections.get(i).row();
6045 index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition);
6046 SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
6047 String selectedGuid = (String)ix.values().toArray()[0];
6049 Note n = conn.getNoteTable().getNote(selectedGuid, false, false, false, false, false);
6050 if (n.getUpdateSequenceNum() == 0 && !conn.getNotebookTable().isNotebookLocal(n.getNotebookGuid())) {
6051 QMessageBox.critical(this, tr("Please Synchronize") ,tr("Please either synchronize or move any " +
6052 "new notes to a local notebook."));
6057 // Start building the URLs
6058 for (int i=0; i<selections.size(); i++) {
6060 int row = selections.get(i).row();
6061 index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition);
6062 SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
6063 String selectedGuid = (String)ix.values().toArray()[0];
6064 mime.setText(selectedGuid);
6068 Note selectedNote = conn.getNoteTable().getNote(selectedGuid, false, false, false, false, false);
6069 if (selectedNote.getUpdateSequenceNum() > 0) {
6073 gid = "00000000-0000-0000-0000-000000000000";
6076 url = new String("evernote://///view/") + new String(user.getId() + "/" +user.getShardId() +"/"
6078 urls.add(new QUrl(url));
6081 clipboard.setMimeData(mime);
6085 //**************************************************
6087 //**************************************************
6088 public void setupFolderImports() {
6089 List<WatchFolderRecord> records = conn.getWatchFolderTable().getAll();
6091 if (importKeepWatcher == null)
6092 importKeepWatcher = new QFileSystemWatcher();
6093 if (importDeleteWatcher == null) {
6094 importDeleteWatcher = new QFileSystemWatcher();
6095 for (int i=0; i<records.size(); i++) {
6096 if (!records.get(i).keep)
6097 folderImportDelete(records.get(i).folder);
6103 // importKeepWatcher.addPath(records.get(i).folder.replace('\\', '/'));
6104 for (int i=0; i<records.size(); i++) {
6105 if (records.get(i).keep)
6106 importKeepWatcher.addPath(records.get(i).folder);
6108 importDeleteWatcher.addPath(records.get(i).folder);
6111 importKeepWatcher.directoryChanged.connect(this, "folderImportKeep(String)");
6112 importDeleteWatcher.directoryChanged.connect(this, "folderImportDelete(String)");
6114 // Look at the files already there so we don't import them again if a new file is created
6115 if (importedFiles == null) {
6116 importedFiles = new ArrayList<String>();
6117 for (int j=0; j<records.size(); j++) {
6118 QDir dir = new QDir(records.get(j).folder);
6119 List<QFileInfo> list = dir.entryInfoList();
6120 for (int k=0; k<list.size(); k++) {
6121 if (list.get(k).isFile())
6122 importedFiles.add(list.get(k).absoluteFilePath());
6127 public void folderImport() {
6128 List<WatchFolderRecord> recs = conn.getWatchFolderTable().getAll();
6129 WatchFolder dialog = new WatchFolder(recs, listManager.getNotebookIndex());
6131 if (!dialog.okClicked())
6134 // We have some sort of update.
6135 if (importKeepWatcher.directories().size() > 0)
6136 importKeepWatcher.removePaths(importKeepWatcher.directories());
6137 if (importDeleteWatcher.directories().size() > 0)
6138 importDeleteWatcher.removePaths(importDeleteWatcher.directories());
6140 conn.getWatchFolderTable().expungeAll();
6141 // Start building from the table
6142 for (int i=0; i<dialog.table.rowCount(); i++) {
6143 QTableWidgetItem item = dialog.table.item(i, 0);
6144 String dir = item.text();
6145 item = dialog.table.item(i, 1);
6146 String notebook = item.text();
6147 item = dialog.table.item(i, 2);
6149 if (item.text().equalsIgnoreCase("Keep"))
6154 String guid = conn.getNotebookTable().findNotebookByName(notebook);
6155 conn.getWatchFolderTable().addWatchFolder(dir, guid, keep, 0);
6157 setupFolderImports();
6160 public void folderImportKeep(String dirName) throws NoSuchAlgorithmException {
6162 String whichOS = System.getProperty("os.name");
6163 if (whichOS.contains("Windows"))
6164 dirName = dirName.replace('/','\\');
6166 FileImporter importer = new FileImporter(logger, conn);
6168 QDir dir = new QDir(dirName);
6169 List<QFileInfo> list = dir.entryInfoList();
6170 String notebook = conn.getWatchFolderTable().getNotebook(dirName);
6172 for (int i=0; i<list.size(); i++){
6174 boolean redundant = false;
6175 // Check if we've already imported this one or if it existed before
6176 for (int j=0; j<importedFiles.size(); j++) {
6177 if (importedFiles.get(j).equals(list.get(i).absoluteFilePath()))
6182 importer.setFileInfo(list.get(i));
6183 importer.setFileName(list.get(i).absoluteFilePath());
6186 if (list.get(i).isFile() && importer.isValidType()) {
6188 if (!importer.importFile()) {
6189 // If we can't get to the file, it is probably locked. We'll try again later.
6190 logger.log(logger.LOW, "Unable to save externally edited file. Saving for later.");
6191 importFilesKeep.add(list.get(i).absoluteFilePath());
6195 Note newNote = importer.getNote();
6196 newNote.setNotebookGuid(notebook);
6197 newNote.setTitle(dir.at(i));
6198 NoteMetadata metadata = new NoteMetadata();
6199 metadata.setDirty(true);
6200 metadata.setGuid(newNote.getGuid());
6201 listManager.addNote(newNote, metadata);
6202 conn.getNoteTable().addNote(newNote, true);
6203 noteTableView.insertRow(newNote, metadata, true, -1);
6204 listManager.updateNoteContent(newNote.getGuid(), importer.getNoteContent());
6205 listManager.countNotebookResults(listManager.getNoteIndex());
6206 importedFiles.add(list.get(i).absoluteFilePath());
6214 public void folderImportDelete(String dirName) {
6216 String whichOS = System.getProperty("os.name");
6217 if (whichOS.contains("Windows"))
6218 dirName = dirName.replace('/','\\');
6220 FileImporter importer = new FileImporter(logger, conn);
6221 QDir dir = new QDir(dirName);
6222 List<QFileInfo> list = dir.entryInfoList();
6223 String notebook = conn.getWatchFolderTable().getNotebook(dirName);
6225 for (int i=0; i<list.size(); i++){
6226 importer.setFileInfo(list.get(i));
6227 importer.setFileName(list.get(i).absoluteFilePath());
6229 if (list.get(i).isFile() && importer.isValidType()) {
6231 if (!importer.importFile()) {
6232 // If we can't get to the file, it is probably locked. We'll try again later.
6233 logger.log(logger.LOW, "Unable to save externally edited file. Saving for later.");
6234 importFilesKeep.add(list.get(i).absoluteFilePath());
6238 Note newNote = importer.getNote();
6239 newNote.setNotebookGuid(notebook);
6240 newNote.setTitle(dir.at(i));
6241 NoteMetadata metadata = new NoteMetadata();
6242 metadata.setDirty(true);
6243 metadata.setGuid(newNote.getGuid());
6244 listManager.addNote(newNote, metadata);
6245 conn.getNoteTable().addNote(newNote, true);
6246 noteTableView.insertRow(newNote, metadata, true, -1);
6247 listManager.updateNoteContent(newNote.getGuid(), importer.getNoteContent());
6248 listManager.countNotebookResults(listManager.getNoteIndex());
6249 dir.remove(dir.at(i));
6255 //**************************************************
6257 //**************************************************
6258 private void externalFileEdited(String fileName) throws NoSuchAlgorithmException {
6259 logger.log(logger.HIGH, "Entering exernalFileEdited");
6261 // Strip URL prefix and base dir path
6262 String dPath = FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath());
6263 String name = fileName.replace(dPath, "");
6264 int pos = name.lastIndexOf('.');
6267 guid = guid.substring(0,pos);
6269 pos = name.lastIndexOf(Global.attachmentNameDelimeter);
6271 guid = name.substring(0, pos);
6274 QFile file = new QFile(fileName);
6275 if (!file.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly))) {
6276 // If we can't get to the file, it is probably locked. We'll try again later.
6277 logger.log(logger.LOW, "Unable to save externally edited file. Saving for later.");
6278 externalFiles.add(fileName);
6281 QByteArray binData = file.readAll();
6283 if (binData.size() == 0) {
6284 // If we can't get to the file, it is probably locked. We'll try again later.
6285 logger.log(logger.LOW, "Unable to save externally edited file. Saving for later.");
6286 externalFiles.add(fileName);
6290 Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
6292 r = conn.getNoteTable().noteResourceTable.getNoteResource(Global.resourceMap.get(guid), true);
6293 if (r == null || r.getData() == null || r.getData().getBody() == null)
6295 String oldHash = Global.byteArrayToHexString(r.getData().getBodyHash());
6296 MessageDigest md = MessageDigest.getInstance("MD5");
6297 md.update(binData.toByteArray());
6298 byte[] hash = md.digest();
6299 String newHash = Global.byteArrayToHexString(hash);
6300 if (r.getNoteGuid().equalsIgnoreCase(currentNoteGuid)) {
6301 updateResourceContentHash(browserWindow, r.getGuid(), oldHash, newHash);
6303 if (externalWindows.containsKey(r.getNoteGuid())) {
6304 updateResourceContentHash(externalWindows.get(r.getNoteGuid()).getBrowserWindow(),
6305 r.getGuid(), oldHash, newHash);
6307 conn.getNoteTable().updateResourceContentHash(r.getNoteGuid(), oldHash, newHash);
6308 Data data = r.getData();
6309 data.setBody(binData.toByteArray());
6310 data.setBodyHash(hash);
6311 logger.log(logger.LOW, "externalFileEdited: " +data.getSize() +" bytes");
6313 conn.getNoteTable().noteResourceTable.updateNoteResource(r,true);
6315 if (r.getNoteGuid().equals(currentNoteGuid)) {
6316 QWebSettings.setMaximumPagesInCache(0);
6317 QWebSettings.setObjectCacheCapacities(0, 0, 0);
6318 refreshEvernoteNote(true);
6319 browserWindow.getBrowser().triggerPageAction(WebAction.Reload);
6322 if (externalWindows.containsKey(r.getNoteGuid())) {
6323 QWebSettings.setMaximumPagesInCache(0);
6324 QWebSettings.setObjectCacheCapacities(0, 0, 0);
6325 externalWindows.get(r.getNoteGuid()).getBrowserWindow().getBrowser().triggerPageAction(WebAction.Reload);
6329 logger.log(logger.HIGH, "Exiting externalFielEdited");
6331 // This is a timer event that tries to save any external files that were edited. This
6332 // is only needed if we couldn't save a file earlier.
6333 public void externalFileEditedSaver() {
6334 for (int i=externalFiles.size()-1; i>=0; i--) {
6336 logger.log(logger.MEDIUM, "Trying to save " +externalFiles.get(i));
6337 externalFileEdited(externalFiles.get(i));
6338 externalFiles.remove(i);
6339 } catch (NoSuchAlgorithmException e) {e.printStackTrace();}
6341 for (int i=0; i<importFilesKeep.size(); i++) {
6343 logger.log(logger.MEDIUM, "Trying to save " +importFilesKeep.get(i));
6344 folderImportKeep(importFilesKeep.get(i));
6345 importFilesKeep.remove(i);
6346 } catch (NoSuchAlgorithmException e) {e.printStackTrace();}
6348 for (int i=0; i<importFilesDelete.size(); i++) {
6349 logger.log(logger.MEDIUM, "Trying to save " +importFilesDelete.get(i));
6350 folderImportDelete(importFilesDelete.get(i));
6351 importFilesDelete.remove(i);
6358 // If an attachment on the current note was edited, we need to update the current notes's hash
6359 // Update a note content's hash. This happens if a resource is edited outside of NN
6360 public void updateResourceContentHash(BrowserWindow browser, String guid, String oldHash, String newHash) {
6361 int position = browserWindow.getContent().indexOf("en-tag=\"en-media\" guid=\""+guid+"\" type=");
6363 for (;position>-1;) {
6364 endPos = browser.getContent().indexOf(">", position+1);
6365 String oldSegment = browser.getContent().substring(position,endPos);
6366 int hashPos = oldSegment.indexOf("hash=\"");
6367 int hashEnd = oldSegment.indexOf("\"", hashPos+7);
6368 String hash = oldSegment.substring(hashPos+6, hashEnd);
6369 if (hash.equalsIgnoreCase(oldHash)) {
6370 String newSegment = oldSegment.replace(oldHash, newHash);
6371 String content = browser.getContent().substring(0,position) +
6373 browser.getContent().substring(endPos);
6374 browser.setContent(new QByteArray(content));;
6377 position = browser.getContent().indexOf("en-tag=\"en-media\" guid=\""+guid+"\" type=", position+1);
6382 //*************************************************
6383 //* Minimize to tray
6384 //*************************************************
6386 public void changeEvent(QEvent e) {
6387 if (e.type() == QEvent.Type.WindowStateChange) {
6388 if (QSystemTrayIcon.isSystemTrayAvailable()) {
6389 if (isMinimized() && (Global.showTrayIcon() || Global.showTrayIcon())) {
6391 QTimer.singleShot(10, this, "hide()");
6395 windowMaximized = true;
6397 windowMaximized = false;
6402 //*************************************************
6403 //* Check database userid & passwords
6404 //*************************************************
6405 private static boolean databaseCheck(String url,String userid, String userPassword, String cypherPassword) {
6406 Connection connection;
6409 Class.forName("org.h2.Driver");
6410 } catch (ClassNotFoundException e1) {
6411 e1.printStackTrace();
6416 String passwordString = null;
6417 if (cypherPassword==null || cypherPassword.trim().equals(""))
6418 passwordString = userPassword;
6420 passwordString = cypherPassword+" "+userPassword;
6421 connection = DriverManager.getConnection(url,userid,passwordString);
6422 } catch (SQLException e) {
6427 } catch (SQLException e) {
6428 e.printStackTrace();
6433 //*************************************************
6434 //* View / Hide source HTML for a note
6435 //*************************************************
6436 public void viewSource() {
6437 browserWindow.showSource(menuBar.viewSource.isChecked());
6439 //*************************************************
6440 // Block the program. This is used for things
6441 // like async web calls.
6442 //*************************************************
6443 @SuppressWarnings("unused")
6444 private void blockApplication(BrowserWindow b) {
6445 // Block all signals
6449 blockTimer = new QTimer();
6450 blockTimer.setSingleShot(true);
6451 blockTimer.setInterval(15000);
6452 blockTimer.timeout.connect(this, "unblockApplication()");
6457 @SuppressWarnings("unused")
6458 private void unblockApplication() {
6460 if (blockingWindow != null && new GregorianCalendar().getTimeInMillis() > blockingWindow.unblockTime && blockingWindow.unblockTime != -1) {
6461 QMessageBox.critical(null, tr("No Response from CodeCogs") ,tr("Unable to contact CodeCogs for LaTeX formula."));
6462 blockingWindow.unblockTime = -1;
6463 blockingWindow.awaitingHttpResponse = false;
6465 blockingWindow = null;
6466 blockSignals(false);