OSDN Git Service

Add the ability to encrypt & decrypt the database more easily.
[neighbornote/NeighborNote.git] / src / cx / fbn / nevernote / NeverNote.java
index 24eadb2..30a5cc7 100644 (file)
@@ -26,6 +26,7 @@ import java.security.NoSuchAlgorithmException;
 import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.SQLException;
+import java.sql.Statement;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Calendar;
@@ -39,6 +40,7 @@ import java.util.SortedMap;
 import java.util.Vector;
 
 import org.apache.thrift.TException;
+import org.h2.tools.ChangeFileEncryption;
 
 import com.evernote.edam.error.EDAMNotFoundException;
 import com.evernote.edam.error.EDAMSystemException;
@@ -64,14 +66,17 @@ import com.trolltech.qt.core.QFileInfo;
 import com.trolltech.qt.core.QFileSystemWatcher;
 import com.trolltech.qt.core.QIODevice;
 import com.trolltech.qt.core.QIODevice.OpenModeFlag;
+import com.trolltech.qt.core.QLocale;
 import com.trolltech.qt.core.QModelIndex;
 import com.trolltech.qt.core.QSize;
 import com.trolltech.qt.core.QTemporaryFile;
 import com.trolltech.qt.core.QTextCodec;
 import com.trolltech.qt.core.QThreadPool;
 import com.trolltech.qt.core.QTimer;
+import com.trolltech.qt.core.QTranslator;
 import com.trolltech.qt.core.QUrl;
 import com.trolltech.qt.core.Qt;
+import com.trolltech.qt.core.Qt.ItemDataRole;
 import com.trolltech.qt.core.Qt.SortOrder;
 import com.trolltech.qt.core.Qt.WidgetAttribute;
 import com.trolltech.qt.gui.QAbstractItemView;
@@ -82,7 +87,6 @@ import com.trolltech.qt.gui.QCloseEvent;
 import com.trolltech.qt.gui.QColor;
 import com.trolltech.qt.gui.QComboBox;
 import com.trolltech.qt.gui.QComboBox.InsertPolicy;
-import com.trolltech.qt.gui.QCursor;
 import com.trolltech.qt.gui.QDesktopServices;
 import com.trolltech.qt.gui.QDialog;
 import com.trolltech.qt.gui.QFileDialog;
@@ -120,8 +124,12 @@ import com.trolltech.qt.xml.QDomDocument;
 import com.trolltech.qt.xml.QDomElement;
 import com.trolltech.qt.xml.QDomNodeList;
 
+import cx.fbn.nevernote.config.FileManager;
+import cx.fbn.nevernote.config.InitializationException;
+import cx.fbn.nevernote.config.StartupConfig;
 import cx.fbn.nevernote.dialog.AccountDialog;
 import cx.fbn.nevernote.dialog.ConfigDialog;
+import cx.fbn.nevernote.dialog.DBEncryptDialog;
 import cx.fbn.nevernote.dialog.DatabaseLoginDialog;
 import cx.fbn.nevernote.dialog.DatabaseStatus;
 import cx.fbn.nevernote.dialog.FindDialog;
@@ -145,15 +153,14 @@ import cx.fbn.nevernote.gui.TableView;
 import cx.fbn.nevernote.gui.TagTreeWidget;
 import cx.fbn.nevernote.gui.Thumbnailer;
 import cx.fbn.nevernote.gui.TrashTreeWidget;
-import cx.fbn.nevernote.signals.DBRunnerSignal;
 import cx.fbn.nevernote.sql.DatabaseConnection;
-import cx.fbn.nevernote.sql.runners.WatchFolderRecord;
-import cx.fbn.nevernote.threads.DBRunner;
+import cx.fbn.nevernote.sql.WatchFolderRecord;
 import cx.fbn.nevernote.threads.IndexRunner;
 import cx.fbn.nevernote.threads.SyncRunner;
 import cx.fbn.nevernote.utilities.AESEncrypter;
 import cx.fbn.nevernote.utilities.ApplicationLogger;
 import cx.fbn.nevernote.utilities.FileImporter;
+import cx.fbn.nevernote.utilities.FileUtils;
 import cx.fbn.nevernote.utilities.ListManager;
 import cx.fbn.nevernote.utilities.SyncTimes;
 import cx.fbn.nevernote.xml.ExportData;
@@ -184,7 +191,7 @@ public class NeverNote extends QMainWindow{
     TableView                          noteTableView;                          //      List of notes (the widget).
 
     public BrowserWindow       browserWindow;                          // Window containing browser & labels
-    QToolBar                           toolBar;                                        // The tool bar under the menu
+    public QToolBar            toolBar;                                        // The tool bar under the menu
 //    QLineEdit                                searchField;                            // The search filter bar on the toolbar
     QComboBox                          searchField;                            // search filter bar on the toolbar;
     boolean                                    searchPerformed = false;        // Search was done?
@@ -202,7 +209,6 @@ public class NeverNote extends QMainWindow{
     boolean                                    noteDirty;                                      // Has the note been changed?
     boolean                            inkNote;                    // if this is an ink note, it is read only
   
-    QThread                                    dbThread;                                       // Thread to handle DB communication
     ListManager                                listManager;                                    // DB runnable task
     
     List<QTemporaryFile>       tempFiles;                                      // Array of temporary files;
@@ -277,6 +283,9 @@ public class NeverNote extends QMainWindow{
     String                             trashNoteGuid;                          // Guid to restore / set into or out of trash to save position
     Thumbnailer                        preview;                                        // generate preview image
     ThumbnailViewer            thumbnailViewer;                        // View preview thumbnail; 
+    boolean                            encryptOnShutdown;                      // should I encrypt when I close?
+    boolean                            decryptOnShutdown;                      // should I decrypt on shutdown;
+    String                             encryptCipher;                          // What cipher should I use?
     
     String iconPath = new String("classpath:cx/fbn/nevernote/icons/");
        
@@ -287,42 +296,20 @@ public class NeverNote extends QMainWindow{
     //***************************************************************
     //***************************************************************
     // Application Constructor 
-       public NeverNote()  {
-                               
-               if (!lockApplication()) {
-                       System.exit(0);
-               }
+       public NeverNote(DatabaseConnection dbConn)  {
+               conn = dbConn;          
+
                thread().setPriority(Thread.MAX_PRIORITY);
                
                logger = new ApplicationLogger("nevernote.log");
-               logger.log(logger.HIGH, tr("Starting Application"));
-               conn = new DatabaseConnection(logger, Global.mainThreadId);
-               conn.dbSetup();
-               
-               logger.log(logger.EXTREME, tr("Creating index connection"));    
-               logger.log(logger.EXTREME, tr("Building DB thread"));
-               Global.dbRunnerSignal = new DBRunnerSignal();
-               if (Global.getDatabaseUrl().toUpperCase().indexOf("CIPHER=") > -1) {
-                       boolean goodCheck = false;
-                       while (!goodCheck) {
-                               DatabaseLoginDialog dialog = new DatabaseLoginDialog();
-                               dialog.exec();
-                               if (!dialog.okPressed())
-                                       System.exit(0);
-                               Global.cipherPassword = dialog.getPassword();
-                               goodCheck = databaseCheck(Global.getDatabaseUrl(), Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
-                       }
-               }
-               Global.dbRunner = new DBRunner(Global.getDatabaseUrl(), Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
-               logger.log(logger.EXTREME, tr("Starting DB thread"));
-               dbThread = new QThread(Global.dbRunner, "Database Thread");
-               dbThread.start();
-               logger.log(logger.EXTREME, tr("DB Thread has started"));
-               Global.dbRunnerSignal.start.emit();
-               logger.log(logger.EXTREME, tr("Setting main thread DB connection"));
-               logger.log(logger.EXTREME, tr("main DB thread setup complete."));
+               logger.log(logger.HIGH, "Starting Application");
+               
+               decryptOnShutdown = false;
+               encryptOnShutdown = false;
                conn.checkDatabaseVersion();
                
+               
+               
                // Start building the invalid XML tables
                Global.invalidElements = conn.getInvalidXMLTable().getInvalidElements();
                List<String> elements = conn.getInvalidXMLTable().getInvalidAttributeElements();
@@ -331,7 +318,16 @@ public class NeverNote extends QMainWindow{
                        Global.invalidAttributes.put(elements.get(i), conn.getInvalidXMLTable().getInvalidAttributes(elements.get(i)));
                }
                
-               logger.log(logger.EXTREME, tr("Starting GUI build"));
+               logger.log(logger.EXTREME, "Starting GUI build");
+
+               QTranslator qtTranslator = new QTranslator();
+               qtTranslator.load("classpath:/translations/qt_" + QLocale.system().name() + ".qm");
+               QApplication.instance().installTranslator(qtTranslator);
+
+               QTranslator nevernoteTranslator = new QTranslator();
+               nevernoteTranslator.load("classpath:/translations/nevernote_"+QLocale.system().name()+ ".qm");
+               QApplication.instance().installTranslator(nevernoteTranslator);
+
                Global.originalPalette = QApplication.palette();
                QApplication.setStyle(Global.getStyle());
                if (Global.useStandardPalette())
@@ -351,11 +347,11 @@ public class NeverNote extends QMainWindow{
         indexRunnerCount = 1;
         QThreadPool.globalInstance().setMaxThreadCount(indexRunnerCount+5);    // increase max thread count
 
-               logger.log(logger.EXTREME, tr("Building list manager"));
-        listManager = new ListManager(conn, logger, Global.mainThreadId);
+               logger.log(logger.EXTREME, "Building list manager");
+        listManager = new ListManager(conn, logger);
         
-               logger.log(logger.EXTREME, tr("Building index runners & timers"));
-        indexRunner = new IndexRunner("indexRunner.log");
+               logger.log(logger.EXTREME, "Building index runners & timers");
+        indexRunner = new IndexRunner("indexRunner.log", Global.getDatabaseUrl(), Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
                indexThread = new QThread(indexRunner, "Index Thread");
                indexThread.start();
                
@@ -363,16 +359,15 @@ public class NeverNote extends QMainWindow{
         synchronizeAnimationTimer.timeout.connect(this, "updateSyncButton()");
         
                indexTimer = new QTimer();
-               indexTime = 1000*60*5;     // look for unindexed every 5 minutes
-//             indexTime = 1000*5;
+               indexTime = 1000*Global.getIndexThreadSleepInterval();  
                indexTimer.start(indexTime);  // Start indexing timer
                indexTimer.timeout.connect(this, "indexTimer()");
                indexDisabled = false;
                indexRunning = false;
                                
-               logger.log(logger.EXTREME, tr("Setting sync thread & timers"));
+               logger.log(logger.EXTREME, "Setting sync thread & timers");
                syncThreadsReady=1;
-               syncRunner = new SyncRunner("syncRunner.log");
+               syncRunner = new SyncRunner("syncRunner.log", Global.getDatabaseUrl(), Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
                syncTime = new SyncTimes().timeValue(Global.getSyncInterval());
                syncTimer = new QTimer();
                syncTimer.timeout.connect(this, "syncTimer()");
@@ -392,13 +387,13 @@ public class NeverNote extends QMainWindow{
                syncThread.start();
                
                
-               logger.log(logger.EXTREME, tr("Starting authentication timer"));
+               logger.log(logger.EXTREME, "Starting authentication timer");
                authTimer = new QTimer();
                authTimer.timeout.connect(this, "authTimer()");
                authTimer.start(1000*60*15);
                syncRunner.syncSignal.authRefreshComplete.connect(this, "authRefreshComplete(boolean)");
                
-               logger.log(logger.EXTREME, tr("Setting save note timer"));
+               logger.log(logger.EXTREME, "Setting save note timer");
                saveTimer = new QTimer();
                saveTimer.timeout.connect(this, "saveNote()");
                if (Global.getAutoSaveInterval() > 0) {
@@ -406,9 +401,9 @@ public class NeverNote extends QMainWindow{
 //                     saveTimer.setInterval(1000*10); // auto save every 20 seconds;
                        saveTimer.start();
                }
+               listManager.saveRunner.noteSignals.noteSaveRunnerError.connect(this, "saveRunnerError(String, String)");
                
-//             Global.trace();
-               logger.log(logger.EXTREME, tr("Starting external file monitor timer"));
+               logger.log(logger.EXTREME, "Starting external file monitor timer");
                externalFileSaveTimer = new QTimer();
                externalFileSaveTimer.timeout.connect(this, "externalFileEditedSaver()");
                externalFileSaveTimer.setInterval(1000*5);   // save every 5 seconds;
@@ -422,7 +417,7 @@ public class NeverNote extends QMainWindow{
         tagTree = new TagTreeWidget(conn);
         savedSearchTree = new SavedSearchTreeWidget();
         trashTree = new TrashTreeWidget();
-        noteTableView = new TableView(logger);
+        noteTableView = new TableView(logger, listManager);
         
         QGridLayout leftGrid = new QGridLayout();
         leftSplitter1.setLayout(leftGrid);
@@ -615,21 +610,31 @@ public class NeverNote extends QMainWindow{
                QApplication.initialize(args);
                QPixmap pixmap = new QPixmap("classpath:cx/fbn/nevernote/icons/splash_logo.png");
                QSplashScreen splash = new QSplashScreen(pixmap);
-                       
-               for (String arg : args) {
-                       String lower = arg.toLowerCase();
-                       if (lower.startsWith("--name="))
-                               Global.setName(arg.substring(arg.indexOf('=')+1));
-                       if (lower.startsWith("--home="))
-                               Global.currentDir = arg.substring(arg.indexOf('=')+1);
-                       if (lower.startsWith("--disable-viewing"))
-                               Global.disableViewing = true;
-               }
-               Global.setup();
-               boolean showSplash = Global.isWindowVisible("SplashScreen");
-               if (showSplash) 
-                       splash.show();
-               NeverNote application = new NeverNote();
+               boolean showSplash;
+               
+               DatabaseConnection dbConn;
+
+        try {
+            initializeGlobalSettings(args);
+
+            showSplash = Global.isWindowVisible("SplashScreen");
+            if (showSplash)
+                splash.show();
+
+            dbConn = setupDatabaseConnection();
+
+            // Must be last stage of setup - only safe once DB is open hence we know we are the only instance running
+            Global.getFileManager().purgeResDirectory();
+
+        } catch (InitializationException e) {
+            // Fatal
+            e.printStackTrace();
+            QMessageBox.critical(null, "Startup error", "Aborting: " + e.getMessage());
+            return;
+        }
+
+        NeverNote application = new NeverNote(dbConn);
+
                application.setAttribute(WidgetAttribute.WA_DeleteOnClose, true);
                if (Global.wasWindowMaximized())
                        application.showMaximized();
@@ -641,7 +646,131 @@ public class NeverNote extends QMainWindow{
                System.out.println("Goodbye.");
                QApplication.exit();
        }
-       // Exit point
+
+    /**
+     * Open the internal database, or create if not present
+     *
+     * @throws InitializationException when opening the database fails, e.g. because another process has it locked
+     */
+    private static DatabaseConnection setupDatabaseConnection() throws InitializationException {
+       ApplicationLogger logger = new ApplicationLogger("nevernote-database.log");
+       
+       File f = Global.getFileManager().getDbDirFile(Global.databaseName + ".h2.db");
+               boolean dbExists = f.exists(); 
+               if (!dbExists)
+                       Global.setDatabaseUrl("");
+       
+        if (Global.getDatabaseUrl().toUpperCase().indexOf("CIPHER=") > -1) {
+            boolean goodCheck = false;
+            while (!goodCheck) {
+                DatabaseLoginDialog dialog = new DatabaseLoginDialog();
+                dialog.exec();
+                if (!dialog.okPressed())
+                    System.exit(0);
+                Global.cipherPassword = dialog.getPassword();
+                goodCheck = databaseCheck(Global.getDatabaseUrl(), Global.getDatabaseUserid(),
+                        Global.getDatabaseUserPassword(), Global.cipherPassword);
+            }
+        }
+               DatabaseConnection dbConn = new DatabaseConnection(logger,Global.getDatabaseUrl(), Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
+       return dbConn;
+    }
+    
+    // Encrypt the database upon shutdown
+    private void encryptOnShutdown() {
+        String dbPath= Global.getFileManager().getDbDirPath("");
+        String dbName = "NeverNote";
+        try {
+               Statement st = conn.getConnection().createStatement();  
+               st.execute("shutdown");
+               QMessageBox box = new QMessageBox();
+                       box.setText("Encrypting Database");
+                       box.show();
+                       ChangeFileEncryption.execute(dbPath, dbName, encryptCipher, null, Global.cipherPassword.toCharArray(), true);
+                       Global.setDatabaseUrl(Global.getDatabaseUrl() + ";CIPHER="+encryptCipher);
+                       box.setText("Encryption Complete");
+                       box.close();
+        } catch (SQLException e) {
+                       e.printStackTrace();
+               }       
+    }
+    
+    // Decrypt the database upon shutdown
+    private void decryptOnShutdown() {
+        String dbPath= Global.getFileManager().getDbDirPath("");
+        String dbName = "NeverNote";
+        try {
+               Statement st = conn.getConnection().createStatement();  
+               st.execute("shutdown");
+               if (Global.getDatabaseUrl().toUpperCase().indexOf(";CIPHER=AES") > -1)
+                       encryptCipher = "AES";
+               else
+                       encryptCipher = "XTEA";
+               QMessageBox box = new QMessageBox();
+                       box.setText("Decrypting Database");
+                       box.show();
+                       ChangeFileEncryption.execute(dbPath, dbName, encryptCipher, Global.cipherPassword.toCharArray(), null, true);
+                       Global.setDatabaseUrl("");
+                       box.setText("Decryption Complete");
+                       box.close();
+               } catch (SQLException e) {
+                       e.printStackTrace();
+               }       
+    }
+    /**
+     * Encrypt/Decrypt the local database
+     **/
+    public void doDatabaseEncrypt() {
+       // The database is not currently encrypted
+        if (Global.getDatabaseUrl().toUpperCase().indexOf("CIPHER=") == -1) {
+               if (QMessageBox.question(this, tr("Confirmation"), tr("Encrypting the database is used" +
+                               "to enhance security and is performed\nupon shutdown, but please be aware that if"+
+                               " you lose the password your\nis lost forever.\n\nIt is highly recommended you " +
+                               "perform a backup and/or fully synchronize\n prior to executing this funtction.\n\n" +
+                               "Do you wish to proceed?"),
+                               QMessageBox.StandardButton.Yes, 
+                               QMessageBox.StandardButton.No)==StandardButton.No.value()) {
+                               return;
+               }
+               DBEncryptDialog dialog = new DBEncryptDialog();
+               dialog.exec();
+               if (dialog.okPressed()) {
+                       Global.cipherPassword = dialog.getPassword();
+                       encryptOnShutdown  = true;
+                       encryptCipher = "AES";
+               }
+        } else {
+            DBEncryptDialog dialog = new DBEncryptDialog();
+            dialog.setWindowTitle("Database Decryption");
+            dialog.exec();
+            if (dialog.okPressed()) {
+               if (!dialog.getPassword().equals(Global.cipherPassword)) {
+                       QMessageBox.critical(null, "Incorrect Password", "Incorrect Password");
+                       return;
+               }
+               decryptOnShutdown  = true;
+               encryptCipher = "";
+            }
+        }
+        return;
+    }
+
+       private static void initializeGlobalSettings(String[] args) throws InitializationException {
+               StartupConfig   startupConfig = new StartupConfig();
+
+        for (String arg : args) {
+            String lower = arg.toLowerCase();
+            if (lower.startsWith("--name="))
+               startupConfig.setName(arg.substring(arg.indexOf('=') + 1));
+            if (lower.startsWith("--home="))
+               startupConfig.setHomeDirPath(arg.substring(arg.indexOf('=') + 1));
+            if (lower.startsWith("--disable-viewing"))
+               startupConfig.setDisableViewing(true);
+        }
+                Global.setup(startupConfig);
+    }
+
+    // Exit point
        @Override
        public void closeEvent(QCloseEvent event) {     
                logger.log(logger.HIGH, "Entering NeverNote.closeEvent");
@@ -652,11 +781,11 @@ public class NeverNote extends QMainWindow{
                                conn.getNoteTable().updateNoteTitle(currentNote.getGuid(), browserWindow.getTitle());
                }
                saveNote();
-               setMessage("Beginning shutdown.");
+               setMessage(tr("Beginning shutdown."));
 
                externalFileEditedSaver();
                if (Global.isConnected && Global.synchronizeOnClose()) {
-                       setMessage("Performing synchronization before closing.");
+                       setMessage(tr("Performing synchronization before closing."));
                        syncRunner.addWork("SYNC");
                }
                setMessage("Closing Program.");
@@ -701,7 +830,8 @@ public class NeverNote extends QMainWindow{
                Global.setColumnPosition("noteTableTitlePosition", position);
                position = noteTableView.header.visualIndex(Global.noteTableSynchronizedPosition);
                Global.setColumnPosition("noteTableSynchronizedPosition", position);
-               
+
+               Global.saveWindowVisible("toolBar", toolBar.isVisible());
                saveNoteIndexWidth();
                
                int width = notebookTree.columnWidth(0);
@@ -737,16 +867,12 @@ public class NeverNote extends QMainWindow{
                        }
                }
 
-               logger.log(logger.EXTREME, "Shutting down database");
-               conn.dbShutdown();
-               logger.log(logger.EXTREME, "Waiting for DB thread to terminate");
-               try {
-                       dbThread.join();
-               } catch (InterruptedException e) {
-                       e.printStackTrace();
+               if (encryptOnShutdown) {
+                       encryptOnShutdown();
+               }
+               if (decryptOnShutdown) {
+                       decryptOnShutdown();
                }
-               logger.log(logger.EXTREME, "DB Thread has terminated");
-               unlockApplication();
                logger.log(logger.HIGH, "Leaving NeverNote.closeEvent");
        }
 
@@ -759,10 +885,10 @@ public class NeverNote extends QMainWindow{
        }
                
        private void waitCursor(boolean wait) {
-               if (wait)
-                       QApplication.setOverrideCursor(new QCursor(Qt.CursorShape.WaitCursor));
-               else
-                       QApplication.restoreOverrideCursor();
+//             if (wait)
+//                     QApplication.setOverrideCursor(new QCursor(Qt.CursorShape.WaitCursor));
+//             else
+//                     QApplication.restoreOverrideCursor();
        }
        
        private void setupIndexListeners() {
@@ -777,15 +903,14 @@ public class NeverNote extends QMainWindow{
         syncRunner.noteIndexSignal.listChanged.connect(this, "noteIndexUpdated(boolean)");
         syncRunner.noteSignal.quotaChanged.connect(this, "updateQuotaBar()");
         
-//             syncRunner.syncSignal.setSequenceDate.connect(this,"setSequenceDate(long)");
                syncRunner.syncSignal.saveUploadAmount.connect(this,"saveUploadAmount(long)");
-//             syncRunner.syncSignal.setUpdateSequenceNumber.connect(this,"setUpdateSequenceNumber(int)");
                syncRunner.syncSignal.saveUserInformation.connect(this,"saveUserInformation(User)");
                syncRunner.syncSignal.saveEvernoteUpdateCount.connect(this,"saveEvernoteUpdateCount(int)");
                
                syncRunner.noteSignal.guidChanged.connect(this, "noteGuidChanged(String, String)");
                syncRunner.noteSignal.noteChanged.connect(this, "invalidateNoteCache(String, String)");
                syncRunner.resourceSignal.resourceGuidChanged.connect(this, "noteResourceGuidChanged(String,String,String)");
+               syncRunner.noteSignal.noteDownloaded.connect(listManager, "noteDownloaded(Note)");
                
                syncRunner.syncSignal.refreshLists.connect(this, "refreshLists()");
        }
@@ -795,72 +920,21 @@ public class NeverNote extends QMainWindow{
                browserWindow.fileWatcher.fileChanged.connect(this, "externalFileEdited(String)");
                browserWindow.noteSignal.tagsChanged.connect(this, "updateNoteTags(String, List)");
            browserWindow.noteSignal.tagsChanged.connect(this, "updateListTags(String, List)");
-               browserWindow.noteSignal.noteChanged.connect(this, "invalidateNoteCache(String, String)");
+               //browserWindow.noteSignal.noteChanged.connect(this, "invalidateNoteCache(String, String)");
            browserWindow.noteSignal.noteChanged.connect(this, "setNoteDirty()");
            browserWindow.noteSignal.titleChanged.connect(listManager, "updateNoteTitle(String, String)");
-           browserWindow.noteSignal.titleChanged.connect(this, "updateListTitle(String, String)");
            browserWindow.noteSignal.notebookChanged.connect(this, "updateNoteNotebook(String, String)");
            browserWindow.noteSignal.createdDateChanged.connect(listManager, "updateNoteCreatedDate(String, QDateTime)");
-           browserWindow.noteSignal.createdDateChanged.connect(this, "updateListDateCreated(String, QDateTime)");
            browserWindow.noteSignal.alteredDateChanged.connect(listManager, "updateNoteAlteredDate(String, QDateTime)");
-           browserWindow.noteSignal.alteredDateChanged.connect(this, "updateListDateChanged(String, QDateTime)");
            browserWindow.noteSignal.subjectDateChanged.connect(listManager, "updateNoteSubjectDate(String, QDateTime)");
-           browserWindow.noteSignal.subjectDateChanged.connect(this, "updateListDateSubject(String, QDateTime)");
            browserWindow.noteSignal.authorChanged.connect(listManager, "updateNoteAuthor(String, String)");
-           browserWindow.noteSignal.authorChanged.connect(this, "updateListAuthor(String, String)");
+           browserWindow.noteSignal.geoChanged.connect(listManager, "updateNoteGeoTag(String, Double,Double,Double)");
+           browserWindow.noteSignal.geoChanged.connect(this, "setNoteDirty()");
            browserWindow.noteSignal.sourceUrlChanged.connect(listManager, "updateNoteSourceUrl(String, String)");
-           browserWindow.noteSignal.sourceUrlChanged.connect(this, "updateListSourceUrl(String, String)");
            browserWindow.focusLost.connect(this, "saveNote()");
            browserWindow.resourceSignal.contentChanged.connect(this, "externalFileEdited(String)");
-//         browserWindow.resourceSignal.externalFileEdit.connect(this, "saveResourceLater(String, String)");
        }
-       private boolean lockApplication() {
-                               
-               String fileName = Global.currentDir +"db" +File.separator +"NeverNote.lock.db";
-//             QFile.remove(fileName);
-               if (QFile.exists(fileName)) {
-                       QMessageBox.question(this, "Lock File Detected",
-                                       "While starting I've found a database lock file.\n" +
-                                       "to prevent multiple instances from accessing the database \n"+
-                                       "at the same time.  Please stop any other program, or (if you\n" +
-                                       "are sure nothing else is using the database) remove the file\n" +
-                                       fileName +".");
-                       return false;
-                       
-               }
-               return true;
-/*             String fileName = Global.currentDir +"nevernote.lock";
 
-               
-               if (QFile.exists(fileName)) {
-                       if (QMessageBox.question(this, "Confirmation",
-                               "While starting I've found a lock file.  This file is used to prevent multiple "+
-                               "instances of this program running at once.  If NeverNote has crashed this " +
-                               "is just a file that wasn't cleaned up and you can safely, "+
-                               "continue, but if there is another instance of this running you are " +
-                               "running the risk of creating problems.\n\n" +
-                               "Are you sure you want to continue?",
-                               QMessageBox.StandardButton.Yes, 
-                               QMessageBox.StandardButton.No)==StandardButton.No.value()) {
-                                       return false;
-                               }
-               }
-               
-               QFile file = new QFile(fileName);
-               file.open(OpenModeFlag.WriteOnly);
-               file.write(new QByteArray("This file is used to prevent multiple instances " +
-                               "of NeverNote running more than once.  " +
-                               "It should be deleted when NeverNote ends"));
-               file.close();
-               return true;
-*/
-       }
-       private void unlockApplication() {
-               String fileName = Global.currentDir +"nevernote.lock";
-               if (QFile.exists(fileName)) {
-                       QFile.remove(fileName);
-               }
-       }
        
 
        //***************************************************************
@@ -875,6 +949,9 @@ public class NeverNote extends QMainWindow{
         String dateFormat = Global.getDateFormat();
         String timeFormat = Global.getTimeFormat();
         
+               indexTime = 1000*Global.getIndexThreadSleepInterval();  
+               indexTimer.start(indexTime);  // reset indexing timer
+        
         settings.exec();
         if (Global.showTrayIcon())
                trayIcon.show();
@@ -923,7 +1000,7 @@ public class NeverNote extends QMainWindow{
        }    
        // Load the style sheet
        private void loadStyleSheet() {
-               String fileName = Global.currentDir +"qss"+System.getProperty("file.separator")+ "default.qss";
+               String fileName = Global.getFileManager().getQssDirPath("default.qss");
                QFile file = new QFile(fileName);
                file.open(OpenModeFlag.ReadOnly);
                String styleSheet = file.readAll().toString();
@@ -970,7 +1047,6 @@ public class NeverNote extends QMainWindow{
        logger.log(logger.HIGH, "Leaving NeverNote.initializeNotebookTree");
     }   
     // Listener when a notebook is selected
-    @SuppressWarnings("unused")
        private void notebookTreeSelection() {
                logger.log(logger.HIGH, "Entering NeverNote.notebookTreeSelection");
 
@@ -981,7 +1057,6 @@ public class NeverNote extends QMainWindow{
                        clearTagFilter();
                        searchField.clear();
                }
-               
                menuBar.noteRestoreAction.setVisible(false);            
        menuBar.notebookEditAction.setEnabled(true);
        menuBar.notebookDeleteAction.setEnabled(true);
@@ -1104,7 +1179,7 @@ public class NeverNote extends QMainWindow{
        private void editNotebook() {
                logger.log(logger.HIGH, "Entering NeverNote.editNotebook");
                NotebookEdit edit = new NotebookEdit();
-               edit.setTitle("Edit Notebook");
+               edit.setTitle(tr("Edit Notebook"));
                edit.setLocalCheckboxEnabled(false);
                List<QTreeWidgetItem> selections = notebookTree.selectedItems();
                QTreeWidgetItem currentSelection;
@@ -1164,18 +1239,18 @@ public class NeverNote extends QMainWindow{
                }
         }
                if (assigned) {
-                       QMessageBox.information(this, "Unable to Delete", "Some of the selected notebook(s) contain notes.\n"+
-                                       "Please delete the notes or move them to another notebook before deleting any notebooks.");
+                       QMessageBox.information(this, tr("Unable to Delete"), tr("Some of the selected notebook(s) contain notes.\n"+
+                                       "Please delete the notes or move them to another notebook before deleting any notebooks."));
                        return;
                }
                
                if (conn.getNotebookTable().getAll().size() == 1) {
-                       QMessageBox.information(this, "Unable to Delete", "You must have at least one notebook.");
+                       QMessageBox.information(this, tr("Unable to Delete"), tr("You must have at least one notebook."));
                        return;
                }
         
         // If all notebooks are clear, verify the delete
-               if (QMessageBox.question(this, "Confirmation", "Delete the selected notebooks?",
+               if (QMessageBox.question(this, tr("Confirmation"), tr("Delete the selected notebooks?"),
                        QMessageBox.StandardButton.Yes, 
                        QMessageBox.StandardButton.No)==StandardButton.No.value()) {
                        return;
@@ -1192,6 +1267,7 @@ public class NeverNote extends QMainWindow{
 //        for (int i=<dbRunner.getLocalNotebooks().size()-1; i>=0; i--) {
  //            if (dbRunner.getLocalNotebooks().get(i).equals(arg0))
  //       }
+        notebookTreeSelection();
         notebookTree.load(listManager.getNotebookIndex(), listManager.getLocalNotebooks());
         listManager.countNotebookResults(listManager.getNoteIndex());
 //             notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
@@ -1211,7 +1287,7 @@ public class NeverNote extends QMainWindow{
                for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
                        if (listManager.getNotebookIndex().get(i).getGuid().equals(notebookGuid)) {
                                notebookName = listManager.getNotebookIndex().get(i).getName();
-                               i=listManager.getNotebookIndex().size();
+                               break;
                        }
                }
                
@@ -1265,10 +1341,10 @@ public class NeverNote extends QMainWindow{
                                }
                        }
                }
-               
+               notebookTreeSelection();
                listManager.loadNotesIndex();
                notebookIndexUpdated();
-               noteIndexUpdated(true);
+               noteIndexUpdated(false);
 //             noteIndexUpdated(false);
                
                // Build a list of non-closed notebooks
@@ -1371,7 +1447,7 @@ public class NeverNote extends QMainWindow{
        private void deleteTag() {
                logger.log(logger.HIGH, "Entering NeverNote.deleteTag");
                
-               if (QMessageBox.question(this, "Confirmation", "Delete the selected tags?",
+               if (QMessageBox.question(this, tr("Confirmation"), tr("Delete the selected tags?"),
                        QMessageBox.StandardButton.Yes, 
                        QMessageBox.StandardButton.No)==StandardButton.No.value()) {
                                                        return;
@@ -1384,6 +1460,7 @@ public class NeverNote extends QMainWindow{
                removeTagItem(currentSelection.text(2));
         }
         tagIndexUpdated(true);
+        tagTreeSelection();
         listManager.countTagResults(listManager.getNoteIndex());
 //             tagTree.updateCounts(listManager.getTagCounter());
         logger.log(logger.HIGH, "Leaving NeverNote.deleteTag");
@@ -1415,14 +1492,9 @@ public class NeverNote extends QMainWindow{
        logger.log(logger.HIGH, "Leaving NeverNote.initializeTagTree");
     }
     // Listener when a tag is selected
-    @SuppressWarnings("unused")
        private void tagTreeSelection() {
        logger.log(logger.HIGH, "Entering NeverNote.tagTreeSelection");
-       
-       List<QTreeWidgetItem> x = tagTree.selectedItems();
-       for (int i=0; i<x.size(); i++) {
-       }
-       
+               
        clearTrashFilter();
        clearAttributeFilter();
        clearSavedSearchFilter();
@@ -1487,6 +1559,13 @@ public class NeverNote extends QMainWindow{
        // A note's tags have been updated
        @SuppressWarnings("unused")
        private void updateNoteTags(String guid, List<String> tags) {
+               // Save any new tags.  We'll need them later.
+               List<String> newTags = new ArrayList<String>();
+               for (int i=0; i<tags.size(); i++) {
+                       if (conn.getTagTable().findTagByName(tags.get(i))==null) 
+                               newTags.add(tags.get(i));
+               }
+               
                listManager.saveNoteTags(guid, tags);
                listManager.countTagResults(listManager.getNoteIndex());
                StringBuffer names = new StringBuffer("");
@@ -1498,7 +1577,10 @@ public class NeverNote extends QMainWindow{
                }
                browserWindow.setTag(names.toString());
                noteDirty = true;
-//             tagTree.updateCounts(listManager.getTagCounter());
+               
+               // Now, we need to add any new tags to the tag tree
+               for (int i=0; i<newTags.size(); i++) 
+                       tagTree.insertTag(newTags.get(i), conn.getTagTable().findTagByName(newTags.get(i)));
        }
        // Get a string containing all tag names for a note
        private String getTagNamesForNote(Note n) {
@@ -1541,25 +1623,31 @@ public class NeverNote extends QMainWindow{
                if (tagName == null)
                        return;
                
-               for (int i=0; i<noteTableView.model.rowCount(); i++) {
-                       QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
-                       if (modelIndex != null) {
-                               SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
-                               String titleGuid = (String)ix.values().toArray()[0];
-                               if (titleGuid.equals(noteGuid)) {
-                                       String text = (String)noteTableView.model.data(i, Global.noteTableTagPosition);
-                                       if (!text.trim().equals(""))
-                                               text = text + Global.tagDelimeter + " " +tagName;
-                                       else
-                                               text = tagName;
-                                       noteTableView.model.setData(i, Global.noteTableTagPosition, text);
-                                       noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
-                                       if (noteGuid.equals(currentNoteGuid))
-                                               browserWindow.setTag(text);
-                                       i=noteTableView.model.rowCount();
+               for (int i=0; i<listManager.getMasterNoteIndex().size(); i++) {
+                       if (listManager.getMasterNoteIndex().get(i).getGuid().equals(noteGuid)) {
+                               List<String> tagNames = new ArrayList<String>();
+                               tagNames.add(new String(tagName));
+                               Note n = listManager.getMasterNoteIndex().get(i);
+                               for (int j=0; j<n.getTagNames().size(); j++) {
+                                       tagNames.add(new String(n.getTagNames().get(j)));
+                               }
+                               listManager.getNoteTableModel().updateNoteTags(noteGuid, n.getTagGuids(), tagNames);
+                               if (n.getGuid().equals(currentNoteGuid)) {
+                                       Collections.sort(tagNames);
+                                       String display = "";
+                                       for (int j=0; j<tagNames.size(); j++) {
+                                               display = display+tagNames.get(j);
+                                               if (j+2<tagNames.size()) 
+                                                       display = display+Global.tagDelimeter+" ";
+                                       }
+                                       browserWindow.setTag(display);
                                }
+                               i=listManager.getMasterNoteIndex().size();
                        }
                }
+               
+               
+               listManager.getNoteTableModel().updateNoteSyncStatus(noteGuid, false);
        }
        private void clearTagFilter() {
                tagTree.blockSignals(true);
@@ -1609,7 +1697,7 @@ public class NeverNote extends QMainWindow{
        private void editSavedSearch() {
                logger.log(logger.HIGH, "Entering NeverNote.editSavedSearch");
                SavedSearchEdit edit = new SavedSearchEdit();
-               edit.setTitle("Edit Search");
+               edit.setTitle(tr("Edit Search"));
                List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
                QTreeWidgetItem currentSelection;
                currentSelection = selections.get(0);
@@ -1800,9 +1888,9 @@ public class NeverNote extends QMainWindow{
        @SuppressWarnings("unused")
        private void compactDatabase() {
        logger.log(logger.HIGH, "Entering NeverNote.compactDatabase");
-               if (QMessageBox.question(this, "Confirmation", "This will free unused space in the database, "+
+               if (QMessageBox.question(this, tr("Confirmation"), tr("This will free unused space in the database, "+
                                "but please be aware that depending upon the size of your database this can be time consuming " +
-                               "and NeverNote will be unresponsive until it is complete.  Do you wish to continue?",
+                               "and NeverNote will be unresponsive until it is complete.  Do you wish to continue?"),
                                QMessageBox.StandardButton.Yes, 
                                QMessageBox.StandardButton.No)==StandardButton.No.value() && Global.verifyDelete() == true) {
                                                        return;
@@ -1829,13 +1917,13 @@ public class NeverNote extends QMainWindow{
                QTextEdit textBox = new QTextEdit();
                layout.addWidget(textBox);
                textBox.setReadOnly(true);
-               QFile file = new QFile(Global.getDirectoryPath()+"release.txt");
+               QFile file = new QFile(Global.getFileManager().getHomeDirPath("release.txt"));
                if (!file.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly,
                 QIODevice.OpenModeFlag.Text)))
                        return;
                textBox.setText(file.readAll().toString());
                file.close();
-               dialog.setWindowTitle("Release Notes");
+               dialog.setWindowTitle(tr("Release Notes"));
                dialog.setLayout(layout);
                dialog.show();
                logger.log(logger.HIGH, "Leaving NeverNote.releaseNotes");
@@ -1851,7 +1939,7 @@ public class NeverNote extends QMainWindow{
                textBox.addItems(emitLog);
                
                dialog.setLayout(layout);
-               dialog.setWindowTitle("Mesasge Log");
+               dialog.setWindowTitle(tr("Mesasge Log"));
                dialog.show();
                logger.log(logger.HIGH, "Leaving NeverNote.logger");
        }
@@ -1861,14 +1949,18 @@ public class NeverNote extends QMainWindow{
                logger.log(logger.HIGH, "Entering NeverNote.about");
                QMessageBox.about(this, 
                                                tr("About NeverNote"),
-                                               tr("<h4><center><b>NeverNote</b></center></h4><hr><center>Version "+Global.version+"<hr></center>Evernote"
-                                                               +" Generic client.<br><br>" 
+                                               tr("<h4><center><b>NeverNote</b></center></h4><hr><center>Version ")
+                                               +Global.version
+                                               +tr("<hr></center>Evernote"
+                                                               +"An Open Source Evernote Client.<br><br>" 
                                                                +"Licensed under GPL v2.  <br><hr><br>"
                                                                +"Evernote is copyright 2001-2010 by Evernote Corporation<br>"
                                                                +"Jambi and QT are the licensed trademark of Nokia Corporation<br>"
                                                                +"PDFRenderer is licened under the LGPL<br>"
+                                                               +"JTidy is copyrighted under the World Wide Web Consortium<br>"
+                                                               +"Apache Common Utilities licensed under the Apache License Version 2.0<br>"
                                                                +"Jazzy is licened under the LGPL<br>"
-                                                               +"Java is a registered trademark of Sun Microsystems.<br><hr>"));       
+                                                               +"Java is a registered trademark of Oracle Corporation.<br><hr>"));     
                logger.log(logger.HIGH, "Leaving NeverNote.about");
        }
        // Hide the entire left hand side
@@ -1937,10 +2029,16 @@ public class NeverNote extends QMainWindow{
        searchPerformed = true;
        logger.log(logger.HIGH, "Leaving NeverNote.searchFieldChanged");
     }
+
     // Build the window tool bar
     private void setupToolBar() {
        logger.log(logger.HIGH, "Entering NeverNote.setupToolBar");
-       toolBar = addToolBar(tr("toolBar"));    
+       toolBar = addToolBar(tr("Tool Bar"));   
+       menuBar.setupToolBarVisible();
+       if (!Global.isWindowVisible("toolBar"))
+               toolBar.setVisible(false);
+       else
+               toolBar.setVisible(true);
 
        prevButton = toolBar.addAction("Previous");
        QIcon prevIcon = new QIcon(iconPath+"back.png");
@@ -2002,7 +2100,7 @@ public class NeverNote extends QMainWindow{
        newButton.triggered.connect(this, "addNote()");
        newButton.setIcon(newIcon);
        toolBar.addSeparator();
-       toolBar.addWidget(new QLabel("Quota:"));
+       toolBar.addWidget(new QLabel(tr("Quota:")));
        toolBar.addWidget(quotaBar);
        //quotaBar.setSizePolicy(Policy.Minimum, Policy.Minimum);
        updateQuotaBar();
@@ -2015,12 +2113,12 @@ public class NeverNote extends QMainWindow{
        zoomSpinner.setSingleStep(10);
        zoomSpinner.setValue(100);
        zoomSpinner.valueChanged.connect(this, "zoomChanged()");
-       toolBar.addWidget(new QLabel("Zoom"));
+       toolBar.addWidget(new QLabel(tr("Zoom")));
        toolBar.addWidget(zoomSpinner);
        
        //toolBar.addWidget(new QLabel("                    "));
        toolBar.addSeparator();
-       toolBar.addWidget(new QLabel("  Search:"));
+       toolBar.addWidget(new QLabel(tr("  Search:")));
        toolBar.addWidget(searchField);
        QSizePolicy sizePolicy = new QSizePolicy();
        sizePolicy.setHorizontalPolicy(Policy.MinimumExpanding);
@@ -2201,8 +2299,8 @@ public class NeverNote extends QMainWindow{
        // SyncRunner had a problem and things are disconnected
        @SuppressWarnings("unused")
        private void remoteErrorDisconnect() {
-               menuBar.connectAction.setText("Connect");
-               menuBar.connectAction.setToolTip("Connect to Evernote");
+               menuBar.connectAction.setText(tr("Connect"));
+               menuBar.connectAction.setToolTip(tr("Connect to Evernote"));
                menuBar.synchronizeAction.setEnabled(false);
                synchronizeAnimationTimer.stop();
                return;
@@ -2221,7 +2319,7 @@ public class NeverNote extends QMainWindow{
        
        AESEncrypter aes = new AESEncrypter();
        try {
-                       aes.decrypt(new FileInputStream(Global.getDirectoryPath()+"secure.txt"));
+                       aes.decrypt(new FileInputStream(Global.getFileManager().getHomeDirFile("secure.txt")));
                } catch (FileNotFoundException e) {
                        // File not found, so we'll just get empty strings anyway. 
                }
@@ -2258,12 +2356,12 @@ public class NeverNote extends QMainWindow{
     private void setupConnectMenuOptions() {
        logger.log(logger.HIGH, "entering NeverNote.setupConnectMenuOptions");
                if (!Global.isConnected) {
-                       menuBar.connectAction.setText("Connect");
-                       menuBar.connectAction.setToolTip("Connect to Evernote");
+                       menuBar.connectAction.setText(tr("Connect"));
+                       menuBar.connectAction.setToolTip(tr("Connect to Evernote"));
                        menuBar.synchronizeAction.setEnabled(false);
                } else {
-                       menuBar.connectAction.setText("Disconnect");
-                       menuBar.connectAction.setToolTip("Disconnect from Evernote");
+                       menuBar.connectAction.setText(tr("Disconnect"));
+                       menuBar.connectAction.setToolTip(tr("Disconnect from Evernote"));
                        menuBar.synchronizeAction.setEnabled(true);
                }
                logger.log(logger.HIGH, "Leaving NeverNote.setupConnectionMenuOptions");
@@ -2297,10 +2395,9 @@ public class NeverNote extends QMainWindow{
                        DateAttributeFilterTable f = null;
                        f = findDateAttributeFilterTable(item.parent());
                        if (f!=null)
-                               f.select(item.text(0));
+                               f.select(item.parent().indexOfChild(item));
                        else {
-                               String text = item.text(0);
-                               Global.containsFilter.select(text);
+                               Global.containsFilter.select(item.parent().indexOfChild(item));
                        }
                }
                listManager.loadNotesIndex();
@@ -2321,21 +2418,22 @@ public class NeverNote extends QMainWindow{
     private DateAttributeFilterTable findDateAttributeFilterTable(QTreeWidgetItem w) {
                if (w.parent() != null && w.childCount() > 0) {
                        QTreeWidgetItem parent = w.parent();
-                       if (parent.text(0).equalsIgnoreCase("created") && 
-                               w.text(0).equalsIgnoreCase("since"))
+                       if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Created && 
+                               w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Since)
                                        return Global.createdSinceFilter;
-                       if (parent.text(0).equalsIgnoreCase("created") && 
-                       w.text(0).equalsIgnoreCase("before"))
+                       if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Created && 
+                       w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Before)
                                        return Global.createdBeforeFilter;
-                       if (parent.text(0).equalsIgnoreCase("last modified") && 
-                       w.text(0).equalsIgnoreCase("since"))
+                       if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.LastModified && 
+                       w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Since)
                                        return Global.changedSinceFilter;
-               if (parent.text(0).equalsIgnoreCase("last modified") && 
-                       w.text(0).equalsIgnoreCase("before"))
+               if (parent.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.LastModified && 
+                       w.data(0,ItemDataRole.UserRole)==AttributeTreeWidget.Attributes.Before)
                                                return Global.changedBeforeFilter;
                }
                return null;
     }
+
     // Show/Hide attribute search window
        private void toggleAttributesWindow() {
                logger.log(logger.HIGH, "Entering NeverNote.toggleAttributesWindow");
@@ -2421,7 +2519,7 @@ public class NeverNote extends QMainWindow{
                                upButton.setEnabled(false);
                        else
                                upButton.setEnabled(true);
-                       if (row < noteTableView.model.rowCount()-1)
+                       if (row < listManager.getNoteTableModel().rowCount()-1)
                                downButton.setEnabled(true);
                        else
                                downButton.setEnabled(false);
@@ -2455,11 +2553,10 @@ public class NeverNote extends QMainWindow{
        // Trigger a refresh when the note db has been updated
        private void noteIndexUpdated(boolean reload) {
                logger.log(logger.HIGH, "Entering NeverNote.noteIndexUpdated");
-               Global.traceReset();  
                saveNote();
        refreshEvernoteNoteList();
        logger.log(logger.HIGH, "Calling note table reload in NeverNote.noteIndexUpdated() - "+reload);
-       noteTableView.load(listManager, reload);
+       noteTableView.load(reload);
        scrollToGuid(currentNoteGuid);
                logger.log(logger.HIGH, "Leaving NeverNote.noteIndexUpdated");
     }
@@ -2564,7 +2661,7 @@ public class NeverNote extends QMainWindow{
        private void downAction() {
        List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
        int row = selections.get(0).row();
-       int max = noteTableView.model.rowCount();
+       int max = listManager.getNoteTableModel().rowCount();
        if (row < max-1) {
                noteTableView.selectRow(row+1);
        }
@@ -2580,14 +2677,14 @@ public class NeverNote extends QMainWindow{
                        tagBuffer.append(", ");
        }
        
-       for (int i=0; i<noteTableView.model.rowCount(); i++) {
-               QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
+       for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
+               QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
                if (modelIndex != null) {
-                       SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+                       SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
                        String tableGuid =  (String)ix.values().toArray()[0];
                        if (tableGuid.equals(guid)) {
-                               noteTableView.model.setData(i, Global.noteTableTagPosition,tagBuffer.toString());
-                               noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
+                               listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition,tagBuffer.toString());
+                               listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
                                return;
                        }
                }
@@ -2596,40 +2693,19 @@ public class NeverNote extends QMainWindow{
     }
     // Update a title for a specific note in the list
     @SuppressWarnings("unused")
-       private void updateListTitle(String guid, String title) {
-       logger.log(logger.HIGH, "Entering NeverNote.updateListTitle");
-
-       for (int i=0; i<noteTableView.model.rowCount(); i++) {
-               //QModelIndex modelIndex =  noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
-               QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
-               if (modelIndex != null) {
-//                     SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(modelIndex);
-                       SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
-                       String tableGuid =  (String)ix.values().toArray()[0];
-                       if (tableGuid.equals(guid)) {
-                               noteTableView.model.setData(i, Global.noteTableTitlePosition,title);
-                               noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
-                               return;
-                       }       
-               }
-       }
-       logger.log(logger.HIGH, "Leaving NeverNote.updateListTitle");
-    }
-    // Update a title for a specific note in the list
-    @SuppressWarnings("unused")
        private void updateListAuthor(String guid, String author) {
        logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
 
-       for (int i=0; i<noteTableView.model.rowCount(); i++) {
+       for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
                //QModelIndex modelIndex =  noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
-               QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
+               QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
                if (modelIndex != null) {
 //                     SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(modelIndex);
-                       SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+                       SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
                        String tableGuid =  (String)ix.values().toArray()[0];
                        if (tableGuid.equals(guid)) {
-                               noteTableView.model.setData(i, Global.noteTableAuthorPosition,author);
-                               noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
+                               listManager.getNoteTableModel().setData(i, Global.noteTableAuthorPosition,author);
+                               listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
                                return;
                        }       
                }
@@ -2637,39 +2713,25 @@ public class NeverNote extends QMainWindow{
        logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
     }
        private void updateListNoteNotebook(String guid, String notebook) {
-       logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
-
-       for (int i=0; i<noteTableView.model.rowCount(); i++) {
-               //QModelIndex modelIndex =  noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
-               QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
-               if (modelIndex != null) {
-//                     SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(modelIndex);
-                       SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
-                       String tableGuid =  (String)ix.values().toArray()[0];
-                       if (tableGuid.equals(guid)) {
-                               noteTableView.model.setData(i, Global.noteTableNotebookPosition,notebook);
-                               noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
-                               return;
-                       }       
-               }
-       }
-       logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
+       logger.log(logger.HIGH, "Entering NeverNote.updateListNoteNotebook");
+       listManager.getNoteTableModel().updateNoteSyncStatus(guid, false);
+       logger.log(logger.HIGH, "Leaving NeverNote.updateListNoteNotebook");
     }
     // Update a title for a specific note in the list
     @SuppressWarnings("unused")
        private void updateListSourceUrl(String guid, String url) {
        logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
 
-       for (int i=0; i<noteTableView.model.rowCount(); i++) {
+       for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
                //QModelIndex modelIndex =  noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
-               QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
+               QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
                if (modelIndex != null) {
 //                     SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(modelIndex);
-                       SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+                       SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
                        String tableGuid =  (String)ix.values().toArray()[0];
                        if (tableGuid.equals(guid)) {
-                               noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
-                               noteTableView.model.setData(i, Global.noteTableSourceUrlPosition,url);
+                               listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
+                               listManager.getNoteTableModel().setData(i, Global.noteTableSourceUrlPosition,url);
                                return;
                        }       
                }
@@ -2679,14 +2741,14 @@ public class NeverNote extends QMainWindow{
        private void updateListGuid(String oldGuid, String newGuid) {
        logger.log(logger.HIGH, "Entering NeverNote.updateListTitle");
 
-       for (int i=0; i<noteTableView.model.rowCount(); i++) {
-               QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
+       for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
+               QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
                if (modelIndex != null) {
-                       SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+                       SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
                        String tableGuid =  (String)ix.values().toArray()[0];
                        if (tableGuid.equals(oldGuid)) {
-                               noteTableView.model.setData(i, Global.noteTableGuidPosition,newGuid);
-                               //noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
+                               listManager.getNoteTableModel().setData(i, Global.noteTableGuidPosition,newGuid);
+                               //listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
                                return;
                        }       
                }
@@ -2700,15 +2762,15 @@ public class NeverNote extends QMainWindow{
                        if (listManager.getNoteIndex().get(j).getTagGuids().contains(guid)) {
                                String newName = listManager.getTagNamesForNote(listManager.getNoteIndex().get(j));
 
-                               for (int i=0; i<noteTableView.model.rowCount(); i++) {
-                                       QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
+                               for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
+                                       QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
                                        if (modelIndex != null) {
-                                               SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+                                               SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
                                                String noteGuid = (String)ix.values().toArray()[0];
                                                if (noteGuid.equalsIgnoreCase(listManager.getNoteIndex().get(j).getGuid())) {
-                                                       noteTableView.model.setData(i, Global.noteTableTagPosition, newName);
-                                                       //noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
-                                                       i=noteTableView.model.rowCount();
+                                                       listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition, newName);
+                                                       //listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
+                                                       i=listManager.getNoteTableModel().rowCount();
                                                }
                                        }
                                }
@@ -2727,15 +2789,15 @@ public class NeverNote extends QMainWindow{
                                }
                                
                                String newName = listManager.getTagNamesForNote(listManager.getNoteIndex().get(j));
-                               for (int i=0; i<noteTableView.model.rowCount(); i++) {
-                                       QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
+                               for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
+                                       QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
                                        if (modelIndex != null) {
-                                               SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+                                               SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
                                                String noteGuid = (String)ix.values().toArray()[0];
                                                if (noteGuid.equalsIgnoreCase(listManager.getNoteIndex().get(j).getGuid())) {
-                                                       noteTableView.model.setData(i, Global.noteTableTagPosition, newName);
-//                                                     noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
-                                                       i=noteTableView.model.rowCount();
+                                                       listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition, newName);
+//                                                     listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
+                                                       i=listManager.getNoteTableModel().rowCount();
                                                }
                                        }
                                }
@@ -2746,14 +2808,14 @@ public class NeverNote extends QMainWindow{
     private void updateListNotebookName(String oldName, String newName) {
        logger.log(logger.HIGH, "Entering NeverNote.updateListNotebookName");
 
-       for (int i=0; i<noteTableView.model.rowCount(); i++) {
-               QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableNotebookPosition); 
+       for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
+               QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableNotebookPosition); 
                if (modelIndex != null) {
-                       SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+                       SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
                        String tableName =  (String)ix.values().toArray()[0];
                        if (tableName.equalsIgnoreCase(oldName)) {
-//                             noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
-                               noteTableView.model.setData(i, Global.noteTableNotebookPosition, newName);
+//                             listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
+                               listManager.getNoteTableModel().setData(i, Global.noteTableNotebookPosition, newName);
                        }
                }
        }
@@ -2763,13 +2825,13 @@ public class NeverNote extends QMainWindow{
        private void updateListDateCreated(String guid, QDateTime date) {
        logger.log(logger.HIGH, "Entering NeverNote.updateListDateCreated");
 
-       for (int i=0; i<noteTableView.model.rowCount(); i++) {
-               QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
+       for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
+               QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
                if (modelIndex != null) {
-                       SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+                       SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
                        String tableGuid =  (String)ix.values().toArray()[0];
                        if (tableGuid.equals(guid)) {
-                               noteTableView.model.setData(i, Global.noteTableCreationPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
+                               listManager.getNoteTableModel().setData(i, Global.noteTableCreationPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
                                return;
                        }
                }
@@ -2780,14 +2842,14 @@ public class NeverNote extends QMainWindow{
        private void updateListDateSubject(String guid, QDateTime date) {
        logger.log(logger.HIGH, "Entering NeverNote.updateListDateSubject");
 
-       for (int i=0; i<noteTableView.model.rowCount(); i++) {
-               QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
+       for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
+               QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
                if (modelIndex != null) {
-                       SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+                       SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
                        String tableGuid =  (String)ix.values().toArray()[0];
                        if (tableGuid.equals(guid)) {
-                               noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
-                               noteTableView.model.setData(i, Global.noteTableSubjectDatePosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
+                               listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
+                               listManager.getNoteTableModel().setData(i, Global.noteTableSubjectDatePosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
                                return;
                        }
                }
@@ -2798,14 +2860,14 @@ public class NeverNote extends QMainWindow{
        private void updateListDateChanged(String guid, QDateTime date) {
        logger.log(logger.HIGH, "Entering NeverNote.updateListDateChanged");
 
-       for (int i=0; i<noteTableView.model.rowCount(); i++) {
-               QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
+       for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
+               QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
                if (modelIndex != null) {
-                       SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+                       SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
                        String tableGuid =  (String)ix.values().toArray()[0];
                        if (tableGuid.equals(guid)) {
-                               noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
-                               noteTableView.model.setData(i, Global.noteTableChangedPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
+                               listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
+                               listManager.getNoteTableModel().setData(i, Global.noteTableChangedPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
                                return;
                        }
                }
@@ -2815,14 +2877,14 @@ public class NeverNote extends QMainWindow{
     private void updateListDateChanged() {
        logger.log(logger.HIGH, "Entering NeverNote.updateListDateChanged");
        QDateTime date = new QDateTime(QDateTime.currentDateTime());
-       for (int i=0; i<noteTableView.model.rowCount(); i++) {
-               QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
+       for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
+               QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
                if (modelIndex != null) {
-                       SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+                       SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
                        String tableGuid =  (String)ix.values().toArray()[0];
                        if (tableGuid.equals(currentNoteGuid)) {
-                               noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
-                               noteTableView.model.setData(i, Global.noteTableChangedPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
+                               listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
+                               listManager.getNoteTableModel().setData(i, Global.noteTableChangedPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
                                return;
                        }
                }
@@ -2872,7 +2934,7 @@ public class NeverNote extends QMainWindow{
 //                     noteTableView.setCurrentIndex(index);
                                noteTableView.selectRow(i);
                        noteTableView.scrollTo(index, ScrollHint.EnsureVisible);  // This should work, but it doesn't
-                               i=noteTableView.model.rowCount();
+                               i=listManager.getNoteTableModel().rowCount();
                }
        }
     }
@@ -2908,18 +2970,18 @@ public class NeverNote extends QMainWindow{
                        selectedNoteGUIDs.add(currentNoteGuid);
                
        for (int j=0; j<selectedNoteGUIDs.size(); j++) {
-               for (int i=0; i<noteTableView.model.rowCount(); i++) {
-                       QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
+               for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
+                       QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
                        if (modelIndex != null) {
-                               SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+                               SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
                                String tableGuid =  (String)ix.values().toArray()[0];
                                if (tableGuid.equals(selectedNoteGUIDs.get(j))) {
                                        for (int k=0; k<Global.noteTableColumnCount; k++) {
-                                               noteTableView.model.setData(i, k, backgroundColor, Qt.ItemDataRole.BackgroundRole);
-                                               noteTableView.model.setData(i, k, foregroundColor, Qt.ItemDataRole.ForegroundRole);
+                                               listManager.getNoteTableModel().setData(i, k, backgroundColor, Qt.ItemDataRole.BackgroundRole);
+                                               listManager.getNoteTableModel().setData(i, k, foregroundColor, Qt.ItemDataRole.ForegroundRole);
                                                listManager.updateNoteTitleColor(selectedNoteGUIDs.get(j), backgroundColor.rgb());
                                        }
-                                       i=noteTableView.model.rowCount();
+                                       i=listManager.getNoteTableModel().rowCount();
                                }
                        }
                }
@@ -2936,20 +2998,33 @@ public class NeverNote extends QMainWindow{
     @SuppressWarnings("unused")
        private void setNoteDirty() {
                logger.log(logger.EXTREME, "Entering NeverNote.setNoteDirty()");
-       noteDirty = true;
-
-       listManager.getUnsynchronizedNotes().add(currentNoteGuid);
-       for (int i=0; i<noteTableView.model.rowCount(); i++) {
-               QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
+               
+               // If the note is dirty, then it is unsynchronized by default.
+               if (noteDirty) 
+                       return;
+               
+               // Set the note as dirty and check if its status is synchronized in the display table
+               noteDirty = true;
+               for (int i=0; i<listManager.getUnsynchronizedNotes().size(); i++) {
+                       if (listManager.getUnsynchronizedNotes().get(i).equals(currentNoteGuid))
+                               return;
+               }
+               
+               // If this wasn't already marked as unsynchronized, then we need to update the table
+               listManager.getNoteTableModel().updateNoteSyncStatus(currentNoteGuid, false);
+/*     listManager.getUnsynchronizedNotes().add(currentNoteGuid);
+       for (int i=0; i<listManager.getNoteTableModel().rowCount(); i++) {
+               QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
                if (modelIndex != null) {
-                       SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+                       SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
                        String tableGuid =  (String)ix.values().toArray()[0];
                        if (tableGuid.equals(currentNoteGuid)) {
-                               noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
+                               listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
                                return;
                        }
                }
        }
+ */    
                logger.log(logger.EXTREME, "Leaving NeverNote.setNoteDirty()");
     }
     private void saveNote() {
@@ -2971,6 +3046,7 @@ public class NeverNote extends QMainWindow{
                        
                logger.log(logger.EXTREME, "updating list manager");
                listManager.updateNoteContent(currentNoteGuid, browserWindow.getContent());
+//             noteCache.put(currentNoteGuid, browserWindow.getContent());
                        logger.log(logger.EXTREME, "Updating title");
                listManager.updateNoteTitle(currentNoteGuid, browserWindow.getTitle());
                updateListDateChanged();
@@ -3078,7 +3154,7 @@ public class NeverNote extends QMainWindow{
        // Save a generated thumbnail
        @SuppressWarnings("unused")
        private void saveThumbnail(String guid) {
-               QFile tFile = new QFile(Global.currentDir+"res/thumbnail-"+guid+".png");
+               QFile tFile = new QFile(Global.getFileManager().getResDirPath("thumbnail-" + guid + ".png"));
                tFile.open(OpenModeFlag.ReadOnly);
                QByteArray imgBytes = tFile.readAll();
                tFile.close();
@@ -3162,19 +3238,19 @@ public class NeverNote extends QMainWindow{
        logger.log(logger.HIGH, "Entering NeverNote.fullReindex");
        // If we are deleting non-trash notes
        if (currentNote.getDeleted() == 0) { 
-               if (QMessageBox.question(this, "Confirmation", "This will cause all notes & attachments to be reindexed, "+
+               if (QMessageBox.question(this, tr("Confirmation"), tr("This will cause all notes & attachments to be reindexed, "+
                                "but please be aware that depending upon the size of your database updating all these records " +
-                               "can be time consuming and NeverNote will be unresponsive until it is complete.  Do you wish to continue?",
+                               "can be time consuming and NeverNote will be unresponsive until it is complete.  Do you wish to continue?"),
                                QMessageBox.StandardButton.Yes, 
                                        QMessageBox.StandardButton.No)==StandardButton.No.value() && Global.verifyDelete() == true) {
                                                                return;
                }
        }
        waitCursor(true);
-       setMessage("Marking notes for reindex.");
+       setMessage(tr("Marking notes for reindex."));
        conn.getNoteTable().reindexAllNotes();
        conn.getNoteTable().noteResourceTable.reindexAll(); 
-       setMessage("Database will be reindexed.");
+       setMessage(tr("Database will be reindexed."));
        waitCursor(false);
        logger.log(logger.HIGH, "Leaving NeverNote.fullRefresh");
     }
@@ -3186,9 +3262,9 @@ public class NeverNote extends QMainWindow{
                        conn.getNoteTable().setIndexNeeded(selectedNoteGUIDs.get(i), true);
                }
                if (selectedNotebookGUIDs.size() > 1)
-                       setMessage("Notes will be reindexed.");
+                       setMessage(tr("Notes will be reindexed."));
                else
-                       setMessage("Note will be reindexed.");
+                       setMessage(tr("Note will be reindexed."));
        logger.log(logger.HIGH, "Leaving NeverNote.reindexNote");
     }
     // Delete the note
@@ -3203,7 +3279,7 @@ public class NeverNote extends QMainWindow{
        // If we are deleting non-trash notes
        if (currentNote.isActive()) { 
                if (Global.verifyDelete()) {
-                       if (QMessageBox.question(this, "Confirmation", "Delete selected note(s)?",
+                       if (QMessageBox.question(this, tr("Confirmation"), tr("Delete selected note(s)?"),
                                        QMessageBox.StandardButton.Yes, 
                                        QMessageBox.StandardButton.No)==StandardButton.No.value() && Global.verifyDelete() == true) {
                                        return;
@@ -3226,13 +3302,13 @@ public class NeverNote extends QMainWindow{
                if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals("")) 
                        selectedNoteGUIDs.add(currentNoteGuid);
                for (int i=selectedNoteGUIDs.size()-1; i>=0; i--) {
-                       for (int j=noteTableView.model.rowCount()-1; j>=0; j--) {
-                       QModelIndex modelIndex =  noteTableView.model.index(j, Global.noteTableGuidPosition);
+                       for (int j=listManager.getNoteTableModel().rowCount()-1; j>=0; j--) {
+                       QModelIndex modelIndex =  listManager.getNoteTableModel().index(j, Global.noteTableGuidPosition);
                        if (modelIndex != null) {
-                               SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+                               SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
                                String tableGuid =  (String)ix.values().toArray()[0];
                                if (tableGuid.equals(selectedNoteGUIDs.get(i))) {
-                                       noteTableView.model.removeRow(j);
+                                       listManager.getNoteTableModel().removeRow(j);
                                        j=-1;
                                }
                        }
@@ -3260,7 +3336,7 @@ public class NeverNote extends QMainWindow{
                "<en-note>\n<br clear=\"none\" /></en-note>");
        
        Long l = new Long(currentTime.getTimeInMillis());
-       String randint = new String(Long.toString(l));
+       String randint = new String(Long.toString(l));          
        
        // Find a notebook.  We first look for a selected notebook (the "All Notebooks" one doesn't count).  
        // Then we look
@@ -3318,13 +3394,27 @@ public class NeverNote extends QMainWindow{
        na.setLongitude(0.0);
        na.setAltitude(0.0);
        newNote.setAttributes(new NoteAttributes());
+               newNote.setTagGuids(new ArrayList<String>());
+               newNote.setTagNames(new ArrayList<String>());
+       
+       // If new notes are to be created based upon the selected tags, then we need to assign the tags
+       if (Global.newNoteWithSelectedTags()) { 
+               List<QTreeWidgetItem> selections = tagTree.selectedItems();
+               QTreeWidgetItem currentSelection;
+               for (int i=0; i<selections.size(); i++) {
+                       currentSelection = selections.get(i);
+                       newNote.getTagGuids().add(currentSelection.text(2));
+                       newNote.getTagNames().add(currentSelection.text(0));
+               }
+       }
+       
        conn.getNoteTable().addNote(newNote, true);
        listManager.getUnsynchronizedNotes().add(newNote.getGuid());
-       noteTableView.insertRow(listManager, newNote, true, -1);
+       listManager.addNote(newNote);
+//     noteTableView.insertRow(newNote, true, -1);
        
        currentNote = newNote;
        currentNoteGuid = currentNote.getGuid();
-       listManager.addNote(newNote);
        refreshEvernoteNote(true);
        listManager.countNotebookResults(listManager.getNoteIndex());
        browserWindow.titleLabel.setFocus();
@@ -3363,7 +3453,7 @@ public class NeverNote extends QMainWindow{
        private void invalidateNoteCache(String guid, String content) {
        String v = noteCache.remove(guid);
        if (content != null) {
-               v = noteCache.put(guid, content);
+               //noteCache.put(guid, content);
        }
     }
     // Signal received that a note guid has changed
@@ -3386,7 +3476,12 @@ public class NeverNote extends QMainWindow{
                        i=listManager.getNoteIndex().size();
                }
        }
-               updateListGuid(oldGuid, newGuid);
+       if (listManager.getNoteTableModel().titleColors.containsKey(oldGuid)) {
+               int color = listManager.getNoteTableModel().titleColors.get(oldGuid);
+               listManager.getNoteTableModel().titleColors.put(newGuid, color);
+               listManager.getNoteTableModel().titleColors.remove(oldGuid);
+       }
+       
     }
     // Toggle the note editor button bar
     private void toggleEditorButtonBar() {
@@ -3402,60 +3497,38 @@ public class NeverNote extends QMainWindow{
     }
     // Show editor buttons
     private void showEditorButtons() {
+               browserWindow.buttonLayout.setVisible(true);
+               browserWindow.undoAction.setVisible(false);
+               
                browserWindow.undoButton.setVisible(false);
-               browserWindow.redoButton.setVisible(false);
-               browserWindow.cutButton.setVisible(false);
-               browserWindow.copyButton.setVisible(false);
-               browserWindow.pasteButton.setVisible(false);
-               browserWindow.strikethroughButton.setVisible(false);
-               browserWindow.underlineButton.setVisible(false);
-               browserWindow.boldButton.setVisible(false);
-               browserWindow.italicButton.setVisible(false);
-               browserWindow.hlineButton.setVisible(false);
-               browserWindow.indentButton.setVisible(false);
-               browserWindow.outdentButton.setVisible(false);
-               browserWindow.fontList.setVisible(false);
-               browserWindow.fontSize.setVisible(false);
-               browserWindow.fontColor.setVisible(false);
-               browserWindow.fontHilight.setVisible(false);
-               browserWindow.leftAlignButton.setVisible(false);
-               browserWindow.centerAlignButton.setVisible(false);
-               browserWindow.rightAlignButton.setVisible(false);
-               browserWindow.indentButton.setVisible(false);
-               browserWindow.outdentButton.setVisible(false);
 
-               browserWindow.undoButton.setVisible(Global.isEditorButtonVisible("undo"));
-               browserWindow.redoButton.setVisible(Global.isEditorButtonVisible("redo"));
-               browserWindow.cutButton.setVisible(Global.isEditorButtonVisible("cut"));
-               browserWindow.copyButton.setVisible(Global.isEditorButtonVisible("copy"));
-               browserWindow.pasteButton.setVisible(Global.isEditorButtonVisible("paste"));
-               browserWindow.strikethroughButton.setVisible(Global.isEditorButtonVisible("strikethrough"));
-               browserWindow.underlineButton.setVisible(Global.isEditorButtonVisible("underline"));
-               browserWindow.boldButton.setVisible(Global.isEditorButtonVisible("bold"));
-               browserWindow.italicButton.setVisible(Global.isEditorButtonVisible("italic"));
-               browserWindow.hlineButton.setVisible(Global.isEditorButtonVisible("hline"));
-               browserWindow.indentButton.setVisible(Global.isEditorButtonVisible("indent"));
-               browserWindow.outdentButton.setVisible(Global.isEditorButtonVisible("outdent"));
-               browserWindow.bulletListButton.setVisible(Global.isEditorButtonVisible("bulletList"));
-               browserWindow.numberListButton.setVisible(Global.isEditorButtonVisible("numberList"));
-               browserWindow.fontList.setVisible(Global.isEditorButtonVisible("font"));
-               browserWindow.fontSize.setVisible(Global.isEditorButtonVisible("fontSize"));
-               browserWindow.fontColor.setVisible(Global.isEditorButtonVisible("fontColor"));
-               browserWindow.fontHilight.setVisible(Global.isEditorButtonVisible("fontHilight"));
-               browserWindow.leftAlignButton.setVisible(Global.isEditorButtonVisible("alignLeft"));
-               browserWindow.centerAlignButton.setVisible(Global.isEditorButtonVisible("alignCenter"));
-               browserWindow.rightAlignButton.setVisible(Global.isEditorButtonVisible("alignRight"));
+               browserWindow.undoAction.setVisible(Global.isEditorButtonVisible("undo"));
+               browserWindow.redoAction.setVisible(Global.isEditorButtonVisible("redo"));
+               browserWindow.cutAction.setVisible(Global.isEditorButtonVisible("cut"));
+               browserWindow.copyAction.setVisible(Global.isEditorButtonVisible("copy"));
+               browserWindow.pasteAction.setVisible(Global.isEditorButtonVisible("paste"));
+               browserWindow.strikethroughAction.setVisible(Global.isEditorButtonVisible("strikethrough"));
+               browserWindow.underlineAction.setVisible(Global.isEditorButtonVisible("underline"));
+               browserWindow.boldAction.setVisible(Global.isEditorButtonVisible("bold"));
+               browserWindow.italicAction.setVisible(Global.isEditorButtonVisible("italic"));
+               browserWindow.hlineAction.setVisible(Global.isEditorButtonVisible("hline"));
+               browserWindow.indentAction.setVisible(Global.isEditorButtonVisible("indent"));
+               browserWindow.outdentAction.setVisible(Global.isEditorButtonVisible("outdent"));
+               browserWindow.bulletListAction.setVisible(Global.isEditorButtonVisible("bulletList"));
+               browserWindow.numberListAction.setVisible(Global.isEditorButtonVisible("numberList"));
+               browserWindow.fontListAction.setVisible(Global.isEditorButtonVisible("font"));
+               browserWindow.fontSizeAction.setVisible(Global.isEditorButtonVisible("fontSize"));
+               browserWindow.fontColorAction.setVisible(Global.isEditorButtonVisible("fontColor"));
+               browserWindow.fontHilightAction.setVisible(Global.isEditorButtonVisible("fontHilight"));
+               browserWindow.leftAlignAction.setVisible(Global.isEditorButtonVisible("alignLeft"));
+               browserWindow.centerAlignAction.setVisible(Global.isEditorButtonVisible("alignCenter"));
+               browserWindow.rightAlignAction.setVisible(Global.isEditorButtonVisible("alignRight"));
     }
     private void duplicateNote(String guid) {
                
-               Calendar currentTime = new GregorianCalendar();
-               Long l = new Long(currentTime.getTimeInMillis());
-               String newGuid = new String(Long.toString(l));
-                                       
                Note oldNote = conn.getNoteTable().getNote(guid, true, true, false, false, false);
-               Note newNote = oldNote.deepCopy();
-               newNote.setGuid(newGuid);
                List<Resource> resList = conn.getNoteTable().noteResourceTable.getNoteResources(guid, true);
+               oldNote.setContent(conn.getNoteTable().getNoteContentBinary(guid));
                oldNote.setResources(resList);
                duplicateNote(oldNote);
        }
@@ -3494,7 +3567,7 @@ public class NeverNote extends QMainWindow{
                listManager.addNote(newNote);
                conn.getNoteTable().addNote(newNote, true);
                listManager.getUnsynchronizedNotes().add(newNote.getGuid());
-               noteTableView.insertRow(listManager, newNote, true, -1);
+               noteTableView.insertRow(newNote, true, -1);
                listManager.countNotebookResults(listManager.getNoteIndex());
                waitCursor(false);
        }
@@ -3586,7 +3659,7 @@ public class NeverNote extends QMainWindow{
        // View a thumbnail of the note
        public void thumbnailView() {
                
-               String thumbnailName = Global.currentDir+"res/thumbnail-"+currentNoteGuid+".png";
+               String thumbnailName = Global.getFileManager().getResDirPath("thumbnail-" + currentNoteGuid + ".png");
                QFile thumbnail = new QFile(thumbnailName);
                if (!thumbnail.exists()) {
                        
@@ -3598,7 +3671,25 @@ public class NeverNote extends QMainWindow{
                if (!thumbnailViewer.isVisible()) 
                        thumbnailViewer.showFullScreen();
        }
-
+       // An error happened while saving a note.  Inform the user
+       @SuppressWarnings("unused")
+       private void saveRunnerError(String guid, String msg) {
+               if (msg == null) {
+                       String title = "*Unknown*";
+                       for (int i=0; i<listManager.getMasterNoteIndex().size(); i++) {
+                               if (listManager.getMasterNoteIndex().get(i).getGuid().equals(guid)) {
+                                       title = listManager.getMasterNoteIndex().get(i).getTitle();
+                                       i=listManager.getMasterNoteIndex().size();
+                               }
+                       }
+                       msg = "An error has happened saving the note \"" +title+
+                       "\". \nThis is probably due to a document that is too complex for Nevernote to process.  "+
+                       "As a result, changes to the note may not be saved.\n\nPlease review the note for any potential problems.";
+                       
+                       QMessageBox.information(this, tr("Error Saving Note"), tr(msg));
+               }
+       }
+       
        //**********************************************************
     //**********************************************************
     //* Online user actions
@@ -3617,12 +3708,12 @@ public class NeverNote extends QMainWindow{
        if (currentNoteGuid == null || currentNoteGuid.equals("")) 
                return;
        if (currentNote.getUpdateSequenceNum() == 0) {
-               setMessage("Note has never been synchronized.");
-                       QMessageBox.information(this, "Error", "This note has never been sent to Evernote, so there is no history.");
+               setMessage(tr("Note has never been synchronized."));
+                       QMessageBox.information(this, tr("Error"), tr("This note has never been sent to Evernote, so there is no history."));
                        return;
        }
        
-       setMessage("Getting Note History");
+       setMessage(tr("Getting Note History"));
        waitCursor(true);
        Note currentOnlineNote = null;
        versions = null;
@@ -3639,7 +3730,7 @@ public class NeverNote extends QMainWindow{
                        setMessage("EDAMSystemException: " +e.getMessage());
                        return;
                } catch (EDAMNotFoundException e) {
-                       setMessage("Note not found on server.");
+                       setMessage(tr("Note not found on server."));
                        QMessageBox.information(this, "Error", "This note could not be found on Evernote's servers.");
                        return;
                } catch (TException e) {
@@ -3663,7 +3754,7 @@ public class NeverNote extends QMainWindow{
                
                loadHistoryWindowContent(currentOnlineNote);
                historyWindow.load(versions);
-               setMessage("History retrieved");
+               setMessage(tr("History retrieved"));
                waitCursor(false);
                historyWindow.exec();
     }
@@ -3721,13 +3812,13 @@ public class NeverNote extends QMainWindow{
     }
     @SuppressWarnings("unused")
        private void restoreHistoryNoteAsNew() {
-       setMessage("Restoring as new note.");
+       setMessage(tr("Restoring as new note."));
        duplicateNote(reloadHistoryWindow(historyWindow.historyCombo.currentText()));
-       setMessage("Note has been restored as a new note.");
+       setMessage(tr("Note has been restored as a new note."));
     }
     @SuppressWarnings("unused")
        private void restoreHistoryNote() {
-       setMessage("Restoring note.");
+       setMessage(tr("Restoring note."));
        Note n = reloadHistoryWindow(historyWindow.historyCombo.currentText());
        conn.getNoteTable().expungeNote(n.getGuid(), true, false);
        n.setActive(true);
@@ -3739,7 +3830,7 @@ public class NeverNote extends QMainWindow{
        listManager.addNote(n);
        conn.getNoteTable().addNote(n, true);
        refreshEvernoteNote(true);
-       setMessage("Note has been restored.");
+       setMessage(tr("Note has been restored."));
     }
     
     
@@ -3753,7 +3844,11 @@ public class NeverNote extends QMainWindow{
     private String findIcon(String appl) {
        logger.log(logger.HIGH, "Entering NeverNote.findIcon");
        appl = appl.toLowerCase();
-       File f = new File(Global.getDirectoryPath()+"images"+File.separator +appl +".png");
+        String relativePath = appl + ".png";
+        File f = Global.getFileManager().getImageDirFile(relativePath);
+        if (f.exists()) {
+            return relativePath;
+        }
        if (f.exists())
                return appl+".png";
        logger.log(logger.HIGH, "Leaving NeverNote.findIcon");
@@ -3786,14 +3881,13 @@ public class NeverNote extends QMainWindow{
                                if (r.getAttributes() != null && r.getAttributes().getFileName() != null && !r.getAttributes().getFileName().equals(""))
                                        fileDetails = r.getAttributes().getFileName();
                                String contextFileName;
-                               String pathPrefix = Global.currentDir;
-                               pathPrefix = Global.getDirectoryPath()+"res/";
-                               if (fileDetails != null && !fileDetails.equals("")) {
+                               FileManager fileManager = Global.getFileManager();
+                if (fileDetails != null && !fileDetails.equals("")) {
                                        enmedia.setAttribute("href", "nnres://" +r.getGuid() +Global.attachmentNameDelimeter +fileDetails);
-                                       contextFileName = Global.currentDir +"res/" +r.getGuid() +Global.attachmentNameDelimeter +fileDetails;
+                                       contextFileName = fileManager.getResDirPath(r.getGuid() + Global.attachmentNameDelimeter + fileDetails);
                                } else { 
                                        enmedia.setAttribute("href", "nnres://" +r.getGuid() +Global.attachmentNameDelimeter +appl);
-                                       contextFileName = pathPrefix+r.getGuid() +Global.attachmentNameDelimeter +appl;
+                                       contextFileName = fileManager.getResDirPath(r.getGuid() + Global.attachmentNameDelimeter + appl);
                                }
                                contextFileName = contextFileName.replace("\\", "/");
                                enmedia.setAttribute("onContextMenu", "window.jambi.resourceContextMenu('" +contextFileName +"');");
@@ -3814,7 +3908,7 @@ public class NeverNote extends QMainWindow{
                                                fileName = res.getGuid()+Global.attachmentNameDelimeter+res.getAttributes().getFileName();
                                        else
                                                fileName = res.getGuid()+".pdf";
-                                       QFile file = new QFile(Global.getDirectoryPath() +"res/"+fileName);
+                                       QFile file = new QFile(fileManager.getResDirPath(fileName));
                                QFile.OpenMode mode = new QFile.OpenMode();
                                mode.set(QFile.OpenModeFlag.WriteOnly);
                                file.open(mode);
@@ -3839,8 +3933,9 @@ public class NeverNote extends QMainWindow{
                                                QDomElement right = doc.createElement("img");
                                                right.setAttribute("onMouseDown", "window.jambi.nextPage('" +file.fileName() +"')");
                                                left.setAttribute("onMouseDown", "window.jambi.previousPage('" +file.fileName() +"')");
-                                               left.setAttribute("src", Global.currentDir+"images/small_left.png");
-                                               right.setAttribute("src", Global.currentDir+"images/small_right.png");
+                                               // NFC TODO: should these be file:// URLs?
+                                               left.setAttribute("src", Global.getFileManager().getImageDirPath("small_left.png"));
+                                               right.setAttribute("src", Global.getFileManager().getImageDirPath("small_right.png"));
                                                right.setAttribute("onMouseOver", "style.cursor='hand'");
                                                
                                                table.appendChild(tr);
@@ -3855,9 +3950,11 @@ public class NeverNote extends QMainWindow{
                                String icon = findIcon(appl);
                                if (icon.equals("attachment.png"))
                                        icon = findIcon(fileDetails.substring(fileDetails.indexOf(".")+1));
-                               newText.setAttribute("src", Global.getDirectoryPath()+"images"+File.separator +icon);
+                               // NFC TODO: should this be a 'file://' URL?
+                               newText.setAttribute("src", Global.getFileManager().getImageDirPath(icon));
                                if (goodPreview) {
-                                       newText.setAttribute("src", Global.getDirectoryPath()+"res/"+filePath);
+                               // NFC TODO: should this be a 'file://' URL?
+                                       newText.setAttribute("src", fileManager.getResDirPath(filePath));
                                        newText.setAttribute("style", "border-style:solid; border-color:green; padding:0.5mm 0.5mm 0.5mm 0.5mm;");
                                }
                                newText.setAttribute("title", fileDetails);
@@ -3891,9 +3988,9 @@ public class NeverNote extends QMainWindow{
                        int endPos =html.indexOf(">",i+1);
                        String input = html.substring(i,endPos);
                        if (input.indexOf("value=\"true\"") > 0) 
-                               input = input.replace("unchecked=\"\"", "checked=\"\"");
+                               input = input.replace(" unchecked=\"\"", " checked=\"\"");
                        else
-                               input = input.replace("checked=\"\"", "unchecked=\"\"");
+                               input = input.replace(" checked=\"\"", " unchecked=\"\"");
                        html.replace(i, endPos, input);
                        i++;
                }
@@ -3910,7 +4007,7 @@ public class NeverNote extends QMainWindow{
                type="";
        
        String resGuid = conn.getNoteTable().noteResourceTable.getNoteResourceGuidByHashHex(currentNoteGuid, hash.value());
-       QFile tfile = new QFile(Global.getDirectoryPath()+"res"+File.separator +resGuid+type);
+       QFile tfile = new QFile(Global.getFileManager().getResDirPath(resGuid + type));
        if (!tfile.exists()) {
                Resource r = null;
                if (resGuid != null)
@@ -3982,7 +4079,7 @@ public class NeverNote extends QMainWindow{
                for (int i=enCryptLen-1; i>=0; i--) {
                        QDomElement enmedia = anchors.at(i).toElement();
                        enmedia.setAttribute("contentEditable","false");
-                       enmedia.setAttribute("src", Global.getDirectoryPath()+"images/encrypt.png");
+                       enmedia.setAttribute("src", Global.getFileManager().getImageDirPath("encrypt.png"));
                        enmedia.setAttribute("en-tag","en-crypt");
                        enmedia.setAttribute("alt", enmedia.text());
                        Global.cryptCounter++;
@@ -4004,6 +4101,15 @@ public class NeverNote extends QMainWindow{
                        enmedia.removeChild(enmedia.firstChild());   // Remove the actual encrypted text
                }
 
+               
+               // Modify link tags
+               anchors = docElem.elementsByTagName("a");
+               enCryptLen = anchors.length();
+               for (int i=0; i<anchors.length(); i++) {
+                       QDomElement element = anchors.at(i).toElement();
+                       element.setAttribute("title", element.attribute("href"));
+               }
+
                logger.log(logger.HIGH, "Leaving NeverNote.modifyTags");
                return doc;
        }
@@ -4015,11 +4121,11 @@ public class NeverNote extends QMainWindow{
                QDomDocument doc = new QDomDocument();
                QDomDocument.Result result = doc.setContent(note);
                if (!result.success) {
-                       logger.log(logger.MEDIUM, tr("Parse error when rebuilding HTML"));
-                       logger.log(logger.MEDIUM, tr("Note guid: " +noteGuid));
-                       logger.log(logger.EXTREME, tr("Start of unmodified note HTML"));
+                       logger.log(logger.MEDIUM, "Parse error when rebuilding HTML");
+                       logger.log(logger.MEDIUM, "Note guid: " +noteGuid);
+                       logger.log(logger.EXTREME, "Start of unmodified note HTML");
                        logger.log(logger.EXTREME, note);
-                       logger.log(logger.EXTREME, tr("End of unmodified note HTML"));
+                       logger.log(logger.EXTREME, "End of unmodified note HTML");
                        return note;
                }
 
@@ -4116,54 +4222,33 @@ public class NeverNote extends QMainWindow{
        }
        @SuppressWarnings("unused")
        private void syncThreadComplete(Boolean refreshNeeded) {
-               setMessage("Finalizing Synchronization");
+               setMessage(tr("Finalizing Synchronization"));
                syncThreadsReady++;
                syncRunning = false;
                syncRunner.syncNeeded = false;
                synchronizeAnimationTimer.stop();
-               noteIndexUpdated(true);
                synchronizeButton.setIcon(synchronizeAnimation.get(0));
                saveNote();
-//             noteTableView.selectionModel().selectionChanged.disconnect(this, "noteTableSelection()");
+               if (currentNote == null) {
+                       currentNote = conn.getNoteTable().getNote(currentNoteGuid, false, false, false, false, true);
+               }
+               listManager.setUnsynchronizedNotes(conn.getNoteTable().getUnsynchronizedGUIDs());
+               noteIndexUpdated(false);
                noteTableView.selectionModel().blockSignals(true);
                scrollToGuid(currentNoteGuid);
                noteTableView.selectionModel().blockSignals(false);
-//             noteTableView.selectionModel().selectionChanged.connect(this, "noteTableSelection()");
-//             indexRunner.setKeepRunning(Global.keepRunning);
-               
-               // Reload the unindexed table  If the dbthread is dead, we are probably shutting down.
-               if (!dbThread.isAlive())
-                       return;
-               listManager.setUnsynchronizedNotes(conn.getNoteTable().getUnsynchronizedGUIDs());
-               for (int i=0; i<noteTableView.model.rowCount(); i++) {
-                       QModelIndex modelIndex =  noteTableView.model.index(i, Global.noteTableGuidPosition);
-                       if (modelIndex != null) {
-                       SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
-                               String tableGuid =  (String)ix.values().toArray()[0];
-                               String synch = "true";
-                               for (int j=0; j<listManager.getUnsynchronizedNotes().size(); j++) {
-                                       if (listManager.getUnsynchronizedNotes().get(j).equalsIgnoreCase(tableGuid)) {
-                                               synch = "false";
-                                               j = listManager.getUnsynchronizedNotes().size();
-                                       }
-                               }
-                               noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, synch);
-                       }
-               }       
                refreshEvernoteNote(false);
                scrollToGuid(currentNoteGuid);
-               setMessage("Synchronization Complete");
+               waitCursor(false);
+               if (!syncRunner.error)
+                       setMessage(tr("Synchronization Complete"));
+               else
+                       setMessage(tr("Synchronization completed with errors.  Please check the log for details."));
                logger.log(logger.MEDIUM, "Sync complete.");
        }   
-//     public void setSequenceDate(long t) {
-//             Global.setSequenceDate(t);
-//     }
        public void saveUploadAmount(long t) {
                Global.saveUploadAmount(t);
        }
-//     public void setUpdateSequenceNumber(int t) {
-//             Global.setUpdateSequenceNumber(t);
-//     }
        public void saveUserInformation(User user) {
                Global.saveUserInformation(user);
        }
@@ -4255,7 +4340,7 @@ public class NeverNote extends QMainWindow{
                                indexTimer.setInterval(indexTime);
                        }
                        if (indexRunning) {
-                               setMessage("Index completed.");
+                               setMessage(tr("Index completed."));
                                logger.log(logger.LOW, "Indexing has completed.");
                                indexRunning = false;
                                indexTimer.setInterval(indexTime);
@@ -4269,7 +4354,7 @@ public class NeverNote extends QMainWindow{
                indexRunner.setIndexType(indexRunner.CONTENT);
                indexRunner.addWork("CONTENT "+unindexedNote);
                if (!indexRunning) {
-                       setMessage("Indexing notes.");
+                       setMessage(tr("Indexing notes."));
                        logger.log(logger.LOW, "Beginning to index note contents.");
                        indexRunning = true;
                }
@@ -4279,7 +4364,7 @@ public class NeverNote extends QMainWindow{
                logger.log(logger.EXTREME, "Leaving NeverNote.indexNoteResource()");
                indexRunner.addWork(new String("RESOURCE "+unindexedResource));
                if (!indexRunning) {
-                       setMessage("Indexing notes.");
+                       setMessage(tr("Indexing notes."));
                        indexRunning = true;
                }
                logger.log(logger.EXTREME, "Leaving NeverNote.indexNoteResource()");
@@ -4293,9 +4378,9 @@ public class NeverNote extends QMainWindow{
                logger.log(logger.HIGH, "Entering NeverNote.toggleIndexing");
                indexDisabled = !indexDisabled;
                if (!indexDisabled)
-                       setMessage("Indexing is now enabled.");
+                       setMessage(tr("Indexing is now enabled."));
                else
-                       setMessage("Indexing is now disabled.");
+                       setMessage(tr("Indexing is now disabled."));
                menuBar.disableIndexing.setChecked(indexDisabled);
        logger.log(logger.HIGH, "Leaving NeverNote.toggleIndexing");
     }  
@@ -4310,53 +4395,46 @@ public class NeverNote extends QMainWindow{
                if (!alive) {
                        tagDeadCount++;
                        if (tagDeadCount > MAX)
-                               QMessageBox.information(this, "A thread his died.", "It appears as the tag counter thread has died.  I recommend "+
-                               "checking stopping NeverNote, saving the logs for later viewing, and restarting.  Sorry.");
+                               QMessageBox.information(this, tr("A thread his died."), tr("It appears as the tag counter thread has died.  I recommend "+
+                               "checking stopping NeverNote, saving the logs for later viewing, and restarting.  Sorry."));
                } else
                        tagDeadCount=0;
                
                alive = listManager.threadCheck(Global.notebookCounterThreadId);
                if (!alive) {
                        notebookThreadDeadCount++;
-                       QMessageBox.information(this, "A thread his died.", "It appears as the notebook counter thread has died.  I recommend "+
-                       "checking stopping NeverNote, saving the logs for later viewing, and restarting.  Sorry.");
+                       QMessageBox.information(this, tr("A thread his died."), tr("It appears as the notebook counter thread has died.  I recommend "+
+                       "checking stopping NeverNote, saving the logs for later viewing, and restarting.  Sorry."));
                } else
                        notebookThreadDeadCount=0;
                
                alive = listManager.threadCheck(Global.trashCounterThreadId);
                if (!alive) {
                        trashDeadCount++;
-                       QMessageBox.information(this, "A thread his died.", "It appears as the trash counter thread has died.  I recommend "+
-                       "checking stopping NeverNote, saving the logs for later viewing, and restarting.  Sorry.");
+                       QMessageBox.information(this, tr("A thread his died."), ("It appears as the trash counter thread has died.  I recommend "+
+                       "checking stopping NeverNote, saving the logs for later viewing, and restarting.  Sorry."));
                } else
                        trashDeadCount = 0;
 
                alive = listManager.threadCheck(Global.saveThreadId);
                if (!alive) {
                        saveThreadDeadCount++;
-                       QMessageBox.information(this, "A thread his died.", "It appears as the note saver thread has died.  I recommend "+
-                       "checking stopping NeverNote, saving the logs for later viewing, and restarting.  Sorry.");
+                       QMessageBox.information(this, tr("A thread his died."), tr("It appears as the note saver thread has died.  I recommend "+
+                       "checking stopping NeverNote, saving the logs for later viewing, and restarting.  Sorry."));
                } else
                        saveThreadDeadCount=0;
 
-               if (!dbThread.isAlive()) {
-                       dbThreadDeadCount++;
-                       QMessageBox.information(this, "A thread his died.", "It appears as the database thread has died.  I recommend "+
-                       "checking stopping NeverNote, saving the logs for later viewing, and restarting.  Sorry.");
-               } else
-                       dbThreadDeadCount=0;
-
                if (!syncThread.isAlive()) {
                        syncThreadDeadCount++;
-                       QMessageBox.information(this, "A thread his died.", "It appears as the synchronization thread has died.  I recommend "+
-                       "checking stopping NeverNote, saving the logs for later viewing, and restarting.  Sorry.");
+                       QMessageBox.information(this, tr("A thread his died."), tr("It appears as the synchronization thread has died.  I recommend "+
+                       "checking stopping NeverNote, saving the logs for later viewing, and restarting.  Sorry."));
                } else
                        syncThreadDeadCount=0;
 
                if (!indexThread.isAlive()) {
                        indexThreadDeadCount++;
-                       QMessageBox.information(this, "A thread his died.", "It appears as the index thread has died.  I recommend "+
-                       "checking stopping NeverNote, saving the logs for later viewing, and restarting.  Sorry.");
+                       QMessageBox.information(this, tr("A thread his died."), tr("It appears as the index thread has died.  I recommend "+
+                       "checking stopping NeverNote, saving the logs for later viewing, and restarting.  Sorry."));
                } else
                        indexThreadDeadCount=0;
 
@@ -4373,7 +4451,7 @@ public class NeverNote extends QMainWindow{
                QFileDialog fd = new QFileDialog(this);
                fd.setFileMode(FileMode.AnyFile);
                fd.setConfirmOverwrite(true);
-               fd.setWindowTitle("Backup Database");
+               fd.setWindowTitle(tr("Backup Database"));
                fd.setFilter(tr("NeverNote Export (*.nnex);;All Files (*.*)"));
                fd.setAcceptMode(AcceptMode.AcceptSave);
                fd.setDirectory(System.getProperty("user.home"));
@@ -4383,7 +4461,7 @@ public class NeverNote extends QMainWindow{
                
                
        waitCursor(true);
-       setMessage("Backing up database");
+       setMessage(tr("Backing up database"));
        saveNote();
 //     conn.backupDatabase(Global.getUpdateSequenceNumber(), Global.getSequenceDate());
        
@@ -4393,18 +4471,18 @@ public class NeverNote extends QMainWindow{
        if (!fileName.endsWith(".nnex"))
                fileName = fileName +".nnex";
        noteWriter.exportData(fileName);
-       setMessage("Database backup completed.");
+       setMessage(tr("Database backup completed."));
  
 
        waitCursor(false);
        }
        @SuppressWarnings("unused")
        private void databaseRestore() {
-               if (QMessageBox.question(this, "Confirmation",
-                               "This is used to restore a database from backups.\n" +
+               if (QMessageBox.question(this, tr("Confirmation"),
+                               tr("This is used to restore a database from backups.\n" +
                                "It is HIGHLY recommened that this only be used to populate\n" +
                                "an empty database.  Restoring into a database that\n already has data" +
-                               " can cause problems.\n\nAre you sure you want to continue?",
+                               " can cause problems.\n\nAre you sure you want to continue?"),
                                QMessageBox.StandardButton.Yes, 
                                QMessageBox.StandardButton.No)==StandardButton.No.value()) {
                                        return;
@@ -4414,7 +4492,7 @@ public class NeverNote extends QMainWindow{
                QFileDialog fd = new QFileDialog(this);
                fd.setFileMode(FileMode.ExistingFile);
                fd.setConfirmOverwrite(true);
-               fd.setWindowTitle("Restore Database");
+               fd.setWindowTitle(tr("Restore Database"));
                fd.setFilter(tr("NeverNote Export (*.nnex);;All Files (*.*)"));
                fd.setAcceptMode(AcceptMode.AcceptOpen);
                fd.setDirectory(System.getProperty("user.home"));
@@ -4424,7 +4502,7 @@ public class NeverNote extends QMainWindow{
                
                
                waitCursor(true);
-               setMessage("Restoring database");
+               setMessage(tr("Restoring database"));
        ImportData noteReader = new ImportData(conn, true);
        noteReader.importData(fd.selectedFiles().get(0));
        
@@ -4438,7 +4516,7 @@ public class NeverNote extends QMainWindow{
        listManager.loadNoteTitleColors();
        refreshLists();
        refreshEvernoteNote(true);
-       setMessage("Database has been restored.");
+       setMessage(tr("Database has been restored."));
        waitCursor(false);
        }
        @SuppressWarnings("unused")
@@ -4446,7 +4524,7 @@ public class NeverNote extends QMainWindow{
                QFileDialog fd = new QFileDialog(this);
                fd.setFileMode(FileMode.AnyFile);
                fd.setConfirmOverwrite(true);
-               fd.setWindowTitle("Backup Database");
+               fd.setWindowTitle(tr("Backup Database"));
                fd.setFilter(tr("NeverNote Export (*.nnex);;All Files (*.*)"));
                fd.setAcceptMode(AcceptMode.AcceptSave);
                fd.setDirectory(System.getProperty("user.home"));
@@ -4456,7 +4534,7 @@ public class NeverNote extends QMainWindow{
                
                
        waitCursor(true);
-       setMessage("Exporting Notes");
+       setMessage(tr("Exporting Notes"));
        saveNote();
        
                if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals("")) 
@@ -4468,7 +4546,7 @@ public class NeverNote extends QMainWindow{
        if (!fileName.endsWith(".nnex"))
                fileName = fileName +".nnex";
        noteWriter.exportData(fileName);
-       setMessage("Export completed.");
+       setMessage(tr("Export completed."));
  
 
        waitCursor(false);
@@ -4479,7 +4557,7 @@ public class NeverNote extends QMainWindow{
                QFileDialog fd = new QFileDialog(this);
                fd.setFileMode(FileMode.ExistingFile);
                fd.setConfirmOverwrite(true);
-               fd.setWindowTitle("Import Notes");
+               fd.setWindowTitle(tr("Import Notes"));
                fd.setFilter(tr("NeverNote Export (*.nnex);;All Files (*.*)"));
                fd.setAcceptMode(AcceptMode.AcceptOpen);
                fd.setDirectory(System.getProperty("user.home"));
@@ -4517,7 +4595,7 @@ public class NeverNote extends QMainWindow{
        listManager.loadNoteTitleColors();
        refreshLists();
        refreshEvernoteNote(false);
-       setMessage("Notes have been imported.");
+       setMessage(tr("Notes have been imported."));
        waitCursor(false);
        
        setMessage("Import completed.");
@@ -4654,7 +4732,7 @@ public class NeverNote extends QMainWindow{
                                        listManager.addNote(newNote);
                                        conn.getNoteTable().addNote(newNote, true);
                                        listManager.getUnsynchronizedNotes().add(newNote.getGuid());
-                                       noteTableView.insertRow(listManager, newNote, true, -1);
+                                       noteTableView.insertRow(newNote, true, -1);
                                        listManager.updateNoteContent(newNote.getGuid(), importer.getNoteContent());
                                        listManager.countNotebookResults(listManager.getNoteIndex());
                                        importedFiles.add(list.get(i).absoluteFilePath());
@@ -4695,7 +4773,7 @@ public class NeverNote extends QMainWindow{
                                listManager.addNote(newNote);
                                conn.getNoteTable().addNote(newNote, true);
                                listManager.getUnsynchronizedNotes().add(newNote.getGuid());
-                               noteTableView.insertRow(listManager, newNote, true, -1);
+                               noteTableView.insertRow(newNote, true, -1);
                                listManager.updateNoteContent(newNote.getGuid(), importer.getNoteContent());
                                listManager.countNotebookResults(listManager.getNoteIndex());
                                dir.remove(dir.at(i));
@@ -4709,9 +4787,9 @@ public class NeverNote extends QMainWindow{
        //**************************************************
        private void externalFileEdited(String fileName) throws NoSuchAlgorithmException {
                logger.log(logger.HIGH, "Entering exernalFileEdited");
-               
-               String dPath = Global.getDirectoryPath() + "res/";
-               dPath = dPath.replace('\\', '/');
+
+               // Strip URL prefix and base dir path
+               String dPath = FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath());
                String name = fileName.replace(dPath, "");
                int pos = name.lastIndexOf('.');
                String guid = name;
@@ -4825,7 +4903,7 @@ public class NeverNote extends QMainWindow{
        //*************************************************
        //* Check database userid & passwords
        //*************************************************
-       public boolean databaseCheck(String url,String userid, String userPassword, String cypherPassword) {
+       private static boolean databaseCheck(String url,String userid, String userPassword, String cypherPassword) {
                        Connection connection;
                        
                        try {