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
+\r
+import org.apache.commons.lang.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.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.QDataStream;\r
import com.trolltech.qt.core.QDateTime;\r
import com.trolltech.qt.gui.QPushButton;\r
import com.trolltech.qt.gui.QShortcut;\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.QNetworkRequest;\r
import cx.fbn.nevernote.dialog.EnDecryptDialog;\r
import cx.fbn.nevernote.dialog.GeoDialog;\r
import cx.fbn.nevernote.dialog.InsertLinkDialog;\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
public EditorButtonBar buttonLayout;\r
public final QComboBox fontList;\r
public final QAction fontListAction;\r
- public final QPushButton fontColor;\r
+ public final QToolButton fontColor;\r
public final QAction fontColorAction;\r
private final ColorMenu fontColorMenu;\r
- public final QPushButton fontHilight;\r
+ public final QToolButton fontHilight;\r
public final QAction fontHilightAction;\r
-// public final ColorComboBox fontHilight;\r
private final ColorMenu fontHilightColorMenu;\r
public final QFileSystemWatcher fileWatcher;\r
public int cursorPosition;\r
private final HashMap<String,Integer> previewPageList; \r
\r
\r
+ public static class SuggestionListener implements SpellCheckListener {\r
+ public boolean abortSpellCheck = false;\r
+ public boolean errorsFound = false;\r
+ \r
+ private final BrowserWindow parent;\r
+ public SuggestionListener(BrowserWindow parent) {\r
+ this.parent = parent;\r
+ }\r
+ public void spellingError(SpellCheckEvent event) {\r
+ errorsFound = true;\r
+ SpellCheck dialog = new SpellCheck();\r
+ dialog.setWord(event.getInvalidWord());\r
+\r
+ List<Word> suggestions = event.getSuggestions();\r
+ if (suggestions.isEmpty()) {\r
+ dialog.setNoSuggestions(true);\r
+ } else {\r
+ dialog.setCurrentSuggestion(suggestions.get(0).getWord());\r
+ for (int i=0; i<suggestions.size(); i++) {\r
+ dialog.addSuggestion(suggestions.get(i).getWord());\r
+ }\r
+ dialog.setSelectedSuggestion(0);\r
+ }\r
+ dialog.exec();\r
+ if (dialog.cancelPressed()) {\r
+ abortSpellCheck = true;\r
+ return;\r
+ }\r
+ if (dialog.replacePressed()) {\r
+ QClipboard clipboard = QApplication.clipboard();\r
+ clipboard.setText(dialog.getReplacementWord()); \r
+ parent.pasteClicked();\r
+ }\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
}\r
\r
// buttonLayout.addWidget(newSeparator(), 0);\r
- fontColor = newEditorButton("fontColor", tr("Font Color"));\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
fontColorAction = buttonLayout.addWidget(fontColor);\r
buttonLayout.toggleFontColorVisible.triggered.connect(this, "toggleFontColorVisible(Boolean)");\r
- fontHilight = newEditorButton("fontHilight", tr("Font Hilight Color"));\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
fontHilightAction = buttonLayout.addWidget(fontHilight);\r
+ fontHilightColorMenu.setDefault(QColor.yellow);\r
buttonLayout.toggleFontHilight.triggered.connect(this, "toggleFontHilightVisible(Boolean)");\r
\r
// buttonLayout.addWidget(new QLabel(), 1);\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
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
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
+ button.setIcon(icon);\r
+ button.setToolTip(toolTip);\r
+ button.clicked.connect(this, name + "Clicked()");\r
+ return button;\r
+ }\r
\r
// New Separator\r
private QLabel newSeparator() {\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
String selectedText = browser.selectedText();\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()\r
- +"\" title=" +dialog.getUrl().trim() \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
// Check the note title\r
private void checkNoteTitle() {\r
String text = browser.page().currentFrame().toPlainText();\r
- if (saveNoteTitle.trim().equals("")) {\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
}\r
\r
\r
+ // Invoke spell checker dialog\r
+ private void doSpellCheck() {\r
+\r
+ File wordList = new File(Global.getFileManager().getSpellDirPath()+Locale.getDefault()+".dic");\r
+ SpellDictionary dictionary;\r
+ try {\r
+ dictionary = new SpellDictionaryHashMap(wordList);\r
+ SpellChecker spellChecker = new SpellChecker(dictionary);\r
+ SuggestionListener spellListener = new SuggestionListener(this);\r
+ spellChecker.addSpellCheckListener(spellListener);\r
+\r
+ String content = getBrowser().page().mainFrame().toPlainText();\r
+ StringWordTokenizer tokenizer = new StringWordTokenizer(content);\r
+ if (!tokenizer.hasMoreWords())\r
+ return;\r
+ String word = tokenizer.nextWord();\r
+ getBrowser().page().action(WebAction.MoveToStartOfDocument);\r
+ QWebPage.FindFlags flags = new QWebPage.FindFlags();\r
+ flags.set(QWebPage.FindFlag.FindBackward);\r
+\r
+ getBrowser().setFocus();\r
+ boolean found = getBrowser().page().findText(word);\r
+ if (!found) {\r
+ QMessageBox.critical(this, tr("Spell Check Error"), \r
+ tr("An error has occurred while launching the spell check. The most probable" +\r
+ " cause is that the cursor was not at the beginning of the document.\n\n" +\r
+ "Please place the cursor at the beginning & try again"));\r
+ return;\r
+ }\r
+ while (found) {\r
+ found = getBrowser().page().findText(word);\r
+ }\r
+ \r
+ spellChecker.checkSpelling(new StringWordTokenizer(word));\r
+ getBrowser().setFocus();\r
+ \r
+ flags = new QWebPage.FindFlags();\r
+ tokenizer = new StringWordTokenizer(content);\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
+ spellChecker.removeSpellCheckListener(spellListener);\r
+ if (!spellListener.errorsFound)\r
+ QMessageBox.information(this, tr("Spell Check Complete"), \r
+ tr("No spelling errors found"));\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
+ } catch (IOException e) {\r
+ QMessageBox.critical(this, tr("Spell Check Error"), \r
+ tr("Dictionary "+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+\r
+ ".dic is invalid."));\r
+ }\r
\r
+ }\r
\r
}\r