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/");
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)");
}
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();
}
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)
// 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
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" +
"\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);
}
// 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);
}
}
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
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
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
@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
}\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
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
// 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
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
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
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
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
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
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
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
}\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
\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
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
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
// 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
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