OSDN Git Service

Correct view source not updating.
[neighbornote/NeighborNote.git] / src / cx / fbn / nevernote / gui / BrowserWindow.java
index 50bdccf..9797e08 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
- * This file is part of NeverNote \r
+ * This file is part of NixNote \r
  * Copyright 2009 Randy Baumgarte\r
  * \r
  * This file may be licensed under the terms of of the\r
@@ -20,6 +20,8 @@
 package cx.fbn.nevernote.gui;\r
 \r
 import java.io.File;\r
+import java.io.FileNotFoundException;\r
+import java.io.IOException;\r
 import java.net.FileNameMap;\r
 import java.net.URI;\r
 import java.net.URLConnection;\r
@@ -28,10 +30,16 @@ import java.security.NoSuchAlgorithmException;
 import java.text.SimpleDateFormat;\r
 import java.util.ArrayList;\r
 import java.util.Calendar;\r
+import java.util.Collections;\r
 import java.util.Date;\r
 import java.util.GregorianCalendar;\r
 import java.util.HashMap;\r
 import java.util.List;\r
+import java.util.Locale;\r
+import java.util.StringTokenizer;\r
+\r
+import org.apache.commons.lang3.StringEscapeUtils;\r
+import org.apache.commons.lang3.StringUtils;\r
 \r
 import com.evernote.edam.limits.Constants;\r
 import com.evernote.edam.type.Data;\r
@@ -40,18 +48,37 @@ import com.evernote.edam.type.Notebook;
 import com.evernote.edam.type.Resource;\r
 import com.evernote.edam.type.ResourceAttributes;\r
 import com.evernote.edam.type.Tag;\r
+import com.evernote.edam.type.User;\r
+import com.swabunga.spell.engine.Configuration;\r
+import com.swabunga.spell.engine.SpellDictionary;\r
+import com.swabunga.spell.engine.SpellDictionaryHashMap;\r
+import com.swabunga.spell.engine.Word;\r
+import com.swabunga.spell.event.SpellCheckEvent;\r
+import com.swabunga.spell.event.SpellCheckListener;\r
+import com.swabunga.spell.event.SpellChecker;\r
+import com.swabunga.spell.event.StringWordTokenizer;\r
 import com.trolltech.qt.core.QByteArray;\r
+import com.trolltech.qt.core.QCoreApplication;\r
 import com.trolltech.qt.core.QDataStream;\r
 import com.trolltech.qt.core.QDateTime;\r
 import com.trolltech.qt.core.QEvent;\r
+import com.trolltech.qt.core.QEvent.Type;\r
 import com.trolltech.qt.core.QFile;\r
 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.QTimer;\r
 import com.trolltech.qt.core.QUrl;\r
+import com.trolltech.qt.core.Qt;\r
+import com.trolltech.qt.core.Qt.Key;\r
+import com.trolltech.qt.core.Qt.KeyboardModifier;\r
+import com.trolltech.qt.core.Qt.KeyboardModifiers;\r
+import com.trolltech.qt.gui.QAction;\r
 import com.trolltech.qt.gui.QApplication;\r
 import com.trolltech.qt.gui.QCalendarWidget;\r
 import com.trolltech.qt.gui.QClipboard;\r
+import com.trolltech.qt.gui.QClipboard.Mode;\r
 import com.trolltech.qt.gui.QColor;\r
 import com.trolltech.qt.gui.QComboBox;\r
 import com.trolltech.qt.gui.QDateEdit;\r
@@ -59,23 +86,35 @@ import com.trolltech.qt.gui.QDesktopServices;
 import com.trolltech.qt.gui.QFileDialog;\r
 import com.trolltech.qt.gui.QFileDialog.AcceptMode;\r
 import com.trolltech.qt.gui.QFileDialog.FileMode;\r
+import com.trolltech.qt.gui.QFont;\r
 import com.trolltech.qt.gui.QFontDatabase;\r
 import com.trolltech.qt.gui.QFormLayout;\r
 import com.trolltech.qt.gui.QGridLayout;\r
 import com.trolltech.qt.gui.QHBoxLayout;\r
 import com.trolltech.qt.gui.QIcon;\r
 import com.trolltech.qt.gui.QImage;\r
+import com.trolltech.qt.gui.QKeyEvent;\r
 import com.trolltech.qt.gui.QKeySequence;\r
 import com.trolltech.qt.gui.QLabel;\r
 import com.trolltech.qt.gui.QLineEdit;\r
 import com.trolltech.qt.gui.QListWidgetItem;\r
 import com.trolltech.qt.gui.QMatrix;\r
 import com.trolltech.qt.gui.QMessageBox;\r
+import com.trolltech.qt.gui.QPalette;\r
+import com.trolltech.qt.gui.QPalette.ColorRole;\r
 import com.trolltech.qt.gui.QPushButton;\r
 import com.trolltech.qt.gui.QShortcut;\r
+import com.trolltech.qt.gui.QSplitter;\r
+import com.trolltech.qt.gui.QTextEdit;\r
+import com.trolltech.qt.gui.QTextEdit.LineWrapMode;\r
 import com.trolltech.qt.gui.QTimeEdit;\r
+import com.trolltech.qt.gui.QToolButton;\r
+import com.trolltech.qt.gui.QToolButton.ToolButtonPopupMode;\r
 import com.trolltech.qt.gui.QVBoxLayout;\r
 import com.trolltech.qt.gui.QWidget;\r
+import com.trolltech.qt.network.QNetworkAccessManager;\r
+import com.trolltech.qt.network.QNetworkReply;\r
+import com.trolltech.qt.network.QNetworkReply.NetworkError;\r
 import com.trolltech.qt.network.QNetworkRequest;\r
 import com.trolltech.qt.webkit.QWebPage;\r
 import com.trolltech.qt.webkit.QWebPage.WebAction;\r
@@ -86,15 +125,21 @@ import cx.fbn.nevernote.Global;
 import cx.fbn.nevernote.dialog.EnCryptDialog;\r
 import cx.fbn.nevernote.dialog.EnDecryptDialog;\r
 import cx.fbn.nevernote.dialog.GeoDialog;\r
+import cx.fbn.nevernote.dialog.InsertLatexImage;\r
 import cx.fbn.nevernote.dialog.InsertLinkDialog;\r
+import cx.fbn.nevernote.dialog.NoteQuickLinkDialog;\r
+import cx.fbn.nevernote.dialog.SpellCheck;\r
 import cx.fbn.nevernote.dialog.TableDialog;\r
 import cx.fbn.nevernote.dialog.TagAssign;\r
 import cx.fbn.nevernote.evernote.EnCrypt;\r
+import cx.fbn.nevernote.filters.FilterEditorTags;\r
 import cx.fbn.nevernote.signals.NoteResourceSignal;\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.utilities.FileUtils;\r
+import cx.fbn.nevernote.utilities.Pair;\r
+import cx.fbn.nevernote.xml.HtmlTagModifier;\r
 \r
 public class BrowserWindow extends QWidget {\r
 \r
@@ -105,7 +150,7 @@ public class BrowserWindow extends QWidget {
        private final QComboBox geoBox;\r
        public final TagLineEdit tagEdit;\r
        public final QLabel tagLabel;\r
-       private final QLabel urlLabel;\r
+       private final QPushButton urlLabel;\r
        private final QLabel alteredLabel;\r
        private final QDateEdit alteredDate;\r
        private final QTimeEdit alteredTime;\r
@@ -118,45 +163,70 @@ public class BrowserWindow extends QWidget {
        private final QLabel notebookLabel;\r
        private final QLabel createdLabel;\r
        public final QComboBox fontSize;\r
+       public final QAction    fontSizeAction;\r
        private boolean extendedOn;\r
        public boolean buttonsVisible;\r
-       private final String iconPath = new String("classpath:cx/fbn/nevernote/icons/");\r
+       private final String iconPath;\r
        private final ContentView browser;\r
+       private final QTextEdit sourceEdit;\r
+       private String sourceEditHeader;\r
+       Highlighter syntaxHighlighter;\r
        private List<Tag> allTags;\r
        private List<String> currentTags;\r
        public NoteSignal noteSignal;\r
+       public Signal2<String,String> evernoteLinkClicked;\r
        private List<Notebook> notebookList;\r
        private Note currentNote;\r
        private String saveNoteTitle;\r
        private String saveTagList;\r
        private boolean insideList;\r
-//     private String selectedText;\r
        private final DatabaseConnection conn;\r
        private final QCalendarWidget createdCalendarWidget;\r
        private final QCalendarWidget alteredCalendarWidget;\r
        private final QCalendarWidget subjectCalendarWidget;\r
 \r
        public final QPushButton undoButton;\r
+       public final QAction    undoAction;\r
        public final QPushButton redoButton;\r
+       public final QAction    redoAction;\r
        public final QPushButton cutButton;\r
+       public final QAction    cutAction;\r
        public final QPushButton copyButton;\r
+       public final QAction    copyAction;\r
        public final QPushButton pasteButton;\r
+       public final QAction    pasteAction;\r
        public final QPushButton boldButton;\r
+       public final QAction    boldAction;\r
        public final QPushButton underlineButton;\r
+       public final QAction    underlineAction;\r
        public final QPushButton italicButton;\r
+       public final QAction    italicAction;\r
        public final Signal0 focusLost;\r
        public final NoteResourceSignal resourceSignal;\r
 \r
        public QPushButton rightAlignButton;\r
+       public final QAction    rightAlignAction;\r
        public QPushButton leftAlignButton;\r
+       public final QAction    leftAlignAction;\r
        public QPushButton centerAlignButton;\r
+       public final QAction    centerAlignAction;\r
 \r
        public final QPushButton strikethroughButton;\r
+       public final QAction    strikethroughAction;\r
        public final QPushButton hlineButton;\r
+       public final QAction    hlineAction;\r
        public final QPushButton indentButton;\r
+       public final QAction    indentAction;\r
        public final QPushButton outdentButton;\r
+       public final QAction    outdentAction;\r
        public final QPushButton bulletListButton;\r
+       public final QAction    bulletListAction;\r
        public final QPushButton numberListButton;\r
+       public final QAction    numberListAction;\r
+       public final QPushButton spellCheckButton;\r
+       public final QAction    spellCheckAction;\r
+       public final QPushButton todoButton;\r
+       public final QAction    todoAction;\r
 \r
        public final QShortcut focusTitleShortcut;\r
        public final QShortcut focusTagShortcut;\r
@@ -164,43 +234,107 @@ public class BrowserWindow extends QWidget {
        public final QShortcut focusUrlShortcut;\r
        public final QShortcut focusAuthorShortcut;\r
        \r
+       public EditorButtonBar buttonLayout;\r
        public final QComboBox fontList;\r
-       public final QPushButton fontColor;\r
+       public final QAction    fontListAction;\r
+       public final QToolButton fontColor;\r
+       public final QAction    fontColorAction;\r
        private final ColorMenu fontColorMenu;\r
-       public final QPushButton fontHilight;\r
-//     public final ColorComboBox fontHilight;\r
+       public final QToolButton fontHilight;\r
+       public final QAction    fontHilightAction;\r
        private final ColorMenu fontHilightColorMenu;\r
        public final QFileSystemWatcher fileWatcher;\r
        public int cursorPosition;\r
-       private boolean forceTextPaste = false;\r
+       private boolean forceTextPaste;\r
        private String selectedFile;\r
        private String currentHyperlink;\r
        public boolean keepPDFNavigationHidden;\r
        private final ApplicationLogger logger;\r
+       SpellDictionary dictionary;\r
+    SpellDictionary userDictionary;\r
+    SpellChecker spellChecker;\r
+    SuggestionListener spellListener;\r
+       private final HashMap<String,Integer> previewPageList;  \r
+       boolean insertHyperlink;\r
+       boolean insideTable;\r
+       boolean insideEncryption;\r
+       public Signal1<BrowserWindow> blockApplication;\r
+       public Signal0 unblockApplication;\r
+       public boolean awaitingHttpResponse;\r
+       public long     unblockTime;\r
+       private final QTimer setSourceTimer;\r
+       String latexGuid;  // This is set if we are editing an existing LaTeX formula.  Useful to track guid.\r
+\r
        \r
-       private final HashMap<String,Integer> previewPageList; \r
+       public static class SuggestionListener implements SpellCheckListener {\r
+               public boolean abortSpellCheck = false;\r
+               public boolean errorsFound = false;\r
+               private final SpellCheck                spellCheckDialog;\r
+               \r
+               \r
+               private final BrowserWindow parent;\r
+               public SuggestionListener(BrowserWindow parent, SpellChecker checker) {\r
+                       this.parent = parent;\r
+                       spellCheckDialog = new SpellCheck(checker);\r
+               }\r
+               public void spellingError(SpellCheckEvent event) {\r
+                       errorsFound = true;\r
+                       spellCheckDialog.setWord(event.getInvalidWord());\r
+\r
+                   @SuppressWarnings("unchecked")\r
+                       List<Word> suggestions = event.getSuggestions();\r
+                   spellCheckDialog.clearSuggestions();\r
+                   if (!suggestions.isEmpty()) {\r
+//                    spellCheckDialog.setCurrentSuggestion(suggestions.get(0).getWord());\r
+                      for (int i=0; i<suggestions.size(); i++) {\r
+                         spellCheckDialog.addSuggestion(suggestions.get(i).getWord());\r
+                      }\r
+                      spellCheckDialog.setSelectedSuggestion(0);\r
+                   }\r
+                   spellCheckDialog.exec();\r
+                   if (spellCheckDialog.cancelPressed()) {\r
+                       abortSpellCheck = true;\r
+                       event.cancel();\r
+                       return;\r
+                   }\r
+                   if (spellCheckDialog.replacePressed()) {\r
+                       QClipboard clipboard = QApplication.clipboard();\r
+                       clipboard.setText(spellCheckDialog.getReplacementWord()); \r
+                       parent.pasteClicked();\r
+                   }\r
+                   event.cancel();\r
+                }\r
+       }\r
+\r
        \r
        \r
        public BrowserWindow(DatabaseConnection c) {\r
                logger = new ApplicationLogger("browser.log");\r
                logger.log(logger.HIGH, "Setting up browser");\r
+               iconPath = new String("classpath:cx/fbn/nevernote/icons/");\r
+               forceTextPaste = false;\r
+               insertHyperlink = true;\r
+               insideTable = false;\r
+               insideEncryption = false;\r
                \r
                fileWatcher = new QFileSystemWatcher();\r
 //             fileWatcher.fileChanged.connect(this, "fileChanged(String)");\r
                noteSignal = new NoteSignal();\r
                titleLabel = new QLineEdit();\r
+               evernoteLinkClicked = new Signal2<String,String>();\r
                titleLabel.setMaxLength(Constants.EDAM_NOTE_TITLE_LEN_MAX);\r
                urlText = new QLineEdit();\r
                authorText = new QLineEdit();\r
                geoBox = new QComboBox();\r
-               urlLabel = new QLabel();\r
+               urlLabel = new QPushButton();\r
+               urlLabel.clicked.connect(this, "sourceUrlClicked()");\r
                authorLabel = new QLabel();\r
                conn = c;\r
                \r
                focusLost = new Signal0();\r
 \r
                tagEdit = new TagLineEdit(allTags);\r
-               tagLabel = new QLabel("Tags:");\r
+               tagLabel = new QLabel(tr("Tags:"));\r
                tagEdit.focusLost.connect(this, "modifyTagsTyping()");\r
 \r
                createdCalendarWidget = new QCalendarWidget();\r
@@ -218,7 +352,7 @@ public class BrowserWindow extends QWidget {
                alteredDate.setCalendarPopup(true);\r
                alteredDate.setCalendarWidget(alteredCalendarWidget);\r
                alteredTime = new QTimeEdit();\r
-               alteredLabel = new QLabel("Altered:");\r
+               alteredLabel = new QLabel(tr("Altered:"));\r
                alteredDate.dateChanged.connect(this, "alteredChanged()");\r
                alteredTime.timeChanged.connect(this, "alteredChanged()");\r
 \r
@@ -228,15 +362,15 @@ public class BrowserWindow extends QWidget {
                subjectDate.setCalendarPopup(true);\r
                subjectDate.setCalendarWidget(subjectCalendarWidget);\r
                subjectTime = new QTimeEdit();\r
-               subjectLabel = new QLabel("Subject Date:");\r
+               subjectLabel = new QLabel(tr("Subject Date:"));\r
                subjectDate.dateChanged.connect(this, "subjectDateTimeChanged()");\r
                subjectTime.timeChanged.connect(this, "subjectDateTimeChanged()");\r
                authorText.textChanged.connect(this, "authorChanged()");\r
                urlText.textChanged.connect(this, "sourceUrlChanged()");\r
 \r
                notebookBox = new QComboBox();\r
-               notebookLabel = new QLabel("Notebook");\r
-               createdLabel = new QLabel("Created:");\r
+               notebookLabel = new QLabel(tr("Notebook"));\r
+               createdLabel = new QLabel(tr("Created:"));\r
                // selectedText = new String();\r
 \r
                urlLabel.setVisible(false);\r
@@ -245,9 +379,9 @@ public class BrowserWindow extends QWidget {
                \r
                geoBox.setVisible(false);\r
                geoBox.addItem(new QIcon(iconPath+"globe.png"), "");\r
-               geoBox.addItem(new String("Set"));\r
-               geoBox.addItem(new String("Clear"));\r
-               geoBox.addItem(new String("View On Map"));\r
+               geoBox.addItem(new String(tr("Set")));\r
+               geoBox.addItem(new String(tr("Clear")));\r
+               geoBox.addItem(new String(tr("View On Map")));\r
                geoBox.activated.connect(this, "geoBoxChanged()");\r
                \r
                authorText.setVisible(false);\r
@@ -267,11 +401,25 @@ public class BrowserWindow extends QWidget {
                setAcceptDrops(true);\r
 \r
                browser = new ContentView(this);\r
+                               \r
                browser.page().setLinkDelegationPolicy(\r
                                QWebPage.LinkDelegationPolicy.DelegateAllLinks);\r
                browser.linkClicked.connect(this, "linkClicked(QUrl)");\r
                currentHyperlink = "";\r
                \r
+               //Setup the source editor\r
+               sourceEdit = new QTextEdit(this);\r
+               sourceEdit.setVisible(false);\r
+               sourceEdit.setTabChangesFocus(true);\r
+               sourceEdit.setLineWrapMode(LineWrapMode.NoWrap);\r
+               QFont font = new QFont();\r
+               font.setFamily("Courier");\r
+               font.setFixedPitch(true);\r
+               font.setPointSize(10);\r
+               sourceEdit.setFont(font);\r
+               syntaxHighlighter = new Highlighter(sourceEdit.document());\r
+               sourceEdit.textChanged.connect(this, "sourceEdited()");\r
+\r
                QVBoxLayout v = new QVBoxLayout();\r
                QFormLayout notebookLayout = new QFormLayout();\r
                QGridLayout dateLayout = new QGridLayout();\r
@@ -317,69 +465,89 @@ public class BrowserWindow extends QWidget {
                dateLayout.addWidget(subjectTime, 0, 8);\r
                v.addLayout(dateLayout, 0);\r
 \r
-               undoButton = newEditorButton("undo", "Undo Change");\r
-               redoButton = newEditorButton("redo", "Redo Change");\r
-               cutButton = newEditorButton("cut", "Cut");\r
-               copyButton = newEditorButton("copy", "Copy");\r
-               pasteButton = newEditorButton("paste", "Paste");\r
-               boldButton = newEditorButton("bold", "Bold");\r
-               underlineButton = newEditorButton("underline", "Underline");\r
-               italicButton = newEditorButton("italic", "Italic");\r
-\r
-               rightAlignButton = newEditorButton("justifyRight", "Right Align");\r
-               leftAlignButton = newEditorButton("justifyLeft", "Left Align");\r
-               centerAlignButton = newEditorButton("justifyCenter", "Center Align");\r
-\r
-               strikethroughButton = newEditorButton("strikethrough", "Strikethrough");\r
-               hlineButton = newEditorButton("hline", "Insert Horizontal Line");\r
-               indentButton = newEditorButton("indent", "Shift Right");\r
-               outdentButton = newEditorButton("outdent", "Shift Left");\r
-               bulletListButton = newEditorButton("bulletList", "Bullet List");\r
-               numberListButton = newEditorButton("numberList", "Number List");\r
-\r
-\r
-               QHBoxLayout buttonLayout;\r
-               buttonLayout = new QHBoxLayout();\r
-               buttonLayout.setSpacing(0);\r
-               v.addLayout(buttonLayout);\r
-               \r
-               buttonLayout.addWidget(undoButton);\r
-               buttonLayout.addWidget(redoButton);\r
-\r
-               buttonLayout.addWidget(newSeparator(), 0);\r
-               buttonLayout.addWidget(cutButton);\r
-               buttonLayout.addWidget(copyButton);\r
-               buttonLayout.addWidget(pasteButton);\r
-\r
-               buttonLayout.addWidget(newSeparator(), 0);\r
-               buttonLayout.addWidget(boldButton);\r
-               buttonLayout.addWidget(italicButton);\r
-               buttonLayout.addWidget(underlineButton);\r
-               buttonLayout.addWidget(strikethroughButton);\r
-               \r
-               buttonLayout.addWidget(newSeparator(), 0);\r
-               buttonLayout.addWidget(leftAlignButton);\r
-               buttonLayout.addWidget(centerAlignButton);\r
-               buttonLayout.addWidget(rightAlignButton);\r
-\r
-               buttonLayout.addWidget(newSeparator(), 0);\r
-               buttonLayout.addWidget(hlineButton);\r
-\r
-               buttonLayout.addWidget(indentButton);\r
-               buttonLayout.addWidget(outdentButton);\r
-               buttonLayout.addWidget(bulletListButton);\r
-               buttonLayout.addWidget(numberListButton);\r
+               undoButton = newEditorButton("undo", tr("Undo Change"));\r
+               redoButton = newEditorButton("redo", tr("Redo Change"));\r
+               cutButton = newEditorButton("cut", tr("Cut"));\r
+               copyButton = newEditorButton("copy", tr("Copy"));\r
+               pasteButton = newEditorButton("paste", tr("Paste"));\r
+               boldButton = newEditorButton("bold", tr("Bold"));\r
+               underlineButton = newEditorButton("underline", tr("Underline"));\r
+               italicButton = newEditorButton("italic", tr("Italic"));\r
+\r
+               rightAlignButton = newEditorButton("justifyRight", tr("Right Align"));\r
+               leftAlignButton = newEditorButton("justifyLeft", tr("Left Align"));\r
+               centerAlignButton = newEditorButton("justifyCenter", tr("Center Align"));\r
+\r
+               strikethroughButton = newEditorButton("strikethrough", tr("Strikethrough"));\r
+               hlineButton = newEditorButton("hline", tr("Insert Horizontal Line"));\r
+               indentButton = newEditorButton("indent", tr("Shift Right"));\r
+               outdentButton = newEditorButton("outdent", tr("Shift Left"));\r
+               bulletListButton = newEditorButton("bulletList", tr("Bullet List"));\r
+               numberListButton = newEditorButton("numberList", tr("Number List"));\r
+               spellCheckButton = newEditorButton("spellCheck", tr("Spell Check"));\r
+               todoButton = newEditorButton("todo", tr("To-do"));\r
+\r
+               \r
+               buttonLayout = new EditorButtonBar();\r
+               v.addWidget(buttonLayout);\r
+               \r
+               undoAction = buttonLayout.addWidget(undoButton);\r
+               buttonLayout.toggleUndoVisible.triggered.connect(this, "toggleUndoVisible(Boolean)");\r
+               redoAction = buttonLayout.addWidget(redoButton);\r
+               buttonLayout.toggleRedoVisible.triggered.connect(this, "toggleRedoVisible(Boolean)");\r
+               \r
+               buttonLayout.addWidget(newSeparator());\r
+               cutAction = buttonLayout.addWidget(cutButton);\r
+               buttonLayout.toggleCutVisible.triggered.connect(this, "toggleCutVisible(Boolean)");\r
+               copyAction = buttonLayout.addWidget(copyButton);\r
+               buttonLayout.toggleCopyVisible.triggered.connect(this, "toggleCopyVisible(Boolean)");\r
+               pasteAction = buttonLayout.addWidget(pasteButton);\r
+               buttonLayout.togglePasteVisible.triggered.connect(this, "togglePasteVisible(Boolean)");\r
+\r
+               buttonLayout.addWidget(newSeparator());\r
+               boldAction = buttonLayout.addWidget(boldButton);\r
+               buttonLayout.toggleBoldVisible.triggered.connect(this, "toggleBoldVisible(Boolean)");\r
+               italicAction = buttonLayout.addWidget(italicButton);\r
+               buttonLayout.toggleItalicVisible.triggered.connect(this, "toggleItalicVisible(Boolean)");\r
+               underlineAction = buttonLayout.addWidget(underlineButton);\r
+               buttonLayout.toggleUnderlineVisible.triggered.connect(this, "toggleUnderlineVisible(Boolean)");\r
+               strikethroughAction = buttonLayout.addWidget(strikethroughButton);\r
+               buttonLayout.toggleStrikethroughVisible.triggered.connect(this, "toggleStrikethroughVisible(Boolean)");\r
+\r
+               \r
+               buttonLayout.addWidget(newSeparator());\r
+               leftAlignAction = buttonLayout.addWidget(leftAlignButton);\r
+               buttonLayout.toggleLeftAlignVisible.triggered.connect(this, "toggleLeftAlignVisible(Boolean)");\r
+               centerAlignAction = buttonLayout.addWidget(centerAlignButton);\r
+               buttonLayout.toggleCenterAlignVisible.triggered.connect(this, "toggleCenterAlignVisible(Boolean)");\r
+               rightAlignAction = buttonLayout.addWidget(rightAlignButton);\r
+               buttonLayout.toggleRightAlignVisible.triggered.connect(this, "toggleRightAlignVisible(Boolean)");\r
+\r
+               buttonLayout.addWidget(newSeparator());\r
+               hlineAction = buttonLayout.addWidget(hlineButton);\r
+               buttonLayout.toggleHLineVisible.triggered.connect(this, "toggleHLineVisible(Boolean)");\r
+\r
+               indentAction = buttonLayout.addWidget(indentButton);\r
+               buttonLayout.toggleIndentVisible.triggered.connect(this, "toggleIndentVisible(Boolean)");\r
+               outdentAction = buttonLayout.addWidget(outdentButton);\r
+               buttonLayout.toggleOutdentVisible.triggered.connect(this, "toggleOutdentVisible(Boolean)");\r
+               bulletListAction = buttonLayout.addWidget(bulletListButton);\r
+               buttonLayout.toggleBulletListVisible.triggered.connect(this, "toggleBulletListVisible(Boolean)");\r
+               numberListAction = buttonLayout.addWidget(numberListButton);\r
+               buttonLayout.toggleNumberListVisible.triggered.connect(this, "toggleNumberListVisible(Boolean)");\r
 \r
                // Setup the font & font size combo boxes\r
-               buttonLayout.addWidget(newSeparator(), 0);\r
+               buttonLayout.addWidget(newSeparator());\r
                fontList = new QComboBox();\r
                fontSize = new QComboBox();\r
                fontList.setToolTip("Font");\r
                fontSize.setToolTip("Font Size");\r
                fontList.activated.connect(this, "fontChanged(String)");\r
                fontSize.activated.connect(this, "fontSizeChanged(String)");\r
-               buttonLayout.addWidget(fontList, 0);\r
-               buttonLayout.addWidget(fontSize, 0);\r
+               fontListAction = buttonLayout.addWidget(fontList);\r
+               buttonLayout.toggleFontVisible.triggered.connect(this, "toggleFontListVisible(Boolean)");\r
+               fontSizeAction = buttonLayout.addWidget(fontSize);\r
+               buttonLayout.toggleFontSizeVisible.triggered.connect(this, "toggleFontSizeVisible(Boolean)");\r
                QFontDatabase fonts = new QFontDatabase();\r
                List<String> fontFamilies = fonts.families();\r
                for (int i = 0; i < fontFamilies.size(); i++) {\r
@@ -389,21 +557,47 @@ public class BrowserWindow extends QWidget {
                        }\r
                }\r
 \r
-               buttonLayout.addWidget(newSeparator(), 0);\r
-               fontColor = newEditorButton("fontColor", "Font Color");\r
+//             buttonLayout.addWidget(newSeparator(), 0);\r
+               fontColor = newToolButton("fontColor", tr("Font Color"));\r
                fontColorMenu = new ColorMenu(this);\r
                fontColor.setMenu(fontColorMenu.getMenu());\r
+               fontColor.setPopupMode(ToolButtonPopupMode.MenuButtonPopup);\r
+               fontColor.setAutoRaise(false);\r
                fontColorMenu.getMenu().triggered.connect(this, "fontColorClicked()");\r
-               buttonLayout.addWidget(fontColor);\r
-               fontHilight = newEditorButton("fontHilight", "Font Hilight Color");\r
+               fontColorAction = buttonLayout.addWidget(fontColor);\r
+               buttonLayout.toggleFontColorVisible.triggered.connect(this, "toggleFontColorVisible(Boolean)");\r
+               fontHilight = newToolButton("fontHilight", tr("Font Hilight Color"));\r
+               fontHilight.setPopupMode(ToolButtonPopupMode.MenuButtonPopup);\r
+               fontHilight.setAutoRaise(false);\r
                fontHilightColorMenu = new ColorMenu(this);\r
+               fontHilightColorMenu.setDefault(QColor.yellow);\r
                fontHilight.setMenu(fontHilightColorMenu.getMenu());\r
                fontHilightColorMenu.getMenu().triggered.connect(this, "fontHilightClicked()");\r
-               buttonLayout.addWidget(fontHilight);\r
+               fontHilightAction = buttonLayout.addWidget(fontHilight);\r
+               fontHilightColorMenu.setDefault(QColor.yellow);\r
+               buttonLayout.toggleFontHilight.triggered.connect(this, "toggleFontHilightVisible(Boolean)");\r
+               \r
+               spellCheckAction = buttonLayout.addWidget(spellCheckButton);\r
+               buttonLayout.toggleNumberListVisible.triggered.connect(this, "spellCheckClicked()");\r
+               buttonLayout.toggleSpellCheck.triggered.connect(this, "toggleSpellCheckVisible(Boolean)");\r
+               \r
+               todoAction = buttonLayout.addWidget(todoButton);\r
+               buttonLayout.toggleNumberListVisible.triggered.connect(this, "todoClicked()");\r
+               buttonLayout.toggleTodo.triggered.connect(this, "toggleTodoVisible(Boolean)");\r
+\r
+               // Setup the source browser);\r
 \r
-               buttonLayout.addWidget(new QLabel(), 1);\r
-               v.addWidget(browser, 1);\r
-//             v.addLayout(buttonLayout,0);\r
+//             buttonLayout.addWidget(new QLabel(), 1);\r
+               QSplitter editSplitter = new QSplitter(this);\r
+               editSplitter.addWidget(browser);\r
+               editSplitter.setOrientation(Qt.Orientation.Vertical);\r
+               editSplitter.addWidget(sourceEdit);\r
+\r
+               \r
+\r
+//             v.addWidget(browser, 1);\r
+//             v.addWidget(sourceEdit);\r
+               v.addWidget(editSplitter);\r
                setLayout(v);\r
 \r
                browser.downloadAttachmentRequested.connect(this,\r
@@ -432,13 +626,39 @@ public class BrowserWindow extends QWidget {
                browser.page().mainFrame().setTextSizeMultiplier(Global.getTextSizeMultiplier());\r
                browser.page().mainFrame().setZoomFactor(Global.getZoomFactor());\r
                \r
-                previewPageList = new HashMap<String,Integer>();\r
+               previewPageList = new HashMap<String,Integer>();\r
                \r
                browser.page().microFocusChanged.connect(this, "microFocusChanged()");\r
+               \r
+               //Setup colors\r
+               \r
+               QPalette pal = new QPalette();\r
+               pal.setColor(ColorRole.Text, QColor.black);\r
+               titleLabel.setPalette(pal);\r
+               authorText.setPalette(pal);\r
+               authorLabel.setPalette(pal);\r
+               urlLabel.setPalette(pal);\r
+               urlText.setPalette(pal);\r
+               createdDate.setPalette(pal);\r
+               createdTime.setPalette(pal);\r
+               alteredDate.setPalette(pal);\r
+               alteredTime.setPalette(pal);\r
+               subjectDate.setPalette(pal);\r
+               subjectTime.setPalette(pal);\r
+               tagEdit.setPalette(pal);\r
+               notebookBox.setPalette(pal);\r
+               \r
+               blockApplication = new Signal1<BrowserWindow>();\r
+               unblockApplication = new Signal0();\r
+               \r
+               setSourceTimer = new QTimer();\r
+               setSourceTimer.timeout.connect(this, "setSource()");\r
+               \r
                logger.log(logger.HIGH, "Browser setup complete");\r
        }\r
 \r
        \r
+       \r
        private void setupShortcut(QShortcut action, String text) {\r
                if (!Global.shortcutKeys.containsAction(text))\r
                        return;\r
@@ -486,7 +706,12 @@ public class BrowserWindow extends QWidget {
                createdDate.setEnabled(!v);\r
                subjectDate.setEnabled(!v);\r
                alteredDate.setEnabled(!v);\r
+               authorText.setEnabled(!v);\r
+               createdTime.setEnabled(!v);\r
+               alteredTime.setEnabled(!v);\r
+               subjectTime.setEnabled(!v);\r
                getBrowser().setEnabled(true);\r
+//             getBrowser().setEnabled(!v);\r
        }\r
        \r
        // expose this class to Javascript on the web page\r
@@ -508,13 +733,19 @@ public class BrowserWindow extends QWidget {
        public void clear() {\r
                logger.log(logger.EXTREME, "Entering BrowserWindow.clear()");\r
                setNote(null);\r
-               browser.setContent(new QByteArray());\r
+               setContent(new QByteArray());\r
                tagEdit.setText("");\r
-               urlLabel.setText("Source URL:");\r
+               tagEdit.tagCompleter.reset();\r
+               urlLabel.setText(tr("Source URL:"));\r
                titleLabel.setText("");\r
                logger.log(logger.EXTREME, "Exiting BrowserWindow.clear()");\r
        }\r
 \r
+       public void setContent(QByteArray data) {\r
+               sourceEdit.blockSignals(true);\r
+               browser.setContent(data);\r
+               setSource();\r
+       }\r
        // get/set current note\r
        public void setNote(Note n) {\r
                currentNote = n;\r
@@ -531,7 +762,18 @@ 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
+               return button;\r
+       }\r
+       // 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 + ".png");\r
                button.setIcon(icon);\r
                button.setToolTip(toolTip);\r
                button.clicked.connect(this, name + "Clicked()");\r
@@ -559,16 +801,32 @@ public class BrowserWindow extends QWidget {
        public void setTag(String t) {\r
                saveTagList = t;\r
                tagEdit.setText(t);\r
+               tagEdit.tagCompleter.reset();\r
        }\r
 \r
        // Set the source URL\r
        public void setUrl(String t) {\r
-               urlLabel.setText("Source URL:\t");\r
+               urlLabel.setText(tr("Source URL:\t"));\r
                urlText.setText(t);\r
        }\r
 \r
+       // The user want's to launch a web browser on the source of the URL\r
+       public void sourceUrlClicked() {\r
+               // Make sure we have a valid URL\r
+               if (urlText.text().trim().equals(""))\r
+                       return;\r
+               \r
+               String url = urlText.text();\r
+               if (!url.toLowerCase().startsWith(tr("http://")))\r
+                       url = tr("http://") +url;\r
+               \r
+        if (!QDesktopServices.openUrl(new QUrl(url))) {\r
+               logger.log(logger.LOW, "Error opening file :" +url);\r
+        }\r
+       }\r
+       \r
        public void setAuthor(String t) {\r
-               authorLabel.setText("Author:\t");\r
+               authorLabel.setText(tr("Author:\t"));\r
                authorText.setText(t);\r
        }\r
 \r
@@ -629,33 +887,8 @@ public class BrowserWindow extends QWidget {
 \r
        public void hideButtons() {\r
 \r
+               undoButton.parentWidget().setVisible(false);\r
                buttonsVisible = false;\r
-               \r
-               undoButton.setVisible(false);\r
-               redoButton.setVisible(false);\r
-               cutButton.setVisible(false);\r
-               copyButton.setVisible(false);\r
-               pasteButton.setVisible(false);\r
-               boldButton.setVisible(false);\r
-               underlineButton.setVisible(false);\r
-               italicButton.setVisible(false);\r
-\r
-               rightAlignButton.setVisible(false);\r
-               leftAlignButton.setVisible(false);\r
-               centerAlignButton.setVisible(false);\r
-\r
-               strikethroughButton.setVisible(false);\r
-               hlineButton.setVisible(false);\r
-               indentButton.setVisible(false);\r
-               outdentButton.setVisible(false);\r
-               bulletListButton.setVisible(false);\r
-               numberListButton.setVisible(false);\r
-\r
-               fontList.setVisible(false);\r
-               fontSize.setVisible(false);\r
-               fontColor.setVisible(false);\r
-               fontHilight.setVisible(false);\r
-\r
        }\r
 \r
 \r
@@ -687,13 +920,33 @@ public class BrowserWindow extends QWidget {
        @SuppressWarnings("unused")\r
        private void linkClicked(QUrl url) {\r
                logger.log(logger.EXTREME, "URL Clicked: " +url.toString());\r
-               if (url.toString().substring(0,8).equals("nnres://")) {\r
+               if (url.toString().startsWith("latex:")) {\r
+                       int position = url.toString().lastIndexOf(".");\r
+                       String guid = url.toString().substring(0,position);\r
+                       position = guid.lastIndexOf("/");\r
+                       guid = guid.substring(position+1);\r
+                       editLatex(guid);\r
+                       return;\r
+               }\r
+               if (url.toString().startsWith("evernote:/view/")) {\r
+                       StringTokenizer tokens = new StringTokenizer(url.toString().replace("evernote:/view/", ""), "/");\r
+                       tokens.nextToken();\r
+                       tokens.nextToken();\r
+                       String sid = tokens.nextToken();\r
+                       String lid = tokens.nextToken();\r
+                       \r
+                       // Emit that we want to switch to a new note\r
+                       evernoteLinkClicked.emit(sid, lid);\r
+\r
+                       return;\r
+               }\r
+               if (url.toString().startsWith("nnres://")) {\r
                        logger.log(logger.EXTREME, "URL is NN resource");\r
                        if (url.toString().endsWith("/vnd.evernote.ink")) {\r
                                logger.log(logger.EXTREME, "Unable to open ink note");\r
-                               QMessageBox.information(this, "Unable Open", "This is an ink note.\n"+\r
+                               QMessageBox.information(this, tr("Unable Open"), tr("This is an ink note.\n"+\r
                                        "Ink notes are not supported since Evernote has not\n published any specifications on them\n" +\r
-                                       "and I'm too lazy to figure them out by myself.");\r
+                                       "and I'm too lazy to figure them out by myself."));\r
                                return;\r
                        }\r
                        String fullName = url.toString().substring(8);\r
@@ -838,7 +1091,7 @@ public class BrowserWindow extends QWidget {
        }\r
 \r
        // Listener when PASTE is clicked\r
-       void pasteClicked() {\r
+       public void pasteClicked() {\r
                logger.log(logger.EXTREME, "Paste Clicked");\r
                if (forceTextPaste) {\r
                        pasteWithoutFormattingClicked();\r
@@ -851,6 +1104,7 @@ public class BrowserWindow extends QWidget {
 \r
                if (mime.hasImage()) {\r
                        logger.log(logger.EXTREME, "Image paste found");\r
+                       browser.setFocus();\r
                        insertImage(mime);\r
                        browser.setFocus();\r
                        return;\r
@@ -858,8 +1112,12 @@ public class BrowserWindow extends QWidget {
 \r
                if (mime.hasUrls()) {\r
                        logger.log(logger.EXTREME, "URL paste found");\r
-                       handleUrls(mime);\r
-                       browser.setFocus();\r
+                       if (!mime.text().startsWith("evernote:")) {\r
+                               handleNoteLink(mime);\r
+                       } else {\r
+                               handleUrls(mime);\r
+                               browser.setFocus();\r
+                       }\r
                        return;\r
                }\r
                \r
@@ -885,11 +1143,40 @@ public class BrowserWindow extends QWidget {
                if (!mime.hasText())\r
                        return;\r
                String text = mime.text();\r
-               clipboard.setText(text);\r
+               clipboard.clear();\r
+               clipboard.setText(text, Mode.Clipboard);\r
                browser.page().triggerAction(WebAction.Paste);\r
-               QApplication.clipboard().setMimeData(mime);\r
-               browser.setFocus();\r
 \r
+               // This is done because pasting into an encryption block\r
+               // can cause multiple cells (which can't happen).  It \r
+               // just goes through the table, extracts the data, & \r
+               // puts it back as one table cell.\r
+               if (insideEncryption) {\r
+                       String js = new String( "function fixEncryption() { "\r
+                                       +"   var selObj = window.getSelection();"\r
+                                       +"   var selRange = selObj.getRangeAt(0);"\r
+                                       +"   var workingNode = window.getSelection().anchorNode;"\r
+                                       +"   while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { " \r
+                                       +"           workingNode = workingNode.parentNode;"\r
+                                       +"   } "\r
+                                       +"   workingNode.innerHTML = window.jambi.fixEncryptionPaste(workingNode.innerHTML);"\r
+                                       +"} fixEncryption();");\r
+                       browser.page().mainFrame().evaluateJavaScript(js);\r
+               }\r
+       }\r
+       \r
+       // This basically removes all the table tags and returns just the contents.\r
+       // This is called by JavaScript to fix encryption pastes.\r
+       public String fixEncryptionPaste(String data) {\r
+               data = data.replace("<tbody>", "");\r
+               data = data.replace("</tbody>", "");\r
+               data = data.replace("<tr>", "");\r
+               data = data.replace("</tr>", "");\r
+               data = data.replace("<td>", "");\r
+               data = data.replace("</td>", "<br>");\r
+               data = data.replace("<br><br>", "<br>");\r
+\r
+               return "<tbody><tr><td>"+data+"</td></tr></tbody>";\r
        }\r
        \r
        // insert date/time\r
@@ -1063,7 +1350,9 @@ public class BrowserWindow extends QWidget {
                                "document.execCommand('insertHtml', false, '");\r
                String script_end = new String("');");\r
                String todo = new String(\r
-                               "<input TYPE=\"CHECKBOX\" value=\"false\" onClick=\"value=checked; window.jambi.contentChanged(); \" />");\r
+                               "<input TYPE=\"CHECKBOX\" value=\"false\" " +\r
+                               "onMouseOver=\"style.cursor=\\'hand\\'\" " +\r
+                               "onClick=\"value=checked; window.jambi.contentChanged(); \" />");\r
                browser.page().mainFrame().evaluateJavaScript(\r
                                script_start + todo + script_end);\r
                browser.setFocus();\r
@@ -1075,6 +1364,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
@@ -1084,9 +1374,10 @@ 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, "Error", "Error Encrypting String");\r
+                       QMessageBox.information(this, tr("Error"), tr("Error Encrypting String"));\r
                        return;\r
                }\r
                StringBuffer buffer = new StringBuffer(encrypted.length() + 100);\r
@@ -1094,8 +1385,7 @@ 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
+               buffer.append("\" src=\"").append(FileUtils.toForwardSlashedPath(Global.getFileManager().getImageDirPath("encrypt.png") +"\""));\r
                Global.cryptCounter++;\r
                buffer.append(" id=\"crypt"+Global.cryptCounter.toString() +"\"");\r
                buffer.append(" onMouseOver=\"style.cursor=\\'hand\\'\"");\r
@@ -1110,7 +1400,39 @@ public class BrowserWindow extends QWidget {
                                script_start + buffer.toString() + script_end);\r
        }\r
 \r
-       \r
+\r
+       // Insert a Quick hyperlink\r
+       public void insertQuickLink() {\r
+               logger.log(logger.EXTREME, "Inserting link");\r
+               String text = browser.selectedText();\r
+               if (text.trim().equalsIgnoreCase(""))\r
+                       return;\r
+\r
+               NoteQuickLinkDialog dialog = new NoteQuickLinkDialog(logger, conn, text);\r
+               if (dialog.getResults().size() == 0) {\r
+                       QMessageBox.critical(null, tr("No Matches Found") ,tr("No matching notes found."));\r
+                       return;\r
+               }\r
+               if (dialog.getResults().size() > 1) {\r
+                       dialog.exec();\r
+                       if (!dialog.okPressed) {\r
+                               logger.log(logger.EXTREME, "Insert link canceled");\r
+                               return;\r
+                       }\r
+               }\r
+\r
+               User user = Global.getUserInformation();\r
+               String dUrl = new String("evernote:///view/") + new String(user.getId() + "/" +user.getShardId() +"/"\r
+                               +dialog.getSelectedNote()+"/"+dialog.getSelectedNote() +"/ " +"style=\"color:#69aa35\"");\r
+               \r
+               String url = "<a title=\"" +dUrl\r
+                               +"\" href=" +dUrl \r
+                               +" >"+text +"</a>";\r
+               String script = "document.execCommand('insertHtml', false, '"+url+"');";\r
+               browser.page().mainFrame().evaluateJavaScript(script);  \r
+               contentChanged();\r
+       }\r
+\r
        // Insert a hyperlink\r
        public void insertLink() {\r
                logger.log(logger.EXTREME, "Inserting link");\r
@@ -1118,7 +1440,7 @@ public class BrowserWindow extends QWidget {
                if (text.trim().equalsIgnoreCase(""))\r
                        return;\r
 \r
-               InsertLinkDialog dialog = new InsertLinkDialog();\r
+               InsertLinkDialog dialog = new InsertLinkDialog(insertHyperlink);\r
                if (currentHyperlink != null && currentHyperlink != "") {\r
                        dialog.setUrl(currentHyperlink);\r
                }\r
@@ -1127,32 +1449,220 @@ public class BrowserWindow extends QWidget {
                        logger.log(logger.EXTREME, "Insert link canceled");\r
                        return;\r
                }\r
-               if (browser.insertLinkAction.text().equalsIgnoreCase("Insert Hyperlink")) {\r
+               \r
+               // Take care of inserting new links\r
+               if (insertHyperlink) {\r
                        String selectedText = browser.selectedText();\r
+                       if (dialog.getUrl().trim().equals(""))\r
+                               return;\r
                        logger.log(logger.EXTREME, "Inserting link on text "+selectedText);\r
                        logger.log(logger.EXTREME, "URL Link " +dialog.getUrl().trim());\r
-                       String url = "<a href=\"" +dialog.getUrl().trim()+"\" >"+selectedText +"</a>";\r
+                       String dUrl = StringUtils.replace(dialog.getUrl().trim(), "'", "\\'");\r
+                       String url = "<a href=\"" +dUrl\r
+                                       +"\" title=" +dUrl \r
+                                       +" >"+selectedText +"</a>";\r
                        String script = "document.execCommand('insertHtml', false, '"+url+"');";\r
                        browser.page().mainFrame().evaluateJavaScript(script);\r
                        return;\r
+               }\r
+               \r
+               // Edit existing links\r
+               String js = new String( "function getCursorPos() {"\r
+                               +"var cursorPos;"\r
+                               +"if (window.getSelection) {"\r
+                               +"   var selObj = window.getSelection();"\r
+                               +"   var selRange = selObj.getRangeAt(0);"\r
+                               +"   var workingNode = window.getSelection().anchorNode.parentNode;"\r
+                               +"   while(workingNode != null) { " \r
+                               +"      if (workingNode.nodeName.toLowerCase()=='a') workingNode.setAttribute('href','" +dialog.getUrl() +"');"\r
+                               +"      workingNode = workingNode.parentNode;"\r
+                               +"   }"\r
+                               +"}"\r
+                               +"} getCursorPos();");\r
+                       browser.page().mainFrame().evaluateJavaScript(js);\r
+               \r
+               if (!dialog.getUrl().trim().equals("")) {\r
+                       contentChanged();\r
+                       return;\r
+               }\r
+               \r
+               // Remove URL\r
+               js = new String( "function getCursorPos() {"\r
+                               +"var cursorPos;"\r
+                               +"if (window.getSelection) {"\r
+                               +"   var selObj = window.getSelection();"\r
+                               +"   var selRange = selObj.getRangeAt(0);"\r
+                               +"   var workingNode = window.getSelection().anchorNode.parentNode;"\r
+                               +"   while(workingNode != null) { " \r
+                               +"      if (workingNode.nodeName.toLowerCase()=='a') { "\r
+                               +"         workingNode.removeAttribute('href');"\r
+                               +"         workingNode.removeAttribute('title');"\r
+                               +"         var text = document.createTextNode(workingNode.innerText);"\r
+                               +"         workingNode.parentNode.insertBefore(text, workingNode);"\r
+                               +"         workingNode.parentNode.removeChild(workingNode);"\r
+                               +"      }"\r
+                               +"      workingNode = workingNode.parentNode;"\r
+                               +"   }"\r
+                               +"}"\r
+                               +"} getCursorPos();");\r
+                       browser.page().mainFrame().evaluateJavaScript(js);\r
+                       \r
+                       contentChanged();\r
+\r
+               \r
+       }\r
+       \r
+       \r
+       // Insert a hyperlink\r
+       public void insertLatex() {\r
+               editLatex(null);\r
+       }\r
+       public void editLatex(String guid) {\r
+               logger.log(logger.EXTREME, "Inserting latex");\r
+               String text = browser.selectedText();\r
+               if (text.trim().equalsIgnoreCase(" ") || text.trim().equalsIgnoreCase("")) {\r
+                       InsertLatexImage dialog = new InsertLatexImage();\r
+                       if (guid != null) {\r
+                               String formula = conn.getNoteTable().noteResourceTable.getNoteSourceUrl(guid).replace("http://latex.codecogs.com/gif.latex?", "");\r
+                               dialog.setFormula(formula);\r
+                       }\r
+                       dialog.exec();\r
+                       if (!dialog.okPressed()) {\r
+                               logger.log(logger.EXTREME, "Edit LaTex canceled");\r
+                               return;\r
+                       }\r
+                       text = dialog.getFormula().trim();\r
+               }\r
+               blockApplication.emit(this);\r
+               logger.log(logger.EXTREME, "Inserting LaTeX formula:" +text);\r
+               latexGuid = guid;\r
+               text = StringUtils.replace(text, "'", "\\'");\r
+               String url = "http://latex.codecogs.com/gif.latex?" +text;\r
+               logger.log(logger.EXTREME, "Sending request to codecogs --> " + url);\r
+               QNetworkAccessManager manager = new QNetworkAccessManager(this);\r
+               manager.finished.connect(this, "insertLatexImageReady(QNetworkReply)");\r
+               unblockTime = new GregorianCalendar().getTimeInMillis()+5000;\r
+               awaitingHttpResponse = true;\r
+               manager.get(new QNetworkRequest(new QUrl(url)));\r
+       }\r
+       \r
+       public void insertLatexImageReady(QNetworkReply reply) {\r
+               logger.log(logger.EXTREME, "Response received from CodeCogs");\r
+               if (reply.error() != NetworkError.NoError) \r
+                       return;\r
+\r
+               unblockTime = -1;\r
+               if (!awaitingHttpResponse)\r
+                       return;\r
+               \r
+               awaitingHttpResponse = false;\r
+               QUrl replyUrl = reply.url();            \r
+               QByteArray image = reply.readAll();\r
+               reply.close();\r
+               logger.log(logger.EXTREME, "New image size: " +image.size());\r
+\r
+               Resource newRes = null;\r
+               QFile tfile;\r
+               String path;\r
+               if (latexGuid == null) {\r
+                       logger.log(logger.EXTREME, "Creating temporary gif");                   \r
+                       path = Global.getFileManager().getResDirPath("latex-temp.gif");\r
+                       tfile = new QFile(path);\r
+                       tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));\r
+                       logger.log(logger.EXTREME, "File Open: " +tfile.errorString());\r
+                       tfile.write(image);\r
+                       logger.log(logger.EXTREME, "Bytes writtes: "+tfile.size());\r
+                       tfile.close();\r
+                       logger.log(logger.EXTREME, "Creating resource");\r
+                       int sequence = 0;\r
+                       if (currentNote.getResources() != null || currentNote.getResources().size() > 0)\r
+                               sequence = currentNote.getResources().size();\r
+                       newRes = createResource(path,sequence ,"image/gif", false);\r
+                       QImage pix = new QImage();\r
+                       pix.loadFromData(image);\r
+                       newRes.setHeight(new Integer(pix.height()).shortValue());\r
+                       newRes.setWidth(new Integer(pix.width()).shortValue());\r
+                       logger.log(logger.EXTREME, "Renaming temporary file to " +newRes.getGuid()+".gif");\r
+                       path = Global.getFileManager().getResDirPath(newRes.getGuid()+".gif");\r
+                       tfile.rename(path);\r
                } else {\r
-                       String js = new String( "function getCursorPos() {"\r
-                                       +"var cursorPos;"\r
-                                       +"if (window.getSelection) {"\r
-                                       +"   var selObj = window.getSelection();"\r
-                                       +"   var selRange = selObj.getRangeAt(0);"\r
-                                       +"   var workingNode = window.getSelection().anchorNode.parentNode;"\r
-                                       +"   while(workingNode != null) { " \r
-                                       +"      if (workingNode.nodeName.toLowerCase()=='a') workingNode.setAttribute('href','" +dialog.getUrl() +"');"\r
-                                       +"      workingNode = workingNode.parentNode;"\r
-                                       +"   }"\r
-                                       +"}"\r
-                                       +"} getCursorPos();");\r
-                               browser.page().mainFrame().evaluateJavaScript(js);\r
-                               contentChanged();\r
+                       newRes = conn.getNoteTable().noteResourceTable.getNoteResource(latexGuid, false);\r
+                       path = Global.getFileManager().getResDirPath(newRes.getGuid()+".gif");\r
+                       tfile = new QFile(path);\r
+                       tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));\r
+                       tfile.write(image);\r
+                       tfile.close();\r
+                       newRes.getData().setBody(image.toByteArray());\r
+                       // Calculate the new hash value\r
+               MessageDigest md;\r
+\r
+               logger.log(logger.EXTREME, "Generating MD5");\r
+               try {\r
+                               md = MessageDigest.getInstance("MD5");\r
+                       md.update(image.toByteArray());\r
+                       byte[] hash = md.digest();\r
+                       newRes.getData().setBodyHash(hash);\r
+                       } catch (NoSuchAlgorithmException e) {\r
+                               e.printStackTrace();\r
+                       }\r
+                       QImage pix = new QImage();\r
+                       pix.loadFromData(image);\r
+                       newRes.setHeight(new Integer(pix.height()).shortValue());\r
+                       newRes.setWidth(new Integer(pix.width()).shortValue());\r
+                       conn.getNoteTable().noteResourceTable.updateNoteResource(newRes, true);\r
+               }\r
+\r
+               logger.log(logger.EXTREME, "Setting source: " +replyUrl.toString());\r
+               newRes.getAttributes().setSourceURL(replyUrl.toString());\r
+               conn.getNoteTable().noteResourceTable.updateNoteSourceUrl(newRes.getGuid(), replyUrl.toString(), true);\r
+               \r
+               for(int i=0; i<currentNote.getResourcesSize(); i++) {\r
+                       if (currentNote.getResources().get(i).getGuid().equals(newRes.getGuid())) {\r
+                               currentNote.getResources().remove(i);\r
+                               i=currentNote.getResourcesSize();\r
+                       }\r
+               }\r
+               currentNote.getResources().add(newRes);\r
+               \r
+\r
+               // do the actual insert into the note.  We only do this on new formulas.  \r
+               if (latexGuid == null) {\r
+                       StringBuffer buffer = new StringBuffer(100);\r
+                       String formula = replyUrl.toString().toLowerCase().replace("http://latex.codecogs.com/gif.latex?", "");\r
+                       buffer.append("<a href=\"latex://"+path.replace("\\", "/")+"\" title=\""+formula+"\""\r
+                                       +"><img src=\"");\r
+                       buffer.append(path.replace("\\", "/"));\r
+                       buffer.append("\" en-tag=\"en-latex\" type=\"image/gif\""\r
+                               +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""\r
+                               +" guid=\"" +newRes.getGuid() +"\""\r
+                               + " /></a>");\r
+               \r
+                       String script_start = new String("document.execCommand('insertHTML', false, '");\r
+                       String script_end = new String("');");\r
+                       browser.page().mainFrame().evaluateJavaScript(\r
+                                       script_start + buffer + script_end);\r
+               } else {\r
+                       HtmlTagModifier modifier = new HtmlTagModifier(getContent());\r
+                       modifier.modifyLatexTagHash(newRes);\r
+                       String newContent = modifier.getHtml();\r
+                       setContent(new QByteArray(newContent));\r
                }\r
+\r
+               logger.log(logger.EXTREME, "New HTML set\n" +browser.page().currentFrame().toHtml());\r
+               QWebSettings.setMaximumPagesInCache(0);\r
+               QWebSettings.setObjectCacheCapacities(0, 0, 0);\r
+               \r
+               browser.page().mainFrame().setHtml(browser.page().mainFrame().toHtml());\r
+               browser.reload();\r
+               contentChanged();\r
+//             resourceSignal.contentChanged.emit(path);\r
+               unblockTime = -1;\r
+       unblockApplication.emit();\r
+               return;\r
                \r
        }\r
+\r
+       \r
        \r
        // Insert a table\r
        public void insertTable() {\r
@@ -1191,6 +1701,7 @@ public class BrowserWindow extends QWidget {
        private void selectionChanged() {\r
                browser.encryptAction.setEnabled(true);\r
                browser.insertLinkAction.setEnabled(true);\r
+               browser.insertQuickLinkAction.setEnabled(true);\r
                String scriptStart = "var selection_text = (window.getSelection()).toString();"\r
                                + "var range = (window.getSelection()).getRangeAt(0);"\r
                                + "var parent_html = range.commonAncestorContainer.innerHTML;"\r
@@ -1220,6 +1731,7 @@ public class BrowserWindow extends QWidget {
                \r
                browser.encryptAction.setEnabled(enabled);\r
                browser.insertLinkAction.setEnabled(enabled);\r
+               browser.insertQuickLinkAction.setEnabled(enabled);\r
 //             selectedText = text;\r
        }\r
 \r
@@ -1233,7 +1745,7 @@ 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
                                Global.passwordSafe.put(slot, Global.passwordRemember.get(i));\r
@@ -1252,13 +1764,21 @@ public class BrowserWindow extends QWidget {
                        }\r
                        plainText = crypt.decrypt(text, dialog.getPassword().trim(), 64);\r
                        if (plainText == null) {\r
-                               QMessageBox.warning(this, "Incorrect Password", "The password entered is not correct");\r
+                               QMessageBox.warning(this, tr("Incorrect Password"), tr("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
@@ -1270,7 +1790,7 @@ public class BrowserWindow extends QWidget {
        // Modify a note's tags\r
        @SuppressWarnings("unused")\r
        private void modifyTags() {\r
-               TagAssign tagWindow = new TagAssign(allTags, currentTags);\r
+               TagAssign tagWindow = new TagAssign(allTags, currentTags, !conn.getNotebookTable().isLinked(currentNote.getNotebookGuid()));\r
                tagWindow.exec();\r
                if (tagWindow.okClicked()) {\r
                        currentTags.clear();\r
@@ -1293,15 +1813,48 @@ public class BrowserWindow extends QWidget {
        // Tag line has been modified by typing text\r
        @SuppressWarnings("unused")\r
        private void modifyTagsTyping() {\r
-\r
-               String newTags = tagEdit.text();\r
-               List<String> test = tagEdit.tagCompleter.getTagList();\r
-               if (newTags.equalsIgnoreCase(saveTagList))\r
+               String completionText = "";\r
+               if (tagEdit.currentCompleterSelection != null && !tagEdit.currentCompleterSelection.equals("")) {\r
+                       completionText = tagEdit.currentCompleterSelection;\r
+                       tagEdit.currentCompleterSelection = "";\r
+               }\r
+               \r
+               if (tagEdit.text().equalsIgnoreCase(saveTagList))\r
                        return;\r
 \r
                // We know something has changed...\r
                String oldTagArray[] = saveTagList.split(Global.tagDelimeter);\r
-               String newTagArray[] = newTags.split(Global.tagDelimeter);\r
+               String newTagArray[];\r
+               if (!completionText.equals("")) {\r
+                       String before = tagEdit.text().substring(0,tagEdit.cursorPosition());\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
+               else {\r
+                       newTagArray = tagEdit.text().split(Global.tagDelimeter);\r
+               }\r
+               \r
+               // Remove any traling or leading blanks\r
+               for (int i=0; i<newTagArray.length; i++)\r
+                       newTagArray[i] = newTagArray[i].trim().replaceAll("^\\s+", "");;\r
+               \r
+               // Remove any potential duplicates from the new list\r
+               for (int i=0; i<newTagArray.length; i++) {\r
+                       boolean foundOnce = false;\r
+                       for (int j=0; j<newTagArray.length; j++) {\r
+                               if (newTagArray[j].equalsIgnoreCase(newTagArray[i])) {\r
+                                       if (!foundOnce) {\r
+                                               foundOnce = true;\r
+                                       } else\r
+                                               newTagArray[j] = "";\r
+                               }\r
+                       }\r
+               }\r
 \r
                List<String> newTagList = new ArrayList<String>();\r
                List<String> oldTagList = new ArrayList<String>();\r
@@ -1313,6 +1866,32 @@ public class BrowserWindow extends QWidget {
                        if (!newTagArray[i].trim().equals(""))\r
                                newTagList.add(newTagArray[i]);\r
 \r
+               if (conn.getNotebookTable().isLinked(currentNote.getNotebookGuid())) {\r
+                       for (int i=newTagList.size()-1; i>=0; i--) {\r
+                               boolean found = false;\r
+                               for (int j=0; j<allTags.size(); j++) {\r
+                                       if (allTags.get(j).getName().equalsIgnoreCase(newTagList.get(i))) {\r
+                                               found = true;\r
+                                               j=allTags.size();\r
+                                       }\r
+                               }\r
+                               if (!found)\r
+                                       newTagList.remove(i);\r
+                       }\r
+               }\r
+\r
+               // Let's cleanup the appearance of the tag list\r
+               Collections.sort(newTagList);\r
+               String newDisplay = "";\r
+               for (int i=0; i<newTagList.size(); i++) {\r
+                       newDisplay = newDisplay+newTagList.get(i);\r
+                       if (i<newTagList.size()-1)\r
+                               newDisplay = newDisplay+Global.tagDelimeter +" ";\r
+               }\r
+               tagEdit.blockSignals(true);\r
+               tagEdit.setText(newDisplay);\r
+               tagEdit.blockSignals(false);\r
+               \r
                // We now have lists of the new & old. Remove duplicates. If all\r
                // are removed from both then nothing has really changed\r
                for (int i = newTagList.size() - 1; i >= 0; i--) {\r
@@ -1329,30 +1908,122 @@ public class BrowserWindow extends QWidget {
 \r
                if (oldTagList.size() != 0 || newTagList.size() != 0) {\r
                        currentTags.clear();\r
+                       newTagArray = tagEdit.text().split(Global.tagDelimeter);\r
                        for (int i = 0; i < newTagArray.length; i++)\r
                                if (!newTagArray[i].trim().equals(""))\r
                                        currentTags.add(newTagArray[i].trim());\r
 \r
                        noteSignal.tagsChanged.emit(currentNote.getGuid(), currentTags);\r
                }\r
-\r
+               \r
        }\r
 \r
        // Tab button was pressed\r
        public void tabPressed() {\r
-               if (!insideList) {\r
+               if (insideEncryption)\r
+                       return;\r
+               if (!insideList && !insideTable) {\r
                        String script_start = new String(\r
                        "document.execCommand('insertHtml', false, '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;');");\r
                        browser.page().mainFrame().evaluateJavaScript(script_start);\r
-               } else \r
+                       return;\r
+               }\r
+               if (insideList) {\r
                        indentClicked();\r
+               }\r
+               if (insideTable) {\r
+                       String js = new String( "function getCursorPosition() { "\r
+                                       +"   var selObj = window.getSelection();"\r
+                                       +"   var selRange = selObj.getRangeAt(0);"\r
+                                       +"   var workingNode = window.getSelection().anchorNode;"\r
+                                       +"   var rowCount = 0;"\r
+                                       +"   var colCount = 0;"\r
+                                       +"   while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { " \r
+                                       +"      if (workingNode.nodeName.toLowerCase()=='tr') {"\r
+                                       +"         rowCount = rowCount+1;"\r
+                                       +"      }"\r
+                                       +"      if (workingNode.nodeName.toLowerCase() == 'td') {"\r
+                                       +"         colCount = colCount+1;"\r
+                                       +"      }"\r
+                                       +"      if (workingNode.previousSibling != null)"\r
+                                       +"          workingNode = workingNode.previousSibling;"\r
+                                       +"      else "\r
+                                       +"           workingNode = workingNode.parentNode;"\r
+                                       +"   }"\r
+                                       +"   var nodes = workingNode.getElementsByTagName('tr');"\r
+                                       +"   var tableRows = nodes.length;"\r
+                                       +"   nodes = nodes[0].getElementsByTagName('td');"\r
+                                       +"   var tableColumns = nodes.length;"\r
+                                       +"   window.jambi.setTableCursorPositionTab(rowCount, colCount, tableRows, tableColumns);"\r
+                                       +"} getCursorPosition();");\r
+                       browser.page().mainFrame().evaluateJavaScript(js);\r
+               }\r
        }\r
        \r
+       // If a user presses tab from within a table\r
+       public void setTableCursorPositionTab(int currentRow, int currentCol, int tableRows, int tableColumns) {\r
+               if (tableRows == currentRow && currentCol == tableColumns) {\r
+                       insertTableRow();\r
+               }\r
+               KeyboardModifiers modifiers = new KeyboardModifiers(KeyboardModifier.NoModifier);\r
+               QKeyEvent right = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Right.value(), modifiers);\r
+               QKeyEvent end = new QKeyEvent(Type.KeyPress, Qt.Key.Key_End.value(), modifiers);\r
+               QKeyEvent end2 = new QKeyEvent(Type.KeyPress, Qt.Key.Key_End.value(), modifiers);\r
+               getBrowser().focusWidget();\r
+               QCoreApplication.postEvent(getBrowser(), end);\r
+               QCoreApplication.postEvent(getBrowser(), right);\r
+               QCoreApplication.postEvent(getBrowser(), end2);\r
+       }\r
+               \r
        public void backtabPressed() {\r
+               if (insideEncryption) \r
+                       return;\r
                if (insideList)\r
                        outdentClicked();\r
+               if (insideTable) {\r
+                       String js = new String( "function getCursorPosition() { "\r
+                                       +"   var selObj = window.getSelection();"\r
+                                       +"   var selRange = selObj.getRangeAt(0);"\r
+                                       +"   var workingNode = window.getSelection().anchorNode;"\r
+                                       +"   var rowCount = 0;"\r
+                                       +"   var colCount = 0;"\r
+                                       +"   while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { " \r
+                                       +"      if (workingNode.nodeName.toLowerCase()=='tr') {"\r
+                                       +"         rowCount = rowCount+1;"\r
+                                       +"      }"\r
+                                       +"      if (workingNode.nodeName.toLowerCase() == 'td') {"\r
+                                       +"         colCount = colCount+1;"\r
+                                       +"      }"\r
+                                       +"      if (workingNode.previousSibling != null)"\r
+                                       +"          workingNode = workingNode.previousSibling;"\r
+                                       +"      else "\r
+                                       +"           workingNode = workingNode.parentNode;"\r
+                                       +"   }"\r
+                                       +"   var nodes = workingNode.getElementsByTagName('tr');"\r
+                                       +"   var tableRows = nodes.length;"\r
+                                       +"   nodes = nodes[0].getElementsByTagName('td');"\r
+                                       +"   var tableColumns = nodes.length;"\r
+                                       +"   window.jambi.setTableCursorPositionBackTab(rowCount, colCount, tableRows, tableColumns);"\r
+                                       +"} getCursorPosition();");\r
+                       browser.page().mainFrame().evaluateJavaScript(js);\r
+                       \r
+               }\r
+       }\r
+       \r
+       // If a user presses backtab from within a table\r
+       public void setTableCursorPositionBackTab(int currentRow, int currentCol, int tableRows, int tableColumns) {\r
+               if (currentRow  == 1 && currentCol == 1) {\r
+                       return;\r
+               }\r
+               KeyboardModifiers modifiers = new KeyboardModifiers(KeyboardModifier.NoModifier);\r
+               QKeyEvent left = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Left.value(), modifiers);\r
+               QKeyEvent home = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Home.value(), modifiers);\r
+               getBrowser().focusWidget();\r
+               QCoreApplication.postEvent(getBrowser(), home);\r
+               QCoreApplication.postEvent(getBrowser(), left);\r
        }\r
        \r
+       \r
        public void setInsideList() {\r
                insideList = true;\r
        }\r
@@ -1408,6 +2079,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
@@ -1417,11 +2095,22 @@ public class BrowserWindow extends QWidget {
        // The note contents have changed\r
        public void contentChanged() {\r
                String content = getContent();\r
-               checkNoteTitle();\r
-               noteSignal.noteChanged.emit(currentNote.getGuid(), content); \r
                \r
+               // This puts in a 1/2 second delay\r
+               // before updating the source editor.\r
+               // It improves response when someone is doing\r
+               // frequent updates on a large note.\r
+               // If the source editor isn't visible, then there\r
+               // is no point to doing any of this.\r
+               if (sourceEdit.isVisible()) {\r
+                       setSourceTimer.stop();\r
+                       setSourceTimer.setInterval(500);\r
+                       setSourceTimer.setSingleShot(true);\r
+                       setSourceTimer.start();\r
+               }\r
                \r
-//        noteSignal.noteChanged.emit(currentNote.getGuid(), unicode);\r
+               checkNoteTitle();\r
+               noteSignal.noteChanged.emit(currentNote.getGuid(), content); \r
        }\r
 \r
        // The notebook selection has changed\r
@@ -1432,6 +2121,13 @@ public class BrowserWindow extends QWidget {
                for (int i = 0; i < notebookList.size(); i++) {\r
                        if (n.equals(notebookList.get(i).getName())) {\r
                                if (!notebookList.get(i).getGuid().equals(currentNote.getNotebookGuid())) {\r
+                                       String guid = conn.getNotebookTable().findNotebookByName(n);\r
+                                       if (conn.getNotebookTable().isLinked(guid)) {\r
+                                               tagEdit.setText("");\r
+                                               noteSignal.tagsChanged.emit(currentNote.getGuid(), new ArrayList<String>());\r
+                                               FilterEditorTags t = new FilterEditorTags(conn, logger);\r
+                                               setAllTags(t.getValidTags(currentNote));\r
+                                       }\r
                                        currentNote.setNotebookGuid(notebookList.get(i).getGuid());\r
                                        changed = true;\r
                                }\r
@@ -1448,25 +2144,29 @@ public class BrowserWindow extends QWidget {
        // Check the note title\r
        private void checkNoteTitle() {\r
                String text = browser.page().currentFrame().toPlainText();\r
-               if (saveNoteTitle.trim().equals("")) {\r
+               if (saveNoteTitle == null)\r
+                       saveNoteTitle = new String();\r
+               if (saveNoteTitle.trim().equals("") || saveNoteTitle.trim().equals("Untitled Note")) {\r
                        int newLine = text.indexOf("\n");\r
                        if (newLine > 0) {\r
                                text = text.substring(0, newLine);\r
                                if (text.trim().equals(""))\r
-                                       text = "Untitled Note";\r
+                                       text = tr("Untitled Note");\r
                                titleLabel.setText(text);\r
                        } else {\r
-                               if (text.length() > 20)\r
-                                       titleLabel.setText(text.substring(0, 20));\r
+                               if (text.length() > Constants.EDAM_NOTE_TITLE_LEN_MAX)\r
+                                       titleLabel.setText(text.substring(0, Constants.EDAM_NOTE_TITLE_LEN_MAX));\r
                                else {\r
+                                       titleLabel.blockSignals(true);\r
                                        if (text.trim().equals(""))\r
-                                               titleLabel.setText("Untitled Note");\r
+                                               titleLabel.setText(tr("Untitled Note"));\r
                                        else\r
                                                titleLabel.setText(text);\r
+                                       titleLabel.blockSignals(false);\r
                                }\r
                        }\r
-                       noteSignal.titleChanged.emit(currentNote.getGuid(), titleLabel\r
-                                       .text());\r
+                       if (currentNote != null && titleLabel != null)\r
+                               noteSignal.titleChanged.emit(currentNote.getGuid(), titleLabel.text());\r
                }\r
        }\r
 \r
@@ -1504,7 +2204,10 @@ public class BrowserWindow extends QWidget {
                // Open the file & write the data\r
                QFile tfile = new QFile(path);\r
                tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));\r
-               img.save(tfile);\r
+               if (!img.save(tfile)) {\r
+                       tfile.close();\r
+                       return;\r
+               }\r
                tfile.close();\r
                \r
                Resource newRes = createResource(QUrl.fromLocalFile(path).toString(), 0, "image/jpeg", false);\r
@@ -1519,14 +2222,50 @@ public class BrowserWindow extends QWidget {
                buffer.append("\" en-tag=en-media type=\"image/jpeg\""\r
                                +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""\r
                                +" guid=\"" +newRes.getGuid() +"\""\r
-                               +" onContextMenu=\"window.jambi.imageContextMenu('" +tfile.fileName() +"');\""\r
+                               +" onContextMenu=\"window.jambi.imageContextMenu(&amp." +tfile.fileName() +"&amp.);\""\r
                                + " />");\r
+               \r
                browser.page().mainFrame().evaluateJavaScript(\r
                                script_start + buffer + script_end);\r
 \r
                return;\r
        }\r
 \r
+       // Handle pasting of a note-to-note link\r
+       private void handleNoteLink(QMimeData mime) {\r
+               for (int i=0; i<mime.urls().size(); i++) {\r
+                       StringTokenizer tokens = new StringTokenizer(mime.urls().get(i).toString().replace("evernote:///view/", ""), "/");\r
+                       tokens.nextToken();\r
+                       tokens.nextToken();\r
+                       String sid = tokens.nextToken();\r
+                       String lid = tokens.nextToken();\r
+                       \r
+                       if (!sid.equals(currentNote.getGuid()) && !lid.equals(currentNote.getGuid())) {\r
+                               \r
+                               Note note = conn.getNoteTable().getNote(sid, false, false, false, false, false);\r
+                               if (note == null)\r
+                                       note = conn.getNoteTable().getNote(lid, false, false, false, false, false);\r
+               \r
+                               if (note == null)\r
+                                       return;\r
+\r
+                               // If we've gotten this far, we have a bunch of values.  We need to build the link.\r
+                               StringBuffer url = new StringBuffer(100);\r
+                               String script_start = new String(\r
+                                       "document.execCommand('insertHtml', false, '");\r
+                               String script_end = new String("');");\r
+       \r
+                               url.append("<a href=\""+mime.urls().get(i).toString() +"\" style=\"color:#69aa35\">");\r
+                               url.append(note.getTitle());\r
+                               url.append("</a>");\r
+                               if (mime.urls().size() > 1)\r
+                                       url.append("&nbsp;");\r
+                               browser.page().mainFrame().evaluateJavaScript(\r
+                                               script_start + url + script_end);\r
+                       }\r
+               }\r
+       }\r
+       \r
        // Handle URLs that are trying to be pasted\r
        public void handleUrls(QMimeData mime) {\r
                logger.log(logger.EXTREME, "Starting handleUrls");\r
@@ -1620,18 +2359,18 @@ public class BrowserWindow extends QWidget {
                String script_end = new String("');");\r
                StringBuffer buffer;\r
 \r
-               for (int i = 0; i < urlList.size(); i++) {\r
-                       buffer = new StringBuffer(100);\r
-                       String url = urlList.get(i).toString();\r
-\r
-                       // Start building the HTML\r
                        String[] type = mimeType.split("/");\r
                        String icon = findIcon(type[1]);\r
                        if (icon.equals("attachment.png"))\r
                                icon = findIcon(type[0]);\r
+                       buffer = new StringBuffer(100);\r
+\r
+               for (int i = 0; i < urlList.size(); i++) {\r
+                       String url = urlList.get(i).toString();\r
+\r
+                       // Start building the HTML\r
                        if (icon.equals("attachment.png"))\r
                                icon = findIcon(url.substring(url.lastIndexOf(".")+1));\r
-                       StringBuffer imageBuffer = new StringBuffer();\r
                        String imageURL = FileUtils.toFileURLString(Global.getFileManager().getImageDirFile(icon));\r
 \r
                        logger.log(logger.EXTREME, "Creating resource ");\r
@@ -1665,12 +2404,12 @@ 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
                                                \r
                        logger.log(logger.EXTREME, "Generating link tags");\r
+                       buffer.delete(0, buffer.length());\r
                        buffer.append("<a en-tag=\"en-media\" guid=\"" +newRes.getGuid()+"\" ");\r
                        buffer.append(" onContextMenu=\"window.jambi.imageContextMenu(&apos;")\r
                      .append(Global.getFileManager().getResDirPath(fileName))\r
@@ -1683,19 +2422,25 @@ public class BrowserWindow extends QWidget {
                }\r
                return;\r
        }\r
+\r
        private Resource createResource(String url, int sequence, String mime, boolean attachment) {\r
                logger.log(logger.EXTREME, "Inside create resource");\r
                QFile resourceFile;\r
-               url = new QUrl(url).toLocalFile();\r
+               String urlTest = new QUrl(url).toLocalFile();\r
+               if (!urlTest.equals(""))\r
+                       url = urlTest;\r
                url = url.replace("/", File.separator);\r
+               logger.log(logger.EXTREME, "Reading from file to create resource");\r
        resourceFile = new QFile(url); \r
        resourceFile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly));\r
+//     logger.log(logger.EXTREME, "Error opening file "+url.toString()  +": "+resourceFile.errorString());\r
        byte[] fileData = resourceFile.readAll().toByteArray();\r
        resourceFile.close();\r
        if (fileData.length == 0)\r
                return null;\r
        MessageDigest md;\r
        try {\r
+               logger.log(logger.EXTREME, "Generating MD5");\r
                md = MessageDigest.getInstance("MD5");\r
                md.update(fileData);\r
                byte[] hash = md.digest();\r
@@ -1753,6 +2498,7 @@ public class BrowserWindow extends QWidget {
                r.setAttributes(a);\r
                \r
                conn.getNoteTable().noteResourceTable.saveNoteResource(r, true);\r
+               logger.log(logger.EXTREME, "Resource created");\r
                return r;\r
        } catch (NoSuchAlgorithmException e1) {\r
                e1.printStackTrace();\r
@@ -1788,8 +2534,8 @@ public class BrowserWindow extends QWidget {
                        return true;\r
                if (type.equalsIgnoreCase("PDF"))\r
                        return true;\r
-               String error = "Non-premium accounts can only attach JPG, PNG, GIF, MP3, WAV, AMR, or PDF files.";\r
-               QMessageBox.information(this, "Non-Premium Account", error);\r
+               String error = tr("Non-premium accounts can only attach JPG, PNG, GIF, MP3, WAV, AMR, or PDF files.");\r
+               QMessageBox.information(this, tr("Non-Premium Account"), error);\r
 \r
                return false;\r
        }\r
@@ -1808,8 +2554,8 @@ public class BrowserWindow extends QWidget {
                if (size < 25)\r
                        return true;\r
 \r
-               String error = "A file attachment may not exceed 25MB.";\r
-               QMessageBox.information(this, "Attachment Size", error);\r
+               String error = tr("A file attachment may not exceed 25MB.");\r
+               QMessageBox.information(this, tr("Attachment Size"), error);\r
                return false;\r
        }\r
 \r
@@ -1850,6 +2596,7 @@ public class BrowserWindow extends QWidget {
                noteSignal.authorChanged.emit(currentNote.getGuid(), authorText.text());\r
        }\r
        \r
+       @SuppressWarnings("unused")\r
        private void geoBoxChanged() {\r
                int index = geoBox.currentIndex();\r
                geoBox.setCurrentIndex(0);\r
@@ -1895,7 +2642,7 @@ public class BrowserWindow extends QWidget {
                QFileDialog fd = new QFileDialog(this);\r
                fd.setFileMode(FileMode.AnyFile);\r
                fd.setConfirmOverwrite(true);\r
-               fd.setWindowTitle("Save File");\r
+               fd.setWindowTitle(tr("Save File"));\r
                fd.setAcceptMode(AcceptMode.AcceptSave);\r
                fd.setDirectory(System.getProperty("user.home"));\r
                String name = request.url().toString();\r
@@ -1918,6 +2665,8 @@ public class BrowserWindow extends QWidget {
                // Strip URL prefix and base dir\r
                guid = guid.replace("nnres://", "")\r
                        .replace(FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath()), "");\r
+               guid = guid.replace("file://", "").replace("/", "")\r
+               .replace(FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath()), "");\r
 \r
                pos = guid.lastIndexOf('.');\r
                if (pos > 0)\r
@@ -1942,12 +2691,11 @@ 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
                fd.setConfirmOverwrite(true);\r
-               fd.setWindowTitle("Save File");\r
+               fd.setWindowTitle(tr("Save File"));\r
                fd.setAcceptMode(AcceptMode.AcceptSave);\r
                fd.setDirectory(System.getProperty("user.home"));\r
                String name = request.url().toString();\r
@@ -1989,7 +2737,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
@@ -2001,10 +2753,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
+                                       setContent(unicode);\r
+                                       if (permanent)\r
+                                               contentChanged();\r
                        }\r
                        imagePos = text.indexOf("<img", imagePos+1);\r
                }\r
@@ -2053,7 +2807,6 @@ public class BrowserWindow extends QWidget {
        //* MicroFocus changed\r
        //****************************************************************\r
        private void microFocusChanged() {\r
-               \r
                boldButton.setDown(false);\r
                italicButton.setDown(false);\r
                underlineButton.setDown(false);\r
@@ -2063,11 +2816,17 @@ public class BrowserWindow extends QWidget {
                browser.rotateImageLeft.setEnabled(false);\r
                browser.rotateImageRight.setEnabled(false);\r
                browser.insertTableAction.setEnabled(true);\r
+               browser.deleteTableColumnAction.setEnabled(false);\r
                browser.insertTableRowAction.setEnabled(false);\r
+               browser.insertTableColumnAction.setEnabled(false);\r
                browser.deleteTableRowAction.setEnabled(false);\r
-               browser.insertLinkAction.setText("Insert Hyperlink");\r
+               browser.insertLinkAction.setText(tr("Insert Hyperlink"));\r
+               insertHyperlink = true;\r
+               browser.insertQuickLinkAction.setEnabled(true);\r
                currentHyperlink ="";\r
                insideList = false;\r
+               insideTable = false;\r
+               insideEncryption = false;\r
                forceTextPaste = false;\r
                \r
                String js = new String( "function getCursorPos() {"\r
@@ -2078,7 +2837,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.insideEncryption(); }"\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
@@ -2101,6 +2860,10 @@ public class BrowserWindow extends QWidget {
                System.out.println("Node Vaule: " +n);\r
        }\r
        \r
+       public void insideEncryption() {\r
+               insideEncryption = true;\r
+               forceTextPaste();\r
+       }\r
        \r
        //****************************************************************\r
        //* Insert a table row\r
@@ -2130,8 +2893,34 @@ public class BrowserWindow extends QWidget {
                browser.page().mainFrame().evaluateJavaScript(js);\r
                contentChanged();\r
        }\r
+       \r
+       public void insertTableColumn() {\r
+               String js = new String( "function insertTableColumn() {"\r
+                               +"   var selObj = window.getSelection();"\r
+                               +"   var selRange = selObj.getRangeAt(0);"\r
+                               +"   var workingNode = window.getSelection().anchorNode.parentNode;"\r
+                               +"   var current = 0;"\r
+                               +"   while (workingNode.nodeName.toLowerCase() != 'table' && workingNode != null) {"\r
+                               +"       if (workingNode.nodeName.toLowerCase() == 'td') {"\r
+                               +"          var td = workingNode;"\r
+                               +"          while (td.previousSibling != null) { " \r
+                               +"             current = current+1; td = td.previousSibling;"\r
+                               +"          }"\r
+                               +"       }"\r
+                               +"       workingNode = workingNode.parentNode; "\r
+                               +"   }"\r
+                               +"   if (workingNode == null) return;"\r
+                               +"   for (var i=0; i<workingNode.rows.length; i++) { " \r
+                               +"      var cell = workingNode.rows[i].insertCell(current+1); "                 \r
+                               +"      cell.innerHTML = '&nbsp'; "\r
+                               +"   }"\r
+                               +"} insertTableColumn();");\r
+                       browser.page().mainFrame().evaluateJavaScript(js);\r
+                       contentChanged();\r
+       }\r
+       \r
        //****************************************************************\r
-       //* Insert a table row\r
+       //* Delete a table row\r
        //****************************************************************\r
        public void deleteTableRow() {\r
                \r
@@ -2151,16 +2940,46 @@ public class BrowserWindow extends QWidget {
                browser.page().mainFrame().evaluateJavaScript(js);\r
                contentChanged();\r
        }\r
+\r
+       public void deleteTableColumn() {\r
+               String js = new String( "function deleteTableColumn() {"\r
+                               +"   var selObj = window.getSelection();"\r
+                               +"   var selRange = selObj.getRangeAt(0);"\r
+                               +"   var workingNode = window.getSelection().anchorNode.parentNode;"\r
+                               +"   var current = 0;"\r
+                               +"   while (workingNode.nodeName.toLowerCase() != 'table' && workingNode != null) {"\r
+                               +"       if (workingNode.nodeName.toLowerCase() == 'td') {"\r
+                               +"          var td = workingNode;"\r
+                               +"          while (td.previousSibling != null) { " \r
+                               +"             current = current+1; td = td.previousSibling;"\r
+                               +"          }"\r
+                               +"       }"\r
+                               +"       workingNode = workingNode.parentNode; "\r
+                               +"   }"\r
+                               +"   if (workingNode == null) return;"\r
+                               +"   for (var i=0; i<workingNode.rows.length; i++) { " \r
+                               +"      workingNode.rows[i].deleteCell(current); "                      \r
+                               +"   }"\r
+                               +"} deleteTableColumn();");\r
+                       browser.page().mainFrame().evaluateJavaScript(js);\r
+                       contentChanged();\r
+       }\r
+       \r
+       \r
        public void setInsideTable() {\r
                browser.insertTableRowAction.setEnabled(true);\r
+               browser.insertTableColumnAction.setEnabled(true);\r
                browser.deleteTableRowAction.setEnabled(true);\r
+               browser.deleteTableColumnAction.setEnabled(true);\r
                browser.insertTableAction.setEnabled(false);\r
                browser.encryptAction.setEnabled(false);\r
+               insideTable = true;\r
        }\r
        \r
        public void setInsideLink(String link) {\r
-               browser.insertLinkAction.setText("Edit Hyperlink");\r
+               browser.insertLinkAction.setText(tr("Edit Hyperlink"));\r
                currentHyperlink = link;\r
+               insertHyperlink = false;\r
        }\r
        \r
        public void italicActive() {\r
@@ -2195,7 +3014,7 @@ public class BrowserWindow extends QWidget {
                browser.setHtml(browser.page().mainFrame().toHtml());\r
                browser.reload();\r
                contentChanged();\r
-//             resourceSignal.contentChanged.emit(selectedFile);\r
+               resourceSignal.contentChanged.emit(selectedFile);\r
 \r
        }\r
        public void rotateImageLeft() {\r
@@ -2207,15 +3026,21 @@ public class BrowserWindow extends QWidget {
                browser.setHtml(browser.page().mainFrame().toHtml());\r
                browser.reload();\r
                contentChanged();\r
-//             resourceSignal.contentChanged.emit(selectedFile);\r
+               resourceSignal.contentChanged.emit(selectedFile);\r
        }\r
        public void resourceContextMenu(String f) {\r
                browser.downloadAttachment.setEnabled(true);\r
                browser.openAction.setEnabled(true);\r
                selectedFile = f;\r
        }\r
-       \r
-       \r
+       public void latexContextMenu(String f) {\r
+               browser.downloadImage.setEnabled(true);\r
+               browser.rotateImageRight.setEnabled(true);\r
+               browser.rotateImageLeft.setEnabled(true);\r
+               browser.openAction.setEnabled(true);\r
+               selectedFile = f;\r
+       }\r
+\r
        //****************************************************************\r
        //* Apply CSS style to specified word\r
        //****************************************************************\r
@@ -2252,6 +3077,14 @@ public class BrowserWindow extends QWidget {
                                int guidEndPos = segment.indexOf("\"", guidStartPos+7);\r
                                String guid = segment.substring(guidStartPos+6,guidEndPos);\r
                                \r
+                               int mimeStartPos = segment.indexOf("type");\r
+                               int mimeEndPos = segment.indexOf("\"", mimeStartPos+7);\r
+                               String mime = segment.substring(mimeStartPos+6,mimeEndPos);\r
+\r
+                               int srcStartPos = segment.indexOf("src");\r
+                               int srcEndPos = segment.indexOf("\"", srcStartPos+6);\r
+                               String src = segment.substring(srcStartPos+5,srcEndPos);\r
+                               \r
                                Calendar currentTime = new GregorianCalendar();\r
                                Long l = new Long(currentTime.getTimeInMillis());\r
                                long prevTime = l;\r
@@ -2261,8 +3094,13 @@ public class BrowserWindow extends QWidget {
                                }\r
                                \r
                                Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);\r
-                               if (r==null)\r
-                                       return "";\r
+                               // if r==null, then the image doesn't exist (it was probably cut out of another note, so \r
+                               // we need to recereate it\r
+                               if (r==null) {\r
+                                       r = createResource(src, 1, mime, false);\r
+                                       if (r==null)\r
+                                               return "";\r
+                               }\r
                        String randint = new String(Long.toString(l));\r
                        String extension = null;\r
                        if (r.getMime()!= null) {\r
@@ -2386,4 +3224,272 @@ public class BrowserWindow extends QWidget {
 //             browser.previousPageAction.setVisible(false);\r
        }\r
 */\r
-}
\ No newline at end of file
+       \r
+       @SuppressWarnings("unused")\r
+       private void toggleUndoVisible(Boolean toggle) {\r
+               undoAction.setVisible(toggle);\r
+               Global.saveEditorButtonsVisible("undo", toggle);\r
+       }\r
+       @SuppressWarnings("unused")\r
+       private void toggleRedoVisible(Boolean toggle) {\r
+               redoAction.setVisible(toggle);\r
+               Global.saveEditorButtonsVisible("redo", toggle);\r
+       }\r
+       @SuppressWarnings("unused")\r
+       private void toggleCutVisible(Boolean toggle) {\r
+               cutAction.setVisible(toggle);\r
+               Global.saveEditorButtonsVisible("cut", toggle);\r
+       }\r
+       @SuppressWarnings("unused")\r
+       private void toggleCopyVisible(Boolean toggle) {\r
+               copyAction.setVisible(toggle);\r
+               Global.saveEditorButtonsVisible("copy", toggle);\r
+       }\r
+       @SuppressWarnings("unused")\r
+       private void togglePasteVisible(Boolean toggle) {\r
+               pasteAction.setVisible(toggle);\r
+               Global.saveEditorButtonsVisible("paste", toggle);\r
+       }\r
+       @SuppressWarnings("unused")\r
+       private void toggleBoldVisible(Boolean toggle) {\r
+               boldAction.setVisible(toggle);\r
+               Global.saveEditorButtonsVisible("bold", toggle);\r
+       }\r
+       @SuppressWarnings("unused")\r
+       private void toggleItalicVisible(Boolean toggle) {\r
+               italicAction.setVisible(toggle);\r
+               Global.saveEditorButtonsVisible("italic", toggle);\r
+       }\r
+       @SuppressWarnings("unused")\r
+       private void toggleUnderlineVisible(Boolean toggle) {\r
+               underlineAction.setVisible(toggle);\r
+               Global.saveEditorButtonsVisible("underline", toggle);\r
+       }\r
+       @SuppressWarnings("unused")\r
+       private void toggleStrikethroughVisible(Boolean toggle) {\r
+               strikethroughAction.setVisible(toggle);\r
+               Global.saveEditorButtonsVisible("strikethrough", toggle);\r
+       }\r
+       @SuppressWarnings("unused")\r
+       private void toggleLeftAlignVisible(Boolean toggle) {\r
+               leftAlignAction.setVisible(toggle);\r
+               Global.saveEditorButtonsVisible("alignLeft", toggle);\r
+       }\r
+       @SuppressWarnings("unused")\r
+       private void toggleRightAlignVisible(Boolean toggle) {\r
+               rightAlignAction.setVisible(toggle);\r
+               Global.saveEditorButtonsVisible("alignRight", toggle);\r
+       }       \r
+       @SuppressWarnings("unused")\r
+       private void toggleCenterAlignVisible(Boolean toggle) {\r
+               centerAlignAction.setVisible(toggle);\r
+               Global.saveEditorButtonsVisible("alignCenter", toggle);\r
+       }\r
+       @SuppressWarnings("unused")\r
+       private void toggleHLineVisible(Boolean toggle) {\r
+               hlineAction.setVisible(toggle);\r
+               Global.saveEditorButtonsVisible("hline", toggle);\r
+       }\r
+       @SuppressWarnings("unused")\r
+       private void toggleIndentVisible(Boolean toggle) {\r
+               indentAction.setVisible(toggle);\r
+               Global.saveEditorButtonsVisible("indent", toggle);\r
+       }\r
+       @SuppressWarnings("unused")\r
+       private void toggleTodoVisible(Boolean toggle) {\r
+               todoAction.setVisible(toggle);\r
+               Global.saveEditorButtonsVisible("todo", toggle);\r
+       }\r
+       @SuppressWarnings("unused")\r
+       private void toggleOutdentVisible(Boolean toggle) {\r
+               outdentAction.setVisible(toggle);\r
+               Global.saveEditorButtonsVisible("outdent", toggle);\r
+       }\r
+       @SuppressWarnings("unused")\r
+       private void toggleBulletListVisible(Boolean toggle) {\r
+               bulletListAction.setVisible(toggle);\r
+               Global.saveEditorButtonsVisible("bulletList", toggle);\r
+       }\r
+       @SuppressWarnings("unused")\r
+       private void toggleNumberListVisible(Boolean toggle) {\r
+               numberListAction.setVisible(toggle);\r
+               Global.saveEditorButtonsVisible("numberList", toggle);\r
+       }\r
+       @SuppressWarnings("unused")\r
+       private void toggleFontListVisible(Boolean toggle) {\r
+               fontListAction.setVisible(toggle);\r
+               Global.saveEditorButtonsVisible("font", toggle);\r
+       }\r
+       @SuppressWarnings("unused")\r
+       private void toggleFontColorVisible(Boolean toggle) {\r
+               fontColorAction.setVisible(toggle);\r
+               Global.saveEditorButtonsVisible("fontColor", toggle);\r
+       }\r
+       @SuppressWarnings("unused")\r
+       private void toggleFontSizeVisible(Boolean toggle) {\r
+               fontSizeAction.setVisible(toggle);\r
+               Global.saveEditorButtonsVisible("fontSize", toggle);\r
+       }\r
+       @SuppressWarnings("unused")\r
+       private void toggleFontHilightVisible(Boolean toggle) {\r
+               fontHilightAction.setVisible(toggle);\r
+               Global.saveEditorButtonsVisible("fontHilight", toggle);\r
+       }\r
+       @SuppressWarnings("unused")\r
+       private void toggleSpellCheckVisible(Boolean toggle) {\r
+               spellCheckAction.setVisible(toggle);\r
+               Global.saveEditorButtonsVisible("spellCheck", toggle);\r
+       }\r
+\r
+\r
+       private void setupDictionary() {\r
+               File wordList = new File(Global.getFileManager().getSpellDirPath()+Locale.getDefault()+".dic");\r
+               try {\r
+                       dictionary = new SpellDictionaryHashMap(wordList);\r
+                       spellChecker = new SpellChecker(dictionary);\r
+                       \r
+                       File userWordList;\r
+                       userWordList = new File(Global.getFileManager().getSpellDirPathUser()+"user.dic");\r
+                       \r
+                       // Get the local user spell dictionary\r
+                       try {\r
+                               userDictionary = new SpellDictionaryHashMap(userWordList);\r
+                       } catch (FileNotFoundException e) {\r
+                               userWordList.createNewFile();\r
+                               userDictionary = new SpellDictionaryHashMap(userWordList);\r
+                       } catch (IOException e) {\r
+                               userWordList.createNewFile();\r
+                               userDictionary = new SpellDictionaryHashMap(userWordList);\r
+                       }\r
+                       \r
+                       spellListener = new SuggestionListener(this, spellChecker);\r
+                       \r
+                       // Add the user dictionary\r
+                       spellChecker.addSpellCheckListener(spellListener);\r
+                       spellChecker.setUserDictionary(userDictionary);\r
+\r
+               } catch (FileNotFoundException e) {\r
+                       QMessageBox.critical(this, tr("Spell Check Error"), \r
+                                       tr("Dictionary ")+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+\r
+                                               tr(".dic was not found."));\r
+               } catch (IOException e) {\r
+                       QMessageBox.critical(this, tr("Spell Check Error"), \r
+                                       tr("Dictionary ")+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+\r
+                                               tr(".dic is invalid."));\r
+               }\r
+\r
+       }\r
+       \r
+       // Invoke spell checker dialog\r
+       @SuppressWarnings("unused")\r
+       private void spellCheckClicked() {\r
+\r
+               if (spellChecker == null) {\r
+                       setupDictionary();      \r
+               }\r
+               \r
+               // Read user settings\r
+               spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREDIGITWORDS, \r
+                               Global.getSpellSetting(Configuration.SPELL_IGNOREDIGITWORDS));\r
+               spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREINTERNETADDRESSES, \r
+                               Global.getSpellSetting(Configuration.SPELL_IGNOREINTERNETADDRESSES));\r
+               spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREMIXEDCASE, \r
+                               Global.getSpellSetting(Configuration.SPELL_IGNOREMIXEDCASE));\r
+               spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREUPPERCASE, \r
+                               Global.getSpellSetting(Configuration.SPELL_IGNOREUPPERCASE));\r
+               spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNORESENTENCECAPITALIZATION, \r
+                               Global.getSpellSetting(Configuration.SPELL_IGNORESENTENCECAPITALIZATION));\r
+\r
+               spellListener.abortSpellCheck = false;\r
+               spellListener.errorsFound = false;\r
+               String content = getBrowser().page().mainFrame().toPlainText();\r
+               StringWordTokenizer tokenizer = new StringWordTokenizer(content);\r
+               if (!tokenizer.hasMoreWords())\r
+                       return;\r
+               getBrowser().page().action(WebAction.MoveToStartOfDocument);\r
+\r
+               getBrowser().setFocus();\r
+               boolean found;\r
+                       \r
+               // Move to the start of page\r
+               KeyboardModifiers ctrl = new KeyboardModifiers(KeyboardModifier.ControlModifier.value());\r
+               QKeyEvent home = new QKeyEvent(Type.KeyPress, Key.Key_Home.value(), ctrl);  \r
+               browser.keyPressEvent(home);\r
+               getBrowser().setFocus();\r
+                       \r
+               tokenizer = new StringWordTokenizer(content);\r
+               String word;\r
+                       \r
+               while(tokenizer.hasMoreWords()) {\r
+                       word = tokenizer.nextWord();\r
+                       found = getBrowser().page().findText(word);\r
+                       if (found && !spellListener.abortSpellCheck) {\r
+                               spellChecker.checkSpelling(new StringWordTokenizer(word));\r
+                               getBrowser().setFocus();\r
+                       }\r
+               }\r
+\r
+               // Go to the end of the document & finish up.\r
+               home = new QKeyEvent(Type.KeyPress, Key.Key_End.value(), ctrl);  \r
+               browser.keyPressEvent(home);\r
+               if (!spellListener.errorsFound)\r
+                       QMessageBox.information(this, tr("Spell Check Complete"), \r
+                                       tr("No Errors Found"));\r
+\r
+    }\r
+       \r
+       // Source edited\r
+       @SuppressWarnings("unused")\r
+       private void sourceEdited() {\r
+               QTextCodec codec = QTextCodec.codecForLocale();\r
+               codec = QTextCodec.codecForName("UTF-8");\r
+        String content =  codec.fromUnicode(sourceEdit.toHtml()).toString();\r
+               content = StringEscapeUtils.unescapeHtml4(removeTags(content));\r
+               QByteArray data = new QByteArray(sourceEditHeader+content+"</body></html>");\r
+               getBrowser().setContent(data);\r
+               checkNoteTitle();\r
+               if (currentNote != null && sourceEdit != null)\r
+                       noteSignal.noteChanged.emit(currentNote.getGuid(), sourceEdit.toPlainText()); \r
+       }\r
+       \r
+       private void setSource() {\r
+               String text = getContent();\r
+               sourceEdit.blockSignals(true);\r
+               int body = text.indexOf("<body");\r
+               if (body > 0) {\r
+                       body = text.indexOf(">",body);\r
+                       if (body > 0) {\r
+                               sourceEditHeader =text.substring(0, body+1);\r
+                               text = text.substring(body+1);\r
+                       }\r
+               }\r
+               text = text.replace("</body></html>", "");\r
+               sourceEdit.setPlainText(text);\r
+               sourceEdit.setReadOnly(!getBrowser().page().isContentEditable());\r
+               //syntaxHighlighter.rehighlight();\r
+               sourceEdit.blockSignals(false);\r
+       }\r
+\r
+       // show/hide view source window\r
+       public void showSource(boolean value) {\r
+               setSource();\r
+               sourceEdit.setVisible(value);\r
+       }\r
+\r
+       // Remove HTML tags\r
+       private String removeTags(String text) {\r
+               StringBuffer buffer = new StringBuffer(text);\r
+               boolean inTag = false;\r
+               int bodyPosition = text.indexOf("<body");\r
+               for (int i=buffer.length()-1; i>=0; i--) {\r
+                       if (buffer.charAt(i) == '>')\r
+                               inTag = true;\r
+                       if (buffer.charAt(i) == '<')\r
+                               inTag = false;\r
+                       if (inTag || buffer.charAt(i) == '<' || i<bodyPosition)\r
+                               buffer.deleteCharAt(i);\r
+               }\r
+               \r
+               return buffer.toString();\r
+       }\r
+}\r