/*\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
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
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
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
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
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
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
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
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
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
- 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
+ buttonLayout = new EditorButtonBar();\r
+ v.addWidget(buttonLayout);\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
+ 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
- buttonLayout.addWidget(indentButton);\r
- buttonLayout.addWidget(outdentButton);\r
- buttonLayout.addWidget(bulletListButton);\r
- buttonLayout.addWidget(numberListButton);\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
}\r
}\r
\r
- buttonLayout.addWidget(newSeparator(), 0);\r
- fontColor = newEditorButton("fontColor", tr("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", tr("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
+ QSplitter editSplitter = new QSplitter(this);\r
+ editSplitter.addWidget(browser);\r
+ editSplitter.setOrientation(Qt.Orientation.Vertical);\r
+ editSplitter.addWidget(sourceEdit);\r
\r
- buttonLayout.addWidget(new QLabel(), 1);\r
- v.addWidget(browser, 1);\r
-// v.addLayout(buttonLayout,0);\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
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
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
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();\r
+ }\r
// get/set current note\r
public void setNote(Note n) {\r
currentNote = n;\r
// 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
\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
@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
}\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
}\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
+ browser.setFocus();\r
insertImage(mime);\r
browser.setFocus();\r
return;\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
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
"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
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
\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, tr("Error"), tr("Error Encrypting String"));\r
+ 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
Global.cryptCounter++;\r
buffer.append(" id=\"crypt"+Global.cryptCounter.toString() +"\"");\r
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
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
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("\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
+ 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
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
\r
browser.encryptAction.setEnabled(enabled);\r
browser.insertLinkAction.setEnabled(enabled);\r
+ browser.insertQuickLinkAction.setEnabled(enabled);\r
// selectedText = text;\r
}\r
\r
\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
}\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
// 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
\r
// We know something has changed...\r
String oldTagArray[] = saveTagList.split(Global.tagDelimeter);\r
- String newTagArray[] = tagEdit.text().split(Global.tagDelimeter);\r
- \r
- if (!completionText.equals("") && newTagArray.length > 0) {\r
- newTagArray[newTagArray.length-1] = completionText;\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
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+", ";\r
+ newDisplay = newDisplay+Global.tagDelimeter +" ";\r
}\r
tagEdit.blockSignals(true);\r
tagEdit.setText(newDisplay);\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, ' ');");\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
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
+ noteSignal.titleChanged.emit(currentNote.getGuid(), titleLabel.text().trim());\r
+ currentNote.setTitle(titleLabel.text().trim());\r
+ saveNoteTitle = titleLabel.text().trim();\r
checkNoteTitle();\r
}\r
\r
}\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
// 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
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
// 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
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(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
// 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
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(&." +tfile.fileName() +"&.);\""\r
+ " />");\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
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
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
String imageURL = FileUtils.toFileURLString(Global.getFileManager().getImageDirFile(icon));\r
\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
+ \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('")\r
.append(Global.getFileManager().getResDirPath(fileName))\r
- .append("');\" "); buffer.append("type=\"" + mimeType + "\" href=\"nnres://" + fileName +"\" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\" >");\r
+ .append("');\" "); \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
}\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
+ 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
+ url = url.replace("file:///", "");\r
+ url = url.replace("file://", "");\r
String urlTest = new QUrl(url).toLocalFile();\r
+ urlTest = url;\r
if (!urlTest.equals(""))\r
url = urlTest;\r
- url = url.replace("/", File.separator);\r
- resourceFile = new QFile(url); \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
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
// 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
// * 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
// *************************************************************\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
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
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(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
+" 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
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
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 = ' '; "\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
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(tr("Edit Hyperlink"));\r
currentHyperlink = link;\r
+ insertHyperlink = false;\r
}\r
\r
public void italicActive() {\r
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
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
// browser.previousPageAction.setVisible(false);\r
}\r
*/\r
+ \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