/*\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
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.StringEscapeUtils;\r
import org.apache.commons.lang.StringUtils;\r
\r
import com.evernote.edam.limits.Constants;\r
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.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
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 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
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 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
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
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
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
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
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
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(getBrowser().page().mainFrame().toHtml());\r
+ }\r
// get/set current note\r
public void setNote(Note n) {\r
currentNote = n;\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
\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
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(" ") || 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
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
}\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
// The note contents have changed\r
public void contentChanged() {\r
String content = getContent();\r
+ setSource(content);\r
+ \r
checkNoteTitle();\r
noteSignal.noteChanged.emit(currentNote.getGuid(), content); \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(" ");\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
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
\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
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.unescapeHtml(removeTags(content));\r
+ QByteArray data = new QByteArray(sourceEditHeader+content+"</body></html>");\r
+ getBrowser().setContent(data);\r
+ checkNoteTitle();\r
+ noteSignal.noteChanged.emit(currentNote.getGuid(), sourceEdit.toPlainText()); \r
+ }\r
+ \r
+ private void setSource(String text) {\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
+ 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