OSDN Git Service

Update merge with local branch. Changes:
authorRandy Baumgarte <randy@fbn.cx>
Sat, 23 Oct 2010 16:05:41 +0000 (12:05 -0400)
committerRandy Baumgarte <randy@fbn.cx>
Sat, 23 Oct 2010 16:05:41 +0000 (12:05 -0400)
- Notes can now be edited in a separate window by double clicking it from the list.
- You can specify a default font & size for new notes.
- Added additional time & date formats.
- Added an "All Notes" button to the button bar.
- The default notebook can now be changed (although there still isn't a visual indicator on which is the default notebook).
- You can now move the note list to be between the note editor and the left hand items (notebook, tags, etc).  This is by request for wider screens to improve space usage.
- Images are now limited to the maximum width of the window to make viewing easier.
- Added a popup to give an error if NeverNote can't connect to the database because another process is using it.
- Corrected a bug in the save note process that could result in the save thread to crash.
- Corrected numerous issues with encrypting & decrypting text in notes.
- Corrected note import where resources could be lost.
- Corrected an error where note columns would be resized back to the startup values after entering preferences.
- Corrected error when editing a note with a PDF where the PDF could be lost when doing a PDF preview and editing the content.
- Corrected an issue where the online note history may not work due to a null pointer.
- Corrected problem where changing the note status wasn't displayed properly.
- Corrected where threads may not terminate in a timely manor during shutdown.
- Corrected a bug where the note title wasn't being displayed as unsynchronized properly when updated.

37 files changed:
qss/branch-closed.png [new file with mode: 0644]
qss/branch-end.png [new file with mode: 0644]
qss/branch-more.png [new file with mode: 0644]
qss/branch-open.png [new file with mode: 0644]
qss/default.qss
qss/vline.png [new file with mode: 0644]
src/cx/fbn/nevernote/Global.java
src/cx/fbn/nevernote/NeverNote.java
src/cx/fbn/nevernote/dialog/ConfigAppearancePage.java
src/cx/fbn/nevernote/dialog/ConfigDialog.java
src/cx/fbn/nevernote/dialog/ConfigFontPage.java [new file with mode: 0644]
src/cx/fbn/nevernote/dialog/EnDecryptDialog.java
src/cx/fbn/nevernote/dialog/NotebookEdit.java
src/cx/fbn/nevernote/dialog/OnlineNoteHistory.java
src/cx/fbn/nevernote/evernote/EnmlConverter.java
src/cx/fbn/nevernote/gui/BrowserWindow.java
src/cx/fbn/nevernote/gui/ContentView.java
src/cx/fbn/nevernote/gui/ExternalBrowse.java [new file with mode: 0644]
src/cx/fbn/nevernote/gui/MainMenuBar.java
src/cx/fbn/nevernote/gui/NoteTableModel.java
src/cx/fbn/nevernote/gui/NotebookTreeWidget.java
src/cx/fbn/nevernote/gui/SavedSearchTreeWidget.java
src/cx/fbn/nevernote/gui/TableView.java
src/cx/fbn/nevernote/gui/TableViewHeader.java
src/cx/fbn/nevernote/gui/Thumbnailer.java
src/cx/fbn/nevernote/gui/TrashTreeWidget.java
src/cx/fbn/nevernote/signals/NoteSignal.java
src/cx/fbn/nevernote/sql/NoteTable.java
src/cx/fbn/nevernote/sql/NotebookTable.java
src/cx/fbn/nevernote/threads/IndexRunner.java
src/cx/fbn/nevernote/threads/SaveRunner.java
src/cx/fbn/nevernote/threads/SyncRunner.java
src/cx/fbn/nevernote/threads/ThumbnailRunner.java [new file with mode: 0644]
src/cx/fbn/nevernote/utilities/ListManager.java
src/cx/fbn/nevernote/xml/ImportData.java
src/cx/fbn/nevernote/xml/NoteFormatter.java [new file with mode: 0644]
src/cx/fbn/nevernote/xml/XMLCleanup.java

diff --git a/qss/branch-closed.png b/qss/branch-closed.png
new file mode 100644 (file)
index 0000000..213ffdd
Binary files /dev/null and b/qss/branch-closed.png differ
diff --git a/qss/branch-end.png b/qss/branch-end.png
new file mode 100644 (file)
index 0000000..54915b3
Binary files /dev/null and b/qss/branch-end.png differ
diff --git a/qss/branch-more.png b/qss/branch-more.png
new file mode 100644 (file)
index 0000000..664ad44
Binary files /dev/null and b/qss/branch-more.png differ
diff --git a/qss/branch-open.png b/qss/branch-open.png
new file mode 100644 (file)
index 0000000..e8cad95
Binary files /dev/null and b/qss/branch-open.png differ
index 84eb5e0..23685ee 100644 (file)
@@ -1 +1,55 @@
-/* empty stylesheet */
+/* Default stylesheet */
+
+ QTreeView::branch:has-siblings:!adjoins-item  {
+     border-image: url(qss/vline.png) 0;
+ }
+
+ QTreeView::branch:has-siblings:adjoins-item {
+     border-image: url(qss/branch-more.png) 0;
+ }
+
+
+ QTreeView::branch:!has-children:!has-siblings:adjoins-item  {
+     border-image: url(qss/branch-end.png) 0;
+ }
+
+ QTreeView::branch:has-children:!has-siblings:closed,
+ QTreeView::branch:closed:has-children:has-siblings  {
+         border-image: none;
+         image: url(qss/branch-closed.png);
+ }
+
+ QTreeView::branch:open:has-children:!has-siblings,
+ QTreeView::branch:open:has-children:has-siblings  {
+         border-image: none;
+         image: url(qss/branch-open.png);
+ }
+ QTreeView::item {
+      padding: 1px 1px 1px 1px;
+ } 
+ QTreeView[hideTree="true"]::branch:!has-chlidren:hasSiblings {
+       border-image: none;
+       image: none;
+ }
+/*
+ QProgressBar {
+      border: 1px solid gray;
+       border-radius: 1em  ;
+       text-align: center;
+       padding: 2px;
+ }
+*/
+
+QProgressBar { 
+       text-align: center; 
+}
+
+QSpinBox {
+     padding-right: 15px; /* make room for the arrows */
+     border-width: 3;
+     text-align: center;
+ }
\ No newline at end of file
diff --git a/qss/vline.png b/qss/vline.png
new file mode 100644 (file)
index 0000000..8f0c336
Binary files /dev/null and b/qss/vline.png differ
index d5c1139..0791c92 100644 (file)
@@ -36,6 +36,7 @@ import com.evernote.edam.type.UserAttributes;
 import com.swabunga.spell.engine.Configuration;\r
 import com.trolltech.qt.core.QByteArray;\r
 import com.trolltech.qt.core.QSettings;\r
+import com.trolltech.qt.core.QSize;\r
 import com.trolltech.qt.gui.QPalette;\r
 \r
 import cx.fbn.nevernote.config.FileManager;\r
@@ -45,36 +46,34 @@ import cx.fbn.nevernote.gui.ContainsAttributeFilterTable;
 import cx.fbn.nevernote.gui.DateAttributeFilterTable;\r
 import cx.fbn.nevernote.gui.ShortcutKeys;\r
 import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+import cx.fbn.nevernote.utilities.Pair;\r
 \r
 public class Global {\r
-       public static String version = "0.92.1";\r
+       public static String version = "0.94";\r
     public static String username = ""; \r
     public static String password = "";     \r
     \r
 \r
     public static final int mainThreadId=0;\r
-    \r
     public static final int syncThreadId=1;\r
-    \r
     public static final int tagCounterThreadId=2;\r
-    \r
     public static final int trashCounterThreadId=3;   // This should always be the highest thread ID\r
-\r
     public static final int indexThreadId=4;           // Thread for indexing words\r
-\r
     public static final int saveThreadId=5;    // Thread used for processing data to saving content\r
-\r
     public static final int notebookCounterThreadId=6;   // Notebook Thread\r
-\r
     public static final int indexThread03Id=7;   // unused\r
-\r
     public static final int indexThread04Id=8;   // unused\r
-    \r
     public static final int dbThreadId=9;   // This should always be the highest thread ID\r
     \r
     \r
-    public static HashMap<String,String> passwordSafe = new HashMap<String, String>();\r
-    public static List<String> passwordRemember = new ArrayList<String>();\r
+    public static int View_List_Wide = 1;\r
+    public static int View_List_Narrow = 2;\r
+    public static QSize smallThumbnailSize = new QSize(50,50);\r
+    public static QSize largeThumbnailSize = new QSize(160,160);\r
+    public static boolean listView = true;\r
+    \r
+    public static HashMap<String,Pair> passwordSafe = new HashMap<String, Pair>();\r
+    public static List<Pair<String,String>> passwordRemember = new ArrayList<Pair<String,String>>();\r
     public static String currentNotebookGuid;\r
     public static User user; \r
     public static long authTimeRemaining;\r
@@ -96,7 +95,8 @@ public class Global {
     public static int noteTableSourceUrlPosition = 7;\r
     public static int noteTableSubjectDatePosition = 8;\r
     public static int noteTableSynchronizedPosition = 9;\r
-    public static int noteTableColumnCount = 10;\r
+    public static int noteTableThumbnailPosition = 10;\r
+    public static int noteTableColumnCount = 11;\r
     public static Integer cryptCounter = 0;\r
     \r
     public static int minimumWordCount = 2;\r
@@ -712,8 +712,13 @@ public class Global {
                settings.endGroup();\r
     }\r
     public static boolean isColumnVisible(String window) {\r
+       String defaultValue = "true";\r
                settings.beginGroup("ColumnsVisible");\r
-               String text = (String)settings.value(window, "true");\r
+               if (window.equalsIgnoreCase("thumbnail"))\r
+                       defaultValue = "false";\r
+               if (window.equalsIgnoreCase("Guid"))\r
+                       defaultValue = "false";\r
+               String text = (String)settings.value(window, defaultValue);\r
                settings.endGroup();\r
                if (text.equalsIgnoreCase("true"))\r
                        return true;\r
@@ -990,7 +995,7 @@ public class Global {
                        try {\r
                                value = (Integer)settings.value("autoSaveInterval", 5);\r
                        } catch (Exception e1) {\r
-                               value = 0;\r
+                               value = 5;\r
                        }\r
                }\r
                settings.endGroup();\r
@@ -1162,6 +1167,74 @@ public class Global {
     public static boolean getDisableViewing() {\r
         return disableViewing;\r
     }\r
+\r
+    \r
+    //**********************\r
+    //* List View settings \r
+    //**********************\r
+    public static void setListView(int view) {\r
+               settings.beginGroup("General");\r
+               settings.setValue("listView", view);\r
+               settings.endGroup();\r
+    }\r
+    public static int getListView() {\r
+               settings.beginGroup("General");\r
+               Integer value;\r
+               try {\r
+                       String val  = (String)settings.value("listView", View_List_Wide);\r
+                       value = new Integer(val.trim());\r
+               } catch (Exception e) {\r
+                       try {\r
+                               value = (Integer)settings.value("listView", View_List_Wide);\r
+                       } catch (Exception e1) {\r
+                               value = View_List_Wide;\r
+                       }\r
+               }\r
+               settings.endGroup();\r
+               return value;\r
+    }\r
+\r
+    \r
+    \r
+    //*******************\r
+    // Font Settings\r
+    //*******************\r
+    public static boolean overrideDefaultFont() {\r
+               settings.beginGroup("Font");\r
+               String text = (String)settings.value("overrideFont", "false");\r
+               settings.endGroup();\r
+               if (text.equalsIgnoreCase("true"))\r
+                       return true;\r
+               else\r
+                       return false;   \r
+    }\r
+    public static void setOverrideDefaultFont(boolean value) {\r
+               settings.beginGroup("Font");\r
+               settings.setValue("overrideFont", value);\r
+               settings.endGroup();    \r
+    }\r
+    public static String getDefaultFont() {\r
+               settings.beginGroup("Font");\r
+               String val  = (String)settings.value("font", "");\r
+               settings.endGroup();\r
+               return val;\r
+    }\r
+    public static void setDefaultFont(String value) {\r
+               settings.beginGroup("Font");\r
+               settings.setValue("font", value);\r
+               settings.endGroup();\r
+    }\r
+    public static String getDefaultFontSize() {\r
+               settings.beginGroup("Font");\r
+               String val  = (String)settings.value("fontSize", "");\r
+               settings.endGroup();\r
+               return val;\r
+    }\r
+    public static void setDefaultFontSize(String value) {\r
+               settings.beginGroup("Font");\r
+               settings.setValue("fontSize", value);\r
+               settings.endGroup();\r
+    }\r
     \r
 \r
 }\r
index 1c4a450..9af637f 100644 (file)
@@ -32,11 +32,13 @@ import java.sql.Statement;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Calendar;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Date;
 import java.util.GregorianCalendar;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.SortedMap;
 import java.util.Vector;
@@ -60,7 +62,6 @@ import com.evernote.edam.type.Tag;
 import com.evernote.edam.type.User;
 import com.trolltech.qt.QThread;
 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;
@@ -79,6 +80,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.BGMode;
 import com.trolltech.qt.core.Qt.ItemDataRole;
 import com.trolltech.qt.core.Qt.SortOrder;
 import com.trolltech.qt.core.Qt.WidgetAttribute;
@@ -105,6 +107,8 @@ import com.trolltech.qt.gui.QMainWindow;
 import com.trolltech.qt.gui.QMenu;
 import com.trolltech.qt.gui.QMessageBox;
 import com.trolltech.qt.gui.QMessageBox.StandardButton;
+import com.trolltech.qt.gui.QPainter;
+import com.trolltech.qt.gui.QPalette.ColorRole;
 import com.trolltech.qt.gui.QPixmap;
 import com.trolltech.qt.gui.QPrintDialog;
 import com.trolltech.qt.gui.QPrinter;
@@ -122,12 +126,7 @@ import com.trolltech.qt.gui.QToolBar;
 import com.trolltech.qt.gui.QTreeWidgetItem;
 import com.trolltech.qt.webkit.QWebPage.WebAction;
 import com.trolltech.qt.webkit.QWebSettings;
-import com.trolltech.qt.xml.QDomAttr;
-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;
@@ -144,13 +143,12 @@ import cx.fbn.nevernote.dialog.SavedSearchEdit;
 import cx.fbn.nevernote.dialog.TagEdit;
 import cx.fbn.nevernote.dialog.ThumbnailViewer;
 import cx.fbn.nevernote.dialog.WatchFolder;
-import cx.fbn.nevernote.filters.EnSearch;
 import cx.fbn.nevernote.gui.AttributeTreeWidget;
 import cx.fbn.nevernote.gui.BrowserWindow;
 import cx.fbn.nevernote.gui.DateAttributeFilterTable;
+import cx.fbn.nevernote.gui.ExternalBrowse;
 import cx.fbn.nevernote.gui.MainMenuBar;
 import cx.fbn.nevernote.gui.NotebookTreeWidget;
-import cx.fbn.nevernote.gui.PDFPreview;
 import cx.fbn.nevernote.gui.SavedSearchTreeWidget;
 import cx.fbn.nevernote.gui.TableView;
 import cx.fbn.nevernote.gui.TagTreeWidget;
@@ -160,6 +158,7 @@ import cx.fbn.nevernote.sql.DatabaseConnection;
 import cx.fbn.nevernote.sql.WatchFolderRecord;
 import cx.fbn.nevernote.threads.IndexRunner;
 import cx.fbn.nevernote.threads.SyncRunner;
+import cx.fbn.nevernote.threads.ThumbnailRunner;
 import cx.fbn.nevernote.utilities.AESEncrypter;
 import cx.fbn.nevernote.utilities.ApplicationLogger;
 import cx.fbn.nevernote.utilities.FileImporter;
@@ -168,7 +167,7 @@ import cx.fbn.nevernote.utilities.ListManager;
 import cx.fbn.nevernote.utilities.SyncTimes;
 import cx.fbn.nevernote.xml.ExportData;
 import cx.fbn.nevernote.xml.ImportData;
-import cx.fbn.nevernote.xml.XMLInsertHilight;
+import cx.fbn.nevernote.xml.NoteFormatter;
 
 
 public class NeverNote extends QMainWindow{
@@ -205,6 +204,7 @@ public class NeverNote extends QMainWindow{
     List<String>                       selectedTagGUIDs;                       // List of selected tag GUIDs
     List<String>                       selectedNoteGUIDs;                      // List of selected notes
     String                                     selectedSavedSearchGUID;        // Currently selected saved searches
+    private final HashMap<String, ExternalBrowse>      externalWindows;        // Notes being edited by an external window;
     
     NoteFilter                         filter;                                         // Note filter
     String                                     currentNoteGuid;                        // GUID of the current note 
@@ -223,11 +223,14 @@ public class NeverNote extends QMainWindow{
     QTimer                                     syncTimer;                                      // Sync on an interval
     QTimer                                     syncDelayTimer;                         // Sync delay to free up database
     SyncRunner                         syncRunner;                                     // thread to do a sync.
-    QThread                                    syncThread;
+    QThread                                    syncThread;                                     // Thread which talks to evernote
+    ThumbnailRunner                    thumbnailRunner;                        // Runner for thumbnail thread
+    QThread                                    thumbnailThread;                        // Thread that generates pretty pictures
     QTimer                                     saveTimer;                                      // Timer to save note contents
     
     QTimer                                     authTimer;                                      // Refresh authentication
     QTimer                                     externalFileSaveTimer;          // Save files altered externally
+    QTimer                                     thumbnailTimer;                         // Wakeup & scan for thumbnails
     List<String>                       externalFiles;                          // External files to save later
     List<String>                       importFilesKeep;                        // Auto-import files to save later
     List<String>                       importFilesDelete;                      // Auto-import files to save later
@@ -247,9 +250,9 @@ public class NeverNote extends QMainWindow{
     QAction                            downButton;                                     // Go to the next item in the list
     QAction                            upButton;                                       // Go to the prev. item in the list;
     QAction                            synchronizeButton;                      // Synchronize with Evernote
-    List<QIcon>                        synchronizeAnimation;           // Synchronize movie
+    QAction                            allNotesButton;                         // Reset & view all notes
     QTimer                             synchronizeAnimationTimer;      // Timer to change animation button
-    int                                        synchronizeFrame;                       // Current frame being viewed
+    double                             synchronizeIconAngle;           // Used to rotate sync icon
     QAction                    printButton;                            // Print Button
     QAction                            tagButton;                                      // Tag edit button
     QAction                            attributeButton;                        // Attribute information button
@@ -284,13 +287,15 @@ public class NeverNote extends QMainWindow{
     int                                        historyPosition;                        // Position within the viewed items
     boolean                            fromHistory;                            // Is this from the history queue?
     String                             trashNoteGuid;                          // Guid to restore / set into or out of trash to save position
-    Thumbnailer                        preview;                                        // generate preview image
+    List<Thumbnailer>  previewList;                            // 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
+    List<String>               pdfReadyQueue;                          // Queue of PDFs that are ready to be rendered.
+    
     
     String iconPath = new String("classpath:cx/fbn/nevernote/icons/");
        
@@ -303,6 +308,14 @@ public class NeverNote extends QMainWindow{
     // Application Constructor 
        public NeverNote(DatabaseConnection dbConn)  {
                conn = dbConn;          
+               if (conn.getConnection() == null) {
+                       String msg = "Unable to connect to the database.\n\nThe most probable reason is that some other process\n" +
+                               "is accessing the database or NeverNote is already running.\n\n" +
+                               "Please end any other process or shutdown the other NeverNote before starting.\n\nExiting program.";
+                       
+            QMessageBox.critical(null, "Database Connection Error",msg);
+                       System.exit(16);
+               }
 
                thread().setPriority(Thread.MAX_PRIORITY);
                
@@ -388,6 +401,19 @@ public class NeverNote extends QMainWindow{
                syncThread.start();
                
                
+               logger.log(logger.EXTREME, "Starting thumnail thread");
+               pdfReadyQueue = new ArrayList<String>();
+               thumbnailRunner = new ThumbnailRunner("thumbnailRunner.log", Global.getDatabaseUrl(), Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
+               thumbnailThread = new QThread(thumbnailRunner, "Thumbnail Thread");
+               thumbnailRunner.noteSignal.thumbnailPageReady.connect(this, "thumbnailHTMLReady(String,String)");
+//             thumbnailThread.start();
+               previewList = new ArrayList<Thumbnailer>();
+               thumbnailTimer = new QTimer();
+               thumbnailTimer.timeout.connect(this, "thumbnailTimer()");
+               thumbnailTimer();
+               thumbnailTimer.setInterval(30*1000);
+//             thumbnailTimer.start();
+               
                logger.log(logger.EXTREME, "Starting authentication timer");
                authTimer = new QTimer();
                authTimer.timeout.connect(this, "authTimer()");
@@ -399,7 +425,7 @@ public class NeverNote extends QMainWindow{
                saveTimer.timeout.connect(this, "saveNote()");
                if (Global.getAutoSaveInterval() > 0) {
                        saveTimer.setInterval(1000*60*Global.getAutoSaveInterval()); 
-//                     saveTimer.setInterval(1000*10); // auto save every 20 seconds;
+//                     saveTimer.setInterval(1000*10); // auto save every 10 seconds;
                        saveTimer.start();
                }
                listManager.saveRunner.noteSignals.noteSaveRunnerError.connect(this, "saveRunnerError(String, String)");
@@ -432,12 +458,20 @@ public class NeverNote extends QMainWindow{
         noteCache = new HashMap<String,String>();
         browserWindow = new BrowserWindow(conn);
 
-        browserIndexSplitter.addWidget(noteTableView);
-        browserIndexSplitter.addWidget(browserWindow);
+        if (Global.getListView() == Global.View_List_Wide) {
+               browserIndexSplitter.addWidget(noteTableView);
+               browserIndexSplitter.addWidget(browserWindow); 
+        }
         
         mainLeftRightSplitter.addWidget(leftSplitter1);
         mainLeftRightSplitter.addWidget(browserIndexSplitter);
 
+        if (Global.getListView() == Global.View_List_Narrow) {
+               mainLeftRightSplitter.addWidget(noteTableView);
+               mainLeftRightSplitter.addWidget(browserWindow); 
+        }
+
+        
         searchField = new QComboBox();
         searchField.setEditable(true);
        searchField.activatedIndex.connect(this, "searchFieldChanged()");
@@ -452,6 +486,9 @@ public class NeverNote extends QMainWindow{
        thumbnailViewer.downArrow.connect(this, "downAction()");
        thumbnailViewer.leftArrow.connect(this, "nextViewedAction()");
        thumbnailViewer.rightArrow.connect(this, "previousViewedAction()");
+       
+       //Setup external browser manager
+       externalWindows = new HashMap<String, ExternalBrowse>();
 
        listManager.loadNotesIndex();
         initializeNotebookTree();
@@ -506,7 +543,6 @@ public class NeverNote extends QMainWindow{
                trashTree.setVisible(Global.isWindowVisible("trashTree"));
                menuBar.hideTrash.setChecked(Global.isWindowVisible("trashTree"));
                trashTree.updateCounts(listManager.getTrashCount());
-
                attributeTree.setVisible(Global.isWindowVisible("attributeTree"));
                menuBar.hideAttributes.setChecked(Global.isWindowVisible("attributeTree"));
 
@@ -559,7 +595,7 @@ public class NeverNote extends QMainWindow{
                showColumns();
                menuBar.showEditorBar.setChecked(Global.isWindowVisible("editorButtonBar"));
                if (menuBar.showEditorBar.isChecked())
-               showEditorButtons();
+               showEditorButtons(browserWindow);
                tagIndexUpdated(true);
                savedSearchIndexUpdated();
                notebookIndexUpdated();
@@ -602,9 +638,31 @@ public class NeverNote extends QMainWindow{
        historyGuids.add(currentNoteGuid);
        historyPosition = 1;
        
+        if (Global.getListView() == Global.View_List_Narrow) { 
+               menuBar.narrowListView.setChecked(true);
+               narrowListView();
+        }
+        else{ 
+               menuBar.wideListView.setChecked(true);
+               wideListView();
+        }
+
+       
        int sortCol = Global.getSortColumn();
                int sortOrder = Global.getSortOrder();
                noteTableView.sortByColumn(sortCol, SortOrder.resolve(sortOrder));
+
+               /*
+               for (int i=0; i<listManager.getNoteIndex().size(); i++) {
+                       Note n = listManager.getNoteIndex().get(i);
+                       if (n.getNotebookGuid().equalsIgnoreCase("2")) {
+                               conn.getNoteTable().updateNoteSequence(n.getGuid(), 0);
+                               n = conn.getNoteTable().getNote(n.getGuid(), false, true, false, false, true);
+                               for (int j=0; j<n.getResourcesSize(); j++) {
+                                       conn.getNoteTable().noteResourceTable.resetUpdateSequenceNumber(n.getResources().get(j).getGuid(), true);       
+                               }
+                       }
+               } */
        }
 
        
@@ -794,7 +852,17 @@ public class NeverNote extends QMainWindow{
                }
                saveNote();
                setMessage(tr("Beginning shutdown."));
-
+               
+               // Close down external windows
+               Collection<ExternalBrowse> windows = externalWindows.values();
+               Iterator<ExternalBrowse> iterator = windows.iterator();
+               while (iterator.hasNext()) {
+                       ExternalBrowse browser = iterator.next();
+                       browser.windowClosing.disconnect();
+                       browser.close();
+               }
+               
+               
                externalFileEditedSaver();
                if (Global.isConnected && Global.synchronizeOnClose()) {
                        setMessage(tr("Performing synchronization before closing."));
@@ -804,7 +872,11 @@ public class NeverNote extends QMainWindow{
                threadMonitorTimer.stop();
 
                syncRunner.addWork("STOP");
+               syncRunner.keepRunning = false;
+               thumbnailRunner.addWork("STOP");
+               syncRunner.keepRunning = false;
                indexRunner.addWork("STOP");
+               syncRunner.keepRunning = false;
                saveNote();
                listManager.stop();
                saveWindowState();
@@ -842,6 +914,10 @@ public class NeverNote extends QMainWindow{
                Global.setColumnPosition("noteTableTitlePosition", position);
                position = noteTableView.header.visualIndex(Global.noteTableSynchronizedPosition);
                Global.setColumnPosition("noteTableSynchronizedPosition", position);
+               position = noteTableView.header.visualIndex(Global.noteTableGuidPosition);
+               Global.setColumnPosition("noteTableGuidPosition", position);
+               position = noteTableView.header.visualIndex(Global.noteTableThumbnailPosition);
+               Global.setColumnPosition("noteTableThumbnailPosition", position);
 
                if (isVisible())
                        Global.saveWindowVisible("toolBar", toolBar.isVisible());
@@ -929,26 +1005,27 @@ public class NeverNote extends QMainWindow{
        }
        
        private void setupBrowserSignalListeners() {
-               
-               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, "setNoteDirty()");
-           browserWindow.noteSignal.titleChanged.connect(listManager, "updateNoteTitle(String, String)");
-           browserWindow.noteSignal.notebookChanged.connect(this, "updateNoteNotebook(String, String)");
-           browserWindow.noteSignal.createdDateChanged.connect(listManager, "updateNoteCreatedDate(String, QDateTime)");
-           browserWindow.noteSignal.alteredDateChanged.connect(listManager, "updateNoteAlteredDate(String, QDateTime)");
-           browserWindow.noteSignal.subjectDateChanged.connect(listManager, "updateNoteSubjectDate(String, QDateTime)");
-           browserWindow.noteSignal.authorChanged.connect(listManager, "updateNoteAuthor(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.focusLost.connect(this, "saveNote()");
-           browserWindow.resourceSignal.contentChanged.connect(this, "externalFileEdited(String)");
+               setupBrowserWindowListeners(browserWindow, true);
        }
 
-       
+       private void setupBrowserWindowListeners(BrowserWindow browser, boolean master) {
+               browser.fileWatcher.fileChanged.connect(this, "externalFileEdited(String)");
+               browser.noteSignal.tagsChanged.connect(this, "updateNoteTags(String, List)");
+           browser.noteSignal.tagsChanged.connect(this, "updateListTags(String, List)");
+           if (master) browser.noteSignal.noteChanged.connect(this, "setNoteDirty()");
+           browser.noteSignal.titleChanged.connect(listManager, "updateNoteTitle(String, String)");
+           browser.noteSignal.titleChanged.connect(this, "updateNoteTitle(String, String)");
+           browser.noteSignal.notebookChanged.connect(this, "updateNoteNotebook(String, String)");
+           browser.noteSignal.createdDateChanged.connect(listManager, "updateNoteCreatedDate(String, QDateTime)");
+           browser.noteSignal.alteredDateChanged.connect(listManager, "updateNoteAlteredDate(String, QDateTime)");
+           browser.noteSignal.subjectDateChanged.connect(listManager, "updateNoteSubjectDate(String, QDateTime)");
+           browser.noteSignal.authorChanged.connect(listManager, "updateNoteAuthor(String, String)");
+           browser.noteSignal.geoChanged.connect(listManager, "updateNoteGeoTag(String, Double,Double,Double)");
+           browser.noteSignal.geoChanged.connect(this, "setNoteDirty()");
+           browser.noteSignal.sourceUrlChanged.connect(listManager, "updateNoteSourceUrl(String, String)");
+           if (master) browser.focusLost.connect(this, "saveNote()");
+           browser.resourceSignal.contentChanged.connect(this, "externalFileEdited(String)");
+       }
 
        //***************************************************************
        //***************************************************************
@@ -958,6 +1035,7 @@ public class NeverNote extends QMainWindow{
        @SuppressWarnings("unused")
        private void settings() {
                logger.log(logger.HIGH, "Entering NeverNote.settings");
+               saveNoteIndexWidth();
         ConfigDialog settings = new ConfigDialog(this);
         String dateFormat = Global.getDateFormat();
         String timeFormat = Global.getTimeFormat();
@@ -972,7 +1050,7 @@ public class NeverNote extends QMainWindow{
                trayIcon.hide();
         showColumns();
         if (menuBar.showEditorBar.isChecked())
-               showEditorButtons();
+               showEditorButtons(browserWindow);
         
         // Reset the save timer
         if (Global.getAutoSaveInterval() > 0)
@@ -1043,6 +1121,10 @@ public class NeverNote extends QMainWindow{
                Global.setColumnWidth("noteTableSubjectDatePosition", width);
                width = noteTableView.getColumnWidth(Global.noteTableSynchronizedPosition);
                Global.setColumnWidth("noteTableSynchronizedPosition", width);
+               width = noteTableView.getColumnWidth(Global.noteTableThumbnailPosition);
+               Global.setColumnWidth("noteTableThumbnailPosition", width);
+               width = noteTableView.getColumnWidth(Global.noteTableGuidPosition);
+               Global.setColumnWidth("noteTableGuidPosition", width);
        }
        
        
@@ -1199,18 +1281,31 @@ public class NeverNote extends QMainWindow{
                currentSelection = selections.get(0);
                edit.setNotebook(currentSelection.text(0));
                edit.setNotebooks(listManager.getNotebookIndex());
+
+               String guid = currentSelection.text(2);
+               for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
+                       if (listManager.getNotebookIndex().get(i).getGuid().equals(guid)) {
+                               edit.setDefaultNotebook(listManager.getNotebookIndex().get(i).isDefaultNotebook());
+                               i=listManager.getNotebookIndex().size();
+                       }
+               }
                edit.exec();
        
                if (!edit.okPressed())
                        return;
         
-               String guid = currentSelection.text(2);
                updateListNotebookName(currentSelection.text(0), edit.getNotebook());
                currentSelection.setText(0, edit.getNotebook());
                
                for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
                        if (listManager.getNotebookIndex().get(i).getGuid().equals(guid)) {
                                listManager.getNotebookIndex().get(i).setName(edit.getNotebook());
+                               if (!listManager.getNotebookIndex().get(i).isDefaultNotebook() && edit.isDefaultNotebook()) {
+                                       for (int j=0; j<listManager.getNotebookIndex().size(); j++)
+                                               listManager.getNotebookIndex().get(j).setDefaultNotebook(false);
+                                       listManager.getNotebookIndex().get(i).setDefaultNotebook(true);
+                                       conn.getNotebookTable().setDefaultNotebook(listManager.getNotebookIndex().get(i).getGuid());
+                               }
                                conn.getNotebookTable().updateNotebook(listManager.getNotebookIndex().get(i), true);
                                i=listManager.getNotebookIndex().size();
                        }
@@ -2079,16 +2174,10 @@ public class NeverNote extends QMainWindow{
        toggleDownArrowButton(Global.isToolbarButtonVisible("downArrow"));
        
        synchronizeButton = toolBar.addAction("Synchronize");
-       synchronizeAnimation = new ArrayList<QIcon>();
-       synchronizeAnimation.add(new QIcon(iconPath+"synchronize-0.png"));
-       synchronizeAnimation.add(new QIcon(iconPath+"synchronize-1.png"));
-       synchronizeAnimation.add(new QIcon(iconPath+"synchronize-2.png"));
-       synchronizeAnimation.add(new QIcon(iconPath+"synchronize-3.png"));
-       synchronizeButton.setIcon(synchronizeAnimation.get(0));
-       synchronizeFrame = 0;
+       synchronizeButton.setIcon(new QIcon(iconPath+"synchronize.png"));
+       synchronizeIconAngle = 0;
        synchronizeButton.triggered.connect(this, "evernoteSync()");
        toggleSynchronizeButton(Global.isToolbarButtonVisible("synchronize"));
-
        
        printButton = toolBar.addAction("Print");
        QIcon printIcon = new QIcon(iconPath+"print.png");
@@ -2126,11 +2215,18 @@ public class NeverNote extends QMainWindow{
        newButton.setIcon(newIcon);
        toggleNewButton(Global.isToolbarButtonVisible("new"));
        
+       allNotesButton = toolBar.addAction("All Notes");
+       QIcon allIcon = new QIcon(iconPath+"allNotes3.png");
+       allNotesButton.triggered.connect(this, "allNotes()");
+       allNotesButton.setIcon(allIcon);
+       toggleAllNotesButton(Global.isToolbarButtonVisible("allNotes"));
+       
        toolBar.addSeparator();
        toolBar.addWidget(new QLabel(tr("Quota:")));
        toolBar.addWidget(quotaBar);
        //quotaBar.setSizePolicy(Policy.Minimum, Policy.Minimum);
        updateQuotaBar();
+       toolBar.addSeparator();
        
        // Setup the zoom
        zoomSpinner = new QSpinBox();
@@ -2209,7 +2305,11 @@ public class NeverNote extends QMainWindow{
        QAction newAction = addContextAction("new", tr("Add"));
        contextMenu.addAction(newAction);
        newAction.triggered.connect(this, "toggleNewButton(Boolean)");
-               
+
+       QAction allNotesAction = addContextAction("allNotes", tr("All Notes"));
+       contextMenu.addAction(allNotesAction);
+       allNotesAction.triggered.connect(this, "toggleAllNotesButton(Boolean)");
+       
        QAction searchClearAction = addContextAction("searchClear", tr("Search Clear"));
        contextMenu.addAction(searchClearAction);
        searchClearAction.triggered.connect(this, "toggleSearchClearButton(Boolean)");
@@ -2268,6 +2368,10 @@ public class NeverNote extends QMainWindow{
                newButton.setVisible(toggle);
                Global.saveToolbarButtonsVisible("new", toggle);
     }
+    private void toggleAllNotesButton(Boolean toggle) {
+               allNotesButton.setVisible(toggle);
+               Global.saveToolbarButtonsVisible("allNotes", toggle);
+    }
     private void toggleSearchClearButton(Boolean toggle) {
                searchClearButton.setVisible(toggle);
                Global.saveToolbarButtonsVisible("searchClear", toggle);
@@ -2279,10 +2383,42 @@ public class NeverNote extends QMainWindow{
 
     @SuppressWarnings("unused")
        private void updateSyncButton() {
      synchronizeFrame++;
/*    synchronizeFrame++;
        if (synchronizeFrame == 4) 
                synchronizeFrame = 0;
        synchronizeButton.setIcon(synchronizeAnimation.get(synchronizeFrame));
+       */
+/*     
+       QPixmap pix = new QPixmap(iconPath+"synchronize.png");
+       QMatrix matrix = new QMatrix();
+       synchronizeIconAngle = synchronizeIconAngle + 1.0;
+       if (synchronizeIconAngle >= 365.0)
+               synchronizeIconAngle = 0.0;
+       matrix.translate(pix.size().width()/2, pix.size().height()/2);
+               matrix.rotate( synchronizeIconAngle );
+       matrix.translate(-pix.size().width()/2, -pix.size().height()/2);
+               pix = pix.transformed(matrix, TransformationMode.SmoothTransformation);
+       synchronizeButton.setIcon(pix);
+*/
+               
+       
+       QPixmap pix = new QPixmap(iconPath+"synchronize.png");
+       QPixmap rotatedPix = new QPixmap(pix.size());
+       QPainter p = new QPainter(rotatedPix);
+
+       rotatedPix.fill(toolBar.palette().color(ColorRole.Button));
+       QSize size = pix.size();
+       p.translate(size.width()/2, size.height()/2);
+       synchronizeIconAngle = synchronizeIconAngle+1.0;
+       if (synchronizeIconAngle >= 359.0)
+               synchronizeIconAngle = 0.0;
+       p.rotate(synchronizeIconAngle);
+       p.setBackgroundMode(BGMode.OpaqueMode);
+       p.translate(-size.width()/2, -size.height()/2);
+       p.drawPixmap(0,0, pix);
+       p.end();
+       synchronizeButton.setIcon(rotatedPix);
+       
     }
     // Synchronize with Evernote
        @SuppressWarnings("unused")
@@ -2291,7 +2427,8 @@ public class NeverNote extends QMainWindow{
        if (!Global.isConnected)
                remoteConnect();
        if (Global.isConnected)
-               synchronizeAnimationTimer.start(200);
+               synchronizeAnimationTimer.start(10);
+//                     synchronizeAnimationTimer.start(200);
        syncTimer();
        logger.log(logger.HIGH, "Leaving NeverNote.evernoteSync");
     }
@@ -2668,7 +2805,8 @@ public class NeverNote extends QMainWindow{
        noteTableView.showColumn(Global.noteTableGuidPosition);
        
        List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
-       noteTableView.hideColumn(Global.noteTableGuidPosition);
+       if (!Global.isColumnVisible("guid"))
+               noteTableView.hideColumn(Global.noteTableGuidPosition);
        
        if (selections.size() > 0) {
                QModelIndex index;
@@ -2857,6 +2995,7 @@ public class NeverNote extends QMainWindow{
                        if (tableGuid.equals(guid)) {
                                listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition,tagBuffer.toString());
                                listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
+                               noteTableView.proxyModel.invalidate();
                                return;
                        }
                }
@@ -2872,16 +3011,17 @@ public class NeverNote extends QMainWindow{
                //QModelIndex modelIndex =  noteTableView.proxyModel.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 = listManager.getNoteTableModel().itemData(modelIndex);
                        String tableGuid =  (String)ix.values().toArray()[0];
                        if (tableGuid.equals(guid)) {
                                listManager.getNoteTableModel().setData(i, Global.noteTableAuthorPosition,author);
                                listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
+                               noteTableView.proxyModel.invalidate();
                                return;
                        }       
                }
        }
+       
        logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
     }
        private void updateListNoteNotebook(String guid, String notebook) {
@@ -2904,6 +3044,7 @@ public class NeverNote extends QMainWindow{
                        if (tableGuid.equals(guid)) {
                                listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
                                listManager.getNoteTableModel().setData(i, Global.noteTableSourceUrlPosition,url);
+                               noteTableView.proxyModel.invalidate();
                                return;
                        }       
                }
@@ -2941,7 +3082,6 @@ public class NeverNote extends QMainWindow{
                                                String noteGuid = (String)ix.values().toArray()[0];
                                                if (noteGuid.equalsIgnoreCase(listManager.getNoteIndex().get(j).getGuid())) {
                                                        listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition, newName);
-                                                       //listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
                                                        i=listManager.getNoteTableModel().rowCount();
                                                }
                                        }
@@ -2968,7 +3108,6 @@ public class NeverNote extends QMainWindow{
                                                String noteGuid = (String)ix.values().toArray()[0];
                                                if (noteGuid.equalsIgnoreCase(listManager.getNoteIndex().get(j).getGuid())) {
                                                        listManager.getNoteTableModel().setData(i, Global.noteTableTagPosition, newName);
-//                                                     listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
                                                        i=listManager.getNoteTableModel().rowCount();
                                                }
                                        }
@@ -2986,7 +3125,6 @@ public class NeverNote extends QMainWindow{
                        SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
                        String tableName =  (String)ix.values().toArray()[0];
                        if (tableName.equalsIgnoreCase(oldName)) {
-//                             listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
                                listManager.getNoteTableModel().setData(i, Global.noteTableNotebookPosition, newName);
                        }
                }
@@ -3004,6 +3142,7 @@ public class NeverNote extends QMainWindow{
                        String tableGuid =  (String)ix.values().toArray()[0];
                        if (tableGuid.equals(guid)) {
                                listManager.getNoteTableModel().setData(i, Global.noteTableCreationPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
+                               noteTableView.proxyModel.invalidate();
                                return;
                        }
                }
@@ -3022,6 +3161,7 @@ public class NeverNote extends QMainWindow{
                        if (tableGuid.equals(guid)) {
                                listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
                                listManager.getNoteTableModel().setData(i, Global.noteTableSubjectDatePosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
+                               noteTableView.proxyModel.invalidate();
                                return;
                        }
                }
@@ -3048,19 +3188,8 @@ 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<listManager.getNoteTableModel().rowCount(); i++) {
-               QModelIndex modelIndex =  listManager.getNoteTableModel().index(i, Global.noteTableGuidPosition);
-               if (modelIndex != null) {
-                       SortedMap<Integer, Object> ix = listManager.getNoteTableModel().itemData(modelIndex);
-                       String tableGuid =  (String)ix.values().toArray()[0];
-                       if (tableGuid.equals(currentNoteGuid)) {
-                               listManager.getNoteTableModel().setData(i, Global.noteTableSynchronizedPosition, "false");
-                               listManager.getNoteTableModel().setData(i, Global.noteTableChangedPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
-                               return;
-                       }
-               }
-       }
+       QDateTime date = new QDateTime(QDateTime.currentDateTime());
+       updateListDateChanged(currentNoteGuid, date);
        logger.log(logger.HIGH, "Leaving NeverNote.updateListDateChanged");
     }  
     // Redo scroll
@@ -3120,11 +3249,8 @@ public class NeverNote extends QMainWindow{
                noteTableView.setColumnHidden(Global.noteTableTagPosition, !Global.isColumnVisible("tags"));
                noteTableView.setColumnHidden(Global.noteTableNotebookPosition, !Global.isColumnVisible("notebook"));
                noteTableView.setColumnHidden(Global.noteTableSynchronizedPosition, !Global.isColumnVisible("synchronized"));
-    }
-    // Open a separate window
-    @SuppressWarnings("unused")
-       private void listDoubleClick() {
-
+               noteTableView.setColumnHidden(Global.noteTableGuidPosition, !Global.isColumnVisible("guid"));
+               noteTableView.setColumnHidden(Global.noteTableThumbnailPosition, !Global.isColumnVisible("thumbnail"));
     }
     // Title color has changed
     @SuppressWarnings("unused")
@@ -3160,6 +3286,102 @@ public class NeverNote extends QMainWindow{
        }
        logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
     }
+    // Wide list was chosen
+    public void narrowListView() {
+       if (!menuBar.narrowListView.isChecked()) {
+               wideListView();
+               return;
+       }
+       menuBar.wideListView.blockSignals(true);
+       menuBar.narrowListView.blockSignals(true);
+       
+       menuBar.wideListView.setChecked(false);
+       menuBar.narrowListView.setChecked(true);
+       
+       menuBar.wideListView.blockSignals(false);
+       menuBar.narrowListView.blockSignals(false);
+//     browserIndexSplitter.setVisible(false);
+       
+       Global.setListView(Global.View_List_Narrow);
+       mainLeftRightSplitter.addWidget(noteTableView);
+       mainLeftRightSplitter.addWidget(browserWindow);
+    }
+    public void wideListView() {
+       if (!menuBar.wideListView.isChecked()) {
+               narrowListView();
+               return;
+       }
+       menuBar.wideListView.blockSignals(true);
+       menuBar.narrowListView.blockSignals(true);
+       
+       menuBar.wideListView.setChecked(true);
+       menuBar.narrowListView.setChecked(false);
+
+       menuBar.wideListView.blockSignals(false);
+       menuBar.narrowListView.blockSignals(false);
+       browserIndexSplitter.setVisible(true);
+       Global.setListView(Global.View_List_Wide);
+//     browserIndexSplitter.setVisible(true);
+        browserIndexSplitter.addWidget(noteTableView);
+        browserIndexSplitter.addWidget(browserWindow);
+    }
+    
+    
+    //***************************************************************
+    //***************************************************************
+    //** External editor window functions                    
+    //***************************************************************
+    //***************************************************************
+    @SuppressWarnings("unused")
+       private void listDoubleClick() {
+       saveNote();
+       if (externalWindows.containsKey(currentNoteGuid)) {
+               externalWindows.get(currentNoteGuid).raise();
+               return;
+       }
+       
+       // We have a new external editor to create
+       QIcon appIcon = new QIcon(iconPath+"nevernote.png");
+       ExternalBrowse newBrowser = new ExternalBrowse(conn);
+       newBrowser.setWindowIcon(appIcon);
+       externalWindows.put(currentNoteGuid, newBrowser);
+       showEditorButtons(newBrowser.getBrowserWindow());
+       loadNoteBrowserInformation(newBrowser.getBrowserWindow());
+       setupBrowserWindowListeners(newBrowser.getBrowserWindow(), false);
+       newBrowser.windowClosing.connect(this, "externalWindowClosing(String)");
+       newBrowser.getBrowserWindow().noteSignal.titleChanged.connect(this, "externalWindowTitleEdited(String, String)");
+       newBrowser.getBrowserWindow().noteSignal.tagsChanged.connect(this, "externalWindowTagsEdited(String, List)");
+       newBrowser.contentsChanged.connect(this, "saveNoteExternalBrowser(String, String, Boolean, BrowserWindow)");
+
+       browserWindow.noteSignal.tagsChanged.connect(newBrowser, "updateTags(String, List)");
+       browserWindow.noteSignal.titleChanged.connect(newBrowser, "updateTitle(String, String)");
+       browserWindow.noteSignal.notebookChanged.connect(newBrowser, "updateNotebook(String, String)");
+       
+       newBrowser.show();
+    }
+    @SuppressWarnings("unused")
+       private void externalWindowTitleEdited(String guid, String text) {
+       if (guid.equals(currentNoteGuid)) {
+               browserWindow.setTitle(text);
+       }
+    }
+    @SuppressWarnings("unused")
+       private void externalWindowTagsEdited(String guid, List values) {
+       StringBuffer line = new StringBuffer(100);
+       for (int i=0; i<values.size(); i++) {
+               if (i>0) 
+                       line.append(Global.tagDelimeter+" ");
+               line.append(values.get(i));
+       }
+       if (guid.equals(currentNoteGuid)) {
+               browserWindow.setTag(line.toString());
+       }
+    }
+    @SuppressWarnings("unused")
+       private void externalWindowClosing(String guid) {
+               externalWindows.remove(guid);
+    }
+    
     
     
     //***************************************************************
@@ -3170,6 +3392,13 @@ public class NeverNote extends QMainWindow{
     @SuppressWarnings("unused")
        private void setNoteDirty() {
                logger.log(logger.EXTREME, "Entering NeverNote.setNoteDirty()");
+               // Find if the note is being edited externally.  If it is, update it.
+               if (externalWindows.containsKey(currentNoteGuid)) {
+                       QTextCodec codec = QTextCodec.codecForName("UTF-8");
+               QByteArray unicode =  codec.fromUnicode(browserWindow.getContent());
+                       ExternalBrowse window = externalWindows.get(currentNoteGuid);
+               window.getBrowserWindow().getBrowser().setContent(unicode);
+               }
                
                // If the note is dirty, then it is unsynchronized by default.
                if (noteDirty) 
@@ -3199,40 +3428,53 @@ public class NeverNote extends QMainWindow{
  */    
                logger.log(logger.EXTREME, "Leaving NeverNote.setNoteDirty()");
     }
+    @SuppressWarnings("unused")
+       private void saveNoteExternalBrowser(String guid, String content, Boolean save, BrowserWindow browser) {
+               QTextCodec codec = QTextCodec.codecForName("UTF-8");
+        QByteArray unicode =  codec.fromUnicode(content);
+       noteCache.remove(guid);
+               noteCache.put(guid, unicode.toString());
+       if (guid.equals(currentNoteGuid)) {
+               noteDirty = true;
+               browserWindow.getBrowser().setContent(unicode);
+       } 
+       if (save) {
+               saveNote(guid, browser);
+       }
+       
+    }
     private void saveNote() {
-               logger.log(logger.EXTREME, "Inside NeverNote.saveNote()");
        if (noteDirty) {
-                       logger.log(logger.EXTREME, "Note is dirty.");
-               waitCursor(true);
-               
-                       preview = new Thumbnailer(currentNoteGuid, new QSize(1024,768));
-                       preview.finished.connect(this, "saveThumbnail(String)");
-                       preview.setContent(browserWindow.getContent());
+               saveNote(currentNoteGuid, browserWindow);
+               noteDirty = false;
+       }
+    }
+    private void saveNote(String guid, BrowserWindow window) {
+               logger.log(logger.EXTREME, "Inside NeverNote.saveNote()");
+               logger.log(logger.EXTREME, "Note is dirty.");
+               waitCursor(true);
                
-                       logger.log(logger.EXTREME, "Saving to cache");
-                       QTextCodec codec = QTextCodec.codecForLocale();
+               logger.log(logger.EXTREME, "Saving to cache");
+               QTextCodec codec = QTextCodec.codecForLocale();
 //             QTextDecoder decoder = codec.makeDecoder();
-                       codec = QTextCodec.codecForName("UTF-8");
-               QByteArray unicode =  codec.fromUnicode(browserWindow.getContent());
-               noteCache.put(currentNoteGuid, unicode.toString());
+               codec = QTextCodec.codecForName("UTF-8");
+        QByteArray unicode =  codec.fromUnicode(window.getContent());
+               noteCache.put(guid, unicode.toString());
                        
-               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();
+               logger.log(logger.EXTREME, "updating list manager");
+               listManager.updateNoteContent(guid, window.getContent());
+               logger.log(logger.EXTREME, "Updating title");
+               listManager.updateNoteTitle(guid, window.getTitle());
+               updateListDateChanged();
 
-                       logger.log(logger.EXTREME, "Looking through note index for refreshed note");
-               for (int i=0; i<listManager.getNoteIndex().size(); i++) {
-                       if (listManager.getNoteIndex().get(i).getGuid().equals(currentNoteGuid)) {
-                               currentNote = listManager.getNoteIndex().get(i);
-                               i = listManager.getNoteIndex().size();
-                       }
+               logger.log(logger.EXTREME, "Looking through note index for refreshed note");
+               for (int i=0; i<listManager.getNoteIndex().size(); i++) {
+               if (listManager.getNoteIndex().get(i).getGuid().equals(guid)) {
+                       currentNote = listManager.getNoteIndex().get(i);
+                       i = listManager.getNoteIndex().size();
                }
-               noteDirty = false;
-               waitCursor(false);
        }
+       waitCursor(false);
     }
     // Get a note from Evernote (and put it in the browser)
        private void refreshEvernoteNote(boolean reload) {
@@ -3258,35 +3500,45 @@ public class NeverNote extends QMainWindow{
                currentNote = conn.getNoteTable().getNote(currentNoteGuid, true,true,false,false,true);
                if (currentNote == null) 
                        return;
-
+               
+               loadNoteBrowserInformation(browserWindow);
+       }
+       private void loadNoteBrowserInformation(BrowserWindow browser) {
+               NoteFormatter formatter = new NoteFormatter(logger, conn, tempFiles);
+               formatter.setNote(currentNote, Global.pdfPreview());
+               formatter.setHighlight(listManager.getEnSearch());
                if (!noteCache.containsKey(currentNoteGuid) || conn.getNoteTable().isThumbnailNeeded(currentNoteGuid)) {
                        QByteArray js = new QByteArray();
                        // We need to prepend the note with <HEAD></HEAD> or encoded characters are ugly 
                        js.append("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">");               
-                       js.append("<style type=\"text/css\">en-crypt-temp { border-style:solid; border-color:blue; padding:0.5mm 0.5mm 0.5mm 0.5mm; }</style>");
+                       js.append("<style type=\"text/css\">.en-crypt-temp { border-collapse:collapse; border-style:solid; border-color:blue; padding:0.0mm 0.0mm 0.0mm 0.0mm; }</style>");
                        js.append("<style type=\"text/css\">en-hilight { background-color: rgb(255,255,0) }</style>");
+                       js.append("<style> img { max-width:100%; }</style>");
                        js.append("<style type=\"text/css\">en-spell { text-decoration: none; border-bottom: dotted 1px #cc0000; }</style>");
                        js.append("</head>");
-                       js.append(rebuildNoteHTML(currentNoteGuid, currentNote.getContent()));
+                       formatter.setNote(currentNote, Global.pdfPreview());
+                       js.append(formatter.rebuildNoteHTML());
                        js.append("</HTML>");
                        js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml.dtd'>", "");
                        js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml2.dtd'>", "");
                        js.replace("<?xml version='1.0' encoding='UTF-8'?>", "");
-                       browserWindow.getBrowser().setContent(js);
+                       browser.getBrowser().setContent(js);
                        noteCache.put(currentNoteGuid, js.toString());
                        if (conn.getNoteTable().isThumbnailNeeded(currentNoteGuid)) {
-                               preview = new Thumbnailer(currentNoteGuid, new QSize(1024,768));
-                               preview.finished.connect(this, "saveThumbnail(String)");
-                               preview.setContent(js.toString());
+                               thumbnailRunner.addWork("GENERATE " +currentNoteGuid);
                        }
                } else {
                        logger.log(logger.HIGH, "Note content is being pulled from the cache");
-                       String cachedContent = modifyCachedTodoTags(noteCache.get(currentNoteGuid));
-                       browserWindow.getBrowser().setContent(new QByteArray(cachedContent));
+                       String cachedContent = formatter.modifyCachedTodoTags(noteCache.get(currentNoteGuid));
+                       browser.getBrowser().setContent(new QByteArray(cachedContent));
                }
+
+               if (formatter.resourceError)
+                       resourceErrorMessage();
+               inkNote = formatter.readOnly;
                
-               browserWindow.getBrowser().page().setContentEditable(!inkNote);  // We don't allow editing of ink notes
-               browserWindow.setNote(currentNote);
+               browser.getBrowser().page().setContentEditable(!inkNote);  // We don't allow editing of ink notes
+               browser.setNote(currentNote);
                
                // Build a list of non-closed notebooks
                List<Notebook> nbooks = new ArrayList<Notebook>();
@@ -3300,52 +3552,30 @@ public class NeverNote extends QMainWindow{
                                nbooks.add(listManager.getNotebookIndex().get(i));
                }
                
-               browserWindow.setNotebookList(nbooks);
-               browserWindow.setTitle(currentNote.getTitle());
-               browserWindow.setTag(getTagNamesForNote(currentNote));
-               browserWindow.setAuthor(currentNote.getAttributes().getAuthor());
+               browser.setNotebookList(nbooks);
+               browser.setTitle(currentNote.getTitle());
+               browser.setTag(getTagNamesForNote(currentNote));
+               browser.setAuthor(currentNote.getAttributes().getAuthor());
                
-               browserWindow.setAltered(currentNote.getUpdated());
-               browserWindow.setCreation(currentNote.getCreated());
+               browser.setAltered(currentNote.getUpdated());
+               browser.setCreation(currentNote.getCreated());
                if (currentNote.getAttributes().getSubjectDate() > 0)
-                       browserWindow.setSubjectDate(currentNote.getAttributes().getSubjectDate());
+                       browser.setSubjectDate(currentNote.getAttributes().getSubjectDate());
                else
-                       browserWindow.setSubjectDate(currentNote.getCreated());
-               browserWindow.setUrl(currentNote.getAttributes().getSourceURL());
-               browserWindow.setAllTags(listManager.getTagIndex());
-               browserWindow.setCurrentTags(currentNote.getTagNames());
+                       browser.setSubjectDate(currentNote.getCreated());
+               browser.setUrl(currentNote.getAttributes().getSourceURL());
+               browser.setAllTags(listManager.getTagIndex());
+               browser.setCurrentTags(currentNote.getTagNames());
                noteDirty = false;
                scrollToGuid(currentNoteGuid);
                
-               browserWindow.loadingData(false);
+               browser.loadingData(false);
                if (thumbnailViewer.isActiveWindow())
                        thumbnailView();
                waitCursor(false);
                logger.log(logger.HIGH, "Leaving NeverNote.refreshEvernoteNote");
        }
        // Save a generated thumbnail
-       @SuppressWarnings("unused")
-       private void saveThumbnail(String guid) {
-               QFile tFile = new QFile(Global.getFileManager().getResDirPath("thumbnail-" + guid + ".png"));
-               tFile.open(OpenModeFlag.ReadOnly);
-               QByteArray imgBytes = tFile.readAll();
-               tFile.close();
-               conn.getNoteTable().setThumbnail(guid, imgBytes);
-               conn.getNoteTable().setThumbnailNeeded(guid, false);
-               thumbnailViewer.setThumbnail(QImage.fromData(imgBytes));
-               if (thumbnailViewer.isVisible()) 
-                       thumbnailViewer.showFullScreen();
-               
-               /*              
-               QByteArray img2 = new QByteArray(conn.getNoteTable().getThumbnail(guid));
-               QFile file = new QFile(Global.currentDir+"res/aaaa.png");
-               file.open(OpenModeFlag.WriteOnly);
-               file.write(img2);
-               file.close(); 
-               */
-       }
-    // Show/Hide note information
-       @SuppressWarnings("unused")
        private void toggleNoteInformation() {
                logger.log(logger.HIGH, "Entering NeverNote.toggleNoteInformation");
        browserWindow.toggleInformation();
@@ -3506,9 +3736,19 @@ public class NeverNote extends QMainWindow{
        browserWindow.setReadOnly(false);
        saveNote();
        Calendar currentTime = new GregorianCalendar();
-       String noteString = new String("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+       StringBuffer noteString = new StringBuffer(100);
+       noteString.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                "<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">\n" +
-               "<en-note>\n<br clear=\"none\" /></en-note>");
+               "<en-note>\n");
+       
+       if (Global.overrideDefaultFont()) {
+               noteString.append("<font face=\"" +Global.getDefaultFont() +"\" >");
+               noteString.append("<span style=\"font-size:" +Global.getDefaultFontSize() +"pt;\">");
+               noteString.append("<br clear=\"none\" />\n");
+               noteString.append("</span>\n</font>\n");
+       } else
+               noteString.append("<br clear=\"none\" />\n");
+       noteString.append("</en-note>");
        
        Long l = new Long(currentTime.getTimeInMillis());
        String randint = new String(Long.toString(l));          
@@ -3559,7 +3799,7 @@ public class NeverNote extends QMainWindow{
        newNote.setGuid(randint);
        newNote.setNotebookGuid(notebook);
        newNote.setTitle("");
-       newNote.setContent(noteString);
+       newNote.setContent(noteString.toString());
        newNote.setDeleted(0);
        newNote.setCreated(System.currentTimeMillis());
        newNote.setUpdated(System.currentTimeMillis());
@@ -3622,6 +3862,9 @@ public class NeverNote extends QMainWindow{
        browserWindow.getBrowser().page().findText(find.getText(), find.getFlags());
        find.setFocus();
     }
+    private void updateNoteTitle(String guid, String title) {
+       listManager.setNoteSynchronized(guid, false);
+    }
     // Signal received that note content has changed.  Normally we just need the guid to remove
     // it from the cache.
     @SuppressWarnings("unused")
@@ -3645,6 +3888,12 @@ public class NeverNote extends QMainWindow{
                        currentNote.setGuid(newGuid);
                currentNoteGuid = newGuid;
        }
+               if (externalWindows.containsKey(oldGuid)) {
+                       ExternalBrowse b = externalWindows.get(oldGuid);
+                       externalWindows.remove(oldGuid);
+                       b.getBrowserWindow().getNote().setGuid(newGuid);
+                       externalWindows.put(newGuid, b);
+               }
        for (int i=0; i<listManager.getNoteIndex().size(); i++) {
                if (listManager.getNoteIndex().get(i).getGuid().equals(newGuid)) {
                        noteTableView.proxyModel.addGuid(newGuid);
@@ -3666,40 +3915,40 @@ public class NeverNote extends QMainWindow{
 //             Global.saveWindowVisible("editorButtonBar", browserWindow.buttonsVisible);
        } else {
                browserWindow.buttonsVisible = true;
-               showEditorButtons();
+               showEditorButtons(browserWindow);
        }
        Global.saveWindowVisible("editorButtonBar", browserWindow.buttonsVisible);
     }
     // Show editor buttons
-    private void showEditorButtons() {
-               browserWindow.buttonLayout.setVisible(true);
-               browserWindow.undoAction.setVisible(false);
+    private void showEditorButtons(BrowserWindow browser) {
+               browser.buttonLayout.setVisible(true);
+               browser.undoAction.setVisible(false);
                
-               browserWindow.undoButton.setVisible(false);
+               browser.undoButton.setVisible(false);
 
-               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"));
-               browserWindow.spellCheckAction.setVisible(Global.isEditorButtonVisible("spellCheck"));
-               browserWindow.todoAction.setVisible(Global.isEditorButtonVisible("todo"));
+               browser.undoAction.setVisible(Global.isEditorButtonVisible("undo"));
+               browser.redoAction.setVisible(Global.isEditorButtonVisible("redo"));
+               browser.cutAction.setVisible(Global.isEditorButtonVisible("cut"));
+               browser.copyAction.setVisible(Global.isEditorButtonVisible("copy"));
+               browser.pasteAction.setVisible(Global.isEditorButtonVisible("paste"));
+               browser.strikethroughAction.setVisible(Global.isEditorButtonVisible("strikethrough"));
+               browser.underlineAction.setVisible(Global.isEditorButtonVisible("underline"));
+               browser.boldAction.setVisible(Global.isEditorButtonVisible("bold"));
+               browser.italicAction.setVisible(Global.isEditorButtonVisible("italic"));
+               browser.hlineAction.setVisible(Global.isEditorButtonVisible("hline"));
+               browser.indentAction.setVisible(Global.isEditorButtonVisible("indent"));
+               browser.outdentAction.setVisible(Global.isEditorButtonVisible("outdent"));
+               browser.bulletListAction.setVisible(Global.isEditorButtonVisible("bulletList"));
+               browser.numberListAction.setVisible(Global.isEditorButtonVisible("numberList"));
+               browser.fontListAction.setVisible(Global.isEditorButtonVisible("font"));
+               browser.fontSizeAction.setVisible(Global.isEditorButtonVisible("fontSize"));
+               browser.fontColorAction.setVisible(Global.isEditorButtonVisible("fontColor"));
+               browser.fontHilightAction.setVisible(Global.isEditorButtonVisible("fontHilight"));
+               browser.leftAlignAction.setVisible(Global.isEditorButtonVisible("alignLeft"));
+               browser.centerAlignAction.setVisible(Global.isEditorButtonVisible("alignCenter"));
+               browser.rightAlignAction.setVisible(Global.isEditorButtonVisible("alignRight"));
+               browser.spellCheckAction.setVisible(Global.isEditorButtonVisible("spellCheck"));
+               browser.todoAction.setVisible(Global.isEditorButtonVisible("todo"));
     }
     private void duplicateNote(String guid) {
                
@@ -3748,6 +3997,19 @@ public class NeverNote extends QMainWindow{
                listManager.countNotebookResults(listManager.getNoteIndex());
                waitCursor(false);
        }
+       // View all notes
+       private void allNotes() {
+               clearAttributeFilter();
+               clearNotebookFilter();
+               clearSavedSearchFilter();
+               clearTrashFilter();
+               clearTagFilter();
+               searchField.clear();
+               if (Global.mimicEvernoteInterface) {
+                       notebookTree.selectGuid("");
+               }
+               notebookTreeSelection();
+       }
        // Merge notes
        @SuppressWarnings("unused")
        private void mergeNotes() {
@@ -3859,13 +4121,30 @@ public class NeverNote extends QMainWindow{
                                        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.";
+                       msg = "An error has happened while saving the note \"" +title+
+                       "\".\n\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 properly in the database."+
+                       "\n\nA cached copy is being preserved so you can recover any data, but data may" +
+                       "\nbe lost.  Please review the note to recover any critical data before restarting.";
                        
                        QMessageBox.information(this, tr("Error Saving Note"), tr(msg));
                }
        }
+       private void thumbnailHTMLReady(String guid,String file) {
+               Thumbnailer preview = null;
+               // Find an idle preview object
+               for (int i=0; i<previewList.size(); i++) {
+                       if (previewList.get(i).idle) {
+                               preview = previewList.get(i);
+                               i=previewList.size();
+                       }
+               } 
+               if (preview == null) {
+                       preview = new Thumbnailer(conn, listManager);
+                       previewList.add(preview);
+               }
+               preview.loadContent(guid, file);
+       }
        
        //**********************************************************
     //**********************************************************
@@ -3917,7 +4196,7 @@ public class NeverNote extends QMainWindow{
                
                // If we've gotten this far, we have a good note.
                if (historyWindow == null) {
-                       historyWindow = new OnlineNoteHistory(conn);
+                       historyWindow = new OnlineNoteHistory(logger, conn);
                        historyWindow.historyCombo.activated.connect(this, "reloadHistoryWindow(String)");
                        historyWindow.restoreAsNew.clicked.connect(this, "restoreHistoryNoteAsNew()");
                        historyWindow.restore.clicked.connect(this, "restoreHistoryNote()");
@@ -4017,332 +4296,6 @@ public class NeverNote extends QMainWindow{
        //* XML Modifying methods
        //**********************************************************
        //**********************************************************
-    // find the appropriate icon for an attachment
-    private String findIcon(String appl) {
-       logger.log(logger.HIGH, "Entering NeverNote.findIcon");
-       appl = appl.toLowerCase();
-        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");
-       return "attachment.png";
-    }
-    // Modify the en-media tag into an attachment
-    private void modifyApplicationTags(QDomDocument doc, QDomElement docElem, QDomElement enmedia, QDomAttr hash, String appl) {
-       logger.log(logger.HIGH, "Entering NeverNote.modifyApplicationTags");
-       if (appl.equalsIgnoreCase("vnd.evernote.ink"))
-               inkNote = true;
-       String resGuid = conn.getNoteTable().noteResourceTable.getNoteResourceGuidByHashHex(currentNote.getGuid(), hash.value());
-       Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(resGuid, false);
-       if (r == null || r.getData() == null) 
-               resourceErrorMessage();
-               if (r!= null) {
-                       if (r.getData()!=null) {
-                               // Did we get a generic applicaiton?  Then look at the file name to 
-                               // try and find a good application type for the icon
-                               if (appl.equalsIgnoreCase("octet-stream")) {
-                                       if (r.getAttributes() != null && r.getAttributes().getFileName() != null) {
-                                               String fn = r.getAttributes().getFileName();
-                                               int pos = fn.lastIndexOf(".");
-                                               if (pos > -1) {
-                                                       appl = fn.substring(pos+1);
-                                               }
-                                       }
-                               }
-                               
-                               String fileDetails = null;
-                               if (r.getAttributes() != null && r.getAttributes().getFileName() != null && !r.getAttributes().getFileName().equals(""))
-                                       fileDetails = r.getAttributes().getFileName();
-                               String contextFileName;
-                               FileManager fileManager = Global.getFileManager();
-                if (fileDetails != null && !fileDetails.equals("")) {
-                                       enmedia.setAttribute("href", "nnres://" +r.getGuid() +Global.attachmentNameDelimeter +fileDetails);
-                                       contextFileName = fileManager.getResDirPath(r.getGuid() + Global.attachmentNameDelimeter + fileDetails);
-                               } else { 
-                                       enmedia.setAttribute("href", "nnres://" +r.getGuid() +Global.attachmentNameDelimeter +appl);
-                                       contextFileName = fileManager.getResDirPath(r.getGuid() + Global.attachmentNameDelimeter + appl);
-                               }
-                               contextFileName = contextFileName.replace("\\", "/");
-                               enmedia.setAttribute("onContextMenu", "window.jambi.resourceContextMenu('" +contextFileName +"');");
-                               if (fileDetails == null || fileDetails.equals(""))
-                                       fileDetails = "";
-                               enmedia.setAttribute("en-tag", "en-media");
-                               enmedia.setAttribute("guid", r.getGuid());
-                               enmedia.setTagName("a");
-                               QDomElement newText = doc.createElement("img");
-                               boolean goodPreview = false;
-                               String filePath = "";
-                               if (appl.equalsIgnoreCase("pdf") && Global.pdfPreview()) {
-                                       String fileName;
-                                       Resource res = conn.getNoteTable().noteResourceTable.getNoteResource(r.getGuid(), true);
-                                       if (res.getAttributes() != null && 
-                                                       res.getAttributes().getFileName() != null && 
-                                                       !res.getAttributes().getFileName().trim().equals(""))
-                                               fileName = res.getGuid()+Global.attachmentNameDelimeter+res.getAttributes().getFileName();
-                                       else
-                                               fileName = res.getGuid()+".pdf";
-                                       QFile file = new QFile(fileManager.getResDirPath(fileName));
-                               QFile.OpenMode mode = new QFile.OpenMode();
-                               mode.set(QFile.OpenModeFlag.WriteOnly);
-                               file.open(mode);
-                               QDataStream out = new QDataStream(file);
-                               Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(res.getGuid(), true);
-                                       QByteArray binData = new QByteArray(resBinary.getData().getBody());
-                                       resBinary = null;
-                               out.writeBytes(binData.toByteArray());
-                               file.close();
-                               PDFPreview pdfPreview = new PDFPreview();
-                                       goodPreview = pdfPreview.setupPreview(file.fileName(), appl,0);
-                                       if (goodPreview) {
-                                               QDomElement span = doc.createElement("span");
-                                               QDomElement table = doc.createElement("table");
-                                               span.setAttribute("pdfNavigationTable", "true");
-                                               QDomElement tr = doc.createElement("tr");
-                                               QDomElement td = doc.createElement("td");
-                                               QDomElement left = doc.createElement("img");
-                                               left.setAttribute("onMouseDown", "window.jambi.nextPage('" +file.fileName() +"')");
-                                               left.setAttribute("onMouseDown", "window.jambi.nextPage('" +file.fileName() +"')");
-                                               left.setAttribute("onMouseOver", "style.cursor='hand'");
-                                               QDomElement right = doc.createElement("img");
-                                               right.setAttribute("onMouseDown", "window.jambi.nextPage('" +file.fileName() +"')");
-                                               left.setAttribute("onMouseDown", "window.jambi.previousPage('" +file.fileName() +"')");
-                                               // 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);
-                                               tr.appendChild(td);
-                                               td.appendChild(left);
-                                               td.appendChild(right);
-                                               span.appendChild(table);
-                                               enmedia.parentNode().insertBefore(span, enmedia);
-                                       } 
-                                       filePath = fileName+".png";
-                               }
-                               String icon = findIcon(appl);
-                               if (icon.equals("attachment.png"))
-                                       icon = findIcon(fileDetails.substring(fileDetails.indexOf(".")+1));
-                               // NFC TODO: should this be a 'file://' URL?
-                               newText.setAttribute("src", Global.getFileManager().getImageDirPath(icon));
-                               if (goodPreview) {
-                               // 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);
-                               enmedia.removeChild(enmedia.firstChild());
-                               
-                               enmedia.appendChild(newText);
-                       }
-               }
-               logger.log(logger.HIGH, "Leaving NeverNote.modifyApplicationTags");
-    }
-    // Modify the en-to tag into an input field
-    private void modifyTodoTags(QDomElement todo) {
-       logger.log(logger.HIGH, "Entering NeverNote.modifyTodoTags");
-               todo.setAttribute("type", "checkbox");
-               String checked = todo.attribute("checked");
-               todo.removeAttribute("checked");
-               if (checked.equalsIgnoreCase("true"))
-                       todo.setAttribute("checked", "");
-               else
-                       todo.setAttribute("unchecked","");
-               todo.setAttribute("value", checked);
-               todo.setAttribute("onClick", "value=checked;window.jambi.contentChanged(); ");
-               todo.setTagName("input");
-               logger.log(logger.HIGH, "Leaving NeverNote.modifyTodoTags");
-    }
-    // Modify any cached todo tags that may have changed
-    private String modifyCachedTodoTags(String note) {
-       logger.log(logger.HIGH, "Entering NeverNote.modifyCachedTodoTags");
-       StringBuffer html = new StringBuffer(note);
-               for (int i=html.indexOf("<input", 0); i>-1; i=html.indexOf("<input", i)) {
-                       int endPos =html.indexOf(">",i+1);
-                       String input = html.substring(i,endPos);
-                       if (input.indexOf("value=\"true\"") > 0) 
-                               input = input.replace(" unchecked=\"\"", " checked=\"\"");
-                       else
-                               input = input.replace(" checked=\"\"", " unchecked=\"\"");
-                       html.replace(i, endPos, input);
-                       i++;
-               }
-               logger.log(logger.HIGH, "Leaving NeverNote.modifyCachedTodoTags");
-               return html.toString();
-    }
-    // Modify the en-media tag into an image tag so it can be displayed.
-    private void modifyImageTags(QDomElement docElem, QDomElement enmedia, QDomAttr hash) {
-       logger.log(logger.HIGH, "Entering NeverNote.modifyImageTags");
-       String type = enmedia.attribute("type");
-       if (type.startsWith("image/"))
-               type = "."+type.substring(6);
-       else
-               type="";
-       
-       String resGuid = conn.getNoteTable().noteResourceTable.getNoteResourceGuidByHashHex(currentNoteGuid, hash.value());
-       QFile tfile = new QFile(Global.getFileManager().getResDirPath(resGuid + type));
-       if (!tfile.exists()) {
-               Resource r = null;
-               if (resGuid != null)
-                       r = conn.getNoteTable().noteResourceTable.getNoteResource(resGuid,true);
-                       if (r==null || r.getData() == null || r.getData().getBody().length == 0)
-                               resourceErrorMessage();
-                       if (r!= null && r.getData() != null && r.getData().getBody().length > 0) {
-                               tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
-                               QByteArray binData = new QByteArray(r.getData().getBody());
-                               tfile.write(binData);
-                               tfile.close();
-                               enmedia.setAttribute("src", QUrl.fromLocalFile(tfile.fileName()).toString());
-                               enmedia.setAttribute("en-tag", "en-media");
-                               enmedia.setNodeValue("");
-                       enmedia.setAttribute("guid", r.getGuid());
-                       enmedia.setTagName("img");
-               }
-       }
-               enmedia.setAttribute("src", QUrl.fromLocalFile(tfile.fileName()).toString());
-               enmedia.setAttribute("en-tag", "en-media");
-               enmedia.setAttribute("onContextMenu", "window.jambi.imageContextMenu('" +tfile.fileName()  +"');");
-               enmedia.setNodeValue("");
-               enmedia.setAttribute("guid", resGuid);
-               enmedia.setTagName("img");
-
-               logger.log(logger.HIGH, "Leaving NeverNote.modifyImageTags");
-    }
-       // Modify tags from Evernote specific things to XHTML tags.
-       private QDomDocument modifyTags(QDomDocument doc) {
-               logger.log(logger.HIGH, "Entering NeverNote.modifyTags");
-               if (tempFiles == null)
-                       tempFiles = new ArrayList<QTemporaryFile>();
-               tempFiles.clear();
-               QDomElement docElem = doc.documentElement();
-               
-               // Modify en-media tags
-               QDomNodeList anchors = docElem.elementsByTagName("en-media");
-               int enMediaCount = anchors.length();
-               for (int i=enMediaCount-1; i>=0; i--) {
-                       QDomElement enmedia = anchors.at(i).toElement();
-                       if (enmedia.hasAttribute("type")) {
-                               QDomAttr attr = enmedia.attributeNode("type");
-                               QDomAttr hash = enmedia.attributeNode("hash");
-                               String[] type = attr.nodeValue().split("/");
-                               String appl = type[1];
-                               
-                               if (type[0] != null) {
-                                       if (type[0].equals("image")) {
-                                               modifyImageTags(docElem, enmedia, hash);
-                                       }
-                                       if (!type[0].equals("image")) {
-                                               modifyApplicationTags(doc, docElem, enmedia, hash, appl);
-                                       }
-                               }
-                       }
-               }
-               
-               // Modify todo tags
-               anchors = docElem.elementsByTagName("en-todo");
-               int enTodoCount = anchors.length();
-               for (int i=enTodoCount-1; i>=0; i--) {
-                       QDomElement enmedia = anchors.at(i).toElement();
-                       modifyTodoTags(enmedia);
-               }
-               
-               // Modify en-crypt tags
-               anchors = docElem.elementsByTagName("en-crypt");
-               int enCryptLen = anchors.length();
-               for (int i=enCryptLen-1; i>=0; i--) {
-                       QDomElement enmedia = anchors.at(i).toElement();
-                       enmedia.setAttribute("contentEditable","false");
-                       enmedia.setAttribute("src", Global.getFileManager().getImageDirPath("encrypt.png"));
-                       enmedia.setAttribute("en-tag","en-crypt");
-                       enmedia.setAttribute("alt", enmedia.text());
-                       Global.cryptCounter++;
-                       enmedia.setAttribute("id", "crypt"+Global.cryptCounter.toString());
-                       String encryptedText = enmedia.text();
-                       
-                       // If the encryption string contains crlf at the end, remove them because they mess up the javascript.
-                       if (encryptedText.endsWith("\n"))
-                               encryptedText = encryptedText.substring(0,encryptedText.length()-1);
-                       if (encryptedText.endsWith("\r"))
-                               encryptedText = encryptedText.substring(0,encryptedText.length()-1);
-                       
-                       // Add the commands
-                       String hint = enmedia.attribute("hint");
-                       hint = hint.replace("'","&apos;");
-                       enmedia.setAttribute("onClick", "window.jambi.decryptText('crypt"+Global.cryptCounter.toString()+"', '"+encryptedText+"', '"+hint+"');");
-                       enmedia.setAttribute("onMouseOver", "style.cursor='hand'");
-                       enmedia.setTagName("img");
-                       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;
-       }
-       // Rebuild the note HTML to something usable
-       private String rebuildNoteHTML(String noteGuid, String note) {
-               logger.log(logger.HIGH, "Entering NeverNote.rebuildNoteHTML");
-               logger.log(logger.EXTREME, "Note guid: " +noteGuid);
-               logger.log(logger.EXTREME, "Note Text:" +note);
-               QDomDocument doc = new QDomDocument();
-               QDomDocument.Result result = doc.setContent(note);
-               if (!result.success) {
-                       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, "End of unmodified note HTML");
-                       return note;
-               }
-
-               if (tempFiles == null)
-                       tempFiles = new ArrayList<QTemporaryFile>();
-               tempFiles.clear();
-               
-               doc = modifyTags(doc);
-               doc = addHilight(doc);
-               QDomElement docElem = doc.documentElement();
-               docElem.setTagName("Body");
-//             docElem.setAttribute("bgcolor", "green");
-               logger.log(logger.EXTREME, "Rebuilt HTML:");
-               logger.log(logger.EXTREME, doc.toString());     
-               logger.log(logger.HIGH, "Leaving NeverNote.rebuildNoteHTML");
-               // Fix the stupid problem where inserting an <img> tag after an <a> tag (which is done
-               // to get the <en-media> application tag to work properly) causes spaces to be inserted
-               // between the <a> & <img>.  This messes things up later.  This is an ugly hack.
-               StringBuffer html = new StringBuffer(doc.toString());
-               for (int i=html.indexOf("<a en-tag=\"en-media\" ", 0); i>-1; i=html.indexOf("<a en-tag=\"en-media\" ", i)) {
-                       i=html.indexOf(">\n",i+1);
-                       int z = html.indexOf("<img",i);
-                       for (int j=z-1; j>i; j--) 
-                               html.deleteCharAt(j);
-                       i=html.indexOf("/>", z+1);
-                       z = html.indexOf("</a>",i);
-                       for (int j=z-1; j>i+1; j--) 
-                               html.deleteCharAt(j);
-               } 
-               return html.toString();
-       }       
-       // Scan and do hilighting of words
-       private QDomDocument addHilight(QDomDocument doc) {
-               EnSearch e = listManager.getEnSearch();
-               if (e.hilightWords == null || e.hilightWords.size() == 0)
-                       return doc;
-               XMLInsertHilight hilight = new XMLInsertHilight(doc, listManager.getEnSearch().hilightWords);
-               return hilight.getDoc();
-       }
-
        // An error has happended fetching a resource.  let the user know
        private void resourceErrorMessage() {
                if (inkNote)
@@ -4358,7 +4311,6 @@ public class NeverNote extends QMainWindow{
                "this note on the Evernote servers.  Sorry."+
                "\n\nP.S. You might want to re-synchronize to see if it corrects this problem.\nWho knows, you might get lucky."));
                inkNote = true;
-////           browserWindow.setEnabled(false);
                browserWindow.setReadOnly(true);
        }
 
@@ -4404,7 +4356,7 @@ public class NeverNote extends QMainWindow{
                syncRunning = false;
                syncRunner.syncNeeded = false;
                synchronizeAnimationTimer.stop();
-               synchronizeButton.setIcon(synchronizeAnimation.get(0));
+               synchronizeButton.setIcon(new QIcon(iconPath+"synchronize.png"));
                saveNote();
                if (currentNote == null) {
                        currentNote = conn.getNoteTable().getNote(currentNoteGuid, false, false, false, false, true);
@@ -4618,7 +4570,9 @@ public class NeverNote extends QMainWindow{
                
        }
 
-       
+       private void thumbnailTimer() {
+               thumbnailRunner.addWork("SCAN");
+       }
        
        //**************************************************
        //* Backup & Restore
@@ -5005,7 +4959,11 @@ public class NeverNote extends QMainWindow{
                byte[] hash = md.digest();
         String newHash = Global.byteArrayToHexString(hash);
         if (r.getNoteGuid().equalsIgnoreCase(currentNoteGuid)) {
-               updateResourceContentHash(r.getGuid(), oldHash, newHash);
+               updateResourceContentHash(browserWindow, r.getGuid(), oldHash, newHash);
+        }
+        if (externalWindows.containsKey(r.getNoteGuid())) {
+               updateResourceContentHash(externalWindows.get(r.getNoteGuid()).getBrowserWindow(), 
+                               r.getGuid(), oldHash, newHash);
         }
         conn.getNoteTable().updateResourceContentHash(r.getNoteGuid(), oldHash, newHash);
         Data data = r.getData();
@@ -5022,6 +4980,13 @@ public class NeverNote extends QMainWindow{
                        browserWindow.getBrowser().triggerPageAction(WebAction.Reload);
         }
         
+        if (externalWindows.containsKey(r.getNoteGuid())) {
+               QWebSettings.setMaximumPagesInCache(0);
+                       QWebSettings.setObjectCacheCapacities(0, 0, 0);
+                       externalWindows.get(r.getNoteGuid()).getBrowserWindow().getBrowser().triggerPageAction(WebAction.Reload);
+                       
+        }
+        
                logger.log(logger.HIGH, "Exiting externalFielEdited");
        }
        // This is a timer event that tries to save any external files that were edited.  This
@@ -5053,24 +5018,24 @@ public class NeverNote extends QMainWindow{
        
        // If an attachment on the current note was edited, we need to update the current notes's hash
        // Update a note content's hash.  This happens if a resource is edited outside of NN
-       public void updateResourceContentHash(String guid, String oldHash, String newHash) {
+       public void updateResourceContentHash(BrowserWindow browser, String guid, String oldHash, String newHash) {
                int position = browserWindow.getContent().indexOf("en-tag=\"en-media\" guid=\""+guid+"\" type=");
                int endPos;
                for (;position>-1;) {
-                       endPos = browserWindow.getContent().indexOf(">", position+1);
-                       String oldSegment = browserWindow.getContent().substring(position,endPos);
+                       endPos = browser.getContent().indexOf(">", position+1);
+                       String oldSegment = browser.getContent().substring(position,endPos);
                        int hashPos = oldSegment.indexOf("hash=\"");
                        int hashEnd = oldSegment.indexOf("\"", hashPos+7);
                        String hash = oldSegment.substring(hashPos+6, hashEnd);
                        if (hash.equalsIgnoreCase(oldHash)) {
                                String newSegment = oldSegment.replace(oldHash, newHash);
-                               String content = browserWindow.getContent().substring(0,position) +
+                               String content = browser.getContent().substring(0,position) +
                                                 newSegment +
-                                                browserWindow.getContent().substring(endPos);
-                               browserWindow.getBrowser().setContent(new QByteArray(content));;
+                                                browser.getContent().substring(endPos);
+                               browser.getBrowser().setContent(new QByteArray(content));;
                        }
                        
-                       position = browserWindow.getContent().indexOf("en-tag=\"en-media\" guid=\""+guid+"\" type=", position+1);
+                       position = browser.getContent().indexOf("en-tag=\"en-media\" guid=\""+guid+"\" type=", position+1);
                }
        }
 
index 39aedab..5460968 100644 (file)
@@ -60,17 +60,27 @@ public class ConfigAppearancePage extends QWidget {
                dformats = new ArrayList<String>();\r
                tformats = new ArrayList<String>();\r
                \r
-               dformats.add("MM/dd/yy - 12/31/09");\r
-               dformats.add("MM/dd/yyyy - 12/31/2009");\r
-               dformats.add("dd/MM/yy - 31/12/09");\r
-               dformats.add("dd/MM/yyyy - 31/12/2009");\r
-               dformats.add("yyyy/MM/dd - 2009/12/31");\r
-               dformats.add("yy/MM/dd - 9/12/31");\r
+               dformats.add("MM/dd/yy - 02/03/09");\r
+               dformats.add("MM/dd/yyyy - 02/03/2009");\r
+               dformats.add("M/dd/yyyy - 2/03/2009");\r
+               dformats.add("M/d/yyyy - 2/3/2009");\r
+               dformats.add("dd/MM/yy - 03/02/09");\r
+               dformats.add("d/M/yy - 3/2/09");\r
+               dformats.add("dd/MM/yyyy - 03/02/2009");\r
+               dformats.add("d/M/yyyy - 3/2/2009");\r
+               dformats.add("yyyy/MM/dd - 2009/02/03");\r
+               dformats.add("yy/MM/dd - 09/02/03");\r
                \r
-               tformats.add("HH:mm:ss - 2:13:01");\r
-               tformats.add("HH:mm:ss a - 2:13:01 am");\r
-               tformats.add("HH:mm - 2:13");\r
-               tformats.add("HH:mm a - 2:13 am");\r
+               tformats.add("HH:mm:ss - 18:13:01");\r
+               tformats.add("HH:mm:ss a - 18:13:01 pm");\r
+               tformats.add("HH:mm - 18:13");\r
+               tformats.add("HH:mm a - 18:13 pm");\r
+               tformats.add("hh:mm:ss - 06:13:01");\r
+               tformats.add("hh:mm:ss a - 06:13:01 pm");\r
+               tformats.add("h:mm:ss a - 6:13:01 pm");\r
+               tformats.add("hh:mm - 06:13");\r
+               tformats.add("hh:mm a - 06:13 pm");\r
+               tformats.add("h:mm a - 6:13 pm");\r
 \r
                \r
                // Style sheet formats\r
@@ -122,7 +132,7 @@ public class ConfigAppearancePage extends QWidget {
                \r
                mimicEvernote = new QCheckBox(tr("Mimic Evernote Selection Behavior (Requires Restart)"));\r
                showSplashScreen = new QCheckBox(tr("Show Splash Screen on Startup"));\r
-               showTrayIcon = new QCheckBox(tr("Show Tray Icon"));\r
+               showTrayIcon = new QCheckBox(tr("Minimize To Tray"));\r
                verifyDelete = new QCheckBox(tr("Verify Deletes"));\r
                startMinimized = new QCheckBox(tr("Start Minimized"));\r
                pdfPreview = new QCheckBox(tr("Display PDF Documents Inline"));\r
index d332691..41c7f33 100644 (file)
@@ -43,6 +43,7 @@ import cx.fbn.nevernote.Global;
 import cx.fbn.nevernote.utilities.AESEncrypter;\r
 public class ConfigDialog extends QDialog {\r
        private final QListWidget                               contentsWidget;\r
+       private final ConfigFontPage                    fontPage;\r
        private final QStackedWidget                    pagesWidget;\r
        private final ConfigConnectionPage              connectionPage;\r
        private final ConfigDebugPage                   debugPage;\r
@@ -60,12 +61,14 @@ public class ConfigDialog extends QDialog {
                contentsWidget.setSpacing(12);\r
                \r
                pagesWidget = new QStackedWidget(this);\r
+               fontPage = new ConfigFontPage(this);\r
                connectionPage = new ConfigConnectionPage(this);\r
                appearancePage = new ConfigAppearancePage(this);\r
                indexPage = new ConfigIndexPage(this);\r
                debugPage = new ConfigDebugPage(this);\r
                spellPage = new ConfigSpellPage(this);\r
                pagesWidget.addWidget(appearancePage);\r
+               pagesWidget.addWidget(fontPage);\r
                pagesWidget.addWidget(indexPage);\r
                pagesWidget.addWidget(spellPage);\r
                pagesWidget.addWidget(connectionPage);\r
@@ -189,6 +192,10 @@ public class ConfigDialog extends QDialog {
                Global.setTimeFormat(timeFmt);\r
                \r
                Global.setSyncInterval(connectionPage.getSyncInterval());\r
+               \r
+               Global.setOverrideDefaultFont(fontPage.overrideFont());\r
+               Global.setDefaultFont(fontPage.getFont());\r
+               Global.setDefaultFontSize(fontPage.getFontSize());\r
                                \r
                close();\r
        }\r
@@ -217,6 +224,12 @@ public class ConfigDialog extends QDialog {
                formatsButton.setFlags(ItemFlag.ItemIsSelectable, ItemFlag.ItemIsEnabled);\r
                formatsButton.setIcon(new QIcon(iconPath+"appearance.jpg"));\r
                \r
+               QListWidgetItem fontButton = new QListWidgetItem(contentsWidget);\r
+               fontButton.setText(tr("Fonts"));\r
+               fontButton.setTextAlignment(AlignmentFlag.AlignHCenter.value());\r
+               fontButton.setFlags(ItemFlag.ItemIsSelectable, ItemFlag.ItemIsEnabled);\r
+               fontButton.setIcon(new QIcon(iconPath+"fontConfig.png"));\r
+               \r
                QListWidgetItem indexButton = new QListWidgetItem(contentsWidget);\r
                indexButton.setText(tr("Indexing"));\r
                indexButton.setTextAlignment(AlignmentFlag.AlignHCenter.value());\r
diff --git a/src/cx/fbn/nevernote/dialog/ConfigFontPage.java b/src/cx/fbn/nevernote/dialog/ConfigFontPage.java
new file mode 100644 (file)
index 0000000..d1abd4c
--- /dev/null
@@ -0,0 +1,143 @@
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.dialog;\r
+\r
+import java.util.List;\r
+\r
+import com.trolltech.qt.gui.QCheckBox;\r
+import com.trolltech.qt.gui.QComboBox;\r
+import com.trolltech.qt.gui.QFontDatabase;\r
+import com.trolltech.qt.gui.QGridLayout;\r
+import com.trolltech.qt.gui.QGroupBox;\r
+import com.trolltech.qt.gui.QLabel;\r
+import com.trolltech.qt.gui.QVBoxLayout;\r
+import com.trolltech.qt.gui.QWidget;\r
+\r
+import cx.fbn.nevernote.Global;\r
+\r
+public class ConfigFontPage extends QWidget {\r
+       private final QCheckBox overrideFonts;\r
+       private final QComboBox fontList;\r
+       private final QComboBox fontSizeList;\r
+       private String font;\r
+       private String fontSize;\r
+               \r
+       public ConfigFontPage(QWidget parent) {\r
+               \r
+               font = Global.getDefaultFont();\r
+               fontSize = Global.getDefaultFontSize();\r
+               \r
+               // Group Box\r
+               QGroupBox fontGroup = new QGroupBox(tr("New Note Defaults"));\r
+               QGridLayout fontLayout = new QGridLayout();\r
+               overrideFonts = new QCheckBox(tr("Override Defaults")); \r
+               overrideFonts.setCheckable(true);\r
+               overrideFonts.setChecked(Global.overrideDefaultFont());\r
+               overrideFonts.clicked.connect(this, "toggleFontOverride(Boolean)");\r
+               fontLayout.addWidget(overrideFonts,1,2);\r
+               \r
+               \r
+               // Fonts\r
+               fontList = new QComboBox();                             \r
+               fontList.activated.connect(this, "fontSelected(String)");\r
+               fontLayout.addWidget(new QLabel(tr("Font")),2,1);\r
+               fontLayout.addWidget(fontList,2,2);\r
+               \r
+               // Font Sizes\r
+               fontSizeList = new QComboBox();                         \r
+               fontLayout.addWidget(fontSizeList,3,2);\r
+               fontSizeList.activated.connect(this, "fontSizeSelected(String)");\r
+               fontLayout.addWidget(new QLabel(tr("Size")),3,1);\r
+               fontGroup.setLayout(fontLayout);\r
+               fontLayout.setColumnStretch(2, 100);\r
+               toggleFontOverride(Global.overrideDefaultFont());\r
+               loadFonts();\r
+               loadSettings();\r
+               \r
+               \r
+               QVBoxLayout mainLayout = new QVBoxLayout();\r
+               mainLayout.addWidget(fontGroup);\r
+               mainLayout.addStretch(1);\r
+               setLayout(mainLayout);\r
+       }\r
+       \r
+       private void toggleFontOverride(Boolean value) {\r
+               fontList.setEnabled(value);\r
+               fontSizeList.setEnabled(value);\r
+       }\r
+       \r
+       private void loadFonts() {\r
+               QFontDatabase fonts = new QFontDatabase();\r
+               List<String> fontFamilies = fonts.families();\r
+               for (int i = 0; i < fontFamilies.size(); i++) {\r
+                       if (font.equals(""))\r
+                               font = fontFamilies.get(i);\r
+                       fontList.addItem(fontFamilies.get(i));\r
+                       if (i == 0) {\r
+                               loadFontSize(fontFamilies.get(i));\r
+                       }\r
+               }\r
+\r
+       }\r
+       \r
+       // Load the font combo box based upon the font selected\r
+       private void loadFontSize(String name) {        \r
+               QFontDatabase db = new QFontDatabase(); \r
+               fontSizeList.clear();\r
+               List<Integer> points = db.pointSizes(name); \r
+               for (int i=0; i<points.size(); i++) { \r
+                       if (fontSize.equals(""))\r
+                               fontSize = points.get(i).toString();\r
+                       fontSizeList.addItem(points.get(i).toString()); \r
+               }\r
+\r
+       }\r
+       \r
+       private void fontSelected(String font) {\r
+               this.font = font;\r
+               loadFontSize(font);\r
+       }\r
+       \r
+       private void fontSizeSelected(String size) {\r
+               this.fontSize = size;\r
+       }\r
+       \r
+       private void loadSettings() {\r
+               if (!Global.getDefaultFont().equals("")) {\r
+                       int index = fontList.findText(Global.getDefaultFont());\r
+                       fontList.setCurrentIndex(index);\r
+               }\r
+               if (!Global.getDefaultFontSize().equals("")) {\r
+                       int index = fontSizeList.findText(Global.getDefaultFontSize());\r
+                       fontSizeList.setCurrentIndex(index);\r
+               }\r
+       }\r
+       \r
+       public String getFont() {\r
+               return font;\r
+       }\r
+       public String getFontSize() {\r
+               return fontSize;\r
+       }\r
+       public boolean overrideFont() {\r
+               return overrideFonts.isChecked();\r
+       }\r
+       \r
+}\r
index 5570a86..60a3d61 100644 (file)
@@ -122,6 +122,9 @@ public class EnDecryptDialog extends QDialog {
        public void setHint(String h) {\r
                hint.setText(h.replace("&apos;", "'"));\r
        }\r
+       public String getHint() {\r
+               return hint.text();\r
+       }\r
        // Set the error message\r
        public void setError(String e) {\r
                error.setText(e);\r
index 8ff181b..d326088 100644 (file)
@@ -35,6 +35,9 @@ public class NotebookEdit extends QDialog {
        private final QCheckBox         localRemote;
        private final QPushButton               ok;
        private List<Notebook>  currentNotebooks;
+       private final QCheckBox         isDefault;
+       private boolean startDefault;
+       private String startText;
                
        // Constructor
        public NotebookEdit() {
@@ -54,7 +57,13 @@ public class NotebookEdit extends QDialog {
                localRemote.setText(tr("Local Notebook"));
                localRemote.setChecked(false);
                grid.addWidget(localRemote, 2,1);
-               
+
+               isDefault = new QCheckBox();
+               isDefault.setText(tr("Default Notebook"));
+               isDefault.setChecked(false);
+               isDefault.toggled.connect(this, "defaultNotebookChecked(Boolean)");
+               grid.addWidget(isDefault, 3,1);
+
                QGridLayout buttonLayout = new QGridLayout();
                ok = new QPushButton(tr("OK"));
                ok.clicked.connect(this, "okButtonPressed()");
@@ -64,7 +73,7 @@ public class NotebookEdit extends QDialog {
                notebook.textChanged.connect(this, "textChanged()");
                buttonLayout.addWidget(ok, 1, 1);
                buttonLayout.addWidget(cancel, 1,2);
-               grid.addLayout(buttonLayout,3,1);
+               grid.addLayout(buttonLayout,4,1);
        }
        
        // The OK button was pressed
@@ -88,7 +97,13 @@ public class NotebookEdit extends QDialog {
        
        // Set the notebook name
        public void setNotebook(String name) {
+               if (name.equalsIgnoreCase("All Notebooks")) {
+                       notebook.setEnabled(false);
+                       localRemote.setEnabled(false);
+                       isDefault.setEnabled(false);
+               }
                notebook.setText(name);
+               startText = name;
        }
        
        // Is this a local notebook?
@@ -117,6 +132,25 @@ public class NotebookEdit extends QDialog {
                currentNotebooks = n;
        }
        
+       // Get default notebook
+       public void setDefaultNotebook(boolean val) {
+               startDefault = val;
+               isDefault.setChecked(val);
+               if (val) 
+                       isDefault.setEnabled(true);
+       }
+       public boolean isDefaultNotebook() {
+               return isDefault.isChecked();
+       }
+       
+       // Action when the default notebook icon is checked
+       private void defaultNotebookChecked(Boolean val) {
+               if (val != startDefault || !startText.equals(notebook.text())) 
+                       ok.setEnabled(true);
+               else
+                       ok.setEnabled(false);
+       }
+       
        // Watch what text is being entered
        @SuppressWarnings("unused")
        private void textChanged() {
index fb76352..6b1b468 100644 (file)
 \r
 package cx.fbn.nevernote.dialog;\r
 \r
-import java.io.File;\r
 import java.text.SimpleDateFormat;\r
+import java.util.ArrayList;\r
 import java.util.List;\r
 \r
 import com.evernote.edam.notestore.NoteVersionId;\r
 import com.evernote.edam.type.Note;\r
-import com.evernote.edam.type.Resource;\r
-import com.trolltech.qt.core.QByteArray;\r
-import com.trolltech.qt.core.QFile;\r
-import com.trolltech.qt.core.QIODevice;\r
+import com.trolltech.qt.core.QTemporaryFile;\r
 import com.trolltech.qt.core.Qt.ContextMenuPolicy;\r
 import com.trolltech.qt.gui.QComboBox;\r
 import com.trolltech.qt.gui.QDialog;\r
@@ -36,25 +33,24 @@ import com.trolltech.qt.gui.QHBoxLayout;
 import com.trolltech.qt.gui.QLabel;\r
 import com.trolltech.qt.gui.QPushButton;\r
 import com.trolltech.qt.gui.QVBoxLayout;\r
-import com.trolltech.qt.xml.QDomAttr;\r
-import com.trolltech.qt.xml.QDomDocument;\r
-import com.trolltech.qt.xml.QDomElement;\r
-import com.trolltech.qt.xml.QDomNodeList;\r
 \r
 import cx.fbn.nevernote.Global;\r
-import cx.fbn.nevernote.NeverNote;\r
 import cx.fbn.nevernote.gui.BrowserWindow;\r
 import cx.fbn.nevernote.sql.DatabaseConnection;\r
+import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+import cx.fbn.nevernote.xml.NoteFormatter;\r
 \r
 public class OnlineNoteHistory extends QDialog {\r
        public final QPushButton        restoreAsNew;\r
        public final QPushButton        restore;\r
-       private DatabaseConnection  conn;\r
+       private final DatabaseConnection  conn;\r
        public final QComboBox          historyCombo;    \r
        private final BrowserWindow     browser;\r
+       private final ApplicationLogger logger;\r
+       List<QTemporaryFile>    tempFiles;\r
        \r
        // Constructor\r
-       public OnlineNoteHistory(DatabaseConnection c) {\r
+       public OnlineNoteHistory(ApplicationLogger l, DatabaseConnection c) {\r
                setWindowTitle(tr("Online Note History"));\r
                QVBoxLayout main = new QVBoxLayout();\r
                setLayout(main);\r
@@ -67,6 +63,7 @@ public class OnlineNoteHistory extends QDialog {
                \r
                main.addLayout(comboLayout);\r
                                \r
+               conn = c;\r
                browser = new BrowserWindow(conn);\r
                main.addWidget(browser);\r
                browser.titleLabel.setVisible(false);\r
@@ -91,7 +88,8 @@ public class OnlineNoteHistory extends QDialog {
                main.addLayout(buttonLayout);\r
                \r
                browser.getBrowser().setContextMenuPolicy(ContextMenuPolicy.NoContextMenu);\r
-\r
+               tempFiles = new ArrayList<QTemporaryFile>();\r
+               logger = l;\r
        }\r
        \r
        @SuppressWarnings("unused")\r
@@ -127,250 +125,31 @@ public class OnlineNoteHistory extends QDialog {
        }\r
        \r
        public void setContent(Note currentNote) {\r
-               StringBuffer b = rebuildNoteHTML(currentNote);\r
+               \r
+               \r
+               NoteFormatter formatter = new NoteFormatter(logger, conn, tempFiles);\r
+               formatter.setNote(currentNote, false);\r
+               formatter.setHighlight(null);\r
+               formatter.setNoteHistory(true);\r
+               \r
                StringBuffer js = new StringBuffer();\r
-\r
+               \r
                // We need to prepend the note with <HEAD></HEAD> or encoded characters are ugly \r
                js.append("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">");       \r
                js.append("<style type=\"text/css\">en-crypt-temp { border-style:solid; border-color:blue; padding:1mm 1mm 1mm 1mm; }</style>");\r
                js.append("</head>");\r
-               js.append(b.toString());\r
+               js.append(formatter.rebuildNoteHTML());\r
                js.append("</HTML>");\r
-//             js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml2.dtd'>", "");\r
-//             js.replace("<?xml version='1.0' encoding='UTF-8'?>", "");\r
                \r
                browser.setNote(currentNote);\r
                browser.getBrowser().page().mainFrame().setHtml(js.toString());\r
        }\r
+}\r
  \r
-       //*************************************************\r
-       //* XML Modifying Methods\r
-       //*************************************************\r
-       private StringBuffer rebuildNoteHTML(Note note) {\r
-               QDomDocument doc = new QDomDocument();\r
-               QDomDocument.Result result = doc.setContent(note.getContent());\r
-               if (!result.success) {\r
-                       return new StringBuffer(note.getContent());\r
-               }\r
-               \r
-               doc = modifyTags(note, doc);\r
-               QDomElement docElem = doc.documentElement();\r
-               docElem.setTagName("Body");\r
-               \r
-               // Fix the stupid problem where inserting an <img> tag after an <a> tag (which is done\r
-               // to get the <en-media> application tag to work properly) causes spaces to be inserted\r
-               // between the <a> & <img>.  This messes things up later.  This is an ugly hack.\r
-               String docString = doc.toString();\r
-               StringBuffer html = new StringBuffer(docString.substring(docString.toLowerCase().indexOf("<body>")));\r
-               \r
-               for (int i=html.indexOf("<a en-tag=\"en-media\" ", 0); i>-1; i=html.indexOf("<a en-tag=\"en-media\" ", i)) {\r
-                       i=html.indexOf(">\n",i+1);\r
-                       int z = html.indexOf("<img",i);\r
-                       for (int j=z-1; j>i; j--) \r
-                               html.deleteCharAt(j);\r
-                       i=html.indexOf("/>", z+1);\r
-                       z = html.indexOf("</a>",i);\r
-                       for (int j=z-1; j>i+1; j--) \r
-                               html.deleteCharAt(j);\r
-               } \r
-               return html;\r
-       }       \r
 \r
-       \r
-       \r
-       private QDomDocument modifyTags(Note note, QDomDocument doc) {\r
-               QDomElement docElem = doc.documentElement();\r
-               \r
-               // Modify en-media tags\r
-               QDomNodeList anchors = docElem.elementsByTagName("en-media");\r
-               int enMediaCount = anchors.length();\r
-               for (int i=enMediaCount-1; i>=0; i--) {\r
-                       QDomElement enmedia = anchors.at(i).toElement();\r
-                       if (enmedia.hasAttribute("type")) {\r
-                               QDomAttr attr = enmedia.attributeNode("type");\r
-                               QDomAttr hash = enmedia.attributeNode("hash");\r
-                               String[] type = attr.nodeValue().split("/");\r
-                               String appl = type[1];\r
-                               \r
-                               if (type[0] != null) {\r
-                                       if (type[0].equals("image")) {\r
-                                               modifyImageTags(note, docElem, enmedia, hash);\r
-                                       }\r
-                                       if (!type[0].equals("image")) {\r
-                                               modifyApplicationTags(note, doc, docElem, enmedia, hash, appl);\r
-                                       }\r
-//                                     if (type[0].equals("audio")) {\r
-//                                             modifyApplicationTags(doc, docElem, enmedia, hash, appl);\r
-//                                     }\r
-                               }\r
-                       }\r
-               }\r
-               \r
-               // Modify todo tags\r
-               anchors = docElem.elementsByTagName("en-todo");\r
-               int enTodoCount = anchors.length();\r
-               for (int i=enTodoCount-1; i>=0; i--) {\r
-                       QDomElement enmedia = anchors.at(i).toElement();\r
-                       modifyTodoTags(enmedia);\r
-               }\r
-               \r
-               // Modify en-crypt tags\r
-               anchors = docElem.elementsByTagName("en-crypt");\r
-               int enCryptLen = anchors.length();\r
-               for (int i=enCryptLen-1; i>=0; i--) {\r
-                       QDomElement enmedia = anchors.at(i).toElement();\r
-                       //enmedia.setAttribute("style","display:none");\r
-                       enmedia.setAttribute("contentEditable","false");\r
-                       enmedia.setAttribute("src", Global.getFileManager().getImageDirPath("encrypt.png"));\r
-                       enmedia.setAttribute("en-tag","en-crypt");\r
-                       enmedia.setAttribute("alt", enmedia.text());\r
-                       Global.cryptCounter++;\r
-                       enmedia.setAttribute("id", "crypt"+Global.cryptCounter.toString());\r
-                       String encryptedText = enmedia.text();\r
-                       \r
-                       // If the encryption string contains crlf at the end, remove them because they mess up the javascript.\r
-                       if (encryptedText.endsWith("\n"))\r
-                               encryptedText = encryptedText.substring(0,encryptedText.length()-1);\r
-                       if (encryptedText.endsWith("\r"))\r
-                               encryptedText = encryptedText.substring(0,encryptedText.length()-1);\r
-                       \r
-                       // Add the commands\r
-                       enmedia.setAttribute("onClick", "window.jambi.decryptText('crypt"+Global.cryptCounter.toString()+"', '"+encryptedText+"', '"+enmedia.attribute("hint")+"');");\r
-                       enmedia.setAttribute("onMouseOver", "style.cursor='hand'");\r
-                       enmedia.setTagName("img");\r
-                       enmedia.removeChild(enmedia.firstChild());   // Remove the actual encrypted text\r
-               }\r
 \r
-               return doc;\r
-       }\r
-       \r
-       \r
-       \r
        \r
-          private void modifyApplicationTags(Note n, QDomDocument doc, QDomElement docElem, QDomElement enmedia, QDomAttr hash, String appl) {\r
-                 \r
-                  Resource r = null;\r
-                  for (int i=0; i<n.getResourcesSize(); i++) {\r
-                          String hashValue = hash.value();\r
-                          byte res[] = n.getResources().get(i).getData().getBodyHash();\r
-                          String resourceHashValue = new String(Global.byteArrayToHexString(res));\r
-                          if (resourceHashValue.equalsIgnoreCase(hashValue)) {\r
-                                  r = n.getResources().get(i);\r
-                                  i=n.getResourcesSize();\r
-                          }\r
-                  }\r
-                  \r
-                  if (r!= null) {\r
-                               if (r.getData()!=null) {\r
-                                       // Did we get a generic applicaiton?  Then look at the file name to \r
-                                       // try and find a good application type for the icon\r
-                                       if (appl.equalsIgnoreCase("octet-stream")) {\r
-                                               if (r.getAttributes() != null && r.getAttributes().getFileName() != null) {\r
-                                                       String fn = r.getAttributes().getFileName();\r
-                                                       int pos = fn.indexOf(".");\r
-                                                       if (pos > -1) {\r
-                                                               appl = fn.substring(pos+1);\r
-                                                       }\r
-                                               }\r
-                                       }\r
-                                       \r
-                                       String fileDetails = null;\r
-                                       if (r.getAttributes() != null && r.getAttributes().getFileName() != null && !r.getAttributes().getFileName().equals(""))\r
-                                               fileDetails = r.getAttributes().getFileName();\r
-                                       if (fileDetails != null && !fileDetails.equals("")) \r
-                                               enmedia.setAttribute("href", "nnres://" +r.getGuid()+n.getUpdateSequenceNum() +Global.attachmentNameDelimeter +fileDetails);\r
-                                       else\r
-                                               enmedia.setAttribute("href", "nnres://" +r.getGuid()+n.getUpdateSequenceNum() +Global.attachmentNameDelimeter +appl);\r
-                                       if (fileDetails == null || fileDetails.equals(""))\r
-                                               fileDetails = "";\r
-                                       enmedia.setAttribute("en-tag", "en-media");\r
-                                       enmedia.setAttribute("guid", r.getGuid());\r
-                                       enmedia.setTagName("a");\r
-                                       QDomElement newText = doc.createElement("img");\r
-                                       String icon = findIcon(appl);\r
-                                       if (icon.equals("attachment.png"))\r
-                                               icon = findIcon(fileDetails.substring(fileDetails.indexOf(".")+1));\r
-                                       newText.setAttribute("src", Global.getFileManager().getImageDirPath(icon));\r
-                                       newText.setAttribute("title", fileDetails);\r
-                                       enmedia.removeChild(enmedia.firstChild());\r
-                                       enmedia.appendChild(newText);\r
-                               }\r
-                       }\r
-           }\r
-          /**\r
-           * find the appropriate icon for an attachment\r
-           *\r
-            * NFC TODO: duplicate of {@link NeverNote#findIcon(String)}\r
-           */\r
-           private String findIcon(String appl) {\r
-               appl = appl.toLowerCase();\r
-        String relativePath = appl + ".png";\r
-        File f = Global.getFileManager().getImageDirFile(relativePath);\r
-        if (f.exists()) {\r
-            return relativePath;\r
-        }\r
-               return "attachment.png";\r
-           }\r
-           \r
        \r
        \r
        \r
-       \r
-       \r
-       \r
-    private void modifyTodoTags(QDomElement todo) {\r
-               todo.setAttribute("type", "checkbox");\r
-               String checked = todo.attribute("checked");\r
-               todo.removeAttribute("checked");\r
-               if (checked.equalsIgnoreCase("true"))\r
-                       todo.setAttribute("checked", "");\r
-               else\r
-                       todo.setAttribute("unchecked","");\r
-               todo.setAttribute("value", checked);\r
-               todo.setAttribute("onClick", "value=checked;window.jambi.contentChanged(); ");\r
-               todo.setTagName("input");\r
-    }\r
-    \r
-    \r
-    private void modifyImageTags(Note note, QDomElement docElem, QDomElement enmedia, QDomAttr hash) {\r
-       String type = enmedia.attribute("type");\r
-       if (type.startsWith("image/"))\r
-               type = "."+type.substring(6);\r
-       else\r
-               type="";\r
-       \r
-       Resource r = null;\r
-               for (int i=0; i<note.getResourcesSize(); i++) {\r
-                       String hashValue = hash.value();\r
-                       byte res[] = note.getResources().get(i).getData().getBodyHash();\r
-                       String resourceHashValue = new String(Global.byteArrayToHexString(res));\r
-                  if (hashValue.equalsIgnoreCase(resourceHashValue)) {\r
-                          r = note.getResources().get(i);\r
-                          i=note.getResourcesSize();\r
-                  }\r
-               }\r
-       \r
-               if (r==null)\r
-                       return;\r
-               \r
-       QFile tfile = new QFile(Global.getFileManager().getResDirPath(r.getGuid() + note.getUpdateSequenceNum() + type));\r
-       if (!tfile.exists()) {\r
-                       if (r!= null && r.getData() != null && r.getData().getBody().length > 0) {\r
-                               tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));\r
-                               QByteArray binData = new QByteArray(r.getData().getBody());\r
-                               tfile.write(binData);\r
-                               tfile.close();\r
-                               enmedia.setAttribute("src", tfile.fileName());\r
-                               enmedia.setAttribute("en-tag", "en-media");\r
-                               enmedia.setNodeValue("");\r
-                       enmedia.setAttribute("guid", r.getGuid());\r
-                       enmedia.setTagName("img");\r
-               }\r
-       }\r
-               enmedia.setAttribute("src", tfile.fileName());\r
-               enmedia.setAttribute("en-tag", "en-media");\r
-               enmedia.setNodeValue("");\r
-               enmedia.setAttribute("guid", r.getGuid());\r
-               enmedia.setTagName("img");\r
-    }\r
-}\r
+\r
index ab224de..f4570be 100644 (file)
@@ -32,6 +32,7 @@ import com.trolltech.qt.core.QTextCodec;
 \r
 import cx.fbn.nevernote.Global;\r
 import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+import cx.fbn.nevernote.utilities.Pair;\r
 import cx.fbn.nevernote.xml.XMLCleanup;\r
 import cx.fbn.nevernote.xml.XMLNoteRepair;\r
 \r
@@ -125,6 +126,9 @@ public class EnmlConverter {
 //             newContent = repair.parse(newContent, false);\r
 //             logger.log(logger.HIGH, "Check complete");\r
        \r
+        logger.log(logger.HIGH, "Fixing encryption tags");\r
+        newContent = fixEncryptionTags(newContent);\r
+               \r
                Tidy tidy = new Tidy();\r
                TidyListener tidyListener = new TidyListener(logger);\r
                tidy.setMessageListener(tidyListener);\r
@@ -137,40 +141,42 @@ public class EnmlConverter {
         \r
 //             byte html[] = newContent.getBytes();\r
 //             ByteArrayInputStream is = new ByteArrayInputStream(html);\r
-\r
+        logger.log(logger.HIGH, "Starting JTidy check");\r
+        logger.log(logger.EXTREME, "Start of JTidy Input");\r
+        logger.log(logger.EXTREME, newContent);\r
+        logger.log(logger.EXTREME, "End Of JTidy Input");\r
                ByteArrayInputStream is = new ByteArrayInputStream(unicode.toByteArray());\r
         ByteArrayOutputStream os = new ByteArrayOutputStream();\r
         tidy.setInputEncoding("UTF-8");\r
-//        tidy.setOutputEncoding("UTF-8");\r
                tidy.parse(is, os);\r
-               newContent = os.toString();\r
-//             newContent = new QByteArray(codec.fromUnicode(os.toString())).toString();\r
+               String tidyContent = os.toString();\r
                if (tidyListener.errorFound) {\r
                        logger.log(logger.LOW, "Note Contents Begin");\r
                        logger.log(logger.LOW, content);\r
                        logger.log(logger.LOW, "Note Contents End");\r
-                       newContent = null;\r
+                       tidyContent = null;\r
                } else {\r
                        if (newContent.trim().equals(""))\r
-                               newContent = null;\r
+                               tidyContent = null;\r
                }\r
 \r
                // If the repair above returned null, then the XML is foobar.\r
                // We are done here.\r
-               if (newContent == null) {\r
-                       // Houston, we've had a problem.\r
-                       logger.log(logger.LOW, "Parse error when converting to ENML");\r
-                       logger.log(logger.LOW, "Start of unmodified note HTML");\r
-                       logger.log(logger.LOW, content);\r
-                       logger.log(logger.LOW, "End of unmodified note HTML");\r
-                       logger.log(logger.LOW, "Start of modified note HTML");\r
-                       logger.log(logger.LOW, newContent);\r
-                       logger.log(logger.LOW, "End of modified note HTML");\r
-//                             logger.log(logger.LOW, result.errorMessage);\r
-//                             logger.log(logger.LOW, "Error Line:Column "+result.errorLine+":" +result.errorColumn);\r
-                       return null;\r
-\r
-\r
+               if (tidyContent != null) {\r
+                       newContent = tidyContent;\r
+               } else {\r
+                       // Houston, we've had a problem.  Fall back to old method\r
+                       logger.log(logger.HIGH, "Error converting to JTidy.  Falling back to old method");\r
+                       String repairedContent = repair.parse(newContent, false);\r
+                       if (repairedContent == null) {\r
+                               logger.log(logger.EXTREME, "Null returned from repair.parse()");\r
+                               logger.log(logger.LOW, "Parse error when converting to ENML. Aborting save");\r
+                               return null;\r
+                       }\r
+                       newContent = repairedContent;\r
+                       logger.log(logger.EXTREME, "Start of repaired content");\r
+                       logger.log(logger.EXTREME, repairedContent);\r
+                       logger.log(logger.EXTREME, "End of repaired content");\r
                }\r
                \r
                // Second pass through the data.  The goal of this pass is to \r
@@ -204,7 +210,11 @@ public class EnmlConverter {
                                "<!DOCTYPE en-note SYSTEM \"" +dtd +"\">");\r
                \r
                logger.log(logger.HIGH, "Validating ENML");\r
-               newContent = repair.parse(newContent, true);\r
+               String repairedContent = repair.parse(newContent, true);\r
+               if (repairedContent == null)\r
+                       logger.log(logger.EXTREME, "Null returned from repair.parse()");\r
+               else\r
+                       newContent = repairedContent;\r
                logger.log(logger.HIGH, "Validation complete");\r
                saveInvalidXML = repair.saveInvalidXML;\r
                \r
@@ -213,10 +223,49 @@ public class EnmlConverter {
                                "<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml2.dtd'>");\r
                \r
                \r
-               \r
+               logger.log(logger.EXTREME, "Leaving ENMLConverter.convert()");\r
                return newContent;\r
        }\r
+\r
        \r
+       private String fixEncryptionTags(String content) {\r
+               // Fix the problem that the document body isn't properly closed\r
+               String newContent = new String(content);\r
+               logger.log(logger.MEDIUM, "Inside EnmlConverter.fixEncryptionTags");\r
+               logger.log(logger.EXTREME, content);\r
+               \r
+               // Fix the problem that the img tag isn't properly closed\r
+               int endPos, startPos, endData,slotStart, slotEnd;\r
+               logger.log(logger.MEDIUM, "Checking table encryption tags");\r
+               String eTag = "<table class=\"en-crypt-temp\"";\r
+               for (int i=newContent.indexOf(eTag); i>0; i = newContent.indexOf(eTag,i+1)) {\r
+                       slotStart = newContent.indexOf("slot", i+1)+6;\r
+                       slotEnd = newContent.indexOf("\"",slotStart);\r
+                       String slot = newContent.substring(slotStart, slotEnd);\r
+                       startPos = newContent.indexOf("<td>", i+1)+4;\r
+                       endData = newContent.indexOf("</td>",startPos);\r
+                       String text = newContent.substring(startPos,endData);\r
+                       endPos = newContent.indexOf("</table>",i+1)+8;\r
+                       // Encrypt the text\r
+                       Pair<String,String> pair;\r
+                       Pair pair2 = Global.passwordSafe.get(slot);\r
+                       pair = pair2;\r
+                       String password = pair.getFirst();\r
+                       String hint = pair.getSecond();\r
+                       EnCrypt crypt = new EnCrypt(); \r
+                       String encrypted = crypt.encrypt(text, password, 64); \r
+\r
+                       // replace the table with an en-crypt tag.\r
+                       newContent = newContent.substring(0,i-1) + \r
+                               "<en-crypt-temp cipher=\"RC2\" length=\"64\" hint=\""+\r
+                               hint +"\" value=\""+\r
+                               encrypted +\r
+                               "\" />" +\r
+                               newContent.substring(endPos);\r
+               }\r
+               \r
+               return newContent;\r
+       }\r
        \r
        // Fix XML problems that Qt can't deal with\r
        public String fixStupidXMLProblems(String content) {\r
@@ -225,7 +274,7 @@ public class EnmlConverter {
                // Fix the problem that the document body isn't properly closed\r
                String newContent = new String(content);\r
                logger.log(logger.MEDIUM, "Inside fixStupidXMLProblems.  Old content:");\r
-               logger.log(logger.MEDIUM, content);\r
+               logger.log(logger.EXTREME, content);\r
                \r
                // Fix the problem that the img tag isn't properly closed\r
                int endPos;\r
@@ -269,12 +318,14 @@ public class EnmlConverter {
 \r
        // Fix XML that Evernote thinks is invalid\r
        public String fixEnXMLCrap(String note) {\r
+               logger.log(logger.EXTREME, "Entering EnmlConverter.fixEnXMLCrap");\r
                if (note == null)\r
                        return null;\r
                \r
                int pos;\r
                StringBuffer buffer = new StringBuffer(note);\r
                \r
+               logger.log(logger.EXTREME, "Converting <b/>");\r
                // change all <b/> to <b></b> because Evernote hates them if they happen in <span>\r
                pos = buffer.indexOf("<b/>");\r
                for (; pos>-1; ) {\r
@@ -282,6 +333,7 @@ public class EnmlConverter {
                        pos = buffer.indexOf("<b/>",pos);\r
                }\r
                // change all <br/> to <br></br> because Evernote hates them if they happen in <span>\r
+               logger.log(logger.EXTREME, "converting <br/>");\r
                pos = buffer.indexOf("<br/>");\r
                for (; pos>-1; ) {\r
                        buffer.replace(pos, pos+5, "<br></br>");\r
@@ -293,17 +345,6 @@ public class EnmlConverter {
                int spanPos;\r
                pos = buffer.indexOf("<li>");\r
                spanPos = buffer.indexOf("<span>");\r
-/*             for (; pos>-1 && spanPos >-1;) {\r
-                       endPos = buffer.indexOf("</li>",pos);\r
-                       if (spanPos > pos && spanPos < endPos) {\r
-                               buffer.replace(spanPos,spanPos+6,"");\r
-                               spanPos = buffer.indexOf("</span>");                            \r
-                               buffer.replace(spanPos,spanPos+7,"");\r
-                       }\r
-                       pos=buffer.indexOf("<li>",pos+1);\r
-                       spanPos = buffer.indexOf("<span>",spanPos);\r
-               }\r
-*/             \r
                // Get rid of empty spans in <li> elements\r
                pos = buffer.indexOf("<li>");\r
                spanPos = buffer.indexOf("<span/>");\r
@@ -316,6 +357,7 @@ public class EnmlConverter {
                        spanPos = buffer.indexOf("<span/>",spanPos);\r
                }\r
                \r
+               logger.log(logger.EXTREME, "Leaving EnmlConverter.fixEnXMLCrap");\r
                return buffer.toString();\r
        }\r
        \r
index d8f4857..6f3280a 100644 (file)
@@ -63,6 +63,7 @@ import com.trolltech.qt.core.QFile;
 import com.trolltech.qt.core.QFileSystemWatcher;\r
 import com.trolltech.qt.core.QIODevice;\r
 import com.trolltech.qt.core.QMimeData;\r
+import com.trolltech.qt.core.QTextCodec;\r
 import com.trolltech.qt.core.QUrl;\r
 import com.trolltech.qt.core.Qt.Key;\r
 import com.trolltech.qt.core.Qt.KeyboardModifier;\r
@@ -118,6 +119,7 @@ import cx.fbn.nevernote.signals.NoteSignal;
 import cx.fbn.nevernote.sql.DatabaseConnection;\r
 import cx.fbn.nevernote.utilities.ApplicationLogger;\r
 import cx.fbn.nevernote.utilities.FileUtils;\r
+import cx.fbn.nevernote.utilities.Pair;\r
 \r
 public class BrowserWindow extends QWidget {\r
 \r
@@ -244,7 +246,6 @@ public class BrowserWindow extends QWidget {
                        spellCheckDialog = new SpellCheck(checker);\r
                }\r
                public void spellingError(SpellCheckEvent event) {\r
-                       System.out.println("**" +event.getInvalidWord());\r
                        errorsFound = true;\r
                        spellCheckDialog.setWord(event.getInvalidWord());\r
 \r
@@ -664,7 +665,8 @@ public class BrowserWindow extends QWidget {
        // New Editor Button\r
        private QPushButton newEditorButton(String name, String toolTip) {\r
                QPushButton button = new QPushButton();\r
-               QIcon icon = new QIcon(iconPath + name + ".gif");\r
+//             QIcon icon = new QIcon(iconPath + name + ".gif");\r
+               QIcon icon = new QIcon(iconPath + name + ".png");\r
                button.setIcon(icon);\r
                button.setToolTip(toolTip);\r
                button.clicked.connect(this, name + "Clicked()");\r
@@ -673,7 +675,8 @@ public class BrowserWindow extends QWidget {
        // New Editor Button\r
        private QToolButton newToolButton(String name, String toolTip) {\r
                QToolButton button = new QToolButton();\r
-               QIcon icon = new QIcon(iconPath + name + ".gif");\r
+//             QIcon icon = new QIcon(iconPath + name + ".gif");\r
+               QIcon icon = new QIcon(iconPath + name + ".png");\r
                button.setIcon(icon);\r
                button.setToolTip(toolTip);\r
                button.clicked.connect(this, name + "Clicked()");\r
@@ -1209,6 +1212,7 @@ public class BrowserWindow extends QWidget {
                String text = browser.selectedText();\r
                if (text.trim().equalsIgnoreCase(""))\r
                        return;\r
+               text = new String(text.replaceAll("\n", "<br/>"));\r
 \r
                EnCryptDialog dialog = new EnCryptDialog();\r
                dialog.exec();\r
@@ -1218,6 +1222,7 @@ public class BrowserWindow extends QWidget {
 \r
                EnCrypt crypt = new EnCrypt();\r
                String encrypted = crypt.encrypt(text, dialog.getPassword().trim(), 64);\r
+               String decrypted = crypt.decrypt(encrypted, dialog.getPassword().trim(), 64);\r
 \r
                if (encrypted.trim().equals("")) {\r
                        QMessageBox.information(this, tr("Error"), tr("Error Encrypting String"));\r
@@ -1228,7 +1233,6 @@ public class BrowserWindow extends QWidget {
                                + dialog.getHint().replace("'","\\'") + "\" length=\"64\" ");\r
                buffer.append("contentEditable=\"false\" alt=\"");\r
                buffer.append(encrypted);\r
-               // NFC FIXME: should this be a file URL like in handleLocalAttachment and importAttachment?\r
                buffer.append("\" src=\"").append(FileUtils.toForwardSlashedPath(Global.getFileManager().getImageDirPath("encrypt.png") +"\""));\r
                Global.cryptCounter++;\r
                buffer.append(" id=\"crypt"+Global.cryptCounter.toString() +"\"");\r
@@ -1370,9 +1374,10 @@ public class BrowserWindow extends QWidget {
                \r
                // First, try to decrypt with any keys we already have\r
                for (int i=0; i<Global.passwordRemember.size(); i++) {\r
-                       plainText = crypt.decrypt(text, Global.passwordRemember.get(i), 64);\r
+                       plainText = crypt.decrypt(text, Global.passwordRemember.get(i).getFirst(), 64);\r
                        if (plainText != null) {\r
                                slot = new String(Long.toString(l));\r
+                               Pair<String,String> passwordPair = new Pair<String,String>();\r
                                Global.passwordSafe.put(slot, Global.passwordRemember.get(i));\r
                                removeEncryption(id, plainText, false, slot);   \r
                                return;\r
@@ -1392,10 +1397,18 @@ public class BrowserWindow extends QWidget {
                                QMessageBox.warning(this, "Incorrect Password", "The password entered is not correct");\r
                        }\r
                }\r
-               Global.passwordSafe.put(slot, dialog.getPassword());\r
+               Pair<String,String> passwordPair = new Pair<String,String>();\r
+               passwordPair.setFirst(dialog.getPassword());\r
+               passwordPair.setSecond(dialog.getHint());\r
+               Global.passwordSafe.put(slot, passwordPair);\r
+//             removeEncryption(id, plainText.replaceAll("\n", "<br/>"), dialog.permanentlyDecrypt(), slot);\r
                removeEncryption(id, plainText, dialog.permanentlyDecrypt(), slot);\r
-               if (dialog.rememberPassword())\r
-                       Global.passwordRemember.add(dialog.getPassword());\r
+               if (dialog.rememberPassword()) {\r
+                       Pair<String, String> pair = new Pair<String,String>();\r
+                       pair.setFirst(dialog.getPassword());\r
+                       pair.setSecond(dialog.getHint());\r
+                       Global.passwordRemember.add(pair);\r
+               }\r
 \r
        }\r
 \r
@@ -1444,7 +1457,11 @@ public class BrowserWindow extends QWidget {
                String newTagArray[];\r
                if (!completionText.equals("")) {\r
                        String before = tagEdit.text().substring(0,tagEdit.cursorPosition());\r
-                       before = before.substring(0,before.lastIndexOf(Global.tagDelimeter));\r
+                       int lastDelimiter = before.lastIndexOf(Global.tagDelimeter);\r
+                       if (lastDelimiter > 0)\r
+                               before = before.substring(0,before.lastIndexOf(Global.tagDelimeter));\r
+                       else \r
+                               before = "";\r
                        String after = tagEdit.text().substring(tagEdit.cursorPosition());\r
                        newTagArray = (before+Global.tagDelimeter+completionText+Global.tagDelimeter+after).split(Global.tagDelimeter);\r
                }\r
@@ -1587,6 +1604,13 @@ public class BrowserWindow extends QWidget {
                        }\r
                }\r
        }\r
+       \r
+       \r
+       // Set the notebook for a note\r
+       public void setNotebook(String notebook) {\r
+               currentNote.setNotebookGuid(notebook);\r
+               loadNotebookList();\r
+       }\r
 \r
        // Get the contents of the editor\r
        public String getContent() {\r
@@ -1848,7 +1872,6 @@ public class BrowserWindow extends QWidget {
 \r
                                PDFPreview pdfPreview = new PDFPreview();\r
                                if (pdfPreview.setupPreview(Global.getFileManager().getResDirPath(fileName), "pdf",0)) {\r
-                               // NFC TODO: should this be a 'file://' url like the ones above?\r
                                imageURL = file.fileName() + ".png";\r
                                }\r
                        }\r
@@ -2130,7 +2153,6 @@ public class BrowserWindow extends QWidget {
        // * User chose to save an attachment. Pares out the request *\r
        // * into a guid & file. Save the result. --- DONE FROM downloadAttachment now!!!!!   \r
        // ************************************************************\r
-       // NFC TODO: unused? remove\r
        public void downloadImage(QNetworkRequest request) {\r
                QFileDialog fd = new QFileDialog(this);\r
                fd.setFileMode(FileMode.AnyFile);\r
@@ -2177,7 +2199,11 @@ public class BrowserWindow extends QWidget {
        // *************************************************************\r
        private void removeEncryption(String id, String plainText, boolean permanent, String slot) {\r
                if (!permanent) {\r
-                       plainText = " <en-crypt-temp slot=\""+slot  +"\">" +plainText+"</en-crypt-temp> ";\r
+                       plainText = " <table class=\"en-crypt-temp\" slot=\""\r
+                                       +slot \r
+                                       +"\""\r
+                                       +"border=1 width=100%><tbody><tr><td>"\r
+                                       +plainText+"</td></tr></tbody></table>";\r
                }\r
                \r
                String html = browser.page().mainFrame().toHtml();\r
@@ -2189,10 +2215,12 @@ public class BrowserWindow extends QWidget {
                        endPos = text.indexOf(">", imagePos);\r
                        String tag = text.substring(imagePos-1,endPos);\r
                        if (tag.indexOf("id=\""+id+"\"") > -1) {\r
-                                       text = text.substring(0,imagePos) +plainText+text.substring(endPos+1);\r
-                                                                               \r
-                                       browser.setContent(new QByteArray(text));\r
-                                       contentChanged();\r
+                                       text = text.substring(0,imagePos) +plainText+text.substring(endPos+1);  \r
+                                       QTextCodec codec = QTextCodec.codecForName("UTF-8");\r
+                               QByteArray unicode =  codec.fromUnicode(text);\r
+                                       browser.setContent(unicode);\r
+                                       if (permanent)\r
+                                               contentChanged();\r
                        }\r
                        imagePos = text.indexOf("<img", imagePos+1);\r
                }\r
@@ -2265,7 +2293,7 @@ public class BrowserWindow extends QWidget {
                        +"   var workingNode = window.getSelection().anchorNode.parentNode;"\r
                        +"   while(workingNode != null) { " \r
 //                     +"      window.jambi.printNode(workingNode.nodeName);"\r
-                       +"      if (workingNode.nodeName=='EN-CRYPT-TEMP') window.jambi.forceTextPaste();"\r
+                       +"      if (workingNode.nodeName=='TABLE') { if (workingNode.getAttribute('class').toLowerCase() == 'en-crypt-temp') window.jambi.forceTextPaste(); }"\r
                        +"      if (workingNode.nodeName=='B') window.jambi.boldActive();"\r
                        +"      if (workingNode.nodeName=='I') window.jambi.italicActive();"\r
                        +"      if (workingNode.nodeName=='U') window.jambi.underlineActive();"\r
index 43bf4c9..81ecdfd 100644 (file)
@@ -255,6 +255,7 @@ public class ContentView extends QWebView {
             QKeyEvent ke = (QKeyEvent) event;\r
             if (ke.key() == Qt.Key.Key_Tab.value()) {\r
                        parent.tabPressed();\r
+                       ke.accept();\r
                 return true;\r
             }\r
             if (ke.key() == Qt.Key.Key_Backtab.value()) {\r
diff --git a/src/cx/fbn/nevernote/gui/ExternalBrowse.java b/src/cx/fbn/nevernote/gui/ExternalBrowse.java
new file mode 100644 (file)
index 0000000..2218cd7
--- /dev/null
@@ -0,0 +1,102 @@
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.gui;\r
+\r
+import java.util.List;\r
+\r
+import com.trolltech.qt.gui.QCloseEvent;\r
+import com.trolltech.qt.gui.QMdiSubWindow;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.sql.DatabaseConnection;\r
+\r
+public class ExternalBrowse extends QMdiSubWindow {\r
+       private final DatabaseConnection  conn;\r
+       private final BrowserWindow     browser;\r
+       public Signal4<String, String, Boolean, BrowserWindow> contentsChanged;\r
+       public Signal1<String>  windowClosing;\r
+       boolean noteDirty;\r
+       \r
+       // Constructor\r
+       public ExternalBrowse(DatabaseConnection c) {\r
+               setWindowTitle(tr("NeverNote"));\r
+               conn = c;\r
+               contentsChanged = new Signal4<String, String, Boolean, BrowserWindow>();\r
+               windowClosing = new Signal1<String>();\r
+               browser = new BrowserWindow(conn);\r
+               setWidget(browser);\r
+               noteDirty = false;\r
+               browser.titleLabel.textChanged.connect(this, "titleChanged(String)");\r
+               browser.getBrowser().page().contentsChanged.connect(this, "contentChanged()");\r
+       }\r
+       \r
+       private void contentChanged() {\r
+               noteDirty = true;\r
+               contentsChanged.emit(getBrowserWindow().getNote().getGuid(), getBrowserWindow().getContent(), false, getBrowserWindow());\r
+       }\r
+\r
+       \r
+       @Override\r
+       public void closeEvent(QCloseEvent event) {\r
+               if (noteDirty) \r
+                       contentsChanged.emit(getBrowserWindow().getNote().getGuid(), getBrowserWindow().getContent(), true, getBrowserWindow());\r
+               windowClosing.emit(getBrowserWindow().getNote().getGuid());\r
+       }\r
+       \r
+    public BrowserWindow getBrowserWindow() {\r
+       return browser;\r
+    }\r
+    \r
+    private void titleChanged(String value) {\r
+       setWindowTitle(tr("NeverNote - ") +value);\r
+    }\r
+    \r
+       private void updateTitle(String guid, String title) {\r
+               if (guid.equals(getBrowserWindow().getNote().getGuid())) {\r
+                       getBrowserWindow().loadingData(true);\r
+                       getBrowserWindow().setTitle(title);\r
+                       getBrowserWindow().getNote().setTitle(title);\r
+                       getBrowserWindow().loadingData(false);\r
+               }\r
+       }\r
+       private void updateNotebook(String guid, String notebook) {\r
+               if (guid.equals(getBrowserWindow().getNote().getGuid())) {\r
+                       getBrowserWindow().loadingData(true);\r
+                       getBrowserWindow().setNotebook(notebook);\r
+                       getBrowserWindow().loadingData(false);\r
+               }\r
+       }\r
+       \r
+       private void updateTags(String guid, List<String> tags) {\r
+               if (guid.equals(getBrowserWindow().getNote().getGuid())) {\r
+                       StringBuffer tagLine = new StringBuffer(100);\r
+                       for (int i=0; i<tags.size(); i++) {\r
+                               if (i>0)\r
+                                       tagLine.append(Global.tagDelimeter+" ");\r
+                               tagLine.append(tags.get(i));\r
+                               \r
+                       }\r
+                       getBrowserWindow().loadingData(true);\r
+                       getBrowserWindow().getTagLine().setText(tagLine.toString());\r
+                       getBrowserWindow().loadingData(false);\r
+               }\r
+       }\r
+\r
+}\r
index f3bbbb9..00cb2bf 100644 (file)
@@ -61,6 +61,8 @@ public class MainMenuBar extends QMenuBar {
        public QAction                  editPasteWithoutFormat;         // Paste selected text\r
        public QAction                  editCopy;                                       // Copy selected text;\r
        \r
+       public QAction                  wideListView;                           // View with list on the top\r
+       public QAction                  narrowListView;                         // View with list on the side\r
        public QAction                  thumbnailView;                          // view thumbnails\r
        public QAction                  hideSavedSearches;                      // show/hide saved searches\r
        public QAction                  hideNotebooks;                          // show/hide notebooks\r
@@ -292,6 +294,18 @@ public class MainMenuBar extends QMenuBar {
                hideNotebooks.setChecked(true);\r
                setupShortcut(hideNotebooks, "View_Show_Notebooks");\r
 \r
+               wideListView = new QAction(tr("Wide List View"), this);\r
+               wideListView.setToolTip("Wide List Viwe");\r
+               wideListView.setCheckable(true);\r
+               wideListView.changed.connect(parent, "wideListView()");\r
+               setupShortcut(wideListView, "View_Wide_List");\r
+               \r
+               narrowListView = new QAction(tr("Narrow List View"), this);\r
+               narrowListView.setToolTip("Narrow List View");\r
+               narrowListView.setCheckable(true);\r
+               narrowListView.changed.connect(parent, "narrowListView()");\r
+               setupShortcut(narrowListView, "View_Narrow_List");\r
+               \r
                thumbnailView = new QAction(tr("Preview"), this);\r
                thumbnailView.setToolTip("Preview Notes");\r
                thumbnailView.triggered.connect(parent, "thumbnailView()");\r
@@ -588,6 +602,8 @@ public class MainMenuBar extends QMenuBar {
                viewMenu = addMenu(tr("&View"));\r
                viewMenu.addAction(noteAttributes);\r
                viewMenu.addSeparator();\r
+               viewMenu.addAction(wideListView);\r
+               viewMenu.addAction(narrowListView);\r
                viewMenu.addAction(thumbnailView);\r
                viewMenu.addSeparator();\r
                viewMenu.addAction(hideNoteList);\r
index 3090919..3961b4b 100644 (file)
@@ -9,8 +9,10 @@ import com.evernote.edam.type.Note;
 import com.trolltech.qt.core.QDateTime;\r
 import com.trolltech.qt.core.QModelIndex;\r
 import com.trolltech.qt.core.Qt;\r
+import com.trolltech.qt.core.Qt.AspectRatioMode;\r
 import com.trolltech.qt.gui.QAbstractTableModel;\r
 import com.trolltech.qt.gui.QColor;\r
+import com.trolltech.qt.gui.QPixmap;\r
 \r
 import cx.fbn.nevernote.Global;\r
 import cx.fbn.nevernote.filters.NoteSortFilterProxyModel;\r
@@ -75,6 +77,12 @@ public class NoteTableModel extends QAbstractTableModel {
         case Qt.ItemDataRole.DisplayRole: {\r
             return valueAt(index.row(), index.column());\r
         }\r
+        case Qt.ItemDataRole.DecorationRole: {\r
+               if (index.column() == Global.noteTableThumbnailPosition)\r
+                       return valueAt(index.row(), index.column());\r
+               else\r
+                       return null;\r
+        }\r
         case Qt.ItemDataRole.BackgroundRole: {\r
                String guid = (String)valueAt(index.row(), Global.noteTableGuidPosition);\r
                QColor backgroundColor = new QColor(QColor.white);\r
@@ -155,6 +163,18 @@ public class NoteTableModel extends QAbstractTableModel {
                                        return listManager.getNotebookIndex().get(i).getName();\r
                        }\r
                }\r
+               if (col == Global.noteTableGuidPosition) {\r
+                       return note.getGuid();\r
+               }\r
+               if (col == Global.noteTableThumbnailPosition) {\r
+                       if (listManager.getThumbnails().get(note.getGuid()) == null)\r
+                               return null;\r
+                       if (Global.listView)\r
+                               return QPixmap.fromImage(listManager.getThumbnails().get(note.getGuid())).scaled(Global.smallThumbnailSize, AspectRatioMode.KeepAspectRatio);\r
+                       else\r
+                               return QPixmap.fromImage(listManager.getThumbnails().get(note.getGuid())).scaled(Global.largeThumbnailSize, AspectRatioMode.KeepAspectRatio);\r
+                               \r
+               }\r
                return "";\r
        }\r
        \r
index bb53f91..32bcc54 100644 (file)
@@ -66,6 +66,7 @@ public class NotebookTreeWidget extends QTreeWidget {
        \r
        public NotebookTreeWidget() {\r
                noteSignal = new NoteSignal();\r
+               setProperty("hideTree", true);\r
                List<String> labels = new ArrayList<String>();\r
                labels.add("Notebooks");\r
                labels.add("");\r
index 768c420..d508426 100644 (file)
@@ -41,6 +41,7 @@ public class SavedSearchTreeWidget extends QTreeWidget {
        public SavedSearchTreeWidget() {\r
 //             setAcceptDrops(true);\r
 //             setDragEnabled(true);\r
+               setProperty("hideTree", true);\r
                setAcceptDrops(false);\r
                setDragEnabled(false);\r
 //             setDragDropMode(QAbstractItemView.DragDropMode.DragDrop);\r
index 3b1d9bb..900eea8 100644 (file)
@@ -89,6 +89,8 @@ public class TableView extends QTableView {
                header.tagsAction.toggled.connect(this, "toggleTags(Boolean)");\r
                header.notebookAction.toggled.connect(this, "toggleNotebook(Boolean)");\r
                header.synchronizedAction.toggled.connect(this, "toggleSynchronized(Boolean)");\r
+               header.guidAction.toggled.connect(this, "toggleGuid(Boolean)");\r
+               header.thumbnailAction.toggled.connect(this, "toggleThumbnail(Boolean)");\r
                \r
                noteSignal = new NoteSignal();\r
                setAcceptDrops(true);\r
@@ -108,13 +110,13 @@ public class TableView extends QTableView {
         runner.getNoteTableModel().setHeaderData(Global.noteTableSourceUrlPosition, Qt.Orientation.Horizontal, tr("Source Url"), Qt.ItemDataRole.DisplayRole);\r
         runner.getNoteTableModel().setHeaderData(Global.noteTableSubjectDatePosition, Qt.Orientation.Horizontal, tr("Subject Date"), Qt.ItemDataRole.DisplayRole);\r
         runner.getNoteTableModel().setHeaderData(Global.noteTableSynchronizedPosition, Qt.Orientation.Horizontal, tr("Synchronized"), Qt.ItemDataRole.DisplayRole);\r
+        runner.getNoteTableModel().setHeaderData(Global.noteTableThumbnailPosition, Qt.Orientation.Horizontal, tr("Thumbnail"), Qt.ItemDataRole.DisplayRole);\r
         header.sortIndicatorChanged.connect(this, "resetViewport()");\r
        \r
         proxyModel = new NoteSortFilterProxyModel(this);\r
         proxyModel.setSourceModel(runner.getNoteTableModel());\r
         setAlternatingRowColors(false);\r
         setModel(proxyModel);\r
-//        setModel(runner.getNoteTableModel());\r
         runner.getNoteTableModel().setSortProxyModel(proxyModel);\r
                \r
         setSortingEnabled(true);\r
@@ -156,7 +158,13 @@ public class TableView extends QTableView {
                proxyModel.clear();\r
                setSortingEnabled(false);\r
                QFontMetrics f = QApplication.fontMetrics();\r
-               verticalHeader().setDefaultSectionSize(f.height());\r
+               if (Global.listView) {\r
+                       if (!Global.isColumnVisible("thumbnail"))\r
+                               verticalHeader().setDefaultSectionSize(f.height());\r
+                       else\r
+                               verticalHeader().setDefaultSectionSize(Global.smallThumbnailSize.height());\r
+               } else\r
+                       verticalHeader().setDefaultSectionSize(Global.largeThumbnailSize.height());\r
                for (int i=0; i<runner.getNoteIndex().size(); i++) {\r
                        if (Global.showDeleted == true && !runner.getNoteIndex().get(i).isActive())\r
                                proxyModel.addGuid(runner.getNoteIndex().get(i).getGuid());\r
@@ -247,7 +255,6 @@ public class TableView extends QTableView {
        public void insertRow(Note tempNote, boolean newNote, int row) {\r
                if (newNote)\r
                        proxyModel.addGuid(tempNote.getGuid());\r
-               \r
                if (row > runner.getNoteTableModel().rowCount())\r
                        runner.getNoteTableModel().insertRow(0);\r
                \r
@@ -255,12 +262,12 @@ public class TableView extends QTableView {
                        row  = runner.getNoteTableModel().rowCount();\r
                        runner.getNoteTableModel().insertRow(row);\r
                }\r
-               \r
                if (newNote) {\r
                        QFontMetrics f = QApplication.fontMetrics();\r
                        fontHeight = f.height();\r
-                       for (int i=0; i<runner.getNoteTableModel().rowCount(); i++)\r
+                       for (int i=0; i<runner.getNoteTableModel().rowCount(); i++) {\r
                                setRowHeight(i, fontHeight);\r
+                       }\r
                }\r
        }\r
        protected boolean filterAcceptsRow(int sourceRow, QModelIndex sourceParent) {\r
@@ -424,33 +431,6 @@ public class TableView extends QTableView {
        public int getColumnWidth(int col) {\r
                return columnWidth(col);\r
        }\r
-\r
-/*\r
-    @Override\r
-       public void scrollTo(final QModelIndex index, ScrollHint hint) {\r
-        QRect area = viewport().rect();\r
-        QRect rect = visualRect(index);\r
-\r
-        if (rect.top() < area.top())\r
-            verticalScrollBar().setValue(\r
-                verticalScrollBar().value() + rect.top() - area.top());\r
-        else if (rect.bottom() > area.bottom())\r
-            verticalScrollBar().setValue(\r
-                verticalScrollBar().value() + Math.min(\r
-                    rect.bottom() - area.bottom(), rect.top() - area.top()));\r
-        update();\r
-    }\r
-    \r
-    @Override\r
-       protected void updateGeometries() {\r
-        verticalScrollBar().setPageStep(viewport().height());\r
-        verticalScrollBar().setRange(0, Math.max(0, viewport().height()));\r
-    }\r
-    @Override\r
-    protected int verticalOffset() {\r
-        return verticalScrollBar().value();\r
-    }\r
-*/\r
        \r
        public void toggleSubjectDate(Boolean toggle) {\r
                Global.saveColumnVisible("dateSubject", toggle);\r
@@ -492,4 +472,23 @@ public class TableView extends QTableView {
                Global.saveColumnVisible("synchronized", toggle);\r
                setColumnHidden(Global.noteTableSynchronizedPosition, !toggle);\r
        }\r
+       public void toggleGuid(Boolean toggle) {\r
+               Global.saveColumnVisible("guid", toggle);\r
+               setColumnHidden(Global.noteTableGuidPosition, !toggle);\r
+       }       \r
+       public void toggleThumbnail(Boolean toggle) {\r
+               Global.saveColumnVisible("thumbnail", toggle);\r
+               int size;\r
+               if (!toggle) {\r
+                       QFontMetrics f = QApplication.fontMetrics();\r
+                       size = f.height();\r
+                       verticalHeader().setDefaultSectionSize(f.height());\r
+               } else\r
+                       size = Global.smallThumbnailSize.height();\r
+               for (int i=0; i<runner.getNoteTableModel().rowCount(); i++) {\r
+                       setRowHeight(i, size);\r
+               }\r
+                       \r
+               setColumnHidden(Global.noteTableThumbnailPosition, !toggle);\r
+       }\r
 }\r
index 0e48a85..d50195b 100644 (file)
@@ -19,6 +19,8 @@ public class TableViewHeader extends QHeaderView {
        public QAction synchronizedAction;\r
        public QAction authorAction;\r
        public QAction urlAction;\r
+       public QAction thumbnailAction;\r
+       public QAction guidAction;\r
        \r
 \r
        public TableViewHeader(Orientation orientation, QWidget parent) {\r
@@ -77,6 +79,18 @@ public class TableViewHeader extends QHeaderView {
                urlAction.setChecked(Global.isColumnVisible("sourceUrl"));\r
                contextMenu.addAction(urlAction);\r
                \r
+               thumbnailAction = new QAction(this);\r
+               thumbnailAction.setText(tr("Thumbnail"));\r
+               thumbnailAction.setCheckable(true);\r
+               thumbnailAction.setChecked(Global.isColumnVisible("thumbnail"));\r
+//             contextMenu.addAction(thumbnailAction);\r
+               \r
+               guidAction = new QAction(this);\r
+               guidAction.setText(tr("Guid"));\r
+               guidAction.setCheckable(true);\r
+               guidAction.setChecked(Global.isColumnVisible("guid"));\r
+//             contextMenu.addAction(guidAction);\r
+               \r
        }\r
        \r
        @Override\r
index 7585ce6..1dda121 100644 (file)
@@ -1,7 +1,6 @@
 package cx.fbn.nevernote.gui;\r
 \r
-import com.trolltech.qt.core.QByteArray;\r
-import com.trolltech.qt.core.QFile;\r
+import com.trolltech.qt.core.QBuffer;\r
 import com.trolltech.qt.core.QIODevice;\r
 import com.trolltech.qt.core.QObject;\r
 import com.trolltech.qt.core.QSize;\r
@@ -12,7 +11,8 @@ import com.trolltech.qt.gui.QImage;
 import com.trolltech.qt.gui.QPainter;\r
 import com.trolltech.qt.webkit.QWebPage;\r
 \r
-import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.sql.DatabaseConnection;\r
+import cx.fbn.nevernote.utilities.ListManager;\r
 \r
 public class Thumbnailer extends QObject {\r
     public QWebPage page;\r
@@ -20,25 +20,29 @@ public class Thumbnailer extends QObject {
     public QPainter painter;\r
     public Signal1<String> finished;\r
     public String guid;\r
+    private final DatabaseConnection conn;\r
+    private final QSize size;\r
+    public boolean idle = false;\r
+    private final ListManager listManager;\r
     \r
-    public Thumbnailer(String g, QSize s)\r
+    public Thumbnailer(DatabaseConnection conn, ListManager l)\r
     {\r
-       guid = g;\r
+       this.conn = conn;\r
        finished = new Signal1<String>();\r
        page = new QWebPage();\r
+       listManager = l;\r
         painter = new QPainter();\r
-\r
+        size = new QSize(1024,768);\r
        page.mainFrame().setScrollBarPolicy(Orientation.Horizontal, ScrollBarPolicy.ScrollBarAlwaysOff);\r
        page.mainFrame().setScrollBarPolicy(Orientation.Vertical, ScrollBarPolicy.ScrollBarAlwaysOff);\r
        page.loadFinished.connect(this, "loadFinished(Boolean)");\r
     }\r
     \r
-    public void setContent(String content) {\r
-        QFile file = new QFile(Global.getFileManager().getResDirPath("thumbnail-" + guid + ".html"));\r
-       file.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));\r
-       file.write(new QByteArray(content));\r
-       file.close(); \r
-       page.mainFrame().load(new QUrl(QUrl.fromLocalFile(file.fileName()).toString()));\r
+    public void loadContent(String guid, String fileName) {\r
+       idle = false;\r
+       this.guid = guid;\r
+       page.setViewportSize(size);\r
+       page.mainFrame().load(new QUrl(QUrl.fromLocalFile(fileName)));\r
     }\r
     \r
 \r
@@ -63,7 +67,19 @@ public class Thumbnailer extends QObject {
         page.mainFrame().render(painter);             //<<<< THIS CAN LOCKUP if height too big!!!!\r
         painter.end();\r
         \r
-        image.save(Global.getFileManager().getResDirPath("thumbnail-" + guid + ".png"));\r
-        finished.emit(guid);\r
+       image = image.scaled(new QSize(100,100));\r
+        \r
+        QBuffer buffer = new QBuffer();\r
+        buffer.open(QIODevice.OpenModeFlag.ReadWrite);\r
+        image.save(buffer);\r
+        conn.getNoteTable().setThumbnail(guid, buffer.data());\r
+        conn.getNoteTable().setThumbnailNeeded(guid, false);\r
+        \r
+        listManager.getThumbnails().remove(guid);\r
+               listManager.getThumbnails().put(guid, image);\r
+               finished.emit(guid); \r
+        \r
+        idle = true;\r
+        return;\r
     }\r
 }\r
index c05d923..adc2d98 100644 (file)
@@ -40,6 +40,9 @@ public class TrashTreeWidget extends QTreeWidget {
        private QAction emptyAction;\r
        private QTreeWidgetItem trashItem;\r
        private Integer trashCount;     \r
+       private final String iconPath;\r
+       private final QIcon trashIcon;\r
+       private final QIcon trashFullIcon;\r
        \r
        public void setEmptyAction(QAction a) {\r
                emptyAction = a;\r
@@ -48,6 +51,10 @@ public class TrashTreeWidget extends QTreeWidget {
        \r
        public TrashTreeWidget() {\r
        trashCount =  0;\r
+       setProperty("hideTree", true);\r
+       iconPath = new String("classpath:cx/fbn/nevernote/icons/");\r
+        trashIcon = new QIcon(iconPath+"trash.png");\r
+        trashFullIcon = new QIcon(iconPath+"trash-full.png");\r
        }\r
        \r
        public void updateCounts(Integer cnt) {\r
@@ -61,16 +68,16 @@ public class TrashTreeWidget extends QTreeWidget {
                header().resizeSection(1, 0);\r
                if (trashCount > 0) {\r
                        trashItem.setForeground(0, black);                      \r
-                       trashItem.setForeground(1, black);                      \r
+                       trashItem.setForeground(1, black);\r
+                       trashItem.setIcon(0, trashFullIcon);\r
                } else {\r
+                       trashItem.setIcon(0,trashIcon);\r
                        trashItem.setForeground(0, gray);                       \r
                        trashItem.setForeground(1, gray);                                               \r
                }\r
        }\r
        \r
        public void load() {\r
-       String iconPath = new String("classpath:cx/fbn/nevernote/icons/");\r
-        QIcon trashIcon = new QIcon(iconPath+"trash.png");\r
         trashItem = new QTreeWidgetItem();\r
         trashItem.setIcon(0, trashIcon);\r
         trashItem.setText(0, "Trash");\r
index ed89ed3..e38a7ca 100644 (file)
@@ -45,6 +45,7 @@ public class NoteSignal extends QSignalEmitter {
        public Signal1<Integer>                         titleColorChanged = new Signal1<Integer>();\r
        public Signal2<Note, Boolean>           noteDownloaded = new Signal2<Note, Boolean>();\r
        public Signal2<String, String>          noteSaveRunnerError = new Signal2<String, String>();\r
+       public Signal2<String, String>          thumbnailPageReady = new Signal2<String,String>();\r
 }\r
 \r
 \r
index 0269fdb..6298178 100644 (file)
@@ -482,8 +482,8 @@ public class NoteTable {
        // Update a note's title\r
        public void updateNoteContent(String guid, String content) {\r
                NSqlQuery query = new NSqlQuery(db.getConnection());\r
-               boolean check = query.prepare("Update Note set content=:content, updated=CURRENT_TIMESTAMP(), isDirty=true, indexNeeded=true " +\r
-                               " where guid=:guid");\r
+               boolean check = query.prepare("Update Note set content=:content, updated=CURRENT_TIMESTAMP(), isDirty=true, indexNeeded=true, " +\r
+                               " thumbnailneeded=true where guid=:guid");\r
                if (!check) {\r
                        logger.log(logger.EXTREME, "Update note content sql prepare has failed.");\r
                        logger.log(logger.MEDIUM, query.lastError());\r
@@ -1108,12 +1108,38 @@ public class NoteTable {
                if (!check) \r
                        logger.log(logger.EXTREME, "Note SQL get thumbail failed: " +query.lastError().toString());\r
                // Get a list of the notes\r
-               if (query.next()) \r
-                       if (query.getBlob(0) != null)\r
-                               return new QByteArray(query.getBlob(0)); \r
+               if (query.next())  {\r
+                       try {\r
+                               if (query.getBlob(0) != null) {\r
+                                       return new QByteArray(query.getBlob(0)); \r
+                               }\r
+                       } catch (java.lang.IllegalArgumentException e) {\r
+                               return null;\r
+                       }\r
+               }\r
                return null;\r
        }\r
-       \r
+       // Get a list of notes that need thumbnails\r
+       // Is a thumbail needed for this guid?\r
+       public List<String> findThumbnailsNeeded() {\r
+               \r
+               boolean check;\r
+        NSqlQuery query = new NSqlQuery(db.getConnection());\r
+                                       \r
+               check = query.prepare("select guid from note where thumbnailneeded = true limit 100");\r
+               check = query.exec();\r
+               if (!check) \r
+                       logger.log(logger.EXTREME, "Note SQL findThumbnailsNeeded query failed: " +query.lastError().toString());\r
+               \r
+\r
+               // Get a list of the notes\r
+               List<String> values = new ArrayList<String>();\r
+               while (query.next()) {\r
+                       values.add(query.valueString(0)); \r
+               }\r
+\r
+               return values;  \r
+       }\r
        \r
        // Update a note content's hash.  This happens if a resource is edited outside of NN\r
        public void updateResourceContentHash(String guid, String oldHash, String newHash) {\r
@@ -1132,7 +1158,7 @@ public class NoteTable {
                                                 newSegment +\r
                                                 n.getContent().substring(endPos);\r
                                NSqlQuery query = new NSqlQuery(db.getConnection());\r
-                               query.prepare("update note set isdirty=true, content=:content where guid=:guid");\r
+                               query.prepare("update note set isdirty=true, thumbnailneeded=true, content=:content where guid=:guid");\r
                                query.bindValue(":content", content);\r
                                query.bindValue(":guid", n.getGuid());\r
                                query.exec();\r
index a0b9aee..15742b5 100644 (file)
@@ -376,7 +376,6 @@ public class NotebookTable {
        }\r
        // Reset the dirty flag.  Typically done after a sync.\r
        public void  resetDirtyFlag(String guid) {\r
-               \r
                NSqlQuery query = new NSqlQuery(db.getConnection());\r
                \r
                query.prepare("Update notebook set isdirty='false' where guid=:guid");\r
@@ -384,7 +383,18 @@ public class NotebookTable {
                if (!query.exec())\r
                        logger.log(logger.EXTREME, "Error resetting notebook dirty field.");\r
        }\r
-       \r
+       // Set the default notebook\r
+       public void setDefaultNotebook(String guid) {\r
+               NSqlQuery query = new NSqlQuery(db.getConnection());\r
+               \r
+               query.prepare("Update notebook set defaultNotebook=false");\r
+               if (!query.exec())\r
+                       logger.log(logger.EXTREME, "Error removing default notebook.");\r
+               query.prepare("Update notebook set defaultNotebook=true where guid = :guid");\r
+               query.bindValue(":guid", guid);\r
+               if (!query.exec())\r
+                       logger.log(logger.EXTREME, "Error setting default notebook.");\r
+       }\r
        \r
        \r
 \r
index 1c02862..a8cab67 100644 (file)
@@ -50,7 +50,7 @@ public class IndexRunner extends QObject implements Runnable {
        private int                                                     indexType;\r
        public final int                                        CONTENT=1; \r
        public final int                                        RESOURCE=2;\r
-       private boolean                                         keepRunning;\r
+       public boolean                                          keepRunning;\r
        private final QDomDocument                      doc;\r
        private static String                           regex = Global.getWordRegex();\r
        private final DatabaseConnection        conn;\r
index 418c211..4569e04 100644 (file)
@@ -37,7 +37,7 @@ import cx.fbn.nevernote.utilities.Pair;
 public class SaveRunner extends QObject implements Runnable {\r
         \r
        private final ApplicationLogger         logger;\r
-       private volatile boolean                        keepRunning;\r
+       public volatile boolean                         keepRunning;\r
        public QMutex                                           threadLock;\r
        private final DatabaseConnection        conn;\r
        private boolean                                         idle;\r
index bb90835..89f9271 100644 (file)
@@ -361,7 +361,7 @@ public class SyncRunner extends QObject implements Runnable {
                \r
                List<DeletedItemRecord> expunged = conn.getDeletedTable().getAllDeleted();\r
                boolean error = false;\r
-               for (int i=0; i<expunged.size(); i++) {\r
+               for (int i=0; i<expunged.size() && keepRunning; i++) {\r
                        \r
                        if (authRefreshNeeded)\r
                                refreshConnection();\r
diff --git a/src/cx/fbn/nevernote/threads/ThumbnailRunner.java b/src/cx/fbn/nevernote/threads/ThumbnailRunner.java
new file mode 100644 (file)
index 0000000..f8d9c43
--- /dev/null
@@ -0,0 +1,152 @@
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.threads;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+import java.util.concurrent.LinkedBlockingQueue;\r
+\r
+import com.evernote.edam.type.Note;\r
+import com.trolltech.qt.core.QByteArray;\r
+import com.trolltech.qt.core.QFile;\r
+import com.trolltech.qt.core.QIODevice.OpenModeFlag;\r
+import com.trolltech.qt.core.QObject;\r
+import com.trolltech.qt.core.QTemporaryFile;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.signals.NoteSignal;\r
+import cx.fbn.nevernote.sql.DatabaseConnection;\r
+import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+import cx.fbn.nevernote.xml.NoteFormatter;\r
+\r
+public class ThumbnailRunner extends QObject implements Runnable {\r
+       \r
+       private final ApplicationLogger                         logger;\r
+       private String                                                          guid;\r
+       public  NoteSignal                                                      noteSignal;\r
+       private boolean                                                         keepRunning;\r
+       private final DatabaseConnection                        conn;\r
+       private volatile LinkedBlockingQueue<String> workQueue;\r
+       private static int                                                      MAX_QUEUED_WAITING = 1000;\r
+\r
+\r
+\r
+       public ThumbnailRunner(String logname, String u, String uid, String pswd, String cpswd) {\r
+               logger = new ApplicationLogger(logname);\r
+               conn = new DatabaseConnection(logger, u, uid, pswd, cpswd);\r
+               noteSignal = new NoteSignal();\r
+               guid = null;\r
+               keepRunning = true;\r
+               workQueue=new LinkedBlockingQueue<String>(MAX_QUEUED_WAITING);  \r
+       }\r
+       \r
+       \r
+       @Override\r
+       public void run() {\r
+               thread().setPriority(Thread.MIN_PRIORITY);\r
+               \r
+               logger.log(logger.MEDIUM, "Starting thumbnail thread ");\r
+               while (keepRunning) {\r
+                       try {\r
+                               String work = workQueue.take();\r
+                               if (work.startsWith("GENERATE")) {\r
+                                       work = work.replace("GENERATE ", "");\r
+                                       guid = work;\r
+                                       generateThumbnail();\r
+                               }\r
+                               if (work.startsWith("SCAN")) {\r
+                                       scanDatabase();\r
+                               }\r
+                               if (work.startsWith("STOP")) {\r
+                                       logger.log(logger.MEDIUM, "Stopping thumbail thread");\r
+                                       keepRunning = false;\r
+                               }\r
+                       } catch (InterruptedException e) {\r
+                               // TODO Auto-generated catch block\r
+                               e.printStackTrace();\r
+                       }\r
+               }\r
+               conn.dbShutdown();\r
+       }\r
+       \r
+       \r
+       private void scanDatabase() {\r
+               // If there is already work in the queue, that takes priority\r
+               logger.log(logger.HIGH, "Scanning database for notes needing thumbnail");\r
+               if (workQueue.size() > 0)\r
+                       return;\r
+               \r
+               // Find a few records that need thumbnails\r
+               List<String> guids = conn.getNoteTable().findThumbnailsNeeded();\r
+               logger.log(logger.HIGH, guids.size() +" records returned");\r
+               for (int i=0; i<guids.size() && keepRunning; i++) {\r
+                       guid = guids.get(i);\r
+                       logger.log(logger.HIGH, "Working on:" +guids.get(i));\r
+                       generateThumbnail();\r
+               }\r
+               logger.log(logger.HIGH, "Scan completed");\r
+       }\r
+\r
+               \r
+       public synchronized boolean addWork(String request) {\r
+               if (workQueue.size() == 0) {\r
+                       workQueue.offer(request);\r
+                       return true;\r
+               }\r
+               return false;\r
+       }\r
+       \r
+       public synchronized int getWorkQueueSize() {\r
+               return workQueue.size();\r
+       }\r
+       \r
+       private void generateThumbnail() {\r
+               QByteArray js = new QByteArray();\r
+               logger.log(logger.HIGH, "Starting thumbnail for " +guid);\r
+               ArrayList<QTemporaryFile> tempFiles = new ArrayList<QTemporaryFile>();\r
+               Note currentNote = conn.getNoteTable().getNote(guid,true,true,false,true,false);\r
+               NoteFormatter formatter = new NoteFormatter(logger, conn, tempFiles);\r
+               currentNote = conn.getNoteTable().getNote(guid, true, true, false, true, false);\r
+               formatter.setNote(currentNote, true);\r
+               formatter.setHighlight(null);\r
+               js.append("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">");               \r
+               js.append("<style type=\"text/css\">.en-crypt-temp { border-collapse:collapse; border-style:solid; border-color:blue; padding:0.0mm 0.0mm 0.0mm 0.0mm; }</style>");\r
+               js.append("<style type=\"text/css\">en-hilight { background-color: rgb(255,255,0) }</style>");\r
+               js.append("<style> img { max-width:100%; }</style>");\r
+               js.append("<style type=\"text/css\">en-spell { text-decoration: none; border-bottom: dotted 1px #cc0000; }</style>");\r
+               js.append("</head>");\r
+               js.append(formatter.rebuildNoteHTML());\r
+               js.append("</HTML>");\r
+               js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml.dtd'>", "");\r
+               js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml2.dtd'>", "");\r
+               js.replace("<?xml version='1.0' encoding='UTF-8'?>", "");\r
+               String fileName = Global.getFileManager().getResDirPath("thumbnail-" + guid + ".html");\r
+               QFile tFile = new QFile(fileName);\r
+               tFile.open(OpenModeFlag.WriteOnly);\r
+               tFile.write(js);\r
+               tFile.close();\r
+               logger.log(logger.HIGH, "Thumbnail file ready");\r
+               noteSignal.thumbnailPageReady.emit(guid, fileName);\r
+       }\r
+               \r
+       \r
+\r
+\r
+}\r
index 90c3fcc..4399b7e 100644 (file)
@@ -34,6 +34,7 @@ import com.evernote.edam.type.SavedSearch;
 import com.evernote.edam.type.Tag;\r
 import com.trolltech.qt.QThread;\r
 import com.trolltech.qt.core.QDateTime;\r
+import com.trolltech.qt.gui.QImage;\r
 import com.trolltech.qt.sql.QSqlQuery;\r
 import com.trolltech.qt.xml.QDomAttr;\r
 import com.trolltech.qt.xml.QDomDocument;\r
@@ -97,8 +98,10 @@ public class ListManager  {
        public NotebookSignal                   notebookSignal;\r
        private int                                             trashCount;\r
     public SaveRunner                          saveRunner;                                     // Thread used to save content.  Used because the xml conversion is slowwwww\r
-    QThread                            saveThread;\r
+    QThread                                                    saveThread;\r
        \r
+    private final HashMap<String,QImage> thumbnailList;\r
+    \r
        // Constructor\r
        public ListManager(DatabaseConnection d, ApplicationLogger l) {\r
                conn = d;\r
@@ -148,7 +151,18 @@ public class ListManager  {
                saveRunner = new SaveRunner("saveRunner.log", Global.getDatabaseUrl(), Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);\r
                saveThread = new QThread(saveRunner, "Save Runner Thread");\r
                saveThread.start();\r
-\r
+               \r
+               thumbnailList = new HashMap<String, QImage>();\r
+/*             for (int i=0; i<getMasterNoteIndex().size(); i++) {\r
+                       QImage img = new QImage();\r
+                       QByteArray dbImage = conn.getNoteTable().getThumbnail(getMasterNoteIndex().get(i).getGuid());\r
+                       if (dbImage != null) {\r
+                               img.loadFromData(dbImage);\r
+                               img.scaled(new QSize(400,400));\r
+                               thumbnailList.put(getMasterNoteIndex().get(i).getGuid(), img);\r
+                       }\r
+               }\r
+*/\r
                loadNoteTitleColors();\r
                                \r
        }\r
@@ -382,7 +396,10 @@ public class ListManager  {
        public List<Note> getMasterNoteIndex() {\r
                return noteModel.getMasterNoteIndex();\r
        }\r
-       \r
+       // Thumbnails\r
+       public HashMap<String, QImage> getThumbnails() {\r
+               return thumbnailList;\r
+       }\r
     //***************************************************************\r
     //***************************************************************\r
     //** These functions deal with setting & retrieving filters\r
@@ -971,7 +988,9 @@ public class ListManager  {
                return false;\r
        }\r
 \r
-       \r
+       public void setNoteSynchronized(String guid, boolean value) {\r
+               getNoteTableModel().updateNoteSyncStatus(guid, value);\r
+       }\r
        \r
        public void updateNoteTitleColor(String guid, Integer color) {\r
                noteModel.updateNoteTitleColor(guid, color);\r
index 15f3e90..47e8aa6 100644 (file)
@@ -65,12 +65,18 @@ public class ImportData {
        private String                                          notebookGuid;\r
        public final boolean                            importTags = false;\r
        public final boolean                            importNotebooks = false;\r
+       private final HashMap<String,String>            tagMap;\r
+       private final HashMap<String,String>            noteMap;\r
+       private final HashMap<String,String>            notebookMap;\r
        \r
        public ImportData(DatabaseConnection c, boolean full) {\r
                logger = new ApplicationLogger("import.log");\r
                backup = full;\r
                conn = c;\r
                titleColors = new HashMap<String,Integer>();\r
+               notebookMap = new HashMap<String,String>();\r
+               tagMap = new HashMap<String,String>();\r
+               noteMap = new HashMap<String,String>();\r
        }\r
        \r
        public void importData(String f) {\r
@@ -182,15 +188,18 @@ public class ImportData {
                boolean atEnd = false;\r
                while(!atEnd) {\r
                        if (reader.isStartElement()) {\r
-                               if (reader.name().equalsIgnoreCase("Guid")) \r
+                               if (reader.name().equalsIgnoreCase("Guid")) \r
                                        note.setGuid(textValue());\r
-                               if (!backup) {\r
-                                       Random random1 = new Random();\r
-                                       String newGuid = "IMP" +new Integer(random1.nextInt(1000)).toString();\r
-                                       newGuid = newGuid+"-"+new Integer(random1.nextInt(1000)).toString();\r
-                                       newGuid = newGuid+"-"+new Integer(random1.nextInt(1000)).toString();\r
-                                       newGuid = newGuid+"-"+new Integer(random1.nextInt(1000)).toString();\r
-                                       note.setGuid(newGuid);\r
+                                       if (!backup) {\r
+                                               Random random1 = new Random();\r
+                                               String newGuid = "IMP" +new Integer(random1.nextInt(1000)).toString();\r
+                                               newGuid = newGuid+"-"+new Integer(random1.nextInt(1000)).toString();\r
+                                               newGuid = newGuid+"-"+new Integer(random1.nextInt(1000)).toString();\r
+                                               newGuid = newGuid+"-"+new Integer(random1.nextInt(1000)).toString();\r
+                                               noteMap.put(note.getGuid(), newGuid);\r
+                                               note.setGuid(newGuid);\r
+                                       } else \r
+                                               noteMap.put(note.getGuid(), note.getGuid());\r
                                }\r
                                if (reader.name().equalsIgnoreCase("UpdateSequenceNumber")) \r
                                        note.setUpdateSequenceNum(intValue());\r
@@ -246,7 +255,7 @@ public class ImportData {
                                        resource.setGuid(newGuid);\r
                                }\r
                                if (reader.name().equalsIgnoreCase("NoteGuid")) \r
-                                       resource.setNoteGuid(textValue());\r
+                                       resource.setNoteGuid(noteMap.get(textValue()));\r
                                if (reader.name().equalsIgnoreCase("UpdateSequenceNumber")) \r
                                        resource.setUpdateSequenceNum(intValue());\r
                                if (reader.name().equalsIgnoreCase("Active")) \r
diff --git a/src/cx/fbn/nevernote/xml/NoteFormatter.java b/src/cx/fbn/nevernote/xml/NoteFormatter.java
new file mode 100644 (file)
index 0000000..0ddf904
--- /dev/null
@@ -0,0 +1,432 @@
+package cx.fbn.nevernote.xml;\r
+\r
+import java.io.File;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.Note;\r
+import com.evernote.edam.type.Resource;\r
+import com.trolltech.qt.core.QByteArray;\r
+import com.trolltech.qt.core.QDataStream;\r
+import com.trolltech.qt.core.QFile;\r
+import com.trolltech.qt.core.QIODevice;\r
+import com.trolltech.qt.core.QTemporaryFile;\r
+import com.trolltech.qt.core.QUrl;\r
+import com.trolltech.qt.xml.QDomAttr;\r
+import com.trolltech.qt.xml.QDomDocument;\r
+import com.trolltech.qt.xml.QDomElement;\r
+import com.trolltech.qt.xml.QDomNodeList;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.config.FileManager;\r
+import cx.fbn.nevernote.filters.EnSearch;\r
+import cx.fbn.nevernote.gui.PDFPreview;\r
+import cx.fbn.nevernote.sql.DatabaseConnection;\r
+import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+\r
+public class NoteFormatter {\r
+\r
+       private final ApplicationLogger logger;\r
+       private final DatabaseConnection conn;\r
+       public boolean resourceError = false;\r
+       public boolean readOnly = false;\r
+       public boolean addHighlight = true;\r
+       private Note currentNote;\r
+       private String currentNoteGuid;\r
+       private boolean pdfPreview;\r
+       ArrayList<QTemporaryFile> tempFiles;\r
+       private EnSearch enSearch;\r
+       private boolean noteHistory;\r
+       \r
+       public NoteFormatter(ApplicationLogger logger, DatabaseConnection conn, List<QTemporaryFile> tempFiles2) {\r
+               this.logger = logger;\r
+               this.conn = conn;\r
+               noteHistory = false;\r
+       }\r
+       \r
+       \r
+       public void setNote(Note note, boolean pdfPreview) {\r
+               currentNote = note;\r
+               this.pdfPreview = pdfPreview;\r
+               currentNoteGuid = note.getGuid();\r
+               readOnly = false;\r
+               resourceError = false;\r
+       }\r
+       \r
+       public void setHighlight(EnSearch search) {\r
+               if (search==null || search.hilightWords == null ||search.hilightWords.size() == 0) {\r
+                       enSearch = null;\r
+                       addHighlight = false;\r
+               } else {\r
+                       enSearch = search;\r
+                       addHighlight = true;\r
+               }\r
+       }\r
+       \r
+       // Set if we are coming here through note histary.  It triggers longer file names to avoid conflicts\r
+       public void setNoteHistory(boolean value) {\r
+               noteHistory = value;\r
+       }\r
+       \r
+       // Rebuild the note HTML to something usable\r
+       public String rebuildNoteHTML() {\r
+               logger.log(logger.HIGH, "Entering NeverNote.rebuildNoteHTML");\r
+               logger.log(logger.EXTREME, "Note guid: " +currentNoteGuid);\r
+               logger.log(logger.EXTREME, "Note Text:" +currentNote);\r
+               QDomDocument doc = new QDomDocument();\r
+               QDomDocument.Result result = doc.setContent(currentNote.getContent());\r
+               if (!result.success) {\r
+                       logger.log(logger.MEDIUM, "Parse error when rebuilding HTML");\r
+                       logger.log(logger.MEDIUM, "Note guid: " +currentNoteGuid);\r
+                       logger.log(logger.EXTREME, "Start of unmodified note HTML");\r
+                       logger.log(logger.EXTREME, currentNote.getContent());\r
+                       logger.log(logger.EXTREME, "End of unmodified note HTML");\r
+                       return currentNote.getContent();\r
+               }\r
+\r
+               if (tempFiles == null)\r
+                       tempFiles = new ArrayList<QTemporaryFile>();\r
+               tempFiles.clear();\r
+               \r
+               doc = modifyTags(doc);\r
+               if (addHighlight)\r
+                       doc = addHilight(doc);\r
+               QDomElement docElem = doc.documentElement();\r
+               docElem.setTagName("Body");\r
+//             docElem.setAttribute("bgcolor", "green");\r
+               logger.log(logger.EXTREME, "Rebuilt HTML:");\r
+               logger.log(logger.EXTREME, doc.toString());     \r
+               logger.log(logger.HIGH, "Leaving NeverNote.rebuildNoteHTML");\r
+               // Fix the stupid problem where inserting an <img> tag after an <a> tag (which is done\r
+               // to get the <en-media> application tag to work properly) causes spaces to be inserted\r
+               // between the <a> & <img>.  This messes things up later.  This is an ugly hack.\r
+               StringBuffer html = new StringBuffer(doc.toString());\r
+               for (int i=html.indexOf("<a en-tag=\"en-media\" ", 0); i>-1; i=html.indexOf("<a en-tag=\"en-media\" ", i)) {\r
+                       i=html.indexOf(">\n",i+1);\r
+                       int z = html.indexOf("<img",i);\r
+                       for (int j=z-1; j>i; j--) \r
+                               html.deleteCharAt(j);\r
+                       i=html.indexOf("/>", z+1);\r
+                       z = html.indexOf("</a>",i);\r
+                       for (int j=z-1; j>i+1; j--) \r
+                               html.deleteCharAt(j);\r
+               } \r
+               return html.toString();\r
+       }       \r
+\r
+       \r
+    // Modify the en-media tag into an image tag so it can be displayed.\r
+    private void modifyImageTags(QDomElement docElem, QDomElement enmedia, QDomAttr hash) {\r
+       logger.log(logger.HIGH, "Entering NeverNote.modifyImageTags");\r
+       String type = enmedia.attribute("type");\r
+       if (type.startsWith("image/"))\r
+               type = "."+type.substring(6);\r
+       else\r
+               type="";\r
+       \r
+       String resGuid = conn.getNoteTable().noteResourceTable.getNoteResourceGuidByHashHex(currentNoteGuid, hash.value());\r
+       QFile tfile = new QFile(Global.getFileManager().getResDirPath(resGuid + type));\r
+       if (!tfile.exists()) {\r
+               Resource r = null;\r
+               if (resGuid != null)\r
+                       r = conn.getNoteTable().noteResourceTable.getNoteResource(resGuid,true);\r
+                       if (r==null || r.getData() == null || r.getData().getBody().length == 0)\r
+                               resourceError = true;;\r
+                       if (r!= null && r.getData() != null && r.getData().getBody().length > 0) {\r
+                               tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));\r
+                               QByteArray binData = new QByteArray(r.getData().getBody());\r
+                               tfile.write(binData);\r
+                               tfile.close();\r
+                               enmedia.setAttribute("src", QUrl.fromLocalFile(tfile.fileName()).toString());\r
+                               enmedia.setAttribute("en-tag", "en-media");\r
+                               enmedia.setNodeValue("");\r
+                       enmedia.setAttribute("guid", r.getGuid());\r
+                       enmedia.setTagName("img");\r
+               }\r
+       }\r
+               enmedia.setAttribute("src", QUrl.fromLocalFile(tfile.fileName()).toString());\r
+               enmedia.setAttribute("en-tag", "en-media");\r
+               enmedia.setAttribute("onContextMenu", "window.jambi.imageContextMenu('" +tfile.fileName()  +"');");\r
+               enmedia.setNodeValue("");\r
+               enmedia.setAttribute("guid", resGuid);\r
+               enmedia.setTagName("img");\r
+\r
+               logger.log(logger.HIGH, "Leaving NeverNote.modifyImageTags");\r
+    }\r
+    \r
+    \r
+       // Modify tags from Evernote specific things to XHTML tags.\r
+       private QDomDocument modifyTags(QDomDocument doc) {\r
+               logger.log(logger.HIGH, "Entering NeverNote.modifyTags");\r
+               if (tempFiles == null)\r
+                       tempFiles = new ArrayList<QTemporaryFile>();\r
+               tempFiles.clear();\r
+               QDomElement docElem = doc.documentElement();\r
+               \r
+               // Modify en-media tags\r
+               QDomNodeList anchors = docElem.elementsByTagName("en-media");\r
+               int enMediaCount = anchors.length();\r
+               for (int i=enMediaCount-1; i>=0; i--) {\r
+                       QDomElement enmedia = anchors.at(i).toElement();\r
+                       if (enmedia.hasAttribute("type")) {\r
+                               QDomAttr attr = enmedia.attributeNode("type");\r
+                               QDomAttr hash = enmedia.attributeNode("hash");\r
+                               String[] type = attr.nodeValue().split("/");\r
+                               String appl = type[1];\r
+                               \r
+                               if (type[0] != null) {\r
+                                       if (type[0].equals("image")) {\r
+                                               modifyImageTags(docElem, enmedia, hash);\r
+                                       }\r
+                                       if (!type[0].equals("image")) {\r
+                                               modifyApplicationTags(doc, docElem, enmedia, hash, appl);\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               // Modify todo tags\r
+               anchors = docElem.elementsByTagName("en-todo");\r
+               int enTodoCount = anchors.length();\r
+               for (int i=enTodoCount-1; i>=0; i--) {\r
+                       QDomElement enmedia = anchors.at(i).toElement();\r
+                       modifyTodoTags(enmedia);\r
+               }\r
+               \r
+               // Modify en-crypt tags\r
+               anchors = docElem.elementsByTagName("en-crypt");\r
+               int enCryptLen = anchors.length();\r
+               for (int i=enCryptLen-1; i>=0; i--) {\r
+                       QDomElement enmedia = anchors.at(i).toElement();\r
+                       enmedia.setAttribute("contentEditable","false");\r
+                       enmedia.setAttribute("src", Global.getFileManager().getImageDirPath("encrypt.png"));\r
+                       enmedia.setAttribute("en-tag","en-crypt");\r
+                       enmedia.setAttribute("alt", enmedia.text());\r
+                       Global.cryptCounter++;\r
+                       enmedia.setAttribute("id", "crypt"+Global.cryptCounter.toString());\r
+                       String encryptedText = enmedia.text();\r
+                       \r
+                       // If the encryption string contains crlf at the end, remove them because they mess up the javascript.\r
+                       if (encryptedText.endsWith("\n"))\r
+                               encryptedText = encryptedText.substring(0,encryptedText.length()-1);\r
+                       if (encryptedText.endsWith("\r"))\r
+                               encryptedText = encryptedText.substring(0,encryptedText.length()-1);\r
+                       \r
+                       // Add the commands\r
+                       String hint = enmedia.attribute("hint");\r
+                       hint = hint.replace("'","&apos;");\r
+                       enmedia.setAttribute("onClick", "window.jambi.decryptText('crypt"+Global.cryptCounter.toString()+"', '"+encryptedText+"', '"+hint+"');");\r
+                       enmedia.setAttribute("onMouseOver", "style.cursor='hand'");\r
+                       enmedia.setTagName("img");\r
+                       enmedia.removeChild(enmedia.firstChild());   // Remove the actual encrypted text\r
+               }\r
+\r
+               \r
+               // Modify link tags\r
+               anchors = docElem.elementsByTagName("a");\r
+               enCryptLen = anchors.length();\r
+               for (int i=0; i<anchors.length(); i++) {\r
+                       QDomElement element = anchors.at(i).toElement();\r
+                       element.setAttribute("title", element.attribute("href"));\r
+               }\r
+\r
+               logger.log(logger.HIGH, "Leaving NeverNote.modifyTags");\r
+               return doc;\r
+       }\r
+       \r
+       \r
+    // Modify the en-media tag into an attachment\r
+    private void modifyApplicationTags(QDomDocument doc, QDomElement docElem, QDomElement enmedia, QDomAttr hash, String appl) {\r
+       logger.log(logger.HIGH, "Entering NeverNote.modifyApplicationTags");\r
+       if (appl.equalsIgnoreCase("vnd.evernote.ink"))\r
+               readOnly = true;\r
+       String resGuid = conn.getNoteTable().noteResourceTable.getNoteResourceGuidByHashHex(currentNote.getGuid(), hash.value());\r
+       Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(resGuid, false);\r
+       if (r == null || r.getData() == null) \r
+               resourceError = true;\r
+               if (r!= null) {\r
+                       if (r.getData()!=null) {\r
+                               // Did we get a generic applicaiton?  Then look at the file name to \r
+                               // try and find a good application type for the icon\r
+                               if (appl.equalsIgnoreCase("octet-stream")) {\r
+                                       if (r.getAttributes() != null && r.getAttributes().getFileName() != null) {\r
+                                               String fn = r.getAttributes().getFileName();\r
+                                               int pos = fn.lastIndexOf(".");\r
+                                               if (pos > -1) {\r
+                                                       appl = fn.substring(pos+1);\r
+                                               }\r
+                                       }\r
+                               }\r
+                               \r
+                               String fileDetails = null;\r
+                               if (r.getAttributes() != null && r.getAttributes().getFileName() != null && !r.getAttributes().getFileName().equals(""))\r
+                                       fileDetails = r.getAttributes().getFileName();\r
+                               String contextFileName;\r
+                               FileManager fileManager = Global.getFileManager();\r
+                if (fileDetails != null && !fileDetails.equals("")) {\r
+                       if (!noteHistory) {\r
+                               enmedia.setAttribute("href", "nnres://" +r.getGuid() \r
+                                               +Global.attachmentNameDelimeter +fileDetails);\r
+                               contextFileName = fileManager.getResDirPath(r.getGuid() \r
+                                               +Global.attachmentNameDelimeter + fileDetails);\r
+                       } else {\r
+                               enmedia.setAttribute("href", "nnres://" +r.getGuid() + currentNote.getUpdateSequenceNum() \r
+                                               +Global.attachmentNameDelimeter +fileDetails);\r
+                               contextFileName = fileManager.getResDirPath(r.getGuid() + currentNote.getUpdateSequenceNum() \r
+                                               +Global.attachmentNameDelimeter + fileDetails);\r
+                       }\r
+                               } else { \r
+                                       if (!noteHistory) {\r
+                                               enmedia.setAttribute("href", "nnres://" +r.getGuid() +currentNote.getUpdateSequenceNum()\r
+                                                               +Global.attachmentNameDelimeter +appl);\r
+                                               contextFileName = fileManager.getResDirPath(r.getGuid() +currentNote.getUpdateSequenceNum() \r
+                                                               +Global.attachmentNameDelimeter + appl);\r
+                                       } else {\r
+                                               enmedia.setAttribute("href", "nnres://" +r.getGuid() \r
+                                                               +Global.attachmentNameDelimeter +appl);\r
+                                               contextFileName = fileManager.getResDirPath(r.getGuid() \r
+                                                               +Global.attachmentNameDelimeter + appl);\r
+                                       }\r
+                               }\r
+                               contextFileName = contextFileName.replace("\\", "/");\r
+                               enmedia.setAttribute("onContextMenu", "window.jambi.resourceContextMenu('" +contextFileName +"');");\r
+                               if (fileDetails == null || fileDetails.equals(""))\r
+                                       fileDetails = "";\r
+                               enmedia.setAttribute("en-tag", "en-media");\r
+                               enmedia.setAttribute("guid", r.getGuid());\r
+                               enmedia.setTagName("a");\r
+                               QDomElement newText = doc.createElement("img");\r
+                               boolean goodPreview = false;\r
+                               String filePath = "";\r
+                               if (appl.equalsIgnoreCase("pdf") && pdfPreview) {\r
+                                       String fileName;\r
+                                       Resource res = conn.getNoteTable().noteResourceTable.getNoteResource(r.getGuid(), true);\r
+                                       if (res.getAttributes() != null && \r
+                                                       res.getAttributes().getFileName() != null && \r
+                                                       !res.getAttributes().getFileName().trim().equals(""))\r
+                                               fileName = res.getGuid()+Global.attachmentNameDelimeter+res.getAttributes().getFileName();\r
+                                       else\r
+                                               fileName = res.getGuid()+".pdf";\r
+                                       QFile file = new QFile(fileManager.getResDirPath(fileName));\r
+                               QFile.OpenMode mode = new QFile.OpenMode();\r
+                               mode.set(QFile.OpenModeFlag.WriteOnly);\r
+                               file.open(mode);\r
+                               QDataStream out = new QDataStream(file);\r
+                               Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(res.getGuid(), true);\r
+                                       QByteArray binData = new QByteArray(resBinary.getData().getBody());\r
+                                       resBinary = null;\r
+                               out.writeBytes(binData.toByteArray());\r
+                               file.close();\r
+                               PDFPreview pdfPreview = new PDFPreview();\r
+                                       goodPreview = pdfPreview.setupPreview(file.fileName(), appl,0);\r
+                                       if (goodPreview) {\r
+                                               QDomElement span = doc.createElement("span");\r
+                                               QDomElement table = doc.createElement("table");\r
+                                               span.setAttribute("pdfNavigationTable", "true");\r
+                                               QDomElement tr = doc.createElement("tr");\r
+                                               QDomElement td = doc.createElement("td");\r
+                                               QDomElement left = doc.createElement("img");\r
+                                               left.setAttribute("onMouseDown", "window.jambi.nextPage('" +file.fileName() +"')");\r
+                                               left.setAttribute("onMouseDown", "window.jambi.nextPage('" +file.fileName() +"')");\r
+                                               left.setAttribute("onMouseOver", "style.cursor='hand'");\r
+                                               QDomElement right = doc.createElement("img");\r
+                                               right.setAttribute("onMouseDown", "window.jambi.nextPage('" +file.fileName() +"')");\r
+                                               left.setAttribute("onMouseDown", "window.jambi.previousPage('" +file.fileName() +"')");\r
+                                               // NFC TODO: should these be file:// URLs?\r
+                                               left.setAttribute("src", Global.getFileManager().getImageDirPath("small_left.png"));\r
+                                               right.setAttribute("src", Global.getFileManager().getImageDirPath("small_right.png"));\r
+                                               right.setAttribute("onMouseOver", "style.cursor='hand'");\r
+                                               \r
+                                               table.appendChild(tr);\r
+                                               tr.appendChild(td);\r
+                                               td.appendChild(left);\r
+                                               td.appendChild(right);\r
+                                               span.appendChild(table);\r
+                                               enmedia.parentNode().insertBefore(span, enmedia);\r
+                                       } \r
+                                       filePath = fileName+".png";\r
+                               }\r
+                               String icon = findIcon(appl);\r
+                               if (icon.equals("attachment.png"))\r
+                                       icon = findIcon(fileDetails.substring(fileDetails.indexOf(".")+1));\r
+                               // NFC TODO: should this be a 'file://' URL?\r
+                               newText.setAttribute("src", Global.getFileManager().getImageDirPath(icon));\r
+                               if (goodPreview) {\r
+                               // NFC TODO: should this be a 'file://' URL?\r
+                                       newText.setAttribute("src", fileManager.getResDirPath(filePath));\r
+                                       newText.setAttribute("style", "border-style:solid; border-color:green; padding:0.5mm 0.5mm 0.5mm 0.5mm;");\r
+                               }\r
+                               newText.setAttribute("title", fileDetails);\r
+                               enmedia.removeChild(enmedia.firstChild());\r
+                               \r
+                               enmedia.appendChild(newText);\r
+                       }\r
+               }\r
+               logger.log(logger.HIGH, "Leaving NeverNote.modifyApplicationTags");\r
+    }\r
+    // Modify the en-to tag into an input field\r
+    private void modifyTodoTags(QDomElement todo) {\r
+       logger.log(logger.HIGH, "Entering NeverNote.modifyTodoTags");\r
+               todo.setAttribute("type", "checkbox");\r
+               String checked = todo.attribute("checked");\r
+               todo.removeAttribute("checked");\r
+               if (checked.equalsIgnoreCase("true"))\r
+                       todo.setAttribute("checked", "");\r
+               else\r
+                       todo.setAttribute("unchecked","");\r
+               todo.setAttribute("value", checked);\r
+               todo.setAttribute("onClick", "value=checked;window.jambi.contentChanged(); ");\r
+               todo.setTagName("input");\r
+               logger.log(logger.HIGH, "Leaving NeverNote.modifyTodoTags");\r
+    }\r
+    \r
+    \r
+    \r
+    // Modify any cached todo tags that may have changed\r
+    public String modifyCachedTodoTags(String note) {\r
+       logger.log(logger.HIGH, "Entering NeverNote.modifyCachedTodoTags");\r
+       StringBuffer html = new StringBuffer(note);\r
+               for (int i=html.indexOf("<input", 0); i>-1; i=html.indexOf("<input", i)) {\r
+                       int endPos =html.indexOf(">",i+1);\r
+                       String input = html.substring(i,endPos);\r
+                       if (input.indexOf("value=\"true\"") > 0) \r
+                               input = input.replace(" unchecked=\"\"", " checked=\"\"");\r
+                       else\r
+                               input = input.replace(" checked=\"\"", " unchecked=\"\"");\r
+                       html.replace(i, endPos, input);\r
+                       i++;\r
+               }\r
+               logger.log(logger.HIGH, "Leaving NeverNote.modifyCachedTodoTags");\r
+               return html.toString();\r
+    }\r
+    \r
+    \r
+\r
+\r
+       // Scan and do hilighting of words\r
+       public QDomDocument addHilight(QDomDocument doc) {\r
+//             EnSearch e = listManager.getEnSearch();\r
+               if (enSearch.hilightWords == null || enSearch.hilightWords.size() == 0)\r
+                       return doc;\r
+               XMLInsertHilight hilight = new XMLInsertHilight(doc, enSearch.hilightWords);\r
+               return hilight.getDoc();\r
+       }\r
+       \r
+       \r
+    // find the appropriate icon for an attachment\r
+    private String findIcon(String appl) {\r
+       logger.log(logger.HIGH, "Entering NeverNote.findIcon");\r
+       appl = appl.toLowerCase();\r
+        String relativePath = appl + ".png";\r
+        File f = Global.getFileManager().getImageDirFile(relativePath);\r
+        if (f.exists()) {\r
+            return relativePath;\r
+        }\r
+       if (f.exists())\r
+               return appl+".png";\r
+       logger.log(logger.HIGH, "Leaving NeverNote.findIcon");\r
+       return "attachment.png";\r
+    }\r
+\r
+\r
+}\r
index 6fd54b8..3d1b280 100644 (file)
@@ -30,7 +30,6 @@ import com.trolltech.qt.xml.QDomNodeList;
 import com.trolltech.qt.xml.QDomText;\r
 \r
 import cx.fbn.nevernote.Global;\r
-import cx.fbn.nevernote.evernote.EnCrypt;\r
 \r
 public class XMLCleanup {\r
        private String content;\r
@@ -44,10 +43,6 @@ public class XMLCleanup {
        \r
        public void setValue(String text) {\r
                content = text;\r
-/*             content = content.replace("<HR>", "<hr/>");\r
-               content = content.replace("<hr>", "<hr/>");\r
-               content = content.replace("</HR>", "");\r
-               content = content.replace("</hr>", ""); */\r
        }\r
        public String getValue() {\r
                return content;\r
@@ -96,8 +91,17 @@ public class XMLCleanup {
                        }\r
                }\r
                \r
+               // Scan through tags node by node\r
                scanTags();\r
                \r
+               // Scan again making sure we didn't miss any <a> tags.  Sometimes we do\r
+               QDomNodeList anchorList = doc.elementsByTagName("a");\r
+               int anchorCount = anchorList.length();\r
+               for (int i=anchorCount-1; i>=0; i--) {\r
+                       QDomNode link = anchorList.at(i);\r
+                       link = fixLinkNode(link);\r
+               }\r
+               \r
                // Remove invalid elements & attributes\r
                // Modify en-media tags\r
                QDomNodeList anchors;\r
@@ -128,10 +132,7 @@ public class XMLCleanup {
 \r
        }\r
        // Start looking through the tree.\r
-       private void scanTags() {\r
-//             System.out.println("scanTags start");\r
-//             QDomElement element = doc.firstChildElement();\r
-//             parseChildren(element.firstChild());    \r
+       private void scanTags() {       \r
                \r
                if (doc.hasChildNodes())\r
                        parseNodes(doc.childNodes());\r
@@ -147,25 +148,7 @@ public class XMLCleanup {
                }\r
        }\r
        \r
-/*     \r
-       // Parse through individual nodes\r
-       private void parseChildren(QDomNode node) {\r
-               System.out.println("Starting parseChildren " +node.toElement().nodeName() +" : " +node.toElement().text());\r
-               for(; !node.isNull(); node = node.nextSibling()) {\r
-                       if (node.hasChildNodes()) {\r
-                               QDomNodeList l = node.childNodes();\r
-                               \r
-                               for (int i=0; i<l.size(); i++)  {\r
-                                       System.out.println("Child node size: " +l.size() +" " +i);\r
-                                       parseChildren(l.at(i));\r
-                               }\r
-                       }\r
-                       fixNode(node);\r
-               }\r
-       }\r
-       \r
-*/     \r
-       \r
+\r
        // Fix the contents of the node back to ENML.\r
        private void fixNode(QDomNode node) {\r
                QDomElement scanChecked = node.toElement();\r
@@ -188,21 +171,8 @@ public class XMLCleanup {
                        e.removeAttribute("type");\r
                }\r
 \r
-\r
                if (node.nodeName().equalsIgnoreCase("a")) {\r
-                       QDomElement e = node.toElement();\r
-                       String enTag = e.attribute("en-tag");\r
-                       if (enTag.equalsIgnoreCase("en-media")) {\r
-                               e.setTagName("en-media");\r
-                               e.removeAttribute("en-type");\r
-                               e.removeAttribute("en-tag");\r
-                               e.removeAttribute("en-new");\r
-                               resources.add(e.attribute("guid"));\r
-                               e.removeAttribute("href");\r
-                               e.removeAttribute("guid");\r
-                               e.setNodeValue("");\r
-                               e.removeChild(e.firstChildElement());\r
-                       }\r
+                       node = fixLinkNode(node);\r
                }\r
                // Restore image resources\r
                if (node.nodeName().equalsIgnoreCase("img")) {\r
@@ -253,20 +223,6 @@ public class XMLCleanup {
                        }\r
                }\r
                \r
-               if (node.nodeName().equalsIgnoreCase("en-crypt-temp")) {\r
-                       QDomElement e = node.toElement();\r
-                       String slot = e.attribute("slot");\r
-                       e.removeAttribute("slot");\r
-                       String password = Global.passwordSafe.get(slot);\r
-                       Global.passwordSafe.remove(slot);\r
-                       EnCrypt crypt = new EnCrypt();\r
-                       String encrypted = crypt.encrypt(e.text(), password, 64); \r
-                       \r
-                       QDomText newText = doc.createTextNode(encrypted);\r
-                       e.appendChild(newText);\r
-                       e.removeChild(e.firstChild());\r
-                       e.setTagName("en-crypt");\r
-               }\r
                if (node.nodeName().equalsIgnoreCase("en-hilight")) {\r
                        QDomElement e = node.toElement();\r
                        QDomText newText = doc.createTextNode(e.text());\r
@@ -282,8 +238,35 @@ public class XMLCleanup {
                                node.parentNode().removeChild(node);\r
                        }\r
                }\r
+               \r
+               // Fix up encryption tag\r
+               if (node.nodeName().equalsIgnoreCase("en-crypt-temp")) {\r
+                       QDomElement e = node.toElement();\r
+                       e.setTagName("en-crypt");\r
+                       String crypt = e.attribute("value");\r
+                       e.removeAttribute("value");\r
+                       QDomText cryptValue = doc.createTextNode(crypt);\r
+                       e.appendChild(cryptValue);\r
+               }\r
        }\r
 \r
+       \r
+       private QDomNode fixLinkNode(QDomNode node) {\r
+               QDomElement e = node.toElement();\r
+               String enTag = e.attribute("en-tag");\r
+               if (enTag.equalsIgnoreCase("en-media")) {\r
+                       e.setTagName("en-media");\r
+                       e.removeAttribute("en-type");\r
+                       e.removeAttribute("en-tag");\r
+                       e.removeAttribute("en-new");\r
+                       resources.add(e.attribute("guid"));\r
+                       e.removeAttribute("href");\r
+                       e.removeAttribute("guid");\r
+                       e.setNodeValue("");\r
+                       e.removeChild(e.firstChildElement());\r
+               }\r
+               return e;\r
+       }\r
 \r
        \r
        // Return old resources we've found\r