2 * This file is part of NeverNote
3 * Copyright 2009 Randy Baumgarte
5 * This file may be licensed under the terms of of the
6 * GNU General Public License Version 2 (the ``GPL'').
8 * Software distributed under the License is distributed
9 * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
10 * express or implied. See the GPL for the specific language
11 * governing rights and limitations.
13 * You should have received a copy of the GPL along with this
14 * program. If not, go to http://www.gnu.org/licenses/gpl.html
15 * or write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 package cx.fbn.nevernote;
20 import java.awt.Desktop;
22 import java.io.FileInputStream;
23 import java.io.FileNotFoundException;
24 import java.net.Authenticator;
25 import java.net.PasswordAuthentication;
26 import java.security.MessageDigest;
27 import java.security.NoSuchAlgorithmException;
28 import java.sql.Connection;
29 import java.sql.DriverManager;
30 import java.sql.SQLException;
31 import java.sql.Statement;
32 import java.text.SimpleDateFormat;
33 import java.util.ArrayList;
34 import java.util.Calendar;
35 import java.util.Collection;
36 import java.util.Collections;
37 import java.util.Comparator;
38 import java.util.Date;
39 import java.util.GregorianCalendar;
40 import java.util.HashMap;
41 import java.util.Iterator;
42 import java.util.List;
43 import java.util.SortedMap;
44 import java.util.Vector;
46 import org.apache.log4j.Level;
47 import org.apache.log4j.Logger;
48 import org.apache.thrift.TException;
49 import org.h2.tools.ChangeFileEncryption;
51 import com.evernote.edam.error.EDAMNotFoundException;
52 import com.evernote.edam.error.EDAMSystemException;
53 import com.evernote.edam.error.EDAMUserException;
54 import com.evernote.edam.notestore.NoteFilter;
55 import com.evernote.edam.notestore.NoteVersionId;
56 import com.evernote.edam.type.Data;
57 import com.evernote.edam.type.LinkedNotebook;
58 import com.evernote.edam.type.Note;
59 import com.evernote.edam.type.NoteAttributes;
60 import com.evernote.edam.type.Notebook;
61 import com.evernote.edam.type.Publishing;
62 import com.evernote.edam.type.QueryFormat;
63 import com.evernote.edam.type.Resource;
64 import com.evernote.edam.type.SavedSearch;
65 import com.evernote.edam.type.Tag;
66 import com.evernote.edam.type.User;
67 import com.trolltech.qt.QThread;
68 import com.trolltech.qt.core.QByteArray;
69 import com.trolltech.qt.core.QDateTime;
70 import com.trolltech.qt.core.QDir;
71 import com.trolltech.qt.core.QEvent;
72 import com.trolltech.qt.core.QFile;
73 import com.trolltech.qt.core.QFileInfo;
74 import com.trolltech.qt.core.QFileSystemWatcher;
75 import com.trolltech.qt.core.QIODevice;
76 import com.trolltech.qt.core.QIODevice.OpenModeFlag;
77 import com.trolltech.qt.core.QLocale;
78 import com.trolltech.qt.core.QMimeData;
79 import com.trolltech.qt.core.QModelIndex;
80 import com.trolltech.qt.core.QSize;
81 import com.trolltech.qt.core.QTemporaryFile;
82 import com.trolltech.qt.core.QTextCodec;
83 import com.trolltech.qt.core.QThreadPool;
84 import com.trolltech.qt.core.QTimer;
85 import com.trolltech.qt.core.QTranslator;
86 import com.trolltech.qt.core.QUrl;
87 import com.trolltech.qt.core.Qt;
88 import com.trolltech.qt.core.Qt.BGMode;
89 import com.trolltech.qt.core.Qt.ItemDataRole;
90 import com.trolltech.qt.core.Qt.KeyboardModifier;
91 import com.trolltech.qt.core.Qt.MouseButton;
92 import com.trolltech.qt.core.Qt.SortOrder;
93 import com.trolltech.qt.core.Qt.WidgetAttribute;
94 import com.trolltech.qt.gui.QAbstractItemView;
95 import com.trolltech.qt.gui.QAbstractItemView.ScrollHint;
96 import com.trolltech.qt.gui.QAction;
97 import com.trolltech.qt.gui.QApplication;
98 import com.trolltech.qt.gui.QClipboard;
99 import com.trolltech.qt.gui.QCloseEvent;
100 import com.trolltech.qt.gui.QColor;
101 import com.trolltech.qt.gui.QComboBox;
102 import com.trolltech.qt.gui.QCursor;
103 import com.trolltech.qt.gui.QDesktopServices;
104 import com.trolltech.qt.gui.QDialog;
105 import com.trolltech.qt.gui.QFileDialog;
106 import com.trolltech.qt.gui.QFileDialog.AcceptMode;
107 import com.trolltech.qt.gui.QFileDialog.FileMode;
108 import com.trolltech.qt.gui.QGridLayout;
109 import com.trolltech.qt.gui.QHBoxLayout;
110 import com.trolltech.qt.gui.QIcon;
111 import com.trolltech.qt.gui.QImage;
112 import com.trolltech.qt.gui.QKeySequence;
113 import com.trolltech.qt.gui.QLabel;
114 import com.trolltech.qt.gui.QMainWindow;
115 import com.trolltech.qt.gui.QMenu;
116 import com.trolltech.qt.gui.QMessageBox;
117 import com.trolltech.qt.gui.QMessageBox.StandardButton;
118 import com.trolltech.qt.gui.QPainter;
119 import com.trolltech.qt.gui.QPalette.ColorRole;
120 import com.trolltech.qt.gui.QPixmap;
121 import com.trolltech.qt.gui.QPrintDialog;
122 import com.trolltech.qt.gui.QPrinter;
123 import com.trolltech.qt.gui.QShortcut;
124 import com.trolltech.qt.gui.QSizePolicy;
125 import com.trolltech.qt.gui.QSizePolicy.Policy;
126 import com.trolltech.qt.gui.QSpinBox;
127 import com.trolltech.qt.gui.QSplashScreen;
128 import com.trolltech.qt.gui.QSplitter;
129 import com.trolltech.qt.gui.QStatusBar;
130 import com.trolltech.qt.gui.QSystemTrayIcon;
131 import com.trolltech.qt.gui.QTableWidgetItem;
132 import com.trolltech.qt.gui.QTextEdit;
133 import com.trolltech.qt.gui.QToolBar;
134 import com.trolltech.qt.gui.QTreeWidgetItem;
135 import com.trolltech.qt.network.QNetworkAccessManager;
136 import com.trolltech.qt.network.QNetworkReply;
137 import com.trolltech.qt.network.QNetworkRequest;
138 import com.trolltech.qt.webkit.QWebPage.WebAction;
139 import com.trolltech.qt.webkit.QWebSettings;
141 import cx.fbn.nevernote.config.InitializationException;
142 import cx.fbn.nevernote.config.StartupConfig;
143 import cx.fbn.nevernote.dialog.AccountDialog;
144 import cx.fbn.nevernote.dialog.ConfigDialog;
145 import cx.fbn.nevernote.dialog.DBEncryptDialog;
146 import cx.fbn.nevernote.dialog.DatabaseLoginDialog;
147 import cx.fbn.nevernote.dialog.DatabaseStatus;
148 import cx.fbn.nevernote.dialog.FindDialog;
149 import cx.fbn.nevernote.dialog.IgnoreSync;
150 import cx.fbn.nevernote.dialog.LogFileDialog;
151 import cx.fbn.nevernote.dialog.LoginDialog;
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.filters.FilterEditorNotebooks;
168 import cx.fbn.nevernote.filters.FilterEditorTags;
169 import cx.fbn.nevernote.gui.AttributeTreeWidget;
170 import cx.fbn.nevernote.gui.BrowserWindow;
171 import cx.fbn.nevernote.gui.DateAttributeFilterTable;
172 import cx.fbn.nevernote.gui.ExternalBrowse;
173 import cx.fbn.nevernote.gui.MainMenuBar;
174 import cx.fbn.nevernote.gui.NotebookTreeWidget;
175 import cx.fbn.nevernote.gui.SavedSearchTreeWidget;
176 import cx.fbn.nevernote.gui.SearchPanel;
177 import cx.fbn.nevernote.gui.TableView;
178 import cx.fbn.nevernote.gui.TagTreeWidget;
179 import cx.fbn.nevernote.gui.Thumbnailer;
180 import cx.fbn.nevernote.gui.TrashTreeWidget;
181 import cx.fbn.nevernote.gui.controls.QuotaProgressBar;
182 import cx.fbn.nevernote.sql.DatabaseConnection;
183 import cx.fbn.nevernote.sql.WatchFolderRecord;
184 import cx.fbn.nevernote.threads.IndexRunner;
185 import cx.fbn.nevernote.threads.SyncRunner;
186 import cx.fbn.nevernote.threads.ThumbnailRunner;
187 import cx.fbn.nevernote.utilities.AESEncrypter;
188 import cx.fbn.nevernote.utilities.ApplicationLogger;
189 import cx.fbn.nevernote.utilities.FileImporter;
190 import cx.fbn.nevernote.utilities.FileUtils;
191 import cx.fbn.nevernote.utilities.ListManager;
192 import cx.fbn.nevernote.utilities.SyncTimes;
193 import cx.fbn.nevernote.xml.ExportData;
194 import cx.fbn.nevernote.xml.ImportData;
195 import cx.fbn.nevernote.xml.NoteFormatter;
198 public class NeverNote extends QMainWindow{
200 QStatusBar statusBar; // Application status bar
202 DatabaseConnection conn;
204 MainMenuBar menuBar; // Main menu bar
205 FindDialog find; // Text search in note dialog
206 List<String> emitLog; // Messages displayed in the status bar;
207 QSystemTrayIcon trayIcon; // little tray icon
208 QMenu trayMenu; // System tray menu
209 QAction trayExitAction; // Exit the application
210 QAction trayShowAction; // toggle the show/hide action
211 QAction trayAddNoteAction; // Add a note from the system tray
212 QNetworkAccessManager versionChecker; // Used when checking for new versions
214 NotebookTreeWidget notebookTree; // List of notebooks
215 AttributeTreeWidget attributeTree; // List of note attributes
216 TagTreeWidget tagTree; // list of user created tags
217 SavedSearchTreeWidget savedSearchTree; // list of saved searches
218 TrashTreeWidget trashTree; // Trashcan
219 TableView noteTableView; // List of notes (the widget).
221 public BrowserWindow browserWindow; // Window containing browser & labels
222 public QToolBar toolBar; // The tool bar under the menu
223 QComboBox searchField; // search filter bar on the toolbar;
224 QShortcut searchShortcut; // Shortcut to search bar
225 boolean searchPerformed = false; // Search was done?
226 QuotaProgressBar quotaBar; // The current quota usage
228 ApplicationLogger logger;
229 List<String> selectedNotebookGUIDs; // List of notebook GUIDs
230 List<String> selectedTagGUIDs; // List of selected tag GUIDs
231 List<String> selectedNoteGUIDs; // List of selected notes
232 String selectedSavedSearchGUID; // Currently selected saved searches
233 private final HashMap<String, ExternalBrowse> externalWindows; // Notes being edited by an external window;
235 NoteFilter filter; // Note filter
236 String currentNoteGuid; // GUID of the current note
237 Note currentNote; // The currently viewed note
238 boolean noteDirty; // Has the note been changed?
239 boolean inkNote; // if this is an ink note, it is read only
240 boolean readOnly; // Is this note read-only?
243 ListManager listManager; // DB runnable task
245 List<QTemporaryFile> tempFiles; // Array of temporary files;
247 QTimer indexTimer; // timer to start the index thread
248 IndexRunner indexRunner; // thread to index notes
251 QTimer syncTimer; // Sync on an interval
252 QTimer syncDelayTimer; // Sync delay to free up database
253 SyncRunner syncRunner; // thread to do a sync.
254 QThread syncThread; // Thread which talks to evernote
255 ThumbnailRunner thumbnailRunner; // Runner for thumbnail thread
256 QThread thumbnailThread; // Thread that generates pretty pictures
257 QTimer saveTimer; // Timer to save note contents
259 QTimer authTimer; // Refresh authentication
260 QTimer externalFileSaveTimer; // Save files altered externally
261 QTimer thumbnailTimer; // Wakeup & scan for thumbnails
262 List<String> externalFiles; // External files to save later
263 List<String> importFilesKeep; // Auto-import files to save later
264 List<String> importFilesDelete; // Auto-import files to save later
266 int indexTime; // how often to try and index
267 boolean indexRunning; // Is indexing running?
268 boolean indexDisabled; // Is indexing disabled?
270 int syncThreadsReady; // number of sync threads that are free
271 int syncTime; // Sync interval
272 boolean syncRunning; // Is sync running?
273 boolean automaticSync; // do sync automatically?
274 QTreeWidgetItem attributeTreeSelected;
276 QAction prevButton; // Go to the previous item viewed
277 QAction nextButton; // Go to the next item in the history
278 QAction downButton; // Go to the next item in the list
279 QAction upButton; // Go to the prev. item in the list;
280 QAction synchronizeButton; // Synchronize with Evernote
281 QAction allNotesButton; // Reset & view all notes
282 QTimer synchronizeAnimationTimer; // Timer to change animation button
283 int synchronizeIconAngle; // Used to rotate sync icon
284 QAction printButton; // Print Button
285 QAction tagButton; // Tag edit button
286 QAction attributeButton; // Attribute information button
287 QAction emailButton; // Email button
288 QAction deleteButton; // Delete button
289 QAction newButton; // new Note Button;
290 QSpinBox zoomSpinner; // Zoom zoom
291 QAction searchClearButton; // Clear the search field
293 SearchPanel searchLayout; // Widget to hold search field, zoom, & quota
295 QSplitter mainLeftRightSplitter; // main splitter for left/right side
296 QSplitter leftSplitter1; // first left hand splitter
297 QSplitter browserIndexSplitter; // splitter between note index & note text
299 QFileSystemWatcher importKeepWatcher; // Watch & keep auto-import
300 QFileSystemWatcher importDeleteWatcher; // Watch & Delete auto-import
301 List<String> importedFiles; // History of imported files (so we don't import twice)
303 OnlineNoteHistory historyWindow; // online history window
304 List<NoteVersionId> versions; // history versions
306 QTimer threadMonitorTimer; // Timer to watch threads.
307 int dbThreadDeadCount=0; // number of consecutive dead times for the db thread
308 int syncThreadDeadCount=0; // number of consecutive dead times for the sync thread
309 int indexThreadDeadCount=0; // number of consecutive dead times for the index thread
310 int notebookThreadDeadCount=0; // number of consecutive dead times for the notebook thread
311 int tagDeadCount=0; // number of consecutive dead times for the tag thread
312 int trashDeadCount=0; // number of consecutive dead times for the trash thread
313 int saveThreadDeadCount=0; // number of consecutive dead times for the save thread
314 boolean disableTagThreadCheck=false;
315 boolean disableNotebookThreadCheck=false;
316 boolean disableTrashThreadCheck=false;
317 boolean disableSaveThreadCheck=false;
318 boolean disableSyncThreadCheck=false;
319 boolean disableIndexThreadCheck=false;
321 HashMap<String, String> noteCache; // Cash of note content
322 HashMap<String, Boolean> readOnlyCache; // List of cashe notes that are read-only
323 HashMap<String, Boolean> inkNoteCache; // List of cache notes that are ink notes
324 List<String> historyGuids; // GUIDs of previously viewed items
325 int historyPosition; // Position within the viewed items
326 boolean fromHistory; // Is this from the history queue?
327 String trashNoteGuid; // Guid to restore / set into or out of trash to save position
328 List<Thumbnailer> thumbGenerators; // generate preview image
329 ThumbnailViewer thumbnailViewer; // View preview thumbnail;
330 boolean encryptOnShutdown; // should I encrypt when I close?
331 boolean decryptOnShutdown; // should I decrypt on shutdown;
332 String encryptCipher; // What cipher should I use?
333 Signal0 minimizeToTray;
334 boolean windowMaximized = false; // Keep track of the window state for restores
335 List<String> pdfReadyQueue; // Queue of PDFs that are ready to be rendered.
336 List<QPixmap> syncIcons; // Array of icons used in sync animation
337 private boolean closeAction = false; // Used to say when to close or when to minimize
338 private static Logger log = Logger.getLogger(NeverNote.class);
339 private String saveLastPath; // last path we used
340 private final QTimer messageTimer; // Timer to clear the status message.
341 private QTimer blockTimer;
342 BrowserWindow blockingWindow;
344 String iconPath = new String("classpath:cx/fbn/nevernote/icons/");
347 //***************************************************************
348 //***************************************************************
349 //** Constructor & main entry point
350 //***************************************************************
351 //***************************************************************
352 // Application Constructor
353 @SuppressWarnings("static-access")
354 public NeverNote(DatabaseConnection dbConn) {
356 if (conn.getConnection() == null) {
357 String msg = new String(tr("Unable to connect to the database.\n\nThe most probable reason is that some other process\n" +
358 "is accessing the database or NeverNote is already running.\n\n" +
359 "Please end any other process or shutdown the other NeverNote before starting.\n\nExiting program."));
361 QMessageBox.critical(null, tr("Database Connection Error") ,msg);
364 setObjectName("mainWindow");
365 // thread().setPriority(Thread.MAX_PRIORITY);
367 logger = new ApplicationLogger("nevernote.log");
368 logger.log(logger.HIGH, "Starting Application");
370 decryptOnShutdown = false;
371 encryptOnShutdown = false;
372 conn.checkDatabaseVersion();
376 // Start building the invalid XML tables
377 Global.invalidElements = conn.getInvalidXMLTable().getInvalidElements();
378 List<String> elements = conn.getInvalidXMLTable().getInvalidAttributeElements();
380 for (int i=0; i<elements.size(); i++) {
381 Global.invalidAttributes.put(elements.get(i), conn.getInvalidXMLTable().getInvalidAttributes(elements.get(i)));
384 logger.log(logger.EXTREME, "Starting GUI build");
386 QTranslator nevernoteTranslator = new QTranslator();
387 nevernoteTranslator.load(Global.getFileManager().getTranslateFilePath("nevernote_" + QLocale.system().name() + ".qm"));
388 QApplication.instance().installTranslator(nevernoteTranslator);
390 Global.originalPalette = QApplication.palette();
391 QApplication.setStyle(Global.getStyle());
392 if (Global.useStandardPalette())
393 QApplication.setPalette(QApplication.style().standardPalette());
394 setWindowTitle(tr("NeverNote"));
396 mainLeftRightSplitter = new QSplitter();
397 setCentralWidget(mainLeftRightSplitter);
398 leftSplitter1 = new QSplitter();
399 leftSplitter1.setOrientation(Qt.Orientation.Vertical);
401 browserIndexSplitter = new QSplitter();
402 browserIndexSplitter.setOrientation(Qt.Orientation.Vertical);
404 //* Setup threads & thread timers
405 // int indexRunnerCount = Global.getIndexThreads();
406 // indexRunnerCount = 1;
407 QThreadPool.globalInstance().setMaxThreadCount(Global.threadCount); // increase max thread count
409 logger.log(logger.EXTREME, "Building list manager");
410 listManager = new ListManager(conn, logger);
412 logger.log(logger.EXTREME, "Building index runners & timers");
413 indexRunner = new IndexRunner("indexRunner.log",
414 Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(),
415 Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
416 indexThread = new QThread(indexRunner, "Index Thread");
417 indexRunner.indexAttachmentsLocally = Global.indexAttachmentsLocally();
418 indexRunner.indexImageRecognition = Global.indexImageRecognition();
419 indexRunner.indexNoteBody = Global.indexNoteBody();
420 indexRunner.indexNoteTitle = Global.indexNoteTitle();
421 indexRunner.specialIndexCharacters = Global.getSpecialIndexCharacters();
424 synchronizeAnimationTimer = new QTimer();
425 synchronizeAnimationTimer.timeout.connect(this, "updateSyncButton()");
427 indexTimer = new QTimer();
428 indexTime = 1000*Global.getIndexThreadSleepInterval();
429 indexTimer.start(indexTime); // Start indexing timer
430 indexTimer.timeout.connect(this, "indexTimer()");
431 indexDisabled = false;
432 indexRunning = false;
434 logger.log(logger.EXTREME, "Setting sync thread & timers");
436 syncRunner = new SyncRunner("syncRunner.log",
437 Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(),
438 Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
439 syncTime = new SyncTimes().timeValue(Global.getSyncInterval());
440 syncTimer = new QTimer();
441 syncTimer.timeout.connect(this, "syncTimer()");
442 syncRunner.status.message.connect(this, "setMessage(String)");
443 syncRunner.syncSignal.finished.connect(this, "syncThreadComplete(Boolean)");
444 syncRunner.syncSignal.errorDisconnect.connect(this, "remoteErrorDisconnect()");
447 automaticSync = true;
448 syncTimer.start(syncTime*60*1000);
450 automaticSync = false;
453 syncRunner.setEvernoteUpdateCount(Global.getEvernoteUpdateCount());
454 syncThread = new QThread(syncRunner, "Synchronization Thread");
458 logger.log(logger.EXTREME, "Starting thumnail thread");
459 pdfReadyQueue = new ArrayList<String>();
460 thumbnailRunner = new ThumbnailRunner("thumbnailRunner.log",
461 Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(),
462 Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
463 thumbnailThread = new QThread(thumbnailRunner, "Thumbnail Thread");
464 thumbnailRunner.noteSignal.thumbnailPageReady.connect(this, "thumbnailHTMLReady(String,QByteArray,Integer)");
465 thumbnailThread.start();
466 thumbGenerators = new ArrayList<Thumbnailer>();
467 thumbnailTimer = new QTimer();
468 thumbnailTimer.timeout.connect(this, "thumbnailTimer()");
470 thumbnailTimer.setInterval(500*1000); // Thumbnail every minute
471 thumbnailTimer.start();
473 logger.log(logger.EXTREME, "Starting authentication timer");
474 authTimer = new QTimer();
475 authTimer.timeout.connect(this, "authTimer()");
476 authTimer.start(1000*60*15);
477 syncRunner.syncSignal.authRefreshComplete.connect(this, "authRefreshComplete(boolean)");
479 logger.log(logger.EXTREME, "Setting save note timer");
480 saveTimer = new QTimer();
481 saveTimer.timeout.connect(this, "saveNote()");
482 if (Global.getAutoSaveInterval() > 0) {
483 saveTimer.setInterval(1000*60*Global.getAutoSaveInterval());
486 listManager.saveRunner.noteSignals.noteSaveRunnerError.connect(this, "saveRunnerError(String, String)");
488 logger.log(logger.EXTREME, "Starting external file monitor timer");
489 externalFileSaveTimer = new QTimer();
490 externalFileSaveTimer.timeout.connect(this, "externalFileEditedSaver()");
491 externalFileSaveTimer.setInterval(1000*5); // save every 5 seconds;
492 externalFiles = new ArrayList<String>();
493 importFilesDelete = new ArrayList<String>();
494 importFilesKeep = new ArrayList<String>();
495 externalFileSaveTimer.start();
497 notebookTree = new NotebookTreeWidget(conn);
498 attributeTree = new AttributeTreeWidget();
499 tagTree = new TagTreeWidget(conn);
500 savedSearchTree = new SavedSearchTreeWidget();
501 trashTree = new TrashTreeWidget();
502 noteTableView = new TableView(logger, listManager);
505 searchField = new QComboBox();
506 searchField.setObjectName("searchField");
507 //setStyleSheet("QComboBox#searchField { background-color: yellow }");
508 searchField.setEditable(true);
509 searchField.activatedIndex.connect(this, "searchFieldChanged()");
510 searchField.setDuplicatesEnabled(false);
511 searchField.editTextChanged.connect(this,"searchFieldTextChanged(String)");
512 searchShortcut = new QShortcut(this);
513 setupShortcut(searchShortcut, "Focus_Search");
514 searchShortcut.activated.connect(this, "focusSearch()");
516 quotaBar = new QuotaProgressBar();
518 zoomSpinner = new QSpinBox();
519 zoomSpinner.setMinimum(10);
520 zoomSpinner.setMaximum(1000);
521 zoomSpinner.setAccelerated(true);
522 zoomSpinner.setSingleStep(10);
523 zoomSpinner.setValue(100);
524 zoomSpinner.valueChanged.connect(this, "zoomChanged()");
526 searchLayout = new SearchPanel(searchField, quotaBar, notebookTree, zoomSpinner);
529 QGridLayout leftGrid = new QGridLayout();
530 leftSplitter1.setContentsMargins(5, 0, 0, 7);
531 leftSplitter1.setLayout(leftGrid);
532 leftGrid.addWidget(searchLayout,1,1);
533 leftGrid.addWidget(tagTree,2,1);
534 leftGrid.addWidget(attributeTree,3,1);
535 leftGrid.addWidget(savedSearchTree,4,1);
536 leftGrid.addWidget(trashTree,5, 1);
538 // Setup the browser window
539 noteCache = new HashMap<String,String>();
540 readOnlyCache = new HashMap<String, Boolean>();
541 inkNoteCache = new HashMap<String, Boolean>();
542 browserWindow = new BrowserWindow(conn);
544 mainLeftRightSplitter.addWidget(leftSplitter1);
545 mainLeftRightSplitter.addWidget(browserIndexSplitter);
547 if (Global.getListView() == Global.View_List_Wide) {
548 browserIndexSplitter.addWidget(noteTableView);
549 browserIndexSplitter.addWidget(browserWindow);
551 mainLeftRightSplitter.addWidget(noteTableView);
552 mainLeftRightSplitter.addWidget(browserWindow);
555 // Setup the thumbnail viewer
556 thumbnailViewer = new ThumbnailViewer();
557 thumbnailViewer.upArrow.connect(this, "upAction()");
558 thumbnailViewer.downArrow.connect(this, "downAction()");
559 thumbnailViewer.leftArrow.connect(this, "nextViewedAction()");
560 thumbnailViewer.rightArrow.connect(this, "previousViewedAction()");
562 //Setup external browser manager
563 externalWindows = new HashMap<String, ExternalBrowse>();
565 listManager.loadNotesIndex();
566 initializeNotebookTree();
568 initializeSavedSearchTree();
569 attributeTree.itemClicked.connect(this, "attributeTreeClicked(QTreeWidgetItem, Integer)");
570 attributeTreeSelected = null;
571 initializeNoteTable();
573 selectedNoteGUIDs = new ArrayList<String>();
574 statusBar = new QStatusBar();
575 setStatusBar(statusBar);
576 menuBar = new MainMenuBar(this);
577 emitLog = new ArrayList<String>();
579 tagTree.setDeleteAction(menuBar.tagDeleteAction);
580 tagTree.setMergeAction(menuBar.tagMergeAction);
581 tagTree.setEditAction(menuBar.tagEditAction);
582 tagTree.setAddAction(menuBar.tagAddAction);
583 tagTree.setIconAction(menuBar.tagIconAction);
584 tagTree.setVisible(Global.isWindowVisible("tagTree"));
585 leftSplitter1.setVisible(Global.isWindowVisible("leftPanel"));
586 tagTree.noteSignal.tagsAdded.connect(this, "tagsAdded(String, String)");
587 menuBar.hideTags.setChecked(Global.isWindowVisible("tagTree"));
588 listManager.tagSignal.listChanged.connect(this, "reloadTagTree()");
590 if (!Global.isWindowVisible("zoom")) {
591 searchLayout.hideZoom();
592 menuBar.hideZoom.setChecked(false);
595 notebookTree.setDeleteAction(menuBar.notebookDeleteAction);
596 notebookTree.setEditAction(menuBar.notebookEditAction);
597 notebookTree.setAddAction(menuBar.notebookAddAction);
598 notebookTree.setIconAction(menuBar.notebookIconAction);
599 notebookTree.setStackAction(menuBar.notebookStackAction);
600 notebookTree.setPublishAction(menuBar.notebookPublishAction);
601 notebookTree.setShareAction(menuBar.notebookShareAction);
602 notebookTree.setVisible(Global.isWindowVisible("notebookTree"));
603 notebookTree.noteSignal.notebookChanged.connect(this, "updateNoteNotebook(String, String)");
604 notebookTree.noteSignal.tagsChanged.connect(this, "updateNoteTags(String, List)");
605 notebookTree.noteSignal.tagsChanged.connect(this, "updateListTags(String, List)");
606 menuBar.hideNotebooks.setChecked(Global.isWindowVisible("notebookTree"));
608 savedSearchTree.setAddAction(menuBar.savedSearchAddAction);
609 savedSearchTree.setEditAction(menuBar.savedSearchEditAction);
610 savedSearchTree.setDeleteAction(menuBar.savedSearchDeleteAction);
611 savedSearchTree.setIconAction(menuBar.savedSearchIconAction);
612 savedSearchTree.itemSelectionChanged.connect(this, "updateSavedSearchSelection()");
613 savedSearchTree.setVisible(Global.isWindowVisible("savedSearchTree"));
614 menuBar.hideSavedSearches.setChecked(Global.isWindowVisible("savedSearchTree"));
616 noteTableView.setAddAction(menuBar.noteAdd);
617 noteTableView.setDeleteAction(menuBar.noteDelete);
618 noteTableView.setRestoreAction(menuBar.noteRestoreAction);
619 noteTableView.setNoteDuplicateAction(menuBar.noteDuplicateAction);
620 noteTableView.setNoteHistoryAction(menuBar.noteOnlineHistoryAction);
621 noteTableView.noteSignal.titleColorChanged.connect(this, "titleColorChanged(Integer)");
622 noteTableView.setMergeNotesAction(menuBar.noteMergeAction);
623 noteTableView.setCopyAsUrlAction(menuBar.noteCopyAsUrlAction);
624 noteTableView.doubleClicked.connect(this, "listDoubleClick()");
625 listManager.trashSignal.countChanged.connect(trashTree, "updateCounts(Integer)");
627 quotaBar.setMouseClickAction(menuBar.accountAction);
630 trashTree.itemSelectionChanged.connect(this, "trashTreeSelection()");
631 trashTree.setEmptyAction(menuBar.emptyTrashAction);
632 trashTree.setVisible(Global.isWindowVisible("trashTree"));
633 menuBar.hideTrash.setChecked(Global.isWindowVisible("trashTree"));
634 trashTree.updateCounts(listManager.getTrashCount());
635 attributeTree.setVisible(Global.isWindowVisible("attributeTree"));
636 menuBar.hideAttributes.setChecked(Global.isWindowVisible("attributeTree"));
638 noteTableView.setVisible(Global.isWindowVisible("noteList"));
639 menuBar.hideNoteList.setChecked(Global.isWindowVisible("noteList"));
641 if (!Global.isWindowVisible("editorButtonBar"))
642 toggleEditorButtonBar();
643 if (!Global.isWindowVisible("leftPanel"))
644 menuBar.hideLeftSide.setChecked(true);
645 if (Global.isWindowVisible("noteInformation"))
646 toggleNoteInformation();
647 quotaBar.setVisible(Global.isWindowVisible("quota"));
648 if (!quotaBar.isVisible())
649 menuBar.hideQuota.setChecked(false);
650 searchField.setVisible(Global.isWindowVisible("searchField"));
651 if (!searchField.isVisible())
652 menuBar.hideSearch.setChecked(false);
654 if (searchField.isHidden() && quotaBar.isHidden() && zoomSpinner.isHidden() && notebookTree.isHidden())
659 find = new FindDialog();
660 find.getOkButton().clicked.connect(this, "doFindText()");
662 // Setup the tray icon menu bar
663 trayShowAction = new QAction(tr("Show/Hide"), this);
664 trayExitAction = new QAction(tr("Exit"), this);
665 trayAddNoteAction = new QAction(tr("Add Note"), this);
667 trayExitAction.triggered.connect(this, "closeNeverNote()");
668 trayAddNoteAction.triggered.connect(this, "addNote()");
669 trayShowAction.triggered.connect(this, "trayToggleVisible()");
671 trayMenu = new QMenu(this);
672 trayMenu.addAction(trayAddNoteAction);
673 trayMenu.addAction(trayShowAction);
674 trayMenu.addAction(trayExitAction);
677 trayIcon = new QSystemTrayIcon(this);
678 trayIcon.setToolTip(tr("NeverNote"));
679 trayIcon.setContextMenu(trayMenu);
680 trayIcon.activated.connect(this, "trayActivated(com.trolltech.qt.gui.QSystemTrayIcon$ActivationReason)");
683 currentNoteGuid = Global.getLastViewedNoteGuid();
684 historyGuids = new ArrayList<String>();
688 if (!currentNoteGuid.trim().equals("")) {
689 currentNote = conn.getNoteTable().getNote(currentNoteGuid, true,true,false,false,true);
692 noteIndexUpdated(true);
694 menuBar.showEditorBar.setChecked(Global.isWindowVisible("editorButtonBar"));
695 if (menuBar.showEditorBar.isChecked())
696 showEditorButtons(browserWindow);
697 tagIndexUpdated(true);
698 savedSearchIndexUpdated();
699 notebookIndexUpdated();
701 setupSyncSignalListeners();
702 setupBrowserSignalListeners();
703 setupIndexListeners();
706 tagTree.tagSignal.listChanged.connect(this, "tagIndexUpdated()");
707 tagTree.showAllTags(true);
709 QIcon appIcon = new QIcon(iconPath+"nevernote.png");
710 setWindowIcon(appIcon);
711 trayIcon.setIcon(appIcon);
712 if (Global.showTrayIcon())
717 scrollToGuid(currentNoteGuid);
718 if (Global.automaticLogin()) {
720 if (Global.isConnected)
723 setupFolderImports();
726 restoreWindowState(true);
728 if (Global.mimicEvernoteInterface) {
729 notebookTree.selectGuid("");
732 threadMonitorTimer = new QTimer();
733 threadMonitorTimer.timeout.connect(this, "threadMonitorCheck()");
734 threadMonitorTimer.start(1000*10); // Check for threads every 10 seconds;
736 historyGuids.add(currentNoteGuid);
739 menuBar.blockSignals(true);
740 menuBar.narrowListView.blockSignals(true);
741 menuBar.wideListView.blockSignals(true);
742 if (Global.getListView() == Global.View_List_Narrow) {
743 menuBar.narrowListView.setChecked(true);
746 menuBar.wideListView.setChecked(true);
748 menuBar.blockSignals(false);
749 menuBar.narrowListView.blockSignals(false);
750 menuBar.wideListView.blockSignals(false);
752 if (Global.getListView() == Global.View_List_Wide) {
753 browserIndexSplitter.addWidget(noteTableView);
754 browserIndexSplitter.addWidget(browserWindow);
756 mainLeftRightSplitter.addWidget(noteTableView);
757 mainLeftRightSplitter.addWidget(browserWindow);
760 messageTimer = new QTimer();
761 messageTimer.timeout.connect(this, "clearMessage()");
762 messageTimer.setInterval(1000*15);
765 int sortCol = Global.getSortColumn();
766 int sortOrder = Global.getSortOrder();
767 noteTableView.sortByColumn(sortCol, SortOrder.resolve(sortOrder));
768 if (Global.checkVersionUpgrade())
773 public static void main(String[] args) {
774 log.setLevel(Level.FATAL);
775 QApplication.initialize(args);
776 QPixmap pixmap = new QPixmap("classpath:cx/fbn/nevernote/icons/splash_logo.png");
777 QSplashScreen splash = new QSplashScreen(pixmap);
780 DatabaseConnection dbConn;
783 initializeGlobalSettings(args);
785 showSplash = Global.isWindowVisible("SplashScreen");
789 dbConn = setupDatabaseConnection();
791 // Must be last stage of setup - only safe once DB is open hence we know we are the only instance running
792 Global.getFileManager().purgeResDirectory(true);
794 } catch (InitializationException e) {
797 QMessageBox.critical(null, "Startup error", "Aborting: " + e.getMessage());
801 NeverNote application = new NeverNote(dbConn);
803 application.setAttribute(WidgetAttribute.WA_DeleteOnClose, true);
804 if (Global.startMinimized())
805 application.showMinimized();
807 if (Global.wasWindowMaximized())
808 application.showMaximized();
814 splash.finish(application);
816 System.out.println("Goodbye.");
821 * Open the internal database, or create if not present
823 * @throws InitializationException when opening the database fails, e.g. because another process has it locked
825 private static DatabaseConnection setupDatabaseConnection() throws InitializationException {
826 ApplicationLogger logger = new ApplicationLogger("nevernote-database.log");
828 File f = Global.getFileManager().getDbDirFile(Global.databaseName + ".h2.db");
829 File fr = Global.getFileManager().getDbDirFile(Global.resourceDatabaseName + ".h2.db");
830 File fi = Global.getFileManager().getDbDirFile(Global.resourceDatabaseName + ".h2.db");
832 Global.setDatabaseUrl("");
834 Global.setResourceDatabaseUrl("");
836 Global.setIndexDatabaseUrl("");
838 if (Global.getDatabaseUrl().toUpperCase().indexOf("CIPHER=") > -1) {
839 boolean goodCheck = false;
841 DatabaseLoginDialog dialog = new DatabaseLoginDialog();
843 if (!dialog.okPressed())
845 Global.cipherPassword = dialog.getPassword();
846 goodCheck = databaseCheck(Global.getDatabaseUrl(), Global.getDatabaseUserid(),
847 Global.getDatabaseUserPassword(), Global.cipherPassword);
850 DatabaseConnection dbConn = new DatabaseConnection(logger,Global.getDatabaseUrl(),
851 Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(),
852 Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword, 0);
856 // Encrypt the database upon shutdown
857 private void encryptOnShutdown() {
858 String dbPath= Global.getFileManager().getDbDirPath("");
861 Statement st = conn.getConnection().createStatement();
862 st.execute("shutdown");
863 st = conn.getResourceConnection().createStatement();
864 st.execute("shutdown");
865 st = conn.getIndexConnection().createStatement();
866 st.execute("shutdown");
867 if (QMessageBox.question(this, tr("Are you sure"),
868 tr("Are you sure you wish to encrypt the database?"),
869 QMessageBox.StandardButton.Yes,
870 QMessageBox.StandardButton.No) == StandardButton.Yes.value()) {
871 ChangeFileEncryption.execute(dbPath, "NeverNote", encryptCipher, null, Global.cipherPassword.toCharArray(), true);
872 ChangeFileEncryption.execute(dbPath, "Resources", encryptCipher, null, Global.cipherPassword.toCharArray(), true);
873 ChangeFileEncryption.execute(dbPath, "Index", encryptCipher, null, Global.cipherPassword.toCharArray(), true);
874 Global.setDatabaseUrl(Global.getDatabaseUrl() + ";CIPHER="+encryptCipher);
875 Global.setResourceDatabaseUrl(Global.getResourceDatabaseUrl() + ";CIPHER="+encryptCipher);
876 Global.setIndexDatabaseUrl(Global.getIndexDatabaseUrl() + ";CIPHER="+encryptCipher);
878 QMessageBox.information(this, tr("Encryption Complete"), tr("Encryption is complete"));
880 } catch (SQLException e) {
885 // Decrypt the database upon shutdown
886 private void decryptOnShutdown() {
887 String dbPath= Global.getFileManager().getDbDirPath("");
888 String dbName = "NeverNote";
890 Statement st = conn.getConnection().createStatement();
891 st.execute("shutdown");
892 if (Global.getDatabaseUrl().toUpperCase().indexOf(";CIPHER=AES") > -1)
893 encryptCipher = "AES";
895 encryptCipher = "XTEA";
896 if (QMessageBox.question(this, tr("Confirmation"), tr("Are you sure",
897 "Are you sure you wish to decrypt the database?"),
898 QMessageBox.StandardButton.Yes,
899 QMessageBox.StandardButton.No) == StandardButton.Yes.value()) {
901 ChangeFileEncryption.execute(dbPath, dbName, encryptCipher, Global.cipherPassword.toCharArray(), null, true);
902 Global.setDatabaseUrl("");
903 Global.setResourceDatabaseUrl("");
904 Global.setIndexDatabaseUrl("");
905 QMessageBox.information(this, tr("Decryption Complete"), tr("Decryption is complete"));
907 } catch (SQLException e) {
912 * Encrypt/Decrypt the local database
914 public void doDatabaseEncrypt() {
915 // The database is not currently encrypted
916 if (Global.getDatabaseUrl().toUpperCase().indexOf("CIPHER=") == -1) {
917 if (QMessageBox.question(this, tr("Confirmation"), tr("Encrypting the database is used" +
918 "to enhance security and is performed\nupon shutdown, but please be aware that if"+
919 " you lose the password your\nis lost forever.\n\nIt is highly recommended you " +
920 "perform a backup and/or fully synchronize\n prior to executing this funtction.\n\n" +
921 "Do you wish to proceed?"),
922 QMessageBox.StandardButton.Yes,
923 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
926 DBEncryptDialog dialog = new DBEncryptDialog();
928 if (dialog.okPressed()) {
929 Global.cipherPassword = dialog.getPassword();
930 encryptOnShutdown = true;
931 encryptCipher = dialog.getEncryptionMethod();
934 DBEncryptDialog dialog = new DBEncryptDialog();
935 dialog.setWindowTitle(tr("Database Decryption"));
936 dialog.hideEncryption();
938 if (dialog.okPressed()) {
939 if (!dialog.getPassword().equals(Global.cipherPassword)) {
940 QMessageBox.critical(null, tr("Incorrect Password"), tr("Incorrect Password"));
943 decryptOnShutdown = true;
950 private static void initializeGlobalSettings(String[] args) throws InitializationException {
951 StartupConfig startupConfig = new StartupConfig();
953 for (String arg : args) {
954 String lower = arg.toLowerCase();
955 if (lower.startsWith("--name="))
956 startupConfig.setName(arg.substring(arg.indexOf('=') + 1));
957 if (lower.startsWith("--home="))
958 startupConfig.setHomeDirPath(arg.substring(arg.indexOf('=') + 1));
959 if (lower.startsWith("--disable-viewing"))
960 startupConfig.setDisableViewing(true);
962 Global.setup(startupConfig);
967 public void closeEvent(QCloseEvent event) {
968 if (Global.minimizeOnClose() && !closeAction && Global.showTrayIcon()) {
973 logger.log(logger.HIGH, "Entering NeverNote.closeEvent");
976 if (currentNote!= null & browserWindow!=null) {
977 if (!currentNote.getTitle().equals(browserWindow.getTitle()))
978 conn.getNoteTable().updateNoteTitle(currentNote.getGuid(), browserWindow.getTitle());
981 setMessage(tr("Beginning shutdown."));
983 // Close down external windows
984 Collection<ExternalBrowse> windows = externalWindows.values();
985 Iterator<ExternalBrowse> iterator = windows.iterator();
986 while (iterator.hasNext()) {
987 ExternalBrowse browser = iterator.next();
988 browser.windowClosing.disconnect();
993 externalFileEditedSaver();
994 if (Global.isConnected && Global.synchronizeOnClose()) {
995 setMessage(tr("Performing synchronization before closing."));
996 syncRunner.syncNeeded = true;
997 syncRunner.addWork("SYNC");
999 syncRunner.keepRunning = false;
1001 syncRunner.addWork("STOP");
1002 setMessage("Closing Program.");
1003 threadMonitorTimer.stop();
1005 thumbnailRunner.addWork("STOP");
1006 indexRunner.addWork("STOP");
1011 if (tempFiles != null)
1014 browserWindow.noteSignal.tagsChanged.disconnect();
1015 browserWindow.noteSignal.titleChanged.disconnect();
1016 browserWindow.noteSignal.noteChanged.disconnect();
1017 browserWindow.noteSignal.notebookChanged.disconnect();
1018 browserWindow.noteSignal.createdDateChanged.disconnect();
1019 browserWindow.noteSignal.alteredDateChanged.disconnect();
1020 syncRunner.searchSignal.listChanged.disconnect();
1021 syncRunner.tagSignal.listChanged.disconnect();
1022 syncRunner.notebookSignal.listChanged.disconnect();
1023 syncRunner.noteIndexSignal.listChanged.disconnect();
1026 Global.saveWindowVisible("toolBar", toolBar.isVisible());
1027 saveNoteColumnPositions();
1028 saveNoteIndexWidth();
1030 int width = notebookTree.columnWidth(0);
1031 Global.setColumnWidth("notebookTreeName", width);
1032 width = tagTree.columnWidth(0);
1033 Global.setColumnWidth("tagTreeName", width);
1035 Global.saveWindowMaximized(isMaximized());
1036 Global.saveCurrentNoteGuid(currentNoteGuid);
1038 int sortCol = noteTableView.proxyModel.sortColumn();
1039 int sortOrder = noteTableView.proxyModel.sortOrder().value();
1040 Global.setSortColumn(sortCol);
1041 Global.setSortOrder(sortOrder);
1045 Global.keepRunning = false;
1047 logger.log(logger.MEDIUM, "Waiting for indexThread to stop");
1048 if (indexRunner.thread().isAlive())
1049 indexRunner.thread().join(50);
1050 if (!indexRunner.thread().isAlive())
1051 logger.log(logger.MEDIUM, "Index thread has stopped");
1053 logger.log(logger.MEDIUM, "Index thread still running - interrupting");
1054 indexRunner.thread().interrupt();
1056 } catch (InterruptedException e1) {
1057 e1.printStackTrace();
1060 if (!syncRunner.thread().isAlive()) {
1061 logger.log(logger.MEDIUM, "Waiting for syncThread to stop");
1062 if (syncRunner.thread().isAlive()) {
1063 System.out.println(tr("Synchronizing. Please be patient."));
1064 for(;syncRunner.thread().isAlive();) {
1067 } catch (InterruptedException e) {
1068 e.printStackTrace();
1072 logger.log(logger.MEDIUM, "Sync thread has stopped");
1075 if (encryptOnShutdown) {
1076 encryptOnShutdown();
1078 if (decryptOnShutdown) {
1079 decryptOnShutdown();
1082 Global.getFileManager().purgeResDirectory(false);
1083 } catch (InitializationException e) {
1084 System.out.println(tr("Empty res directory purge failed"));
1085 e.printStackTrace();
1087 logger.log(logger.HIGH, "Leaving NeverNote.closeEvent");
1090 @SuppressWarnings("unused")
1091 private void closeNeverNote() {
1095 public void setMessage(String s) {
1096 logger.log(logger.HIGH, "Entering NeverNote.setMessage");
1099 logger.log(logger.HIGH, "Message: " +s);
1100 statusBar.showMessage(s);
1104 messageTimer.stop();
1105 messageTimer.setSingleShot(true);
1106 messageTimer.start();
1109 logger.log(logger.HIGH, "Leaving NeverNote.setMessage");
1112 private void clearMessage() {
1113 statusBar.clearMessage();
1117 private void waitCursor(boolean wait) {
1119 if (QApplication.overrideCursor() == null)
1120 QApplication.setOverrideCursor(new QCursor(Qt.CursorShape.WaitCursor));
1123 while (QApplication.overrideCursor() != null)
1124 QApplication.restoreOverrideCursor();
1126 listManager.refreshCounters();
1129 private void setupIndexListeners() {
1130 // indexRunner.noteSignal.noteIndexed.connect(this, "indexThreadComplete(String)");
1131 // indexRunner.resourceSignal.resourceIndexed.connect(this, "indexThreadComplete(String)");
1132 indexRunner.signal.indexStarted.connect(this, "indexStarted()");
1133 indexRunner.signal.indexFinished.connect(this, "indexComplete()");
1135 private void setupSyncSignalListeners() {
1136 syncRunner.tagSignal.listChanged.connect(this, "tagIndexUpdated()");
1137 syncRunner.searchSignal.listChanged.connect(this, "savedSearchIndexUpdated()");
1138 syncRunner.notebookSignal.listChanged.connect(this, "notebookIndexUpdated()");
1139 syncRunner.noteIndexSignal.listChanged.connect(this, "noteIndexUpdated(boolean)");
1140 syncRunner.noteSignal.quotaChanged.connect(this, "updateQuotaBar()");
1142 syncRunner.syncSignal.saveUploadAmount.connect(this,"saveUploadAmount(long)");
1143 syncRunner.syncSignal.saveUserInformation.connect(this,"saveUserInformation(User)");
1144 syncRunner.syncSignal.saveEvernoteUpdateCount.connect(this,"saveEvernoteUpdateCount(int)");
1146 syncRunner.noteSignal.guidChanged.connect(this, "noteGuidChanged(String, String)");
1147 syncRunner.noteSignal.noteChanged.connect(this, "invalidateNoteCache(String, String)");
1148 syncRunner.resourceSignal.resourceGuidChanged.connect(this, "noteResourceGuidChanged(String,String,String)");
1149 syncRunner.noteSignal.noteDownloaded.connect(listManager, "noteDownloaded(Note)");
1150 syncRunner.noteSignal.notebookChanged.connect(this, "updateNoteNotebook(String, String)");
1152 syncRunner.syncSignal.refreshLists.connect(this, "refreshLists()");
1155 private void setupBrowserSignalListeners() {
1156 setupBrowserWindowListeners(browserWindow, true);
1159 private void setupBrowserWindowListeners(BrowserWindow browser, boolean master) {
1160 browser.fileWatcher.fileChanged.connect(this, "externalFileEdited(String)");
1161 browser.noteSignal.tagsChanged.connect(this, "updateNoteTags(String, List)");
1162 browser.noteSignal.tagsChanged.connect(this, "updateListTags(String, List)");
1163 if (master) browser.noteSignal.noteChanged.connect(this, "setNoteDirty()");
1164 browser.noteSignal.titleChanged.connect(listManager, "updateNoteTitle(String, String)");
1165 browser.noteSignal.titleChanged.connect(this, "updateNoteTitle(String, String)");
1166 browser.noteSignal.notebookChanged.connect(this, "updateNoteNotebook(String, String)");
1167 browser.noteSignal.createdDateChanged.connect(listManager, "updateNoteCreatedDate(String, QDateTime)");
1168 browser.noteSignal.alteredDateChanged.connect(listManager, "updateNoteAlteredDate(String, QDateTime)");
1169 browser.noteSignal.subjectDateChanged.connect(listManager, "updateNoteSubjectDate(String, QDateTime)");
1170 browser.noteSignal.authorChanged.connect(listManager, "updateNoteAuthor(String, String)");
1171 browser.noteSignal.geoChanged.connect(listManager, "updateNoteGeoTag(String, Double,Double,Double)");
1172 browser.noteSignal.geoChanged.connect(this, "setNoteDirty()");
1173 browser.noteSignal.sourceUrlChanged.connect(listManager, "updateNoteSourceUrl(String, String)");
1174 browser.blockApplication.connect(this, "blockApplication(BrowserWindow)");
1175 browser.unblockApplication.connect(this, "unblockApplication()");
1176 if (master) browser.focusLost.connect(this, "saveNote()");
1177 browser.resourceSignal.contentChanged.connect(this, "externalFileEdited(String)");
1178 browser.evernoteLinkClicked.connect(this, "evernoteLinkClick(String, String)");
1181 //**************************************************
1183 //**************************************************
1184 private void setupShortcut(QShortcut action, String text) {
1185 if (!Global.shortcutKeys.containsAction(text))
1187 action.setKey(new QKeySequence(Global.shortcutKeys.getShortcut(text)));
1190 //***************************************************************
1191 //***************************************************************
1192 //* Settings and look & feel
1193 //***************************************************************
1194 //***************************************************************
1195 @SuppressWarnings("unused")
1196 private void settings() {
1197 logger.log(logger.HIGH, "Entering NeverNote.settings");
1198 saveNoteColumnPositions();
1199 saveNoteIndexWidth();
1201 ConfigDialog settings = new ConfigDialog(this);
1202 String dateFormat = Global.getDateFormat();
1203 String timeFormat = Global.getTimeFormat();
1205 indexTime = 1000*Global.getIndexThreadSleepInterval();
1206 indexTimer.start(indexTime); // reset indexing timer
1209 indexRunner.indexAttachmentsLocally = Global.indexAttachmentsLocally();
1210 indexRunner.indexNoteBody = Global.indexNoteBody();
1211 indexRunner.indexNoteTitle = Global.indexNoteTitle();
1212 indexRunner.specialIndexCharacters = Global.getSpecialIndexCharacters();
1213 indexRunner.indexImageRecognition = Global.indexImageRecognition();
1214 if (Global.showTrayIcon())
1219 if (menuBar.showEditorBar.isChecked())
1220 showEditorButtons(browserWindow);
1222 // Reset the save timer
1223 if (Global.getAutoSaveInterval() > 0)
1224 saveTimer.setInterval(1000*60*Global.getAutoSaveInterval());
1229 // Set special reloads
1230 if (settings.getDebugPage().reloadSharedNotebooksClicked()) {
1231 conn.executeSql("Delete from LinkedNotebook");
1232 conn.executeSql("delete from SharedNotebook");
1233 conn.executeSql("Delete from Notebook where linked=true");
1234 conn.executeSql("Insert into Sync (key, value) values ('FullLinkedNotebookSync', 'true')");
1235 conn.executeSql("Insert into Sync (key, value) values ('FullSharedNotebookSync', 'true')");
1240 readOnlyCache.clear();
1241 inkNoteCache.clear();
1242 noteIndexUpdated(true);
1244 logger.log(logger.HIGH, "Leaving NeverNote.settings");
1246 // Restore things to the way they were
1247 private void restoreWindowState(boolean mainWindow) {
1248 // We need to name things or this doesn't work.
1249 setObjectName("NeverNote");
1250 restoreState(Global.restoreState(objectName()));
1251 mainLeftRightSplitter.setObjectName("mainLeftRightSplitter");
1252 browserIndexSplitter.setObjectName("browserIndexSplitter");
1253 leftSplitter1.setObjectName("leftSplitter1");
1255 // Restore the actual positions.
1257 restoreGeometry(Global.restoreGeometry(objectName()));
1258 mainLeftRightSplitter.restoreState(Global.restoreState(mainLeftRightSplitter.objectName()));
1259 browserIndexSplitter.restoreState(Global.restoreState(browserIndexSplitter.objectName()));
1260 leftSplitter1.restoreState(Global.restoreState(leftSplitter1.objectName()));
1263 // Save window positions for the next start
1264 private void saveWindowState() {
1265 Global.saveGeometry(objectName(), saveGeometry());
1266 Global.saveState(mainLeftRightSplitter.objectName(), mainLeftRightSplitter.saveState());
1267 Global.saveState(browserIndexSplitter.objectName(), browserIndexSplitter.saveState());
1268 Global.saveState(leftSplitter1.objectName(), leftSplitter1.saveState());
1269 Global.saveState(objectName(), saveState());
1271 // Load the style sheet
1272 private void loadStyleSheet() {
1273 String styleSheetName = "default.qss";
1274 if (Global.getStyle().equalsIgnoreCase("cleanlooks"))
1275 styleSheetName = "default-cleanlooks.qss";
1276 String fileName = Global.getFileManager().getQssDirPathUser("default.qss");
1277 QFile file = new QFile(fileName);
1279 // If a user default.qss doesn't exist, we use the one shipped with NeverNote
1280 if (!file.exists()) {
1281 fileName = Global.getFileManager().getQssDirPath(styleSheetName);
1282 file = new QFile(fileName);
1284 file.open(OpenModeFlag.ReadOnly);
1285 String styleSheet = file.readAll().toString();
1287 setStyleSheet(styleSheet);
1289 // Save column positions for the next time
1290 private void saveNoteColumnPositions() {
1291 int position = noteTableView.header.visualIndex(Global.noteTableCreationPosition);
1292 Global.setColumnPosition("noteTableCreationPosition", position);
1293 position = noteTableView.header.visualIndex(Global.noteTableTagPosition);
1294 Global.setColumnPosition("noteTableTagPosition", position);
1295 position = noteTableView.header.visualIndex(Global.noteTableNotebookPosition);
1296 Global.setColumnPosition("noteTableNotebookPosition", position);
1297 position = noteTableView.header.visualIndex(Global.noteTableChangedPosition);
1298 Global.setColumnPosition("noteTableChangedPosition", position);
1299 position = noteTableView.header.visualIndex(Global.noteTableAuthorPosition);
1300 Global.setColumnPosition("noteTableAuthorPosition", position);
1301 position = noteTableView.header.visualIndex(Global.noteTableSourceUrlPosition);
1302 Global.setColumnPosition("noteTableSourceUrlPosition", position);
1303 position = noteTableView.header.visualIndex(Global.noteTableSubjectDatePosition);
1304 Global.setColumnPosition("noteTableSubjectDatePosition", position);
1305 position = noteTableView.header.visualIndex(Global.noteTableTitlePosition);
1306 Global.setColumnPosition("noteTableTitlePosition", position);
1307 position = noteTableView.header.visualIndex(Global.noteTableSynchronizedPosition);
1308 Global.setColumnPosition("noteTableSynchronizedPosition", position);
1309 position = noteTableView.header.visualIndex(Global.noteTableGuidPosition);
1310 Global.setColumnPosition("noteTableGuidPosition", position);
1311 position = noteTableView.header.visualIndex(Global.noteTableThumbnailPosition);
1312 Global.setColumnPosition("noteTableThumbnailPosition", position);
1315 // Save column widths for the next time
1316 private void saveNoteIndexWidth() {
1318 width = noteTableView.getColumnWidth(Global.noteTableCreationPosition);
1319 Global.setColumnWidth("noteTableCreationPosition", width);
1320 width = noteTableView.getColumnWidth(Global.noteTableChangedPosition);
1321 Global.setColumnWidth("noteTableChangedPosition", width);
1322 width = noteTableView.getColumnWidth(Global.noteTableGuidPosition);
1323 Global.setColumnWidth("noteTableGuidPosition", width);
1324 width = noteTableView.getColumnWidth(Global.noteTableNotebookPosition);
1325 Global.setColumnWidth("noteTableNotebookPosition", width);
1326 width = noteTableView.getColumnWidth(Global.noteTableTagPosition);
1327 Global.setColumnWidth("noteTableTagPosition", width);
1328 width = noteTableView.getColumnWidth(Global.noteTableTitlePosition);
1329 Global.setColumnWidth("noteTableTitlePosition", width);
1330 width = noteTableView.getColumnWidth(Global.noteTableSourceUrlPosition);
1331 Global.setColumnWidth("noteTableSourceUrlPosition", width);
1332 width = noteTableView.getColumnWidth(Global.noteTableAuthorPosition);
1333 Global.setColumnWidth("noteTableAuthorPosition", width);
1334 width = noteTableView.getColumnWidth(Global.noteTableSubjectDatePosition);
1335 Global.setColumnWidth("noteTableSubjectDatePosition", width);
1336 width = noteTableView.getColumnWidth(Global.noteTableSynchronizedPosition);
1337 Global.setColumnWidth("noteTableSynchronizedPosition", width);
1338 width = noteTableView.getColumnWidth(Global.noteTableThumbnailPosition);
1339 Global.setColumnWidth("noteTableThumbnailPosition", width);
1340 width = noteTableView.getColumnWidth(Global.noteTableGuidPosition);
1341 Global.setColumnWidth("noteTableGuidPosition", width);
1344 @SuppressWarnings("unused")
1345 private void toggleSearchWindow() {
1346 logger.log(logger.HIGH, "Entering NeverNote.toggleSearchWindow");
1347 searchLayout.toggleSearchField();
1348 menuBar.hideSearch.setChecked(searchField.isVisible());
1349 Global.saveWindowVisible("searchField", searchField.isVisible());
1350 logger.log(logger.HIGH, "Leaving NeverNote.toggleSearchWindow");
1352 @SuppressWarnings("unused")
1353 private void toggleQuotaWindow() {
1354 logger.log(logger.HIGH, "Entering NeverNote.toggleQuotaWindow");
1355 searchLayout.toggleQuotaBar();
1356 menuBar.hideQuota.setChecked(quotaBar.isVisible());
1357 Global.saveWindowVisible("quota", quotaBar.isVisible());
1358 logger.log(logger.HIGH, "Leaving NeverNote.toggleQuotaWindow");
1360 @SuppressWarnings("unused")
1361 private void toggleZoomWindow() {
1362 logger.log(logger.HIGH, "Entering NeverNote.toggleZoomWindow");
1363 searchLayout.toggleZoom();
1364 menuBar.hideZoom.setChecked(zoomSpinner.isVisible());
1365 Global.saveWindowVisible("zoom", zoomSpinner.isVisible());
1366 logger.log(logger.HIGH, "Leaving NeverNote.toggleZoomWindow");
1371 //***************************************************************
1372 //***************************************************************
1373 //** These functions deal with Notebook menu items
1374 //***************************************************************
1375 //***************************************************************
1376 // Setup the tree containing the user's notebooks.
1377 private void initializeNotebookTree() {
1378 logger.log(logger.HIGH, "Entering NeverNote.initializeNotebookTree");
1379 // notebookTree.itemClicked.connect(this, "notebookTreeSelection()");
1380 notebookTree.selectionSignal.connect(this, "notebookTreeSelection()");
1381 listManager.notebookSignal.refreshNotebookTreeCounts.connect(notebookTree, "updateCounts(List, List)");
1382 logger.log(logger.HIGH, "Leaving NeverNote.initializeNotebookTree");
1384 // Listener when a notebook is selected
1385 private void notebookTreeSelection() {
1386 logger.log(logger.HIGH, "Entering NeverNote.notebookTreeSelection");
1389 clearAttributeFilter();
1390 clearSavedSearchFilter();
1391 if (Global.mimicEvernoteInterface) {
1393 searchField.clear();
1395 menuBar.noteRestoreAction.setVisible(false);
1396 menuBar.notebookEditAction.setEnabled(true);
1397 menuBar.notebookDeleteAction.setEnabled(true);
1398 menuBar.notebookPublishAction.setEnabled(true);
1399 menuBar.notebookShareAction.setEnabled(true);
1400 menuBar.notebookIconAction.setEnabled(true);
1401 menuBar.notebookStackAction.setEnabled(true);
1402 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1403 selectedNotebookGUIDs.clear();
1405 String stackName = "";
1406 if (selections.size() > 0) {
1407 guid = (selections.get(0).text(2));
1408 stackName = selections.get(0).text(0);
1410 if (!Global.mimicEvernoteInterface) {
1411 // If no notebooks are selected, we make it look like the "all notebooks" one was selected
1412 if (selections.size()==0) {
1413 selectedNotebookGUIDs.clear();
1414 for (int i=0; i < listManager.getNotebookIndex().size(); i++) {
1415 selectedNotebookGUIDs.add(listManager.getNotebookIndex().get(i).getGuid());
1417 menuBar.notebookEditAction.setEnabled(false);
1418 menuBar.notebookDeleteAction.setEnabled(false);
1419 menuBar.notebookStackAction.setEnabled(false);
1420 menuBar.notebookIconAction.setEnabled(false);
1423 if (!guid.equals("") && !guid.equals("STACK")) {
1424 selectedNotebookGUIDs.add(guid);
1425 menuBar.notebookIconAction.setEnabled(true);
1427 menuBar.notebookIconAction.setEnabled(true);
1428 for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1429 Notebook book = listManager.getNotebookIndex().get(j);
1430 if (book.getStack() != null && book.getStack().equalsIgnoreCase(stackName))
1431 selectedNotebookGUIDs.add(book.getGuid());
1434 listManager.setSelectedNotebooks(selectedNotebookGUIDs);
1435 listManager.loadNotesIndex();
1436 noteIndexUpdated(false);
1437 refreshEvernoteNote(true);
1438 listManager.refreshCounters = true;
1439 listManager.refreshCounters();
1440 logger.log(logger.HIGH, "Leaving NeverNote.notebookTreeSelection");
1443 private void clearNotebookFilter() {
1444 notebookTree.blockSignals(true);
1445 notebookTree.clearSelection();
1446 menuBar.noteRestoreAction.setVisible(false);
1447 menuBar.notebookEditAction.setEnabled(false);
1448 menuBar.notebookDeleteAction.setEnabled(false);
1449 selectedNotebookGUIDs.clear();
1450 listManager.setSelectedNotebooks(selectedNotebookGUIDs);
1451 notebookTree.blockSignals(false);
1453 // Triggered when the notebook DB has been updated
1454 private void notebookIndexUpdated() {
1455 logger.log(logger.HIGH, "Entering NeverNote.notebookIndexUpdated");
1457 // Get the possible icons
1458 HashMap<String, QIcon> icons = conn.getNotebookTable().getAllIcons();
1459 notebookTree.setIcons(icons);
1461 if (selectedNotebookGUIDs == null)
1462 selectedNotebookGUIDs = new ArrayList<String>();
1463 List<Notebook> books = conn.getNotebookTable().getAll();
1464 for (int i=books.size()-1; i>=0; i--) {
1465 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
1466 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(books.get(i).getGuid())) {
1468 j=listManager.getArchiveNotebookIndex().size();
1474 listManager.countNotebookResults(listManager.getNoteIndex());
1475 notebookTree.blockSignals(true);
1476 notebookTree.load(books, listManager.getLocalNotebooks());
1477 for (int i=selectedNotebookGUIDs.size()-1; i>=0; i--) {
1478 boolean found = notebookTree.selectGuid(selectedNotebookGUIDs.get(i));
1480 selectedNotebookGUIDs.remove(i);
1482 listManager.refreshCounters = true;
1483 listManager.refreshCounters();
1484 notebookTree.blockSignals(false);
1486 logger.log(logger.HIGH, "Leaving NeverNote.notebookIndexUpdated");
1488 // Show/Hide note information
1489 @SuppressWarnings("unused")
1490 private void toggleNotebookWindow() {
1491 logger.log(logger.HIGH, "Entering NeverNote.toggleNotebookWindow");
1492 searchLayout.toggleNotebook();
1493 menuBar.hideNotebooks.setChecked(notebookTree.isVisible());
1494 Global.saveWindowVisible("notebookTree", notebookTree.isVisible());
1495 logger.log(logger.HIGH, "Leaving NeverNote.toggleNotebookWindow");
1497 // Add a new notebook
1498 @SuppressWarnings("unused")
1499 private void addNotebook() {
1500 logger.log(logger.HIGH, "Inside NeverNote.addNotebook");
1501 NotebookEdit edit = new NotebookEdit();
1502 edit.setNotebooks(listManager.getNotebookIndex());
1505 if (!edit.okPressed())
1508 Calendar currentTime = new GregorianCalendar();
1509 Long l = new Long(currentTime.getTimeInMillis());
1510 String randint = new String(Long.toString(l));
1512 Notebook newBook = new Notebook();
1513 newBook.setUpdateSequenceNum(0);
1514 newBook.setGuid(randint);
1515 newBook.setName(edit.getNotebook());
1516 newBook.setServiceCreated(new Date().getTime());
1517 newBook.setServiceUpdated(new Date().getTime());
1518 newBook.setDefaultNotebook(false);
1519 newBook.setPublished(false);
1521 listManager.getNotebookIndex().add(newBook);
1523 listManager.getLocalNotebooks().add(newBook.getGuid());
1524 conn.getNotebookTable().addNotebook(newBook, true, edit.isLocal());
1525 notebookIndexUpdated();
1526 listManager.countNotebookResults(listManager.getNoteIndex());
1527 // notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
1528 logger.log(logger.HIGH, "Leaving NeverNote.addNotebook");
1530 // Edit an existing notebook
1531 @SuppressWarnings("unused")
1532 private void stackNotebook() {
1533 logger.log(logger.HIGH, "Entering NeverNote.stackNotebook");
1534 StackNotebook edit = new StackNotebook();
1536 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1537 QTreeWidgetItem currentSelection;
1538 for (int i=0; i<selections.size(); i++) {
1539 currentSelection = selections.get(0);
1540 String guid = currentSelection.text(2);
1541 if (guid.equalsIgnoreCase("")) {
1542 QMessageBox.critical(this, tr("Unable To Stack") ,tr("You can't stack the \"All Notebooks\" item."));
1545 if (guid.equalsIgnoreCase("STACK")) {
1546 QMessageBox.critical(this, tr("Unable To Stack") ,tr("You can't stack a stack."));
1551 edit.setStackNames(conn.getNotebookTable().getAllStackNames());
1556 if (!edit.okPressed())
1559 String stack = edit.getStackName();
1561 for (int i=0; i<selections.size(); i++) {
1562 currentSelection = selections.get(i);
1563 String guid = currentSelection.text(2);
1564 listManager.updateNotebookStack(guid, stack);
1566 notebookIndexUpdated();
1567 logger.log(logger.HIGH, "Leaving NeverNote.stackNotebook");
1569 // Edit an existing notebook
1570 @SuppressWarnings("unused")
1571 private void editNotebook() {
1572 logger.log(logger.HIGH, "Entering NeverNote.editNotebook");
1573 NotebookEdit edit = new NotebookEdit();
1575 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1576 QTreeWidgetItem currentSelection;
1577 currentSelection = selections.get(0);
1578 edit.setNotebook(currentSelection.text(0));
1580 String guid = currentSelection.text(2);
1581 if (!guid.equalsIgnoreCase("STACK")) {
1582 edit.setTitle(tr("Edit Notebook"));
1583 edit.setNotebooks(listManager.getNotebookIndex());
1584 edit.setLocalCheckboxEnabled(false);
1585 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1586 if (listManager.getNotebookIndex().get(i).getGuid().equals(guid)) {
1587 edit.setDefaultNotebook(listManager.getNotebookIndex().get(i).isDefaultNotebook());
1588 i=listManager.getNotebookIndex().size();
1592 edit.setTitle(tr("Edit Stack"));
1593 edit.setStacks(conn.getNotebookTable().getAllStackNames());
1594 edit.hideLocalCheckbox();
1595 edit.hideDefaultCheckbox();
1600 if (!edit.okPressed())
1604 if (guid.equalsIgnoreCase("STACK")) {
1605 conn.getNotebookTable().renameStacks(currentSelection.text(0), edit.getNotebook());
1606 for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1607 if (listManager.getNotebookIndex().get(j).getStack() != null &&
1608 listManager.getNotebookIndex().get(j).getStack().equalsIgnoreCase(currentSelection.text(0)))
1609 listManager.getNotebookIndex().get(j).setStack(edit.getNotebook());
1611 conn.getNotebookTable().renameStacks(currentSelection.text(0), edit.getNotebook());
1612 currentSelection.setText(0, edit.getNotebook());
1616 updateListNotebookName(currentSelection.text(0), edit.getNotebook());
1617 currentSelection.setText(0, edit.getNotebook());
1619 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1620 if (listManager.getNotebookIndex().get(i).getGuid().equals(guid)) {
1621 listManager.getNotebookIndex().get(i).setName(edit.getNotebook());
1622 if (!listManager.getNotebookIndex().get(i).isDefaultNotebook() && edit.isDefaultNotebook()) {
1623 for (int j=0; j<listManager.getNotebookIndex().size(); j++)
1624 listManager.getNotebookIndex().get(j).setDefaultNotebook(false);
1625 listManager.getNotebookIndex().get(i).setDefaultNotebook(true);
1626 conn.getNotebookTable().setDefaultNotebook(listManager.getNotebookIndex().get(i).getGuid());
1628 conn.getNotebookTable().updateNotebook(listManager.getNotebookIndex().get(i), true);
1629 if (conn.getNotebookTable().isLinked(listManager.getNotebookIndex().get(i).getGuid())) {
1630 LinkedNotebook linkedNotebook = conn.getLinkedNotebookTable().getByNotebookGuid(listManager.getNotebookIndex().get(i).getGuid());
1631 linkedNotebook.setShareName(edit.getNotebook());
1632 conn.getLinkedNotebookTable().updateNotebook(linkedNotebook, true);
1634 i=listManager.getNotebookIndex().size();
1638 // Build a list of non-closed notebooks
1639 List<Notebook> nbooks = new ArrayList<Notebook>();
1640 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1641 boolean found=false;
1642 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
1643 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid()))
1647 nbooks.add(listManager.getNotebookIndex().get(i));
1651 FilterEditorNotebooks notebookFilter = new FilterEditorNotebooks(conn, logger);
1652 List<Notebook> filteredBooks = notebookFilter.getValidNotebooks(currentNote, listManager.getNotebookIndex());
1653 browserWindow.setNotebookList(filteredBooks);
1654 Iterator<String> set = externalWindows.keySet().iterator();
1655 while(set.hasNext())
1656 externalWindows.get(set.next()).getBrowserWindow().setNotebookList(filteredBooks);
1657 logger.log(logger.HIGH, "Leaving NeverNote.editNotebook");
1659 // Publish a notebook
1660 @SuppressWarnings("unused")
1661 private void publishNotebook() {
1662 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1663 QTreeWidgetItem currentSelection;
1664 currentSelection = selections.get(0);
1665 String guid = currentSelection.text(2);
1667 if (guid.equalsIgnoreCase("STACK") || guid.equalsIgnoreCase(""))
1672 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1673 if (guid.equals(listManager.getNotebookIndex().get(i).getGuid())) {
1674 n = listManager.getNotebookIndex().get(i);
1676 i = listManager.getNotebookIndex().size();
1682 PublishNotebook publish = new PublishNotebook(Global.username, Global.getServer(), n);
1685 if (!publish.okClicked())
1688 Publishing p = publish.getPublishing();
1689 boolean isPublished = !publish.isStopPressed();
1690 conn.getNotebookTable().setPublishing(n.getGuid(), isPublished, p);
1691 n.setPublished(isPublished);
1693 listManager.getNotebookIndex().set(position, n);
1694 notebookIndexUpdated();
1696 // Publish a notebook
1697 @SuppressWarnings("unused")
1698 private void shareNotebook() {
1699 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1700 QTreeWidgetItem currentSelection;
1701 currentSelection = selections.get(0);
1702 String guid = currentSelection.text(2);
1704 if (guid.equalsIgnoreCase("STACK") || guid.equalsIgnoreCase(""))
1708 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1709 if (guid.equals(listManager.getNotebookIndex().get(i).getGuid())) {
1710 n = listManager.getNotebookIndex().get(i);
1711 i = listManager.getNotebookIndex().size();
1715 String authToken = null;
1716 if (syncRunner.isConnected)
1717 authToken = syncRunner.authToken;
1718 ShareNotebook share = new ShareNotebook(n.getName(), conn, n, syncRunner);
1723 // Delete an existing notebook
1724 @SuppressWarnings("unused")
1725 private void deleteNotebook() {
1726 logger.log(logger.HIGH, "Entering NeverNote.deleteNotebook");
1727 boolean stacksFound = false;
1728 boolean notebooksFound = false;
1729 boolean assigned = false;
1730 // Check if any notes have this notebook
1731 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1732 for (int i=0; i<selections.size(); i++) {
1733 QTreeWidgetItem currentSelection;
1734 currentSelection = selections.get(i);
1735 String guid = currentSelection.text(2);
1736 if (!guid.equalsIgnoreCase("STACK")) {
1737 notebooksFound = true;
1738 for (int j=0; j<listManager.getNoteIndex().size(); j++) {
1739 String noteGuid = listManager.getNoteIndex().get(j).getNotebookGuid();
1740 if (noteGuid.equals(guid)) {
1742 j=listManager.getNoteIndex().size();
1743 i=selections.size();
1751 QMessageBox.information(this, tr("Unable to Delete"), tr("Some of the selected notebook(s) contain notes.\n"+
1752 "Please delete the notes or move them to another notebook before deleting any notebooks."));
1756 if (conn.getNotebookTable().getAll().size() == 1) {
1757 QMessageBox.information(this, tr("Unable to Delete"), tr("You must have at least one notebook."));
1761 // If all notebooks are clear, verify the delete
1762 String msg1 = new String(tr("Delete selected notebooks?"));
1763 String msg2 = new String(tr("Remove selected stacks (notebooks will not be deleted)?"));
1764 String msg3 = new String(tr("Delete selected notebooks & remove stacks? Notebooks under the stacks are" +
1765 " not deleted unless selected?"));
1767 if (stacksFound && notebooksFound)
1769 if (!stacksFound && notebooksFound)
1771 if (stacksFound && !notebooksFound)
1773 if (QMessageBox.question(this, tr("Confirmation"), msg,
1774 QMessageBox.StandardButton.Yes,
1775 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
1779 // If confirmed, delete the notebook
1780 for (int i=selections.size()-1; i>=0; i--) {
1781 QTreeWidgetItem currentSelection;
1782 currentSelection = selections.get(i);
1783 String guid = currentSelection.text(2);
1784 if (currentSelection.text(2).equalsIgnoreCase("STACK")) {
1785 conn.getNotebookTable().renameStacks(currentSelection.text(0), "");
1786 listManager.renameStack(currentSelection.text(0), "");
1788 conn.getNotebookTable().expungeNotebook(guid, true);
1789 listManager.deleteNotebook(guid);
1793 notebookIndexUpdated();
1794 // notebookTreeSelection();
1795 // notebookTree.load(listManager.getNotebookIndex(), listManager.getLocalNotebooks());
1796 // listManager.countNotebookResults(listManager.getNoteIndex());
1797 logger.log(logger.HIGH, "Entering NeverNote.deleteNotebook");
1799 // A note's notebook has been updated
1800 @SuppressWarnings("unused")
1801 private void updateNoteNotebook(String guid, String notebookGuid) {
1803 // Update the list manager
1804 listManager.updateNoteNotebook(guid, notebookGuid);
1805 listManager.countNotebookResults(listManager.getNoteIndex());
1806 // notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
1808 // Find the name of the notebook
1809 String notebookName = null;
1810 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1811 if (listManager.getNotebookIndex().get(i).getGuid().equals(notebookGuid)) {
1812 notebookName = listManager.getNotebookIndex().get(i).getName();
1817 // If we found the name, update the browser window
1818 if (notebookName != null) {
1819 updateListNoteNotebook(guid, notebookName);
1820 if (guid.equals(currentNoteGuid)) {
1821 int pos = browserWindow.notebookBox.findText(notebookName);
1823 browserWindow.notebookBox.setCurrentIndex(pos);
1827 // If we're dealing with the current note, then we need to be sure and update the notebook there
1828 if (guid.equals(currentNoteGuid)) {
1829 if (currentNote != null) {
1830 currentNote.setNotebookGuid(notebookGuid);
1834 // Open/close notebooks
1835 @SuppressWarnings("unused")
1836 private void closeNotebooks() {
1837 NotebookArchive na = new NotebookArchive(listManager.getNotebookIndex(), listManager.getArchiveNotebookIndex());
1839 if (!na.okClicked())
1843 listManager.getArchiveNotebookIndex().clear();
1845 for (int i=na.getClosedBookList().count()-1; i>=0; i--) {
1846 String text = na.getClosedBookList().takeItem(i).text();
1847 for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1848 if (listManager.getNotebookIndex().get(j).getName().equalsIgnoreCase(text)) {
1849 Notebook n = listManager.getNotebookIndex().get(j);
1850 conn.getNotebookTable().setArchived(n.getGuid(),true);
1851 listManager.getArchiveNotebookIndex().add(n);
1852 j=listManager.getNotebookIndex().size();
1857 for (int i=na.getOpenBookList().count()-1; i>=0; i--) {
1858 String text = na.getOpenBookList().takeItem(i).text();
1859 for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
1860 if (listManager.getNotebookIndex().get(j).getName().equalsIgnoreCase(text)) {
1861 Notebook n = listManager.getNotebookIndex().get(j);
1862 conn.getNotebookTable().setArchived(n.getGuid(),false);
1863 j=listManager.getNotebookIndex().size();
1867 notebookTreeSelection();
1868 listManager.loadNotesIndex();
1869 notebookIndexUpdated();
1870 noteIndexUpdated(false);
1871 reloadTagTree(true);
1872 // noteIndexUpdated(false);
1874 // Build a list of non-closed notebooks
1875 List<Notebook> nbooks = new ArrayList<Notebook>();
1876 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
1877 boolean found=false;
1878 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
1879 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid()))
1883 nbooks.add(listManager.getNotebookIndex().get(i));
1886 FilterEditorNotebooks notebookFilter = new FilterEditorNotebooks(conn, logger);
1887 List<Notebook> filteredBooks = notebookFilter.getValidNotebooks(currentNote, listManager.getNotebookIndex());
1888 browserWindow.setNotebookList(filteredBooks);
1890 // Update any external windows
1891 Iterator<String> set = externalWindows.keySet().iterator();
1892 while(set.hasNext())
1893 externalWindows.get(set.next()).getBrowserWindow().setNotebookList(filteredBooks);
1897 // Change the notebook's icon
1898 @SuppressWarnings("unused")
1899 private void setNotebookIcon() {
1900 boolean stackSelected = false;
1901 boolean allNotebookSelected = false;
1903 QTreeWidgetItem currentSelection;
1904 List<QTreeWidgetItem> selections = notebookTree.selectedItems();
1905 if (selections.size() == 0)
1908 currentSelection = selections.get(0);
1909 String guid = currentSelection.text(2);
1910 if (guid.equalsIgnoreCase(""))
1911 allNotebookSelected = true;
1912 if (guid.equalsIgnoreCase("STACK"))
1913 stackSelected = true;
1915 QIcon currentIcon = currentSelection.icon(0);
1919 if (!stackSelected && !allNotebookSelected) {
1920 icon = conn.getNotebookTable().getIcon(guid);
1922 dialog = new SetIcon(currentIcon, saveLastPath);
1923 dialog.setUseDefaultIcon(true);
1925 dialog = new SetIcon(icon, saveLastPath);
1926 dialog.setUseDefaultIcon(false);
1929 if (stackSelected) {
1930 icon = conn.getSystemIconTable().getIcon(currentSelection.text(0), "STACK");
1932 icon = conn.getSystemIconTable().getIcon(currentSelection.text(0), "ALLNOTEBOOK");
1935 dialog = new SetIcon(currentIcon, saveLastPath);
1936 dialog.setUseDefaultIcon(true);
1938 dialog = new SetIcon(icon, saveLastPath);
1939 dialog.setUseDefaultIcon(false);
1943 if (dialog.okPressed()) {
1944 saveLastPath = dialog.getPath();
1946 QIcon newIcon = dialog.getIcon();
1947 if (stackSelected) {
1948 conn.getSystemIconTable().setIcon(currentSelection.text(0), "STACK", newIcon, dialog.getFileType());
1949 if (newIcon == null) {
1950 newIcon = new QIcon(iconPath+"books2.png");
1952 currentSelection.setIcon(0,newIcon);
1955 if (allNotebookSelected) {
1956 conn.getSystemIconTable().setIcon(currentSelection.text(0), "ALLNOTEBOOK", newIcon, dialog.getFileType());
1957 if (newIcon == null) {
1958 newIcon = new QIcon(iconPath+"notebook-green.png");
1960 currentSelection.setIcon(0,newIcon);
1963 conn.getNotebookTable().setIcon(guid, newIcon, dialog.getFileType());
1964 if (newIcon == null) {
1965 boolean isPublished = false;;
1966 boolean found = false;
1967 for (int i=0; i<listManager.getNotebookIndex().size() && !found; i++) {
1968 if (listManager.getNotebookIndex().get(i).getGuid().equals(guid)) {
1969 isPublished = listManager.getNotebookIndex().get(i).isPublished();
1973 newIcon = notebookTree.findDefaultIcon(guid, currentSelection.text(1), listManager.getLocalNotebooks(), isPublished);
1975 currentSelection.setIcon(0, newIcon);
1981 //***************************************************************
1982 //***************************************************************
1983 //** These functions deal with Tag menu items
1984 //***************************************************************
1985 //***************************************************************
1986 // Add a new notebook
1987 @SuppressWarnings("unused")
1988 private void addTag() {
1989 logger.log(logger.HIGH, "Inside NeverNote.addTag");
1990 TagEdit edit = new TagEdit();
1991 edit.setTagList(listManager.getTagIndex());
1993 List<QTreeWidgetItem> selections = tagTree.selectedItems();
1994 QTreeWidgetItem currentSelection = null;
1995 if (selections.size() > 0) {
1996 currentSelection = selections.get(0);
1997 edit.setParentTag(currentSelection.text(0));
2002 if (!edit.okPressed())
2005 Calendar currentTime = new GregorianCalendar();
2006 Long l = new Long(currentTime.getTimeInMillis());
2007 String randint = new String(Long.toString(l));
2009 Tag newTag = new Tag();
2010 newTag.setUpdateSequenceNum(0);
2011 newTag.setGuid(randint);
2012 newTag.setName(edit.getTag());
2013 if (edit.getParentTag().isChecked()) {
2014 newTag.setParentGuid(currentSelection.text(2));
2015 newTag.setParentGuidIsSet(true);
2016 currentSelection.setExpanded(true);
2018 conn.getTagTable().addTag(newTag, true);
2019 listManager.getTagIndex().add(newTag);
2020 reloadTagTree(true);
2022 logger.log(logger.HIGH, "Leaving NeverNote.addTag");
2024 @SuppressWarnings("unused")
2025 private void reloadTagTree() {
2026 reloadTagTree(false);
2028 private void reloadTagTree(boolean reload) {
2029 logger.log(logger.HIGH, "Entering NeverNote.reloadTagTree");
2030 tagIndexUpdated(reload);
2031 boolean filter = false;
2033 listManager.countTagResults(listManager.getNoteIndex());
2034 if (notebookTree.selectedItems().size() > 0
2035 && !notebookTree.selectedItems().get(0).text(0).equalsIgnoreCase("All Notebooks"))
2037 if (tagTree.selectedItems().size() > 0)
2039 tagTree.showAllTags(!filter);
2040 logger.log(logger.HIGH, "Leaving NeverNote.reloadTagTree");
2042 // Edit an existing tag
2043 @SuppressWarnings("unused")
2044 private void editTag() {
2045 logger.log(logger.HIGH, "Entering NeverNote.editTag");
2046 TagEdit edit = new TagEdit();
2047 edit.setTitle("Edit Tag");
2048 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2049 QTreeWidgetItem currentSelection;
2050 currentSelection = selections.get(0);
2051 edit.setTag(currentSelection.text(0));
2052 edit.setTagList(listManager.getTagIndex());
2055 if (!edit.okPressed())
2058 String guid = currentSelection.text(2);
2059 currentSelection.setText(0,edit.getTag());
2061 for (int i=0; i<listManager.getTagIndex().size(); i++) {
2062 if (listManager.getTagIndex().get(i).getGuid().equals(guid)) {
2063 listManager.getTagIndex().get(i).setName(edit.getTag());
2064 conn.getTagTable().updateTag(listManager.getTagIndex().get(i), true);
2065 updateListTagName(guid);
2066 if (currentNote != null && currentNote.getTagGuids().contains(guid))
2067 browserWindow.setTag(getTagNamesForNote(currentNote));
2068 logger.log(logger.HIGH, "Leaving NeverNote.editTag");
2072 browserWindow.setTag(getTagNamesForNote(currentNote));
2073 logger.log(logger.HIGH, "Leaving NeverNote.editTag...");
2075 // Delete an existing tag
2076 @SuppressWarnings("unused")
2077 private void deleteTag() {
2078 logger.log(logger.HIGH, "Entering NeverNote.deleteTag");
2080 if (QMessageBox.question(this, tr("Confirmation"), tr("Delete the selected tags?"),
2081 QMessageBox.StandardButton.Yes,
2082 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
2086 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2087 for (int i=selections.size()-1; i>=0; i--) {
2088 QTreeWidgetItem currentSelection;
2089 currentSelection = selections.get(i);
2090 removeTagItem(currentSelection.text(2));
2092 tagIndexUpdated(true);
2094 listManager.countTagResults(listManager.getNoteIndex());
2095 // tagTree.updateCounts(listManager.getTagCounter());
2096 logger.log(logger.HIGH, "Leaving NeverNote.deleteTag");
2098 // Remove a tag tree item. Go recursively down & remove the children too
2099 private void removeTagItem(String guid) {
2100 for (int j=listManager.getTagIndex().size()-1; j>=0; j--) {
2101 String parent = listManager.getTagIndex().get(j).getParentGuid();
2102 if (parent != null && parent.equals(guid)) {
2103 //Remove this tag's children
2104 removeTagItem(listManager.getTagIndex().get(j).getGuid());
2107 //Now, remove this tag
2108 removeListTagName(guid);
2109 conn.getTagTable().expungeTag(guid, true);
2110 for (int a=0; a<listManager.getTagIndex().size(); a++) {
2111 if (listManager.getTagIndex().get(a).getGuid().equals(guid)) {
2112 listManager.getTagIndex().remove(a);
2117 // Setup the tree containing the user's tags
2118 private void initializeTagTree() {
2119 logger.log(logger.HIGH, "Entering NeverNote.initializeTagTree");
2120 // tagTree.itemSelectionChanged.connect(this, "tagTreeSelection()");
2121 // tagTree.itemClicked.connect(this, "tagTreeSelection()");
2122 tagTree.selectionSignal.connect(this, "tagTreeSelection()");
2123 listManager.tagSignal.refreshTagTreeCounts.connect(tagTree, "updateCounts(List)");
2124 logger.log(logger.HIGH, "Leaving NeverNote.initializeTagTree");
2126 // Listener when a tag is selected
2127 private void tagTreeSelection() {
2128 logger.log(logger.HIGH, "Entering NeverNote.tagTreeSelection");
2131 clearAttributeFilter();
2132 clearSavedSearchFilter();
2134 menuBar.noteRestoreAction.setVisible(false);
2136 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2137 QTreeWidgetItem currentSelection;
2138 selectedTagGUIDs.clear();
2139 for (int i=0; i<selections.size(); i++) {
2140 currentSelection = selections.get(i);
2141 selectedTagGUIDs.add(currentSelection.text(2));
2143 if (selections.size() > 0) {
2144 menuBar.tagEditAction.setEnabled(true);
2145 menuBar.tagDeleteAction.setEnabled(true);
2146 menuBar.tagIconAction.setEnabled(true);
2149 menuBar.tagEditAction.setEnabled(false);
2150 menuBar.tagDeleteAction.setEnabled(false);
2151 menuBar.tagIconAction.setEnabled(true);
2153 if (selections.size() > 1)
2154 menuBar.tagMergeAction.setEnabled(true);
2156 menuBar.tagMergeAction.setEnabled(false);
2157 listManager.setSelectedTags(selectedTagGUIDs);
2158 listManager.loadNotesIndex();
2159 noteIndexUpdated(false);
2160 refreshEvernoteNote(true);
2161 listManager.refreshCounters = true;
2162 listManager.refreshCounters();
2163 logger.log(logger.HIGH, "Leaving NeverNote.tagTreeSelection");
2165 // trigger the tag index to be refreshed
2166 @SuppressWarnings("unused")
2167 private void tagIndexUpdated() {
2168 tagIndexUpdated(true);
2170 private void tagIndexUpdated(boolean reload) {
2171 logger.log(logger.HIGH, "Entering NeverNote.tagIndexUpdated");
2172 if (selectedTagGUIDs == null)
2173 selectedTagGUIDs = new ArrayList<String>();
2175 listManager.reloadTagIndex();
2177 tagTree.blockSignals(true);
2179 tagTree.setIcons(conn.getTagTable().getAllIcons());
2180 tagTree.load(listManager.getTagIndex());
2183 for (int i=selectedTagGUIDs.size()-1; i>=0; i--) {
2184 boolean found = tagTree.selectGuid(selectedTagGUIDs.get(i));
2186 selectedTagGUIDs.remove(i);
2188 tagTree.blockSignals(false);
2190 browserWindow.setTag(getTagNamesForNote(currentNote));
2191 logger.log(logger.HIGH, "Leaving NeverNote.tagIndexUpdated");
2193 // Show/Hide note information
2194 @SuppressWarnings("unused")
2195 private void toggleTagWindow() {
2196 logger.log(logger.HIGH, "Entering NeverNote.toggleTagWindow");
2197 if (tagTree.isVisible())
2201 menuBar.hideTags.setChecked(tagTree.isVisible());
2202 Global.saveWindowVisible("tagTree", tagTree.isVisible());
2203 logger.log(logger.HIGH, "Leaving NeverNote.toggleTagWindow");
2205 // A note's tags have been updated
2206 @SuppressWarnings("unused")
2207 private void updateNoteTags(String guid, List<String> tags) {
2208 // Save any new tags. We'll need them later.
2209 List<String> newTags = new ArrayList<String>();
2210 for (int i=0; i<tags.size(); i++) {
2211 if (conn.getTagTable().findTagByName(tags.get(i))==null)
2212 newTags.add(tags.get(i));
2215 listManager.saveNoteTags(guid, tags);
2216 listManager.countTagResults(listManager.getNoteIndex());
2217 StringBuffer names = new StringBuffer("");
2218 for (int i=0; i<tags.size(); i++) {
2219 names = names.append(tags.get(i));
2220 if (i<tags.size()-1) {
2221 names.append(Global.tagDelimeter + " ");
2224 browserWindow.setTag(names.toString());
2227 // Now, we need to add any new tags to the tag tree
2228 for (int i=0; i<newTags.size(); i++)
2229 tagTree.insertTag(newTags.get(i), conn.getTagTable().findTagByName(newTags.get(i)));
2231 // Get a string containing all tag names for a note
2232 private String getTagNamesForNote(Note n) {
2233 logger.log(logger.HIGH, "Entering NeverNote.getTagNamesForNote");
2234 if (n==null || n.getGuid() == null || n.getGuid().equals(""))
2236 StringBuffer buffer = new StringBuffer(100);
2237 Vector<String> v = new Vector<String>();
2238 List<String> guids = n.getTagGuids();
2243 for (int i=0; i<guids.size(); i++) {
2244 v.add(listManager.getTagNameByGuid(guids.get(i)));
2246 Comparator<String> comparator = Collections.reverseOrder();
2247 Collections.sort(v,comparator);
2248 Collections.reverse(v);
2250 for (int i = 0; i<v.size(); i++) {
2252 buffer.append(", ");
2253 buffer.append(v.get(i));
2256 logger.log(logger.HIGH, "Leaving NeverNote.getTagNamesForNote");
2257 return buffer.toString();
2259 // Tags were added via dropping notes from the note list
2260 @SuppressWarnings("unused")
2261 private void tagsAdded(String noteGuid, String tagGuid) {
2262 String tagName = null;
2263 for (int i=0; i<listManager.getTagIndex().size(); i++) {
2264 if (listManager.getTagIndex().get(i).getGuid().equals(tagGuid)) {
2265 tagName = listManager.getTagIndex().get(i).getName();
2266 i=listManager.getTagIndex().size();
2269 if (tagName == null)
2272 for (int i=0; i<listManager.getMasterNoteIndex().size(); i++) {
2273 if (listManager.getMasterNoteIndex().get(i).getGuid().equals(noteGuid)) {
2274 List<String> tagNames = new ArrayList<String>();
2275 tagNames.add(new String(tagName));
2276 Note n = listManager.getMasterNoteIndex().get(i);
2277 for (int j=0; j<n.getTagNames().size(); j++) {
2278 tagNames.add(new String(n.getTagNames().get(j)));
2280 listManager.getNoteTableModel().updateNoteTags(noteGuid, n.getTagGuids(), tagNames);
2281 if (n.getGuid().equals(currentNoteGuid)) {
2282 Collections.sort(tagNames);
2283 String display = "";
2284 for (int j=0; j<tagNames.size(); j++) {
2285 display = display+tagNames.get(j);
2286 if (j+2<tagNames.size())
2287 display = display+Global.tagDelimeter+" ";
2289 browserWindow.setTag(display);
2291 i=listManager.getMasterNoteIndex().size();
2296 listManager.getNoteTableModel().updateNoteSyncStatus(noteGuid, false);
2298 private void clearTagFilter() {
2299 tagTree.blockSignals(true);
2300 tagTree.clearSelection();
2301 menuBar.noteRestoreAction.setVisible(false);
2302 menuBar.tagEditAction.setEnabled(false);
2303 menuBar.tagMergeAction.setEnabled(false);
2304 menuBar.tagDeleteAction.setEnabled(false);
2305 menuBar.tagIconAction.setEnabled(false);
2306 selectedTagGUIDs.clear();
2307 listManager.setSelectedTags(selectedTagGUIDs);
2308 tagTree.blockSignals(false);
2310 // Change the icon for a tag
2311 @SuppressWarnings("unused")
2312 private void setTagIcon() {
2313 QTreeWidgetItem currentSelection;
2314 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2315 if (selections.size() == 0)
2318 currentSelection = selections.get(0);
2319 String guid = currentSelection.text(2);
2321 QIcon currentIcon = currentSelection.icon(0);
2322 QIcon icon = conn.getTagTable().getIcon(guid);
2325 dialog = new SetIcon(currentIcon, saveLastPath);
2326 dialog.setUseDefaultIcon(true);
2328 dialog = new SetIcon(icon, saveLastPath);
2329 dialog.setUseDefaultIcon(false);
2332 if (dialog.okPressed()) {
2333 saveLastPath = dialog.getPath();
2334 QIcon newIcon = dialog.getIcon();
2335 conn.getTagTable().setIcon(guid, newIcon, dialog.getFileType());
2336 if (newIcon == null)
2337 newIcon = new QIcon(iconPath+"tag.png");
2338 currentSelection.setIcon(0, newIcon);
2343 @SuppressWarnings("unused")
2344 private void mergeTags() {
2345 List<Tag> tags = new ArrayList<Tag>();
2346 List<QTreeWidgetItem> selections = tagTree.selectedItems();
2347 for (int i=0; i<selections.size(); i++) {
2348 Tag record = new Tag();
2349 record.setGuid(selections.get(i).text(2));
2350 record.setName(selections.get(i).text(0));
2354 TagMerge mergeDialog = new TagMerge(tags);
2356 if (!mergeDialog.okClicked())
2358 String newGuid = mergeDialog.getNewTagGuid();
2360 for (int i=0; i<tags.size(); i++) {
2361 if (!tags.get(i).getGuid().equals(newGuid)) {
2362 List<String> noteGuids = conn.getNoteTable().noteTagsTable.getTagNotes(tags.get(i).getGuid());
2363 for (int j=0; j<noteGuids.size(); j++) {
2364 String noteGuid = noteGuids.get(j);
2365 conn.getNoteTable().noteTagsTable.deleteNoteTag(noteGuid);
2366 if (!conn.getNoteTable().noteTagsTable.checkNoteNoteTags(noteGuid, newGuid))
2367 conn.getNoteTable().noteTagsTable.saveNoteTag(noteGuid, newGuid);
2371 listManager.reloadIndexes();
2374 //***************************************************************
2375 //***************************************************************
2376 //** These functions deal with Saved Search menu items
2377 //***************************************************************
2378 //***************************************************************
2379 // Add a new notebook
2380 @SuppressWarnings("unused")
2381 private void addSavedSearch() {
2382 logger.log(logger.HIGH, "Inside NeverNote.addSavedSearch");
2383 SavedSearchEdit edit = new SavedSearchEdit();
2384 edit.setSearchList(listManager.getSavedSearchIndex());
2387 if (!edit.okPressed())
2390 Calendar currentTime = new GregorianCalendar();
2391 Long l = new Long(currentTime.getTimeInMillis());
2392 String randint = new String(Long.toString(l));
2394 SavedSearch search = new SavedSearch();
2395 search.setUpdateSequenceNum(0);
2396 search.setGuid(randint);
2397 search.setName(edit.getName());
2398 search.setQuery(edit.getQuery());
2399 search.setFormat(QueryFormat.USER);
2400 listManager.getSavedSearchIndex().add(search);
2401 conn.getSavedSearchTable().addSavedSearch(search, true);
2402 savedSearchIndexUpdated();
2403 logger.log(logger.HIGH, "Leaving NeverNote.addSavedSearch");
2405 // Edit an existing tag
2406 @SuppressWarnings("unused")
2407 private void editSavedSearch() {
2408 logger.log(logger.HIGH, "Entering NeverNote.editSavedSearch");
2409 SavedSearchEdit edit = new SavedSearchEdit();
2410 edit.setTitle(tr("Edit Search"));
2411 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2412 QTreeWidgetItem currentSelection;
2413 currentSelection = selections.get(0);
2414 String guid = currentSelection.text(1);
2415 SavedSearch s = conn.getSavedSearchTable().getSavedSearch(guid);
2416 edit.setName(currentSelection.text(0));
2417 edit.setQuery(s.getQuery());
2418 edit.setSearchList(listManager.getSavedSearchIndex());
2421 if (!edit.okPressed())
2424 List<SavedSearch> list = listManager.getSavedSearchIndex();
2425 SavedSearch search = null;
2426 boolean found = false;
2427 for (int i=0; i<list.size(); i++) {
2428 search = list.get(i);
2429 if (search.getGuid().equals(guid)) {
2436 search.setName(edit.getName());
2437 search.setQuery(edit.getQuery());
2438 conn.getSavedSearchTable().updateSavedSearch(search, true);
2439 savedSearchIndexUpdated();
2440 logger.log(logger.HIGH, "Leaving NeverNote.editSavedSearch");
2442 // Delete an existing tag
2443 @SuppressWarnings("unused")
2444 private void deleteSavedSearch() {
2445 logger.log(logger.HIGH, "Entering NeverNote.deleteSavedSearch");
2447 if (QMessageBox.question(this, tr("Confirmation"), tr("Delete the selected search?"),
2448 QMessageBox.StandardButton.Yes,
2449 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
2453 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2454 for (int i=selections.size()-1; i>=0; i--) {
2455 QTreeWidgetItem currentSelection;
2456 currentSelection = selections.get(i);
2457 for (int j=0; j<listManager.getSavedSearchIndex().size(); j++) {
2458 if (listManager.getSavedSearchIndex().get(j).getGuid().equals(currentSelection.text(1))) {
2459 conn.getSavedSearchTable().expungeSavedSearch(listManager.getSavedSearchIndex().get(j).getGuid(), true);
2460 listManager.getSavedSearchIndex().remove(j);
2461 j=listManager.getSavedSearchIndex().size()+1;
2464 selections.remove(i);
2466 savedSearchIndexUpdated();
2467 logger.log(logger.HIGH, "Leaving NeverNote.deleteSavedSearch");
2469 // Setup the tree containing the user's tags
2470 private void initializeSavedSearchTree() {
2471 logger.log(logger.HIGH, "Entering NeverNote.initializeSavedSearchTree");
2472 savedSearchTree.itemSelectionChanged.connect(this, "savedSearchTreeSelection()");
2473 logger.log(logger.HIGH, "Leaving NeverNote.initializeSavedSearchTree");
2475 // Listener when a tag is selected
2476 @SuppressWarnings("unused")
2477 private void savedSearchTreeSelection() {
2478 logger.log(logger.HIGH, "Entering NeverNote.savedSearchTreeSelection");
2480 clearNotebookFilter();
2483 clearAttributeFilter();
2485 String currentGuid = selectedSavedSearchGUID;
2486 menuBar.savedSearchEditAction.setEnabled(true);
2487 menuBar.savedSearchDeleteAction.setEnabled(true);
2488 menuBar.savedSearchIconAction.setEnabled(true);
2489 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2490 QTreeWidgetItem currentSelection;
2491 selectedSavedSearchGUID = "";
2492 for (int i=0; i<selections.size(); i++) {
2493 currentSelection = selections.get(i);
2494 if (currentSelection.text(1).equals(currentGuid)) {
2495 currentSelection.setSelected(false);
2497 selectedSavedSearchGUID = currentSelection.text(1);
2499 // i = selections.size() +1;
2502 // There is the potential for no notebooks to be selected if this
2503 // happens then we make it look like all notebooks were selecetd.
2504 // If that happens, just select the "all notebooks"
2505 if (selections.size()==0) {
2506 clearSavedSearchFilter();
2508 listManager.setSelectedSavedSearch(selectedSavedSearchGUID);
2510 logger.log(logger.HIGH, "Leaving NeverNote.savedSearchTreeSelection");
2512 private void clearSavedSearchFilter() {
2513 menuBar.savedSearchEditAction.setEnabled(false);
2514 menuBar.savedSearchDeleteAction.setEnabled(false);
2515 menuBar.savedSearchIconAction.setEnabled(false);
2516 savedSearchTree.blockSignals(true);
2517 savedSearchTree.clearSelection();
2518 savedSearchTree.blockSignals(false);
2519 selectedSavedSearchGUID = "";
2520 searchField.setEditText("");
2521 searchPerformed = false;
2522 listManager.setSelectedSavedSearch(selectedSavedSearchGUID);
2524 // trigger the tag index to be refreshed
2525 private void savedSearchIndexUpdated() {
2526 if (selectedSavedSearchGUID == null)
2527 selectedSavedSearchGUID = new String();
2528 savedSearchTree.blockSignals(true);
2529 savedSearchTree.setIcons(conn.getSavedSearchTable().getAllIcons());
2530 savedSearchTree.load(listManager.getSavedSearchIndex());
2531 savedSearchTree.selectGuid(selectedSavedSearchGUID);
2532 savedSearchTree.blockSignals(false);
2534 // trigger when the saved search selection changes
2535 @SuppressWarnings("unused")
2536 private void updateSavedSearchSelection() {
2537 logger.log(logger.HIGH, "Entering NeverNote.updateSavedSearchSelection()");
2539 menuBar.savedSearchEditAction.setEnabled(true);
2540 menuBar.savedSearchDeleteAction.setEnabled(true);
2541 menuBar.savedSearchIconAction.setEnabled(true);
2542 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2544 if (selections.size() > 0) {
2545 menuBar.savedSearchEditAction.setEnabled(true);
2546 menuBar.savedSearchDeleteAction.setEnabled(true);
2547 menuBar.savedSearchIconAction.setEnabled(true);
2548 selectedSavedSearchGUID = selections.get(0).text(1);
2549 SavedSearch s = conn.getSavedSearchTable().getSavedSearch(selectedSavedSearchGUID);
2550 searchField.setEditText(s.getQuery());
2552 menuBar.savedSearchEditAction.setEnabled(false);
2553 menuBar.savedSearchDeleteAction.setEnabled(false);
2554 menuBar.savedSearchIconAction.setEnabled(false);
2555 selectedSavedSearchGUID = "";
2556 searchField.setEditText("");
2558 searchFieldChanged();
2560 logger.log(logger.HIGH, "Leaving NeverNote.updateSavedSearchSelection()");
2564 // Show/Hide note information
2565 @SuppressWarnings("unused")
2566 private void toggleSavedSearchWindow() {
2567 logger.log(logger.HIGH, "Entering NeverNote.toggleSavedSearchWindow");
2568 if (savedSearchTree.isVisible())
2569 savedSearchTree.hide();
2571 savedSearchTree.show();
2572 menuBar.hideSavedSearches.setChecked(savedSearchTree.isVisible());
2574 Global.saveWindowVisible("savedSearchTree", savedSearchTree.isVisible());
2575 logger.log(logger.HIGH, "Leaving NeverNote.toggleSavedSearchWindow");
2577 // Change the icon for a saved search
2578 @SuppressWarnings("unused")
2579 private void setSavedSearchIcon() {
2580 QTreeWidgetItem currentSelection;
2581 List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
2582 if (selections.size() == 0)
2585 currentSelection = selections.get(0);
2586 String guid = currentSelection.text(1);
2588 QIcon currentIcon = currentSelection.icon(0);
2589 QIcon icon = conn.getSavedSearchTable().getIcon(guid);
2592 dialog = new SetIcon(currentIcon, saveLastPath);
2593 dialog.setUseDefaultIcon(true);
2595 dialog = new SetIcon(icon, saveLastPath);
2596 dialog.setUseDefaultIcon(false);
2599 if (dialog.okPressed()) {
2600 saveLastPath = dialog.getPath();
2601 QIcon newIcon = dialog.getIcon();
2602 conn.getSavedSearchTable().setIcon(guid, newIcon, dialog.getFileType());
2603 if (newIcon == null)
2604 newIcon = new QIcon(iconPath+"search.png");
2605 currentSelection.setIcon(0, newIcon);
2613 //***************************************************************
2614 //***************************************************************
2615 //** These functions deal with Help menu & tool menu items
2616 //***************************************************************
2617 //***************************************************************
2618 // Show database status
2619 @SuppressWarnings("unused")
2620 private void databaseStatus() {
2622 indexRunner.interrupt = true;
2623 int dirty = conn.getNoteTable().getDirtyCount();
2624 int unindexed = conn.getNoteTable().getUnindexedCount();
2625 DatabaseStatus status = new DatabaseStatus();
2626 status.setUnsynchronized(dirty);
2627 status.setUnindexed(unindexed);
2628 status.setNoteCount(conn.getNoteTable().getNoteCount());
2629 status.setNotebookCount(listManager.getNotebookIndex().size());
2630 status.setUnindexedResourceCount(conn.getNoteTable().noteResourceTable.getUnindexedCount());
2631 status.setSavedSearchCount(listManager.getSavedSearchIndex().size());
2632 status.setTagCount(listManager.getTagIndex().size());
2633 status.setResourceCount(conn.getNoteTable().noteResourceTable.getResourceCount());
2634 status.setWordCount(conn.getWordsTable().getWordCount());
2638 // Compact the database
2639 @SuppressWarnings("unused")
2640 private void compactDatabase() {
2641 logger.log(logger.HIGH, "Entering NeverNote.compactDatabase");
2642 if (QMessageBox.question(this, tr("Confirmation"), tr("This will free unused space in the database, "+
2643 "but please be aware that depending upon the size of your database this can be time consuming " +
2644 "and NeverNote will be unresponsive until it is complete. Do you wish to continue?"),
2645 QMessageBox.StandardButton.Yes,
2646 QMessageBox.StandardButton.No)==StandardButton.No.value() && Global.verifyDelete() == true) {
2649 setMessage("Compacting database.");
2651 listManager.compactDatabase();
2653 setMessage("Database compact is complete.");
2654 logger.log(logger.HIGH, "Leaving NeverNote.compactDatabase");
2656 @SuppressWarnings("unused")
2657 private void accountInformation() {
2658 logger.log(logger.HIGH, "Entering NeverNote.accountInformation");
2659 AccountDialog dialog = new AccountDialog();
2661 logger.log(logger.HIGH, "Leaving NeverNote.accountInformation");
2663 @SuppressWarnings("unused")
2664 private void releaseNotes() {
2665 logger.log(logger.HIGH, "Entering NeverNote.releaseNotes");
2666 QDialog dialog = new QDialog(this);
2667 QHBoxLayout layout = new QHBoxLayout();
2668 QTextEdit textBox = new QTextEdit();
2669 layout.addWidget(textBox);
2670 textBox.setReadOnly(true);
2671 QFile file = new QFile(Global.getFileManager().getHomeDirPath("release.txt"));
2672 if (!file.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly,
2673 QIODevice.OpenModeFlag.Text)))
2675 textBox.setText(file.readAll().toString());
2677 dialog.setWindowTitle(tr("Release Notes"));
2678 dialog.setLayout(layout);
2680 logger.log(logger.HIGH, "Leaving NeverNote.releaseNotes");
2682 // Called when user picks Log from the help menu
2683 @SuppressWarnings("unused")
2684 private void logger() {
2685 logger.log(logger.HIGH, "Entering NeverNote.logger");
2686 LogFileDialog dialog = new LogFileDialog(emitLog);
2688 logger.log(logger.HIGH, "Leaving NeverNote.logger");
2690 // Menu option "help/about" was selected
2691 @SuppressWarnings("unused")
2692 private void about() {
2693 logger.log(logger.HIGH, "Entering NeverNote.about");
2694 QMessageBox.about(this,
2695 tr("About NixNote"),
2696 tr("<h4><center><b>NixNote</b></center></h4><hr><center>Version ")
2698 +tr("<hr></center>Evernote"
2699 +"An Open Source Evernote Client.<br><br>"
2700 +"Licensed under GPL v2. <br><hr><br>"
2701 +"Evernote is copyright 2001-2010 by Evernote Corporation<br>"
2702 +"Jambi and QT are the licensed trademark of Nokia Corporation<br>"
2703 +"PDFRenderer is licened under the LGPL<br>"
2704 +"JTidy is copyrighted under the World Wide Web Consortium<br>"
2705 +"Apache Common Utilities licensed under the Apache License Version 2.0<br>"
2706 +"Jazzy is licened under the LGPL<br>"
2707 +"Java is a registered trademark of Oracle Corporation.<br><hr>"
2708 +"Special thanks to:<br>BitRock InstallBuilder for the Windows installer"
2709 +"<br>CodeCogs (www.codecogs.com) for the LaTeX image rendering."));
2710 logger.log(logger.HIGH, "Leaving NeverNote.about");
2712 // Hide the entire left hand side
2713 @SuppressWarnings("unused")
2714 private void toggleLeftSide() {
2717 hidden = !menuBar.hideLeftSide.isChecked();
2718 menuBar.hideLeftSide.setChecked(!hidden);
2721 leftSplitter1.setHidden(true);
2723 leftSplitter1.setHidden(false);
2725 Global.saveWindowVisible("leftPanel", hidden);
2728 public void checkForUpdates() {
2729 // Send off thread to check for a new version
2730 versionChecker = new QNetworkAccessManager(this);
2731 versionChecker.finished.connect(this, "upgradeFileRead(QNetworkReply)");
2732 QNetworkRequest request = new QNetworkRequest();
2733 request.setUrl(new QUrl(Global.getUpdatesAvailableUrl()));
2734 versionChecker.get(request);
2736 @SuppressWarnings("unused")
2737 private void upgradeFileRead(QNetworkReply reply) {
2738 if (!reply.isReadable())
2741 String winVersion = Global.version;
2742 String osxVersion = Global.version;
2743 String linuxVersion = Global.version;
2744 String linux64Version = Global.version;
2745 String version = Global.version;
2747 // Determine the versions available
2748 QByteArray data = reply.readLine();
2749 while (data != null && !reply.atEnd()) {
2750 String line = data.toString();
2752 if (line.contains(":"))
2753 lineVersion = line.substring(line.indexOf(":")+1).replace(" ", "").replace("\n", "");
2756 if (line.toLowerCase().contains("windows"))
2757 winVersion = lineVersion;
2758 else if (line.toLowerCase().contains("os-x"))
2759 osxVersion = lineVersion;
2760 else if (line.toLowerCase().contains("linux amd64"))
2761 linux64Version = lineVersion;
2762 else if (line.toLowerCase().contains("linux i386"))
2763 linuxVersion = lineVersion;
2764 else if (line.toLowerCase().contains("default"))
2765 version = lineVersion;
2767 // Read the next line
2768 data = reply.readLine();
2771 // Now we need to determine what system we are on.
2772 if (System.getProperty("os.name").toLowerCase().contains("windows"))
2773 version = winVersion;
2774 if (System.getProperty("os.name").toLowerCase().contains("mac os"))
2775 version = osxVersion;
2776 if (System.getProperty("os.name").toLowerCase().contains("Linux")) {
2777 if (System.getProperty("os.arch").contains("amd64") ||
2778 System.getProperty("os.arch").contains("x86_64"))
2779 version = linux64Version;
2781 version = linuxVersion;
2785 for (String validVersion : Global.validVersions) {
2786 if (version.equals(validVersion))
2790 UpgradeAvailableDialog dialog = new UpgradeAvailableDialog();
2792 if (dialog.remindMe())
2793 Global.setCheckVersionUpgrade(true);
2795 Global.setCheckVersionUpgrade(false);
2799 //***************************************************************
2800 //***************************************************************
2801 //** These functions deal with the Toolbar
2802 //***************************************************************
2803 //***************************************************************
2804 @SuppressWarnings("unused")
2805 private void focusSearch() {
2806 searchField.setFocus();
2809 // Text in the search bar has been cleared
2810 private void searchFieldCleared() {
2813 // This is done because we want to force a reload of
2814 // images. Some images we may want to highlight the text.
2815 readOnlyCache.clear();
2816 inkNoteCache.clear();
2818 QWebSettings.setMaximumPagesInCache(0);
2819 QWebSettings.setObjectCacheCapacities(0, 0, 0);
2821 searchField.setEditText("");
2822 saveNoteColumnPositions();
2823 saveNoteIndexWidth();
2824 noteIndexUpdated(true);
2825 if (currentNote == null && listManager.getNoteIndex().size() > 0) {
2826 currentNote = listManager.getNoteIndex().get(0);
2827 currentNoteGuid = currentNote.getGuid();
2829 refreshEvernoteNote(true);
2830 if (currentNote != null)
2831 loadNoteBrowserInformation(browserWindow, currentNoteGuid, currentNote);
2833 // text in the search bar changed. We only use this to tell if it was cleared,
2834 // otherwise we trigger off searchFieldChanged.
2835 @SuppressWarnings("unused")
2836 private void searchFieldTextChanged(String text) {
2837 QWebSettings.setMaximumPagesInCache(0);
2838 QWebSettings.setObjectCacheCapacities(0, 0, 0);
2840 if (text.trim().equals("")) {
2841 searchFieldCleared();
2842 if (searchPerformed) {
2844 // This is done because we want to force a reload of
2845 // images. Some images we may want to highlight the text.
2847 readOnlyCache.clear();
2848 inkNoteCache.clear();
2850 listManager.setEnSearch("");
2851 listManager.loadNotesIndex();
2852 refreshEvernoteNote(true);
2853 noteIndexUpdated(false);
2854 refreshEvernoteNote(true);
2856 searchPerformed = false;
2859 // Text in the toolbar has changed
2860 private void searchFieldChanged() {
2861 logger.log(logger.HIGH, "Entering NeverNote.searchFieldChanged");
2863 readOnlyCache.clear();
2864 inkNoteCache.clear();
2865 saveNoteColumnPositions();
2866 saveNoteIndexWidth();
2867 String text = searchField.currentText();
2868 listManager.setEnSearch(text.trim());
2869 listManager.loadNotesIndex();
2870 noteIndexUpdated(false);
2871 refreshEvernoteNote(true);
2872 searchPerformed = true;
2873 logger.log(logger.HIGH, "Leaving NeverNote.searchFieldChanged");
2876 // Build the window tool bar
2877 private void setupToolBar() {
2878 logger.log(logger.HIGH, "Entering NeverNote.setupToolBar");
2879 toolBar = addToolBar(tr("Tool Bar"));
2880 toolBar.setObjectName("toolBar");
2881 menuBar.setupToolBarVisible();
2882 if (!Global.isWindowVisible("toolBar"))
2883 toolBar.setVisible(false);
2885 toolBar.setVisible(true);
2887 // toolBar.addWidget(menuBar);
2888 // menuBar.setSizePolicy(Policy.Minimum, Policy.Minimum);
2889 // toolBar.addSeparator();
2890 prevButton = toolBar.addAction(tr("Previous"));
2891 QIcon prevIcon = new QIcon(iconPath+"back.png");
2892 prevButton.setIcon(prevIcon);
2893 prevButton.triggered.connect(this, "previousViewedAction()");
2894 togglePrevArrowButton(Global.isToolbarButtonVisible("prevArrow"));
2896 nextButton = toolBar.addAction(tr("Next"));
2897 QIcon nextIcon = new QIcon(iconPath+"forward.png");
2898 nextButton.setIcon(nextIcon);
2899 nextButton.triggered.connect(this, "nextViewedAction()");
2900 toggleNextArrowButton(Global.isToolbarButtonVisible("nextArrow"));
2902 upButton = toolBar.addAction(tr("Up"));
2903 QIcon upIcon = new QIcon(iconPath+"up.png");
2904 upButton.setIcon(upIcon);
2905 upButton.triggered.connect(this, "upAction()");
2906 toggleUpArrowButton(Global.isToolbarButtonVisible("upArrow"));
2909 downButton = toolBar.addAction(tr("Down"));
2910 QIcon downIcon = new QIcon(iconPath+"down.png");
2911 downButton.setIcon(downIcon);
2912 downButton.triggered.connect(this, "downAction()");
2913 toggleDownArrowButton(Global.isToolbarButtonVisible("downArrow"));
2915 synchronizeButton = toolBar.addAction(tr("Synchronize"));
2916 synchronizeButton.setIcon(new QIcon(iconPath+"synchronize.png"));
2917 synchronizeIconAngle = 0;
2918 synchronizeButton.triggered.connect(this, "evernoteSync()");
2919 toggleSynchronizeButton(Global.isToolbarButtonVisible("synchronize"));
2921 printButton = toolBar.addAction(tr("Print"));
2922 QIcon printIcon = new QIcon(iconPath+"print.png");
2923 printButton.setIcon(printIcon);
2924 printButton.triggered.connect(this, "printNote()");
2925 togglePrintButton(Global.isToolbarButtonVisible("print"));
2927 tagButton = toolBar.addAction(tr("Tag"));
2928 QIcon tagIcon = new QIcon(iconPath+"tag.png");
2929 tagButton.setIcon(tagIcon);
2930 tagButton.triggered.connect(browserWindow, "modifyTags()");
2931 toggleTagButton(Global.isToolbarButtonVisible("tag"));
2933 attributeButton = toolBar.addAction(tr("Attributes"));
2934 QIcon attributeIcon = new QIcon(iconPath+"attribute.png");
2935 attributeButton.setIcon(attributeIcon);
2936 attributeButton.triggered.connect(this, "toggleNoteInformation()");
2937 toggleAttributeButton(Global.isToolbarButtonVisible("attribute"));
2939 emailButton = toolBar.addAction(tr("Email"));
2940 QIcon emailIcon = new QIcon(iconPath+"email.png");
2941 emailButton.setIcon(emailIcon);
2942 emailButton.triggered.connect(this, "emailNote()");
2943 toggleEmailButton(Global.isToolbarButtonVisible("email"));
2945 deleteButton = toolBar.addAction(tr("Delete"));
2946 QIcon deleteIcon = new QIcon(iconPath+"delete.png");
2947 deleteButton.setIcon(deleteIcon);
2948 deleteButton.triggered.connect(this, "deleteNote()");
2949 toggleDeleteButton(Global.isToolbarButtonVisible("delete"));
2951 newButton = toolBar.addAction(tr("New"));
2952 QIcon newIcon = new QIcon(iconPath+"new.png");
2953 newButton.triggered.connect(this, "addNote()");
2954 newButton.setIcon(newIcon);
2955 toggleNewButton(Global.isToolbarButtonVisible("new"));
2957 allNotesButton = toolBar.addAction(tr("All Notes"));
2958 QIcon allIcon = new QIcon(iconPath+"books.png");
2959 allNotesButton.triggered.connect(this, "allNotes()");
2960 allNotesButton.setIcon(allIcon);
2961 toggleAllNotesButton(Global.isToolbarButtonVisible("allNotes"));
2963 //toolBar.addSeparator();
2964 //toolBar.addWidget(new QLabel(tr("Quota:")));
2965 //toolBar.addWidget(quotaBar);
2966 //quotaBar.setSizePolicy(Policy.Minimum, Policy.Minimum);
2968 //toolBar.addSeparator();
2970 //toolBar.addWidget(new QLabel(tr("Zoom")));
2971 //toolBar.addWidget(zoomSpinner);
2973 //toolBar.addWidget(new QLabel(" "));
2974 //toolBar.addSeparator();
2975 //toolBar.addWidget(new QLabel(tr(" Search:")));
2976 //toolBar.addWidget(searchField);
2977 QSizePolicy sizePolicy = new QSizePolicy();
2978 sizePolicy.setHorizontalPolicy(Policy.MinimumExpanding);
2979 QLabel spacer = new QLabel("");
2980 spacer.setSizePolicy(sizePolicy);
2981 toolBar.addWidget(spacer);
2982 //searchField.setInsertPolicy(InsertPolicy.InsertAtTop);
2984 //searchClearButton = toolBar.addAction("Search Clear");
2985 //QIcon searchClearIcon = new QIcon(iconPath+"searchclear.png");
2986 //searchClearButton.setIcon(searchClearIcon);
2987 //searchClearButton.triggered.connect(this, "searchFieldCleared()");
2988 //toggleSearchClearButton(Global.isToolbarButtonVisible("searchClear"));
2990 logger.log(logger.HIGH, "Leaving NeverNote.setupToolBar");
2992 // Update the sychronize button picture
2994 public QMenu createPopupMenu() {
2995 QMenu contextMenu = super.createPopupMenu();
2997 contextMenu.addSeparator();
2998 QAction prevAction = addContextAction("prevArrow", tr("Previous Arrow"));
2999 contextMenu.addAction(prevAction);
3000 prevAction.triggered.connect(this, "togglePrevArrowButton(Boolean)");
3002 QAction nextAction = addContextAction("nextArrow", tr("Next Arrow"));
3003 contextMenu.addAction(nextAction);
3004 nextAction.triggered.connect(this, "toggleNextArrowButton(Boolean)");
3006 QAction upAction = addContextAction("upArrow", tr("Up Arrow"));
3007 contextMenu.addAction(upAction);
3008 upAction.triggered.connect(this, "toggleUpArrowButton(Boolean)");
3010 QAction downAction = addContextAction("downArrow", tr("Down Arrow"));
3011 contextMenu.addAction(downAction);
3012 downAction.triggered.connect(this, "toggleDownArrowButton(Boolean)");
3014 QAction synchronizeAction = addContextAction("synchronize", tr("Synchronize"));
3015 contextMenu.addAction(synchronizeAction);
3016 synchronizeAction.triggered.connect(this, "toggleSynchronizeButton(Boolean)");
3018 QAction printAction = addContextAction("print", tr("Print"));
3019 contextMenu.addAction(printAction);
3020 printAction.triggered.connect(this, "togglePrintButton(Boolean)");
3022 QAction tagAction = addContextAction("tag", tr("Tag"));
3023 contextMenu.addAction(tagAction);
3024 tagAction.triggered.connect(this, "toggleTagButton(Boolean)");
3026 QAction attributeAction = addContextAction("attribute", tr("Attribute"));
3027 contextMenu.addAction(attributeAction);
3028 attributeAction.triggered.connect(this, "toggleAttributeButton(Boolean)");
3030 QAction emailAction = addContextAction("email", tr("Email"));
3031 contextMenu.addAction(emailAction);
3032 emailAction.triggered.connect(this, "toggleEmailButton(Boolean)");
3034 QAction deleteAction = addContextAction("delete", tr("Delete"));
3035 contextMenu.addAction(deleteAction);
3036 deleteAction.triggered.connect(this, "toggleDeleteButton(Boolean)");
3038 QAction newAction = addContextAction("new", tr("Add"));
3039 contextMenu.addAction(newAction);
3040 newAction.triggered.connect(this, "toggleNewButton(Boolean)");
3042 QAction allNotesAction = addContextAction("allNotes", tr("All Notes"));
3043 contextMenu.addAction(allNotesAction);
3044 allNotesAction.triggered.connect(this, "toggleAllNotesButton(Boolean)");
3046 QAction searchClearAction = addContextAction("searchClear", tr("Search Clear"));
3047 contextMenu.addAction(searchClearAction);
3048 searchClearAction.triggered.connect(this, "toggleSearchClearButton(Boolean)");
3053 private QAction addContextAction(String config, String name) {
3054 QAction newAction = new QAction(this);
3055 newAction.setText(name);
3056 newAction.setCheckable(true);
3057 newAction.setChecked(Global.isToolbarButtonVisible(config));
3060 private void togglePrevArrowButton(Boolean toggle) {
3061 prevButton.setVisible(toggle);
3062 Global.saveToolbarButtonsVisible("prevArrow", toggle);
3064 private void toggleNextArrowButton(Boolean toggle) {
3065 nextButton.setVisible(toggle);
3066 Global.saveToolbarButtonsVisible("nextArrow", toggle);
3068 private void toggleUpArrowButton(Boolean toggle) {
3069 upButton.setVisible(toggle);
3070 Global.saveToolbarButtonsVisible("upArrow", toggle);
3072 private void toggleDownArrowButton(Boolean toggle) {
3073 downButton.setVisible(toggle);
3074 Global.saveToolbarButtonsVisible("downArrow", toggle);
3076 private void toggleSynchronizeButton(Boolean toggle) {
3077 synchronizeButton.setVisible(toggle);
3078 Global.saveToolbarButtonsVisible("synchronize", toggle);
3080 private void togglePrintButton(Boolean toggle) {
3081 printButton.setVisible(toggle);
3082 Global.saveToolbarButtonsVisible("print", toggle);
3084 private void toggleTagButton(Boolean toggle) {
3085 tagButton.setVisible(toggle);
3086 Global.saveToolbarButtonsVisible("tag", toggle);
3088 private void toggleAttributeButton(Boolean toggle) {
3089 attributeButton.setVisible(toggle);
3090 Global.saveToolbarButtonsVisible("attribute", toggle);
3092 private void toggleEmailButton(Boolean toggle) {
3093 emailButton.setVisible(toggle);
3094 Global.saveToolbarButtonsVisible("email", toggle);
3096 private void toggleDeleteButton(Boolean toggle) {
3097 deleteButton.setVisible(toggle);
3098 Global.saveToolbarButtonsVisible("delete", toggle);
3100 private void toggleNewButton(Boolean toggle) {
3101 newButton.setVisible(toggle);
3102 Global.saveToolbarButtonsVisible("new", toggle);
3104 private void toggleAllNotesButton(Boolean toggle) {
3105 allNotesButton.setVisible(toggle);
3106 Global.saveToolbarButtonsVisible("allNotes", toggle);
3108 @SuppressWarnings("unused")
3109 private void toggleSearchClearButton(Boolean toggle) {
3110 searchClearButton.setVisible(toggle);
3111 Global.saveToolbarButtonsVisible("searchClear", toggle);
3118 @SuppressWarnings("unused")
3119 private void updateSyncButton() {
3121 if (syncIcons == null) {
3122 syncIcons = new ArrayList<QPixmap>();
3124 synchronizeIconAngle = 0;
3125 QPixmap pix = new QPixmap(iconPath+"synchronize.png");
3127 for (int i=0; i<=360; i++) {
3128 QPixmap rotatedPix = new QPixmap(pix.size());
3129 QPainter p = new QPainter(rotatedPix);
3130 rotatedPix.fill(toolBar.palette().color(ColorRole.Button));
3131 QSize size = pix.size();
3132 p.translate(size.width()/2, size.height()/2);
3135 p.setBackgroundMode(BGMode.OpaqueMode);
3136 p.translate(-size.width()/2, -size.height()/2);
3137 p.drawPixmap(0,0, pix);
3139 syncIcons.add(rotatedPix);
3143 synchronizeIconAngle++;
3144 if (synchronizeIconAngle > 359)
3145 synchronizeIconAngle=0;
3146 synchronizeButton.setIcon(syncIcons.get(synchronizeIconAngle));
3149 // Synchronize with Evernote
3151 private void evernoteSync() {
3152 logger.log(logger.HIGH, "Entering NeverNote.evernoteSync");
3153 if (!Global.isConnected)
3155 if (Global.isConnected)
3156 synchronizeAnimationTimer.start(5);
3157 // synchronizeAnimationTimer.start(200);
3159 logger.log(logger.HIGH, "Leaving NeverNote.evernoteSync");
3161 private void updateQuotaBar() {
3162 long limit = Global.getUploadLimit();
3163 long amount = Global.getUploadAmount();
3164 if (amount>0 && limit>0) {
3165 int percent =(int)(amount*100/limit);
3166 quotaBar.setValue(percent);
3168 quotaBar.setValue(0);
3171 @SuppressWarnings("unused")
3172 private void zoomChanged() {
3173 browserWindow.getBrowser().setZoomFactor(new Double(zoomSpinner.value())/100);
3176 //****************************************************************
3177 //****************************************************************
3178 //* System Tray functions
3179 //****************************************************************
3180 //****************************************************************
3181 private void trayToggleVisible() {
3186 if (windowMaximized)
3193 @SuppressWarnings("unused")
3194 private void trayActivated(QSystemTrayIcon.ActivationReason reason) {
3195 if (reason == QSystemTrayIcon.ActivationReason.DoubleClick) {
3196 String name = QSystemTrayIcon.MessageIcon.resolve(reason.value()).name();
3197 trayToggleVisible();
3202 //***************************************************************
3203 //***************************************************************
3204 //** These functions deal with the trash tree
3205 //***************************************************************
3206 //***************************************************************
3207 // Setup the tree containing the trash.
3208 @SuppressWarnings("unused")
3209 private void trashTreeSelection() {
3210 logger.log(logger.HIGH, "Entering NeverNote.trashTreeSelection");
3212 clearNotebookFilter();
3214 clearAttributeFilter();
3215 clearSavedSearchFilter();
3217 String tempGuid = currentNoteGuid;
3219 // currentNoteGuid = "";
3220 currentNote = new Note();
3221 selectedNoteGUIDs.clear();
3222 listManager.getSelectedNotebooks().clear();
3223 listManager.getSelectedTags().clear();
3224 listManager.setSelectedSavedSearch("");
3225 browserWindow.clear();
3227 // toggle the add buttons
3228 newButton.setEnabled(!newButton.isEnabled());
3229 menuBar.noteAdd.setEnabled(newButton.isEnabled());
3230 menuBar.noteAdd.setVisible(true);
3232 List<QTreeWidgetItem> selections = trashTree.selectedItems();
3233 if (selections.size() == 0) {
3234 currentNoteGuid = trashNoteGuid;
3235 trashNoteGuid = tempGuid;
3236 Global.showDeleted = false;
3237 menuBar.noteRestoreAction.setEnabled(false);
3238 menuBar.noteRestoreAction.setVisible(false);
3241 currentNoteGuid = trashNoteGuid;
3242 trashNoteGuid = tempGuid;
3243 menuBar.noteRestoreAction.setEnabled(true);
3244 menuBar.noteRestoreAction.setVisible(true);
3245 Global.showDeleted = true;
3247 listManager.loadNotesIndex();
3248 noteIndexUpdated(false);
3249 //// browserWindow.setEnabled(newButton.isEnabled());
3250 browserWindow.setReadOnly(!newButton.isEnabled());
3251 logger.log(logger.HIGH, "Leaving NeverNote.trashTreeSelection");
3253 // Empty the trash file
3254 @SuppressWarnings("unused")
3255 private void emptyTrash() {
3256 // browserWindow.clear();
3257 logger.log(logger.EXTREME, "Emptying Trash");
3258 listManager.emptyTrash();
3259 logger.log(logger.EXTREME, "Resetting view after trash empty");
3260 if (trashTree.selectedItems().size() > 0) {
3261 listManager.getSelectedNotebooks().clear();
3262 listManager.getSelectedTags().clear();
3263 listManager.setSelectedSavedSearch("");
3264 newButton.setEnabled(!newButton.isEnabled());
3265 menuBar.noteAdd.setEnabled(newButton.isEnabled());
3266 menuBar.noteAdd.setVisible(true);
3267 browserWindow.clear();
3270 clearNotebookFilter();
3271 clearSavedSearchFilter();
3272 clearAttributeFilter();
3274 Global.showDeleted = false;
3275 menuBar.noteRestoreAction.setEnabled(false);
3276 menuBar.noteRestoreAction.setVisible(false);
3278 listManager.loadNotesIndex();
3279 noteIndexUpdated(false);
3282 // Show/Hide trash window
3283 @SuppressWarnings("unused")
3284 private void toggleTrashWindow() {
3285 logger.log(logger.HIGH, "Entering NeverNote.toggleTrashWindow");
3286 if (trashTree.isVisible())
3290 menuBar.hideTrash.setChecked(trashTree.isVisible());
3292 Global.saveWindowVisible("trashTree", trashTree.isVisible());
3293 logger.log(logger.HIGH, "Leaving NeverNote.trashWindow");
3295 private void clearTrashFilter() {
3296 Global.showDeleted = false;
3297 newButton.setEnabled(true);
3298 menuBar.noteAdd.setEnabled(true);
3299 menuBar.noteAdd.setVisible(true);
3300 trashTree.blockSignals(true);
3301 trashTree.clearSelection();
3302 trashTree.blockSignals(false);
3307 //***************************************************************
3308 //***************************************************************
3309 //** These functions deal with connection settings
3310 //***************************************************************
3311 //***************************************************************
3312 // SyncRunner had a problem and things are disconnected
3313 @SuppressWarnings("unused")
3314 private void remoteErrorDisconnect() {
3315 menuBar.connectAction.setText(tr("Connect"));
3316 menuBar.connectAction.setToolTip(tr("Connect to Evernote"));
3317 menuBar.synchronizeAction.setEnabled(false);
3318 Global.isConnected = false;
3319 synchronizeAnimationTimer.stop();
3322 // Do a manual connect/disconnect
3323 private void remoteConnect() {
3324 logger.log(logger.HIGH, "Entering NeverNote.remoteConnect");
3326 if (Global.isConnected) {
3327 Global.isConnected = false;
3328 syncRunner.enDisconnect();
3329 setupConnectMenuOptions();
3334 AESEncrypter aes = new AESEncrypter();
3336 aes.decrypt(new FileInputStream(Global.getFileManager().getHomeDirFile("secure.txt")));
3337 } catch (FileNotFoundException e) {
3338 // File not found, so we'll just get empty strings anyway.
3341 if (Global.getProxyValue("url").equals("")) {
3342 System.setProperty("http.proxyHost","") ;
3343 System.setProperty("http.proxyPort", "") ;
3344 System.setProperty("https.proxyHost","") ;
3345 System.setProperty("https.proxyPort", "") ;
3348 System.setProperty("http.proxyHost",Global.getProxyValue("url")) ;
3349 System.setProperty("http.proxyPort", Global.getProxyValue("port")) ;
3350 System.setProperty("https.proxyHost",Global.getProxyValue("url")) ;
3351 System.setProperty("https.proxyPort", Global.getProxyValue("port")) ;
3353 if (Global.getProxyValue("userid").equals("")) {
3354 Authenticator.setDefault(new Authenticator() {
3356 protected PasswordAuthentication getPasswordAuthentication() {
3358 PasswordAuthentication(Global.getProxyValue("userid"),Global.getProxyValue("password").toCharArray());
3364 syncRunner.userStoreUrl = Global.userStoreUrl;
3365 syncRunner.noteStoreUrl = Global.noteStoreUrl;
3366 syncRunner.noteStoreUrlBase = Global.noteStoreUrlBase;
3368 String userid = aes.getUserid();
3369 String password = aes.getPassword();
3370 if (!userid.equals("") && !password.equals("")) {
3371 Global.username = userid;
3372 Global.password = password;
3373 syncRunner.username = Global.username;
3374 syncRunner.password = Global.password;
3375 syncRunner.enConnect();
3378 Global.isConnected = syncRunner.isConnected;
3380 if (!Global.isConnected) {
3381 // Show the login dialog box
3382 if (!Global.automaticLogin() || userid.equals("")|| password.equals("")) {
3383 LoginDialog login = new LoginDialog();
3386 if (!login.okPressed()) {
3390 Global.username = login.getUserid();
3391 Global.password = login.getPassword();
3393 syncRunner.username = Global.username;
3394 syncRunner.password = Global.password;
3395 syncRunner.enConnect();
3396 Global.isConnected = syncRunner.isConnected;
3399 if (!Global.isConnected)
3402 setupConnectMenuOptions();
3403 logger.log(logger.HIGH, "Leaving NeverNote.remoteConnect");
3405 private void setupConnectMenuOptions() {
3406 logger.log(logger.HIGH, "entering NeverNote.setupConnectMenuOptions");
3407 if (!Global.isConnected) {
3408 menuBar.connectAction.setText(tr("Connect"));
3409 menuBar.connectAction.setToolTip(tr("Connect to Evernote"));
3410 menuBar.synchronizeAction.setEnabled(false);
3412 menuBar.connectAction.setText(tr("Disconnect"));
3413 menuBar.connectAction.setToolTip(tr("Disconnect from Evernote"));
3414 menuBar.synchronizeAction.setEnabled(true);
3416 logger.log(logger.HIGH, "Leaving NeverNote.setupConnectionMenuOptions");
3421 //***************************************************************
3422 //***************************************************************
3423 //** These functions deal with the GUI Attribute tree
3424 //***************************************************************
3425 //***************************************************************
3426 @SuppressWarnings("unused")
3427 private void attributeTreeClicked(QTreeWidgetItem item, Integer integer) {
3429 // clearTagFilter();
3430 // clearNotebookFilter();
3432 // clearSavedSearchFilter();
3434 if (attributeTreeSelected == null || item.nativeId() != attributeTreeSelected.nativeId()) {
3435 if (item.childCount() > 0) {
3436 item.setSelected(false);
3438 Global.createdBeforeFilter.reset();
3439 Global.createdSinceFilter.reset();
3440 Global.changedBeforeFilter.reset();
3441 Global.changedSinceFilter.reset();
3442 Global.containsFilter.reset();
3443 attributeTreeSelected = item;
3444 DateAttributeFilterTable f = null;
3445 f = findDateAttributeFilterTable(item.parent());
3447 f.select(item.parent().indexOfChild(item));
3449 Global.containsFilter.select(item.parent().indexOfChild(item));
3452 listManager.loadNotesIndex();
3453 noteIndexUpdated(false);
3456 attributeTreeSelected = null;
3457 item.setSelected(false);
3458 Global.createdBeforeFilter.reset();
3459 Global.createdSinceFilter.reset();
3460 Global.changedBeforeFilter.reset();
3461 Global.changedSinceFilter.reset();
3462 Global.containsFilter.reset();
3463 listManager.loadNotesIndex();
3464 noteIndexUpdated(false);
3466 // This determines what attribute filter we need, depending upon the selection
3467 private DateAttributeFilterTable findDateAttributeFilterTable(QTreeWidgetItem w) {
3468 if (w.parent() != null && w.childCount() > 0) {
3469 QTreeWidgetItem parent = w.parent();
3470 if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Created &&
3471 w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Since)
3472 return Global.createdSinceFilter;
3473 if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Created &&
3474 w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Before)
3475 return Global.createdBeforeFilter;
3476 if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.LastModified &&
3477 w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Since)
3478 return Global.changedSinceFilter;
3479 if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.LastModified &&
3480 w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Before)
3481 return Global.changedBeforeFilter;
3486 // Show/Hide attribute search window
3487 @SuppressWarnings("unused")
3488 private void toggleAttributesWindow() {
3489 logger.log(logger.HIGH, "Entering NeverNote.toggleAttributesWindow");
3490 if (attributeTree.isVisible())
3491 attributeTree.hide();
3493 attributeTree.show();
3494 menuBar.hideAttributes.setChecked(attributeTree.isVisible());
3496 Global.saveWindowVisible("attributeTree", attributeTree.isVisible());
3497 logger.log(logger.HIGH, "Leaving NeverNote.toggleAttributeWindow");
3499 private void clearAttributeFilter() {
3500 Global.createdBeforeFilter.reset();
3501 Global.createdSinceFilter.reset();
3502 Global.changedBeforeFilter.reset();
3503 Global.changedSinceFilter.reset();
3504 Global.containsFilter.reset();
3505 attributeTreeSelected = null;
3506 attributeTree.blockSignals(true);
3507 attributeTree.clearSelection();
3508 attributeTree.blockSignals(false);
3512 //***************************************************************
3513 //***************************************************************
3514 //** These functions deal with the GUI Note index table
3515 //***************************************************************
3516 //***************************************************************
3517 // Initialize the note list table
3518 private void initializeNoteTable() {
3519 logger.log(logger.HIGH, "Entering NeverNote.initializeNoteTable");
3520 noteTableView.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection);
3521 noteTableView.selectionModel().selectionChanged.connect(this, "noteTableSelection()");
3522 logger.log(logger.HIGH, "Leaving NeverNote.initializeNoteTable");
3524 // Show/Hide trash window
3525 @SuppressWarnings("unused")
3526 private void toggleNoteListWindow() {
3527 logger.log(logger.HIGH, "Entering NeverNote.toggleNoteListWindow");
3528 if (noteTableView.isVisible())
3529 noteTableView.hide();
3531 noteTableView.show();
3532 menuBar.hideNoteList.setChecked(noteTableView.isVisible());
3534 Global.saveWindowVisible("noteList", noteTableView.isVisible());
3535 logger.log(logger.HIGH, "Leaving NeverNote.toggleNoteListWindow");
3537 // Handle the event that a user selects a note from the table
3538 @SuppressWarnings("unused")
3539 private void noteTableSelection() {
3540 logger.log(logger.HIGH, "Entering NeverNote.noteTableSelection");
3544 // If the ctrl key is pressed, then they are selecting multiple
3545 // entries and we don't want to change the currently viewed note.
3546 if (QApplication.keyboardModifiers().isSet(KeyboardModifier.ControlModifier) &&
3547 QApplication.mouseButtons().isSet(MouseButton.LeftButton))
3550 if (historyGuids.size() == 0) {
3551 historyGuids.add(currentNoteGuid);
3552 historyPosition = 1;
3554 noteTableView.showColumn(Global.noteTableGuidPosition);
3556 List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
3557 if (!Global.isColumnVisible("guid"))
3558 noteTableView.hideColumn(Global.noteTableGuidPosition);
3560 if (selections.size() > 0) {
3562 menuBar.noteDuplicateAction.setEnabled(true);
3563 menuBar.noteOnlineHistoryAction.setEnabled(true);
3564 menuBar.noteMergeAction.setEnabled(true);
3565 selectedNoteGUIDs.clear();
3566 if (selections.size() != 1 || Global.showDeleted) {
3567 menuBar.noteDuplicateAction.setEnabled(false);
3569 if (selections.size() != 1 || !Global.isConnected) {
3570 menuBar.noteOnlineHistoryAction.setEnabled(false);
3572 if (selections.size() == 1) {
3573 menuBar.noteMergeAction.setEnabled(false);
3575 for (int i=0; i<selections.size(); i++) {
3576 int row = selections.get(i).row();
3578 upButton.setEnabled(false);
3580 upButton.setEnabled(true);
3581 if (row < listManager.getNoteTableModel().rowCount()-1)
3582 downButton.setEnabled(true);
3584 downButton.setEnabled(false);
3585 index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition);
3586 SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
3587 currentNoteGuid = (String)ix.values().toArray()[0];
3588 selectedNoteGUIDs.add(currentNoteGuid);
3592 nextButton.setEnabled(true);
3593 prevButton.setEnabled(true);
3595 int endPosition = historyGuids.size()-1;
3596 for (int j=historyPosition; j<=endPosition; j++) {
3597 historyGuids.remove(historyGuids.size()-1);
3599 historyGuids.add(currentNoteGuid);
3600 historyPosition = historyGuids.size();
3602 if (historyPosition <= 1)
3603 prevButton.setEnabled(false);
3604 if (historyPosition == historyGuids.size())
3605 nextButton.setEnabled(false);
3607 fromHistory = false;
3608 scrollToGuid(currentNoteGuid);
3609 refreshEvernoteNote(true);
3610 logger.log(logger.HIGH, "Leaving NeverNote.noteTableSelection");
3612 // Trigger a refresh when the note db has been updated
3613 private void noteIndexUpdated(boolean reload) {
3614 logger.log(logger.HIGH, "Entering NeverNote.noteIndexUpdated");
3616 refreshEvernoteNoteList();
3617 logger.log(logger.HIGH, "Calling note table reload in NeverNote.noteIndexUpdated() - "+reload);
3618 noteTableView.load(reload);
3619 if (currentNoteGuid == null || currentNoteGuid.equals("")) {
3621 if (noteTableView.proxyModel.sortOrder() == SortOrder.AscendingOrder)
3622 pos = noteTableView.proxyModel.rowCount();
3625 if (noteTableView.proxyModel.rowCount() == 0)
3628 QModelIndex i = noteTableView.proxyModel.index(pos-1, Global.noteTableGuidPosition);
3630 currentNoteGuid = (String)i.data();
3634 if (!noteTableView.isColumnHidden(Global.noteTableGuidPosition))
3636 scrollToGuid(currentNoteGuid);
3637 logger.log(logger.HIGH, "Leaving NeverNote.noteIndexUpdated");
3639 // Called when the list of notes is updated
3640 private void refreshEvernoteNoteList() {
3641 logger.log(logger.HIGH, "Entering NeverNote.refreshEvernoteNoteList");
3642 browserWindow.setDisabled(false);
3643 if (selectedNoteGUIDs == null)
3644 selectedNoteGUIDs = new ArrayList<String>();
3645 selectedNoteGUIDs.clear(); // clear out old entries
3647 String saveCurrentNoteGuid = new String();
3648 String tempNoteGuid = new String();
3650 historyGuids.clear();
3651 historyPosition = 0;
3652 prevButton.setEnabled(false);
3653 nextButton.setEnabled(false);
3655 if (currentNoteGuid == null)
3656 currentNoteGuid = new String();
3658 //determine current note guid
3659 for (Note note : listManager.getNoteIndex()) {
3660 tempNoteGuid = note.getGuid();
3661 if (currentNoteGuid.equals(tempNoteGuid)) {
3662 saveCurrentNoteGuid = tempNoteGuid;
3666 if (listManager.getNoteIndex().size() == 0) {
3667 currentNoteGuid = "";
3669 browserWindow.clear();
3670 browserWindow.setDisabled(true);
3673 if (!saveCurrentNoteGuid.equals("")) {
3674 refreshEvernoteNote(false);
3676 currentNoteGuid = "";
3678 reloadTagTree(false);
3680 logger.log(logger.HIGH, "Leaving NeverNote.refreshEvernoteNoteList");
3682 // Called when the previous arrow button is clicked
3683 @SuppressWarnings("unused")
3684 private void previousViewedAction() {
3685 if (!prevButton.isEnabled())
3687 if (historyPosition == 0)
3690 if (historyPosition <= 0)
3692 String historyGuid = historyGuids.get(historyPosition-1);
3694 for (int i=0; i<noteTableView.model().rowCount(); i++) {
3695 QModelIndex modelIndex = noteTableView.model().index(i, Global.noteTableGuidPosition);
3696 if (modelIndex != null) {
3697 SortedMap<Integer, Object> ix = noteTableView.model().itemData(modelIndex);
3698 String tableGuid = (String)ix.values().toArray()[0];
3699 if (tableGuid.equals(historyGuid)) {
3700 noteTableView.selectRow(i);
3706 @SuppressWarnings("unused")
3707 private void nextViewedAction() {
3708 if (!nextButton.isEnabled())
3710 String historyGuid = historyGuids.get(historyPosition);
3713 for (int i=0; i<noteTableView.model().rowCount(); i++) {
3714 QModelIndex modelIndex = noteTableView.model().index(i, Global.noteTableGuidPosition);
3715 if (modelIndex != null) {
3716 SortedMap<Integer, Object> ix = noteTableView.model().itemData(modelIndex);
3717 String tableGuid = (String)ix.values().toArray()[0];
3718 if (tableGuid.equals(historyGuid)) {
3719 noteTableView.selectRow(i);
3725 // Called when the up arrow is clicked
3726 @SuppressWarnings("unused")
3727 private void upAction() {
3728 List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
3729 int row = selections.get(0).row();
3731 noteTableView.selectRow(row-1);
3734 // Called when the down arrow is clicked
3735 @SuppressWarnings("unused")
3736 private void downAction() {
3737 List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
3738 int row = selections.get(0).row();
3739 int max = listManager.getNoteTableModel().rowCount();
3741 noteTableView.selectRow(row+1);
3744 // Update a tag string for a specific note in the list
3745 @SuppressWarnings("unused")
3746 private void updateListTags(String guid, List<String> tags) {
3747 logger.log(logger.HIGH, "Entering NeverNote.updateListTags");
3748 StringBuffer tagBuffer = new StringBuffer();
3749 for (int i=0; i<tags.size(); i++) {
3750 tagBuffer.append(tags.get(i));
3751 if (i<tags.size()-1)
3752 tagBuffer.append(", ");
3755 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3756 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3757 if (modelIndex != null) {
3758 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3759 String tableGuid = (String)ix.values().toArray()[0];
3760 if (tableGuid.equals(guid)) {
3761 listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition,tagBuffer.toString());
3762 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
3763 noteTableView.proxyModel.invalidate();
3768 logger.log(logger.HIGH, "Leaving NeverNote.updateListTags");
3770 // Update a title for a specific note in the list
3771 @SuppressWarnings("unused")
3772 private void updateListAuthor(String guid, String author) {
3773 logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
3775 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3776 //QModelIndex modelIndex = noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
3777 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3778 if (modelIndex != null) {
3779 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3780 String tableGuid = (String)ix.values().toArray()[0];
3781 if (tableGuid.equals(guid)) {
3782 listManager.getNoteTableModel().setData(i, Global.noteTableAuthorPosition,author);
3783 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
3784 noteTableView.proxyModel.invalidate();
3790 logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
3792 private void updateListNoteNotebook(String guid, String notebook) {
3793 logger.log(logger.HIGH, "Entering NeverNote.updateListNoteNotebook");
3794 listManager.getNoteTableModel().updateNoteSyncStatus(guid, false);
3795 logger.log(logger.HIGH, "Leaving NeverNote.updateListNoteNotebook");
3797 // Update a title for a specific note in the list
3798 @SuppressWarnings("unused")
3799 private void updateListSourceUrl(String guid, String url) {
3800 logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
3802 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3803 //QModelIndex modelIndex = noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
3804 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3805 if (modelIndex != null) {
3806 // SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(modelIndex);
3807 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3808 String tableGuid = (String)ix.values().toArray()[0];
3809 if (tableGuid.equals(guid)) {
3810 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
3811 listManager.getNoteTableModel().setData(i, Global.noteTableSourceUrlPosition,url);
3812 noteTableView.proxyModel.invalidate();
3817 logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
3819 @SuppressWarnings("unused")
3820 private void updateListGuid(String oldGuid, String newGuid) {
3821 logger.log(logger.HIGH, "Entering NeverNote.updateListTitle");
3823 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3824 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3825 if (modelIndex != null) {
3826 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3827 String tableGuid = (String)ix.values().toArray()[0];
3828 if (tableGuid.equals(oldGuid)) {
3829 listManager.getNoteTableModel().setData(i, Global.noteTableGuidPosition,newGuid);
3830 //listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
3835 logger.log(logger.HIGH, "Leaving NeverNote.updateListTitle");
3837 private void updateListTagName(String guid) {
3838 logger.log(logger.HIGH, "Entering NeverNote.updateTagName");
3840 for (int j=0; j<listManager.getNoteIndex().size(); j++) {
3841 if (listManager.getNoteIndex().get(j).getTagGuids().contains(guid)) {
3842 String newName = listManager.getTagNamesForNote(listManager.getNoteIndex().get(j));
3844 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3845 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3846 if (modelIndex != null) {
3847 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3848 String noteGuid = (String)ix.values().toArray()[0];
3849 if (noteGuid.equalsIgnoreCase(listManager.getNoteIndex().get(j).getGuid())) {
3850 listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition, newName);
3851 i=listManager.getNoteTableModel().rowCount();
3857 logger.log(logger.HIGH, "Leaving NeverNote.updateListNotebook");
3859 private void removeListTagName(String guid) {
3860 logger.log(logger.HIGH, "Entering NeverNote.updateTagName");
3862 for (int j=0; j<listManager.getNoteIndex().size(); j++) {
3863 if (listManager.getNoteIndex().get(j).getTagGuids().contains(guid)) {
3864 for (int i=listManager.getNoteIndex().get(j).getTagGuids().size()-1; i>=0; i--) {
3865 if (listManager.getNoteIndex().get(j).getTagGuids().get(i).equals(guid))
3866 listManager.getNoteIndex().get(j).getTagGuids().remove(i);
3869 String newName = listManager.getTagNamesForNote(listManager.getNoteIndex().get(j));
3870 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3871 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3872 if (modelIndex != null) {
3873 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3874 String noteGuid = (String)ix.values().toArray()[0];
3875 if (noteGuid.equalsIgnoreCase(listManager.getNoteIndex().get(j).getGuid())) {
3876 listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition, newName);
3877 i=listManager.getNoteTableModel().rowCount();
3883 logger.log(logger.HIGH, "Leaving NeverNote.updateListNotebook");
3885 private void updateListNotebookName(String oldName, String newName) {
3886 logger.log(logger.HIGH, "Entering NeverNote.updateListNotebookName");
3888 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3889 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableNotebookPosition);
3890 if (modelIndex != null) {
3891 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3892 String tableName = (String)ix.values().toArray()[0];
3893 if (tableName.equalsIgnoreCase(oldName)) {
3894 listManager.getNoteTableModel().setData(i, Global.noteTableNotebookPosition, newName);
3898 logger.log(logger.HIGH, "Leaving NeverNote.updateListNotebookName");
3900 @SuppressWarnings("unused")
3901 private void updateListDateCreated(String guid, QDateTime date) {
3902 logger.log(logger.HIGH, "Entering NeverNote.updateListDateCreated");
3904 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3905 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3906 if (modelIndex != null) {
3907 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3908 String tableGuid = (String)ix.values().toArray()[0];
3909 if (tableGuid.equals(guid)) {
3910 listManager.getNoteTableModel().setData(i, Global.noteTableCreationPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
3911 noteTableView.proxyModel.invalidate();
3916 logger.log(logger.HIGH, "Leaving NeverNote.updateListDateCreated");
3918 @SuppressWarnings("unused")
3919 private void updateListDateSubject(String guid, QDateTime date) {
3920 logger.log(logger.HIGH, "Entering NeverNote.updateListDateSubject");
3922 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3923 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3924 if (modelIndex != null) {
3925 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3926 String tableGuid = (String)ix.values().toArray()[0];
3927 if (tableGuid.equals(guid)) {
3928 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
3929 listManager.getNoteTableModel().setData(i, Global.noteTableSubjectDatePosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
3930 noteTableView.proxyModel.invalidate();
3935 logger.log(logger.HIGH, "Leaving NeverNote.updateListDateCreated");
3937 private void updateListDateChanged(String guid, QDateTime date) {
3938 logger.log(logger.HIGH, "Entering NeverNote.updateListDateChanged");
3940 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
3941 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
3942 if (modelIndex != null) {
3943 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
3944 String tableGuid = (String)ix.values().toArray()[0];
3945 if (tableGuid.equals(guid)) {
3946 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
3947 listManager.getNoteTableModel().setData(i, Global.noteTableChangedPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
3952 logger.log(logger.HIGH, "Leaving NeverNote.updateListDateChanged");
3954 private void updateListDateChanged() {
3955 logger.log(logger.HIGH, "Entering NeverNote.updateListDateChanged");
3956 QDateTime date = new QDateTime(QDateTime.currentDateTime());
3957 updateListDateChanged(currentNoteGuid, date);
3958 logger.log(logger.HIGH, "Leaving NeverNote.updateListDateChanged");
3961 private void scrollToCurrentGuid() {
3962 //scrollToGuid(currentNoteGuid);
3963 List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
3964 if (selections.size() == 0)
3966 QModelIndex index = selections.get(0);
3967 int row = selections.get(0).row();
3968 String guid = (String)index.model().index(row, Global.noteTableGuidPosition).data();
3971 // Scroll to the current GUID in tthe list.
3972 // Scroll to a particular index item
3973 private void scrollToGuid(String guid) {
3974 if (currentNote == null || guid == null)
3976 if (currentNote.isActive() && Global.showDeleted) {
3977 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
3978 if (!listManager.getNoteIndex().get(i).isActive()) {
3979 currentNote = listManager.getNoteIndex().get(i);
3980 currentNoteGuid = currentNote.getGuid();
3981 i = listManager.getNoteIndex().size();
3985 if (!currentNote.isActive() && !Global.showDeleted) {
3986 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
3987 if (listManager.getNoteIndex().get(i).isActive()) {
3988 currentNote = listManager.getNoteIndex().get(i);
3989 currentNoteGuid = currentNote.getGuid();
3990 i = listManager.getNoteIndex().size();
3995 for (int i=0; i<noteTableView.model().rowCount(); i++) {
3996 index = noteTableView.model().index(i, Global.noteTableGuidPosition);
3997 if (currentNoteGuid.equals(index.data())) {
3998 // noteTableView.selectionModel().blockSignals(true);
3999 noteTableView.selectRow(i);
4000 // noteTableView.selectionModel().blockSignals(false);
4001 noteTableView.scrollTo(index, ScrollHint.EnsureVisible); // This should work, but it doesn't
4002 i=listManager.getNoteTableModel().rowCount();
4005 noteTableView.repaint();
4007 // Show/Hide columns
4008 private void showColumns() {
4009 noteTableView.setColumnHidden(Global.noteTableCreationPosition, !Global.isColumnVisible("dateCreated"));
4010 noteTableView.setColumnHidden(Global.noteTableChangedPosition, !Global.isColumnVisible("dateChanged"));
4011 noteTableView.setColumnHidden(Global.noteTableSubjectDatePosition, !Global.isColumnVisible("dateSubject"));
4012 noteTableView.setColumnHidden(Global.noteTableAuthorPosition, !Global.isColumnVisible("author"));
4013 noteTableView.setColumnHidden(Global.noteTableSourceUrlPosition, !Global.isColumnVisible("sourceUrl"));
4014 noteTableView.setColumnHidden(Global.noteTableTagPosition, !Global.isColumnVisible("tags"));
4015 noteTableView.setColumnHidden(Global.noteTableNotebookPosition, !Global.isColumnVisible("notebook"));
4016 noteTableView.setColumnHidden(Global.noteTableSynchronizedPosition, !Global.isColumnVisible("synchronized"));
4017 noteTableView.setColumnHidden(Global.noteTableGuidPosition, !Global.isColumnVisible("guid"));
4018 noteTableView.setColumnHidden(Global.noteTableThumbnailPosition, !Global.isColumnVisible("thumbnail"));
4019 noteTableView.setColumnHidden(Global.noteTableTitlePosition, !Global.isColumnVisible("title"));
4021 // Title color has changed
4022 @SuppressWarnings("unused")
4023 private void titleColorChanged(Integer color) {
4024 logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
4026 QColor backgroundColor = new QColor();
4027 QColor foregroundColor = new QColor(QColor.black);
4028 backgroundColor.setRgb(color);
4030 if (backgroundColor.rgb() == QColor.black.rgb() || backgroundColor.rgb() == QColor.blue.rgb())
4031 foregroundColor.setRgb(QColor.white.rgb());
4033 if (selectedNoteGUIDs.size() == 0)
4034 selectedNoteGUIDs.add(currentNoteGuid);
4036 for (int j=0; j<selectedNoteGUIDs.size(); j++) {
4037 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4038 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4039 if (modelIndex != null) {
4040 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4041 String tableGuid = (String)ix.values().toArray()[0];
4042 if (tableGuid.equals(selectedNoteGUIDs.get(j))) {
4043 for (int k=0; k<Global.noteTableColumnCount; k++) {
4044 listManager.getNoteTableModel().setData(i, k, backgroundColor, Qt.ItemDataRole.BackgroundRole);
4045 listManager.getNoteTableModel().setData(i, k, foregroundColor, Qt.ItemDataRole.ForegroundRole);
4046 listManager.updateNoteTitleColor(selectedNoteGUIDs.get(j), backgroundColor.rgb());
4048 i=listManager.getNoteTableModel().rowCount();
4053 logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
4055 // Wide list was chosen
4056 public void narrowListView() {
4057 saveNoteColumnPositions();
4058 saveNoteIndexWidth();
4060 int sortCol = noteTableView.proxyModel.sortColumn();
4061 int sortOrder = noteTableView.proxyModel.sortOrder().value();
4062 Global.setSortColumn(sortCol);
4063 Global.setSortOrder(sortOrder);
4065 Global.setListView(Global.View_List_Narrow);
4067 menuBar.wideListView.blockSignals(true);
4068 menuBar.narrowListView.blockSignals(true);
4070 menuBar.wideListView.setChecked(false);
4071 menuBar.narrowListView.setChecked(true);
4073 menuBar.wideListView.blockSignals(false);
4074 menuBar.narrowListView.blockSignals(false);
4076 mainLeftRightSplitter.addWidget(noteTableView);
4077 mainLeftRightSplitter.addWidget(browserWindow);
4078 restoreWindowState(false);
4079 noteTableView.repositionColumns();
4080 noteTableView.resizeColumnWidths();
4081 noteTableView.resizeRowHeights();
4083 sortCol = Global.getSortColumn();
4084 sortOrder = Global.getSortOrder();
4085 noteTableView.sortByColumn(sortCol, SortOrder.resolve(sortOrder));
4088 noteTableView.load(false);
4089 refreshEvernoteNote(true);
4090 scrollToCurrentGuid();
4092 public void wideListView() {
4093 int sortCol = noteTableView.proxyModel.sortColumn();
4094 int sortOrder = noteTableView.proxyModel.sortOrder().value();
4095 Global.setSortColumn(sortCol);
4096 Global.setSortOrder(sortOrder);
4099 saveNoteColumnPositions();
4100 saveNoteIndexWidth();
4101 Global.setListView(Global.View_List_Wide);
4103 menuBar.wideListView.blockSignals(true);
4104 menuBar.narrowListView.blockSignals(true);
4106 menuBar.wideListView.setChecked(true);
4107 menuBar.narrowListView.setChecked(false);
4109 menuBar.wideListView.blockSignals(false);
4110 menuBar.narrowListView.blockSignals(false);
4111 browserIndexSplitter.setVisible(true);
4112 browserIndexSplitter.addWidget(noteTableView);
4113 browserIndexSplitter.addWidget(browserWindow);
4114 restoreWindowState(false);
4115 noteTableView.repositionColumns();
4116 noteTableView.resizeColumnWidths();
4117 noteTableView.resizeRowHeights();
4119 sortCol = Global.getSortColumn();
4120 sortOrder = Global.getSortOrder();
4121 noteTableView.sortByColumn(sortCol, SortOrder.resolve(sortOrder));
4124 noteTableView.load(false);
4125 scrollToCurrentGuid();
4129 //***************************************************************
4130 @SuppressWarnings("unused")
4131 private void evernoteLinkClick(String syncGuid, String locGuid) {
4133 if (conn.getNoteTable().guidExists(syncGuid)) {
4136 // If we didn't find it via the synchronized guid, look under the local guid
4137 // Iwe don't find it there, look to see if the GUID is posted under the local GUID, but was
4138 // later synchronized (that causes the guid to change so we need to find the new one).
4139 if (conn.getNoteTable().guidExists(locGuid))
4142 guid = conn.getNoteTable().findAlternateGuid(locGuid);
4145 openExternalEditor(guid);
4149 //If we've gotten this far, we can't find the note
4150 QMessageBox.information(this, tr("Note Not Found"), tr("Sorry, but I can't"+
4151 " seem to find that note."));
4153 //***************************************************************
4154 //***************************************************************
4155 //** External editor window functions
4156 //***************************************************************
4157 //***************************************************************
4158 private void listDoubleClick() {
4160 openExternalEditor(currentNoteGuid);
4162 private void openExternalEditor(String guid) {
4164 if (externalWindows.containsKey(guid)) {
4165 externalWindows.get(guid).raise();
4168 Note note = conn.getNoteTable().getNote(guid, true, true, false, true, true);
4169 // We have a new external editor to create
4170 QIcon appIcon = new QIcon(iconPath+"nevernote.png");
4171 ExternalBrowse newBrowser = new ExternalBrowse(conn);
4172 newBrowser.setWindowIcon(appIcon);
4173 externalWindows.put(guid, newBrowser);
4174 showEditorButtons(newBrowser.getBrowserWindow());
4175 loadNoteBrowserInformation(newBrowser.getBrowserWindow(), guid, note);
4176 setupBrowserWindowListeners(newBrowser.getBrowserWindow(), false);
4177 newBrowser.windowClosing.connect(this, "externalWindowClosing(String)");
4178 newBrowser.getBrowserWindow().noteSignal.titleChanged.connect(this, "externalWindowTitleEdited(String, String)");
4179 newBrowser.getBrowserWindow().noteSignal.tagsChanged.connect(this, "externalWindowTagsEdited(String, List)");
4180 newBrowser.contentsChanged.connect(this, "saveNoteExternalBrowser(String, String, Boolean, BrowserWindow)");
4181 newBrowser.getBrowserWindow().blockApplication.connect(this, "blockApplication(BrowserWindow)");
4182 newBrowser.getBrowserWindow().unblockApplication.connect(this, "unblockApplication()");
4184 browserWindow.noteSignal.tagsChanged.connect(newBrowser, "updateTags(String, List)");
4185 browserWindow.noteSignal.titleChanged.connect(newBrowser, "updateTitle(String, String)");
4186 browserWindow.noteSignal.notebookChanged.connect(newBrowser, "updateNotebook(String, String)");
4190 @SuppressWarnings("unused")
4191 private void externalWindowTitleEdited(String guid, String text) {
4192 if (guid.equals(currentNoteGuid)) {
4193 browserWindow.setTitle(text);
4196 @SuppressWarnings({ "rawtypes", "unused" })
4197 private void externalWindowTagsEdited(String guid, List values) {
4198 StringBuffer line = new StringBuffer(100);
4199 for (int i=0; i<values.size(); i++) {
4201 line.append(Global.tagDelimeter+" ");
4202 line.append(values.get(i));
4204 if (guid.equals(currentNoteGuid)) {
4205 browserWindow.setTag(line.toString());
4208 @SuppressWarnings("unused")
4209 private void externalWindowClosing(String guid) {
4210 externalWindows.remove(guid);
4215 //***************************************************************
4216 //***************************************************************
4217 //** These functions deal with Note specific things
4218 //***************************************************************
4219 //***************************************************************
4220 @SuppressWarnings("unused")
4221 private void setNoteDirty() {
4222 logger.log(logger.EXTREME, "Entering NeverNote.setNoteDirty()");
4224 // Find if the note is being edited externally. If it is, update it.
4225 if (externalWindows.containsKey(currentNoteGuid)) {
4226 QTextCodec codec = QTextCodec.codecForName("UTF-8");
4227 QByteArray unicode = codec.fromUnicode(browserWindow.getContent());
4228 ExternalBrowse window = externalWindows.get(currentNoteGuid);
4229 window.getBrowserWindow().setContent(unicode);
4232 // If the note is dirty, then it is unsynchronized by default.
4236 // Set the note as dirty and check if its status is synchronized in the display table
4238 for (int i=0; i<listManager.getUnsynchronizedNotes().size(); i++) {
4239 if (listManager.getUnsynchronizedNotes().get(i).equals(currentNoteGuid))
4243 // If this wasn't already marked as unsynchronized, then we need to update the table
4244 listManager.getNoteTableModel().updateNoteSyncStatus(currentNoteGuid, false);
4245 /* listManager.getUnsynchronizedNotes().add(currentNoteGuid);
4246 for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
4247 QModelIndex modelIndex = listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
4248 if (modelIndex != null) {
4249 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4250 String tableGuid = (String)ix.values().toArray()[0];
4251 if (tableGuid.equals(currentNoteGuid)) {
4252 listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
4258 logger.log(logger.EXTREME, "Leaving NeverNote.setNoteDirty()");
4260 @SuppressWarnings("unused")
4261 private void saveNoteExternalBrowser(String guid, String content, Boolean save, BrowserWindow browser) {
4262 QTextCodec codec = QTextCodec.codecForName("UTF-8");
4263 QByteArray unicode = codec.fromUnicode(content);
4264 noteCache.remove(guid);
4265 noteCache.put(guid, unicode.toString());
4266 if (guid.equals(currentNoteGuid)) {
4268 browserWindow.setContent(unicode);
4271 thumbnailRunner.addWork("GENERATE "+ guid);
4272 saveNote(guid, browser);
4276 private void saveNote() {
4278 saveNote(currentNoteGuid, browserWindow);
4279 thumbnailRunner.addWork("GENERATE "+ currentNoteGuid);
4283 private void saveNote(String guid, BrowserWindow window) {
4284 logger.log(logger.EXTREME, "Inside NeverNote.saveNote()");
4287 logger.log(logger.EXTREME, "Saving to cache");
4288 QTextCodec codec = QTextCodec.codecForLocale();
4289 // QTextDecoder decoder = codec.makeDecoder();
4290 codec = QTextCodec.codecForName("UTF-8");
4291 QByteArray unicode = codec.fromUnicode(window.getContent());
4292 noteCache.put(guid, unicode.toString());
4294 logger.log(logger.EXTREME, "updating list manager");
4295 listManager.updateNoteContent(guid, window.getContent());
4296 logger.log(logger.EXTREME, "Updating title");
4297 listManager.updateNoteTitle(guid, window.getTitle());
4298 updateListDateChanged();
4300 logger.log(logger.EXTREME, "Looking through note index for refreshed note");
4301 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
4302 if (listManager.getNoteIndex().get(i).getGuid().equals(guid)) {
4303 currentNote = listManager.getNoteIndex().get(i);
4304 i = listManager.getNoteIndex().size();
4309 // Get a note from Evernote (and put it in the browser)
4310 private void refreshEvernoteNote(boolean reload) {
4311 logger.log(logger.HIGH, "Entering NeverNote.refreshEvernoteNote");
4313 if (Global.disableViewing) {
4314 browserWindow.setEnabled(false);
4319 if (Global.showDeleted || currentNoteGuid == null || currentNoteGuid.equals(""))
4321 Global.cryptCounter =0;
4323 browserWindow.setReadOnly(true);
4331 browserWindow.loadingData(true);
4333 currentNote = conn.getNoteTable().getNote(currentNoteGuid, true,true,false,false,true);
4334 if (currentNote == null)
4336 loadNoteBrowserInformation(browserWindow, currentNoteGuid, currentNote);
4339 private void loadNoteBrowserInformation(BrowserWindow browser, String guid, Note note) {
4340 NoteFormatter formatter = new NoteFormatter(logger, conn, tempFiles);
4341 formatter.setNote(note, Global.pdfPreview());
4342 formatter.setHighlight(listManager.getEnSearch());
4344 if (!noteCache.containsKey(guid)) {
4345 js = new QByteArray();
4346 // We need to prepend the note with <HEAD></HEAD> or encoded characters are ugly
4347 js.append("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">");
4348 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>");
4349 js.append("<style type=\"text/css\">en-hilight { background-color: rgb(255,255,0) }</style>");
4350 js.append("<style> img { max-width:100%; }</style>");
4351 js.append("<style type=\"text/css\">en-spell { text-decoration: none; border-bottom: dotted 1px #cc0000; }</style>");
4352 js.append("</head>");
4353 formatter.setNote(note, Global.pdfPreview());
4354 js.append(formatter.rebuildNoteHTML());
4355 js.append("</HTML>");
4356 js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml.dtd'>", "");
4357 js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml2.dtd'>", "");
4358 js.replace("<?xml version='1.0' encoding='UTF-8'?>", "");
4359 // if (Global.enableHTMLEntitiesFix) {
4360 // browser.getBrowser().setContent(new QByteArray(StringEscapeUtils.unescapeHtml(js.toString())));
4362 browser.setContent(js);
4363 noteCache.put(guid, js.toString());
4365 if (formatter.resourceError)
4366 resourceErrorMessage();
4367 if (formatter.formatError) {
4369 QMessageBox.information(this, tr("Error"),
4370 tr("NeverNote had issues formatting this note." +
4371 " To protect your data this note is being marked as read-only."));
4374 readOnly = formatter.readOnly;
4375 inkNote = formatter.inkNote;
4377 readOnlyCache.put(guid, true);
4379 inkNoteCache.put(guid, true);
4381 logger.log(logger.HIGH, "Note content is being pulled from the cache");
4382 String cachedContent = formatter.modifyCachedTodoTags(noteCache.get(guid));
4383 js = new QByteArray(cachedContent);
4384 browser.setContent(js);
4385 if (readOnlyCache.containsKey(guid))
4387 if (inkNoteCache.containsKey(guid))
4390 if (conn.getNoteTable().isThumbnailNeeded(guid)) {
4391 thumbnailHTMLReady(guid, js, Global.calculateThumbnailZoom(js.toString()));
4393 if (readOnly || inkNote)
4394 browser.getBrowser().page().setContentEditable(false); // We don't allow editing of ink notes
4396 browser.getBrowser().page().setContentEditable(true);
4397 browser.setReadOnly(readOnly);
4398 deleteButton.setEnabled(!readOnly);
4399 tagButton.setEnabled(!readOnly);
4400 menuBar.noteDelete.setEnabled(!readOnly);
4401 menuBar.noteTags.setEnabled(!readOnly);
4402 browser.setNote(note);
4404 if (note != null && note.getNotebookGuid() != null &&
4405 conn.getNotebookTable().isLinked(note.getNotebookGuid())) {
4406 deleteButton.setEnabled(false);
4407 menuBar.notebookDeleteAction.setEnabled(false);
4409 deleteButton.setEnabled(true);
4410 menuBar.notebookDeleteAction.setEnabled(true);
4413 // Build a list of non-closed notebooks
4414 List<Notebook> nbooks = new ArrayList<Notebook>();
4415 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
4416 boolean found=false;
4417 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
4418 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid()))
4422 nbooks.add(listManager.getNotebookIndex().get(i));
4425 browser.setTitle(note.getTitle());
4426 browser.setTag(getTagNamesForNote(note));
4427 browser.setAuthor(note.getAttributes().getAuthor());
4429 browser.setAltered(note.getUpdated());
4430 browser.setCreation(note.getCreated());
4431 if (note.getAttributes().getSubjectDate() > 0)
4432 browser.setSubjectDate(note.getAttributes().getSubjectDate());
4434 browser.setSubjectDate(note.getCreated());
4435 browser.setUrl(note.getAttributes().getSourceURL());
4437 FilterEditorTags tagFilter = new FilterEditorTags(conn, logger);
4438 List<Tag> tagList = tagFilter.getValidTags(note);
4439 browser.setAllTags(tagList);
4441 browser.setCurrentTags(note.getTagNames());
4445 browser.loadingData(false);
4446 if (thumbnailViewer.isActiveWindow())
4449 FilterEditorNotebooks notebookFilter = new FilterEditorNotebooks(conn, logger);
4450 browser.setNotebookList(notebookFilter.getValidNotebooks(note, listManager.getNotebookIndex()));
4453 logger.log(logger.HIGH, "Leaving NeverNote.refreshEvernoteNote");
4455 // Save a generated thumbnail
4456 private void toggleNoteInformation() {
4457 logger.log(logger.HIGH, "Entering NeverNote.toggleNoteInformation");
4458 browserWindow.toggleInformation();
4459 menuBar.noteAttributes.setChecked(browserWindow.isExtended());
4460 Global.saveWindowVisible("noteInformation", browserWindow.isExtended());
4461 logger.log(logger.HIGH, "Leaving NeverNote.toggleNoteInformation");
4463 // Listener triggered when a print button is pressed
4464 @SuppressWarnings("unused")
4465 private void printNote() {
4466 logger.log(logger.HIGH, "Entering NeverNote.printNote");
4468 QPrintDialog dialog = new QPrintDialog();
4469 if (dialog.exec() == QDialog.DialogCode.Accepted.value()) {
4470 QPrinter printer = dialog.printer();
4471 browserWindow.getBrowser().print(printer);
4473 logger.log(logger.HIGH, "Leaving NeverNote.printNote");
4476 // Listener triggered when the email button is pressed
4477 @SuppressWarnings("unused")
4478 private void emailNote() {
4479 logger.log(logger.HIGH, "Entering NeverNote.emailNote");
4481 if (Desktop.isDesktopSupported()) {
4482 Desktop desktop = Desktop.getDesktop();
4484 String text2 = browserWindow.getContentsToEmail();
4485 QUrl url = new QUrl("mailto:");
4486 url.addQueryItem("subject", currentNote.getTitle());
4487 // url.addQueryItem("body", QUrl.toPercentEncoding(text2).toString());
4488 url.addQueryItem("body", text2);
4489 QDesktopServices.openUrl(url);
4493 if (desktop.isSupported(Desktop.Action.MAIL)) {
4494 URI uriMailTo = null;
4496 //String text = browserWindow.getBrowser().page().currentFrame().toPlainText();
4497 String text = browserWindow.getContentsToEmail();
4498 //text = "<b>" +text +"</b>";
4499 uriMailTo = new URI("mailto", "&SUBJECT="+currentNote.getTitle()
4500 +"&BODY=" +text, null);
4501 uriMailTo = new URI("mailto", "&SUBJECT="+currentNote.getTitle()
4502 +"&ATTACHMENT=d:/test.pdf", null);
4503 desktop.mail(uriMailTo);
4504 } catch (URISyntaxException e) {
4505 e.printStackTrace();
4506 } catch (IOException e) {
4507 e.printStackTrace();
4514 logger.log(logger.HIGH, "Leaving NeverNote.emailNote");
4516 // Reindex all notes
4517 @SuppressWarnings("unused")
4518 private void fullReindex() {
4519 logger.log(logger.HIGH, "Entering NeverNote.fullReindex");
4520 indexRunner.addWork("REINDEXALL");
4521 setMessage(tr("Database will be reindexed."));
4522 logger.log(logger.HIGH, "Leaving NeverNote.fullReindex");
4524 // Listener when a user wants to reindex a specific note
4525 @SuppressWarnings("unused")
4526 private void reindexNote() {
4527 logger.log(logger.HIGH, "Entering NeverNote.reindexNote");
4528 for (int i=0; i<selectedNoteGUIDs.size(); i++) {
4529 indexRunner.addWork("REINDEXNOTE "+selectedNoteGUIDs.get(i));
4531 if (selectedNotebookGUIDs.size() > 1)
4532 setMessage(tr("Notes will be reindexed."));
4534 setMessage(tr("Note will be reindexed."));
4535 logger.log(logger.HIGH, "Leaving NeverNote.reindexNote");
4538 @SuppressWarnings("unused")
4539 private void deleteNote() {
4540 logger.log(logger.HIGH, "Entering NeverNote.deleteNote");
4541 if (currentNote == null)
4543 if (currentNoteGuid.equals(""))
4545 String title = null;
4546 if (selectedNoteGUIDs.size() == 1)
4547 title = conn.getNoteTable().getNote(selectedNoteGUIDs.get(0),false,false,false,false,false).getTitle();
4549 // If we are deleting non-trash notes
4550 if (currentNote.isActive()) {
4551 if (Global.verifyDelete()) {
4553 if (selectedNoteGUIDs.size() > 1) {
4554 msg = new String(tr("Delete ") +selectedNoteGUIDs.size() +" notes?");
4557 msg = new String(tr("Delete note \"") +title +"\"?");
4559 msg = new String(tr("Delete note selected note?"));
4561 if (QMessageBox.question(this, tr("Confirmation"), msg,
4562 QMessageBox.StandardButton.Yes,
4563 QMessageBox.StandardButton.No)==StandardButton.No.value() && Global.verifyDelete() == true) {
4567 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
4568 selectedNoteGUIDs.add(currentNoteGuid);
4569 for (int i=0; i<selectedNoteGUIDs.size(); i++) {
4570 listManager.deleteNote(selectedNoteGUIDs.get(i));
4573 // If we are deleting from the trash.
4574 if (Global.verifyDelete()) {
4576 if (selectedNoteGUIDs.size() > 1) {
4577 msg = new String(tr("Permanently delete ") +selectedNoteGUIDs.size() +" notes?");
4580 msg = new String(tr("Permanently delete note \"") +title +"\"?");
4582 msg = new String(tr("Permanently delete note selected note?"));
4584 if (QMessageBox.question(this, "Confirmation", msg,
4585 QMessageBox.StandardButton.Yes,
4586 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
4590 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
4591 selectedNoteGUIDs.add(currentNoteGuid);
4592 for (int i=selectedNoteGUIDs.size()-1; i>=0; i--) {
4593 for (int j=listManager.getNoteTableModel().rowCount()-1; j>=0; j--) {
4594 QModelIndex modelIndex = listManager.getNoteTableModel().index(j, Global.noteTableGuidPosition);
4595 if (modelIndex != null) {
4596 SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
4597 String tableGuid = (String)ix.values().toArray()[0];
4598 if (tableGuid.equals(selectedNoteGUIDs.get(i))) {
4599 listManager.getNoteTableModel().removeRow(j);
4604 listManager.expungeNote(selectedNoteGUIDs.get(i));
4607 currentNoteGuid = "";
4608 listManager.loadNotesIndex();
4609 noteIndexUpdated(false);
4610 refreshEvernoteNote(true);
4611 scrollToGuid(currentNoteGuid);
4612 logger.log(logger.HIGH, "Leaving NeverNote.deleteNote");
4615 @SuppressWarnings("unused")
4616 private void addNote() {
4617 logger.log(logger.HIGH, "Inside NeverNote.addNote");
4618 // browserWindow.setEnabled(true);
4619 browserWindow.setReadOnly(false);
4621 Calendar currentTime = new GregorianCalendar();
4622 StringBuffer noteString = new StringBuffer(100);
4623 noteString.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
4624 "<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">\n" +
4627 if (Global.overrideDefaultFont()) {
4628 noteString.append("<font face=\"" +Global.getDefaultFont() +"\" >");
4629 noteString.append("<span style=\"font-size:" +Global.getDefaultFontSize() +"pt;\">");
4630 noteString.append("<br clear=\"none\" />\n");
4631 noteString.append("</span>\n</font>\n");
4633 noteString.append("<br clear=\"none\" />\n");
4634 noteString.append("</en-note>");
4636 Long l = new Long(currentTime.getTimeInMillis());
4637 String randint = new String(Long.toString(l));
4639 // Find a notebook. We first look for a selected notebook (the "All Notebooks" one doesn't count).
4641 // for the first non-archived notebook. Finally, if nothing else we
4642 // pick the first notebook in the list.
4643 String notebook = null;
4644 listManager.getNotebookIndex().get(0).getGuid();
4645 List<QTreeWidgetItem> selectedNotebook = notebookTree.selectedItems();
4646 if (selectedNotebook.size() > 0 && !selectedNotebook.get(0).text(0).equalsIgnoreCase("All Notebooks")) {
4647 QTreeWidgetItem currentSelectedNotebook = selectedNotebook.get(0);
4648 notebook = currentSelectedNotebook.text(2);
4650 boolean found = false;
4651 List<Notebook> goodNotebooks = new ArrayList<Notebook>();
4652 for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
4653 boolean match = false;
4654 for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
4655 if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid())) {
4657 j = listManager.getArchiveNotebookIndex().size();
4661 //goodNotebooks.add(listManager.getNotebookIndex().get(i).deepCopy());
4662 goodNotebooks.add((Notebook)Global.deepCopy(listManager.getNotebookIndex().get(i)));
4664 // Now we have a list of good notebooks, so we can look for the default
4666 for (int i=0; i<goodNotebooks.size(); i++) {
4667 if (goodNotebooks.get(i).isDefaultNotebook()) {
4668 notebook = goodNotebooks.get(i).getGuid();
4670 i = goodNotebooks.size();
4674 if (goodNotebooks.size() > 0 && !found)
4675 notebook = goodNotebooks.get(0).getGuid();
4678 notebook = listManager.getNotebookIndex().get(0).getGuid();
4681 Note newNote = new Note();
4682 newNote.setUpdateSequenceNum(0);
4683 newNote.setGuid(randint);
4684 newNote.setNotebookGuid(notebook);
4685 newNote.setTitle("Untitled Note");
4686 newNote.setContent(noteString.toString());
4687 newNote.setDeleted(0);
4688 newNote.setCreated(System.currentTimeMillis());
4689 newNote.setUpdated(System.currentTimeMillis());
4690 newNote.setActive(true);
4691 NoteAttributes na = new NoteAttributes();
4692 na.setLatitude(0.0);
4693 na.setLongitude(0.0);
4694 na.setAltitude(0.0);
4695 newNote.setAttributes(new NoteAttributes());
4696 newNote.setTagGuids(new ArrayList<String>());
4697 newNote.setTagNames(new ArrayList<String>());
4699 // If new notes are to be created based upon the selected tags, then we need to assign the tags
4700 if (Global.newNoteWithSelectedTags()) {
4701 List<QTreeWidgetItem> selections = tagTree.selectedItems();
4702 QTreeWidgetItem currentSelection;
4703 for (int i=0; i<selections.size(); i++) {
4704 currentSelection = selections.get(i);
4705 newNote.getTagGuids().add(currentSelection.text(2));
4706 newNote.getTagNames().add(currentSelection.text(0));
4710 conn.getNoteTable().addNote(newNote, true);
4711 listManager.getUnsynchronizedNotes().add(newNote.getGuid());
4712 listManager.addNote(newNote);
4713 // noteTableView.insertRow(newNote, true, -1);
4715 currentNote = newNote;
4716 currentNoteGuid = currentNote.getGuid();
4717 noteTableView.clearSelection();
4718 refreshEvernoteNote(true);
4719 listManager.countNotebookResults(listManager.getNoteIndex());
4720 browserWindow.titleLabel.setFocus();
4721 browserWindow.titleLabel.selectAll();
4722 // notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
4724 // If the window is hidden, then we want to popup this in an external window &
4728 logger.log(logger.HIGH, "Leaving NeverNote.addNote");
4730 // Restore a note from the trash;
4731 @SuppressWarnings("unused")
4732 private void restoreNote() {
4734 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
4735 selectedNoteGUIDs.add(currentNoteGuid);
4736 for (int i=0; i<selectedNoteGUIDs.size(); i++) {
4737 listManager.restoreNote(selectedNoteGUIDs.get(i));
4739 currentNoteGuid = "";
4740 listManager.loadNotesIndex();
4741 noteIndexUpdated(false);
4744 // Search a note for specific txt
4745 @SuppressWarnings("unused")
4746 private void findText() {
4748 find.setFocusOnTextField();
4750 @SuppressWarnings("unused")
4751 private void doFindText() {
4752 browserWindow.getBrowser().page().findText(find.getText(), find.getFlags());
4755 @SuppressWarnings("unused")
4756 private void updateNoteTitle(String guid, String title) {
4757 listManager.setNoteSynchronized(guid, false);
4759 // Signal received that note content has changed. Normally we just need the guid to remove
4760 // it from the cache.
4761 @SuppressWarnings("unused")
4762 private void invalidateNoteCache(String guid, String content) {
4763 noteCache.remove(guid);
4764 refreshEvernoteNote(true);
4766 // Signal received that a note guid has changed
4767 @SuppressWarnings("unused")
4768 private void noteGuidChanged(String oldGuid, String newGuid) {
4769 if (noteCache.containsKey(oldGuid)) {
4770 if (!oldGuid.equals(currentNoteGuid)) {
4771 String cache = noteCache.get(oldGuid);
4772 noteCache.put(newGuid, cache);
4773 noteCache.remove(oldGuid);
4775 noteCache.remove(oldGuid);
4776 noteCache.put(newGuid, browserWindow.getContent());
4780 listManager.updateNoteGuid(oldGuid, newGuid, false);
4781 if (currentNoteGuid.equals(oldGuid)) {
4782 if (currentNote != null)
4783 currentNote.setGuid(newGuid);
4784 currentNoteGuid = newGuid;
4787 if (externalWindows.containsKey(oldGuid)) {
4788 ExternalBrowse b = externalWindows.get(oldGuid);
4789 externalWindows.remove(oldGuid);
4790 b.getBrowserWindow().getNote().setGuid(newGuid);
4791 externalWindows.put(newGuid, b);
4794 for (int i=0; i<listManager.getNoteIndex().size(); i++) {
4795 if (listManager.getNoteIndex().get(i).getGuid().equals(newGuid)) {
4796 noteTableView.proxyModel.addGuid(newGuid);
4797 i=listManager.getNoteIndex().size();
4801 if (listManager.getNoteTableModel().titleColors.containsKey(oldGuid)) {
4802 int color = listManager.getNoteTableModel().titleColors.get(oldGuid);
4803 listManager.getNoteTableModel().titleColors.put(newGuid, color);
4804 listManager.getNoteTableModel().titleColors.remove(oldGuid);
4808 // Toggle the note editor button bar
4809 private void toggleEditorButtonBar() {
4810 if (browserWindow.buttonsVisible) {
4811 browserWindow.hideButtons();
4812 menuBar.showEditorBar.setChecked(browserWindow.buttonsVisible);
4813 // Global.saveWindowVisible("editorButtonBar", browserWindow.buttonsVisible);
4815 browserWindow.buttonsVisible = true;
4816 showEditorButtons(browserWindow);
4818 Global.saveWindowVisible("editorButtonBar", browserWindow.buttonsVisible);
4820 // Show editor buttons
4821 private void showEditorButtons(BrowserWindow browser) {
4822 browser.buttonLayout.setVisible(true);
4823 browser.undoAction.setVisible(false);
4825 browser.undoButton.setVisible(false);
4827 browser.undoAction.setVisible(Global.isEditorButtonVisible("undo"));
4828 browser.redoAction.setVisible(Global.isEditorButtonVisible("redo"));
4829 browser.cutAction.setVisible(Global.isEditorButtonVisible("cut"));
4830 browser.copyAction.setVisible(Global.isEditorButtonVisible("copy"));
4831 browser.pasteAction.setVisible(Global.isEditorButtonVisible("paste"));
4832 browser.strikethroughAction.setVisible(Global.isEditorButtonVisible("strikethrough"));
4833 browser.underlineAction.setVisible(Global.isEditorButtonVisible("underline"));
4834 browser.boldAction.setVisible(Global.isEditorButtonVisible("bold"));
4835 browser.italicAction.setVisible(Global.isEditorButtonVisible("italic"));
4836 browser.hlineAction.setVisible(Global.isEditorButtonVisible("hline"));
4837 browser.indentAction.setVisible(Global.isEditorButtonVisible("indent"));
4838 browser.outdentAction.setVisible(Global.isEditorButtonVisible("outdent"));
4839 browser.bulletListAction.setVisible(Global.isEditorButtonVisible("bulletList"));
4840 browser.numberListAction.setVisible(Global.isEditorButtonVisible("numberList"));
4841 browser.fontListAction.setVisible(Global.isEditorButtonVisible("font"));
4842 browser.fontSizeAction.setVisible(Global.isEditorButtonVisible("fontSize"));
4843 browser.fontColorAction.setVisible(Global.isEditorButtonVisible("fontColor"));
4844 browser.fontHilightAction.setVisible(Global.isEditorButtonVisible("fontHilight"));
4845 browser.leftAlignAction.setVisible(Global.isEditorButtonVisible("alignLeft"));
4846 browser.centerAlignAction.setVisible(Global.isEditorButtonVisible("alignCenter"));
4847 browser.rightAlignAction.setVisible(Global.isEditorButtonVisible("alignRight"));
4848 browser.spellCheckAction.setVisible(Global.isEditorButtonVisible("spellCheck"));
4849 browser.todoAction.setVisible(Global.isEditorButtonVisible("todo"));
4851 private void duplicateNote(String guid) {
4853 Note oldNote = conn.getNoteTable().getNote(guid, true, false,false,false,true);
4854 List<Resource> resList = conn.getNoteTable().noteResourceTable.getNoteResources(guid, true);
4855 oldNote.setContent(conn.getNoteTable().getNoteContentBinary(guid));
4856 oldNote.setResources(resList);
4857 duplicateNote(oldNote);
4859 private void duplicateNote(Note oldNote) {
4861 // Now that we have a good notebook guid, we need to move the conflicting note
4862 // to the local notebook
4863 Calendar currentTime = new GregorianCalendar();
4864 Long l = new Long(currentTime.getTimeInMillis());
4865 String newGuid = new String(Long.toString(l));
4867 // Note newNote = oldNote.deepCopy();
4868 Note newNote = (Note)Global.deepCopy(oldNote);
4869 newNote.setUpdateSequenceNum(0);
4870 newNote.setGuid(newGuid);
4871 newNote.setDeleted(0);
4872 newNote.setActive(true);
4875 List<String> tagNames = new ArrayList<String>();
4876 List<String> tagGuids = new ArrayList<String>();;
4877 for (int i=0; i<oldNote.getTagGuidsSize(); i++) {
4878 tagNames.add(oldNote.getTagNames().get(i));
4879 tagGuids.add(oldNote.getTagGuids().get(i));
4882 // Sort note Tags to make them look nice
4883 for (int i=0; i<tagNames.size()-1; i++) {
4884 if (tagNames.get(i).compareTo(tagNames.get(i+1))<0) {
4885 String n1 = tagNames.get(i);
4886 String n2 = tagNames.get(i+1);
4887 tagNames.set(i, n2);
4888 tagNames.set(i+1, n1);
4891 newNote.setTagGuids(tagGuids);
4892 newNote.setTagNames(tagNames);
4894 // Add tag guids to note
4897 // Duplicate resources
4898 List<Resource> resList = oldNote.getResources();
4899 if (resList == null)
4900 resList = new ArrayList<Resource>();
4902 for (int i=0; i<resList.size(); i++) {
4904 while (l == prevGuid) {
4905 currentTime = new GregorianCalendar();
4906 l = new Long(currentTime.getTimeInMillis());
4909 String newResGuid = new String(Long.toString(l));
4910 resList.get(i).setNoteGuid(newGuid);
4911 resList.get(i).setGuid(newResGuid);
4912 resList.get(i).setUpdateSequenceNum(0);
4913 resList.get(i).setActive(true);
4914 conn.getNoteTable().noteResourceTable.saveNoteResource(
4915 (Resource)Global.deepCopy(resList.get(i)), true);
4917 newNote.setResources(resList);
4919 // Add note to the database
4920 listManager.addNote(newNote);
4921 conn.getNoteTable().addNote(newNote, true);
4922 listManager.getUnsynchronizedNotes().add(newNote.getGuid());
4923 noteTableView.insertRow(newNote, true, -1);
4924 currentNoteGuid = newNote.getGuid();
4925 currentNote = newNote;
4926 refreshEvernoteNote(true);
4927 listManager.countNotebookResults(listManager.getNoteIndex());
4931 @SuppressWarnings("unused")
4932 private void allNotes() {
4933 clearAttributeFilter();
4934 clearNotebookFilter();
4935 clearSavedSearchFilter();
4938 searchField.clear();
4939 if (Global.mimicEvernoteInterface) {
4940 notebookTree.selectGuid("");
4942 notebookTreeSelection();
4943 refreshEvernoteNote(true);
4946 @SuppressWarnings("unused")
4947 private void mergeNotes() {
4948 logger.log(logger.HIGH, "Merging notes");
4951 String masterGuid = null;
4952 List<String> sources = new ArrayList<String>();
4954 for (int i=0; i<noteTableView.selectionModel().selectedRows().size(); i++) {
4955 int r = noteTableView.selectionModel().selectedRows().get(i).row();
4956 index = noteTableView.proxyModel.index(r, Global.noteTableGuidPosition);
4957 SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
4959 masterGuid = (String)ix.values().toArray()[0];
4961 sources.add((String)ix.values().toArray()[0]);
4964 logger.log(logger.EXTREME, "Master guid=" +masterGuid);
4965 logger.log(logger.EXTREME, "Children count: "+sources.size());
4966 mergeNoteContents(masterGuid, sources);
4967 currentNoteGuid = masterGuid;
4968 noteIndexUpdated(false);
4969 refreshEvernoteNote(true);
4972 private void mergeNoteContents(String targetGuid, List<String> sources) {
4973 Note target = conn.getNoteTable().getNote(targetGuid, true, false, false, false, false);
4974 String newContent = target.getContent();
4975 newContent = newContent.replace("</en-note>", "<br></br>");
4977 for (int i=0; i<sources.size(); i++) {
4978 Note source = conn.getNoteTable().getNote(sources.get(i), true, true, false, false, false);
4979 if (source.isSetTitle()) {
4980 newContent = newContent +("<table bgcolor=\"lightgrey\"><tr><td><font size=\"6\"><b>" +source.getTitle() +"</b></font></td></tr></table>");
4982 String sourceContent = source.getContent();
4983 logger.log(logger.EXTREME, "Merging contents into note");
4984 logger.log(logger.EXTREME, sourceContent);
4985 logger.log(logger.EXTREME, "End of content");
4986 int startOfNote = sourceContent.indexOf("<en-note>");
4987 sourceContent = sourceContent.substring(startOfNote+9);
4988 int endOfNote = sourceContent.indexOf("</en-note>");
4989 sourceContent = sourceContent.substring(0,endOfNote);
4990 newContent = newContent + sourceContent;
4991 logger.log(logger.EXTREME, "New note content");
4992 logger.log(logger.EXTREME, newContent);
4993 logger.log(logger.EXTREME, "End of content");
4994 for (int j=0; j<source.getResourcesSize(); j++) {
4995 logger.log(logger.EXTREME, "Reassigning resource: "+source.getResources().get(j).getGuid());
4996 Resource r = source.getResources().get(j);
4997 Resource newRes = conn.getNoteTable().noteResourceTable.getNoteResource(r.getGuid(), true);
4999 Calendar currentTime = new GregorianCalendar();
5000 Long l = new Long(currentTime.getTimeInMillis());
5004 while (l == prevGuid) {
5005 currentTime = new GregorianCalendar();
5006 l = new Long(currentTime.getTimeInMillis());
5008 String newResGuid = new String(Long.toString(l));
5009 newRes.setNoteGuid(targetGuid);
5010 newRes.setGuid(newResGuid);
5011 newRes.setUpdateSequenceNum(0);
5012 newRes.setActive(true);
5013 conn.getNoteTable().noteResourceTable.saveNoteResource(newRes, true);
5016 logger.log(logger.EXTREME, "Updating note");
5017 conn.getNoteTable().updateNoteContent(targetGuid, newContent +"</en-note>");
5018 for (int i=0; i<sources.size(); i++) {
5019 logger.log(logger.EXTREME, "Deleting note " +sources.get(i));
5020 listManager.deleteNote(sources.get(i));
5022 logger.log(logger.EXTREME, "Exiting merge note");
5024 // A resource within a note has had a guid change
5025 @SuppressWarnings("unused")
5026 private void noteResourceGuidChanged(String noteGuid, String oldGuid, String newGuid) {
5027 if (oldGuid != null && !oldGuid.equals(newGuid))
5028 Global.resourceMap.put(oldGuid, newGuid);
5030 // View a thumbnail of the note
5031 public void thumbnailView() {
5033 String thumbnailName = Global.getFileManager().getResDirPath("thumbnail-" + currentNoteGuid + ".png");
5034 QFile thumbnail = new QFile(thumbnailName);
5035 if (!thumbnail.exists()) {
5037 QImage img = new QImage();
5038 img.loadFromData(conn.getNoteTable().getThumbnail(currentNoteGuid));
5039 thumbnailViewer.setThumbnail(img);
5041 thumbnailViewer.setThumbnail(thumbnailName);
5042 if (!thumbnailViewer.isVisible())
5043 thumbnailViewer.showFullScreen();
5045 // An error happened while saving a note. Inform the user
5046 @SuppressWarnings("unused")
5047 private void saveRunnerError(String guid, String msg) {
5049 String title = "*Unknown*";
5050 for (int i=0; i<listManager.getMasterNoteIndex().size(); i++) {
5051 if (listManager.getMasterNoteIndex().get(i).getGuid().equals(guid)) {
5052 title = listManager.getMasterNoteIndex().get(i).getTitle();
5053 i=listManager.getMasterNoteIndex().size();
5056 msg = tr("An error has happened while saving the note \"") +title+
5057 tr("\".\n\nThis is probably due to a document that is too complex for Nevernote to process. "+
5058 "As a result, changes to the note may not be saved properly in the database."+
5059 "\n\nA cached copy is being preserved so you can recover any data, but data may" +
5060 "\nbe lost. Please review the note to recover any critical data before restarting.");
5062 QMessageBox.information(this, tr("Error Saving Note"), tr(msg));
5065 private void thumbnailHTMLReady(String guid, QByteArray html, Integer zoom) {
5066 logger.log(logger.HIGH, "Entering thumnailHTMLReady()");
5067 logger.log(logger.HIGH, "Thumbnail ready for " +guid);
5068 // Find an idle preview object
5069 for (int i=0; i<thumbGenerators.size(); i++) {
5070 if (thumbGenerators.get(i).mutex.tryLock()) {
5071 logger.log(logger.EXTREME, "Idle generator found - loading thumbnail for " +guid);
5072 thumbGenerators.get(i).loadContent(guid, html, zoom);
5076 if (thumbGenerators.size() >= 1) {
5077 logger.log(logger.EXTREME, "No available thumbnail generators. Aborting " +guid);
5081 logger.log(logger.EXTREME, "Creating new thumbnail generator " +guid);
5082 Thumbnailer preview = new Thumbnailer(logger, conn, listManager, thumbnailRunner);
5083 thumbGenerators.add(preview);
5085 if (preview.mutex.tryLock()) {
5086 logger.log(logger.EXTREME, "Loading thumbnail for " +guid);
5087 preview.loadContent(guid, html, zoom);
5089 logger.log(logger.HIGH, "Exiting thumnailHTMLReady()");
5094 //**********************************************************
5095 //**********************************************************
5096 //* Online user actions
5097 //**********************************************************
5098 //**********************************************************
5099 private void setupOnlineMenu() {
5100 if (!Global.isConnected) {
5101 menuBar.noteOnlineHistoryAction.setEnabled(false);
5102 menuBar.selectiveSyncAction.setEnabled(false);
5105 menuBar.noteOnlineHistoryAction.setEnabled(true);
5106 menuBar.selectiveSyncAction.setEnabled(true);
5109 @SuppressWarnings("unused")
5110 private void viewNoteHistory() {
5111 if (currentNoteGuid == null || currentNoteGuid.equals(""))
5113 if (currentNote.getUpdateSequenceNum() == 0) {
5114 setMessage(tr("Note has never been synchronized."));
5115 QMessageBox.information(this, tr("Error"), tr("This note has never been sent to Evernote, so there is no history."));
5119 setMessage(tr("Getting Note History"));
5121 Note currentOnlineNote = null;
5124 if (Global.isPremium())
5125 versions = syncRunner.localNoteStore.listNoteVersions(syncRunner.authToken, currentNoteGuid);
5127 versions = new ArrayList<NoteVersionId>();
5128 currentOnlineNote = syncRunner.localNoteStore.getNote(syncRunner.authToken, currentNoteGuid, true, true, false, false);
5129 } catch (EDAMUserException e) {
5130 setMessage("EDAMUserException: " +e.getMessage());
5132 } catch (EDAMSystemException e) {
5133 setMessage("EDAMSystemException: " +e.getMessage());
5135 } catch (EDAMNotFoundException e) {
5136 setMessage(tr("Note not found on server."));
5137 QMessageBox.information(this, tr("Error"), tr("This note could not be found on Evernote's servers."));
5139 } catch (TException e) {
5140 setMessage("EDAMTransactionException: " +e.getMessage());
5144 // If we've gotten this far, we have a good note.
5145 if (historyWindow == null) {
5146 historyWindow = new OnlineNoteHistory(logger, conn);
5147 historyWindow.historyCombo.activated.connect(this, "reloadHistoryWindow(String)");
5148 historyWindow.restoreAsNew.clicked.connect(this, "restoreHistoryNoteAsNew()");
5149 historyWindow.restore.clicked.connect(this, "restoreHistoryNote()");
5151 historyWindow.historyCombo.clear();
5153 boolean isDirty = conn.getNoteTable().isNoteDirty(currentNoteGuid);
5154 if (currentNote.getUpdateSequenceNum() != currentOnlineNote.getUpdateSequenceNum())
5156 historyWindow.setCurrent(isDirty);
5158 loadHistoryWindowContent(currentOnlineNote);
5159 historyWindow.load(versions);
5160 setMessage(tr("History retrieved"));
5162 historyWindow.exec();
5164 private Note reloadHistoryWindow(String selection) {
5166 String fmt = Global.getDateFormat() + " " + Global.getTimeFormat();
5167 String dateTimeFormat = new String(fmt);
5168 SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);
5172 for (int i=0; i<versions.size(); i++) {
5173 StringBuilder versionDate = new StringBuilder(simple.format(versions.get(i).getSaved()));
5174 if (versionDate.toString().equals(selection))
5178 if (index > -1 || selection.indexOf("Current") > -1) {
5179 Note historyNote = null;
5182 usn = versions.get(index).getUpdateSequenceNum();
5183 historyNote = syncRunner.localNoteStore.getNoteVersion(syncRunner.authToken, currentNoteGuid, usn, true, true, true);
5185 historyNote = syncRunner.localNoteStore.getNote(syncRunner.authToken, currentNoteGuid, true,true,true,true);
5186 } catch (EDAMUserException e) {
5187 setMessage("EDAMUserException: " +e.getMessage());
5190 } catch (EDAMSystemException e) {
5191 setMessage("EDAMSystemException: " +e.getMessage());
5194 } catch (EDAMNotFoundException e) {
5195 setMessage("EDAMNotFoundException: " +e.getMessage());
5198 } catch (TException e) {
5199 setMessage("EDAMTransactionException: " +e.getMessage());
5205 if (historyNote != null)
5206 historyWindow.setContent(historyNote);
5212 private void loadHistoryWindowContent(Note note) {
5213 note.setUpdateSequenceNum(0);
5214 historyWindow.setContent(note);
5216 @SuppressWarnings("unused")
5217 private void restoreHistoryNoteAsNew() {
5218 setMessage(tr("Restoring as new note."));
5219 duplicateNote(reloadHistoryWindow(historyWindow.historyCombo.currentText()));
5220 setMessage(tr("Note has been restored as a new note."));
5222 @SuppressWarnings("unused")
5223 private void restoreHistoryNote() {
5224 setMessage(tr("Restoring note."));
5225 Note n = reloadHistoryWindow(historyWindow.historyCombo.currentText());
5226 conn.getNoteTable().expungeNote(n.getGuid(), true, false);
5229 for (int i=0; i<n.getResourcesSize(); i++) {
5230 n.getResources().get(i).setActive(true);
5231 conn.getNoteTable().noteResourceTable.saveNoteResource(n.getResources().get(i), true);
5233 listManager.addNote(n);
5234 conn.getNoteTable().addNote(n, true);
5235 refreshEvernoteNote(true);
5236 setMessage(tr("Note has been restored."));
5238 @SuppressWarnings("unused")
5239 private void setupSelectiveSync() {
5241 // Get a list of valid notebooks
5242 List<Notebook> notebooks = null;
5243 List<Tag> tags = null;
5244 List<LinkedNotebook> linkedNotebooks = null;
5246 notebooks = syncRunner.localNoteStore.listNotebooks(syncRunner.authToken);
5247 tags = syncRunner.localNoteStore.listTags(syncRunner.authToken);
5248 linkedNotebooks = syncRunner.localNoteStore.listLinkedNotebooks(syncRunner.authToken);
5249 } catch (EDAMUserException e) {
5250 setMessage("EDAMUserException: " +e.getMessage());
5252 } catch (EDAMSystemException e) {
5253 setMessage("EDAMSystemException: " +e.getMessage());
5255 } catch (TException e) {
5256 setMessage("EDAMTransactionException: " +e.getMessage());
5258 } catch (EDAMNotFoundException e) {
5259 setMessage("EDAMNotFoundException: " +e.getMessage());
5263 // Split up notebooks into synchronized & non-synchronized
5264 List<Notebook> ignoredBooks = new ArrayList<Notebook>();
5265 List<String> dbIgnoredNotebooks = conn.getSyncTable().getIgnoreRecords("NOTEBOOK");
5267 for (int i=notebooks.size()-1; i>=0; i--) {
5268 for (int j=0; j<dbIgnoredNotebooks.size(); j++) {
5269 if (notebooks.get(i).getGuid().equalsIgnoreCase(dbIgnoredNotebooks.get(j))) {
5270 ignoredBooks.add(notebooks.get(i));
5271 j=dbIgnoredNotebooks.size();
5276 // split up tags into synchronized & non-synchronized
5277 List<Tag> ignoredTags = new ArrayList<Tag>();
5278 List<String> dbIgnoredTags = conn.getSyncTable().getIgnoreRecords("TAG");
5280 for (int i=tags.size()-1; i>=0; i--) {
5281 for (int j=0; j<dbIgnoredTags.size(); j++) {
5282 if (tags.get(i).getGuid().equalsIgnoreCase(dbIgnoredTags.get(j))) {
5283 ignoredTags.add(tags.get(i));
5284 j=dbIgnoredTags.size();
5289 // split up linked notebooks into synchronized & non-synchronized
5290 List<LinkedNotebook> ignoredLinkedNotebooks = new ArrayList<LinkedNotebook>();
5291 List<String> dbIgnoredLinkedNotebooks = conn.getSyncTable().getIgnoreRecords("LINKEDNOTEBOOK");
5292 for (int i=linkedNotebooks.size()-1; i>=0; i--) {
5293 String notebookGuid = linkedNotebooks.get(i).getGuid();
5294 for (int j=0; j<dbIgnoredLinkedNotebooks.size(); j++) {
5295 if (notebookGuid.equalsIgnoreCase(dbIgnoredLinkedNotebooks.get(j))) {
5296 ignoredLinkedNotebooks.add(linkedNotebooks.get(i));
5297 j=dbIgnoredLinkedNotebooks.size();
5302 IgnoreSync ignore = new IgnoreSync(notebooks, ignoredBooks, tags, ignoredTags, linkedNotebooks, ignoredLinkedNotebooks);
5304 if (!ignore.okClicked())
5309 // Clear out old notebooks & add the new ones
5310 List<String> oldIgnoreNotebooks = conn.getSyncTable().getIgnoreRecords("NOTEBOOK");
5311 for (int i=0; i<oldIgnoreNotebooks.size(); i++) {
5312 conn.getSyncTable().deleteRecord("IGNORENOTEBOOK-"+oldIgnoreNotebooks.get(i));
5315 List<String> newNotebooks = new ArrayList<String>();
5316 for (int i=ignore.getIgnoredBookList().count()-1; i>=0; i--) {
5317 String text = ignore.getIgnoredBookList().takeItem(i).text();
5318 for (int j=0; j<notebooks.size(); j++) {
5319 if (notebooks.get(j).getName().equalsIgnoreCase(text)) {
5320 Notebook n = notebooks.get(j);
5321 conn.getSyncTable().addRecord("IGNORENOTEBOOK-"+n.getGuid(), n.getGuid());
5323 newNotebooks.add(n.getGuid());
5328 // Clear out old tags & add new ones
5329 List<String> oldIgnoreTags = conn.getSyncTable().getIgnoreRecords("TAG");
5330 for (int i=0; i<oldIgnoreTags.size(); i++) {
5331 conn.getSyncTable().deleteRecord("IGNORETAG-"+oldIgnoreTags.get(i));
5334 List<String> newTags = new ArrayList<String>();
5335 for (int i=ignore.getIgnoredTagList().count()-1; i>=0; i--) {
5336 String text = ignore.getIgnoredTagList().takeItem(i).text();
5337 for (int j=0; j<tags.size(); j++) {
5338 if (tags.get(j).getName().equalsIgnoreCase(text)) {
5339 Tag t = tags.get(j);
5340 conn.getSyncTable().addRecord("IGNORETAG-"+t.getGuid(), t.getGuid());
5341 newTags.add(t.getGuid());
5347 // Clear out old tags & add new ones
5348 List<String> oldIgnoreLinkedNotebooks = conn.getSyncTable().getIgnoreRecords("LINKEDNOTEBOOK");
5349 for (int i=0; i<oldIgnoreLinkedNotebooks.size(); i++) {
5350 conn.getSyncTable().deleteRecord("IGNORELINKEDNOTEBOOK-"+oldIgnoreLinkedNotebooks.get(i));
5353 List<String> newLinked = new ArrayList<String>();
5354 for (int i=ignore.getIgnoredLinkedNotebookList().count()-1; i>=0; i--) {
5355 String text = ignore.getIgnoredLinkedNotebookList().takeItem(i).text();
5356 for (int j=0; j<linkedNotebooks.size(); j++) {
5357 if (linkedNotebooks.get(j).getShareName().equalsIgnoreCase(text)) {
5358 LinkedNotebook t = linkedNotebooks.get(j);
5359 conn.getSyncTable().addRecord("IGNORELINKEDNOTEBOOK-"+t.getGuid(), t.getGuid());
5360 newLinked.add(t.getGuid());
5361 j=linkedNotebooks.size();
5366 conn.getNoteTable().expungeIgnoreSynchronizedNotes(newNotebooks, newTags, newLinked);
5372 //**********************************************************
5373 //**********************************************************
5374 //* XML Modifying methods
5375 //**********************************************************
5376 //**********************************************************
5377 // An error has happended fetching a resource. let the user know
5378 private void resourceErrorMessage() {
5382 QMessageBox.information(this, tr("DOUGH!!!"), tr("Well, this is embarrassing."+
5383 "\n\nSome attachments or images for this note appear to be missing from my database.\n"+
5384 "In a perfect world this wouldn't happen, but it has.\n" +
5385 "It is embarasing when a program like me, designed to save all your\n"+
5386 "precious data, has a problem finding data.\n\n" +
5387 "I guess life isn't fair, but I'll survive. Somehow...\n\n" +
5388 "In the mean time, I'm not going to let you make changes to this note.\n" +
5389 "Don't get angry. I'm doing it to prevent you from messing up\n"+
5390 "this note on the Evernote servers. Sorry."+
5391 "\n\nP.S. You might want to re-synchronize to see if it corrects this problem.\nWho knows, you might get lucky."));
5393 browserWindow.setReadOnly(true);
5400 //**********************************************************
5401 //**********************************************************
5403 //**********************************************************
5404 //**********************************************************
5405 // We should now do a sync with Evernote
5406 private void syncTimer() {
5407 logger.log(logger.EXTREME, "Entering NeverNote.syncTimer()");
5408 syncRunner.syncNeeded = true;
5409 syncRunner.disableUploads = Global.disableUploads;
5411 logger.log(logger.EXTREME, "Leaving NeverNote.syncTimer()");
5413 private void syncStart() {
5414 logger.log(logger.EXTREME, "Entering NeverNote.syncStart()");
5416 if (!syncRunning && Global.isConnected) {
5417 syncRunner.setConnected(true);
5418 syncRunner.setKeepRunning(Global.keepRunning);
5419 syncRunner.syncDeletedContent = Global.synchronizeDeletedContent();
5421 if (syncThreadsReady > 0) {
5422 thumbnailRunner.interrupt = true;
5423 saveNoteIndexWidth();
5424 saveNoteColumnPositions();
5425 if (syncRunner.addWork("SYNC")) {
5427 syncRunner.syncNeeded = true;
5432 logger.log(logger.EXTREME, "Leaving NeverNote.syncStart");
5434 @SuppressWarnings("unused")
5435 private void syncThreadComplete(Boolean refreshNeeded) {
5436 setMessage(tr("Finalizing Synchronization"));
5438 syncRunning = false;
5439 syncRunner.syncNeeded = false;
5440 synchronizeAnimationTimer.stop();
5441 synchronizeButton.setIcon(new QIcon(iconPath+"synchronize.png"));
5443 if (currentNote == null) {
5444 currentNote = conn.getNoteTable().getNote(currentNoteGuid, false, false, false, false, true);
5446 listManager.setUnsynchronizedNotes(conn.getNoteTable().getUnsynchronizedGUIDs());
5447 noteIndexUpdated(false);
5448 noteTableView.selectionModel().blockSignals(true);
5449 scrollToGuid(currentNoteGuid);
5450 noteTableView.selectionModel().blockSignals(false);
5451 refreshEvernoteNote(false);
5452 scrollToGuid(currentNoteGuid);
5455 // Check to see if there were any shared notebook errors
5456 if (syncRunner.error && syncRunner.errorSharedNotebooks.size() > 0) {
5457 String guid = syncRunner.errorSharedNotebooks.get(0);
5458 String notebookGuid = conn.getLinkedNotebookTable().getLocalNotebookGuid(guid);
5459 String localName = listManager.getNotebookNameByGuid(notebookGuid);
5460 SharedNotebookSyncError syncDialog = new SharedNotebookSyncError(localName);
5462 if (syncDialog.okPressed()) {
5463 if (syncDialog.doNothing.isChecked()) {
5464 syncRunner.errorSharedNotebooksIgnored.put(guid, guid);
5467 if (syncDialog.deleteNotebook.isChecked()) {
5468 conn.getNoteTable().expungeNotesByNotebook(notebookGuid, true, false);
5469 conn.getNotebookTable().expungeNotebook(notebookGuid, false);
5470 conn.getLinkedNotebookTable().expungeNotebook(guid, false);
5471 conn.getLinkedNotebookTable().expungeNotebook(guid, false);
5474 /* if (syncDialog.convertToLocal.isChecked()) {
5475 conn.getNotebookTable().convertFromSharedNotebook(notebookGuid, true);
5476 conn.getLinkedNotebookTable().expungeNotebook(guid, false);
5479 if (syncDialog.convertToShared.isChecked()) {
5480 conn.getLinkedNotebookTable().expungeNotebook(guid, false);
5481 conn.getNotebookTable().convertFromSharedNotebook(notebookGuid, false);
5489 // Finalize the synchronization
5490 if (!syncRunner.error)
5491 setMessage(tr("Synchronization Complete"));
5493 setMessage(tr("Synchronization completed with errors. Please check the log for details."));
5494 logger.log(logger.MEDIUM, "Sync complete.");
5496 public void saveUploadAmount(long t) {
5497 Global.saveUploadAmount(t);
5499 public void saveUserInformation(User user) {
5500 Global.saveUserInformation(user);
5502 public void saveEvernoteUpdateCount(int i) {
5503 Global.saveEvernoteUpdateCount(i);
5505 public void refreshLists() {
5506 logger.log(logger.EXTREME, "Entering NeverNote.refreshLists");
5508 listManager.refreshLists(currentNote, noteDirty, browserWindow.getContent());
5509 tagIndexUpdated(true);
5510 notebookIndexUpdated();
5511 savedSearchIndexUpdated();
5512 listManager.loadNotesIndex();
5514 noteTableView.selectionModel().blockSignals(true);
5515 noteIndexUpdated(true);
5516 noteTableView.selectionModel().blockSignals(false);
5517 logger.log(logger.EXTREME, "Leaving NeverNote.refreshLists");
5521 @SuppressWarnings("unused")
5522 private void authTimer() {
5523 Calendar cal = Calendar.getInstance();
5525 // If we are not connected let's get out of here
5526 if (!Global.isConnected)
5529 // If this is the first time through, then we need to set this
5530 // if (syncRunner.authRefreshTime == 0 || cal.getTimeInMillis() > syncRunner.authRefreshTime)
5531 // syncRunner.authRefreshTime = cal.getTimeInMillis();
5533 // long now = new Date().getTime();
5534 // if (now > Global.authRefreshTime && Global.isConnected) {
5535 syncRunner.authRefreshNeeded = true;
5539 @SuppressWarnings("unused")
5540 private void authRefreshComplete(boolean goodSync) {
5541 logger.log(logger.EXTREME, "Entering NeverNote.authRefreshComplete");
5542 Global.isConnected = syncRunner.isConnected;
5544 // authTimer.start((int)syncRunner.authTimeRemaining/4);
5545 authTimer.start(1000*60*15);
5546 logger.log(logger.LOW, "Authentication token has been renewed");
5547 // setMessage("Authentication token has been renewed.");
5549 authTimer.start(1000*60*5);
5550 logger.log(logger.LOW, "Authentication token renew has failed - retry in 5 minutes.");
5551 // setMessage("Authentication token renew has failed - retry in 5 minutes.");
5553 logger.log(logger.EXTREME, "Leaving NeverNote.authRefreshComplete");
5557 @SuppressWarnings("unused")
5558 private synchronized void indexTimer() {
5559 logger.log(logger.EXTREME, "Index timer activated. Sync running="+syncRunning);
5562 if (!indexDisabled && indexRunner.idle) {
5563 thumbnailRunner.interrupt = true;
5564 indexRunner.addWork("SCAN");
5566 logger.log(logger.EXTREME, "Leaving neverNote index timer");
5569 @SuppressWarnings("unused")
5570 private void indexStarted() {
5571 setMessage(tr("Indexing notes"));
5573 @SuppressWarnings("unused")
5574 private void indexComplete() {
5575 setMessage(tr("Index complete"));
5577 @SuppressWarnings("unused")
5578 private synchronized void toggleNoteIndexing() {
5579 logger.log(logger.HIGH, "Entering NeverNote.toggleIndexing");
5580 indexDisabled = !indexDisabled;
5582 setMessage(tr("Indexing is now enabled."));
5584 setMessage(tr("Indexing is now disabled."));
5585 menuBar.disableIndexing.setChecked(indexDisabled);
5586 logger.log(logger.HIGH, "Leaving NeverNote.toggleIndexing");
5589 @SuppressWarnings("unused")
5590 private void threadMonitorCheck() {
5595 alive = listManager.threadCheck(Global.tagCounterThreadId);
5598 if (tagDeadCount > MAX && !disableTagThreadCheck) {
5599 QMessageBox.information(this, tr("A thread has died."), tr("It appears as the tag counter thread has died. I recommend "+
5600 "checking stopping NeverNote, saving the logs for later viewing, and restarting. Sorry."));
5601 disableTagThreadCheck = true;
5606 alive = listManager.threadCheck(Global.notebookCounterThreadId);
5608 notebookThreadDeadCount++;
5609 if (notebookThreadDeadCount > MAX && !disableNotebookThreadCheck) {
5610 QMessageBox.information(this, tr("A thread has died."), tr("It appears as the notebook counter thread has died. I recommend "+
5611 "checking stopping NeverNote, saving the logs for later viewing, and restarting. Sorry."));
5612 disableNotebookThreadCheck=true;
5615 notebookThreadDeadCount=0;
5617 alive = listManager.threadCheck(Global.trashCounterThreadId);
5620 if (trashDeadCount > MAX && !disableTrashThreadCheck) {
5621 QMessageBox.information(this, tr("A thread has died."), ("It appears as the trash counter thread has died. I recommend "+
5622 "checking stopping NeverNote, saving the logs for later viewing, and restarting. Sorry."));
5623 disableTrashThreadCheck = true;
5628 alive = listManager.threadCheck(Global.saveThreadId);
5630 saveThreadDeadCount++;
5631 if (saveThreadDeadCount > MAX && !disableSaveThreadCheck) {
5632 QMessageBox.information(this, tr("A thread has died."), tr("It appears as the note saver thread has died. I recommend "+
5633 "checking stopping NeverNote, saving the logs for later viewing, and restarting. Sorry."));
5634 disableSaveThreadCheck = true;
5637 saveThreadDeadCount=0;
5639 if (!syncThread.isAlive()) {
5640 syncThreadDeadCount++;
5641 if (syncThreadDeadCount > MAX && !disableSyncThreadCheck) {
5642 QMessageBox.information(this, tr("A thread has died."), tr("It appears as the synchronization thread has died. I recommend "+
5643 "checking stopping NeverNote, saving the logs for later viewing, and restarting. Sorry."));
5644 disableSyncThreadCheck = true;
5647 syncThreadDeadCount=0;
5649 if (!indexThread.isAlive()) {
5650 indexThreadDeadCount++;
5651 if (indexThreadDeadCount > MAX && !disableIndexThreadCheck) {
5652 QMessageBox.information(this, tr("A thread has died."), tr("It appears as the index thread has died. I recommend "+
5653 "checking stopping NeverNote, saving the logs for later viewing, and restarting. Sorry."));
5654 disableIndexThreadCheck = true;
5657 indexThreadDeadCount=0;
5662 private void thumbnailTimer() {
5663 if (Global.enableThumbnails() && !syncRunning && indexRunner.idle) {
5664 thumbnailRunner.addWork("SCAN");
5668 //**************************************************
5669 //* Backup & Restore
5670 //**************************************************
5671 @SuppressWarnings("unused")
5672 private void databaseBackup() {
5673 QFileDialog fd = new QFileDialog(this);
5674 fd.setFileMode(FileMode.AnyFile);
5675 fd.setConfirmOverwrite(true);
5676 fd.setWindowTitle(tr("Backup Database"));
5677 fd.setFilter(tr("NeverNote Export (*.nnex);;All Files (*.*)"));
5678 fd.setAcceptMode(AcceptMode.AcceptSave);
5679 if (saveLastPath == null || saveLastPath.equals(""))
5680 fd.setDirectory(System.getProperty("user.home"));
5682 fd.setDirectory(saveLastPath);
5683 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
5689 saveLastPath = fd.selectedFiles().get(0);
5690 saveLastPath = saveLastPath.substring(0,saveLastPath.lastIndexOf("/"));
5691 setMessage(tr("Backing up database"));
5693 // conn.backupDatabase(Global.getUpdateSequenceNumber(), Global.getSequenceDate());
5695 ExportData noteWriter = new ExportData(conn, true);
5696 String fileName = fd.selectedFiles().get(0);
5698 if (!fileName.endsWith(".nnex"))
5699 fileName = fileName +".nnex";
5700 noteWriter.exportData(fileName);
5701 setMessage(tr("Database backup completed."));
5706 @SuppressWarnings("unused")
5707 private void databaseRestore() {
5708 if (QMessageBox.question(this, tr("Confirmation"),
5709 tr("This is used to restore a database from backups.\n" +
5710 "It is HIGHLY recommened that this only be used to populate\n" +
5711 "an empty database. Restoring into a database that\n already has data" +
5712 " can cause problems.\n\nAre you sure you want to continue?"),
5713 QMessageBox.StandardButton.Yes,
5714 QMessageBox.StandardButton.No)==StandardButton.No.value()) {
5719 QFileDialog fd = new QFileDialog(this);
5720 fd.setFileMode(FileMode.ExistingFile);
5721 fd.setConfirmOverwrite(true);
5722 fd.setWindowTitle(tr("Restore Database"));
5723 fd.setFilter(tr("NeverNote Export (*.nnex);;All Files (*.*)"));
5724 fd.setAcceptMode(AcceptMode.AcceptOpen);
5725 if (saveLastPath == null || saveLastPath.equals(""))
5726 fd.setDirectory(System.getProperty("user.home"));
5728 fd.setDirectory(saveLastPath);
5729 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
5735 saveLastPath = fd.selectedFiles().get(0);
5736 saveLastPath = saveLastPath.substring(0,saveLastPath.lastIndexOf("/"));
5738 setMessage(tr("Restoring database"));
5739 ImportData noteReader = new ImportData(conn, true);
5740 noteReader.importData(fd.selectedFiles().get(0));
5742 if (noteReader.lastError != 0) {
5743 setMessage(noteReader.getErrorMessage());
5744 logger.log(logger.LOW, "Restore problem: " +noteReader.lastError);
5749 listManager.loadNoteTitleColors();
5751 refreshEvernoteNote(true);
5752 setMessage(tr("Database has been restored."));
5755 @SuppressWarnings("unused")
5756 private void exportNotes() {
5757 QFileDialog fd = new QFileDialog(this);
5758 fd.setFileMode(FileMode.AnyFile);
5759 fd.setConfirmOverwrite(true);
5760 fd.setWindowTitle(tr("Backup Database"));
5761 fd.setFilter(tr("NeverNote Export (*.nnex);;All Files (*.*)"));
5762 fd.setAcceptMode(AcceptMode.AcceptSave);
5763 fd.setDirectory(System.getProperty("user.home"));
5764 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
5770 setMessage(tr("Exporting Notes"));
5773 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
5774 selectedNoteGUIDs.add(currentNoteGuid);
5776 ExportData noteWriter = new ExportData(conn, false, selectedNoteGUIDs);
5777 String fileName = fd.selectedFiles().get(0);
5779 if (!fileName.endsWith(".nnex"))
5780 fileName = fileName +".nnex";
5781 noteWriter.exportData(fileName);
5782 setMessage(tr("Export completed."));
5788 @SuppressWarnings("unused")
5789 private void importNotes() {
5790 QFileDialog fd = new QFileDialog(this);
5791 fd.setFileMode(FileMode.ExistingFile);
5792 fd.setConfirmOverwrite(true);
5793 fd.setWindowTitle(tr("Import Notes"));
5794 fd.setFilter(tr("NeverNote Export (*.nnex);;All Files (*.*)"));
5795 fd.setAcceptMode(AcceptMode.AcceptOpen);
5796 if (saveLastPath == null || saveLastPath.equals(""))
5797 fd.setDirectory(System.getProperty("user.home"));
5799 fd.setDirectory(saveLastPath);
5800 if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
5806 setMessage(tr("Importing Notes"));
5809 if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
5810 selectedNoteGUIDs.add(currentNoteGuid);
5812 ImportData noteReader = new ImportData(conn, false);
5813 String fileName = fd.selectedFiles().get(0);
5814 // saveLastPath.substring(0,fileName.lastIndexOf("/"));
5816 if (!fileName.endsWith(".nnex"))
5817 fileName = fileName +".nnex";
5818 if (selectedNotebookGUIDs != null && selectedNotebookGUIDs.size() > 0)
5819 noteReader.setNotebookGuid(selectedNotebookGUIDs.get(0));
5821 noteReader.setNotebookGuid(listManager.getNotebookIndex().get(0).getGuid());
5823 noteReader.importData(fileName);
5825 if (noteReader.lastError != 0) {
5826 setMessage(noteReader.getErrorMessage());
5827 logger.log(logger.LOW, "Import problem: " +noteReader.lastError);
5832 listManager.loadNoteTitleColors();
5834 refreshEvernoteNote(false);
5835 setMessage(tr("Notes have been imported."));
5838 setMessage(tr("Import completed."));
5845 //**************************************************
5846 //* Duplicate a note
5847 //**************************************************
5848 @SuppressWarnings("unused")
5849 private void duplicateNote() {
5851 duplicateNote(currentNoteGuid);
5854 //**************************************************
5855 //* Action from when a user clicks Copy As URL
5856 //**************************************************
5857 @SuppressWarnings("unused")
5858 private void copyAsUrlClicked() {
5859 QClipboard clipboard = QApplication.clipboard();
5860 QMimeData mime = new QMimeData();
5862 mime.setText(currentNoteGuid);
5863 List<QUrl> urls = new ArrayList<QUrl>();
5865 // Start building the URL
5866 User user = Global.getUserInformation();
5868 // Check that we have everything we need
5869 if ((user.getShardId().equals("") || user.getId() == 0) && !Global.bypassSynchronizationWarning()) {
5870 SynchronizationRequiredWarning warning = new SynchronizationRequiredWarning(this);
5872 if (!warning.neverSynchronize())
5875 Global.setBypassSynchronizationWarning(true);
5876 user.setShardId("s0");
5882 // Start building a list of URLs based upon the selected notes
5883 noteTableView.showColumn(Global.noteTableGuidPosition);
5885 List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
5886 if (!Global.isColumnVisible("guid"))
5887 noteTableView.hideColumn(Global.noteTableGuidPosition);
5889 // Check that the note is either synchronized, or in a local notebook
5890 for (int i=0; i<selections.size(); i++) {
5892 int row = selections.get(i).row();
5893 index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition);
5894 SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
5895 String selectedGuid = (String)ix.values().toArray()[0];
5897 Note n = conn.getNoteTable().getNote(selectedGuid, false, false, false, false, false);
5898 if (n.getUpdateSequenceNum() == 0 && !conn.getNotebookTable().isNotebookLocal(n.getNotebookGuid())) {
5899 QMessageBox.critical(this, tr("Please Synchronize") ,tr("Please either synchronize or move any " +
5900 "new notes to a local notebook."));
5905 // Start building the URLs
5906 for (int i=0; i<selections.size(); i++) {
5908 int row = selections.get(i).row();
5909 index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition);
5910 SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
5911 String selectedGuid = (String)ix.values().toArray()[0];
5912 mime.setText(selectedGuid);
5916 Note selectedNote = conn.getNoteTable().getNote(selectedGuid, false, false, false, false, false);
5917 if (selectedNote.getUpdateSequenceNum() > 0) {
5921 gid = "00000000-0000-0000-0000-000000000000";
5924 url = new String("evernote://///view/") + new String(user.getId() + "/" +user.getShardId() +"/"
5926 urls.add(new QUrl(url));
5929 clipboard.setMimeData(mime);
5933 //**************************************************
5935 //**************************************************
5936 public void setupFolderImports() {
5937 List<WatchFolderRecord> records = conn.getWatchFolderTable().getAll();
5939 if (importKeepWatcher == null)
5940 importKeepWatcher = new QFileSystemWatcher();
5941 if (importDeleteWatcher == null) {
5942 importDeleteWatcher = new QFileSystemWatcher();
5943 for (int i=0; i<records.size(); i++) {
5944 if (!records.get(i).keep)
5945 folderImportDelete(records.get(i).folder);
5951 // importKeepWatcher.addPath(records.get(i).folder.replace('\\', '/'));
5952 for (int i=0; i<records.size(); i++) {
5953 if (records.get(i).keep)
5954 importKeepWatcher.addPath(records.get(i).folder);
5956 importDeleteWatcher.addPath(records.get(i).folder);
5959 importKeepWatcher.directoryChanged.connect(this, "folderImportKeep(String)");
5960 importDeleteWatcher.directoryChanged.connect(this, "folderImportDelete(String)");
5962 // Look at the files already there so we don't import them again if a new file is created
5963 if (importedFiles == null) {
5964 importedFiles = new ArrayList<String>();
5965 for (int j=0; j<records.size(); j++) {
5966 QDir dir = new QDir(records.get(j).folder);
5967 List<QFileInfo> list = dir.entryInfoList();
5968 for (int k=0; k<list.size(); k++) {
5969 if (list.get(k).isFile())
5970 importedFiles.add(list.get(k).absoluteFilePath());
5975 public void folderImport() {
5976 List<WatchFolderRecord> recs = conn.getWatchFolderTable().getAll();
5977 WatchFolder dialog = new WatchFolder(recs, listManager.getNotebookIndex());
5979 if (!dialog.okClicked())
5982 // We have some sort of update.
5983 if (importKeepWatcher.directories().size() > 0)
5984 importKeepWatcher.removePaths(importKeepWatcher.directories());
5985 if (importDeleteWatcher.directories().size() > 0)
5986 importDeleteWatcher.removePaths(importDeleteWatcher.directories());
5988 conn.getWatchFolderTable().expungeAll();
5989 // Start building from the table
5990 for (int i=0; i<dialog.table.rowCount(); i++) {
5991 QTableWidgetItem item = dialog.table.item(i, 0);
5992 String dir = item.text();
5993 item = dialog.table.item(i, 1);
5994 String notebook = item.text();
5995 item = dialog.table.item(i, 2);
5997 if (item.text().equalsIgnoreCase("Keep"))
6002 String guid = conn.getNotebookTable().findNotebookByName(notebook);
6003 conn.getWatchFolderTable().addWatchFolder(dir, guid, keep, 0);
6005 setupFolderImports();
6008 public void folderImportKeep(String dirName) throws NoSuchAlgorithmException {
6010 String whichOS = System.getProperty("os.name");
6011 if (whichOS.contains("Windows"))
6012 dirName = dirName.replace('/','\\');
6014 FileImporter importer = new FileImporter(logger, conn);
6016 QDir dir = new QDir(dirName);
6017 List<QFileInfo> list = dir.entryInfoList();
6018 String notebook = conn.getWatchFolderTable().getNotebook(dirName);
6020 for (int i=0; i<list.size(); i++){
6022 boolean redundant = false;
6023 // Check if we've already imported this one or if it existed before
6024 for (int j=0; j<importedFiles.size(); j++) {
6025 if (importedFiles.get(j).equals(list.get(i).absoluteFilePath()))
6030 importer.setFileInfo(list.get(i));
6031 importer.setFileName(list.get(i).absoluteFilePath());
6034 if (list.get(i).isFile() && importer.isValidType()) {
6036 if (!importer.importFile()) {
6037 // If we can't get to the file, it is probably locked. We'll try again later.
6038 logger.log(logger.LOW, "Unable to save externally edited file. Saving for later.");
6039 importFilesKeep.add(list.get(i).absoluteFilePath());
6043 Note newNote = importer.getNote();
6044 newNote.setNotebookGuid(notebook);
6045 newNote.setTitle(dir.at(i));
6046 listManager.addNote(newNote);
6047 conn.getNoteTable().addNote(newNote, true);
6048 listManager.getUnsynchronizedNotes().add(newNote.getGuid());
6049 noteTableView.insertRow(newNote, true, -1);
6050 listManager.updateNoteContent(newNote.getGuid(), importer.getNoteContent());
6051 listManager.countNotebookResults(listManager.getNoteIndex());
6052 importedFiles.add(list.get(i).absoluteFilePath());
6060 public void folderImportDelete(String dirName) {
6062 String whichOS = System.getProperty("os.name");
6063 if (whichOS.contains("Windows"))
6064 dirName = dirName.replace('/','\\');
6066 FileImporter importer = new FileImporter(logger, conn);
6067 QDir dir = new QDir(dirName);
6068 List<QFileInfo> list = dir.entryInfoList();
6069 String notebook = conn.getWatchFolderTable().getNotebook(dirName);
6071 for (int i=0; i<list.size(); i++){
6072 importer.setFileInfo(list.get(i));
6073 importer.setFileName(list.get(i).absoluteFilePath());
6075 if (list.get(i).isFile() && importer.isValidType()) {
6077 if (!importer.importFile()) {
6078 // If we can't get to the file, it is probably locked. We'll try again later.
6079 logger.log(logger.LOW, "Unable to save externally edited file. Saving for later.");
6080 importFilesKeep.add(list.get(i).absoluteFilePath());
6084 Note newNote = importer.getNote();
6085 newNote.setNotebookGuid(notebook);
6086 newNote.setTitle(dir.at(i));
6087 listManager.addNote(newNote);
6088 conn.getNoteTable().addNote(newNote, true);
6089 listManager.getUnsynchronizedNotes().add(newNote.getGuid());
6090 noteTableView.insertRow(newNote, true, -1);
6091 listManager.updateNoteContent(newNote.getGuid(), importer.getNoteContent());
6092 listManager.countNotebookResults(listManager.getNoteIndex());
6093 dir.remove(dir.at(i));
6099 //**************************************************
6101 //**************************************************
6102 private void externalFileEdited(String fileName) throws NoSuchAlgorithmException {
6103 logger.log(logger.HIGH, "Entering exernalFileEdited");
6105 // Strip URL prefix and base dir path
6106 String dPath = FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath());
6107 String name = fileName.replace(dPath, "");
6108 int pos = name.lastIndexOf('.');
6111 guid = guid.substring(0,pos);
6113 pos = name.lastIndexOf(Global.attachmentNameDelimeter);
6115 guid = name.substring(0, pos);
6118 QFile file = new QFile(fileName);
6119 if (!file.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly))) {
6120 // If we can't get to the file, it is probably locked. We'll try again later.
6121 logger.log(logger.LOW, "Unable to save externally edited file. Saving for later.");
6122 externalFiles.add(fileName);
6125 QByteArray binData = file.readAll();
6127 if (binData.size() == 0) {
6128 // If we can't get to the file, it is probably locked. We'll try again later.
6129 logger.log(logger.LOW, "Unable to save externally edited file. Saving for later.");
6130 externalFiles.add(fileName);
6134 Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
6136 r = conn.getNoteTable().noteResourceTable.getNoteResource(Global.resourceMap.get(guid), true);
6137 if (r == null || r.getData() == null || r.getData().getBody() == null)
6139 String oldHash = Global.byteArrayToHexString(r.getData().getBodyHash());
6140 MessageDigest md = MessageDigest.getInstance("MD5");
6141 md.update(binData.toByteArray());
6142 byte[] hash = md.digest();
6143 String newHash = Global.byteArrayToHexString(hash);
6144 if (r.getNoteGuid().equalsIgnoreCase(currentNoteGuid)) {
6145 updateResourceContentHash(browserWindow, r.getGuid(), oldHash, newHash);
6147 if (externalWindows.containsKey(r.getNoteGuid())) {
6148 updateResourceContentHash(externalWindows.get(r.getNoteGuid()).getBrowserWindow(),
6149 r.getGuid(), oldHash, newHash);
6151 conn.getNoteTable().updateResourceContentHash(r.getNoteGuid(), oldHash, newHash);
6152 Data data = r.getData();
6153 data.setBody(binData.toByteArray());
6154 data.setBodyHash(hash);
6155 logger.log(logger.LOW, "externalFileEdited: " +data.getSize() +" bytes");
6157 conn.getNoteTable().noteResourceTable.updateNoteResource(r,true);
6159 if (r.getNoteGuid().equals(currentNoteGuid)) {
6160 QWebSettings.setMaximumPagesInCache(0);
6161 QWebSettings.setObjectCacheCapacities(0, 0, 0);
6162 refreshEvernoteNote(true);
6163 browserWindow.getBrowser().triggerPageAction(WebAction.Reload);
6166 if (externalWindows.containsKey(r.getNoteGuid())) {
6167 QWebSettings.setMaximumPagesInCache(0);
6168 QWebSettings.setObjectCacheCapacities(0, 0, 0);
6169 externalWindows.get(r.getNoteGuid()).getBrowserWindow().getBrowser().triggerPageAction(WebAction.Reload);
6173 logger.log(logger.HIGH, "Exiting externalFielEdited");
6175 // This is a timer event that tries to save any external files that were edited. This
6176 // is only needed if we couldn't save a file earlier.
6177 public void externalFileEditedSaver() {
6178 for (int i=externalFiles.size()-1; i>=0; i--) {
6180 logger.log(logger.MEDIUM, "Trying to save " +externalFiles.get(i));
6181 externalFileEdited(externalFiles.get(i));
6182 externalFiles.remove(i);
6183 } catch (NoSuchAlgorithmException e) {e.printStackTrace();}
6185 for (int i=0; i<importFilesKeep.size(); i++) {
6187 logger.log(logger.MEDIUM, "Trying to save " +importFilesKeep.get(i));
6188 folderImportKeep(importFilesKeep.get(i));
6189 importFilesKeep.remove(i);
6190 } catch (NoSuchAlgorithmException e) {e.printStackTrace();}
6192 for (int i=0; i<importFilesDelete.size(); i++) {
6193 logger.log(logger.MEDIUM, "Trying to save " +importFilesDelete.get(i));
6194 folderImportDelete(importFilesDelete.get(i));
6195 importFilesDelete.remove(i);
6202 // If an attachment on the current note was edited, we need to update the current notes's hash
6203 // Update a note content's hash. This happens if a resource is edited outside of NN
6204 public void updateResourceContentHash(BrowserWindow browser, String guid, String oldHash, String newHash) {
6205 int position = browserWindow.getContent().indexOf("en-tag=\"en-media\" guid=\""+guid+"\" type=");
6207 for (;position>-1;) {
6208 endPos = browser.getContent().indexOf(">", position+1);
6209 String oldSegment = browser.getContent().substring(position,endPos);
6210 int hashPos = oldSegment.indexOf("hash=\"");
6211 int hashEnd = oldSegment.indexOf("\"", hashPos+7);
6212 String hash = oldSegment.substring(hashPos+6, hashEnd);
6213 if (hash.equalsIgnoreCase(oldHash)) {
6214 String newSegment = oldSegment.replace(oldHash, newHash);
6215 String content = browser.getContent().substring(0,position) +
6217 browser.getContent().substring(endPos);
6218 browser.setContent(new QByteArray(content));;
6221 position = browser.getContent().indexOf("en-tag=\"en-media\" guid=\""+guid+"\" type=", position+1);
6226 //*************************************************
6227 //* Minimize to tray
6228 //*************************************************
6230 public void changeEvent(QEvent e) {
6231 if (e.type() == QEvent.Type.WindowStateChange) {
6232 if (isMinimized() && Global.showTrayIcon()) {
6234 QTimer.singleShot(10, this, "hide()");
6238 windowMaximized = true;
6240 windowMaximized = false;
6244 //*************************************************
6245 //* Check database userid & passwords
6246 //*************************************************
6247 private static boolean databaseCheck(String url,String userid, String userPassword, String cypherPassword) {
6248 Connection connection;
6251 Class.forName("org.h2.Driver");
6252 } catch (ClassNotFoundException e1) {
6253 e1.printStackTrace();
6258 String passwordString = null;
6259 if (cypherPassword==null || cypherPassword.trim().equals(""))
6260 passwordString = userPassword;
6262 passwordString = cypherPassword+" "+userPassword;
6263 connection = DriverManager.getConnection(url,userid,passwordString);
6264 } catch (SQLException e) {
6269 } catch (SQLException e) {
6270 e.printStackTrace();
6275 //*************************************************
6276 //* View / Hide source HTML for a note
6277 //*************************************************
6278 public void viewSource() {
6279 browserWindow.showSource(menuBar.viewSource.isChecked());
6281 //*************************************************
6282 // Block the program. This is used for things
6283 // like async web calls.
6284 //*************************************************
6285 @SuppressWarnings("unused")
6286 private void blockApplication(BrowserWindow b) {
6287 // Block all signals
6291 blockTimer = new QTimer();
6292 blockTimer.setSingleShot(true);
6293 blockTimer.setInterval(15000);
6294 blockTimer.timeout.connect(this, "unblockApplication()");
6299 @SuppressWarnings("unused")
6300 private void unblockApplication() {
6302 if (blockingWindow != null && new GregorianCalendar().getTimeInMillis() > blockingWindow.unblockTime && blockingWindow.unblockTime != -1) {
6303 QMessageBox.critical(null, tr("No Response from CodeCogs") ,tr("Unable to contact CodeCogs for LaTeX formula."));
6304 blockingWindow.unblockTime = -1;
6305 blockingWindow.awaitingHttpResponse = false;
6307 blockingWindow = null;
6308 blockSignals(false);