OSDN Git Service

Correct problem with title label being updated from first line of text incorrectly.
[neighbornote/NeighborNote.git] / src / cx / fbn / nevernote / gui / BrowserWindow.java
index f47dd85..d90d8dd 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
@@ -36,8 +36,10 @@ import java.util.GregorianCalendar;
 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.lang.StringUtils;\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
@@ -46,6 +48,7 @@ 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
@@ -65,6 +68,7 @@ import com.trolltech.qt.core.QFileSystemWatcher;
 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
@@ -82,6 +86,7 @@ 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
@@ -99,6 +104,9 @@ import com.trolltech.qt.gui.QPalette;
 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
@@ -119,6 +127,7 @@ import cx.fbn.nevernote.dialog.EnDecryptDialog;
 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
@@ -157,11 +166,15 @@ public class BrowserWindow extends QWidget {
        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
@@ -232,7 +245,7 @@ public class BrowserWindow extends QWidget {
        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
@@ -242,13 +255,14 @@ public class BrowserWindow extends QWidget {
     SpellChecker spellChecker;\r
     SuggestionListener spellListener;\r
        private final HashMap<String,Integer> previewPageList;  \r
-       boolean insertHyperlink = true;\r
-       boolean insideTable = false;\r
-       boolean insideEncryption = false;\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
@@ -297,11 +311,17 @@ public class BrowserWindow extends QWidget {
        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
@@ -314,7 +334,7 @@ public class BrowserWindow extends QWidget {
                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
@@ -332,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
@@ -381,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
@@ -551,9 +585,19 @@ public class BrowserWindow extends QWidget {
                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
+               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
@@ -607,6 +651,9 @@ public class BrowserWindow extends QWidget {
                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
@@ -686,7 +733,7 @@ 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
                tagEdit.tagCompleter.reset();\r
                urlLabel.setText(tr("Source URL:"));\r
@@ -694,6 +741,11 @@ public class BrowserWindow extends QWidget {
                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
@@ -876,6 +928,18 @@ public class BrowserWindow extends QWidget {
                        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
@@ -1035,8 +1099,6 @@ public class BrowserWindow extends QWidget {
                }\r
                QClipboard clipboard = QApplication.clipboard();\r
                QMimeData mime = clipboard.mimeData();\r
-               \r
-//              String x = mime.html();\r
 \r
                if (mime.hasImage()) {\r
                        logger.log(logger.EXTREME, "Image paste found");\r
@@ -1048,8 +1110,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
@@ -1332,7 +1398,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
@@ -1420,7 +1518,7 @@ public class BrowserWindow extends QWidget {
        public void editLatex(String guid) {\r
                logger.log(logger.EXTREME, "Inserting latex");\r
                String text = browser.selectedText();\r
-               if (text.trim().equalsIgnoreCase("")) {\r
+               if (text.trim().equalsIgnoreCase("\n") || 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
@@ -1545,7 +1643,7 @@ public class BrowserWindow extends QWidget {
                        HtmlTagModifier modifier = new HtmlTagModifier(getContent());\r
                        modifier.modifyLatexTagHash(newRes);\r
                        String newContent = modifier.getHtml();\r
-                       browser.setContent(new QByteArray(newContent));\r
+                       setContent(new QByteArray(newContent));\r
                }\r
 \r
                logger.log(logger.EXTREME, "New HTML set\n" +browser.page().currentFrame().toHtml());\r
@@ -1601,6 +1699,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
@@ -1630,6 +1729,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
@@ -1662,7 +1762,7 @@ 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
                Pair<String,String> passwordPair = new Pair<String,String>();\r
@@ -1937,9 +2037,12 @@ public class BrowserWindow extends QWidget {
                        return;\r
                \r
                // If we have a real change, we need to save it.\r
-               noteSignal.titleChanged.emit(currentNote.getGuid(), titleLabel.text());\r
-               currentNote.setTitle(titleLabel.text());\r
-               saveNoteTitle = titleLabel.text();\r
+               String text = titleLabel.text().trim();\r
+               if (text.equals("")) \r
+                       text = tr("Untitled Note");\r
+               noteSignal.titleChanged.emit(currentNote.getGuid(), text);\r
+               currentNote.setTitle(text);\r
+               saveNoteTitle = text;\r
                checkNoteTitle();\r
        }\r
 \r
@@ -1993,6 +2096,20 @@ public class BrowserWindow extends QWidget {
        // The note contents have changed\r
        public void contentChanged() {\r
                String content = getContent();\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
                checkNoteTitle();\r
                noteSignal.noteChanged.emit(currentNote.getGuid(), content); \r
        }\r
@@ -2028,28 +2145,32 @@ public class BrowserWindow extends QWidget {
        // Check the note title\r
        private void checkNoteTitle() {\r
                String text = browser.page().currentFrame().toPlainText();\r
+               if (saveNoteTitle == null)\r
+                       saveNoteTitle = new String();\r
+               text = text.trim();\r
+               if (!saveNoteTitle.trim().equals("") && !saveNoteTitle.trim().equals("Untitled Note"))\r
+                       text = saveNoteTitle.trim();\r
+               int newLine = text.indexOf("\n");\r
+               if (newLine > 0)\r
+                       text = text.substring(0,newLine);\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 = tr("Untitled Note");\r
+                       if (text.trim().equals(""))\r
+                               text = tr("Untitled Note");\r
                                titleLabel.setText(text);\r
-                       } else {\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(tr("Untitled Note"));\r
-                                       else\r
-                                               titleLabel.setText(text);\r
-                                       titleLabel.blockSignals(false);\r
-                               }\r
+               } else {\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(tr("Untitled Note"));\r
+                               else\r
+                                       titleLabel.setText(text);\r
+                               titleLabel.blockSignals(false);\r
                        }\r
-                       noteSignal.titleChanged.emit(currentNote.getGuid(), titleLabel\r
-                                       .text());\r
                }\r
+               if (currentNote != null && titleLabel != null)\r
+                       noteSignal.titleChanged.emit(currentNote.getGuid(), text);\r
        }\r
 \r
        // Return the note contents so we can email them\r
@@ -2113,6 +2234,41 @@ public class BrowserWindow extends QWidget {
                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
@@ -2140,10 +2296,9 @@ public class BrowserWindow extends QWidget {
                                handleLocalImageURLPaste(mime, mimeType);\r
                                return;\r
                        }\r
-                       String[] type = mimeType.split("/");\r
-                       boolean valid = validAttachment(type[1]);\r
+\r
                        boolean smallEnough = checkFileAttachmentSize(url);\r
-                       if (smallEnough && valid\r
+                       if (smallEnough \r
                                        && url.substring(0, 5).equalsIgnoreCase("file:")\r
                                        && !mimeType.substring(0, 5).equalsIgnoreCase("image")) {\r
                                handleLocalAttachment(mime, mimeType);\r
@@ -2254,13 +2409,14 @@ public class BrowserWindow extends QWidget {
                                imageURL = file.fileName() + ".png";\r
                                }\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
-                     .append("&apos;);\" ");                   buffer.append("type=\"" + mimeType + "\" href=\"nnres://" + fileName +"\" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\" >");\r
+                     .append("&apos;);\" ");                   \r
+                       buffer.append("type=\"" + mimeType + "\" href=\"nnres://" + fileName +"\" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\" >");\r
                        buffer.append("<img src=\"" + imageURL + "\" title=\"" +newRes.getAttributes().getFileName());\r
                        buffer.append("\"></img>");\r
                        buffer.append("</a>");\r
@@ -2272,17 +2428,28 @@ public class BrowserWindow extends QWidget {
 \r
        private Resource createResource(String url, int sequence, String mime, boolean attachment) {\r
                logger.log(logger.EXTREME, "Inside create resource");\r
-               QFile resourceFile;\r
+               QFile resourceFile; \r
+               //These two lines are added to handle odd characters in the name like #.  Without it\r
+               // toLocalFile() chokes and returns the wrong name.\r
+               logger.log(logger.EXTREME, "File URL:" +url);\r
+               String whichOS = System.getProperty("os.name");\r
+               if (whichOS.contains("Windows")) \r
+                       url = url.replace("file:///", "");\r
+               else\r
+                       url = url.replace("file://", "");\r
                String urlTest = new QUrl(url).toLocalFile();\r
+               logger.log(logger.EXTREME, "File URL toLocalFile():" +urlTest);\r
+               urlTest = url;\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
+//             url = url.replace("/", File.separator);\r
+               logger.log(logger.EXTREME, "Reading from file to create resource:" +url);\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
+       logger.log(logger.EXTREME, "Error opening file "+url.toString()  +": "+resourceFile.errorString());\r
        byte[] fileData = resourceFile.readAll().toByteArray();\r
        resourceFile.close();\r
+       logger.log(logger.EXTREME, "File Length: " +fileData.length);\r
        if (fileData.length == 0)\r
                return null;\r
        MessageDigest md;\r
@@ -2363,29 +2530,7 @@ public class BrowserWindow extends QWidget {
        return "attachment.png";\r
     }\r
 \r
-       // Check if the account supports this type of attachment\r
-       private boolean validAttachment(String type) {\r
-               if (Global.isPremium())\r
-                       return true;\r
-               if (type.equalsIgnoreCase("JPG"))\r
-                       return true;\r
-               if (type.equalsIgnoreCase("PNG"))\r
-                       return true;\r
-               if (type.equalsIgnoreCase("GIF"))\r
-                       return true;\r
-               if (type.equalsIgnoreCase("MP3"))\r
-                       return true;\r
-               if (type.equalsIgnoreCase("WAV"))\r
-                       return true;\r
-               if (type.equalsIgnoreCase("AMR"))\r
-                       return true;\r
-               if (type.equalsIgnoreCase("PDF"))\r
-                       return true;\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
 \r
        // Check the file attachment to be sure it isn't over 25 mb\r
        private boolean checkFileAttachmentSize(String url) {\r
@@ -2603,7 +2748,7 @@ public class BrowserWindow extends QWidget {
                                        text = text.substring(0,imagePos) +plainText+text.substring(endPos+1);  \r
                                        QTextCodec codec = QTextCodec.codecForName("UTF-8");\r
                                QByteArray unicode =  codec.fromUnicode(text);\r
-                                       browser.setContent(unicode);\r
+                                       setContent(unicode);\r
                                        if (permanent)\r
                                                contentChanged();\r
                        }\r
@@ -2669,6 +2814,7 @@ public class BrowserWindow extends QWidget {
                browser.deleteTableRowAction.setEnabled(false);\r
                browser.insertLinkAction.setText(tr("Insert Hyperlink"));\r
                insertHyperlink = true;\r
+               browser.insertQuickLinkAction.setEnabled(true);\r
                currentHyperlink ="";\r
                insideList = false;\r
                insideTable = false;\r
@@ -3216,12 +3362,12 @@ public class BrowserWindow extends QWidget {
 \r
                } catch (FileNotFoundException e) {\r
                        QMessageBox.critical(this, tr("Spell Check Error"), \r
-                                       tr("Dictionary "+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+\r
-                                               ".dic was not found."));\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
-                                               ".dic is invalid."));\r
+                                       tr("Dictionary ")+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+\r
+                                               tr(".dic is invalid."));\r
                }\r
 \r
        }\r
@@ -3283,5 +3429,59 @@ public class BrowserWindow extends QWidget {
                                        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