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 // We sort the table twice to fix a bug. For some reaosn the table won't sort properly if it is in narrow
775 // list view and sorted descending on the date created. By sorting it twice it forces the proper sort. Ugly.
776 noteTableView.sortByColumn(sortCol, SortOrder.resolve(0));
777 noteTableView.sortByColumn(sortCol, SortOrder.resolve(sortOrder));
778 noteTableView.proxyModel.blocked = false;
779 noteTableView.proxyModel.sortChanged.connect(this, "tableSortOrderChanged(Integer,Integer)");
781 // Set the startup notebook
782 String defaultNotebook = Global.getStartupNotebook();
783 if (!defaultNotebook.equals("AllNotebooks") && !defaultNotebook.equals("")) {
784 for (int k=0; k<listManager.getNotebookIndex().size(); k++) {
785 if (listManager.getNotebookIndex().get(k).isDefaultNotebook()) {
786 notebookTree.clearSelection();
787 notebookTree.selectGuid(listManager.getNotebookIndex().get(k).getGuid());
788 notebookTree.selectionSignal.emit();
793 if (Global.checkVersionUpgrade())
798 public static void main(String[] args) {
799 log.setLevel(Level.FATAL);
800 QApplication.initialize(args);
801 QPixmap pixmap = new QPixmap("classpath:cx/fbn/nevernote/icons/splash_logo.png");
802 QSplashScreen splash = new QSplashScreen(pixmap);
805 DatabaseConnection dbConn;
808 initializeGlobalSettings(args);
810 showSplash = Global.isWindowVisible("SplashScreen");
814 dbConn = setupDatabaseConnection();
816 // Must be last stage of setup - only safe once DB is open hence we know we are the only instance running
817 Global.getFileManager().purgeResDirectory(true);
819 } catch (InitializationException e) {
822 QMessageBox.critical(null, "Startup error", "Aborting: " + e.getMessage());
826 NeverNote application = new NeverNote(dbConn);
827 if (Global.syncOnly) {
828 System.out.println("Performing synchronization only.");
829 application.remoteConnect();
830 if (Global.isConnected) {
831 application.syncRunner.syncNeeded = true;
832 application.syncRunner.addWork("SYNC");
833 application.syncRunner.addWork("STOP");
834 while(!application.syncRunner.isIdle());
835 application.closeNeverNote();
840 application.setAttribute(WidgetAttribute.WA_DeleteOnClose, true);
841 if (Global.startMinimized())
842 application.showMinimized();
844 if (Global.wasWindowMaximized())
845 application.showMaximized();
851 splash.finish(application);
853 System.out.println("Goodbye.");
858 * Open the internal database, or create if not present
860 * @throws InitializationException when opening the database fails, e.g. because another process has it locked
862 private static DatabaseConnection setupDatabaseConnection() throws InitializationException {
863 ApplicationLogger logger = new ApplicationLogger("nevernote-database.log");
865 File f = Global.getFileManager().getDbDirFile(Global.databaseName + ".h2.db");
866 File fr = Global.getFileManager().getDbDirFile(Global.resourceDatabaseName + ".h2.db");
867 File fi = Global.getFileManager().getDbDirFile(Global.resourceDatabaseName + ".h2.db");
869 Global.setDatabaseUrl("");
871 Global.setResourceDatabaseUrl("");
873 Global.setIndexDatabaseUrl("");
875 if (Global.getDatabaseUrl().toUpperCase().indexOf("CIPHER=") > -1) {
876 boolean goodCheck = false;
878 DatabaseLoginDialog dialog = new DatabaseLoginDialog();
880 if (!dialog.okPressed())
882 Global.cipherPassword = dialog.getPassword();
883 goodCheck = databaseCheck(Global.getDatabaseUrl(), Global.getDatabaseUserid(),
884 Global.getDatabaseUserPassword(), Global.cipherPassword);
887 DatabaseConnection dbConn = new DatabaseConnection(logger,Global.getDatabaseUrl(),
888 Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(),
889 Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword, 0);
893 // Encrypt the database upon shutdown
894 private void encryptOnShutdown() {
895 String dbPath= Global.getFileManager().getDbDirPath("");
898 Statement st = conn.getConnection().createStatement();
899 st.execute("shutdown");
900 st = conn.getResourceConnection().createStatement();
901 st.execute("shutdown");
902 st = conn.getIndexConnection().createStatement();
903 st.execute("shutdown");
904 if (QMessageBox.question(this, tr("Are you sure"),
905 tr("Are you sure you wish to encrypt the database?"),
906 QMessageBox.StandardButton.Yes,
907 QMessageBox.StandardButton.No) == StandardButton.Yes.value()) {
908 ChangeFileEncryption.execute(dbPath, "NeverNote", encryptCipher, null, Global.cipherPassword.toCharArray(), true);
909 ChangeFileEncryption.execute(dbPath, "Resources", encryptCipher, null, Global.cipherPassword.toCharArray(), true);
910 ChangeFileEncryption.execute(dbPath, "Index", encryptCipher, null, Global.cipherPassword.toCharArray(), true);
911 Global.setDatabaseUrl(Global.getDatabaseUrl() + ";CIPHER="+encryptCipher);
912 Global.setResourceDatabaseUrl(Global.getResourceDatabaseUrl() + ";CIPHER="+encryptCipher);
913 Global.setIndexDatabaseUrl(Global.getIndexDatabaseUrl() + ";CIPHER="+encryptCipher);
915 QMessageBox.information(this, tr("Encryption Complete"), tr("Encryption is complete"));
917 } catch (SQLException e) {
922 // Decrypt the database upon shutdown
923 private void decryptOnShutdown() {
924 String dbPath= Global.getFileManager().getDbDirPath("");
925 String dbName = "NeverNote";
927 Statement st = conn.getConnection().createStatement();
928 st.execute("shutdown");
929 if (Global.getDatabaseUrl().toUpperCase().indexOf(";CIPHER=AES") > -1)
930 encryptCipher = "AES";
932 encryptCipher = "XTEA";
933 if (QMessageBox.question(this, tr("Confirmation"), tr("Are you sure",
934 "Are you sure you wish to decrypt the database?"),
935 QMessageBox.StandardButton.Yes,
936 QMessageBox.StandardButton.No) == StandardButton.Yes.value()) {
938 ChangeFileEncryption.execute(dbPath, dbName, encryptCipher, Global.cipherPassword.toCharArray(), null, true);
939 Global.setDatabaseUrl("");
940 Global.setResourceDatabaseUrl("");
941 Global.setIndexDatabaseUrl("");
942 QMessageBox.information(this, tr("Decryption Complete"), tr("Decryption is complete"));
944 } catch (SQLException e) {
949 * Encrypt/Decrypt the local database
951 public void doDatabaseEncrypt() {
952 // The database is not currently encrypted
953 if (Global.getDatabaseUrl().toUpperCase().indexOf("CIPHER=") == -1) {
954 if (QMessageBox.question(this, tr("Confirmation"), tr("Encrypting the database is used" +
955 "to enhance security and is performed\nupon shutdown, but please be aware that if"+
956 " you lose the password your\nis lost forever.\n\nIt is highly recommended you " +
957 "perform a backup and/or fully synchronize\n prior to executing this funtction.\n\n" +
958 "Do you wish to proceed?"),
959 QMessageBox.StandardButton.Yes,
960 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
963 DBEncryptDialog dialog = new DBEncryptDialog();
965 if (dialog.okPressed()) {
966 Global.cipherPassword = dialog.getPassword();
967 encryptOnShutdown = true;
968 encryptCipher = dialog.getEncryptionMethod();
971 DBEncryptDialog dialog = new DBEncryptDialog();
972 dialog.setWindowTitle(tr("Database Decryption"));
973 dialog.hideEncryption();
975 if (dialog.okPressed()) {
976 if (!dialog.getPassword().equals(Global.cipherPassword)) {
977 QMessageBox.critical(null, tr("Incorrect Password"), tr("Incorrect Password"));
980 decryptOnShutdown = true;
987 private static void initializeGlobalSettings(String[] args) throws InitializationException {
988 StartupConfig startupConfig = new StartupConfig();
990 for (String arg : args) {
991 String lower = arg.toLowerCase();
992 if (lower.startsWith("--name="))
993 startupConfig.setName(arg.substring(arg.indexOf('=') + 1));
994 if (lower.startsWith("--home="))
995 startupConfig.setHomeDirPath(arg.substring(arg.indexOf('=') + 1));
996 if (lower.startsWith("--disable-viewing"))
997 startupConfig.setDisableViewing(true);
998 if (lower.startsWith("--sync-only=true"))
999 startupConfig.setSyncOnly(true);
1001 Global.setup(startupConfig);
1007 public void closeEvent(QCloseEvent event) {
1008 if (Global.minimizeOnClose() && !closeAction) {
1013 logger.log(logger.HIGH, "Entering NeverNote.closeEvent");
1016 if (currentNote!= null & browserWindow!=null) {
1017 if (currentNote.getTitle() != null && browserWindow != null
1018 && !currentNote.getTitle().equals(browserWindow.getTitle()))
1019 conn.getNoteTable().updateNoteTitle(currentNote.getGuid(), browserWindow.getTitle());
1022 setMessage(tr("Beginning shutdown."));
1024 // Close down external windows
1025 Collection<ExternalBrowse> windows = externalWindows.values();
1026 Iterator<ExternalBrowse> iterator = windows.iterator();
1027 while (iterator.hasNext()) {
1028 ExternalBrowse browser = iterator.next();
1029 browser.windowClosing.disconnect();
1034 externalFileEditedSaver();
1035 if (Global.isConnected && Global.synchronizeOnClose()) {
1036 setMessage(tr("Performing synchronization before closing."));
1037 syncRunner.syncNeeded = true;
1038 syncRunner.addWork("SYNC");
1040 syncRunner.keepRunning = false;
1042 syncRunner.addWork("STOP");
1043 setMessage("Closing Program.");
1044 threadMonitorTimer.stop();
1046 thumbnailRunner.addWork("STOP");
1047 indexRunner.addWork("STOP");
1052 if (tempFiles != null)
1055 browserWindow.noteSignal.tagsChanged.disconnect();
1056 browserWindow.noteSignal.titleChanged.disconnect();
1057 browserWindow.noteSignal.noteChanged.disconnect();
1058 browserWindow.noteSignal.notebookChanged.disconnect();
1059 browserWindow.noteSignal.createdDateChanged.disconnect();
1060 browserWindow.noteSignal.alteredDateChanged.disconnect();
1061 syncRunner.searchSignal.listChanged.disconnect();
1062 syncRunner.tagSignal.listChanged.disconnect();
1063 syncRunner.notebookSignal.listChanged.disconnect();
1064 syncRunner.noteIndexSignal.listChanged.disconnect();
1067 Global.saveWindowVisible("toolBar", toolBar.isVisible());
1068 saveNoteColumnPositions();
1069 saveNoteIndexWidth();
1071 int width = notebookTree.columnWidth(0);
1072 Global.setColumnWidth("notebookTreeName", width);
1073 width = tagTree.columnWidth(0);
1074 Global.setColumnWidth("tagTreeName", width);
1076 Global.saveWindowMaximized(isMaximized());
1077 Global.saveCurrentNoteGuid(currentNoteGuid);
1079 int sortCol = noteTableView.proxyModel.sortColumn();
1080 int sortOrder = noteTableView.proxyModel.sortOrder().value();
1081 Global.setSortColumn(sortCol);
1082 Global.setSortOrder(sortOrder);
1086 Global.keepRunning = false;
1088 logger.log(logger.MEDIUM, "Waiting for indexThread to stop");
1089 if (indexRunner.thread().isAlive())
1090 indexRunner.thread().join(50);
1091 if (!indexRunner.thread().isAlive())
1092 logger.log(logger.MEDIUM, "Index thread has stopped");
1094 logger.log(logger.MEDIUM, "Index thread still running - interrupting");
1095 indexRunner.thread().interrupt();
1097 } catch (InterruptedException e1) {
1098 e1.printStackTrace();
1101 if (!syncRunner.thread().isAlive()) {
1102 logger.log(logger.MEDIUM, "Waiting for syncThread to stop");
1103 if (syncRunner.thread().isAlive()) {
1104 System.out.println(tr("Synchronizing. Please be patient."));
1105 for(;syncRunner.thread().isAlive();) {
1108 } catch (InterruptedException e) {
1109 e.printStackTrace();
1113 logger.log(logger.MEDIUM, "Sync thread has stopped");
1116 if (encryptOnShutdown) {
1117 encryptOnShutdown();
1119 if (decryptOnShutdown) {
1120 decryptOnShutdown();
1123 Global.getFileManager().purgeResDirectory(false);
1124 } catch (InitializationException e) {
1125 System.out.println(tr("Empty res directory purge failed"));
1126 e.printStackTrace();
1128 logger.log(logger.HIGH, "Leaving NeverNote.closeEvent");
1132 private void closeNeverNote() {
1136 public void setMessage(String s) {
1137 logger.log(logger.HIGH, "Entering NeverNote.setMessage");
1140 logger.log(logger.HIGH, "Message: " +s);
1141 statusBar.showMessage(s);
1145 messageTimer.stop();
1146 messageTimer.setSingleShot(true);
1147 messageTimer.start();
1150 logger.log(logger.HIGH, "Leaving NeverNote.setMessage");
1153 private void clearMessage() {
1154 statusBar.clearMessage();
1158 private void waitCursor(boolean wait) {
1160 if (QApplication.overrideCursor() == null)
1161 QApplication.setOverrideCursor(new QCursor(Qt.CursorShape.WaitCursor));
1164 while (QApplication.overrideCursor() != null)
1165 QApplication.restoreOverrideCursor();
1167 listManager.refreshCounters();
1170 private void setupIndexListeners() {
1171 // indexRunner.noteSignal.noteIndexed.connect(this, "indexThreadComplete(String)");
1172 // indexRunner.resourceSignal.resourceIndexed.connect(this, "indexThreadComplete(String)");
1173 indexRunner.signal.indexStarted.connect(this, "indexStarted()");
1174 indexRunner.signal.indexFinished.connect(this, "indexComplete()");
1176 private void setupSyncSignalListeners() {
1177 syncRunner.tagSignal.listChanged.connect(this, "tagIndexUpdated()");
1178 syncRunner.searchSignal.listChanged.connect(this, "savedSearchIndexUpdated()");
1179 syncRunner.notebookSignal.listChanged.connect(this, "notebookIndexUpdated()");
1180 syncRunner.noteIndexSignal.listChanged.connect(this, "noteIndexUpdated(boolean)");
1181 syncRunner.noteSignal.quotaChanged.connect(this, "updateQuotaBar()");
1183 syncRunner.syncSignal.saveUploadAmount.connect(this,"saveUploadAmount(long)");
1184 syncRunner.syncSignal.saveUserInformation.connect(this,"saveUserInformation(User)");
1185 syncRunner.syncSignal.saveEvernoteUpdateCount.connect(this,"saveEvernoteUpdateCount(int)");
1187 syncRunner.noteSignal.guidChanged.connect(this, "noteGuidChanged(String, String)");
1188 syncRunner.noteSignal.noteChanged.connect(this, "invalidateNoteCache(String, String)");
1189 syncRunner.resourceSignal.resourceGuidChanged.connect(this, "noteResourceGuidChanged(String,String,String)");
1190 syncRunner.noteSignal.noteDownloaded.connect(listManager, "noteDownloaded(Note)");
1191 syncRunner.noteSignal.notebookChanged.connect(this, "updateNoteNotebook(String, String)");
1193 syncRunner.syncSignal.refreshLists.connect(this, "refreshLists()");
1196 private void setupBrowserSignalListeners() {
1197 setupBrowserWindowListeners(browserWindow, true);
1200 private void setupBrowserWindowListeners(BrowserWindow browser, boolean master) {
1201 browser.fileWatcher.fileChanged.connect(this, "externalFileEdited(String)");
1202 browser.noteSignal.tagsChanged.connect(this, "updateNoteTags(String, List)");
1203 browser.noteSignal.tagsChanged.connect(this, "updateListTags(String, List)");
1204 if (master) browser.noteSignal.noteChanged.connect(this, "setNoteDirty()");
1205 browser.noteSignal.titleChanged.connect(listManager, "updateNoteTitle(String, String)");
1206 browser.noteSignal.titleChanged.connect(this, "updateNoteTitle(String, String)");
1207 browser.noteSignal.notebookChanged.connect(this, "updateNoteNotebook(String, String)");
1208 browser.noteSignal.createdDateChanged.connect(listManager, "updateNoteCreatedDate(String, QDateTime)");
1209 browser.noteSignal.alteredDateChanged.connect(listManager, "updateNoteAlteredDate(String, QDateTime)");
1210 browser.noteSignal.subjectDateChanged.connect(listManager, "updateNoteSubjectDate(String, QDateTime)");
1211 browser.noteSignal.authorChanged.connect(listManager, "updateNoteAuthor(String, String)");
1212 browser.noteSignal.geoChanged.connect(listManager, "updateNoteGeoTag(String, Double,Double,Double)");
1213 browser.noteSignal.geoChanged.connect(this, "setNoteDirty()");
1214 browser.noteSignal.sourceUrlChanged.connect(listManager, "updateNoteSourceUrl(String, String)");
1215 browser.blockApplication.connect(this, "blockApplication(BrowserWindow)");
1216 browser.unblockApplication.connect(this, "unblockApplication()");
1217 if (master) browser.focusLost.connect(this, "saveNote()");
1218 browser.resourceSignal.contentChanged.connect(this, "externalFileEdited(String)");
1219 browser.evernoteLinkClicked.connect(this, "evernoteLinkClick(String, String)");
1222 //**************************************************
1224 //**************************************************
1225 private void setupShortcut(QShortcut action, String text) {
1226 if (!Global.shortcutKeys.containsAction(text))
1228 action.setKey(new QKeySequence(Global.shortcutKeys.getShortcut(text)));
1231 //***************************************************************
1232 //***************************************************************
1233 //* Settings and look & feel
1234 //***************************************************************
1235 //***************************************************************
1236 @SuppressWarnings("unused")
1237 private void settings() {
1238 logger.log(logger.HIGH, "Entering NeverNote.settings");
1239 saveNoteColumnPositions();
1240 saveNoteIndexWidth();
1242 ConfigDialog settings = new ConfigDialog(this);
1243 String dateFormat = Global.getDateFormat();
1244 String timeFormat = Global.getTimeFormat();
1246 indexTime = 1000*Global.getIndexThreadSleepInterval();
1247 indexTimer.start(indexTime); // reset indexing timer
1250 indexRunner.indexAttachmentsLocally = Global.indexAttachmentsLocally();
1251 indexRunner.indexNoteBody = Global.indexNoteBody();
1252 indexRunner.indexNoteTitle = Global.indexNoteTitle();
1253 indexRunner.specialIndexCharacters = Global.getSpecialIndexCharacters();
1254 indexRunner.indexImageRecognition = Global.indexImageRecognition();
1255 if (Global.showTrayIcon() || Global.minimizeOnClose())
1260 if (menuBar.showEditorBar.isChecked())
1261 showEditorButtons(browserWindow);
1263 // Reset the save timer
1264 if (Global.getAutoSaveInterval() > 0)
1265 saveTimer.setInterval(1000*60*Global.getAutoSaveInterval());
1270 // Set special reloads
1271 if (settings.getDebugPage().reloadSharedNotebooksClicked()) {
1272 conn.executeSql("Delete from LinkedNotebook");
1273 conn.executeSql("delete from SharedNotebook");
1274 conn.executeSql("Delete from Notebook where linked=true");
1275 conn.executeSql("Insert into Sync (key, value) values ('FullLinkedNotebookSync', 'true')");
1276 conn.executeSql("Insert into Sync (key, value) values ('FullSharedNotebookSync', 'true')");
1281 readOnlyCache.clear();
1282 inkNoteCache.clear();
1283 noteIndexUpdated(true);
1285 logger.log(logger.HIGH, "Leaving NeverNote.settings");
1287 // Restore things to the way they were
1288 private void restoreWindowState(boolean mainWindow) {
1289 // We need to name things or this doesn't work.
1290 setObjectName("NeverNote");
1291 restoreState(Global.restoreState(objectName()));
1292 mainLeftRightSplitter.setObjectName("mainLeftRightSplitter");
1293 browserIndexSplitter.setObjectName("browserIndexSplitter");
1294 leftSplitter1.setObjectName("leftSplitter1");
1296 // Restore the actual positions.
1298 restoreGeometry(Global.restoreGeometry(objectName()));
1299 mainLeftRightSplitter.restoreState(Global.restoreState(mainLeftRightSplitter.objectName()));
1300 browserIndexSplitter.restoreState(Global.restoreState(browserIndexSplitter.objectName()));
1301 leftSplitter1.restoreState(Global.restoreState(leftSplitter1.objectName()));
1304 // Save window positions for the next start
1305 private void saveWindowState() {
1306 Global.saveGeometry(objectName(), saveGeometry());
1307 Global.saveState(mainLeftRightSplitter.objectName(), mainLeftRightSplitter.saveState());
1308 Global.saveState(browserIndexSplitter.objectName(), browserIndexSplitter.saveState());
1309 Global.saveState(leftSplitter1.objectName(), leftSplitter1.saveState());
1310 Global.saveState(objectName(), saveState());
1312 // Load the style sheet
1313 private void loadStyleSheet() {
1314 String styleSheetName = "default.qss";
1315 if (Global.getStyle().equalsIgnoreCase("cleanlooks"))
1316 styleSheetName = "default-cleanlooks.qss";
1317 String fileName = Global.getFileManager().getQssDirPathUser("default.qss");
1318 QFile file = new QFile(fileName);
1320 // If a user default.qss doesn't exist, we use the one shipped with NeverNote
1321 if (!file.exists()) {
1322 fileName = Global.getFileManager().getQssDirPath(styleSheetName);
1323 file = new QFile(fileName);
1325 file.open(OpenModeFlag.ReadOnly);
1326 String styleSheet = file.readAll().toString();
1328 setStyleSheet(styleSheet);
1330 // Save column positions for the next time
1331 private void saveNoteColumnPositions() {
1332 int position = noteTableView.header.visualIndex(Global.noteTableCreationPosition);
1333 Global.setColumnPosition("noteTableCreationPosition", position);
1334 position = noteTableView.header.visualIndex(Global.noteTableTagPosition);
1335 Global.setColumnPosition("noteTableTagPosition", position);
1336 position = noteTableView.header.visualIndex(Global.noteTableNotebookPosition);
1337 Global.setColumnPosition("noteTableNotebookPosition", position);
1338 position = noteTableView.header.visualIndex(Global.noteTableChangedPosition);
1339 Global.setColumnPosition("noteTableChangedPosition", position);
1340 position = noteTableView.header.visualIndex(Global.noteTableAuthorPosition);
1341 Global.setColumnPosition("noteTableAuthorPosition", position);
1342 position = noteTableView.header.visualIndex(Global.noteTableSourceUrlPosition);
1343 Global.setColumnPosition("noteTableSourceUrlPosition", position);
1344 position = noteTableView.header.visualIndex(Global.noteTableSubjectDatePosition);
1345 Global.setColumnPosition("noteTableSubjectDatePosition", position);
1346 position = noteTableView.header.visualIndex(Global.noteTableTitlePosition);
1347 Global.setColumnPosition("noteTableTitlePosition", position);
1348 position = noteTableView.header.visualIndex(Global.noteTableSynchronizedPosition);
1349 Global.setColumnPosition("noteTableSynchronizedPosition", position);
1350 position = noteTableView.header.visualIndex(Global.noteTableGuidPosition);
1351 Global.setColumnPosition("noteTableGuidPosition", position);
1352 position = noteTableView.header.visualIndex(Global.noteTableThumbnailPosition);
1353 Global.setColumnPosition("noteTableThumbnailPosition", position);
1354 position = noteTableView.header.visualIndex(Global.noteTablePinnedPosition);
1355 Global.setColumnPosition("noteTablePinnedPosition", position);
1358 // Save column widths for the next time
1359 private void saveNoteIndexWidth() {
1361 width = noteTableView.getColumnWidth(Global.noteTableCreationPosition);
1362 Global.setColumnWidth("noteTableCreationPosition", width);
1363 width = noteTableView.getColumnWidth(Global.noteTableChangedPosition);
1364 Global.setColumnWidth("noteTableChangedPosition", width);
1365 width = noteTableView.getColumnWidth(Global.noteTableGuidPosition);
1366 Global.setColumnWidth("noteTableGuidPosition", width);
1367 width = noteTableView.getColumnWidth(Global.noteTableNotebookPosition);
1368 Global.setColumnWidth("noteTableNotebookPosition", width);
1369 width = noteTableView.getColumnWidth(Global.noteTableTagPosition);
1370 Global.setColumnWidth("noteTableTagPosition", width);
1371 width = noteTableView.getColumnWidth(Global.noteTableTitlePosition);
1372 Global.setColumnWidth("noteTableTitlePosition", width);
1373 width = noteTableView.getColumnWidth(Global.noteTableSourceUrlPosition);
1374 Global.setColumnWidth("noteTableSourceUrlPosition", width);
1375 width = noteTableView.getColumnWidth(Global.noteTableAuthorPosition);
1376 Global.setColumnWidth("noteTableAuthorPosition", width);
1377 width = noteTableView.getColumnWidth(Global.noteTableSubjectDatePosition);
1378 Global.setColumnWidth("noteTableSubjectDatePosition", width);
1379 width = noteTableView.getColumnWidth(Global.noteTableSynchronizedPosition);
1380 Global.setColumnWidth("noteTableSynchronizedPosition", width);
1381 width = noteTableView.getColumnWidth(Global.noteTableThumbnailPosition);
1382 Global.setColumnWidth("noteTableThumbnailPosition", width);
1383 width = noteTableView.getColumnWidth(Global.noteTableGuidPosition);
1384 Global.setColumnWidth("noteTableGuidPosition", width);
1385 width = noteTableView.getColumnWidth(Global.noteTablePinnedPosition);
1386 Global.setColumnWidth("noteTablePinnedPosition", width);
1389 @SuppressWarnings("unused")
1390 private void toggleSearchWindow() {
1391 logger.log(logger.HIGH, "Entering NeverNote.toggleSearchWindow");
1392 searchLayout.toggleSearchField();
1393 menuBar.hideSearch.setChecked(searchField.isVisible());
1394 Global.saveWindowVisible("searchField", searchField.isVisible());
1395 logger.log(logger.HIGH, "Leaving NeverNote.toggleSearchWindow");
1397 @SuppressWarnings("unused")
1398 private void toggleQuotaWindow() {
1399 logger.log(logger.HIGH, "Entering NeverNote.toggleQuotaWindow");
1400 searchLayout.toggleQuotaBar();
1401 menuBar.hideQuota.setChecked(quotaBar.isVisible());
1402 Global.saveWindowVisible("quota", quotaBar.isVisible());
1403 logger.log(logger.HIGH, "Leaving NeverNote.toggleQuotaWindow");
1405 @SuppressWarnings("unused")
1406 private void toggleZoomWindow() {
1407 logger.log(logger.HIGH, "Entering NeverNote.toggleZoomWindow");
1408 searchLayout.toggleZoom();
1409 menuBar.hideZoom.setChecked(zoomSpinner.isVisible());
1410 Global.saveWindowVisible("zoom", zoomSpinner.isVisible());
1411 logger.log(logger.HIGH, "Leaving NeverNote.toggleZoomWindow");
1416 //***************************************************************
1417 //***************************************************************
1418 //** These functions deal with Notebook menu items
1419 //***************************************************************
1420 //***************************************************************
1421 // Setup the tree containing the user's notebooks.
1422 private void initializeNotebookTree() {
1423 logger.log(logger.HIGH, "Entering NeverNote.initializeNotebookTree");
1424 // notebookTree.itemClicked.connect(this, "notebookTreeSelection()");
1425 notebookTree.selectionSignal.connect(this, "notebookTreeSelection()");
1426 listManager.notebookSignal.refreshNotebookTreeCounts.connect(notebookTree, "updateCounts(List, List)");
1427 logger.log(logger.HIGH, "Leaving NeverNote.initializeNotebookTree");
1429 // Listener when a notebook is selected
1430 private void notebookTreeSelection() {
1431 logger.log(logger.HIGH, "Entering NeverNote.notebookTreeSelection");
1432 noteTableView.proxyModel.blocked = true;
1435 clearAttributeFilter();
1436 clearSavedSearchFilter();
1437 if (Global.mimicEvernoteInterface) {
1439 searchField.clear();
1441 menuBar.noteRestoreAction.setVisible(false);
1442 menuBar.notebookEditAction.setEnabled(true);
1443 menuBar.notebookDeleteAction.setEnabled(true);
1444 menuBar.notebookPublishAction.setEnabled(true);
1445 menuBar.notebookShareAction.setEnabled(true);
1446 menuBar.notebookIconAction.setEnabled(true);
1447 menuBar.notebookStackAction.setEnabled(true);
1448 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1449 selectedNotebookGUIDs.clear();
1451 String stackName = "";
1452 if (selections.size() > 0) {
1453 guid = (selections.get(0).text(2));
1454 stackName = selections.get(0).text(0);
1456 if (!Global.mimicEvernoteInterface) {
1457 // If no notebooks are selected, we make it look like the "all notebooks" one was selected
1458 if (selections.size()==0) {
1459 selectedNotebookGUIDs.clear();
1460 for (int i=0; i < listManager.getNotebookIndex().size(); i++) {
1461 selectedNotebookGUIDs.add(listManager.getNotebookIndex().get(i).getGuid());
1463 menuBar.notebookEditAction.setEnabled(false);
1464 menuBar.notebookDeleteAction.setEnabled(false);
1465 menuBar.notebookStackAction.setEnabled(false);
1466 menuBar.notebookIconAction.setEnabled(false);
1469 if (!guid.equals("") && !guid.equals("STACK")) {
1470 selectedNotebookGUIDs.add(guid);
1471 menuBar.notebookIconAction.setEnabled(true);
1473 menuBar.notebookIconAction.setEnabled(true);
1474 for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1475 Notebook book = listManager.getNotebookIndex().get(j);
1476 if (book.getStack() != null && book.getStack().equalsIgnoreCase(stackName))
1477 selectedNotebookGUIDs.add(book.getGuid());
1480 listManager.setSelectedNotebooks(selectedNotebookGUIDs);
1481 listManager.loadNotesIndex();
1482 noteIndexUpdated(false);
1483 refreshEvernoteNote(true);
1484 listManager.refreshCounters = true;
1485 listManager.refreshCounters();
1486 if (selectedNotebookGUIDs.size() == 1) {
1487 int col = conn.getNotebookTable().getSortColumn(selectedNotebookGUIDs.get(0));
1488 int order = conn.getNotebookTable().getSortOrder(selectedNotebookGUIDs.get(0));
1490 noteTableView.proxyModel.blocked = true;
1492 noteTableView.sortByColumn(col, Qt.SortOrder.DescendingOrder);
1494 noteTableView.sortByColumn(col, Qt.SortOrder.AscendingOrder);
1497 noteTableView.proxyModel.blocked = false;
1498 logger.log(logger.HIGH, "Leaving NeverNote.notebookTreeSelection");
1501 private void clearNotebookFilter() {
1502 notebookTree.blockSignals(true);
1503 notebookTree.clearSelection();
1504 menuBar.noteRestoreAction.setVisible(false);
1505 menuBar.notebookEditAction.setEnabled(false);
1506 menuBar.notebookDeleteAction.setEnabled(false);
1507 selectedNotebookGUIDs.clear();
1508 listManager.setSelectedNotebooks(selectedNotebookGUIDs);
1509 notebookTree.blockSignals(false);
1511 // Triggered when the notebook DB has been updated
1512 private void notebookIndexUpdated() {
1513 logger.log(logger.HIGH, "Entering NeverNote.notebookIndexUpdated");
1515 // Get the possible icons
1516 HashMap<String, QIcon> icons = conn.getNotebookTable().getAllIcons();
1517 notebookTree.setIcons(icons);
1519 if (selectedNotebookGUIDs == null)
1520 selectedNotebookGUIDs = new ArrayList<String>();
1521 List<Notebook> books = conn.getNotebookTable().getAll();
1522 for (int i=books.size()-1; i>=0; i--) {
1523 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
1524 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(books.get(i).getGuid())) {
1526 j=listManager.getArchiveNotebookIndex().size();
1532 listManager.countNotebookResults(listManager.getNoteIndex());
1533 notebookTree.blockSignals(true);
1534 notebookTree.load(books, listManager.getLocalNotebooks());
1535 for (int i=selectedNotebookGUIDs.size()-1; i>=0; i--) {
1536 boolean found = notebookTree.selectGuid(selectedNotebookGUIDs.get(i));
1538 selectedNotebookGUIDs.remove(i);
1540 listManager.refreshCounters = true;
1541 listManager.refreshCounters();
1542 notebookTree.blockSignals(false);
1544 logger.log(logger.HIGH, "Leaving NeverNote.notebookIndexUpdated");
1546 // Show/Hide note information
1547 @SuppressWarnings("unused")
1548 private void toggleNotebookWindow() {
1549 logger.log(logger.HIGH, "Entering NeverNote.toggleNotebookWindow");
1550 searchLayout.toggleNotebook();
1551 menuBar.hideNotebooks.setChecked(notebookTree.isVisible());
1552 Global.saveWindowVisible("notebookTree", notebookTree.isVisible());
1553 logger.log(logger.HIGH, "Leaving NeverNote.toggleNotebookWindow");
1555 // Add a new notebook
1556 @SuppressWarnings("unused")
1557 private void addNotebook() {
1558 logger.log(logger.HIGH, "Inside NeverNote.addNotebook");
1559 NotebookEdit edit = new NotebookEdit();
1560 edit.setNotebooks(listManager.getNotebookIndex());
1563 if (!edit.okPressed())
1566 Calendar currentTime = new GregorianCalendar();
1567 Long l = new Long(currentTime.getTimeInMillis());
1568 String randint = new String(Long.toString(l));
1570 Notebook newBook = new Notebook();
1571 newBook.setUpdateSequenceNum(0);
1572 newBook.setGuid(randint);
1573 newBook.setName(edit.getNotebook());
1574 newBook.setServiceCreated(new Date().getTime());
1575 newBook.setServiceUpdated(new Date().getTime());
1576 newBook.setDefaultNotebook(false);
1577 newBook.setPublished(false);
1579 listManager.getNotebookIndex().add(newBook);
1581 listManager.getLocalNotebooks().add(newBook.getGuid());
1582 conn.getNotebookTable().addNotebook(newBook, true, edit.isLocal());
1583 notebookIndexUpdated();
1584 listManager.countNotebookResults(listManager.getNoteIndex());
1585 // notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
1586 logger.log(logger.HIGH, "Leaving NeverNote.addNotebook");
1588 // Edit an existing notebook
1589 @SuppressWarnings("unused")
1590 private void stackNotebook() {
1591 logger.log(logger.HIGH, "Entering NeverNote.stackNotebook");
1592 StackNotebook edit = new StackNotebook();
1594 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1595 QTreeWidgetItem currentSelection;
1596 for (int i=0; i<selections.size(); i++) {
1597 currentSelection = selections.get(0);
1598 String guid = currentSelection.text(2);
1599 if (guid.equalsIgnoreCase("")) {
1600 QMessageBox.critical(this, tr("Unable To Stack") ,tr("You can't stack the \"All Notebooks\" item."));
1603 if (guid.equalsIgnoreCase("STACK")) {
1604 QMessageBox.critical(this, tr("Unable To Stack") ,tr("You can't stack a stack."));
1609 edit.setStackNames(conn.getNotebookTable().getAllStackNames());
1614 if (!edit.okPressed())
1617 String stack = edit.getStackName();
1619 for (int i=0; i<selections.size(); i++) {
1620 currentSelection = selections.get(i);
1621 String guid = currentSelection.text(2);
1622 listManager.updateNotebookStack(guid, stack);
1624 notebookIndexUpdated();
1625 logger.log(logger.HIGH, "Leaving NeverNote.stackNotebook");
1627 // Edit an existing notebook
1628 @SuppressWarnings("unused")
1629 private void editNotebook() {
1630 logger.log(logger.HIGH, "Entering NeverNote.editNotebook");
1631 NotebookEdit edit = new NotebookEdit();
1633 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1634 QTreeWidgetItem currentSelection;
1635 currentSelection = selections.get(0);
1636 edit.setNotebook(currentSelection.text(0));
1638 String guid = currentSelection.text(2);
1639 if (!guid.equalsIgnoreCase("STACK")) {
1640 edit.setTitle(tr("Edit Notebook"));
1641 edit.setNotebooks(listManager.getNotebookIndex());
1642 edit.setLocalCheckboxEnabled(false);
1643 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1644 if (listManager.getNotebookIndex().get(i).getGuid().equals(guid)) {
1645 edit.setDefaultNotebook(listManager.getNotebookIndex().get(i).isDefaultNotebook());
1646 i=listManager.getNotebookIndex().size();
1650 edit.setTitle(tr("Edit Stack"));
1651 edit.setStacks(conn.getNotebookTable().getAllStackNames());
1652 edit.hideLocalCheckbox();
1653 edit.hideDefaultCheckbox();
1658 if (!edit.okPressed())
1662 if (guid.equalsIgnoreCase("STACK")) {
1663 conn.getNotebookTable().renameStacks(currentSelection.text(0), edit.getNotebook());
1664 for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1665 if (listManager.getNotebookIndex().get(j).getStack() != null &&
1666 listManager.getNotebookIndex().get(j).getStack().equalsIgnoreCase(currentSelection.text(0)))
1667 listManager.getNotebookIndex().get(j).setStack(edit.getNotebook());
1669 conn.getNotebookTable().renameStacks(currentSelection.text(0), edit.getNotebook());
1670 currentSelection.setText(0, edit.getNotebook());
1674 updateListNotebookName(currentSelection.text(0), edit.getNotebook());
1675 currentSelection.setText(0, edit.getNotebook());
1677 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1678 if (listManager.getNotebookIndex().get(i).getGuid().equals(guid)) {
1679 listManager.getNotebookIndex().get(i).setName(edit.getNotebook());
1680 if (!listManager.getNotebookIndex().get(i).isDefaultNotebook() && edit.isDefaultNotebook()) {
1681 for (int j=0; j<listManager.getNotebookIndex().size(); j++)
1682 listManager.getNotebookIndex().get(j).setDefaultNotebook(false);
1683 listManager.getNotebookIndex().get(i).setDefaultNotebook(true);
1684 conn.getNotebookTable().setDefaultNotebook(listManager.getNotebookIndex().get(i).getGuid());
1686 conn.getNotebookTable().updateNotebook(listManager.getNotebookIndex().get(i), true);
1687 if (conn.getNotebookTable().isLinked(listManager.getNotebookIndex().get(i).getGuid())) {
1688 LinkedNotebook linkedNotebook = conn.getLinkedNotebookTable().getByNotebookGuid(listManager.getNotebookIndex().get(i).getGuid());
1689 linkedNotebook.setShareName(edit.getNotebook());
1690 conn.getLinkedNotebookTable().updateNotebook(linkedNotebook, true);
1692 i=listManager.getNotebookIndex().size();
1696 // Build a list of non-closed notebooks
1697 List<Notebook> nbooks = new ArrayList<Notebook>();
1698 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1699 boolean found=false;
1700 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
1701 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid()))
1705 nbooks.add(listManager.getNotebookIndex().get(i));
1709 FilterEditorNotebooks notebookFilter = new FilterEditorNotebooks(conn, logger);
1710 List<Notebook> filteredBooks = notebookFilter.getValidNotebooks(currentNote, listManager.getNotebookIndex());
1711 browserWindow.setNotebookList(filteredBooks);
1712 Iterator<String> set = externalWindows.keySet().iterator();
1713 while(set.hasNext())
1714 externalWindows.get(set.next()).getBrowserWindow().setNotebookList(filteredBooks);
1715 logger.log(logger.HIGH, "Leaving NeverNote.editNotebook");
1717 // Publish a notebook
1718 @SuppressWarnings("unused")
1719 private void publishNotebook() {
1720 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1721 QTreeWidgetItem currentSelection;
1722 currentSelection = selections.get(0);
1723 String guid = currentSelection.text(2);
1725 if (guid.equalsIgnoreCase("STACK") || guid.equalsIgnoreCase(""))
1730 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1731 if (guid.equals(listManager.getNotebookIndex().get(i).getGuid())) {
1732 n = listManager.getNotebookIndex().get(i);
1734 i = listManager.getNotebookIndex().size();
1740 PublishNotebook publish = new PublishNotebook(Global.username, Global.getServer(), n);
1743 if (!publish.okClicked())
1746 Publishing p = publish.getPublishing();
1747 boolean isPublished = !publish.isStopPressed();
1748 conn.getNotebookTable().setPublishing(n.getGuid(), isPublished, p);
1749 n.setPublished(isPublished);
1751 listManager.getNotebookIndex().set(position, n);
1752 notebookIndexUpdated();
1754 // Publish a notebook
1755 @SuppressWarnings("unused")
1756 private void shareNotebook() {
1757 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1758 QTreeWidgetItem currentSelection;
1759 currentSelection = selections.get(0);
1760 String guid = currentSelection.text(2);
1762 if (guid.equalsIgnoreCase("STACK") || guid.equalsIgnoreCase(""))
1766 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1767 if (guid.equals(listManager.getNotebookIndex().get(i).getGuid())) {
1768 n = listManager.getNotebookIndex().get(i);
1769 i = listManager.getNotebookIndex().size();
1773 String authToken = null;
1774 if (syncRunner.isConnected)
1775 authToken = syncRunner.authToken;
1776 ShareNotebook share = new ShareNotebook(n.getName(), conn, n, syncRunner);
1781 // Delete an existing notebook
1782 @SuppressWarnings("unused")
1783 private void deleteNotebook() {
1784 logger.log(logger.HIGH, "Entering NeverNote.deleteNotebook");
1785 boolean stacksFound = false;
1786 boolean notebooksFound = false;
1787 boolean assigned = false;
1788 // Check if any notes have this notebook
1789 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1790 for (int i=0; i<selections.size(); i++) {
1791 QTreeWidgetItem currentSelection;
1792 currentSelection = selections.get(i);
1793 String guid = currentSelection.text(2);
1794 if (!guid.equalsIgnoreCase("STACK")) {
1795 notebooksFound = true;
1796 for (int j=0; j<listManager.getNoteIndex().size(); j++) {
1797 String noteGuid = listManager.getNoteIndex().get(j).getNotebookGuid();
1798 if (noteGuid.equals(guid)) {
1800 j=listManager.getNoteIndex().size();
1801 i=selections.size();
1809 QMessageBox.information(this, tr("Unable to Delete"), tr("Some of the selected notebook(s) contain notes.\n"+
1810 "Please delete the notes or move them to another notebook before deleting any notebooks."));
1814 if (conn.getNotebookTable().getAll().size() == 1) {
1815 QMessageBox.information(this, tr("Unable to Delete"), tr("You must have at least one notebook."));
1819 // If all notebooks are clear, verify the delete
1820 String msg1 = new String(tr("Delete selected notebooks?"));
1821 String msg2 = new String(tr("Remove selected stacks (notebooks will not be deleted)?"));
1822 String msg3 = new String(tr("Delete selected notebooks & remove stacks? Notebooks under the stacks are" +
1823 " not deleted unless selected?"));
1825 if (stacksFound && notebooksFound)
1827 if (!stacksFound && notebooksFound)
1829 if (stacksFound && !notebooksFound)
1831 if (QMessageBox.question(this, tr("Confirmation"), msg,
1832 QMessageBox.StandardButton.Yes,
1833 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
1837 // If confirmed, delete the notebook
1838 for (int i=selections.size()-1; i>=0; i--) {
1839 QTreeWidgetItem currentSelection;
1840 currentSelection = selections.get(i);
1841 String guid = currentSelection.text(2);
1842 if (currentSelection.text(2).equalsIgnoreCase("STACK")) {
1843 conn.getNotebookTable().renameStacks(currentSelection.text(0), "");
1844 listManager.renameStack(currentSelection.text(0), "");
1846 conn.getNotebookTable().expungeNotebook(guid, true);
1847 listManager.deleteNotebook(guid);
1851 notebookIndexUpdated();
1852 // notebookTreeSelection();
1853 // notebookTree.load(listManager.getNotebookIndex(), listManager.getLocalNotebooks());
1854 // listManager.countNotebookResults(listManager.getNoteIndex());
1855 logger.log(logger.HIGH, "Entering NeverNote.deleteNotebook");
1857 // A note's notebook has been updated
1858 @SuppressWarnings("unused")
1859 private void updateNoteNotebook(String guid, String notebookGuid) {
1861 // Update the list manager
1862 listManager.updateNoteNotebook(guid, notebookGuid);
1863 listManager.countNotebookResults(listManager.getNoteIndex());
1864 // notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
1866 // Find the name of the notebook
1867 String notebookName = null;
1868 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1869 if (listManager.getNotebookIndex().get(i).getGuid().equals(notebookGuid)) {
1870 notebookName = listManager.getNotebookIndex().get(i).getName();
1875 // If we found the name, update the browser window
1876 if (notebookName != null) {
1877 updateListNoteNotebook(guid, notebookName);
1878 if (guid.equals(currentNoteGuid)) {
1879 int pos = browserWindow.notebookBox.findText(notebookName);
1881 browserWindow.notebookBox.setCurrentIndex(pos);
1885 // If we're dealing with the current note, then we need to be sure and update the notebook there
1886 if (guid.equals(currentNoteGuid)) {
1887 if (currentNote != null) {
1888 currentNote.setNotebookGuid(notebookGuid);
1892 // Open/close notebooks
1893 @SuppressWarnings("unused")
1894 private void closeNotebooks() {
1895 NotebookArchive na = new NotebookArchive(listManager.getNotebookIndex(), listManager.getArchiveNotebookIndex());
1897 if (!na.okClicked())
1901 listManager.getArchiveNotebookIndex().clear();
1903 for (int i=na.getClosedBookList().count()-1; i>=0; i--) {
1904 String text = na.getClosedBookList().takeItem(i).text();
1905 for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1906 if (listManager.getNotebookIndex().get(j).getName().equalsIgnoreCase(text)) {
1907 Notebook n = listManager.getNotebookIndex().get(j);
1908 conn.getNotebookTable().setArchived(n.getGuid(),true);
1909 listManager.getArchiveNotebookIndex().add(n);
1910 j=listManager.getNotebookIndex().size();
1915 for (int i=na.getOpenBookList().count()-1; i>=0; i--) {
1916 String text = na.getOpenBookList().takeItem(i).text();
1917 for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1918 if (listManager.getNotebookIndex().get(j).getName().equalsIgnoreCase(text)) {
1919 Notebook n = listManager.getNotebookIndex().get(j);
1920 conn.getNotebookTable().setArchived(n.getGuid(),false);
1921 j=listManager.getNotebookIndex().size();
1925 notebookTreeSelection();
1926 listManager.loadNotesIndex();
1927 notebookIndexUpdated();
1928 noteIndexUpdated(false);
1929 reloadTagTree(true);
1930 // noteIndexUpdated(false);
1932 // Build a list of non-closed notebooks
1933 List<Notebook> nbooks = new ArrayList<Notebook>();
1934 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1935 boolean found=false;
1936 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
1937 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid()))
1941 nbooks.add(listManager.getNotebookIndex().get(i));
1944 FilterEditorNotebooks notebookFilter = new FilterEditorNotebooks(conn, logger);
1945 List<Notebook> filteredBooks = notebookFilter.getValidNotebooks(currentNote, listManager.getNotebookIndex());
1946 browserWindow.setNotebookList(filteredBooks);
1948 // Update any external windows
1949 Iterator<String> set = externalWindows.keySet().iterator();
1950 while(set.hasNext())
1951 externalWindows.get(set.next()).getBrowserWindow().setNotebookList(filteredBooks);
1955 // Change the notebook's icon
1956 @SuppressWarnings("unused")
1957 private void setNotebookIcon() {
1958 boolean stackSelected = false;
1959 boolean allNotebookSelected = false;
1961 QTreeWidgetItem currentSelection;
1962 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1963 if (selections.size() == 0)
1966 currentSelection = selections.get(0);
1967 String guid = currentSelection.text(2);
1968 if (guid.equalsIgnoreCase(""))
1969 allNotebookSelected = true;
1970 if (guid.equalsIgnoreCase("STACK"))
1971 stackSelected = true;
1973 QIcon currentIcon = currentSelection.icon(0);
1977 if (!stackSelected && !allNotebookSelected) {
1978 icon = conn.getNotebookTable().getIcon(guid);
1980 dialog = new SetIcon(currentIcon, saveLastPath);
1981 dialog.setUseDefaultIcon(true);
1983 dialog = new SetIcon(icon, saveLastPath);
1984 dialog.setUseDefaultIcon(false);
1987 if (stackSelected) {
1988 icon = conn.getSystemIconTable().getIcon(currentSelection.text(0), "STACK");
1990 icon = conn.getSystemIconTable().getIcon(currentSelection.text(0), "ALLNOTEBOOK");
1993 dialog = new SetIcon(currentIcon, saveLastPath);
1994 dialog.setUseDefaultIcon(true);
1996 dialog = new SetIcon(icon, saveLastPath);
1997 dialog.setUseDefaultIcon(false);
2001 if (dialog.okPressed()) {
2002 saveLastPath = dialog.getPath();
2004 QIcon newIcon = dialog.getIcon();
2005 if (stackSelected) {
2006 conn.getSystemIconTable().setIcon(currentSelection.text(0), "STACK", newIcon, dialog.getFileType());
2007 if (newIcon == null) {
2008 newIcon = new QIcon(iconPath+"books2.png");
2010 currentSelection.setIcon(0,newIcon);
2013 if (allNotebookSelected) {
2014 conn.getSystemIconTable().setIcon(currentSelection.text(0), "ALLNOTEBOOK", newIcon, dialog.getFileType());
2015 if (newIcon == null) {
2016 newIcon = new QIcon(iconPath+"notebook-green.png");
2018 currentSelection.setIcon(0,newIcon);
2021 conn.getNotebookTable().setIcon(guid, newIcon, dialog.getFileType());
2022 if (newIcon == null) {
2023 boolean isPublished = false;;
2024 boolean found = false;
2025 for (int i=0; i<listManager.getNotebookIndex().size() && !found; i++) {
2026 if (listManager.getNotebookIndex().get(i).getGuid().equals(guid)) {
2027 isPublished = listManager.getNotebookIndex().get(i).isPublished();
2031 newIcon = notebookTree.findDefaultIcon(guid, currentSelection.text(1), listManager.getLocalNotebooks(), isPublished);
2033 currentSelection.setIcon(0, newIcon);
2039 //***************************************************************
2040 //***************************************************************
2041 //** These functions deal with Tag menu items
2042 //***************************************************************
2043 //***************************************************************
2044 // Add a new notebook
2045 @SuppressWarnings("unused")
2046 private void addTag() {
2047 logger.log(logger.HIGH, "Inside NeverNote.addTag");
2048 TagEdit edit = new TagEdit();
2049 edit.setTagList(listManager.getTagIndex());
2051 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2052 QTreeWidgetItem currentSelection = null;
2053 if (selections.size() > 0) {
2054 currentSelection = selections.get(0);
2055 edit.setParentTag(currentSelection.text(0));
2060 if (!edit.okPressed())
2063 Calendar currentTime = new GregorianCalendar();
2064 Long l = new Long(currentTime.getTimeInMillis());
2065 String randint = new String(Long.toString(l));
2067 Tag newTag = new Tag();
2068 newTag.setUpdateSequenceNum(0);
2069 newTag.setGuid(randint);
2070 newTag.setName(edit.getTag());
2071 if (edit.getParentTag().isChecked()) {
2072 newTag.setParentGuid(currentSelection.text(2));
2073 newTag.setParentGuidIsSet(true);
2074 currentSelection.setExpanded(true);
2076 conn.getTagTable().addTag(newTag, true);
2077 listManager.getTagIndex().add(newTag);
2078 reloadTagTree(true);
2080 logger.log(logger.HIGH, "Leaving NeverNote.addTag");
2082 @SuppressWarnings("unused")
2083 private void reloadTagTree() {
2084 reloadTagTree(false);
2086 private void reloadTagTree(boolean reload) {
2087 logger.log(logger.HIGH, "Entering NeverNote.reloadTagTree");
2088 tagIndexUpdated(reload);
2089 boolean filter = false;
2091 listManager.countTagResults(listManager.getNoteIndex());
2092 if (notebookTree.selectedItems().size() > 0
2093 && !notebookTree.selectedItems().get(0).text(0).equalsIgnoreCase("All Notebooks"))
2095 if (tagTree.selectedItems().size() > 0)
2097 tagTree.showAllTags(!filter);
2098 tagIndexUpdated(false);
2099 logger.log(logger.HIGH, "Leaving NeverNote.reloadTagTree");
2101 // Edit an existing tag
2102 @SuppressWarnings("unused")
2103 private void editTag() {
2104 logger.log(logger.HIGH, "Entering NeverNote.editTag");
2105 TagEdit edit = new TagEdit();
2106 edit.setTitle("Edit Tag");
2107 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2108 QTreeWidgetItem currentSelection;
2109 currentSelection = selections.get(0);
2110 edit.setTag(currentSelection.text(0));
2111 edit.setTagList(listManager.getTagIndex());
2114 if (!edit.okPressed())
2117 String guid = currentSelection.text(2);
2118 currentSelection.setText(0,edit.getTag());
2120 for (int i=0; i<listManager.getTagIndex().size(); i++) {
2121 if (listManager.getTagIndex().get(i).getGuid().equals(guid)) {
2122 listManager.getTagIndex().get(i).setName(edit.getTag());
2123 conn.getTagTable().updateTag(listManager.getTagIndex().get(i), true);
2124 updateListTagName(guid);
2125 if (currentNote != null && currentNote.getTagGuids().contains(guid))
2126 browserWindow.setTag(getTagNamesForNote(currentNote));
2127 logger.log(logger.HIGH, "Leaving NeverNote.editTag");
2131 listManager.reloadNoteTagNames(guid, edit.getTag());
2132 noteIndexUpdated(true);
2133 refreshEvernoteNote(true);
2134 browserWindow.setTag(getTagNamesForNote(currentNote));
2135 logger.log(logger.HIGH, "Leaving NeverNote.editTag...");
2137 // Delete an existing tag
2138 @SuppressWarnings("unused")
2139 private void deleteTag() {
2140 logger.log(logger.HIGH, "Entering NeverNote.deleteTag");
2142 if (QMessageBox.question(this, tr("Confirmation"), tr("Delete the selected tags?"),
2143 QMessageBox.StandardButton.Yes,
2144 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
2148 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2149 for (int i=selections.size()-1; i>=0; i--) {
2150 QTreeWidgetItem currentSelection;
2151 currentSelection = selections.get(i);
2152 removeTagItem(currentSelection.text(2));
2154 tagIndexUpdated(true);
2156 listManager.countTagResults(listManager.getNoteIndex());
2157 // tagTree.updateCounts(listManager.getTagCounter());
2158 logger.log(logger.HIGH, "Leaving NeverNote.deleteTag");
2160 // Remove a tag tree item. Go recursively down & remove the children too
2161 private void removeTagItem(String guid) {
2162 for (int j=listManager.getTagIndex().size()-1; j>=0; j--) {
2163 String parent = listManager.getTagIndex().get(j).getParentGuid();
2164 if (parent != null && parent.equals(guid)) {
2165 //Remove this tag's children
2166 removeTagItem(listManager.getTagIndex().get(j).getGuid());
2169 //Now, remove this tag
2170 removeListTagName(guid);
2171 conn.getTagTable().expungeTag(guid, true);
2172 for (int a=0; a<listManager.getTagIndex().size(); a++) {
2173 if (listManager.getTagIndex().get(a).getGuid().equals(guid)) {
2174 listManager.getTagIndex().remove(a);
2179 // Setup the tree containing the user's tags
2180 private void initializeTagTree() {
2181 logger.log(logger.HIGH, "Entering NeverNote.initializeTagTree");
2182 // tagTree.itemSelectionChanged.connect(this, "tagTreeSelection()");
2183 // tagTree.itemClicked.connect(this, "tagTreeSelection()");
2184 tagTree.selectionSignal.connect(this, "tagTreeSelection()");
2185 listManager.tagSignal.refreshTagTreeCounts.connect(tagTree, "updateCounts(List)");
2186 logger.log(logger.HIGH, "Leaving NeverNote.initializeTagTree");
2188 // Listener when a tag is selected
2189 private void tagTreeSelection() {
2190 logger.log(logger.HIGH, "Entering NeverNote.tagTreeSelection");
2193 clearAttributeFilter();
2194 clearSavedSearchFilter();
2196 menuBar.noteRestoreAction.setVisible(false);
2198 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2199 QTreeWidgetItem currentSelection;
2200 selectedTagGUIDs.clear();
2201 for (int i=0; i<selections.size(); i++) {
2202 currentSelection = selections.get(i);
2203 selectedTagGUIDs.add(currentSelection.text(2));
2205 if (selections.size() > 0) {
2206 menuBar.tagEditAction.setEnabled(true);
2207 menuBar.tagDeleteAction.setEnabled(true);
2208 menuBar.tagIconAction.setEnabled(true);
2211 menuBar.tagEditAction.setEnabled(false);
2212 menuBar.tagDeleteAction.setEnabled(false);
2213 menuBar.tagIconAction.setEnabled(true);
2215 if (selections.size() > 1)
2216 menuBar.tagMergeAction.setEnabled(true);
2218 menuBar.tagMergeAction.setEnabled(false);
2219 listManager.setSelectedTags(selectedTagGUIDs);
2220 listManager.loadNotesIndex();
2221 noteIndexUpdated(false);
2222 refreshEvernoteNote(true);
2223 listManager.refreshCounters = true;
2224 listManager.refreshCounters();
2225 logger.log(logger.HIGH, "Leaving NeverNote.tagTreeSelection");
2227 // trigger the tag index to be refreshed
2228 @SuppressWarnings("unused")
2229 private void tagIndexUpdated() {
2230 tagIndexUpdated(true);
2232 private void tagIndexUpdated(boolean reload) {
2233 logger.log(logger.HIGH, "Entering NeverNote.tagIndexUpdated");
2234 if (selectedTagGUIDs == null)
2235 selectedTagGUIDs = new ArrayList<String>();
2237 listManager.reloadTagIndex();
2239 tagTree.blockSignals(true);
2241 tagTree.setIcons(conn.getTagTable().getAllIcons());
2242 tagTree.load(listManager.getTagIndex());
2245 for (int i=selectedTagGUIDs.size()-1; i>=0; i--) {
2246 boolean found = tagTree.selectGuid(selectedTagGUIDs.get(i));
2248 selectedTagGUIDs.remove(i);
2250 tagTree.blockSignals(false);
2252 browserWindow.setTag(getTagNamesForNote(currentNote));
2253 logger.log(logger.HIGH, "Leaving NeverNote.tagIndexUpdated");
2255 // Show/Hide note information
2256 @SuppressWarnings("unused")
2257 private void toggleTagWindow() {
2258 logger.log(logger.HIGH, "Entering NeverNote.toggleTagWindow");
2259 if (tagTree.isVisible())
2263 menuBar.hideTags.setChecked(tagTree.isVisible());
2264 Global.saveWindowVisible("tagTree", tagTree.isVisible());
2265 logger.log(logger.HIGH, "Leaving NeverNote.toggleTagWindow");
2267 // A note's tags have been updated
2268 @SuppressWarnings("unused")
2269 private void updateNoteTags(String guid, List<String> tags) {
2270 // Save any new tags. We'll need them later.
2271 List<String> newTags = new ArrayList<String>();
2272 for (int i=0; i<tags.size(); i++) {
2273 if (conn.getTagTable().findTagByName(tags.get(i))==null)
2274 newTags.add(tags.get(i));
2277 listManager.saveNoteTags(guid, tags);
2278 listManager.countTagResults(listManager.getNoteIndex());
2279 StringBuffer names = new StringBuffer("");
2280 for (int i=0; i<tags.size(); i++) {
2281 names = names.append(tags.get(i));
2282 if (i<tags.size()-1) {
2283 names.append(Global.tagDelimeter + " ");
2286 browserWindow.setTag(names.toString());
2289 // Now, we need to add any new tags to the tag tree
2290 for (int i=0; i<newTags.size(); i++)
2291 tagTree.insertTag(newTags.get(i), conn.getTagTable().findTagByName(newTags.get(i)));
2293 // Get a string containing all tag names for a note
2294 private String getTagNamesForNote(Note n) {
2295 logger.log(logger.HIGH, "Entering NeverNote.getTagNamesForNote");
2296 if (n==null || n.getGuid() == null || n.getGuid().equals(""))
2298 StringBuffer buffer = new StringBuffer(100);
2299 Vector<String> v = new Vector<String>();
2300 List<String> guids = n.getTagGuids();
2305 for (int i=0; i<guids.size(); i++) {
2306 v.add(listManager.getTagNameByGuid(guids.get(i)));
2308 Comparator<String> comparator = Collections.reverseOrder();
2309 Collections.sort(v,comparator);
2310 Collections.reverse(v);
2312 for (int i = 0; i<v.size(); i++) {
2314 buffer.append(", ");
2315 buffer.append(v.get(i));
2318 logger.log(logger.HIGH, "Leaving NeverNote.getTagNamesForNote");
2319 return buffer.toString();
2321 // Tags were added via dropping notes from the note list
2322 @SuppressWarnings("unused")
2323 private void tagsAdded(String noteGuid, String tagGuid) {
2324 String tagName = null;
2325 for (int i=0; i<listManager.getTagIndex().size(); i++) {
2326 if (listManager.getTagIndex().get(i).getGuid().equals(tagGuid)) {
2327 tagName = listManager.getTagIndex().get(i).getName();
2328 i=listManager.getTagIndex().size();
2331 if (tagName == null)
2334 for (int i=0; i<listManager.getMasterNoteIndex().size(); i++) {
2335 if (listManager.getMasterNoteIndex().get(i).getGuid().equals(noteGuid)) {
2336 List<String> tagNames = new ArrayList<String>();
2337 tagNames.add(new String(tagName));
2338 Note n = listManager.getMasterNoteIndex().get(i);
2339 for (int j=0; j<n.getTagNames().size(); j++) {
2340 tagNames.add(new String(n.getTagNames().get(j)));
2342 listManager.getNoteTableModel().updateNoteTags(noteGuid, n.getTagGuids(), tagNames);
2343 if (n.getGuid().equals(currentNoteGuid)) {
2344 Collections.sort(tagNames);
2345 String display = "";
2346 for (int j=0; j<tagNames.size(); j++) {
2347 display = display+tagNames.get(j);
2348 if (j+2<tagNames.size())
2349 display = display+Global.tagDelimeter+" ";
2351 browserWindow.setTag(display);
2353 i=listManager.getMasterNoteIndex().size();
2358 listManager.getNoteTableModel().updateNoteSyncStatus(noteGuid, false);
2360 private void clearTagFilter() {
2361 tagTree.blockSignals(true);
2362 tagTree.clearSelection();
2363 menuBar.noteRestoreAction.setVisible(false);
2364 menuBar.tagEditAction.setEnabled(false);
2365 menuBar.tagMergeAction.setEnabled(false);
2366 menuBar.tagDeleteAction.setEnabled(false);
2367 menuBar.tagIconAction.setEnabled(false);
2368 selectedTagGUIDs.clear();
2369 listManager.setSelectedTags(selectedTagGUIDs);
2370 tagTree.blockSignals(false);
2372 // Change the icon for a tag
2373 @SuppressWarnings("unused")
2374 private void setTagIcon() {
2375 QTreeWidgetItem currentSelection;
2376 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2377 if (selections.size() == 0)
2380 currentSelection = selections.get(0);
2381 String guid = currentSelection.text(2);
2383 QIcon currentIcon = currentSelection.icon(0);
2384 QIcon icon = conn.getTagTable().getIcon(guid);
2387 dialog = new SetIcon(currentIcon, saveLastPath);
2388 dialog.setUseDefaultIcon(true);
2390 dialog = new SetIcon(icon, saveLastPath);
2391 dialog.setUseDefaultIcon(false);
2394 if (dialog.okPressed()) {
2395 saveLastPath = dialog.getPath();
2396 QIcon newIcon = dialog.getIcon();
2397 conn.getTagTable().setIcon(guid, newIcon, dialog.getFileType());
2398 if (newIcon == null)
2399 newIcon = new QIcon(iconPath+"tag.png");
2400 currentSelection.setIcon(0, newIcon);
2405 @SuppressWarnings("unused")
2406 private void mergeTags() {
2407 List<Tag> tags = new ArrayList<Tag>();
2408 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2409 for (int i=0; i<selections.size(); i++) {
2410 Tag record = new Tag();
2411 record.setGuid(selections.get(i).text(2));
2412 record.setName(selections.get(i).text(0));
2416 TagMerge mergeDialog = new TagMerge(tags);
2418 if (!mergeDialog.okClicked())
2420 String newGuid = mergeDialog.getNewTagGuid();
2422 for (int i=0; i<tags.size(); i++) {
2423 if (!tags.get(i).getGuid().equals(newGuid)) {
2424 List<String> noteGuids = conn.getNoteTable().noteTagsTable.getTagNotes(tags.get(i).getGuid());
2425 for (int j=0; j<noteGuids.size(); j++) {
2426 String noteGuid = noteGuids.get(j);
2427 conn.getNoteTable().noteTagsTable.deleteNoteTag(noteGuid);
2428 if (!conn.getNoteTable().noteTagsTable.checkNoteNoteTags(noteGuid, newGuid))
2429 conn.getNoteTable().noteTagsTable.saveNoteTag(noteGuid, newGuid);
2433 listManager.reloadIndexes();
2436 //***************************************************************
2437 //***************************************************************
2438 //** These functions deal with Saved Search menu items
2439 //***************************************************************
2440 //***************************************************************
2441 // Add a new notebook
2442 @SuppressWarnings("unused")
2443 private void addSavedSearch() {
2444 logger.log(logger.HIGH, "Inside NeverNote.addSavedSearch");
2445 SavedSearchEdit edit = new SavedSearchEdit();
2446 edit.setSearchList(listManager.getSavedSearchIndex());
2449 if (!edit.okPressed())
2452 Calendar currentTime = new GregorianCalendar();
2453 Long l = new Long(currentTime.getTimeInMillis());
2454 String randint = new String(Long.toString(l));
2456 SavedSearch search = new SavedSearch();
2457 search.setUpdateSequenceNum(0);
2458 search.setGuid(randint);
2459 search.setName(edit.getName());
2460 search.setQuery(edit.getQuery());
2461 search.setFormat(QueryFormat.USER);
2462 listManager.getSavedSearchIndex().add(search);
2463 conn.getSavedSearchTable().addSavedSearch(search, true);
2464 savedSearchIndexUpdated();
2465 logger.log(logger.HIGH, "Leaving NeverNote.addSavedSearch");
2467 // Edit an existing tag
2468 @SuppressWarnings("unused")
2469 private void editSavedSearch() {
2470 logger.log(logger.HIGH, "Entering NeverNote.editSavedSearch");
2471 SavedSearchEdit edit = new SavedSearchEdit();
2472 edit.setTitle(tr("Edit Search"));
2473 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2474 QTreeWidgetItem currentSelection;
2475 currentSelection = selections.get(0);
2476 String guid = currentSelection.text(1);
2477 SavedSearch s = conn.getSavedSearchTable().getSavedSearch(guid);
2478 edit.setName(currentSelection.text(0));
2479 edit.setQuery(s.getQuery());
2480 edit.setSearchList(listManager.getSavedSearchIndex());
2483 if (!edit.okPressed())
2486 List<SavedSearch> list = listManager.getSavedSearchIndex();
2487 SavedSearch search = null;
2488 boolean found = false;
2489 for (int i=0; i<list.size(); i++) {
2490 search = list.get(i);
2491 if (search.getGuid().equals(guid)) {
2498 search.setName(edit.getName());
2499 search.setQuery(edit.getQuery());
2500 conn.getSavedSearchTable().updateSavedSearch(search, true);
2501 savedSearchIndexUpdated();
2502 logger.log(logger.HIGH, "Leaving NeverNote.editSavedSearch");
2504 // Delete an existing tag
2505 @SuppressWarnings("unused")
2506 private void deleteSavedSearch() {
2507 logger.log(logger.HIGH, "Entering NeverNote.deleteSavedSearch");
2509 if (QMessageBox.question(this, tr("Confirmation"), tr("Delete the selected search?"),
2510 QMessageBox.StandardButton.Yes,
2511 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
2515 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2516 for (int i=selections.size()-1; i>=0; i--) {
2517 QTreeWidgetItem currentSelection;
2518 currentSelection = selections.get(i);
2519 for (int j=0; j<listManager.getSavedSearchIndex().size(); j++) {
2520 if (listManager.getSavedSearchIndex().get(j).getGuid().equals(currentSelection.text(1))) {
2521 conn.getSavedSearchTable().expungeSavedSearch(listManager.getSavedSearchIndex().get(j).getGuid(), true);
2522 listManager.getSavedSearchIndex().remove(j);
2523 j=listManager.getSavedSearchIndex().size()+1;
2526 selections.remove(i);
2528 savedSearchIndexUpdated();
2529 logger.log(logger.HIGH, "Leaving NeverNote.deleteSavedSearch");
2531 // Setup the tree containing the user's tags
2532 private void initializeSavedSearchTree() {
2533 logger.log(logger.HIGH, "Entering NeverNote.initializeSavedSearchTree");
2534 savedSearchTree.itemSelectionChanged.connect(this, "savedSearchTreeSelection()");
2535 logger.log(logger.HIGH, "Leaving NeverNote.initializeSavedSearchTree");
2537 // Listener when a tag is selected
2538 @SuppressWarnings("unused")
2539 private void savedSearchTreeSelection() {
2540 logger.log(logger.HIGH, "Entering NeverNote.savedSearchTreeSelection");
2542 clearNotebookFilter();
2545 clearAttributeFilter();
2547 String currentGuid = selectedSavedSearchGUID;
2548 menuBar.savedSearchEditAction.setEnabled(true);
2549 menuBar.savedSearchDeleteAction.setEnabled(true);
2550 menuBar.savedSearchIconAction.setEnabled(true);
2551 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2552 QTreeWidgetItem currentSelection;
2553 selectedSavedSearchGUID = "";
2554 for (int i=0; i<selections.size(); i++) {
2555 currentSelection = selections.get(i);
2556 if (currentSelection.text(1).equals(currentGuid)) {
2557 currentSelection.setSelected(false);
2559 selectedSavedSearchGUID = currentSelection.text(1);
2561 // i = selections.size() +1;
2564 // There is the potential for no notebooks to be selected if this
2565 // happens then we make it look like all notebooks were selecetd.
2566 // If that happens, just select the "all notebooks"
2567 if (selections.size()==0) {
2568 clearSavedSearchFilter();
2570 listManager.setSelectedSavedSearch(selectedSavedSearchGUID);
2572 logger.log(logger.HIGH, "Leaving NeverNote.savedSearchTreeSelection");
2574 private void clearSavedSearchFilter() {
2575 menuBar.savedSearchEditAction.setEnabled(false);
2576 menuBar.savedSearchDeleteAction.setEnabled(false);
2577 menuBar.savedSearchIconAction.setEnabled(false);
2578 savedSearchTree.blockSignals(true);
2579 savedSearchTree.clearSelection();
2580 savedSearchTree.blockSignals(false);
2581 selectedSavedSearchGUID = "";
2582 searchField.setEditText("");
2583 searchPerformed = false;
2584 listManager.setSelectedSavedSearch(selectedSavedSearchGUID);
2586 // trigger the tag index to be refreshed
2587 private void savedSearchIndexUpdated() {
2588 if (selectedSavedSearchGUID == null)
2589 selectedSavedSearchGUID = new String();
2590 savedSearchTree.blockSignals(true);
2591 savedSearchTree.setIcons(conn.getSavedSearchTable().getAllIcons());
2592 savedSearchTree.load(listManager.getSavedSearchIndex());
2593 savedSearchTree.selectGuid(selectedSavedSearchGUID);
2594 savedSearchTree.blockSignals(false);
2596 // trigger when the saved search selection changes
2597 @SuppressWarnings("unused")
2598 private void updateSavedSearchSelection() {
2599 logger.log(logger.HIGH, "Entering NeverNote.updateSavedSearchSelection()");
2601 menuBar.savedSearchEditAction.setEnabled(true);
2602 menuBar.savedSearchDeleteAction.setEnabled(true);
2603 menuBar.savedSearchIconAction.setEnabled(true);
2604 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2606 if (selections.size() > 0) {
2607 menuBar.savedSearchEditAction.setEnabled(true);
2608 menuBar.savedSearchDeleteAction.setEnabled(true);
2609 menuBar.savedSearchIconAction.setEnabled(true);
2610 selectedSavedSearchGUID = selections.get(0).text(1);
2611 SavedSearch s = conn.getSavedSearchTable().getSavedSearch(selectedSavedSearchGUID);
2612 searchField.setEditText(s.getQuery());
2614 menuBar.savedSearchEditAction.setEnabled(false);
2615 menuBar.savedSearchDeleteAction.setEnabled(false);
2616 menuBar.savedSearchIconAction.setEnabled(false);
2617 selectedSavedSearchGUID = "";
2618 searchField.setEditText("");
2620 searchFieldChanged();
2622 logger.log(logger.HIGH, "Leaving NeverNote.updateSavedSearchSelection()");
2626 // Show/Hide note information
2627 @SuppressWarnings("unused")
2628 private void toggleSavedSearchWindow() {
2629 logger.log(logger.HIGH, "Entering NeverNote.toggleSavedSearchWindow");
2630 if (savedSearchTree.isVisible())
2631 savedSearchTree.hide();
2633 savedSearchTree.show();
2634 menuBar.hideSavedSearches.setChecked(savedSearchTree.isVisible());
2636 Global.saveWindowVisible("savedSearchTree", savedSearchTree.isVisible());
2637 logger.log(logger.HIGH, "Leaving NeverNote.toggleSavedSearchWindow");
2639 // Change the icon for a saved search
2640 @SuppressWarnings("unused")
2641 private void setSavedSearchIcon() {
2642 QTreeWidgetItem currentSelection;
2643 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2644 if (selections.size() == 0)
2647 currentSelection = selections.get(0);
2648 String guid = currentSelection.text(1);
2650 QIcon currentIcon = currentSelection.icon(0);
2651 QIcon icon = conn.getSavedSearchTable().getIcon(guid);
2654 dialog = new SetIcon(currentIcon, saveLastPath);
2655 dialog.setUseDefaultIcon(true);
2657 dialog = new SetIcon(icon, saveLastPath);
2658 dialog.setUseDefaultIcon(false);
2661 if (dialog.okPressed()) {
2662 saveLastPath = dialog.getPath();
2663 QIcon newIcon = dialog.getIcon();
2664 conn.getSavedSearchTable().setIcon(guid, newIcon, dialog.getFileType());
2665 if (newIcon == null)
2666 newIcon = new QIcon(iconPath+"search.png");
2667 currentSelection.setIcon(0, newIcon);
2675 //***************************************************************
2676 //***************************************************************
2677 //** These functions deal with Help menu & tool menu items
2678 //***************************************************************
2679 //***************************************************************
2680 // Show database status
2681 @SuppressWarnings("unused")
2682 private void databaseStatus() {
2684 indexRunner.interrupt = true;
2685 int dirty = conn.getNoteTable().getDirtyCount();
2686 int unindexed = conn.getNoteTable().getUnindexedCount();
2687 DatabaseStatus status = new DatabaseStatus();
2688 status.setUnsynchronized(dirty);
2689 status.setUnindexed(unindexed);
2690 status.setNoteCount(conn.getNoteTable().getNoteCount());
2691 status.setNotebookCount(listManager.getNotebookIndex().size());
2692 status.setUnindexedResourceCount(conn.getNoteTable().noteResourceTable.getUnindexedCount());
2693 status.setSavedSearchCount(listManager.getSavedSearchIndex().size());
2694 status.setTagCount(listManager.getTagIndex().size());
2695 status.setResourceCount(conn.getNoteTable().noteResourceTable.getResourceCount());
2696 status.setWordCount(conn.getWordsTable().getWordCount());
2700 // Compact the database
2701 @SuppressWarnings("unused")
2702 private void compactDatabase() {
2703 logger.log(logger.HIGH, "Entering NeverNote.compactDatabase");
2704 if (QMessageBox.question(this, tr("Confirmation"), tr("This will free unused space in the database, "+
2705 "but please be aware that depending upon the size of your database this can be time consuming " +
2706 "and NixNote will be unresponsive until it is complete. Do you wish to continue?"),
2707 QMessageBox.StandardButton.Yes,
2708 QMessageBox.StandardButton.No)==StandardButton.No.value() && Global.verifyDelete() == true) {
2711 setMessage("Compacting database.");
2713 listManager.compactDatabase();
2715 setMessage("Database compact is complete.");
2716 logger.log(logger.HIGH, "Leaving NeverNote.compactDatabase");
2718 @SuppressWarnings("unused")
2719 private void accountInformation() {
2720 logger.log(logger.HIGH, "Entering NeverNote.accountInformation");
2721 AccountDialog dialog = new AccountDialog();
2723 logger.log(logger.HIGH, "Leaving NeverNote.accountInformation");
2725 @SuppressWarnings("unused")
2726 private void releaseNotes() {
2727 logger.log(logger.HIGH, "Entering NeverNote.releaseNotes");
2728 QDialog dialog = new QDialog(this);
2729 QHBoxLayout layout = new QHBoxLayout();
2730 QTextEdit textBox = new QTextEdit();
2731 layout.addWidget(textBox);
2732 textBox.setReadOnly(true);
2733 QFile file = new QFile(Global.getFileManager().getProgramDirPath("release.txt"));
2734 if (!file.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly,
2735 QIODevice.OpenModeFlag.Text)))
2737 textBox.setText(file.readAll().toString());
2739 dialog.setWindowTitle(tr("Release Notes"));
2740 dialog.setLayout(layout);
2742 logger.log(logger.HIGH, "Leaving NeverNote.releaseNotes");
2744 // Called when user picks Log from the help menu
2745 @SuppressWarnings("unused")
2746 private void logger() {
2747 logger.log(logger.HIGH, "Entering NeverNote.logger");
2748 LogFileDialog dialog = new LogFileDialog(emitLog);
2750 logger.log(logger.HIGH, "Leaving NeverNote.logger");
2752 // Menu option "help/about" was selected
2753 @SuppressWarnings("unused")
2754 private void about() {
2755 logger.log(logger.HIGH, "Entering NeverNote.about");
2756 QMessageBox.about(this,
2757 tr("About NixNote"),
2758 tr("<h4><center><b>NixNote</b></center></h4><hr><center>Version ")
2762 +"Open Source Evernote Client.<br><br>"
2763 +"Licensed under GPL v2. <br><hr><br>"
2764 +"</center>Evernote is copyright 2001-2012 by Evernote Corporation<br>"
2765 +"Jambi and QT are the licensed trademark of Nokia Corporation<br>"
2766 +"PDFRenderer is licened under the LGPL<br>"
2767 +"JTidy is copyrighted under the World Wide Web Consortium<br>"
2768 +"Apache Common Utilities licensed under the Apache License Version 2.0<br>"
2769 +"Jazzy is licened under the LGPL<br>"
2770 +"Java is a registered trademark of Oracle Corporation.<br><hr>"
2771 +"Special thanks to:<br>BitRock InstallBuilder for the Windows installer"
2772 +"<br>CodeCogs (www.codecogs.com) for the LaTeX image rendering."));
2773 logger.log(logger.HIGH, "Leaving NeverNote.about");
2775 // Hide the entire left hand side
2776 @SuppressWarnings("unused")
2777 private void toggleLeftSide() {
2780 hidden = !menuBar.hideLeftSide.isChecked();
2781 menuBar.hideLeftSide.setChecked(!hidden);
2784 leftSplitter1.setHidden(true);
2786 leftSplitter1.setHidden(false);
2788 Global.saveWindowVisible("leftPanel", hidden);
2791 public void checkForUpdates() {
2792 // Send off thread to check for a new version
2793 versionChecker = new QNetworkAccessManager(this);
2794 versionChecker.finished.connect(this, "upgradeFileRead(QNetworkReply)");
2795 QNetworkRequest request = new QNetworkRequest();
2796 request.setUrl(new QUrl(Global.getUpdatesAvailableUrl()));
2797 versionChecker.get(request);
2799 @SuppressWarnings("unused")
2800 private void upgradeFileRead(QNetworkReply reply) {
2801 if (!reply.isReadable())
2804 String winVersion = Global.version;
2805 String osxVersion = Global.version;
2806 String linuxVersion = Global.version;
2807 String linux64Version = Global.version;
2808 String version = Global.version;
2810 // Determine the versions available
2811 QByteArray data = reply.readLine();
2812 while (data != null && !reply.atEnd()) {
2813 String line = data.toString();
2815 if (line.contains(":"))
2816 lineVersion = line.substring(line.indexOf(":")+1).replace(" ", "").replace("\n", "");
2819 if (line.toLowerCase().contains("windows"))
2820 winVersion = lineVersion;
2821 else if (line.toLowerCase().contains("os-x"))
2822 osxVersion = lineVersion;
2823 else if (line.toLowerCase().contains("linux amd64"))
2824 linux64Version = lineVersion;
2825 else if (line.toLowerCase().contains("linux i386"))
2826 linuxVersion = lineVersion;
2827 else if (line.toLowerCase().contains("default"))
2828 version = lineVersion;
2830 // Read the next line
2831 data = reply.readLine();
2834 // Now we need to determine what system we are on.
2835 if (System.getProperty("os.name").toLowerCase().contains("windows"))
2836 version = winVersion;
2837 if (System.getProperty("os.name").toLowerCase().contains("mac os"))
2838 version = osxVersion;
2839 if (System.getProperty("os.name").toLowerCase().contains("Linux")) {
2840 if (System.getProperty("os.arch").contains("amd64") ||
2841 System.getProperty("os.arch").contains("x86_64"))
2842 version = linux64Version;
2844 version = linuxVersion;
2848 for (String validVersion : Global.validVersions) {
2849 if (version.equals(validVersion))
2853 UpgradeAvailableDialog dialog = new UpgradeAvailableDialog();
2855 if (dialog.remindMe())
2856 Global.setCheckVersionUpgrade(true);
2858 Global.setCheckVersionUpgrade(false);
2862 //***************************************************************
2863 //***************************************************************
2864 //** These functions deal with the Toolbar
2865 //***************************************************************
2866 //***************************************************************
2867 @SuppressWarnings("unused")
2868 private void focusSearch() {
2869 searchField.setFocus();
2872 // Text in the search bar has been cleared
2873 private void searchFieldCleared() {
2876 // This is done because we want to force a reload of
2877 // images. Some images we may want to highlight the text.
2878 readOnlyCache.clear();
2879 inkNoteCache.clear();
2881 QWebSettings.setMaximumPagesInCache(0);
2882 QWebSettings.setObjectCacheCapacities(0, 0, 0);
2884 searchField.setEditText("");
2885 saveNoteColumnPositions();
2886 saveNoteIndexWidth();
2887 noteIndexUpdated(true);
2888 if (currentNote == null && listManager.getNoteIndex().size() > 0) {
2889 currentNote = listManager.getNoteIndex().get(0);
2890 currentNoteGuid = currentNote.getGuid();
2892 refreshEvernoteNote(true);
2893 if (currentNote != null)
2894 loadNoteBrowserInformation(browserWindow, currentNoteGuid, currentNote);
2896 // text in the search bar changed. We only use this to tell if it was cleared,
2897 // otherwise we trigger off searchFieldChanged.
2898 @SuppressWarnings("unused")
2899 private void searchFieldTextChanged(String text) {
2900 QWebSettings.setMaximumPagesInCache(0);
2901 QWebSettings.setObjectCacheCapacities(0, 0, 0);
2903 if (text.trim().equals("")) {
2904 searchFieldCleared();
2905 if (searchPerformed) {
2907 // This is done because we want to force a reload of
2908 // images. Some images we may want to highlight the text.
2910 readOnlyCache.clear();
2911 inkNoteCache.clear();
2913 listManager.setEnSearch("");
2914 listManager.loadNotesIndex();
2915 refreshEvernoteNote(true);
2916 noteIndexUpdated(false);
2917 refreshEvernoteNote(true);
2919 searchPerformed = false;
2922 // Text in the toolbar has changed
2923 private void searchFieldChanged() {
2924 logger.log(logger.HIGH, "Entering NeverNote.searchFieldChanged");
2926 readOnlyCache.clear();
2927 inkNoteCache.clear();
2928 saveNoteColumnPositions();
2929 saveNoteIndexWidth();
2930 String text = searchField.currentText();
2931 listManager.setEnSearch(text.trim());
2932 listManager.loadNotesIndex();
2933 noteIndexUpdated(false);
2935 refreshEvernoteNote(true);
2936 searchPerformed = true;
2938 logger.log(logger.HIGH, "Leaving NeverNote.searchFieldChanged");
2941 // Build the window tool bar
2942 private void setupToolBar() {
2943 logger.log(logger.HIGH, "Entering NeverNote.setupToolBar");
2944 toolBar = addToolBar(tr("Tool Bar"));
2945 toolBar.setObjectName("toolBar");
2946 menuBar.setupToolBarVisible();
2947 if (!Global.isWindowVisible("toolBar"))
2948 toolBar.setVisible(false);
2950 toolBar.setVisible(true);
2952 // toolBar.addWidget(menuBar);
2953 // menuBar.setSizePolicy(Policy.Minimum, Policy.Minimum);
2954 // toolBar.addSeparator();
2955 prevButton = toolBar.addAction(tr("Previous"));
2956 QIcon prevIcon = new QIcon(iconPath+"back.png");
2957 prevButton.setIcon(prevIcon);
2958 prevButton.triggered.connect(this, "previousViewedAction()");
2959 togglePrevArrowButton(Global.isToolbarButtonVisible("prevArrow"));
2961 nextButton = toolBar.addAction(tr("Next"));
2962 QIcon nextIcon = new QIcon(iconPath+"forward.png");
2963 nextButton.setIcon(nextIcon);
2964 nextButton.triggered.connect(this, "nextViewedAction()");
2965 toggleNextArrowButton(Global.isToolbarButtonVisible("nextArrow"));
2967 upButton = toolBar.addAction(tr("Up"));
2968 QIcon upIcon = new QIcon(iconPath+"up.png");
2969 upButton.setIcon(upIcon);
2970 upButton.triggered.connect(this, "upAction()");
2971 toggleUpArrowButton(Global.isToolbarButtonVisible("upArrow"));
2974 downButton = toolBar.addAction(tr("Down"));
2975 QIcon downIcon = new QIcon(iconPath+"down.png");
2976 downButton.setIcon(downIcon);
2977 downButton.triggered.connect(this, "downAction()");
2978 toggleDownArrowButton(Global.isToolbarButtonVisible("downArrow"));
2980 synchronizeButton = toolBar.addAction(tr("Synchronize"));
2981 synchronizeButton.setIcon(new QIcon(iconPath+"synchronize.png"));
2982 synchronizeIconAngle = 0;
2983 synchronizeButton.triggered.connect(this, "evernoteSync()");
2984 toggleSynchronizeButton(Global.isToolbarButtonVisible("synchronize"));
2986 printButton = toolBar.addAction(tr("Print"));
2987 QIcon printIcon = new QIcon(iconPath+"print.png");
2988 printButton.setIcon(printIcon);
2989 printButton.triggered.connect(this, "printNote()");
2990 togglePrintButton(Global.isToolbarButtonVisible("print"));
2992 tagButton = toolBar.addAction(tr("Tag"));
2993 QIcon tagIcon = new QIcon(iconPath+"tag.png");
2994 tagButton.setIcon(tagIcon);
2995 tagButton.triggered.connect(browserWindow, "modifyTags()");
2996 toggleTagButton(Global.isToolbarButtonVisible("tag"));
2998 attributeButton = toolBar.addAction(tr("Attributes"));
2999 QIcon attributeIcon = new QIcon(iconPath+"attribute.png");
3000 attributeButton.setIcon(attributeIcon);
3001 attributeButton.triggered.connect(this, "toggleNoteInformation()");
3002 toggleAttributeButton(Global.isToolbarButtonVisible("attribute"));
3004 emailButton = toolBar.addAction(tr("Email"));
3005 QIcon emailIcon = new QIcon(iconPath+"email.png");
3006 emailButton.setIcon(emailIcon);
3007 emailButton.triggered.connect(this, "emailNote()");
3008 toggleEmailButton(Global.isToolbarButtonVisible("email"));
3010 deleteButton = toolBar.addAction(tr("Delete"));
3011 QIcon deleteIcon = new QIcon(iconPath+"delete.png");
3012 deleteButton.setIcon(deleteIcon);
3013 deleteButton.triggered.connect(this, "deleteNote()");
3014 toggleDeleteButton(Global.isToolbarButtonVisible("delete"));
3016 newButton = toolBar.addAction(tr("New"));
3017 QIcon newIcon = new QIcon(iconPath+"new.png");
3018 newButton.triggered.connect(this, "addNote()");
3019 newButton.setIcon(newIcon);
3020 toggleNewButton(Global.isToolbarButtonVisible("new"));
3022 allNotesButton = toolBar.addAction(tr("All Notes"));
3023 QIcon allIcon = new QIcon(iconPath+"books.png");
3024 allNotesButton.triggered.connect(this, "allNotes()");
3025 allNotesButton.setIcon(allIcon);
3026 toggleAllNotesButton(Global.isToolbarButtonVisible("allNotes"));
3028 //toolBar.addSeparator();
3029 //toolBar.addWidget(new QLabel(tr("Quota:")));
3030 //toolBar.addWidget(quotaBar);
3031 //quotaBar.setSizePolicy(Policy.Minimum, Policy.Minimum);
3033 //toolBar.addSeparator();
3035 //toolBar.addWidget(new QLabel(tr("Zoom")));
3036 //toolBar.addWidget(zoomSpinner);
3038 //toolBar.addWidget(new QLabel(" "));
3039 //toolBar.addSeparator();
3040 //toolBar.addWidget(new QLabel(tr(" Search:")));
3041 //toolBar.addWidget(searchField);
3042 QSizePolicy sizePolicy = new QSizePolicy();
3043 sizePolicy.setHorizontalPolicy(Policy.MinimumExpanding);
3044 QLabel spacer = new QLabel("");
3045 spacer.setSizePolicy(sizePolicy);
3046 toolBar.addWidget(spacer);
3047 //searchField.setInsertPolicy(InsertPolicy.InsertAtTop);
3049 //searchClearButton = toolBar.addAction("Search Clear");
3050 //QIcon searchClearIcon = new QIcon(iconPath+"searchclear.png");
3051 //searchClearButton.setIcon(searchClearIcon);
3052 //searchClearButton.triggered.connect(this, "searchFieldCleared()");
3053 //toggleSearchClearButton(Global.isToolbarButtonVisible("searchClear"));
3055 logger.log(logger.HIGH, "Leaving NeverNote.setupToolBar");
3057 // Update the sychronize button picture
3059 public QMenu createPopupMenu() {
3060 QMenu contextMenu = super.createPopupMenu();
3062 contextMenu.addSeparator();
3063 QAction prevAction = addContextAction("prevArrow", tr("Previous Arrow"));
3064 contextMenu.addAction(prevAction);
3065 prevAction.triggered.connect(this, "togglePrevArrowButton(Boolean)");
3067 QAction nextAction = addContextAction("nextArrow", tr("Next Arrow"));
3068 contextMenu.addAction(nextAction);
3069 nextAction.triggered.connect(this, "toggleNextArrowButton(Boolean)");
3071 QAction upAction = addContextAction("upArrow", tr("Up Arrow"));
3072 contextMenu.addAction(upAction);
3073 upAction.triggered.connect(this, "toggleUpArrowButton(Boolean)");
3075 QAction downAction = addContextAction("downArrow", tr("Down Arrow"));
3076 contextMenu.addAction(downAction);
3077 downAction.triggered.connect(this, "toggleDownArrowButton(Boolean)");
3079 QAction synchronizeAction = addContextAction("synchronize", tr("Synchronize"));
3080 contextMenu.addAction(synchronizeAction);
3081 synchronizeAction.triggered.connect(this, "toggleSynchronizeButton(Boolean)");
3083 QAction printAction = addContextAction("print", tr("Print"));
3084 contextMenu.addAction(printAction);
3085 printAction.triggered.connect(this, "togglePrintButton(Boolean)");
3087 QAction tagAction = addContextAction("tag", tr("Tag"));
3088 contextMenu.addAction(tagAction);
3089 tagAction.triggered.connect(this, "toggleTagButton(Boolean)");
3091 QAction attributeAction = addContextAction("attribute", tr("Attribute"));
3092 contextMenu.addAction(attributeAction);
3093 attributeAction.triggered.connect(this, "toggleAttributeButton(Boolean)");
3095 QAction emailAction = addContextAction("email", tr("Email"));
3096 contextMenu.addAction(emailAction);
3097 emailAction.triggered.connect(this, "toggleEmailButton(Boolean)");
3099 QAction deleteAction = addContextAction("delete", tr("Delete"));
3100 contextMenu.addAction(deleteAction);
3101 deleteAction.triggered.connect(this, "toggleDeleteButton(Boolean)");
3103 QAction newAction = addContextAction("new", tr("Add"));
3104 contextMenu.addAction(newAction);
3105 newAction.triggered.connect(this, "toggleNewButton(Boolean)");
3107 QAction allNotesAction = addContextAction("allNotes", tr("All Notes"));
3108 contextMenu.addAction(allNotesAction);
3109 allNotesAction.triggered.connect(this, "toggleAllNotesButton(Boolean)");
3111 QAction searchClearAction = addContextAction("searchClear", tr("Search Clear"));
3112 contextMenu.addAction(searchClearAction);
3113 searchClearAction.triggered.connect(this, "toggleSearchClearButton(Boolean)");
3118 private QAction addContextAction(String config, String name) {
3119 QAction newAction = new QAction(this);
3120 newAction.setText(name);
3121 newAction.setCheckable(true);
3122 newAction.setChecked(Global.isToolbarButtonVisible(config));
3125 private void togglePrevArrowButton(Boolean toggle) {
3126 prevButton.setVisible(toggle);
3127 Global.saveToolbarButtonsVisible("prevArrow", toggle);
3129 private void toggleNextArrowButton(Boolean toggle) {
3130 nextButton.setVisible(toggle);
3131 Global.saveToolbarButtonsVisible("nextArrow", toggle);
3133 private void toggleUpArrowButton(Boolean toggle) {
3134 upButton.setVisible(toggle);
3135 Global.saveToolbarButtonsVisible("upArrow", toggle);
3137 private void toggleDownArrowButton(Boolean toggle) {
3138 downButton.setVisible(toggle);
3139 Global.saveToolbarButtonsVisible("downArrow", toggle);
3141 private void toggleSynchronizeButton(Boolean toggle) {
3142 synchronizeButton.setVisible(toggle);
3143 Global.saveToolbarButtonsVisible("synchronize", toggle);
3145 private void togglePrintButton(Boolean toggle) {
3146 printButton.setVisible(toggle);
3147 Global.saveToolbarButtonsVisible("print", toggle);
3149 private void toggleTagButton(Boolean toggle) {
3150 tagButton.setVisible(toggle);
3151 Global.saveToolbarButtonsVisible("tag", toggle);
3153 private void toggleAttributeButton(Boolean toggle) {
3154 attributeButton.setVisible(toggle);
3155 Global.saveToolbarButtonsVisible("attribute", toggle);
3157 private void toggleEmailButton(Boolean toggle) {
3158 emailButton.setVisible(toggle);
3159 Global.saveToolbarButtonsVisible("email", toggle);
3161 private void toggleDeleteButton(Boolean toggle) {
3162 deleteButton.setVisible(toggle);
3163 Global.saveToolbarButtonsVisible("delete", toggle);
3165 private void toggleNewButton(Boolean toggle) {
3166 newButton.setVisible(toggle);
3167 Global.saveToolbarButtonsVisible("new", toggle);
3169 private void toggleAllNotesButton(Boolean toggle) {
3170 allNotesButton.setVisible(toggle);
3171 Global.saveToolbarButtonsVisible("allNotes", toggle);
3173 @SuppressWarnings("unused")
3174 private void toggleSearchClearButton(Boolean toggle) {
3175 searchClearButton.setVisible(toggle);
3176 Global.saveToolbarButtonsVisible("searchClear", toggle);
3183 @SuppressWarnings("unused")
3184 private void updateSyncButton() {
3186 if (syncIcons == null) {
3187 syncIcons = new ArrayList<QPixmap>();
3189 synchronizeIconAngle = 0;
3190 QPixmap pix = new QPixmap(iconPath+"synchronize.png");
3192 for (int i=0; i<=360; i++) {
3193 QPixmap rotatedPix = new QPixmap(pix.size());
3194 QPainter p = new QPainter(rotatedPix);
3195 rotatedPix.fill(toolBar.palette().color(ColorRole.Button));
3196 QSize size = pix.size();
3197 p.translate(size.width()/2, size.height()/2);
3200 p.setBackgroundMode(BGMode.OpaqueMode);
3201 p.translate(-size.width()/2, -size.height()/2);
3202 p.drawPixmap(0,0, pix);
3204 syncIcons.add(rotatedPix);
3208 synchronizeIconAngle++;
3209 if (synchronizeIconAngle > 359)
3210 synchronizeIconAngle=0;
3211 synchronizeButton.setIcon(syncIcons.get(synchronizeIconAngle));
3214 // Synchronize with Evernote
3216 private void evernoteSync() {
3217 logger.log(logger.HIGH, "Entering NeverNote.evernoteSync");
3218 if (!Global.isConnected)
3220 if (Global.isConnected)
3221 synchronizeAnimationTimer.start(5);
3222 // synchronizeAnimationTimer.start(200);
3224 logger.log(logger.HIGH, "Leaving NeverNote.evernoteSync");
3226 private void updateQuotaBar() {
3227 long limit = Global.getUploadLimit();
3228 long amount = Global.getUploadAmount();
3229 if (amount>0 && limit>0) {
3230 int percent =(int)(amount*100/limit);
3231 quotaBar.setValue(percent);
3233 quotaBar.setValue(0);
3236 @SuppressWarnings("unused")
3237 private void zoomChanged() {
3238 browserWindow.getBrowser().setZoomFactor(new Double(zoomSpinner.value())/100);
3241 //****************************************************************
3242 //****************************************************************
3243 //* System Tray functions
3244 //****************************************************************
3245 //****************************************************************
3246 private void trayToggleVisible() {
3251 if (windowMaximized)
3258 @SuppressWarnings("unused")
3259 private void trayActivated(QSystemTrayIcon.ActivationReason reason) {
3260 if (reason == QSystemTrayIcon.ActivationReason.DoubleClick) {
3261 String name = QSystemTrayIcon.MessageIcon.resolve(reason.value()).name();
3262 trayToggleVisible();
3267 //***************************************************************
3268 //***************************************************************
3269 //** These functions deal with the trash tree
3270 //***************************************************************
3271 //***************************************************************
3272 // Setup the tree containing the trash.
3273 @SuppressWarnings("unused")
3274 private void trashTreeSelection() {
3275 logger.log(logger.HIGH, "Entering NeverNote.trashTreeSelection");
3277 clearNotebookFilter();
3279 clearAttributeFilter();
3280 clearSavedSearchFilter();
3282 String tempGuid = currentNoteGuid;
3284 // currentNoteGuid = "";
3285 currentNote = new Note();
3286 selectedNoteGUIDs.clear();
3287 listManager.getSelectedNotebooks().clear();
3288 listManager.getSelectedTags().clear();
3289 listManager.setSelectedSavedSearch("");
3290 browserWindow.clear();
3292 // toggle the add buttons
3293 newButton.setEnabled(!newButton.isEnabled());
3294 menuBar.noteAdd.setEnabled(newButton.isEnabled());
3295 menuBar.noteAdd.setVisible(true);
3297 List<QTreeWidgetItem> selections = trashTree.selectedItems();
3298 if (selections.size() == 0) {
3299 currentNoteGuid = trashNoteGuid;
3300 trashNoteGuid = tempGuid;
3301 Global.showDeleted = false;
3302 menuBar.noteRestoreAction.setEnabled(false);
3303 menuBar.noteRestoreAction.setVisible(false);
3306 trashNoteGuid = tempGuid;
3307 currentNoteGuid = trashNoteGuid;
3308 menuBar.noteRestoreAction.setEnabled(true);
3309 menuBar.noteRestoreAction.setVisible(true);
3310 Global.showDeleted = true;
3312 listManager.loadNotesIndex();
3313 noteIndexUpdated(false);
3314 //// browserWindow.setEnabled(newButton.isEnabled());
3315 browserWindow.setReadOnly(!newButton.isEnabled());
3316 logger.log(logger.HIGH, "Leaving NeverNote.trashTreeSelection");
3318 // Empty the trash file
3319 @SuppressWarnings("unused")
3320 private void emptyTrash() {
3321 // browserWindow.clear();
3322 logger.log(logger.EXTREME, "Emptying Trash");
3323 listManager.emptyTrash();
3324 logger.log(logger.EXTREME, "Resetting view after trash empty");
3325 if (trashTree.selectedItems().size() > 0) {
3326 listManager.getSelectedNotebooks().clear();
3327 listManager.getSelectedTags().clear();
3328 listManager.setSelectedSavedSearch("");
3329 newButton.setEnabled(!newButton.isEnabled());
3330 menuBar.noteAdd.setEnabled(newButton.isEnabled());
3331 menuBar.noteAdd.setVisible(true);
3332 browserWindow.clear();
3335 clearNotebookFilter();
3336 clearSavedSearchFilter();
3337 clearAttributeFilter();
3339 Global.showDeleted = false;
3340 menuBar.noteRestoreAction.setEnabled(false);
3341 menuBar.noteRestoreAction.setVisible(false);
3343 listManager.loadNotesIndex();
3344 noteIndexUpdated(false);
3347 // Show/Hide trash window
3348 @SuppressWarnings("unused")
3349 private void toggleTrashWindow() {
3350 logger.log(logger.HIGH, "Entering NeverNote.toggleTrashWindow");
3351 if (trashTree.isVisible())
3355 menuBar.hideTrash.setChecked(trashTree.isVisible());
3357 Global.saveWindowVisible("trashTree", trashTree.isVisible());
3358 logger.log(logger.HIGH, "Leaving NeverNote.trashWindow");
3360 private void clearTrashFilter() {
3361 Global.showDeleted = false;
3362 newButton.setEnabled(true);
3363 menuBar.noteAdd.setEnabled(true);
3364 menuBar.noteAdd.setVisible(true);
3365 trashTree.blockSignals(true);
3366 trashTree.clearSelection();
3367 trashTree.blockSignals(false);
3372 //***************************************************************
3373 //***************************************************************
3374 //** These functions deal with connection settings
3375 //***************************************************************
3376 //***************************************************************
3377 // SyncRunner had a problem and things are disconnected
3378 @SuppressWarnings("unused")
3379 private void remoteErrorDisconnect() {
3380 menuBar.connectAction.setText(tr("Connect"));
3381 menuBar.connectAction.setToolTip(tr("Connect to Evernote"));
3382 menuBar.synchronizeAction.setEnabled(false);
3383 Global.isConnected = false;
3384 synchronizeAnimationTimer.stop();
3387 // Do a manual connect/disconnect
3388 private void remoteConnect() {
3390 logger.log(logger.HIGH, "Entering NeverNote.remoteConnect");
3392 // If we are already connected, we just disconnect
3393 if (Global.isConnected) {
3394 Global.isConnected = false;
3395 syncRunner.enDisconnect();
3396 setupConnectMenuOptions();
3401 OAuthTokenizer tokenizer = new OAuthTokenizer();
3402 AESEncrypter aes = new AESEncrypter();
3404 aes.decrypt(new FileInputStream(Global.getFileManager().getHomeDirFile("oauth.txt")));
3405 } catch (FileNotFoundException e) {
3406 // File not found, so we'll just get empty strings anyway.
3410 if (Global.getProxyValue("url").equals("")) {
3411 System.setProperty("http.proxyHost","") ;
3412 System.setProperty("http.proxyPort", "") ;
3413 System.setProperty("https.proxyHost","") ;
3414 System.setProperty("https.proxyPort", "") ;
3417 System.setProperty("http.proxyHost",Global.getProxyValue("url")) ;
3418 System.setProperty("http.proxyPort", Global.getProxyValue("port")) ;
3419 System.setProperty("https.proxyHost",Global.getProxyValue("url")) ;
3420 System.setProperty("https.proxyPort", Global.getProxyValue("port")) ;
3422 if (Global.getProxyValue("userid").equals("")) {
3423 Authenticator.setDefault(new Authenticator() {
3425 protected PasswordAuthentication getPasswordAuthentication() {
3427 PasswordAuthentication(Global.getProxyValue("userid"),Global.getProxyValue("password").toCharArray());
3433 syncRunner.userStoreUrl = Global.userStoreUrl;
3434 syncRunner.noteStoreUrl = Global.noteStoreUrl;
3435 syncRunner.noteStoreUrlBase = Global.noteStoreUrlBase;
3439 String authString = aes.getString();
3440 if (!authString.equals("")) {
3441 tokenizer.tokenize(authString);
3442 syncRunner.authToken = tokenizer.oauth_token;
3443 syncRunner.enConnect();
3446 Global.isConnected = syncRunner.isConnected;
3448 if (!Global.isConnected) {
3449 OAuthWindow window = new OAuthWindow(logger);
3451 setMessage(window.errorMessage);
3456 setMessage(window.errorMessage);
3459 tokenizer.tokenize(window.response);
3460 if (tokenizer.oauth_token.equals("")) {
3461 setMessage(tr("Invalid authorization token received."));
3464 aes.setString(window.response);
3466 aes.encrypt(new FileOutputStream(Global.getFileManager().getHomeDirFile("oauth.txt")));
3467 } catch (FileNotFoundException e) {
3468 // TODO Auto-generated catch block
3469 e.printStackTrace();
3471 syncRunner.authToken = tokenizer.oauth_token;
3472 syncRunner.enConnect();
3473 Global.isConnected = syncRunner.isConnected;
3475 Global.username = syncRunner.username;
3477 if (!Global.isConnected)
3480 setupConnectMenuOptions();
3481 logger.log(logger.HIGH, "Leaving NeverNote.remoteConnect");
3485 private void setupConnectMenuOptions() {
3486 logger.log(logger.HIGH, "entering NeverNote.setupConnectMenuOptions");
3487 if (!Global.isConnected) {
3488 menuBar.connectAction.setText(tr("Connect"));
3489 menuBar.connectAction.setToolTip(tr("Connect to Evernote"));
3490 menuBar.synchronizeAction.setEnabled(false);
3492 menuBar.connectAction.setText(tr("Disconnect"));
3493 menuBar.connectAction.setToolTip(tr("Disconnect from Evernote"));
3494 menuBar.synchronizeAction.setEnabled(true);
3496 logger.log(logger.HIGH, "Leaving NeverNote.setupConnectionMenuOptions");
3501 //***************************************************************
3502 //***************************************************************
3503 //** These functions deal with the GUI Attribute tree
3504 //***************************************************************
3505 //***************************************************************
3506 @SuppressWarnings("unused")
3507 private void attributeTreeClicked(QTreeWidgetItem item, Integer integer) {
3509 // clearTagFilter();
3510 // clearNotebookFilter();
3512 // clearSavedSearchFilter();
3514 if (attributeTreeSelected == null || item.nativeId() != attributeTreeSelected.nativeId()) {
3515 if (item.childCount() > 0) {
3516 item.setSelected(false);
3518 Global.createdBeforeFilter.reset();
3519 Global.createdSinceFilter.reset();
3520 Global.changedBeforeFilter.reset();
3521 Global.changedSinceFilter.reset();
3522 Global.containsFilter.reset();
3523 attributeTreeSelected = item;
3524 DateAttributeFilterTable f = null;
3525 f = findDateAttributeFilterTable(item.parent());
3527 f.select(item.parent().indexOfChild(item));
3529 Global.containsFilter.select(item.parent().indexOfChild(item));
3532 listManager.loadNotesIndex();
3533 noteIndexUpdated(false);
3536 attributeTreeSelected = null;
3537 item.setSelected(false);
3538 Global.createdBeforeFilter.reset();
3539 Global.createdSinceFilter.reset();
3540 Global.changedBeforeFilter.reset();
3541 Global.changedSinceFilter.reset();
3542 Global.containsFilter.reset();
3543 listManager.loadNotesIndex();
3544 noteIndexUpdated(false);
3546 // This determines what attribute filter we need, depending upon the selection
3547 private DateAttributeFilterTable findDateAttributeFilterTable(QTreeWidgetItem w) {
3548 if (w.parent() != null && w.childCount() > 0) {
3549 QTreeWidgetItem parent = w.parent();
3550 if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Created &&
3551 w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Since)
3552 return Global.createdSinceFilter;
3553 if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Created &&
3554 w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Before)
3555 return Global.createdBeforeFilter;
3556 if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.LastModified &&
3557 w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Since)
3558 return Global.changedSinceFilter;
3559 if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.LastModified &&
3560 w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Before)
3561 return Global.changedBeforeFilter;
3566 // Show/Hide attribute search window
3567 @SuppressWarnings("unused")
3568 private void toggleAttributesWindow() {
3569 logger.log(logger.HIGH, "Entering NeverNote.toggleAttributesWindow");
3570 if (attributeTree.isVisible())
3571 attributeTree.hide();
3573 attributeTree.show();
3574 menuBar.hideAttributes.setChecked(attributeTree.isVisible());
3576 Global.saveWindowVisible("attributeTree", attributeTree.isVisible());
3577 logger.log(logger.HIGH, "Leaving NeverNote.toggleAttributeWindow");
3579 private void clearAttributeFilter() {
3580 Global.createdBeforeFilter.reset();
3581 Global.createdSinceFilter.reset();
3582 Global.changedBeforeFilter.reset();
3583 Global.changedSinceFilter.reset();
3584 Global.containsFilter.reset();
3585 attributeTreeSelected = null;
3586 attributeTree.blockSignals(true);
3587 attributeTree.clearSelection();
3588 attributeTree.blockSignals(false);
3592 //***************************************************************
3593 //***************************************************************
3594 //** These functions deal with the GUI Note index table
3595 //***************************************************************
3596 //***************************************************************
3597 // Initialize the note list table
3598 private void initializeNoteTable() {
3599 logger.log(logger.HIGH, "Entering NeverNote.initializeNoteTable");
3600 noteTableView.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection);
3601 noteTableView.selectionModel().selectionChanged.connect(this, "noteTableSelection()");
3602 logger.log(logger.HIGH, "Leaving NeverNote.initializeNoteTable");
3604 // Show/Hide trash window
3605 @SuppressWarnings("unused")
3606 private void toggleNoteListWindow() {
3607 logger.log(logger.HIGH, "Entering NeverNote.toggleNoteListWindow");
3608 if (noteTableView.isVisible())
3609 noteTableView.hide();
3611 noteTableView.show();
3612 menuBar.hideNoteList.setChecked(noteTableView.isVisible());
3614 Global.saveWindowVisible("noteList", noteTableView.isVisible());
3615 logger.log(logger.HIGH, "Leaving NeverNote.toggleNoteListWindow");
3617 // Handle the event that a user selects a note from the table
3618 @SuppressWarnings("unused")
3619 private void noteTableSelection() {
3620 logger.log(logger.HIGH, "Entering NeverNote.noteTableSelection");
3624 // If we have more than one selection, then set the merge note action to true.
3625 List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
3626 if (selections.size() > 1)
3627 menuBar.noteMergeAction.setEnabled(true);
3629 menuBar.noteMergeAction.setEnabled(false);
3631 // If the ctrl key is pressed, then they are selecting multiple
3632 // entries and we don't want to change the currently viewed note.
3633 if (QApplication.keyboardModifiers().isSet(KeyboardModifier.ControlModifier) &&
3634 QApplication.mouseButtons().isSet(MouseButton.LeftButton))
3637 if (historyGuids.size() == 0) {
3638 historyGuids.add(currentNoteGuid);
3639 historyPosition = 1;
3641 noteTableView.showColumn(Global.noteTableGuidPosition);
3643 if (!Global.isColumnVisible("guid"))
3644 noteTableView.hideColumn(Global.noteTableGuidPosition);
3646 if (selections.size() > 0) {
3648 menuBar.noteDuplicateAction.setEnabled(true);
3649 menuBar.noteOnlineHistoryAction.setEnabled(true);
3650 menuBar.noteMergeAction.setEnabled(true);
3651 selectedNoteGUIDs.clear();
3652 if (selections.size() != 1 || Global.showDeleted) {
3653 menuBar.noteDuplicateAction.setEnabled(false);
3655 if (selections.size() != 1 || !Global.isConnected) {
3656 menuBar.noteOnlineHistoryAction.setEnabled(false);
3658 if (selections.size() == 1) {
3659 menuBar.noteMergeAction.setEnabled(false);
3661 for (int i=0; i<selections.size(); i++) {
3662 int row = selections.get(i).row();
3664 upButton.setEnabled(false);
3666 upButton.setEnabled(true);
3667 if (row < listManager.getNoteTableModel().rowCount()-1)
3668 downButton.setEnabled(true);
3670 downButton.setEnabled(false);
3671 index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition);
3672 SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
3673 currentNoteGuid = (String)ix.values().toArray()[0];
3674 selectedNoteGUIDs.add(currentNoteGuid);
3678 nextButton.setEnabled(true);
3679 prevButton.setEnabled(true);
3681 int endPosition = historyGuids.size()-1;
3682 for (int j=historyPosition; j<=endPosition; j++) {
3683 historyGuids.remove(historyGuids.size()-1);
3685 historyGuids.add(currentNoteGuid);
3686 historyPosition = historyGuids.size();
3688 if (historyPosition <= 1)
3689 prevButton.setEnabled(false);
3690 if (historyPosition == historyGuids.size())
3691 nextButton.setEnabled(false);
3693 fromHistory = false;
3694 scrollToGuid(currentNoteGuid);
3695 refreshEvernoteNote(true);
3696 logger.log(logger.HIGH, "Leaving NeverNote.noteTableSelection");
3698 // Trigger a refresh when the note db has been updated
3699 private void noteIndexUpdated(boolean reload) {
3700 logger.log(logger.HIGH, "Entering NeverNote.noteIndexUpdated");
3702 refreshEvernoteNoteList();
3703 logger.log(logger.HIGH, "Calling note table reload in NeverNote.noteIndexUpdated() - "+reload);
3704 noteTableView.load(reload);
3705 if (currentNoteGuid == null || currentNoteGuid.equals("")) {
3707 if (noteTableView.proxyModel.sortOrder() == SortOrder.AscendingOrder)
3708 pos = noteTableView.proxyModel.rowCount();
3711 if (noteTableView.proxyModel.rowCount() == 0)
3714 QModelIndex i = noteTableView.proxyModel.index(pos-1, Global.noteTableGuidPosition);
3716 currentNoteGuid = (String)i.data();
3720 if (!noteTableView.isColumnHidden(Global.noteTableGuidPosition))
3722 scrollToGuid(currentNoteGuid);
3723 logger.log(logger.HIGH, "Leaving NeverNote.noteIndexUpdated");
3725 // Called when the list of notes is updated
3726 private void refreshEvernoteNoteList() {
3727 logger.log(logger.HIGH, "Entering NeverNote.refreshEvernoteNoteList");
3728 browserWindow.setDisabled(false);
3729 if (selectedNoteGUIDs == null)
3730 selectedNoteGUIDs = new ArrayList<String>();
3731 selectedNoteGUIDs.clear(); // clear out old entries
3733 String saveCurrentNoteGuid = new String();
3734 String tempNoteGuid = new String();
3736 historyGuids.clear();
3737 historyPosition = 0;
3738 prevButton.setEnabled(false);
3739 nextButton.setEnabled(false);
3741 if (currentNoteGuid == null)
3742 currentNoteGuid = new String();
3744 //determine current note guid
3745 for (Note note : listManager.getNoteIndex()) {
3746 tempNoteGuid = note.getGuid();
3747 if (currentNoteGuid.equals(tempNoteGuid)) {
3748 saveCurrentNoteGuid = tempNoteGuid;
3752 if (listManager.getNoteIndex().size() == 0) {
3753 currentNoteGuid = "";
3755 browserWindow.clear();
3756 browserWindow.setDisabled(true);
3759 if (Global.showDeleted && listManager.getNotebookIndex().size() > 0 && saveCurrentNoteGuid.equals("")) {
3760 currentNoteGuid = listManager.getNoteIndex().get(0).getGuid();
3761 saveCurrentNoteGuid = currentNoteGuid;
3762 refreshEvernoteNote(true);
3765 if (!saveCurrentNoteGuid.equals("")) {
3766 refreshEvernoteNote(false);
3768 currentNoteGuid = "";
3770 reloadTagTree(false);
3772 logger.log(logger.HIGH, "Leaving NeverNote.refreshEvernoteNoteList");
3774 // Called when the previous arrow button is clicked
3775 @SuppressWarnings("unused")
3776 private void previousViewedAction() {
3777 if (!prevButton.isEnabled())
3779 if (historyPosition == 0)
3782 if (historyPosition <= 0)
3784 String historyGuid = historyGuids.get(historyPosition-1);
3786 for (int i=0; i<noteTableView.model().rowCount(); i++) {
3787 QModelIndex modelIndex = noteTableView.model().index(i, Global.noteTableGuidPosition);
3788 if (modelIndex != null) {
3789 SortedMap<Integer, Object> ix = noteTableView.model().itemData(modelIndex);
3790 String tableGuid = (String)ix.values().toArray()[0];
3791 if (tableGuid.equals(historyGuid)) {
3792 noteTableView.selectRow(i);
3798 @SuppressWarnings("unused")
3799 private void nextViewedAction() {
3800 if (!nextButton.isEnabled())
3802 String historyGuid = historyGuids.get(historyPosition);
3805 for (int i=0; i<noteTableView.model().rowCount(); i++) {
3806 QModelIndex modelIndex = noteTableView.model().index(i, Global.noteTableGuidPosition);
3807 if (modelIndex != null) {
3808 SortedMap<Integer, Object> ix = noteTableView.model().itemData(modelIndex);
3809 String tableGuid = (String)ix.values().toArray()[0];
3810 if (tableGuid.equals(historyGuid)) {
3811 noteTableView.selectRow(i);
3817 // Called when the up arrow is clicked
3818 @SuppressWarnings("unused")
3819 private void upAction() {
3820 List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
3821 int row = selections.get(0).row();
3823 noteTableView.selectRow(row-1);
3826 // Called when the down arrow is clicked
3827 @SuppressWarnings("unused")
3828 private void downAction() {
3829 List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
3830 int row = selections.get(0).row();
3831 int max = listManager.getNoteTableModel().rowCount();
3833 noteTableView.selectRow(row+1);
3836 // Update a tag string for a specific note in the list
3837 @SuppressWarnings("unused")
3838 private void updateListTags(String guid, List<String> tags) {
3839 logger.log(logger.HIGH, "Entering NeverNote.updateListTags");
3840 StringBuffer tagBuffer = new StringBuffer();
3841 for (int i=0; i<tags.size(); i++) {
3842 tagBuffer.append(tags.get(i));
3843 if (i<tags.size()-1)
3844 tagBuffer.append(", ");
3847 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3848 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3849 if (modelIndex != null) {
3850 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3851 String tableGuid = (String)ix.values().toArray()[0];
3852 if (tableGuid.equals(guid)) {
3853 listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition,tagBuffer.toString());
3854 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
3855 noteTableView.proxyModel.invalidate();
3860 logger.log(logger.HIGH, "Leaving NeverNote.updateListTags");
3862 // Update a title for a specific note in the list
3863 @SuppressWarnings("unused")
3864 private void updateListAuthor(String guid, String author) {
3865 logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
3867 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3868 //QModelIndex modelIndex = noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
3869 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3870 if (modelIndex != null) {
3871 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3872 String tableGuid = (String)ix.values().toArray()[0];
3873 if (tableGuid.equals(guid)) {
3874 listManager.getNoteTableModel().setData(i, Global.noteTableAuthorPosition,author);
3875 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
3876 noteTableView.proxyModel.invalidate();
3882 logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
3884 private void updateListNoteNotebook(String guid, String notebook) {
3885 logger.log(logger.HIGH, "Entering NeverNote.updateListNoteNotebook");
3886 listManager.getNoteTableModel().updateNoteSyncStatus(guid, false);
3887 logger.log(logger.HIGH, "Leaving NeverNote.updateListNoteNotebook");
3889 // Update a title for a specific note in the list
3890 @SuppressWarnings("unused")
3891 private void updateListSourceUrl(String guid, String url) {
3892 logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
3894 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3895 //QModelIndex modelIndex = noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
3896 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3897 if (modelIndex != null) {
3898 // SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(modelIndex);
3899 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3900 String tableGuid = (String)ix.values().toArray()[0];
3901 if (tableGuid.equals(guid)) {
3902 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
3903 listManager.getNoteTableModel().setData(i, Global.noteTableSourceUrlPosition,url);
3904 noteTableView.proxyModel.invalidate();
3909 logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
3911 @SuppressWarnings("unused")
3912 private void updateListGuid(String oldGuid, String newGuid) {
3913 logger.log(logger.HIGH, "Entering NeverNote.updateListTitle");
3915 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3916 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3917 if (modelIndex != null) {
3918 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3919 String tableGuid = (String)ix.values().toArray()[0];
3920 if (tableGuid.equals(oldGuid)) {
3921 listManager.getNoteTableModel().setData(i, Global.noteTableGuidPosition,newGuid);
3922 //listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
3927 logger.log(logger.HIGH, "Leaving NeverNote.updateListTitle");
3929 private void updateListTagName(String guid) {
3930 logger.log(logger.HIGH, "Entering NeverNote.updateTagName");
3932 for (int j=0; j<listManager.getNoteIndex().size(); j++) {
3933 if (listManager.getNoteIndex().get(j).getTagGuids().contains(guid)) {
3934 String newName = listManager.getTagNamesForNote(listManager.getNoteIndex().get(j));
3936 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3937 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3938 if (modelIndex != null) {
3939 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3940 String noteGuid = (String)ix.values().toArray()[0];
3941 if (noteGuid.equalsIgnoreCase(listManager.getNoteIndex().get(j).getGuid())) {
3942 listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition, newName);
3943 i=listManager.getNoteTableModel().rowCount();
3949 logger.log(logger.HIGH, "Leaving NeverNote.updateListNotebook");
3951 private void removeListTagName(String guid) {
3952 logger.log(logger.HIGH, "Entering NeverNote.updateTagName");
3954 for (int j=0; j<listManager.getNoteIndex().size(); j++) {
3955 if (listManager.getNoteIndex().get(j).getTagGuids().contains(guid)) {
3956 for (int i=listManager.getNoteIndex().get(j).getTagGuids().size()-1; i>=0; i--) {
3957 if (listManager.getNoteIndex().get(j).getTagGuids().get(i).equals(guid))
3958 listManager.getNoteIndex().get(j).getTagGuids().remove(i);
3961 String newName = listManager.getTagNamesForNote(listManager.getNoteIndex().get(j));
3962 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3963 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3964 if (modelIndex != null) {
3965 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3966 String noteGuid = (String)ix.values().toArray()[0];
3967 if (noteGuid.equalsIgnoreCase(listManager.getNoteIndex().get(j).getGuid())) {
3968 listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition, newName);
3969 i=listManager.getNoteTableModel().rowCount();
3975 logger.log(logger.HIGH, "Leaving NeverNote.updateListNotebook");
3977 private void updateListNotebookName(String oldName, String newName) {
3978 logger.log(logger.HIGH, "Entering NeverNote.updateListNotebookName");
3980 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3981 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableNotebookPosition);
3982 if (modelIndex != null) {
3983 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3984 String tableName = (String)ix.values().toArray()[0];
3985 if (tableName.equalsIgnoreCase(oldName)) {
3986 listManager.getNoteTableModel().setData(i, Global.noteTableNotebookPosition, newName);
3990 logger.log(logger.HIGH, "Leaving NeverNote.updateListNotebookName");
3992 @SuppressWarnings("unused")
3993 private void updateListDateCreated(String guid, QDateTime date) {
3994 logger.log(logger.HIGH, "Entering NeverNote.updateListDateCreated");
3996 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3997 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3998 if (modelIndex != null) {
3999 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4000 String tableGuid = (String)ix.values().toArray()[0];
4001 if (tableGuid.equals(guid)) {
4002 listManager.getNoteTableModel().setData(i, Global.noteTableCreationPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
4003 noteTableView.proxyModel.invalidate();
4008 logger.log(logger.HIGH, "Leaving NeverNote.updateListDateCreated");
4010 @SuppressWarnings("unused")
4011 private void updateListDateSubject(String guid, QDateTime date) {
4012 logger.log(logger.HIGH, "Entering NeverNote.updateListDateSubject");
4014 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4015 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4016 if (modelIndex != null) {
4017 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4018 String tableGuid = (String)ix.values().toArray()[0];
4019 if (tableGuid.equals(guid)) {
4020 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
4021 listManager.getNoteTableModel().setData(i, Global.noteTableSubjectDatePosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
4022 noteTableView.proxyModel.invalidate();
4027 logger.log(logger.HIGH, "Leaving NeverNote.updateListDateCreated");
4029 private void updateListDateChanged(String guid, QDateTime date) {
4030 logger.log(logger.HIGH, "Entering NeverNote.updateListDateChanged");
4032 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4033 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4034 if (modelIndex != null) {
4035 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4036 String tableGuid = (String)ix.values().toArray()[0];
4037 if (tableGuid.equals(guid)) {
4038 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
4039 listManager.getNoteTableModel().setData(i, Global.noteTableChangedPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
4044 logger.log(logger.HIGH, "Leaving NeverNote.updateListDateChanged");
4046 private void updateListDateChanged() {
4047 logger.log(logger.HIGH, "Entering NeverNote.updateListDateChanged");
4048 QDateTime date = new QDateTime(QDateTime.currentDateTime());
4049 updateListDateChanged(currentNoteGuid, date);
4050 logger.log(logger.HIGH, "Leaving NeverNote.updateListDateChanged");
4053 private void scrollToCurrentGuid() {
4054 //scrollToGuid(currentNoteGuid);
4055 List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
4056 if (selections.size() == 0)
4058 QModelIndex index = selections.get(0);
4059 int row = selections.get(0).row();
4060 String guid = (String)index.model().index(row, Global.noteTableGuidPosition).data();
4063 // Scroll to the current GUID in tthe list.
4064 // Scroll to a particular index item
4065 private void scrollToGuid(String guid) {
4066 if (currentNote == null || guid == null)
4068 if (currentNote.isActive() && Global.showDeleted) {
4069 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
4070 if (!listManager.getNoteIndex().get(i).isActive()) {
4071 currentNote = listManager.getNoteIndex().get(i);
4072 currentNoteGuid = currentNote.getGuid();
4073 i = listManager.getNoteIndex().size();
4077 if (!currentNote.isActive() && !Global.showDeleted) {
4078 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
4079 if (listManager.getNoteIndex().get(i).isActive()) {
4080 currentNote = listManager.getNoteIndex().get(i);
4081 currentNoteGuid = currentNote.getGuid();
4082 i = listManager.getNoteIndex().size();
4087 for (int i=0; i<noteTableView.model().rowCount(); i++) {
4088 index = noteTableView.model().index(i, Global.noteTableGuidPosition);
4089 if (currentNoteGuid.equals(index.data())) {
4090 // noteTableView.selectionModel().blockSignals(true);
4091 noteTableView.selectRow(i);
4092 // noteTableView.selectionModel().blockSignals(false);
4093 noteTableView.scrollTo(index, ScrollHint.EnsureVisible); // This should work, but it doesn't
4094 i=listManager.getNoteTableModel().rowCount();
4097 noteTableView.repaint();
4099 // Show/Hide columns
4100 private void showColumns() {
4101 noteTableView.setColumnHidden(Global.noteTableCreationPosition, !Global.isColumnVisible("dateCreated"));
4102 noteTableView.setColumnHidden(Global.noteTableChangedPosition, !Global.isColumnVisible("dateChanged"));
4103 noteTableView.setColumnHidden(Global.noteTableSubjectDatePosition, !Global.isColumnVisible("dateSubject"));
4104 noteTableView.setColumnHidden(Global.noteTableAuthorPosition, !Global.isColumnVisible("author"));
4105 noteTableView.setColumnHidden(Global.noteTableSourceUrlPosition, !Global.isColumnVisible("sourceUrl"));
4106 noteTableView.setColumnHidden(Global.noteTableTagPosition, !Global.isColumnVisible("tags"));
4107 noteTableView.setColumnHidden(Global.noteTableNotebookPosition, !Global.isColumnVisible("notebook"));
4108 noteTableView.setColumnHidden(Global.noteTableSynchronizedPosition, !Global.isColumnVisible("synchronized"));
4109 noteTableView.setColumnHidden(Global.noteTableGuidPosition, !Global.isColumnVisible("guid"));
4110 noteTableView.setColumnHidden(Global.noteTableThumbnailPosition, !Global.isColumnVisible("thumbnail"));
4111 noteTableView.setColumnHidden(Global.noteTableTitlePosition, !Global.isColumnVisible("title"));
4112 noteTableView.setColumnHidden(Global.noteTablePinnedPosition, !Global.isColumnVisible("pinned"));
4114 // Title color has changed
4115 @SuppressWarnings("unused")
4116 private void titleColorChanged(Integer color) {
4117 logger.log(logger.HIGH, "Entering NeverNote.titleColorChanged");
4120 QColor backgroundColor = new QColor();
4121 QColor foregroundColor = new QColor(QColor.black);
4122 backgroundColor.setRgb(color);
4124 if (backgroundColor.rgb() == QColor.black.rgb() || backgroundColor.rgb() == QColor.blue.rgb())
4125 foregroundColor.setRgb(QColor.white.rgb());
4127 if (selectedNoteGUIDs.size() == 0)
4128 selectedNoteGUIDs.add(currentNoteGuid);
4130 for (int j=0; j<selectedNoteGUIDs.size(); j++) {
4131 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4132 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4133 if (modelIndex != null) {
4134 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4135 String tableGuid = (String)ix.values().toArray()[0];
4136 if (tableGuid.equals(selectedNoteGUIDs.get(j))) {
4137 for (int k=0; k<Global.noteTableColumnCount; k++) {
4138 listManager.getNoteTableModel().setData(i, k, backgroundColor, Qt.ItemDataRole.BackgroundRole);
4139 listManager.getNoteTableModel().setData(i, k, foregroundColor, Qt.ItemDataRole.ForegroundRole);
4140 listManager.updateNoteTitleColor(selectedNoteGUIDs.get(j), backgroundColor.rgb());
4142 i=listManager.getNoteTableModel().rowCount();
4147 logger.log(logger.HIGH, "Leaving NeverNote.titleColorChanged");
4149 // A note has been pinned or unpinned
4150 @SuppressWarnings("unused")
4151 private void notePinned() {
4152 logger.log(logger.EXTREME, "Entering NeverNote.notePinned()");
4155 for (int j=0; j<selectedNoteGUIDs.size(); j++) {
4156 NoteMetadata meta = listManager.getNoteMetadata().get(selectedNoteGUIDs.get(j));
4157 boolean pinned = !meta.isPinned();
4158 meta.setPinned(pinned); // Toggle the pinned/unpinned
4160 // Update the list & table
4161 listManager.updateNoteMetadata(meta);
4162 noteTableView.proxyModel.addGuid(selectedNoteGUIDs.get(j), meta);
4165 logger.log(logger.EXTREME, "Leaving NeverNote.setNoteDirty()");
4167 // Wide list was chosen
4168 public void narrowListView() {
4169 saveNoteColumnPositions();
4170 saveNoteIndexWidth();
4172 int sortCol = noteTableView.proxyModel.sortColumn();
4173 int sortOrder = noteTableView.proxyModel.sortOrder().value();
4174 Global.setSortColumn(sortCol);
4175 Global.setSortOrder(sortOrder);
4177 Global.setListView(Global.View_List_Narrow);
4179 menuBar.wideListView.blockSignals(true);
4180 menuBar.narrowListView.blockSignals(true);
4182 menuBar.wideListView.setChecked(false);
4183 menuBar.narrowListView.setChecked(true);
4185 menuBar.wideListView.blockSignals(false);
4186 menuBar.narrowListView.blockSignals(false);
4188 mainLeftRightSplitter.addWidget(noteTableView);
4189 mainLeftRightSplitter.addWidget(browserWindow);
4190 restoreWindowState(false);
4191 noteTableView.repositionColumns();
4192 noteTableView.resizeColumnWidths();
4193 noteTableView.resizeRowHeights();
4195 sortCol = Global.getSortColumn();
4196 sortOrder = Global.getSortOrder();
4197 noteTableView.proxyModel.blocked = true;
4198 noteTableView.sortByColumn(sortCol, SortOrder.resolve(sortOrder));
4199 noteTableView.proxyModel.blocked = false;
4203 noteTableView.load(false);
4204 refreshEvernoteNote(true);
4205 scrollToCurrentGuid();
4207 public void wideListView() {
4208 int sortCol = noteTableView.proxyModel.sortColumn();
4209 int sortOrder = noteTableView.proxyModel.sortOrder().value();
4210 Global.setSortColumn(sortCol);
4211 Global.setSortOrder(sortOrder);
4214 saveNoteColumnPositions();
4215 saveNoteIndexWidth();
4216 Global.setListView(Global.View_List_Wide);
4218 menuBar.wideListView.blockSignals(true);
4219 menuBar.narrowListView.blockSignals(true);
4221 menuBar.wideListView.setChecked(true);
4222 menuBar.narrowListView.setChecked(false);
4224 menuBar.wideListView.blockSignals(false);
4225 menuBar.narrowListView.blockSignals(false);
4226 browserIndexSplitter.setVisible(true);
4227 browserIndexSplitter.addWidget(noteTableView);
4228 browserIndexSplitter.addWidget(browserWindow);
4229 restoreWindowState(false);
4230 noteTableView.repositionColumns();
4231 noteTableView.resizeColumnWidths();
4232 noteTableView.resizeRowHeights();
4234 sortCol = Global.getSortColumn();
4235 sortOrder = Global.getSortOrder();
4236 noteTableView.proxyModel.blocked = true;
4237 noteTableView.sortByColumn(sortCol, SortOrder.resolve(sortOrder));
4238 noteTableView.proxyModel.blocked = false;
4241 noteTableView.load(false);
4242 scrollToCurrentGuid();
4244 // Sort order for the notebook has changed
4245 public void tableSortOrderChanged(Integer column, Integer order) {
4247 // Find what notebook (if any) is selected. We ignore stacks & the "All Notebooks".
4248 List<QTreeWidgetItem> selectedNotebook = notebookTree.selectedItems();
4249 if (selectedNotebook.size() > 0 && !selectedNotebook.get(0).text(0).equalsIgnoreCase("All Notebooks") && !selectedNotebook.get(0).text(2).equalsIgnoreCase("STACK")) {
4250 QTreeWidgetItem currentSelectedNotebook = selectedNotebook.get(0);
4252 notebook = currentSelectedNotebook.text(2);
4253 conn.getNotebookTable().setSortOrder(notebook, column, order);
4257 //***************************************************************
4258 @SuppressWarnings("unused")
4259 private void evernoteLinkClick(String syncGuid, String locGuid) {
4261 if (conn.getNoteTable().guidExists(syncGuid)) {
4264 // If we didn't find it via the synchronized guid, look under the local guid
4265 // Iwe don't find it there, look to see if the GUID is posted under the local GUID, but was
4266 // later synchronized (that causes the guid to change so we need to find the new one).
4267 if (conn.getNoteTable().guidExists(locGuid))
4270 guid = conn.getNoteTable().findAlternateGuid(locGuid);
4273 openExternalEditor(guid);
4277 //If we've gotten this far, we can't find the note
4278 QMessageBox.information(this, tr("Note Not Found"), tr("Sorry, but I can't"+
4279 " seem to find that note."));
4281 //***************************************************************
4282 //***************************************************************
4283 //** External editor window functions
4284 //***************************************************************
4285 //***************************************************************
4286 private void listDoubleClick() {
4288 openExternalEditor(currentNoteGuid);
4290 private void openExternalEditor(String guid) {
4292 if (externalWindows.containsKey(guid)) {
4293 externalWindows.get(guid).raise();
4296 Note note = conn.getNoteTable().getNote(guid, true, true, false, true, true);
4297 // We have a new external editor to create
4298 QIcon appIcon = new QIcon(iconPath+"nevernote.png");
4299 ExternalBrowse newBrowser = new ExternalBrowse(conn);
4300 newBrowser.setWindowIcon(appIcon);
4301 externalWindows.put(guid, newBrowser);
4302 showEditorButtons(newBrowser.getBrowserWindow());
4303 loadNoteBrowserInformation(newBrowser.getBrowserWindow(), guid, note);
4304 setupBrowserWindowListeners(newBrowser.getBrowserWindow(), false);
4305 newBrowser.windowClosing.connect(this, "externalWindowClosing(String)");
4306 //newBrowser.getBrowserWindow().noteSignal.titleChanged.connect(this, "externalWindowTitleEdited(String, String)");
4307 newBrowser.getBrowserWindow().noteSignal.tagsChanged.connect(this, "externalWindowTagsEdited(String, List)");
4308 newBrowser.contentsChanged.connect(this, "saveNoteExternalBrowser(String, String, Boolean, BrowserWindow)");
4309 newBrowser.getBrowserWindow().blockApplication.connect(this, "blockApplication(BrowserWindow)");
4310 newBrowser.getBrowserWindow().unblockApplication.connect(this, "unblockApplication()");
4312 browserWindow.noteSignal.tagsChanged.connect(newBrowser, "updateTags(String, List)");
4313 browserWindow.noteSignal.titleChanged.connect(newBrowser, "updateTitle(String, String)");
4314 browserWindow.noteSignal.notebookChanged.connect(newBrowser, "updateNotebook(String, String)");
4318 @SuppressWarnings({ "rawtypes", "unused" })
4319 private void externalWindowTagsEdited(String guid, List values) {
4320 StringBuffer line = new StringBuffer(100);
4321 for (int i=0; i<values.size(); i++) {
4323 line.append(Global.tagDelimeter+" ");
4324 line.append(values.get(i));
4326 if (guid.equals(currentNoteGuid)) {
4327 browserWindow.setTag(line.toString());
4330 @SuppressWarnings("unused")
4331 private void externalWindowClosing(String guid) {
4332 externalWindows.remove(guid);
4337 //***************************************************************
4338 //***************************************************************
4339 //** These functions deal with Note specific things
4340 //***************************************************************
4341 //***************************************************************
4342 private void setNoteDirty() {
4343 logger.log(logger.EXTREME, "Entering NeverNote.setNoteDirty()");
4345 // Find if the note is being edited externally. If it is, update it.
4346 if (externalWindows.containsKey(currentNoteGuid)) {
4347 QTextCodec codec = QTextCodec.codecForName("UTF-8");
4348 QByteArray unicode = codec.fromUnicode(browserWindow.getContent());
4349 ExternalBrowse window = externalWindows.get(currentNoteGuid);
4350 window.getBrowserWindow().setContent(unicode);
4353 // If the note is dirty, then it is unsynchronized by default.
4357 // Set the note as dirty and check if its status is synchronized in the display table
4359 if (listManager.getNoteMetadata().containsKey(currentNoteGuid) &&
4360 listManager.getNoteMetadata().get(currentNoteGuid).isDirty()) {
4364 // If this wasn't already marked as unsynchronized, then we need to update the table
4365 listManager.getNoteTableModel().updateNoteSyncStatus(currentNoteGuid, false);
4366 // listManager.getUnsynchronizedNotes().add(currentNoteGuid);
4367 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4368 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4369 if (modelIndex != null) {
4370 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4371 String tableGuid = (String)ix.values().toArray()[0];
4372 if (tableGuid.equals(currentNoteGuid)) {
4373 listManager.getNoteTableModel().proxyModel.setData(i, Global.noteTableSynchronizedPosition, "false");
4379 logger.log(logger.EXTREME, "Leaving NeverNote.setNoteDirty()");
4381 @SuppressWarnings("unused")
4382 private void saveNoteExternalBrowser(String guid, String content, Boolean save, BrowserWindow browser) {
4383 QTextCodec codec = QTextCodec.codecForName("UTF-8");
4384 QByteArray unicode = codec.fromUnicode(content);
4385 noteCache.remove(guid);
4386 noteCache.put(guid, unicode.toString());
4387 if (guid.equals(currentNoteGuid)) {
4389 browserWindow.setContent(unicode);
4392 thumbnailRunner.addWork("GENERATE "+ guid);
4393 saveNote(guid, browser);
4397 private void saveNote() {
4399 saveNote(currentNoteGuid, browserWindow);
4400 thumbnailRunner.addWork("GENERATE "+ currentNoteGuid);
4404 private void saveNote(String guid, BrowserWindow window) {
4405 logger.log(logger.EXTREME, "Inside NeverNote.saveNote()");
4408 logger.log(logger.EXTREME, "Saving to cache");
4409 QTextCodec codec = QTextCodec.codecForLocale();
4410 // QTextDecoder decoder = codec.makeDecoder();
4411 codec = QTextCodec.codecForName("UTF-8");
4412 QByteArray unicode = codec.fromUnicode(window.getContent());
4413 noteCache.put(guid, unicode.toString());
4415 logger.log(logger.EXTREME, "updating list manager");
4416 listManager.updateNoteContent(guid, window.getContent());
4417 logger.log(logger.EXTREME, "Updating title");
4418 listManager.updateNoteTitle(guid, window.getTitle());
4419 updateListDateChanged();
4421 logger.log(logger.EXTREME, "Looking through note index for refreshed note");
4422 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
4423 if (listManager.getNoteIndex().get(i).getGuid().equals(guid)) {
4424 currentNote = listManager.getNoteIndex().get(i);
4425 i = listManager.getNoteIndex().size();
4430 // Get a note from Evernote (and put it in the browser)
4431 private void refreshEvernoteNote(boolean reload) {
4432 logger.log(logger.HIGH, "Entering NeverNote.refreshEvernoteNote");
4434 if (Global.disableViewing) {
4435 browserWindow.setEnabled(false);
4440 if (Global.showDeleted || currentNoteGuid == null || currentNoteGuid.equals(""))
4442 Global.cryptCounter =0;
4444 browserWindow.setReadOnly(true);
4451 browserWindow.loadingData(true);
4453 currentNote = conn.getNoteTable().getNote(currentNoteGuid, true,true,false,false,true);
4454 if (currentNote == null)
4456 loadNoteBrowserInformation(browserWindow, currentNoteGuid, currentNote);
4459 private void loadNoteBrowserInformation(BrowserWindow browser, String guid, Note note) {
4460 NoteFormatter formatter = new NoteFormatter(logger, conn, tempFiles);
4461 formatter.setNote(note, Global.pdfPreview());
4462 formatter.setHighlight(listManager.getEnSearch());
4464 if (!noteCache.containsKey(guid)) {
4465 js = new QByteArray();
4466 // We need to prepend the note with <HEAD></HEAD> or encoded characters are ugly
4467 js.append("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">");
4468 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>");
4469 js.append("<style type=\"text/css\">en-hilight { background-color: rgb(255,255,0) }</style>");
4470 js.append("<style> img { height:auto; width:auto; max-height:auto; max-width:100%; }</style>");
4471 if (Global.displayRightToLeft())
4472 js.append("<style> body { direction:rtl; }</style>");
4473 js.append("<style type=\"text/css\">en-spell { text-decoration: none; border-bottom: dotted 1px #cc0000; }</style>");
4474 js.append("</head>");
4475 formatter.setNote(note, Global.pdfPreview());
4476 js.append(formatter.rebuildNoteHTML());
4477 js.append("</HTML>");
4478 js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml.dtd'>", "");
4479 js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml2.dtd'>", "");
4480 js.replace("<?xml version='1.0' encoding='UTF-8'?>", "");
4481 // if (Global.enableHTMLEntitiesFix) {
4482 // browser.getBrowser().setContent(new QByteArray(StringEscapeUtils.unescapeHtml(js.toString())));
4484 browser.setContent(js);
4485 noteCache.put(guid, js.toString());
4487 if (formatter.resourceError)
4488 resourceErrorMessage();
4489 if (formatter.formatError) {
4491 QMessageBox.information(this, tr("Error"),
4492 tr("NixNote had issues formatting this note." +
4493 " To protect your data this note is being marked as read-only."));
4496 readOnly = formatter.readOnly;
4497 inkNote = formatter.inkNote;
4499 readOnlyCache.put(guid, true);
4501 inkNoteCache.put(guid, true);
4503 logger.log(logger.HIGH, "Note content is being pulled from the cache");
4504 String cachedContent = formatter.modifyCachedTodoTags(noteCache.get(guid));
4505 js = new QByteArray(cachedContent);
4506 browser.setContent(js);
4507 if (readOnlyCache.containsKey(guid))
4509 if (inkNoteCache.containsKey(guid))
4512 if (conn.getNoteTable().isThumbnailNeeded(guid)) {
4513 thumbnailHTMLReady(guid, js, Global.calculateThumbnailZoom(js.toString()));
4515 if (readOnly || inkNote ||
4516 (note.getAttributes() != null && note.getAttributes().getContentClass() != null && note.getAttributes().getContentClass() != ""))
4517 browser.getBrowser().page().setContentEditable(false); // We don't allow editing of ink notes
4519 browser.getBrowser().page().setContentEditable(true);
4520 browser.setReadOnly(readOnly);
4521 deleteButton.setEnabled(!readOnly);
4522 tagButton.setEnabled(!readOnly);
4523 menuBar.noteDelete.setEnabled(!readOnly);
4524 menuBar.noteTags.setEnabled(!readOnly);
4525 browser.setNote(note);
4527 if (note != null && note.getNotebookGuid() != null &&
4528 conn.getNotebookTable().isLinked(note.getNotebookGuid())) {
4529 deleteButton.setEnabled(false);
4530 menuBar.notebookDeleteAction.setEnabled(false);
4532 deleteButton.setEnabled(true);
4533 menuBar.notebookDeleteAction.setEnabled(true);
4536 // Build a list of non-closed notebooks
4537 List<Notebook> nbooks = new ArrayList<Notebook>();
4538 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
4539 boolean found=false;
4540 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
4541 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid()))
4545 nbooks.add(listManager.getNotebookIndex().get(i));
4548 browser.setTitle(note.getTitle());
4549 browser.setTag(getTagNamesForNote(note));
4550 browser.setAuthor(note.getAttributes().getAuthor());
4552 browser.setAltered(note.getUpdated());
4553 browser.setCreation(note.getCreated());
4554 if (note.getAttributes().getSubjectDate() > 0)
4555 browser.setSubjectDate(note.getAttributes().getSubjectDate());
4557 browser.setSubjectDate(note.getCreated());
4558 browser.setUrl(note.getAttributes().getSourceURL());
4560 FilterEditorTags tagFilter = new FilterEditorTags(conn, logger);
4561 List<Tag> tagList = tagFilter.getValidTags(note);
4562 browser.setAllTags(tagList);
4564 browser.setCurrentTags(note.getTagNames());
4568 browser.loadingData(false);
4569 if (thumbnailViewer.isActiveWindow())
4572 FilterEditorNotebooks notebookFilter = new FilterEditorNotebooks(conn, logger);
4573 browser.setNotebookList(notebookFilter.getValidNotebooks(note, listManager.getNotebookIndex()));
4576 logger.log(logger.HIGH, "Leaving NeverNote.refreshEvernoteNote");
4578 // Save a generated thumbnail
4579 private void toggleNoteInformation() {
4580 logger.log(logger.HIGH, "Entering NeverNote.toggleNoteInformation");
4581 browserWindow.toggleInformation();
4582 menuBar.noteAttributes.setChecked(browserWindow.isExtended());
4583 Global.saveWindowVisible("noteInformation", browserWindow.isExtended());
4584 logger.log(logger.HIGH, "Leaving NeverNote.toggleNoteInformation");
4586 // Listener triggered when a print button is pressed
4587 @SuppressWarnings("unused")
4588 private void printNote() {
4589 logger.log(logger.HIGH, "Entering NeverNote.printNote");
4591 QPrintDialog dialog = new QPrintDialog();
4592 if (dialog.exec() == QDialog.DialogCode.Accepted.value()) {
4593 QPrinter printer = dialog.printer();
4594 browserWindow.getBrowser().print(printer);
4596 logger.log(logger.HIGH, "Leaving NeverNote.printNote");
4599 // Listener triggered when the email button is pressed
4600 @SuppressWarnings("unused")
4601 private void emailNote() {
4602 logger.log(logger.HIGH, "Entering NeverNote.emailNote");
4604 if (Desktop.isDesktopSupported()) {
4605 Desktop desktop = Desktop.getDesktop();
4607 String text2 = browserWindow.getContentsToEmail();
4608 QUrl url = new QUrl("mailto:");
4609 url.addQueryItem("subject", currentNote.getTitle());
4610 // url.addQueryItem("body", QUrl.toPercentEncoding(text2).toString());
4611 url.addQueryItem("body", text2);
4612 QDesktopServices.openUrl(url);
4616 if (desktop.isSupported(Desktop.Action.MAIL)) {
4617 URI uriMailTo = null;
4619 //String text = browserWindow.getBrowser().page().currentFrame().toPlainText();
4620 String text = browserWindow.getContentsToEmail();
4621 //text = "<b>" +text +"</b>";
4622 uriMailTo = new URI("mailto", "&SUBJECT="+currentNote.getTitle()
4623 +"&BODY=" +text, null);
4624 uriMailTo = new URI("mailto", "&SUBJECT="+currentNote.getTitle()
4625 +"&ATTACHMENT=d:/test.pdf", null);
4626 desktop.mail(uriMailTo);
4627 } catch (URISyntaxException e) {
4628 e.printStackTrace();
4629 } catch (IOException e) {
4630 e.printStackTrace();
4637 logger.log(logger.HIGH, "Leaving NeverNote.emailNote");
4639 // Reindex all notes
4640 @SuppressWarnings("unused")
4641 private void fullReindex() {
4642 logger.log(logger.HIGH, "Entering NeverNote.fullReindex");
4643 indexRunner.addWork("REINDEXALL");
4644 setMessage(tr("Database will be reindexed."));
4645 logger.log(logger.HIGH, "Leaving NeverNote.fullReindex");
4647 // Listener when a user wants to reindex a specific note
4648 @SuppressWarnings("unused")
4649 private void reindexNote() {
4650 logger.log(logger.HIGH, "Entering NeverNote.reindexNote");
4651 for (int i=0; i<selectedNoteGUIDs.size(); i++) {
4652 indexRunner.addWork("REINDEXNOTE "+selectedNoteGUIDs.get(i));
4654 if (selectedNotebookGUIDs.size() > 1)
4655 setMessage(tr("Notes will be reindexed."));
4657 setMessage(tr("Note will be reindexed."));
4658 logger.log(logger.HIGH, "Leaving NeverNote.reindexNote");
4661 @SuppressWarnings("unused")
4662 private void deleteNote() {
4663 logger.log(logger.HIGH, "Entering NeverNote.deleteNote");
4664 if (currentNote == null)
4666 if (currentNoteGuid.equals(""))
4668 String title = null;
4669 if (selectedNoteGUIDs.size() == 1)
4670 title = conn.getNoteTable().getNote(selectedNoteGUIDs.get(0),false,false,false,false,false).getTitle();
4672 // If we are deleting non-trash notes
4673 if (currentNote.isActive()) {
4674 if (Global.verifyDelete()) {
4676 if (selectedNoteGUIDs.size() > 1) {
4677 msg = new String(tr("Delete ") +selectedNoteGUIDs.size() +" notes?");
4680 msg = new String(tr("Delete note \"") +title +"\"?");
4682 msg = new String(tr("Delete note selected note?"));
4684 if (QMessageBox.question(this, tr("Confirmation"), msg,
4685 QMessageBox.StandardButton.Yes,
4686 QMessageBox.StandardButton.No)==StandardButton.No.value() && Global.verifyDelete() == true) {
4690 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
4691 selectedNoteGUIDs.add(currentNoteGuid);
4692 for (int i=0; i<selectedNoteGUIDs.size(); i++) {
4693 listManager.deleteNote(selectedNoteGUIDs.get(i));
4696 // If we are deleting from the trash.
4697 if (Global.verifyDelete()) {
4699 if (selectedNoteGUIDs.size() > 1) {
4700 msg = new String(tr("Permanently delete ") +selectedNoteGUIDs.size() +" notes?");
4703 msg = new String(tr("Permanently delete note \"") +title +"\"?");
4705 msg = new String(tr("Permanently delete note selected note?"));
4707 if (QMessageBox.question(this, "Confirmation", msg,
4708 QMessageBox.StandardButton.Yes,
4709 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
4713 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
4714 selectedNoteGUIDs.add(currentNoteGuid);
4715 for (int i=selectedNoteGUIDs.size()-1; i>=0; i--) {
4716 for (int j=listManager.getNoteTableModel().rowCount()-1; j>=0; j--) {
4717 QModelIndex modelIndex = listManager.getNoteTableModel().index(j, Global.noteTableGuidPosition);
4718 if (modelIndex != null) {
4719 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4720 String tableGuid = (String)ix.values().toArray()[0];
4721 if (tableGuid.equals(selectedNoteGUIDs.get(i))) {
4722 listManager.getNoteTableModel().removeRow(j);
4727 listManager.expungeNote(selectedNoteGUIDs.get(i));
4730 currentNoteGuid = "";
4731 listManager.loadNotesIndex();
4732 noteIndexUpdated(false);
4733 refreshEvernoteNote(true);
4734 scrollToGuid(currentNoteGuid);
4735 logger.log(logger.HIGH, "Leaving NeverNote.deleteNote");
4738 @SuppressWarnings("unused")
4739 private void addNote() {
4740 logger.log(logger.HIGH, "Inside NeverNote.addNote");
4741 // browserWindow.setEnabled(true);
4742 browserWindow.setReadOnly(false);
4744 Calendar currentTime = new GregorianCalendar();
4745 StringBuffer noteString = new StringBuffer(100);
4746 noteString.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
4747 "<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">\n" +
4750 if (Global.overrideDefaultFont()) {
4751 noteString.append("<font face=\"" +Global.getDefaultFont() +"\" >");
4752 noteString.append("<span style=\"font-size:" +Global.getDefaultFontSize() +"pt;\">");
4753 noteString.append("<br clear=\"none\" />\n");
4754 noteString.append("</span>\n</font>\n");
4756 noteString.append("<br clear=\"none\" />\n");
4757 noteString.append("</en-note>");
4759 Long l = new Long(currentTime.getTimeInMillis());
4760 String randint = new String(Long.toString(l));
4762 // Find a notebook. We first look for a selected notebook (the "All Notebooks" one doesn't count).
4764 // for the first non-archived notebook. Finally, if nothing else we
4765 // pick the first notebook in the list.
4766 String notebook = null;
4767 listManager.getNotebookIndex().get(0).getGuid();
4768 List<QTreeWidgetItem> selectedNotebook = notebookTree.selectedItems();
4769 if (selectedNotebook.size() > 0 && !selectedNotebook.get(0).text(0).equalsIgnoreCase("All Notebooks") && !selectedNotebook.get(0).text(2).equalsIgnoreCase("STACK")) {
4770 QTreeWidgetItem currentSelectedNotebook = selectedNotebook.get(0);
4771 notebook = currentSelectedNotebook.text(2);
4773 boolean found = false;
4774 List<Notebook> goodNotebooks = new ArrayList<Notebook>();
4775 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
4776 boolean match = false;
4777 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
4778 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid())) {
4780 j = listManager.getArchiveNotebookIndex().size();
4784 //goodNotebooks.add(listManager.getNotebookIndex().get(i).deepCopy());
4785 goodNotebooks.add((Notebook)Global.deepCopy(listManager.getNotebookIndex().get(i)));
4787 // Now we have a list of good notebooks, so we can look for the default
4789 for (int i=0; i<goodNotebooks.size(); i++) {
4790 if (goodNotebooks.get(i).isDefaultNotebook()) {
4791 notebook = goodNotebooks.get(i).getGuid();
4793 i = goodNotebooks.size();
4797 if (goodNotebooks.size() > 0 && !found)
4798 notebook = goodNotebooks.get(0).getGuid();
4801 notebook = listManager.getNotebookIndex().get(0).getGuid();
4804 Note newNote = new Note();
4805 newNote.setUpdateSequenceNum(0);
4806 newNote.setGuid(randint);
4807 newNote.setNotebookGuid(notebook);
4808 newNote.setTitle("Untitled Note");
4809 newNote.setContent(noteString.toString());
4810 newNote.setDeleted(0);
4811 newNote.setCreated(System.currentTimeMillis());
4812 newNote.setUpdated(System.currentTimeMillis());
4813 newNote.setActive(true);
4814 NoteAttributes na = new NoteAttributes();
4815 na.setLatitude(0.0);
4816 na.setLongitude(0.0);
4817 na.setAltitude(0.0);
4818 newNote.setAttributes(new NoteAttributes());
4819 newNote.setTagGuids(new ArrayList<String>());
4820 newNote.setTagNames(new ArrayList<String>());
4822 // If new notes are to be created based upon the selected tags, then we need to assign the tags
4823 if (Global.newNoteWithSelectedTags()) {
4824 List<QTreeWidgetItem> selections = tagTree.selectedItems();
4825 QTreeWidgetItem currentSelection;
4826 for (int i=0; i<selections.size(); i++) {
4827 currentSelection = selections.get(i);
4828 newNote.getTagGuids().add(currentSelection.text(2));
4829 newNote.getTagNames().add(currentSelection.text(0));
4833 conn.getNoteTable().addNote(newNote, true);
4834 NoteMetadata metadata = new NoteMetadata();
4835 metadata.setGuid(newNote.getGuid());
4836 metadata.setDirty(true);
4837 listManager.addNote(newNote, metadata);
4838 // noteTableView.insertRow(newNote, true, -1);
4840 currentNote = newNote;
4841 currentNoteGuid = currentNote.getGuid();
4842 noteTableView.clearSelection();
4843 refreshEvernoteNote(true);
4844 listManager.countNotebookResults(listManager.getNoteIndex());
4845 browserWindow.titleLabel.setFocus();
4846 browserWindow.titleLabel.selectAll();
4847 // notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
4849 // If the window is hidden, then we want to popup this in an external window &
4853 logger.log(logger.HIGH, "Leaving NeverNote.addNote");
4855 // Restore a note from the trash;
4856 @SuppressWarnings("unused")
4857 private void restoreNote() {
4859 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
4860 selectedNoteGUIDs.add(currentNoteGuid);
4861 for (int i=0; i<selectedNoteGUIDs.size(); i++) {
4862 listManager.restoreNote(selectedNoteGUIDs.get(i));
4864 currentNoteGuid = "";
4865 listManager.loadNotesIndex();
4866 noteIndexUpdated(false);
4869 // Search a note for specific txt
4870 @SuppressWarnings("unused")
4871 private void findText() {
4873 find.setFocusOnTextField();
4875 @SuppressWarnings("unused")
4876 private void doFindText() {
4877 browserWindow.getBrowser().page().findText(find.getText(), find.getFlags());
4880 @SuppressWarnings("unused")
4881 private void updateNoteTitle(String guid, String title) {
4882 listManager.setNoteSynchronized(guid, false);
4884 // We do this manually because if we've edited the note in an
4885 // external window we run into the possibility of signal recursion
4887 if (guid.equals(currentNoteGuid)) {
4888 browserWindow.titleLabel.blockSignals(true);
4889 browserWindow.titleLabel.setText(title);
4890 browserWindow.titleLabel.blockSignals(false);
4893 // Signal received that note content has changed. Normally we just need the guid to remove
4894 // it from the cache.
4895 @SuppressWarnings("unused")
4896 private void invalidateNoteCache(String guid, String content) {
4897 noteCache.remove(guid);
4898 refreshEvernoteNote(true);
4900 // Signal received that a note guid has changed
4901 @SuppressWarnings("unused")
4902 private void noteGuidChanged(String oldGuid, String newGuid) {
4903 if (noteCache.containsKey(oldGuid)) {
4904 if (!oldGuid.equals(currentNoteGuid)) {
4905 String cache = noteCache.get(oldGuid);
4906 noteCache.put(newGuid, cache);
4907 noteCache.remove(oldGuid);
4909 noteCache.remove(oldGuid);
4910 noteCache.put(newGuid, browserWindow.getContent());
4914 listManager.updateNoteGuid(oldGuid, newGuid, false);
4915 if (currentNoteGuid.equals(oldGuid)) {
4916 if (currentNote != null)
4917 currentNote.setGuid(newGuid);
4918 currentNoteGuid = newGuid;
4921 if (externalWindows.containsKey(oldGuid)) {
4922 ExternalBrowse b = externalWindows.get(oldGuid);
4923 externalWindows.remove(oldGuid);
4924 b.getBrowserWindow().getNote().setGuid(newGuid);
4925 externalWindows.put(newGuid, b);
4928 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
4929 if (listManager.getNoteIndex().get(i).getGuid().equals(newGuid)) {
4930 noteTableView.proxyModel.addGuid(newGuid, listManager.getNoteMetadata().get(newGuid));
4931 i=listManager.getNoteIndex().size();
4935 if (listManager.getNoteTableModel().metaData.containsKey(oldGuid)) {
4936 NoteMetadata meta = listManager.getNoteTableModel().metaData.get(oldGuid);
4937 listManager.getNoteTableModel().metaData.put(newGuid, meta);
4938 listManager.getNoteTableModel().metaData.remove(oldGuid);
4942 // Toggle the note editor button bar
4943 private void toggleEditorButtonBar() {
4944 if (browserWindow.buttonsVisible) {
4945 browserWindow.hideButtons();
4946 menuBar.showEditorBar.setChecked(browserWindow.buttonsVisible);
4947 // Global.saveWindowVisible("editorButtonBar", browserWindow.buttonsVisible);
4949 browserWindow.buttonsVisible = true;
4950 showEditorButtons(browserWindow);
4952 Global.saveWindowVisible("editorButtonBar", browserWindow.buttonsVisible);
4954 // Show editor buttons
4955 private void showEditorButtons(BrowserWindow browser) {
4956 browser.buttonLayout.setVisible(true);
4957 browser.undoAction.setVisible(false);
4959 browser.undoButton.setVisible(false);
4961 browser.undoAction.setVisible(Global.isEditorButtonVisible("undo"));
4962 browser.redoAction.setVisible(Global.isEditorButtonVisible("redo"));
4963 browser.cutAction.setVisible(Global.isEditorButtonVisible("cut"));
4964 browser.copyAction.setVisible(Global.isEditorButtonVisible("copy"));
4965 browser.pasteAction.setVisible(Global.isEditorButtonVisible("paste"));
4966 browser.strikethroughAction.setVisible(Global.isEditorButtonVisible("strikethrough"));
4967 browser.underlineAction.setVisible(Global.isEditorButtonVisible("underline"));
4968 browser.boldAction.setVisible(Global.isEditorButtonVisible("bold"));
4969 browser.italicAction.setVisible(Global.isEditorButtonVisible("italic"));
4970 browser.hlineAction.setVisible(Global.isEditorButtonVisible("hline"));
4971 browser.indentAction.setVisible(Global.isEditorButtonVisible("indent"));
4972 browser.outdentAction.setVisible(Global.isEditorButtonVisible("outdent"));
4973 browser.bulletListAction.setVisible(Global.isEditorButtonVisible("bulletList"));
4974 browser.numberListAction.setVisible(Global.isEditorButtonVisible("numberList"));
4975 browser.fontListAction.setVisible(Global.isEditorButtonVisible("font"));
4976 browser.fontSizeAction.setVisible(Global.isEditorButtonVisible("fontSize"));
4977 browser.fontColorAction.setVisible(Global.isEditorButtonVisible("fontColor"));
4978 browser.fontHilightAction.setVisible(Global.isEditorButtonVisible("fontHilight"));
4979 browser.leftAlignAction.setVisible(Global.isEditorButtonVisible("alignLeft"));
4980 browser.centerAlignAction.setVisible(Global.isEditorButtonVisible("alignCenter"));
4981 browser.rightAlignAction.setVisible(Global.isEditorButtonVisible("alignRight"));
4982 browser.spellCheckAction.setVisible(Global.isEditorButtonVisible("spellCheck"));
4983 browser.todoAction.setVisible(Global.isEditorButtonVisible("todo"));
4985 private void duplicateNote(String guid) {
4987 Note oldNote = conn.getNoteTable().getNote(guid, true, false,false,false,true);
4988 List<Resource> resList = conn.getNoteTable().noteResourceTable.getNoteResources(guid, true);
4989 oldNote.setContent(conn.getNoteTable().getNoteContentNoUTFConversion(guid));
4990 oldNote.setResources(resList);
4991 duplicateNote(oldNote);
4993 private void duplicateNote(Note oldNote) {
4995 // Now that we have a good notebook guid, we need to move the conflicting note
4996 // to the local notebook
4997 Calendar currentTime = new GregorianCalendar();
4998 Long l = new Long(currentTime.getTimeInMillis());
4999 String newGuid = new String(Long.toString(l));
5001 // Note newNote = oldNote.deepCopy();
5002 Note newNote = (Note)Global.deepCopy(oldNote);
5003 newNote.setUpdateSequenceNum(0);
5004 newNote.setGuid(newGuid);
5005 newNote.setDeleted(0);
5006 newNote.setActive(true);
5009 List<String> tagNames = new ArrayList<String>();
5010 List<String> tagGuids = new ArrayList<String>();;
5011 for (int i=0; i<oldNote.getTagGuidsSize(); i++) {
5012 tagNames.add(oldNote.getTagNames().get(i));
5013 tagGuids.add(oldNote.getTagGuids().get(i));
5016 // Sort note Tags to make them look nice
5017 for (int i=0; i<tagNames.size()-1; i++) {
5018 if (tagNames.get(i).compareTo(tagNames.get(i+1))<0) {
5019 String n1 = tagNames.get(i);
5020 String n2 = tagNames.get(i+1);
5021 tagNames.set(i, n2);
5022 tagNames.set(i+1, n1);
5025 newNote.setTagGuids(tagGuids);
5026 newNote.setTagNames(tagNames);
5028 // Add tag guids to note
5031 // Duplicate resources
5032 List<Resource> resList = oldNote.getResources();
5033 if (resList == null)
5034 resList = new ArrayList<Resource>();
5036 for (int i=0; i<resList.size(); i++) {
5038 while (l == prevGuid) {
5039 currentTime = new GregorianCalendar();
5040 l = new Long(currentTime.getTimeInMillis());
5043 String newResGuid = new String(Long.toString(l));
5044 resList.get(i).setNoteGuid(newGuid);
5045 resList.get(i).setGuid(newResGuid);
5046 resList.get(i).setUpdateSequenceNum(0);
5047 resList.get(i).setActive(true);
5048 conn.getNoteTable().noteResourceTable.saveNoteResource(
5049 (Resource)Global.deepCopy(resList.get(i)), true);
5051 newNote.setResources(resList);
5053 // Add note to the database
5054 conn.getNoteTable().addNote(newNote, true);
5055 NoteMetadata metaData = new NoteMetadata();
5056 NoteMetadata oldMeta = listManager.getNoteMetadata().get(oldNote.getGuid());
5057 metaData.copy(oldMeta);
5058 metaData.setGuid(newNote.getGuid());
5059 listManager.addNote(newNote, metaData);
5060 noteTableView.insertRow(newNote, metaData, true, -1);
5061 currentNoteGuid = newNote.getGuid();
5062 currentNote = newNote;
5063 refreshEvernoteNote(true);
5064 listManager.countNotebookResults(listManager.getNoteIndex());
5068 @SuppressWarnings("unused")
5069 private void allNotes() {
5070 clearAttributeFilter();
5071 clearNotebookFilter();
5072 clearSavedSearchFilter();
5075 searchField.clear();
5076 if (Global.mimicEvernoteInterface) {
5077 notebookTree.selectGuid("");
5079 notebookTreeSelection();
5080 refreshEvernoteNote(true);
5083 @SuppressWarnings("unused")
5084 private void mergeNotes() {
5085 logger.log(logger.HIGH, "Merging notes");
5088 String masterGuid = null;
5089 List<String> sources = new ArrayList<String>();
5091 for (int i=0; i<noteTableView.selectionModel().selectedRows().size(); i++) {
5092 int r = noteTableView.selectionModel().selectedRows().get(i).row();
5093 index = noteTableView.proxyModel.index(r, Global.noteTableGuidPosition);
5094 SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
5096 masterGuid = (String)ix.values().toArray()[0];
5098 sources.add((String)ix.values().toArray()[0]);
5101 logger.log(logger.EXTREME, "Master guid=" +masterGuid);
5102 logger.log(logger.EXTREME, "Children count: "+sources.size());
5103 mergeNoteContents(masterGuid, sources);
5104 currentNoteGuid = masterGuid;
5105 noteIndexUpdated(false);
5106 refreshEvernoteNote(true);
5109 private void mergeNoteContents(String targetGuid, List<String> sources) {
5110 Note target = conn.getNoteTable().getNote(targetGuid, true, false, false, false, false);
5111 String newContent = target.getContent();
5112 newContent = newContent.replace("</en-note>", "<br></br>");
5114 for (int i=0; i<sources.size(); i++) {
5115 Note source = conn.getNoteTable().getNote(sources.get(i), true, true, false, false, false);
5116 if (source.isSetTitle()) {
5117 newContent = newContent +("<table bgcolor=\"lightgrey\"><tr><td><font size=\"6\"><b>" +source.getTitle() +"</b></font></td></tr></table>");
5119 String sourceContent = source.getContent();
5120 logger.log(logger.EXTREME, "Merging contents into note");
5121 logger.log(logger.EXTREME, sourceContent);
5122 logger.log(logger.EXTREME, "End of content");
5123 int startOfNote = sourceContent.indexOf("<en-note>");
5124 sourceContent = sourceContent.substring(startOfNote+9);
5125 int endOfNote = sourceContent.indexOf("</en-note>");
5126 sourceContent = sourceContent.substring(0,endOfNote);
5127 newContent = newContent + sourceContent;
5128 logger.log(logger.EXTREME, "New note content");
5129 logger.log(logger.EXTREME, newContent);
5130 logger.log(logger.EXTREME, "End of content");
5131 for (int j=0; j<source.getResourcesSize(); j++) {
5132 logger.log(logger.EXTREME, "Reassigning resource: "+source.getResources().get(j).getGuid());
5133 Resource r = source.getResources().get(j);
5134 Resource newRes = conn.getNoteTable().noteResourceTable.getNoteResource(r.getGuid(), true);
5136 Calendar currentTime = new GregorianCalendar();
5137 Long l = new Long(currentTime.getTimeInMillis());
5141 while (l == prevGuid) {
5142 currentTime = new GregorianCalendar();
5143 l = new Long(currentTime.getTimeInMillis());
5145 String newResGuid = new String(Long.toString(l));
5146 newRes.setNoteGuid(targetGuid);
5147 newRes.setGuid(newResGuid);
5148 newRes.setUpdateSequenceNum(0);
5149 newRes.setActive(true);
5150 conn.getNoteTable().noteResourceTable.saveNoteResource(newRes, true);
5153 logger.log(logger.EXTREME, "Updating note");
5154 conn.getNoteTable().updateNoteContent(targetGuid, newContent +"</en-note>");
5155 for (int i=0; i<sources.size(); i++) {
5156 logger.log(logger.EXTREME, "Deleting note " +sources.get(i));
5157 listManager.deleteNote(sources.get(i));
5159 logger.log(logger.EXTREME, "Exiting merge note");
5161 // A resource within a note has had a guid change
5162 @SuppressWarnings("unused")
5163 private void noteResourceGuidChanged(String noteGuid, String oldGuid, String newGuid) {
5164 if (oldGuid != null && !oldGuid.equals(newGuid))
5165 Global.resourceMap.put(oldGuid, newGuid);
5167 // View a thumbnail of the note
5168 public void thumbnailView() {
5170 String thumbnailName = Global.getFileManager().getResDirPath("thumbnail-" + currentNoteGuid + ".png");
5171 QFile thumbnail = new QFile(thumbnailName);
5172 if (!thumbnail.exists()) {
5174 QImage img = new QImage();
5175 img.loadFromData(conn.getNoteTable().getThumbnail(currentNoteGuid));
5176 thumbnailViewer.setThumbnail(img);
5178 thumbnailViewer.setThumbnail(thumbnailName);
5179 if (!thumbnailViewer.isVisible())
5180 thumbnailViewer.showFullScreen();
5182 // An error happened while saving a note. Inform the user
5183 @SuppressWarnings("unused")
5184 private void saveRunnerError(String guid, String msg) {
5186 String title = "*Unknown*";
5187 for (int i=0; i<listManager.getMasterNoteIndex().size(); i++) {
5188 if (listManager.getMasterNoteIndex().get(i).getGuid().equals(guid)) {
5189 title = listManager.getMasterNoteIndex().get(i).getTitle();
5190 i=listManager.getMasterNoteIndex().size();
5193 msg = tr("An error has happened while saving the note \"") +title+
5194 tr("\".\n\nThis is probably due to a document that is too complex for NixNote to process. "+
5195 "As a result, changes to the note may not be saved properly in the database."+
5196 "\n\nA cached copy is being preserved so you can recover any data, but data may" +
5197 "\nbe lost. Please review the note to recover any critical data before restarting.");
5199 QMessageBox.information(this, tr("Error Saving Note"), tr(msg));
5202 private void thumbnailHTMLReady(String guid, QByteArray html, Integer zoom) {
5203 logger.log(logger.HIGH, "Entering thumnailHTMLReady()");
5204 logger.log(logger.HIGH, "Thumbnail ready for " +guid);
5205 // Find an idle preview object
5206 for (int i=0; i<thumbGenerators.size(); i++) {
5207 if (thumbGenerators.get(i).mutex.tryLock()) {
5208 logger.log(logger.EXTREME, "Idle generator found - loading thumbnail for " +guid);
5209 thumbGenerators.get(i).loadContent(guid, html, zoom);
5213 if (thumbGenerators.size() >= 1) {
5214 logger.log(logger.EXTREME, "No available thumbnail generators. Aborting " +guid);
5218 logger.log(logger.EXTREME, "Creating new thumbnail generator " +guid);
5219 Thumbnailer preview = new Thumbnailer(logger, conn, listManager, thumbnailRunner);
5220 thumbGenerators.add(preview);
5222 if (preview.mutex.tryLock()) {
5223 logger.log(logger.EXTREME, "Loading thumbnail for " +guid);
5224 preview.loadContent(guid, html, zoom);
5226 logger.log(logger.HIGH, "Exiting thumnailHTMLReady()");
5231 //**********************************************************
5232 //**********************************************************
5233 //* Online user actions
5234 //**********************************************************
5235 //**********************************************************
5236 private void setupOnlineMenu() {
5237 if (!Global.isConnected) {
5238 menuBar.noteOnlineHistoryAction.setEnabled(false);
5239 menuBar.selectiveSyncAction.setEnabled(false);
5242 menuBar.noteOnlineHistoryAction.setEnabled(true);
5243 menuBar.selectiveSyncAction.setEnabled(true);
5246 @SuppressWarnings("unused")
5247 private void viewNoteHistory() {
5248 if (currentNoteGuid == null || currentNoteGuid.equals(""))
5250 if (currentNote.getUpdateSequenceNum() == 0) {
5251 setMessage(tr("Note has never been synchronized."));
5252 QMessageBox.information(this, tr("Error"), tr("This note has never been sent to Evernote, so there is no history."));
5256 setMessage(tr("Getting Note History"));
5258 Note currentOnlineNote = null;
5261 if (Global.isPremium())
5262 versions = syncRunner.localNoteStore.listNoteVersions(syncRunner.authToken, currentNoteGuid);
5264 versions = new ArrayList<NoteVersionId>();
5265 currentOnlineNote = syncRunner.localNoteStore.getNote(syncRunner.authToken, currentNoteGuid, true, true, false, false);
5266 } catch (EDAMUserException e) {
5267 setMessage("EDAMUserException: " +e.getMessage());
5269 } catch (EDAMSystemException e) {
5270 setMessage("EDAMSystemException: " +e.getMessage());
5272 } catch (EDAMNotFoundException e) {
5273 setMessage(tr("Note not found on server."));
5274 QMessageBox.information(this, tr("Error"), tr("This note could not be found on Evernote's servers."));
5276 } catch (TException e) {
5277 setMessage("EDAMTransactionException: " +e.getMessage());
5281 // If we've gotten this far, we have a good note.
5282 if (historyWindow == null) {
5283 historyWindow = new OnlineNoteHistory(logger, conn);
5284 historyWindow.historyCombo.activated.connect(this, "reloadHistoryWindow(String)");
5285 historyWindow.restoreAsNew.clicked.connect(this, "restoreHistoryNoteAsNew()");
5286 historyWindow.restore.clicked.connect(this, "restoreHistoryNote()");
5288 historyWindow.historyCombo.clear();
5290 boolean isDirty = conn.getNoteTable().isNoteDirty(currentNoteGuid);
5291 if (currentNote.getUpdateSequenceNum() != currentOnlineNote.getUpdateSequenceNum())
5293 historyWindow.setCurrent(isDirty);
5295 loadHistoryWindowContent(currentOnlineNote);
5296 historyWindow.load(versions);
5297 setMessage(tr("History retrieved"));
5299 historyWindow.exec();
5301 private Note reloadHistoryWindow(String selection) {
5303 String fmt = Global.getDateFormat() + " " + Global.getTimeFormat();
5304 String dateTimeFormat = new String(fmt);
5305 SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);
5309 for (int i=0; i<versions.size(); i++) {
5310 StringBuilder versionDate = new StringBuilder(simple.format(versions.get(i).getSaved()));
5311 if (versionDate.toString().equals(selection))
5315 if (index > -1 || selection.indexOf("Current") > -1) {
5316 Note historyNote = null;
5319 usn = versions.get(index).getUpdateSequenceNum();
5320 historyNote = syncRunner.localNoteStore.getNoteVersion(syncRunner.authToken, currentNoteGuid, usn, true, true, true);
5322 historyNote = syncRunner.localNoteStore.getNote(syncRunner.authToken, currentNoteGuid, true,true,true,true);
5323 } catch (EDAMUserException e) {
5324 setMessage("EDAMUserException: " +e.getMessage());
5327 } catch (EDAMSystemException e) {
5328 setMessage("EDAMSystemException: " +e.getMessage());
5331 } catch (EDAMNotFoundException e) {
5332 setMessage("EDAMNotFoundException: " +e.getMessage());
5335 } catch (TException e) {
5336 setMessage("EDAMTransactionException: " +e.getMessage());
5342 if (historyNote != null)
5343 historyWindow.setContent(historyNote);
5349 private void loadHistoryWindowContent(Note note) {
5350 note.setUpdateSequenceNum(0);
5351 historyWindow.setContent(note);
5353 @SuppressWarnings("unused")
5354 private void restoreHistoryNoteAsNew() {
5355 setMessage(tr("Restoring as new note."));
5356 duplicateNote(reloadHistoryWindow(historyWindow.historyCombo.currentText()));
5357 setMessage(tr("Note has been restored as a new note."));
5359 @SuppressWarnings("unused")
5360 private void restoreHistoryNote() {
5361 setMessage(tr("Restoring note."));
5362 Note n = reloadHistoryWindow(historyWindow.historyCombo.currentText());
5363 conn.getNoteTable().expungeNote(n.getGuid(), true, false);
5366 for (int i=0; i<n.getResourcesSize(); i++) {
5367 n.getResources().get(i).setActive(true);
5368 conn.getNoteTable().noteResourceTable.saveNoteResource(n.getResources().get(i), true);
5370 NoteMetadata metadata = new NoteMetadata();
5371 metadata.setGuid(n.getGuid());
5372 listManager.addNote(n, metadata);
5373 conn.getNoteTable().addNote(n, true);
5374 refreshEvernoteNote(true);
5375 setMessage(tr("Note has been restored."));
5377 @SuppressWarnings("unused")
5378 private void setupSelectiveSync() {
5380 // Get a list of valid notebooks
5381 List<Notebook> notebooks = null;
5382 List<Tag> tags = null;
5383 List<LinkedNotebook> linkedNotebooks = null;
5385 notebooks = syncRunner.localNoteStore.listNotebooks(syncRunner.authToken);
5386 tags = syncRunner.localNoteStore.listTags(syncRunner.authToken);
5387 linkedNotebooks = syncRunner.localNoteStore.listLinkedNotebooks(syncRunner.authToken);
5388 } catch (EDAMUserException e) {
5389 setMessage("EDAMUserException: " +e.getMessage());
5391 } catch (EDAMSystemException e) {
5392 setMessage("EDAMSystemException: " +e.getMessage());
5394 } catch (TException e) {
5395 setMessage("EDAMTransactionException: " +e.getMessage());
5397 } catch (EDAMNotFoundException e) {
5398 setMessage("EDAMNotFoundException: " +e.getMessage());
5402 // Split up notebooks into synchronized & non-synchronized
5403 List<Notebook> ignoredBooks = new ArrayList<Notebook>();
5404 List<String> dbIgnoredNotebooks = conn.getSyncTable().getIgnoreRecords("NOTEBOOK");
5406 for (int i=notebooks.size()-1; i>=0; i--) {
5407 for (int j=0; j<dbIgnoredNotebooks.size(); j++) {
5408 if (notebooks.get(i).getGuid().equalsIgnoreCase(dbIgnoredNotebooks.get(j))) {
5409 ignoredBooks.add(notebooks.get(i));
5410 j=dbIgnoredNotebooks.size();
5415 // split up tags into synchronized & non-synchronized
5416 List<Tag> ignoredTags = new ArrayList<Tag>();
5417 List<String> dbIgnoredTags = conn.getSyncTable().getIgnoreRecords("TAG");
5419 for (int i=tags.size()-1; i>=0; i--) {
5420 for (int j=0; j<dbIgnoredTags.size(); j++) {
5421 if (tags.get(i).getGuid().equalsIgnoreCase(dbIgnoredTags.get(j))) {
5422 ignoredTags.add(tags.get(i));
5423 j=dbIgnoredTags.size();
5428 // split up linked notebooks into synchronized & non-synchronized
5429 List<LinkedNotebook> ignoredLinkedNotebooks = new ArrayList<LinkedNotebook>();
5430 List<String> dbIgnoredLinkedNotebooks = conn.getSyncTable().getIgnoreRecords("LINKEDNOTEBOOK");
5431 for (int i=linkedNotebooks.size()-1; i>=0; i--) {
5432 String notebookGuid = linkedNotebooks.get(i).getGuid();
5433 for (int j=0; j<dbIgnoredLinkedNotebooks.size(); j++) {
5434 if (notebookGuid.equalsIgnoreCase(dbIgnoredLinkedNotebooks.get(j))) {
5435 ignoredLinkedNotebooks.add(linkedNotebooks.get(i));
5436 j=dbIgnoredLinkedNotebooks.size();
5441 IgnoreSync ignore = new IgnoreSync(notebooks, ignoredBooks, tags, ignoredTags, linkedNotebooks, ignoredLinkedNotebooks);
5443 if (!ignore.okClicked())
5448 // Clear out old notebooks & add the new ones
5449 List<String> oldIgnoreNotebooks = conn.getSyncTable().getIgnoreRecords("NOTEBOOK");
5450 for (int i=0; i<oldIgnoreNotebooks.size(); i++) {
5451 conn.getSyncTable().deleteRecord("IGNORENOTEBOOK-"+oldIgnoreNotebooks.get(i));
5454 List<String> newNotebooks = new ArrayList<String>();
5455 for (int i=ignore.getIgnoredBookList().count()-1; i>=0; i--) {
5456 String text = ignore.getIgnoredBookList().takeItem(i).text();
5457 for (int j=0; j<notebooks.size(); j++) {
5458 if (notebooks.get(j).getName().equalsIgnoreCase(text)) {
5459 Notebook n = notebooks.get(j);
5460 conn.getSyncTable().addRecord("IGNORENOTEBOOK-"+n.getGuid(), n.getGuid());
5462 newNotebooks.add(n.getGuid());
5467 // Clear out old tags & add new ones
5468 List<String> oldIgnoreTags = conn.getSyncTable().getIgnoreRecords("TAG");
5469 for (int i=0; i<oldIgnoreTags.size(); i++) {
5470 conn.getSyncTable().deleteRecord("IGNORETAG-"+oldIgnoreTags.get(i));
5473 List<String> newTags = new ArrayList<String>();
5474 for (int i=ignore.getIgnoredTagList().count()-1; i>=0; i--) {
5475 String text = ignore.getIgnoredTagList().takeItem(i).text();
5476 for (int j=0; j<tags.size(); j++) {
5477 if (tags.get(j).getName().equalsIgnoreCase(text)) {
5478 Tag t = tags.get(j);
5479 conn.getSyncTable().addRecord("IGNORETAG-"+t.getGuid(), t.getGuid());
5480 newTags.add(t.getGuid());
5486 // Clear out old tags & add new ones
5487 List<String> oldIgnoreLinkedNotebooks = conn.getSyncTable().getIgnoreRecords("LINKEDNOTEBOOK");
5488 for (int i=0; i<oldIgnoreLinkedNotebooks.size(); i++) {
5489 conn.getSyncTable().deleteRecord("IGNORELINKEDNOTEBOOK-"+oldIgnoreLinkedNotebooks.get(i));
5492 List<String> newLinked = new ArrayList<String>();
5493 for (int i=ignore.getIgnoredLinkedNotebookList().count()-1; i>=0; i--) {
5494 String text = ignore.getIgnoredLinkedNotebookList().takeItem(i).text();
5495 for (int j=0; j<linkedNotebooks.size(); j++) {
5496 if (linkedNotebooks.get(j).getShareName().equalsIgnoreCase(text)) {
5497 LinkedNotebook t = linkedNotebooks.get(j);
5498 conn.getSyncTable().addRecord("IGNORELINKEDNOTEBOOK-"+t.getGuid(), t.getGuid());
5499 newLinked.add(t.getGuid());
5500 j=linkedNotebooks.size();
5505 conn.getNoteTable().expungeIgnoreSynchronizedNotes(newNotebooks, newTags, newLinked);
5511 //**********************************************************
5512 //**********************************************************
5513 //* XML Modifying methods
5514 //**********************************************************
5515 //**********************************************************
5516 // An error has happended fetching a resource. let the user know
5517 private void resourceErrorMessage() {
5521 QMessageBox.information(this, tr("DOUGH!!!"), tr("Well, this is embarrassing."+
5522 "\n\nSome attachments or images for this note appear to be missing from my database.\n"+
5523 "In a perfect world this wouldn't happen, but it has.\n" +
5524 "It is embarasing when a program like me, designed to save all your\n"+
5525 "precious data, has a problem finding data.\n\n" +
5526 "I guess life isn't fair, but I'll survive. Somehow...\n\n" +
5527 "In the mean time, I'm not going to let you make changes to this note.\n" +
5528 "Don't get angry. I'm doing it to prevent you from messing up\n"+
5529 "this note on the Evernote servers. Sorry."+
5530 "\n\nP.S. You might want to re-synchronize to see if it corrects this problem.\nWho knows, you might get lucky."));
5532 browserWindow.setReadOnly(true);
5539 //**********************************************************
5540 //**********************************************************
5542 //**********************************************************
5543 //**********************************************************
5544 // We should now do a sync with Evernote
5545 private void syncTimer() {
5546 logger.log(logger.EXTREME, "Entering NeverNote.syncTimer()");
5547 syncRunner.syncNeeded = true;
5548 syncRunner.disableUploads = Global.disableUploads;
5550 logger.log(logger.EXTREME, "Leaving NeverNote.syncTimer()");
5552 private void syncStart() {
5553 logger.log(logger.EXTREME, "Entering NeverNote.syncStart()");
5555 if (!syncRunning && Global.isConnected) {
5556 syncRunner.setConnected(true);
5557 syncRunner.setKeepRunning(Global.keepRunning);
5558 syncRunner.syncDeletedContent = Global.synchronizeDeletedContent();
5560 if (syncThreadsReady > 0) {
5561 thumbnailRunner.interrupt = true;
5562 saveNoteIndexWidth();
5563 saveNoteColumnPositions();
5564 if (syncRunner.addWork("SYNC")) {
5566 syncRunner.syncNeeded = true;
5571 logger.log(logger.EXTREME, "Leaving NeverNote.syncStart");
5573 @SuppressWarnings("unused")
5574 private void syncThreadComplete(Boolean refreshNeeded) {
5575 setMessage(tr("Finalizing Synchronization"));
5577 syncRunning = false;
5578 syncRunner.syncNeeded = false;
5579 synchronizeAnimationTimer.stop();
5580 synchronizeButton.setIcon(new QIcon(iconPath+"synchronize.png"));
5582 if (currentNote == null) {
5583 currentNote = conn.getNoteTable().getNote(currentNoteGuid, false, false, false, false, true);
5585 listManager.refreshNoteMetadata();
5586 noteIndexUpdated(true);
5587 noteTableView.selectionModel().blockSignals(true);
5588 scrollToGuid(currentNoteGuid);
5589 noteTableView.selectionModel().blockSignals(false);
5590 refreshEvernoteNote(false);
5591 scrollToGuid(currentNoteGuid);
5594 // Check to see if there were any shared notebook errors
5595 if (syncRunner.error && syncRunner.errorSharedNotebooks.size() > 0) {
5596 String guid = syncRunner.errorSharedNotebooks.get(0);
5597 String notebookGuid = conn.getLinkedNotebookTable().getLocalNotebookGuid(guid);
5598 String localName = listManager.getNotebookNameByGuid(notebookGuid);
5599 SharedNotebookSyncError syncDialog = new SharedNotebookSyncError(localName);
5601 if (syncDialog.okPressed()) {
5602 if (syncDialog.doNothing.isChecked()) {
5603 syncRunner.errorSharedNotebooksIgnored.put(guid, guid);
5606 if (syncDialog.deleteNotebook.isChecked()) {
5607 conn.getNoteTable().expungeNotesByNotebook(notebookGuid, true, false);
5608 conn.getNotebookTable().expungeNotebook(notebookGuid, false);
5609 conn.getLinkedNotebookTable().expungeNotebook(guid, false);
5610 conn.getLinkedNotebookTable().expungeNotebook(guid, false);
5618 // Finalize the synchronization
5619 if (!syncRunner.error)
5620 setMessage(tr("Synchronization Complete"));
5622 setMessage(tr("Synchronization completed with errors. Please check the log for details."));
5623 logger.log(logger.MEDIUM, "Sync complete.");
5625 public void saveUploadAmount(long t) {
5626 Global.saveUploadAmount(t);
5628 public void saveUserInformation(User user) {
5629 Global.saveUserInformation(user);
5631 public void saveEvernoteUpdateCount(int i) {
5632 Global.saveEvernoteUpdateCount(i);
5634 public void refreshLists() {
5635 logger.log(logger.EXTREME, "Entering NeverNote.refreshLists");
5637 listManager.refreshLists(currentNote, noteDirty, browserWindow.getContent());
5638 tagIndexUpdated(true);
5639 notebookIndexUpdated();
5640 savedSearchIndexUpdated();
5641 listManager.loadNotesIndex();
5643 noteTableView.selectionModel().blockSignals(true);
5644 noteIndexUpdated(true);
5645 noteTableView.selectionModel().blockSignals(false);
5646 logger.log(logger.EXTREME, "Leaving NeverNote.refreshLists");
5650 @SuppressWarnings("unused")
5651 private void authTimer() {
5652 Calendar cal = Calendar.getInstance();
5654 // If we are not connected let's get out of here
5655 if (!Global.isConnected)
5658 // If this is the first time through, then we need to set this
5659 // if (syncRunner.authRefreshTime == 0 || cal.getTimeInMillis() > syncRunner.authRefreshTime)
5660 // syncRunner.authRefreshTime = cal.getTimeInMillis();
5662 // long now = new Date().getTime();
5663 // if (now > Global.authRefreshTime && Global.isConnected) {
5664 syncRunner.authRefreshNeeded = true;
5668 @SuppressWarnings("unused")
5669 private void authRefreshComplete(boolean goodSync) {
5670 logger.log(logger.EXTREME, "Entering NeverNote.authRefreshComplete");
5671 Global.isConnected = syncRunner.isConnected;
5673 // authTimer.start((int)syncRunner.authTimeRemaining/4);
5674 authTimer.start(1000*60*15);
5675 logger.log(logger.LOW, "Authentication token has been renewed");
5676 // setMessage("Authentication token has been renewed.");
5678 authTimer.start(1000*60*5);
5679 logger.log(logger.LOW, "Authentication token renew has failed - retry in 5 minutes.");
5680 // setMessage("Authentication token renew has failed - retry in 5 minutes.");
5682 logger.log(logger.EXTREME, "Leaving NeverNote.authRefreshComplete");
5686 @SuppressWarnings("unused")
5687 private synchronized void indexTimer() {
5688 logger.log(logger.EXTREME, "Index timer activated. Sync running="+syncRunning);
5691 if (!indexDisabled && indexRunner.idle) {
5692 thumbnailRunner.interrupt = true;
5693 indexRunner.addWork("SCAN");
5695 logger.log(logger.EXTREME, "Leaving NixNote index timer");
5698 @SuppressWarnings("unused")
5699 private void indexStarted() {
5700 setMessage(tr("Indexing notes"));
5702 @SuppressWarnings("unused")
5703 private void indexComplete() {
5704 setMessage(tr("Index complete"));
5706 @SuppressWarnings("unused")
5707 private synchronized void toggleNoteIndexing() {
5708 logger.log(logger.HIGH, "Entering NeverNote.toggleIndexing");
5709 indexDisabled = !indexDisabled;
5711 setMessage(tr("Indexing is now enabled."));
5713 setMessage(tr("Indexing is now disabled."));
5714 menuBar.disableIndexing.setChecked(indexDisabled);
5715 logger.log(logger.HIGH, "Leaving NeverNote.toggleIndexing");
5718 @SuppressWarnings("unused")
5719 private void threadMonitorCheck() {
5724 alive = listManager.threadCheck(Global.tagCounterThreadId);
5727 if (tagDeadCount > MAX && !disableTagThreadCheck) {
5728 QMessageBox.information(this, tr("A thread has died."), tr("It appears as the tag counter thread has died. I recommend "+
5729 "checking stopping NixNote, saving the logs for later viewing, and restarting. Sorry."));
5730 disableTagThreadCheck = true;
5735 alive = listManager.threadCheck(Global.notebookCounterThreadId);
5737 notebookThreadDeadCount++;
5738 if (notebookThreadDeadCount > MAX && !disableNotebookThreadCheck) {
5739 QMessageBox.information(this, tr("A thread has died."), tr("It appears as the notebook counter thread has died. I recommend "+
5740 "checking stopping NixNote, saving the logs for later viewing, and restarting. Sorry."));
5741 disableNotebookThreadCheck=true;
5744 notebookThreadDeadCount=0;
5746 alive = listManager.threadCheck(Global.trashCounterThreadId);
5749 if (trashDeadCount > MAX && !disableTrashThreadCheck) {
5750 QMessageBox.information(this, tr("A thread has died."), ("It appears as the trash counter thread has died. I recommend "+
5751 "checking stopping NixNote, saving the logs for later viewing, and restarting. Sorry."));
5752 disableTrashThreadCheck = true;
5757 alive = listManager.threadCheck(Global.saveThreadId);
5759 saveThreadDeadCount++;
5760 if (saveThreadDeadCount > MAX && !disableSaveThreadCheck) {
5761 QMessageBox.information(this, tr("A thread has died."), tr("It appears as the note saver thread has died. I recommend "+
5762 "checking stopping NixNote, saving the logs for later viewing, and restarting. Sorry."));
5763 disableSaveThreadCheck = true;
5766 saveThreadDeadCount=0;
5768 if (!syncThread.isAlive()) {
5769 syncThreadDeadCount++;
5770 if (syncThreadDeadCount > MAX && !disableSyncThreadCheck) {
5771 QMessageBox.information(this, tr("A thread has died."), tr("It appears as the synchronization thread has died. I recommend "+
5772 "checking stopping NixNote, saving the logs for later viewing, and restarting. Sorry."));
5773 disableSyncThreadCheck = true;
5776 syncThreadDeadCount=0;
5778 if (!indexThread.isAlive()) {
5779 indexThreadDeadCount++;
5780 if (indexThreadDeadCount > MAX && !disableIndexThreadCheck) {
5781 QMessageBox.information(this, tr("A thread has died."), tr("It appears as the index thread has died. I recommend "+
5782 "checking stopping NixNote, saving the logs for later viewing, and restarting. Sorry."));
5783 disableIndexThreadCheck = true;
5786 indexThreadDeadCount=0;
5791 private void thumbnailTimer() {
5792 if (Global.enableThumbnails() && !syncRunning && indexRunner.idle) {
5793 thumbnailRunner.addWork("SCAN");
5797 //**************************************************
5798 //* Backup & Restore
5799 //**************************************************
5800 @SuppressWarnings("unused")
5801 private void databaseBackup() {
5802 QFileDialog fd = new QFileDialog(this);
5803 fd.setFileMode(FileMode.AnyFile);
5804 fd.setConfirmOverwrite(true);
5805 fd.setWindowTitle(tr("Backup Database"));
5806 fd.setFilter(tr("NixNote Export (*.nnex);;All Files (*.*)"));
5807 fd.setAcceptMode(AcceptMode.AcceptSave);
5808 if (saveLastPath == null || saveLastPath.equals(""))
5809 fd.setDirectory(System.getProperty("user.home"));
5811 fd.setDirectory(saveLastPath);
5812 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
5818 saveLastPath = fd.selectedFiles().get(0);
5819 saveLastPath = saveLastPath.substring(0,saveLastPath.lastIndexOf("/"));
5820 setMessage(tr("Backing up database"));
5822 // conn.backupDatabase(Global.getUpdateSequenceNumber(), Global.getSequenceDate());
5824 ExportData noteWriter = new ExportData(conn, true);
5825 String fileName = fd.selectedFiles().get(0);
5827 if (!fileName.endsWith(".nnex"))
5828 fileName = fileName +".nnex";
5829 noteWriter.exportData(fileName);
5830 setMessage(tr("Database backup completed."));
5835 @SuppressWarnings("unused")
5836 private void databaseRestore() {
5837 if (QMessageBox.question(this, tr("Confirmation"),
5838 tr("This is used to restore a database from backups.\n" +
5839 "It is HIGHLY recommened that this only be used to populate\n" +
5840 "an empty database. Restoring into a database that\n already has data" +
5841 " can cause problems.\n\nAre you sure you want to continue?"),
5842 QMessageBox.StandardButton.Yes,
5843 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
5848 QFileDialog fd = new QFileDialog(this);
5849 fd.setFileMode(FileMode.ExistingFile);
5850 fd.setConfirmOverwrite(true);
5851 fd.setWindowTitle(tr("Restore Database"));
5852 fd.setFilter(tr("NixNote Export (*.nnex);;All Files (*.*)"));
5853 fd.setAcceptMode(AcceptMode.AcceptOpen);
5854 if (saveLastPath == null || saveLastPath.equals(""))
5855 fd.setDirectory(System.getProperty("user.home"));
5857 fd.setDirectory(saveLastPath);
5858 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
5864 saveLastPath = fd.selectedFiles().get(0);
5865 saveLastPath = saveLastPath.substring(0,saveLastPath.lastIndexOf("/"));
5867 setMessage(tr("Restoring database"));
5868 ImportData noteReader = new ImportData(conn, true);
5869 noteReader.importData(fd.selectedFiles().get(0));
5871 if (noteReader.lastError != 0) {
5872 setMessage(noteReader.getErrorMessage());
5873 logger.log(logger.LOW, "Restore problem: " +noteReader.lastError);
5878 listManager.loadNoteTitleColors();
5880 refreshEvernoteNote(true);
5881 setMessage(tr("Database has been restored."));
5884 @SuppressWarnings("unused")
5885 private void exportNotes() {
5886 QFileDialog fd = new QFileDialog(this);
5887 fd.setFileMode(FileMode.AnyFile);
5888 fd.setConfirmOverwrite(true);
5889 fd.setWindowTitle(tr("Backup Database"));
5890 fd.setFilter(tr("NixNote Export (*.nnex);;All Files (*.*)"));
5891 fd.setAcceptMode(AcceptMode.AcceptSave);
5892 fd.setDirectory(System.getProperty("user.home"));
5893 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
5899 setMessage(tr("Exporting Notes"));
5902 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
5903 selectedNoteGUIDs.add(currentNoteGuid);
5905 ExportData noteWriter = new ExportData(conn, false, selectedNoteGUIDs);
5906 String fileName = fd.selectedFiles().get(0);
5908 if (!fileName.endsWith(".nnex"))
5909 fileName = fileName +".nnex";
5910 noteWriter.exportData(fileName);
5911 setMessage(tr("Export completed."));
5917 @SuppressWarnings("unused")
5918 private void importNotes() {
5919 QFileDialog fd = new QFileDialog(this);
5920 fd.setFileMode(FileMode.ExistingFile);
5921 fd.setConfirmOverwrite(true);
5922 fd.setWindowTitle(tr("Import Notes"));
5923 fd.setFilter(tr("NixNote Export (*.nnex);;Evernote Export (*.enex);;All Files (*.*)"));
5924 fd.setAcceptMode(AcceptMode.AcceptOpen);
5925 if (saveLastPath == null || saveLastPath.equals(""))
5926 fd.setDirectory(System.getProperty("user.home"));
5928 fd.setDirectory(saveLastPath);
5929 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
5935 setMessage(tr("Importing Notes"));
5938 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
5939 selectedNoteGUIDs.add(currentNoteGuid);
5941 String fileName = fd.selectedFiles().get(0);
5942 // saveLastPath.substring(0,fileName.lastIndexOf("/"));
5944 if (fileName.endsWith(".nnex")) {
5945 ImportData noteReader = new ImportData(conn, false);
5946 if (selectedNotebookGUIDs != null && selectedNotebookGUIDs.size() > 0)
5947 noteReader.setNotebookGuid(selectedNotebookGUIDs.get(0));
5949 noteReader.setNotebookGuid(listManager.getNotebookIndex().get(0).getGuid());
5951 noteReader.importData(fileName);
5953 if (noteReader.lastError != 0) {
5954 setMessage(noteReader.getErrorMessage());
5955 logger.log(logger.LOW, "Import problem: " +noteReader.lastError);
5960 if (fileName.endsWith(".enex")) {
5961 ImportEnex noteReader = new ImportEnex(conn, false);
5962 if (selectedNotebookGUIDs != null && selectedNotebookGUIDs.size() > 0)
5963 noteReader.setNotebookGuid(selectedNotebookGUIDs.get(0));
5965 noteReader.setNotebookGuid(listManager.getNotebookIndex().get(0).getGuid());
5968 if (QMessageBox.question(this, tr("Confirmation"),
5969 tr("Create new tags from import?"),
5970 QMessageBox.StandardButton.Yes,
5971 QMessageBox.StandardButton.No) == StandardButton.Yes.value()) {
5972 noteReader.createNewTags = true;
5974 noteReader.createNewTags = false;
5976 noteReader.importData(fileName);
5978 if (noteReader.lastError != 0) {
5979 setMessage(noteReader.getErrorMessage());
5980 logger.log(logger.LOW, "Import problem: " +noteReader.lastError);
5987 listManager.loadNoteTitleColors();
5989 refreshEvernoteNote(false);
5990 setMessage(tr("Notes have been imported."));
5993 setMessage(tr("Import completed."));
6000 //**************************************************
6001 //* Duplicate a note
6002 //**************************************************
6003 @SuppressWarnings("unused")
6004 private void duplicateNote() {
6006 duplicateNote(currentNoteGuid);
6009 //**************************************************
6010 //* Action from when a user clicks Copy As URL
6011 //**************************************************
6012 @SuppressWarnings("unused")
6013 private void copyAsUrlClicked() {
6014 QClipboard clipboard = QApplication.clipboard();
6015 QMimeData mime = new QMimeData();
6017 mime.setText(currentNoteGuid);
6018 List<QUrl> urls = new ArrayList<QUrl>();
6020 // Start building the URL
6021 User user = Global.getUserInformation();
6023 // Check that we have everything we need
6024 if ((user.getShardId().equals("") || user.getId() == 0) && !Global.bypassSynchronizationWarning()) {
6025 SynchronizationRequiredWarning warning = new SynchronizationRequiredWarning(this);
6027 if (!warning.neverSynchronize())
6030 Global.setBypassSynchronizationWarning(true);
6031 user.setShardId("s0");
6037 // Start building a list of URLs based upon the selected notes
6038 noteTableView.showColumn(Global.noteTableGuidPosition);
6040 List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
6041 if (!Global.isColumnVisible("guid"))
6042 noteTableView.hideColumn(Global.noteTableGuidPosition);
6044 // Check that the note is either synchronized, or in a local notebook
6045 for (int i=0; i<selections.size(); i++) {
6047 int row = selections.get(i).row();
6048 index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition);
6049 SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
6050 String selectedGuid = (String)ix.values().toArray()[0];
6052 Note n = conn.getNoteTable().getNote(selectedGuid, false, false, false, false, false);
6053 if (n.getUpdateSequenceNum() == 0 && !conn.getNotebookTable().isNotebookLocal(n.getNotebookGuid())) {
6054 QMessageBox.critical(this, tr("Please Synchronize") ,tr("Please either synchronize or move any " +
6055 "new notes to a local notebook."));
6060 // Start building the URLs
6061 for (int i=0; i<selections.size(); i++) {
6063 int row = selections.get(i).row();
6064 index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition);
6065 SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
6066 String selectedGuid = (String)ix.values().toArray()[0];
6067 mime.setText(selectedGuid);
6071 Note selectedNote = conn.getNoteTable().getNote(selectedGuid, false, false, false, false, false);
6072 if (selectedNote.getUpdateSequenceNum() > 0) {
6076 gid = "00000000-0000-0000-0000-000000000000";
6079 url = new String("evernote://///view/") + new String(user.getId() + "/" +user.getShardId() +"/"
6081 urls.add(new QUrl(url));
6084 clipboard.setMimeData(mime);
6088 //**************************************************
6090 //**************************************************
6091 public void setupFolderImports() {
6092 List<WatchFolderRecord> records = conn.getWatchFolderTable().getAll();
6094 if (importKeepWatcher == null)
6095 importKeepWatcher = new QFileSystemWatcher();
6096 if (importDeleteWatcher == null) {
6097 importDeleteWatcher = new QFileSystemWatcher();
6098 for (int i=0; i<records.size(); i++) {
6099 if (!records.get(i).keep)
6100 folderImportDelete(records.get(i).folder);
6106 // importKeepWatcher.addPath(records.get(i).folder.replace('\\', '/'));
6107 for (int i=0; i<records.size(); i++) {
6108 if (records.get(i).keep)
6109 importKeepWatcher.addPath(records.get(i).folder);
6111 importDeleteWatcher.addPath(records.get(i).folder);
6114 importKeepWatcher.directoryChanged.connect(this, "folderImportKeep(String)");
6115 importDeleteWatcher.directoryChanged.connect(this, "folderImportDelete(String)");
6117 // Look at the files already there so we don't import them again if a new file is created
6118 if (importedFiles == null) {
6119 importedFiles = new ArrayList<String>();
6120 for (int j=0; j<records.size(); j++) {
6121 QDir dir = new QDir(records.get(j).folder);
6122 List<QFileInfo> list = dir.entryInfoList();
6123 for (int k=0; k<list.size(); k++) {
6124 if (list.get(k).isFile())
6125 importedFiles.add(list.get(k).absoluteFilePath());
6130 public void folderImport() {
6131 List<WatchFolderRecord> recs = conn.getWatchFolderTable().getAll();
6132 WatchFolder dialog = new WatchFolder(recs, listManager.getNotebookIndex());
6134 if (!dialog.okClicked())
6137 // We have some sort of update.
6138 if (importKeepWatcher.directories().size() > 0)
6139 importKeepWatcher.removePaths(importKeepWatcher.directories());
6140 if (importDeleteWatcher.directories().size() > 0)
6141 importDeleteWatcher.removePaths(importDeleteWatcher.directories());
6143 conn.getWatchFolderTable().expungeAll();
6144 // Start building from the table
6145 for (int i=0; i<dialog.table.rowCount(); i++) {
6146 QTableWidgetItem item = dialog.table.item(i, 0);
6147 String dir = item.text();
6148 item = dialog.table.item(i, 1);
6149 String notebook = item.text();
6150 item = dialog.table.item(i, 2);
6152 if (item.text().equalsIgnoreCase("Keep"))
6157 String guid = conn.getNotebookTable().findNotebookByName(notebook);
6158 conn.getWatchFolderTable().addWatchFolder(dir, guid, keep, 0);
6160 setupFolderImports();
6163 public void folderImportKeep(String dirName) throws NoSuchAlgorithmException {
6165 String whichOS = System.getProperty("os.name");
6166 if (whichOS.contains("Windows"))
6167 dirName = dirName.replace('/','\\');
6169 FileImporter importer = new FileImporter(logger, conn);
6171 QDir dir = new QDir(dirName);
6172 List<QFileInfo> list = dir.entryInfoList();
6173 String notebook = conn.getWatchFolderTable().getNotebook(dirName);
6175 for (int i=0; i<list.size(); i++){
6177 boolean redundant = false;
6178 // Check if we've already imported this one or if it existed before
6179 for (int j=0; j<importedFiles.size(); j++) {
6180 if (importedFiles.get(j).equals(list.get(i).absoluteFilePath()))
6185 importer.setFileInfo(list.get(i));
6186 importer.setFileName(list.get(i).absoluteFilePath());
6189 if (list.get(i).isFile() && importer.isValidType()) {
6191 if (!importer.importFile()) {
6192 // If we can't get to the file, it is probably locked. We'll try again later.
6193 logger.log(logger.LOW, "Unable to save externally edited file. Saving for later.");
6194 importFilesKeep.add(list.get(i).absoluteFilePath());
6198 Note newNote = importer.getNote();
6199 newNote.setNotebookGuid(notebook);
6200 newNote.setTitle(dir.at(i));
6201 NoteMetadata metadata = new NoteMetadata();
6202 metadata.setDirty(true);
6203 metadata.setGuid(newNote.getGuid());
6204 listManager.addNote(newNote, metadata);
6205 conn.getNoteTable().addNote(newNote, true);
6206 noteTableView.insertRow(newNote, metadata, true, -1);
6207 listManager.updateNoteContent(newNote.getGuid(), importer.getNoteContent());
6208 listManager.countNotebookResults(listManager.getNoteIndex());
6209 importedFiles.add(list.get(i).absoluteFilePath());
6217 public void folderImportDelete(String dirName) {
6219 String whichOS = System.getProperty("os.name");
6220 if (whichOS.contains("Windows"))
6221 dirName = dirName.replace('/','\\');
6223 FileImporter importer = new FileImporter(logger, conn);
6224 QDir dir = new QDir(dirName);
6225 List<QFileInfo> list = dir.entryInfoList();
6226 String notebook = conn.getWatchFolderTable().getNotebook(dirName);
6228 for (int i=0; i<list.size(); i++){
6229 importer.setFileInfo(list.get(i));
6230 importer.setFileName(list.get(i).absoluteFilePath());
6232 if (list.get(i).isFile() && importer.isValidType()) {
6234 if (!importer.importFile()) {
6235 // If we can't get to the file, it is probably locked. We'll try again later.
6236 logger.log(logger.LOW, "Unable to save externally edited file. Saving for later.");
6237 importFilesKeep.add(list.get(i).absoluteFilePath());
6241 Note newNote = importer.getNote();
6242 newNote.setNotebookGuid(notebook);
6243 newNote.setTitle(dir.at(i));
6244 NoteMetadata metadata = new NoteMetadata();
6245 metadata.setDirty(true);
6246 metadata.setGuid(newNote.getGuid());
6247 listManager.addNote(newNote, metadata);
6248 conn.getNoteTable().addNote(newNote, true);
6249 noteTableView.insertRow(newNote, metadata, true, -1);
6250 listManager.updateNoteContent(newNote.getGuid(), importer.getNoteContent());
6251 listManager.countNotebookResults(listManager.getNoteIndex());
6252 dir.remove(dir.at(i));
6258 //**************************************************
6260 //**************************************************
6261 private void externalFileEdited(String fileName) throws NoSuchAlgorithmException {
6262 logger.log(logger.HIGH, "Entering exernalFileEdited");
6264 // Strip URL prefix and base dir path
6265 String dPath = FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath());
6266 String name = fileName.replace(dPath, "");
6267 int pos = name.lastIndexOf('.');
6270 guid = guid.substring(0,pos);
6272 pos = name.lastIndexOf(Global.attachmentNameDelimeter);
6274 guid = name.substring(0, pos);
6277 QFile file = new QFile(fileName);
6278 if (!file.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly))) {
6279 // If we can't get to the file, it is probably locked. We'll try again later.
6280 logger.log(logger.LOW, "Unable to save externally edited file. Saving for later.");
6281 externalFiles.add(fileName);
6284 QByteArray binData = file.readAll();
6286 if (binData.size() == 0) {
6287 // If we can't get to the file, it is probably locked. We'll try again later.
6288 logger.log(logger.LOW, "Unable to save externally edited file. Saving for later.");
6289 externalFiles.add(fileName);
6293 Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
6295 r = conn.getNoteTable().noteResourceTable.getNoteResource(Global.resourceMap.get(guid), true);
6296 if (r == null || r.getData() == null || r.getData().getBody() == null)
6298 String oldHash = Global.byteArrayToHexString(r.getData().getBodyHash());
6299 MessageDigest md = MessageDigest.getInstance("MD5");
6300 md.update(binData.toByteArray());
6301 byte[] hash = md.digest();
6302 String newHash = Global.byteArrayToHexString(hash);
6303 if (r.getNoteGuid().equalsIgnoreCase(currentNoteGuid)) {
6304 updateResourceContentHash(browserWindow, r.getGuid(), oldHash, newHash);
6306 if (externalWindows.containsKey(r.getNoteGuid())) {
6307 updateResourceContentHash(externalWindows.get(r.getNoteGuid()).getBrowserWindow(),
6308 r.getGuid(), oldHash, newHash);
6310 conn.getNoteTable().updateResourceContentHash(r.getNoteGuid(), oldHash, newHash);
6311 Data data = r.getData();
6312 data.setBody(binData.toByteArray());
6313 data.setBodyHash(hash);
6314 logger.log(logger.LOW, "externalFileEdited: " +data.getSize() +" bytes");
6316 conn.getNoteTable().noteResourceTable.updateNoteResource(r,true);
6318 if (r.getNoteGuid().equals(currentNoteGuid)) {
6319 QWebSettings.setMaximumPagesInCache(0);
6320 QWebSettings.setObjectCacheCapacities(0, 0, 0);
6321 refreshEvernoteNote(true);
6322 browserWindow.getBrowser().triggerPageAction(WebAction.Reload);
6325 if (externalWindows.containsKey(r.getNoteGuid())) {
6326 QWebSettings.setMaximumPagesInCache(0);
6327 QWebSettings.setObjectCacheCapacities(0, 0, 0);
6328 externalWindows.get(r.getNoteGuid()).getBrowserWindow().getBrowser().triggerPageAction(WebAction.Reload);
6332 logger.log(logger.HIGH, "Exiting externalFielEdited");
6334 // This is a timer event that tries to save any external files that were edited. This
6335 // is only needed if we couldn't save a file earlier.
6336 public void externalFileEditedSaver() {
6337 for (int i=externalFiles.size()-1; i>=0; i--) {
6339 logger.log(logger.MEDIUM, "Trying to save " +externalFiles.get(i));
6340 externalFileEdited(externalFiles.get(i));
6341 externalFiles.remove(i);
6342 } catch (NoSuchAlgorithmException e) {e.printStackTrace();}
6344 for (int i=0; i<importFilesKeep.size(); i++) {
6346 logger.log(logger.MEDIUM, "Trying to save " +importFilesKeep.get(i));
6347 folderImportKeep(importFilesKeep.get(i));
6348 importFilesKeep.remove(i);
6349 } catch (NoSuchAlgorithmException e) {e.printStackTrace();}
6351 for (int i=0; i<importFilesDelete.size(); i++) {
6352 logger.log(logger.MEDIUM, "Trying to save " +importFilesDelete.get(i));
6353 folderImportDelete(importFilesDelete.get(i));
6354 importFilesDelete.remove(i);
6361 // If an attachment on the current note was edited, we need to update the current notes's hash
6362 // Update a note content's hash. This happens if a resource is edited outside of NN
6363 public void updateResourceContentHash(BrowserWindow browser, String guid, String oldHash, String newHash) {
6364 int position = browserWindow.getContent().indexOf("en-tag=\"en-media\" guid=\""+guid+"\" type=");
6366 for (;position>-1;) {
6367 endPos = browser.getContent().indexOf(">", position+1);
6368 String oldSegment = browser.getContent().substring(position,endPos);
6369 int hashPos = oldSegment.indexOf("hash=\"");
6370 int hashEnd = oldSegment.indexOf("\"", hashPos+7);
6371 String hash = oldSegment.substring(hashPos+6, hashEnd);
6372 if (hash.equalsIgnoreCase(oldHash)) {
6373 String newSegment = oldSegment.replace(oldHash, newHash);
6374 String content = browser.getContent().substring(0,position) +
6376 browser.getContent().substring(endPos);
6377 browser.setContent(new QByteArray(content));;
6380 position = browser.getContent().indexOf("en-tag=\"en-media\" guid=\""+guid+"\" type=", position+1);
6385 //*************************************************
6386 //* Minimize to tray
6387 //*************************************************
6389 public void changeEvent(QEvent e) {
6390 if (e.type() == QEvent.Type.WindowStateChange) {
6391 if (QSystemTrayIcon.isSystemTrayAvailable()) {
6392 if (isMinimized() && (Global.showTrayIcon() || Global.showTrayIcon())) {
6394 QTimer.singleShot(10, this, "hide()");
6398 windowMaximized = true;
6400 windowMaximized = false;
6405 //*************************************************
6406 //* Check database userid & passwords
6407 //*************************************************
6408 private static boolean databaseCheck(String url,String userid, String userPassword, String cypherPassword) {
6409 Connection connection;
6412 Class.forName("org.h2.Driver");
6413 } catch (ClassNotFoundException e1) {
6414 e1.printStackTrace();
6419 String passwordString = null;
6420 if (cypherPassword==null || cypherPassword.trim().equals(""))
6421 passwordString = userPassword;
6423 passwordString = cypherPassword+" "+userPassword;
6424 connection = DriverManager.getConnection(url,userid,passwordString);
6425 } catch (SQLException e) {
6430 } catch (SQLException e) {
6431 e.printStackTrace();
6436 //*************************************************
6437 //* View / Hide source HTML for a note
6438 //*************************************************
6439 public void viewSource() {
6440 browserWindow.showSource(menuBar.viewSource.isChecked());
6442 //*************************************************
6443 // Block the program. This is used for things
6444 // like async web calls.
6445 //*************************************************
6446 @SuppressWarnings("unused")
6447 private void blockApplication(BrowserWindow b) {
6448 // Block all signals
6452 blockTimer = new QTimer();
6453 blockTimer.setSingleShot(true);
6454 blockTimer.setInterval(15000);
6455 blockTimer.timeout.connect(this, "unblockApplication()");
6460 @SuppressWarnings("unused")
6461 private void unblockApplication() {
6463 if (blockingWindow != null && new GregorianCalendar().getTimeInMillis() > blockingWindow.unblockTime && blockingWindow.unblockTime != -1) {
6464 QMessageBox.critical(null, tr("No Response from CodeCogs") ,tr("Unable to contact CodeCogs for LaTeX formula."));
6465 blockingWindow.unblockTime = -1;
6466 blockingWindow.awaitingHttpResponse = false;
6468 blockingWindow = null;
6469 blockSignals(false);