OSDN Git Service

Lowered timer for hiding the window on minimize.
[neighbornote/NeighborNote.git] / src / cx / fbn / nevernote / NeverNote.java
index a5c0b79..0d4366d 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;
@@ -59,6 +61,7 @@ import com.trolltech.qt.core.QByteArray;
 import com.trolltech.qt.core.QDataStream;
 import com.trolltech.qt.core.QDateTime;
 import com.trolltech.qt.core.QDir;
+import com.trolltech.qt.core.QEvent;
 import com.trolltech.qt.core.QFile;
 import com.trolltech.qt.core.QFileInfo;
 import com.trolltech.qt.core.QFileSystemWatcher;
@@ -74,6 +77,7 @@ 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;
@@ -84,7 +88,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;
@@ -127,6 +130,7 @@ 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;
@@ -188,7 +192,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?
@@ -280,6 +284,11 @@ 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?
+    Signal0                    minimizeToTray;
+    boolean                            windowMaximized = false;        // Keep track of the window state for restores
     
     String iconPath = new String("classpath:cx/fbn/nevernote/icons/");
        
@@ -297,9 +306,13 @@ public class NeverNote extends QMainWindow{
                
                logger = new ApplicationLogger("nevernote.log");
                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();
@@ -349,8 +362,7 @@ 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;
@@ -392,6 +404,7 @@ 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)");
                
                logger.log(logger.EXTREME, "Starting external file monitor timer");
                externalFileSaveTimer = new QTimer();
@@ -644,8 +657,12 @@ public class NeverNote extends QMainWindow{
      */
     private static DatabaseConnection setupDatabaseConnection() throws InitializationException {
        ApplicationLogger logger = new ApplicationLogger("nevernote-database.log");
-       DatabaseConnection dbConn = new DatabaseConnection(logger,Global.getDatabaseUrl(), Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
-
+       
+       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) {
@@ -658,24 +675,107 @@ public class NeverNote extends QMainWindow{
                         Global.getDatabaseUserPassword(), Global.cipherPassword);
             }
         }
-        return dbConn;
+               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");
+               if (QMessageBox.question(this, "Are you sure", 
+                               "Are you sure you wish to encrypt the database?",
+                               QMessageBox.StandardButton.Yes, 
+                               QMessageBox.StandardButton.No) == StandardButton.Yes.value()) {
+                       ChangeFileEncryption.execute(dbPath, dbName, encryptCipher, null, Global.cipherPassword.toCharArray(), true);
+                       Global.setDatabaseUrl(Global.getDatabaseUrl() + ";CIPHER="+encryptCipher);
+                       QMessageBox.information(this, "Encryption Complete", "Encryption is complete");
+               }
+        } 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";
+               if (QMessageBox.question(this, tr("Confirmation"), tr("Are you sure", 
+                               "Are you sure you wish to decrypt the database?"),
+                               QMessageBox.StandardButton.Yes, 
+                               QMessageBox.StandardButton.No) == StandardButton.Yes.value()) {
 
-       private static void initializeGlobalSettings(String[] args) throws InitializationException {
-                StartupConfig startupConfig = new StartupConfig();
+                       ChangeFileEncryption.execute(dbPath, dbName, encryptCipher, Global.cipherPassword.toCharArray(), null, true);
+                       Global.setDatabaseUrl("");
+                       QMessageBox.information(this, tr("Decryption Complete"), tr("Decryption is complete"));
+               }
+               } 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 = dialog.getEncryptionMethod();
+               }
+        } else {
+            DBEncryptDialog dialog = new DBEncryptDialog();
+            dialog.setWindowTitle("Database Decryption");
+            dialog.hideEncryption();
+            dialog.exec();
+            if (dialog.okPressed()) {
+               if (!dialog.getPassword().equals(Global.cipherPassword)) {
+                       QMessageBox.critical(null, tr("Incorrect Password"), tr("Incorrect Password"));
+                       return;
+               }
+               decryptOnShutdown  = true;
+               encryptCipher = "";
+            }
+        }
+        return;
+    }
 
-                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);
-                }
+       private static void initializeGlobalSettings(String[] args) throws InitializationException {
+               StartupConfig   startupConfig = new StartupConfig();
 
-                Global.setup(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
@@ -737,7 +837,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);
@@ -773,6 +874,12 @@ public class NeverNote extends QMainWindow{
                        }
                }
 
+               if (encryptOnShutdown) {
+                       encryptOnShutdown();
+               }
+               if (decryptOnShutdown) {
+                       decryptOnShutdown();
+               }
                logger.log(logger.HIGH, "Leaving NeverNote.closeEvent");
        }
 
@@ -785,10 +892,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() {
@@ -820,7 +927,7 @@ 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.notebookChanged.connect(this, "updateNoteNotebook(String, String)");
@@ -849,6 +956,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();
@@ -1184,7 +1294,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;
                        }
                }
                
@@ -1594,7 +1704,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);
@@ -1849,13 +1959,15 @@ public class NeverNote extends QMainWindow{
                                                tr("<h4><center><b>NeverNote</b></center></h4><hr><center>Version ")
                                                +Global.version
                                                +tr("<hr></center>Evernote"
-                                                               +" Generic client.<br><br>" 
+                                                               +"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
@@ -1924,10 +2036,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");
@@ -1989,7 +2107,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();
@@ -2002,12 +2120,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);
@@ -2065,6 +2183,10 @@ public class NeverNote extends QMainWindow{
                hide();
        } else {
                show();
+               if (windowMaximized)
+                       showMaximized();
+               else
+                       showNormal();
                raise();
        }
     }
@@ -2188,8 +2310,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;
@@ -2245,12 +2367,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");
@@ -2284,10 +2406,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();
@@ -2308,21 +2429,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");
@@ -2935,6 +3057,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();
@@ -3092,7 +3215,8 @@ public class NeverNote extends QMainWindow{
             String text2 = browserWindow.getContentsToEmail();
             QUrl url = new QUrl("mailto:");
             url.addQueryItem("subject", currentNote.getTitle());
-            url.addQueryItem("body", QUrl.toPercentEncoding(text2).toString());
+//            url.addQueryItem("body", QUrl.toPercentEncoding(text2).toString());
+            url.addQueryItem("body", text2);
             QDesktopServices.openUrl(url);
         }
 /*            
@@ -3341,7 +3465,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
@@ -3364,7 +3488,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() {
@@ -3380,60 +3509,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);
        }
@@ -3576,7 +3683,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
@@ -3875,9 +4000,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++;
                }
@@ -3988,6 +4113,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;
        }
@@ -4118,7 +4252,10 @@ public class NeverNote extends QMainWindow{
                refreshEvernoteNote(false);
                scrollToGuid(currentNoteGuid);
                waitCursor(false);
-               setMessage(tr("Synchronization Complete"));
+               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 saveUploadAmount(long t) {
@@ -4773,7 +4910,23 @@ public class NeverNote extends QMainWindow{
        }
 
 
-       
+       //*************************************************
+       //* Minimize to tray
+       //*************************************************
+       @Override
+       public void changeEvent(QEvent e) {
+               if (e.type() == QEvent.Type.WindowStateChange) {
+                       if (isMinimized() && Global.showTrayIcon()) {
+                               e.accept();
+                               QTimer.singleShot(10, this, "hide()");
+                               return;
+                       }
+                       if (isMaximized())
+                               windowMaximized = true;
+                       else 
+                               windowMaximized = false;
+               }
+       }
        
        //*************************************************
        //* Check database userid & passwords