OSDN Git Service

Correct errors relating to LaTeX images & editing.
authorRandy Baumgarte <randy@fbn.cx>
Wed, 20 Apr 2011 14:26:20 +0000 (10:26 -0400)
committerRandy Baumgarte <randy@fbn.cx>
Sat, 30 Apr 2011 12:18:12 +0000 (08:18 -0400)
src/cx/fbn/nevernote/NeverNote.java
src/cx/fbn/nevernote/gui/BrowserWindow.java
src/cx/fbn/nevernote/threads/SaveRunner.java
src/cx/fbn/nevernote/xml/NoteFormatter.java
src/cx/fbn/nevernote/xml/XMLCleanup.java

index 3b55dc0..96b53c6 100644 (file)
@@ -332,8 +332,8 @@ public class NeverNote extends QMainWindow{
     private static Logger log = Logger.getLogger(NeverNote.class); 
     private String             saveLastPath;                           // last path we used
     private final QTimer               messageTimer;                           // Timer to clear the status message.
-    private long               blockTime;                                      // When the app. is blocked, this is the time to unblock it.
-    
+    private QTimer             blockTimer;
+    BrowserWindow              blockingWindow;
     
     String iconPath = new String("classpath:cx/fbn/nevernote/icons/");
        
@@ -1144,6 +1144,8 @@ public class NeverNote extends QMainWindow{
            browser.noteSignal.geoChanged.connect(listManager, "updateNoteGeoTag(String, Double,Double,Double)");
            browser.noteSignal.geoChanged.connect(this, "setNoteDirty()");
            browser.noteSignal.sourceUrlChanged.connect(listManager, "updateNoteSourceUrl(String, String)");
+       browser.blockApplication.connect(this, "blockApplication(BrowserWindow)");
+       browser.unblockApplication.connect(this, "unblockApplication()");
            if (master) browser.focusLost.connect(this, "saveNote()");
            browser.resourceSignal.contentChanged.connect(this, "externalFileEdited(String)");
        }
@@ -4098,12 +4100,12 @@ public class NeverNote extends QMainWindow{
        newBrowser.getBrowserWindow().noteSignal.titleChanged.connect(this, "externalWindowTitleEdited(String, String)");
        newBrowser.getBrowserWindow().noteSignal.tagsChanged.connect(this, "externalWindowTagsEdited(String, List)");
        newBrowser.contentsChanged.connect(this, "saveNoteExternalBrowser(String, String, Boolean, BrowserWindow)");
+       newBrowser.getBrowserWindow().blockApplication.connect(this, "blockApplication(BrowserWindow)");
+       newBrowser.getBrowserWindow().unblockApplication.connect(this, "unblockApplication()");
 
        browserWindow.noteSignal.tagsChanged.connect(newBrowser, "updateTags(String, List)");
        browserWindow.noteSignal.titleChanged.connect(newBrowser, "updateTitle(String, String)");
        browserWindow.noteSignal.notebookChanged.connect(newBrowser, "updateNotebook(String, String)");
-       browserWindow.blockApplication.connect(this, "blockApplication(Long)");
-       browserWindow.unblockApplication.connect(this, "unblockApplication()");
        
        newBrowser.show();
     }
@@ -4282,6 +4284,13 @@ public class NeverNote extends QMainWindow{
 
                        if (formatter.resourceError)
                                resourceErrorMessage();
+                       if (formatter.formatError) {
+                               waitCursor(false);
+                            QMessageBox.information(this, tr("Error"),
+                                               tr("NeverNote had issues formatting this note." +
+                                               " To protect your data this note is being marked as read-only."));      
+                            waitCursor(true);
+                       }
                        readOnly = formatter.readOnly;
                        inkNote = formatter.inkNote;
                        if (readOnly)
@@ -4935,7 +4944,7 @@ public class NeverNote extends QMainWindow{
        // A resource within a note has had a guid change 
        @SuppressWarnings("unused")
        private void noteResourceGuidChanged(String noteGuid, String oldGuid, String newGuid) {
-               if (!oldGuid.equals(newGuid))
+               if (oldGuid != null && !oldGuid.equals(newGuid))
                        Global.resourceMap.put(oldGuid, newGuid);
        }
        // View a thumbnail of the note
@@ -5289,6 +5298,7 @@ public class NeverNote extends QMainWindow{
        private void resourceErrorMessage() {
                if (inkNote)
                        return;
+               waitCursor(false);
                QMessageBox.information(this, tr("DOUGH!!!"), tr("Well, this is embarrassing."+
                "\n\nSome attachments or images for this note appear to be missing from my database.\n"+
                "In a perfect world this wouldn't happen, but it has.\n" +
@@ -5301,6 +5311,7 @@ public class NeverNote extends QMainWindow{
                "\n\nP.S. You might want to re-synchronize to see if it corrects this problem.\nWho knows, you might get lucky."));
                inkNote = true;
                browserWindow.setReadOnly(true);
+               waitCursor(true);
        }
 
        
@@ -6074,23 +6085,28 @@ public class NeverNote extends QMainWindow{
        // like async web calls.
        //*************************************************
        @SuppressWarnings("unused")
-       private void blockApplication(Long time) {
-               Calendar currentTime = new GregorianCalendar();
+       private void blockApplication(BrowserWindow b) {
+               // Block all signals
                waitCursor(true);
-               blockTime = new Long(currentTime.getTimeInMillis())+time;
-
-               for (;currentTime.getTimeInMillis()>blockTime;) {
-                       try {
-                               wait(1);
-                       } catch (InterruptedException e) {
-                               e.printStackTrace();
-                       }
-                       waitCursor(false);
-               }
-               
+               blockSignals(true);
+               
+               blockTimer = new QTimer();
+               blockTimer.setSingleShot(true);
+               blockTimer.setInterval(15000);
+               blockTimer.timeout.connect(this, "unblockApplication()");
+               blockingWindow  = b;
+               blockTimer.start();
        }
+       
        @SuppressWarnings("unused")
        private void unblockApplication() {
-               blockTime = -1;
+               waitCursor(false);
+               if (blockingWindow != null && new GregorianCalendar().getTimeInMillis() > blockingWindow.unblockTime && blockingWindow.unblockTime != -1) {
+                       QMessageBox.critical(null, tr("No Response from CodeCogs") ,tr("Unable to contact CodeCogs for LaTeX formula."));
+                       blockingWindow.unblockTime = -1;
+                       blockingWindow.awaitingHttpResponse = false;
+               }
+               blockingWindow = null;
+               blockSignals(false);
        }
 }
index 35a3201..d9b6d76 100644 (file)
@@ -244,8 +244,10 @@ public class BrowserWindow extends QWidget {
        boolean insertHyperlink = true;\r
        boolean insideTable = false;\r
        boolean insideEncryption = false;\r
-       public Signal1<Long> blockApplication;\r
+       public Signal1<BrowserWindow> blockApplication;\r
        public Signal0 unblockApplication;\r
+       public boolean awaitingHttpResponse;\r
+       public long     unblockTime;\r
        String latexGuid;  // This is set if we are editing an existing LaTeX formula.  Useful to track guid.\r
 \r
        \r
@@ -601,7 +603,7 @@ public class BrowserWindow extends QWidget {
                tagEdit.setPalette(pal);\r
                notebookBox.setPalette(pal);\r
                \r
-               blockApplication = new Signal1<Long>();\r
+               blockApplication = new Signal1<BrowserWindow>();\r
                unblockApplication = new Signal0();\r
                \r
                logger.log(logger.HIGH, "Browser setup complete");\r
@@ -661,7 +663,7 @@ public class BrowserWindow extends QWidget {
                alteredTime.setEnabled(!v);\r
                subjectTime.setEnabled(!v);\r
                getBrowser().setEnabled(true);\r
-               getBrowser().setEnabled(!v);\r
+//             getBrowser().setEnabled(!v);\r
        }\r
        \r
        // expose this class to Javascript on the web page\r
@@ -865,7 +867,7 @@ 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().startsWith("latex://")) {\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
@@ -1430,33 +1432,49 @@ public class BrowserWindow extends QWidget {
                        }\r
                        text = dialog.getFormula().trim();\r
                }\r
-               blockApplication.emit(new Long(5000));\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
-\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
                        newRes = createResource(path,0,"image/gif", false);\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
@@ -1466,13 +1484,13 @@ public class BrowserWindow extends QWidget {
                        tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));\r
                        tfile.write(image);\r
                        tfile.close();\r
+                       newRes.getData().setBody(image.toByteArray());\r
+                       conn.getNoteTable().noteResourceTable.updateNoteResource(newRes, true);\r
                }\r
 \r
-\r
-               newRes.getAttributes().setSourceURL(reply.url().toString());\r
-//             newRes.getData().setBody(image.toByteArray());\r
-//             conn.getNoteTable().noteResourceTable.updateNoteResource(newRes, true);\r
-               conn.getNoteTable().noteResourceTable.updateNoteSourceUrl(newRes.getGuid(), reply.url().toString(), true);\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
@@ -1487,10 +1505,11 @@ public class BrowserWindow extends QWidget {
                // just write out the file (which is aleady done) and reload.\r
                if (latexGuid == null) {\r
                        StringBuffer buffer = new StringBuffer(100);\r
-                       String formula = reply.url().toString().toLowerCase().replace("http://latex.codecogs.com/gif.latex?", "");\r
-                       buffer.append("<a href=\"latex://"+path.replace("\\", "/")+"\" title=\""+formula+"\"><img src=\"");\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-media type=\"image/gif\""\r
+                       buffer.append("\" en-tag=\"en-latex\" type=\"image/gif\""\r
                                +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""\r
                                +" guid=\"" +newRes.getGuid() +"\""\r
                                + " /></a>");\r
@@ -1500,13 +1519,18 @@ public class BrowserWindow extends QWidget {
                        browser.page().mainFrame().evaluateJavaScript(\r
                                        script_start + buffer + script_end);\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
-               browser.setHtml(browser.page().mainFrame().toHtml());\r
+               \r
+               browser.page().mainFrame().setHtml(browser.page().mainFrame().toHtml());\r
                browser.reload();\r
                contentChanged();\r
-               resourceSignal.contentChanged.emit(path);\r
+//             resourceSignal.contentChanged.emit(path);\r
+               unblockTime = -1;\r
        unblockApplication.emit();\r
+\r
                return;\r
                \r
        }\r
@@ -2226,14 +2250,17 @@ public class BrowserWindow extends QWidget {
                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
@@ -2291,6 +2318,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
index af4ce9f..3e9d060 100644 (file)
@@ -57,6 +57,13 @@ public class SaveRunner extends QObject implements Runnable {
                noteSignals = new NoteSignal();\r
        }\r
        \r
+       public SaveRunner(ApplicationLogger l, DatabaseConnection c) {\r
+               logger = l;\r
+               conn = c;\r
+               keepRunning = true;\r
+               noteSignals = new NoteSignal();\r
+       }\r
+       \r
        \r
        \r
        //*********************************************\r
index 1da2050..0632121 100644 (file)
@@ -1,9 +1,14 @@
 package cx.fbn.nevernote.xml;\r
 \r
+import java.io.ByteArrayInputStream;\r
+import java.io.ByteArrayOutputStream;\r
 import java.io.File;\r
 import java.util.ArrayList;\r
 import java.util.List;\r
 \r
+import org.w3c.tidy.Tidy;\r
+import org.w3c.tidy.TidyMessage;\r
+\r
 import com.evernote.edam.type.Note;\r
 import com.evernote.edam.type.Resource;\r
 import com.trolltech.qt.core.QByteArray;\r
@@ -12,6 +17,7 @@ import com.trolltech.qt.core.QFile;
 import com.trolltech.qt.core.QIODevice;\r
 import com.trolltech.qt.core.QIODevice.OpenModeFlag;\r
 import com.trolltech.qt.core.QTemporaryFile;\r
+import com.trolltech.qt.core.QTextCodec;\r
 import com.trolltech.qt.core.QUrl;\r
 import com.trolltech.qt.core.Qt.BGMode;\r
 import com.trolltech.qt.gui.QColor;\r
@@ -44,6 +50,7 @@ public class NoteFormatter {
        ArrayList<QTemporaryFile> tempFiles;\r
        private EnSearch enSearch;\r
        private boolean noteHistory;\r
+       public boolean formatError;\r
        \r
        public NoteFormatter(ApplicationLogger logger, DatabaseConnection conn, List<QTemporaryFile> tempFiles2) {\r
                this.logger = logger;\r
@@ -52,6 +59,34 @@ public class NoteFormatter {
        }\r
        \r
        \r
+       private class TidyListener implements org.w3c.tidy.TidyMessageListener {\r
+               \r
+               ApplicationLogger logger;\r
+               public boolean errorFound; \r
+               \r
+               public TidyListener(ApplicationLogger logger) {\r
+                       this.logger = logger;\r
+                       errorFound = false;\r
+               }\r
+               @Override\r
+               public void messageReceived(TidyMessage msg) {\r
+                       if (msg.getLevel() == TidyMessage.Level.ERROR) {\r
+                               logger.log(logger.LOW, "******* JTIDY ERORR *******");\r
+                               logger.log(logger.LOW, "Error Code: " +msg.getErrorCode());\r
+                               logger.log(logger.LOW, "Column: " +msg.getColumn());\r
+                               logger.log(logger.LOW, "Column: " +msg.getColumn());\r
+                               logger.log(logger.LOW, "Line: " +msg.getLine());\r
+                               logger.log(logger.LOW, "Message: " +msg.getMessage());\r
+                               logger.log(logger.LOW, "***************************");\r
+                               errorFound = true;\r
+                       } else \r
+                               logger.log(logger.EXTREME, "JTidy Results: "+msg.getMessage());\r
+               }\r
+               \r
+       }\r
+\r
+       \r
+       \r
        public void setNote(Note note, boolean pdfPreview) {\r
                currentNote = note;\r
                this.pdfPreview = pdfPreview;\r
@@ -81,6 +116,7 @@ public class NoteFormatter {
        \r
        // Rebuild the note HTML to something usable\r
        public String rebuildNoteHTML() {\r
+               formatError = false;\r
                if (currentNote == null)\r
                        return null;\r
                logger.log(logger.HIGH, "Entering NeverNote.rebuildNoteHTML");\r
@@ -88,12 +124,49 @@ public class NoteFormatter {
                logger.log(logger.EXTREME, "Note Text:" +currentNote);\r
                QDomDocument doc = new QDomDocument();\r
                QDomDocument.Result result = doc.setContent(currentNote.getContent());\r
+\r
+               // Handle any errors\r
+               if (!result.success) {\r
+                       logger.log(logger.LOW, "Error parsing document.  Attempting to restructure");\r
+                       Tidy tidy = new Tidy();\r
+                       TidyListener tidyListener = new TidyListener(logger);\r
+                       tidy.setMessageListener(tidyListener);\r
+                       tidy.getStderr().close();  // the listener will capture messages\r
+                       tidy.setXmlTags(true);\r
+                       \r
+                       QTextCodec codec;\r
+                       codec = QTextCodec.codecForName("UTF-8");\r
+               QByteArray unicode =  codec.fromUnicode(currentNote.getContent());\r
+               \r
+               logger.log(logger.MEDIUM, "Starting JTidy check");\r
+               logger.log(logger.MEDIUM, "Start of JTidy Input");\r
+               logger.log(logger.MEDIUM, currentNote.getContent());\r
+               logger.log(logger.MEDIUM, "End Of JTidy Input");\r
+                       ByteArrayInputStream is = new ByteArrayInputStream(unicode.toByteArray());\r
+               ByteArrayOutputStream os = new ByteArrayOutputStream();\r
+               tidy.setInputEncoding("UTF-8");\r
+                       tidy.parse(is, os);\r
+                       String tidyContent = os.toString();\r
+                       if (tidyListener.errorFound) {\r
+                               logger.log(logger.LOW, "Restructure failed!!!");\r
+                       } else {\r
+                               doc = null;\r
+                               doc = new QDomDocument();\r
+                               result = doc.setContent(tidyContent);\r
+                       }\r
+               }\r
                if (!result.success) {\r
-                       logger.log(logger.MEDIUM, "Parse error when rebuilding HTML");\r
+                       logger.log(logger.MEDIUM, "Parse error when rebuilding XML to HTML");\r
                        logger.log(logger.MEDIUM, "Note guid: " +currentNoteGuid);\r
-                       logger.log(logger.EXTREME, "Start of unmodified note HTML");\r
+                       logger.log(logger.MEDIUM, "Error: "+result.errorMessage);\r
+                       logger.log(logger.MEDIUM, "Line: " +result.errorLine + " Column: " +result.errorColumn);\r
+                       System.out.println("Error: "+result.errorMessage);\r
+                       System.out.println("Line: " +result.errorLine + " Column: " +result.errorColumn);\r
+                       logger.log(logger.EXTREME, "**** Start of unmodified note HTML");\r
                        logger.log(logger.EXTREME, currentNote.getContent());\r
-                       logger.log(logger.EXTREME, "End of unmodified note HTML");\r
+                       logger.log(logger.EXTREME, "**** End of unmodified note HTML");\r
+                       formatError = true;\r
+                       readOnly = true;\r
                        return currentNote.getContent();\r
                }\r
 \r
@@ -244,14 +317,16 @@ public class NoteFormatter {
                enmedia.setAttribute("src", tfile.fileName().toString());\r
                enmedia.setAttribute("en-tag", "en-media");\r
                enmedia.setTagName("img");\r
-               if (r.getAttributes().getSourceURL() == null || !r.getAttributes().getSourceURL().toLowerCase().startsWith("http://latex.codecogs.com/gif.latex?"))\r
+               if (r != null && r.getAttributes() != null && \r
+                               (r.getAttributes().getSourceURL() == null || !r.getAttributes().getSourceURL().toLowerCase().startsWith("http://latex.codecogs.com/gif.latex?")))\r
                        enmedia.setAttribute("onContextMenu", "window.jambi.imageContextMenu('" +tfile.fileName()  +"');");\r
                else {\r
                        QDomElement newText = doc.createElement("a");\r
                        enmedia.setAttribute("src", tfile.fileName().toString());\r
                        enmedia.setAttribute("en-tag", "en-latex");\r
                        newText.setAttribute("onMouseOver", "style.cursor='hand'");\r
-                       newText.setAttribute("title", r.getAttributes().getSourceURL());\r
+                       if (r!= null && r.getAttributes() != null && r.getAttributes().getSourceURL() != null)\r
+                               newText.setAttribute("title", r.getAttributes().getSourceURL());\r
                        newText.setAttribute("href", "latex://"+tfile.fileName().toString());\r
                        enmedia.parentNode().replaceChild(newText, enmedia);\r
                        newText.appendChild(enmedia);\r
@@ -276,7 +351,7 @@ public class NoteFormatter {
                // Modify en-media tags\r
                QDomNodeList anchors = docElem.elementsByTagName("en-media");\r
                int enMediaCount = anchors.length();\r
-               for (int i=enMediaCount-1; i>=0; i--) {\r
+               for (int i=enMediaCount-1; i>=0; --i) {\r
                        QDomElement enmedia = anchors.at(i).toElement();\r
                        if (enmedia.hasAttribute("type")) {\r
                                QDomAttr attr = enmedia.attributeNode("type");\r
index d0d860e..2fd872c 100644 (file)
@@ -207,7 +207,6 @@ public class XMLCleanup {
                                parent.removeChild(e);\r
                                parent.parentNode().replaceChild(e, parent);\r
                        }\r
-\r
                        \r
                        // If we've gotten this far, we have an en-media tag\r
                        e.setTagName(enType);\r