2 * This file is part of NixNote/NeighborNote
3 * Copyright 2009 Randy Baumgarte
4 * Copyright 2013 Yuki Takahashi
6 * This file may be licensed under the terms of of the
7 * GNU General Public License Version 2 (the ``GPL'').
9 * Software distributed under the License is distributed
10 * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
11 * express or implied. See the GPL for the specific language
12 * governing rights and limitations.
14 * You should have received a copy of the GPL along with this
15 * program. If not, go to http://www.gnu.org/licenses/gpl.html
16 * or write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 package cx.fbn.nevernote.gui;
24 import java.io.FileNotFoundException;
25 import java.io.IOException;
26 import java.net.FileNameMap;
28 import java.net.URLConnection;
29 import java.security.MessageDigest;
30 import java.security.NoSuchAlgorithmException;
31 import java.text.SimpleDateFormat;
32 import java.util.ArrayList;
33 import java.util.Calendar;
34 import java.util.Collections;
35 import java.util.Date;
36 import java.util.GregorianCalendar;
37 import java.util.HashMap;
38 import java.util.List;
39 import java.util.Locale;
40 import java.util.StringTokenizer;
42 import org.apache.commons.lang3.StringEscapeUtils;
43 import org.apache.commons.lang3.StringUtils;
45 import com.evernote.edam.limits.Constants;
46 import com.evernote.edam.type.Data;
47 import com.evernote.edam.type.Note;
48 import com.evernote.edam.type.Notebook;
49 import com.evernote.edam.type.Resource;
50 import com.evernote.edam.type.ResourceAttributes;
51 import com.evernote.edam.type.Tag;
52 import com.evernote.edam.type.User;
53 import com.swabunga.spell.engine.Configuration;
54 import com.swabunga.spell.engine.SpellDictionary;
55 import com.swabunga.spell.engine.SpellDictionaryHashMap;
56 import com.swabunga.spell.engine.Word;
57 import com.swabunga.spell.event.SpellCheckEvent;
58 import com.swabunga.spell.event.SpellCheckListener;
59 import com.swabunga.spell.event.SpellChecker;
60 import com.swabunga.spell.event.StringWordTokenizer;
61 import com.trolltech.qt.core.QByteArray;
62 import com.trolltech.qt.core.QCoreApplication;
63 import com.trolltech.qt.core.QDataStream;
64 import com.trolltech.qt.core.QDateTime;
65 import com.trolltech.qt.core.QEvent;
66 import com.trolltech.qt.core.QEvent.Type;
67 import com.trolltech.qt.core.QFile;
68 import com.trolltech.qt.core.QFileSystemWatcher;
69 import com.trolltech.qt.core.QIODevice;
70 import com.trolltech.qt.core.QMimeData;
71 import com.trolltech.qt.core.QSize;
72 import com.trolltech.qt.core.QTextCodec;
73 import com.trolltech.qt.core.QTimer;
74 import com.trolltech.qt.core.QUrl;
75 import com.trolltech.qt.core.Qt;
76 import com.trolltech.qt.core.Qt.Key;
77 import com.trolltech.qt.core.Qt.KeyboardModifier;
78 import com.trolltech.qt.core.Qt.KeyboardModifiers;
79 import com.trolltech.qt.gui.QAction;
80 import com.trolltech.qt.gui.QApplication;
81 import com.trolltech.qt.gui.QCalendarWidget;
82 import com.trolltech.qt.gui.QClipboard;
83 import com.trolltech.qt.gui.QClipboard.Mode;
84 import com.trolltech.qt.gui.QColor;
85 import com.trolltech.qt.gui.QComboBox;
86 import com.trolltech.qt.gui.QDateEdit;
87 import com.trolltech.qt.gui.QDesktopServices;
88 import com.trolltech.qt.gui.QFileDialog;
89 import com.trolltech.qt.gui.QFileDialog.AcceptMode;
90 import com.trolltech.qt.gui.QFileDialog.FileMode;
91 import com.trolltech.qt.gui.QFont;
92 import com.trolltech.qt.gui.QFontDatabase;
93 import com.trolltech.qt.gui.QFormLayout;
94 import com.trolltech.qt.gui.QGridLayout;
95 import com.trolltech.qt.gui.QHBoxLayout;
96 import com.trolltech.qt.gui.QIcon;
97 import com.trolltech.qt.gui.QImage;
98 import com.trolltech.qt.gui.QKeyEvent;
99 import com.trolltech.qt.gui.QKeySequence;
100 import com.trolltech.qt.gui.QLabel;
101 import com.trolltech.qt.gui.QLineEdit;
102 import com.trolltech.qt.gui.QListWidgetItem;
103 import com.trolltech.qt.gui.QMatrix;
104 import com.trolltech.qt.gui.QMessageBox;
105 import com.trolltech.qt.gui.QPalette;
106 import com.trolltech.qt.gui.QPalette.ColorRole;
107 import com.trolltech.qt.gui.QPushButton;
108 import com.trolltech.qt.gui.QShortcut;
109 import com.trolltech.qt.gui.QSplitter;
110 import com.trolltech.qt.gui.QTextEdit;
111 import com.trolltech.qt.gui.QTextEdit.LineWrapMode;
112 import com.trolltech.qt.gui.QTimeEdit;
113 import com.trolltech.qt.gui.QToolButton;
114 import com.trolltech.qt.gui.QToolButton.ToolButtonPopupMode;
115 import com.trolltech.qt.gui.QVBoxLayout;
116 import com.trolltech.qt.gui.QWidget;
117 import com.trolltech.qt.network.QNetworkAccessManager;
118 import com.trolltech.qt.network.QNetworkReply;
119 import com.trolltech.qt.network.QNetworkReply.NetworkError;
120 import com.trolltech.qt.network.QNetworkRequest;
121 import com.trolltech.qt.webkit.QWebPage;
122 import com.trolltech.qt.webkit.QWebPage.WebAction;
123 import com.trolltech.qt.webkit.QWebSettings;
124 import com.trolltech.qt.webkit.QWebView;
126 import cx.fbn.nevernote.Global;
127 import cx.fbn.nevernote.clipboard.ClipBoardObserver;
128 import cx.fbn.nevernote.dialog.EnCryptDialog;
129 import cx.fbn.nevernote.dialog.EnDecryptDialog;
130 import cx.fbn.nevernote.dialog.GeoDialog;
131 import cx.fbn.nevernote.dialog.InsertLatexImage;
132 import cx.fbn.nevernote.dialog.InsertLinkDialog;
133 import cx.fbn.nevernote.dialog.NoteQuickLinkDialog;
134 import cx.fbn.nevernote.dialog.SpellCheck;
135 import cx.fbn.nevernote.dialog.TableDialog;
136 import cx.fbn.nevernote.dialog.TagAssign;
137 import cx.fbn.nevernote.evernote.EnCrypt;
138 import cx.fbn.nevernote.filters.FilterEditorTags;
139 import cx.fbn.nevernote.signals.NoteResourceSignal;
140 import cx.fbn.nevernote.signals.NoteSignal;
141 import cx.fbn.nevernote.sql.DatabaseConnection;
142 import cx.fbn.nevernote.utilities.ApplicationLogger;
143 import cx.fbn.nevernote.utilities.FileUtils;
144 import cx.fbn.nevernote.utilities.Pair;
145 import cx.fbn.nevernote.xml.HtmlTagModifier;
147 public class BrowserWindow extends QWidget {
149 public final QLineEdit titleLabel;
150 private final QLineEdit urlText;
151 private final QLabel authorLabel;
152 private final QLineEdit authorText;
153 private final QComboBox geoBox;
154 public final TagLineEdit tagEdit;
155 public final QLabel tagLabel;
156 private final QPushButton urlLabel;
157 private final QLabel alteredLabel;
158 private final QDateEdit alteredDate;
159 private final QTimeEdit alteredTime;
160 private final QDateEdit createdDate;
161 private final QTimeEdit createdTime;
162 private final QLabel subjectLabel;
163 private final QDateEdit subjectDate;
164 private final QTimeEdit subjectTime;
165 public final QComboBox notebookBox;
166 private final QLabel notebookLabel;
167 private final QLabel createdLabel;
168 public final QComboBox fontSize;
169 public final QAction fontSizeAction;
170 private boolean extendedOn;
171 public boolean buttonsVisible;
172 private final String iconPath;
173 public final ContentView browser;
174 private final QTextEdit sourceEdit;
175 private String sourceEditHeader;
176 Highlighter syntaxHighlighter;
177 private List<Tag> allTags;
178 private List<String> currentTags;
179 public NoteSignal noteSignal;
180 public Signal2<String,String> evernoteLinkClicked;
181 private List<Notebook> notebookList;
182 private Note currentNote;
183 private String saveNoteTitle;
184 private String saveTagList;
185 private boolean insideList;
186 private final DatabaseConnection conn;
187 private final QCalendarWidget createdCalendarWidget;
188 private final QCalendarWidget alteredCalendarWidget;
189 private final QCalendarWidget subjectCalendarWidget;
191 public final QPushButton undoButton;
192 public final QAction undoAction;
193 public final QPushButton redoButton;
194 public final QAction redoAction;
195 public final QPushButton cutButton;
196 public final QAction cutAction;
197 public final QPushButton copyButton;
198 public final QAction copyAction;
199 public final QPushButton pasteButton;
200 public final QAction pasteAction;
201 public final QPushButton boldButton;
202 public final QAction boldAction;
203 public final QPushButton underlineButton;
204 public final QAction underlineAction;
205 public final QPushButton italicButton;
206 public final QAction italicAction;
207 public final Signal0 focusLost;
208 public final NoteResourceSignal resourceSignal;
210 public QPushButton rightAlignButton;
211 public final QAction rightAlignAction;
212 public QPushButton leftAlignButton;
213 public final QAction leftAlignAction;
214 public QPushButton centerAlignButton;
215 public final QAction centerAlignAction;
217 public final QPushButton strikethroughButton;
218 public final QAction strikethroughAction;
219 public final QPushButton hlineButton;
220 public final QAction hlineAction;
221 public final QPushButton indentButton;
222 public final QAction indentAction;
223 public final QPushButton outdentButton;
224 public final QAction outdentAction;
225 public final QPushButton bulletListButton;
226 public final QAction bulletListAction;
227 public final QPushButton numberListButton;
228 public final QAction numberListAction;
229 public final QPushButton spellCheckButton;
230 public final QAction spellCheckAction;
231 public final QPushButton todoButton;
232 public final QAction todoAction;
234 public final QShortcut focusTitleShortcut;
235 public final QShortcut focusTagShortcut;
236 public final QShortcut focusNoteShortcut;
237 public final QShortcut focusUrlShortcut;
238 public final QShortcut focusAuthorShortcut;
240 public EditorButtonBar buttonLayout;
241 public final QComboBox fontList;
242 public final QAction fontListAction;
243 public final QToolButton fontColor;
244 public final QAction fontColorAction;
245 private final ColorMenu fontColorMenu;
246 public final QToolButton fontHilight;
247 public final QAction fontHilightAction;
248 private final ColorMenu fontHilightColorMenu;
249 public final QFileSystemWatcher fileWatcher;
250 public int cursorPosition;
251 private boolean forceTextPaste;
252 private String selectedFile;
253 private String currentHyperlink;
254 public boolean keepPDFNavigationHidden;
255 private final ApplicationLogger logger;
256 SpellDictionary dictionary;
257 SpellDictionary userDictionary;
258 SpellChecker spellChecker;
259 SuggestionListener spellListener;
260 private final HashMap<String,Integer> previewPageList;
261 boolean insertHyperlink;
263 boolean insideEncryption;
264 public Signal1<BrowserWindow> blockApplication;
265 public Signal0 unblockApplication;
266 public boolean awaitingHttpResponse;
267 public long unblockTime;
268 private final QTimer setSourceTimer;
269 String latexGuid; // This is set if we are editing an existing LaTeX formula. Useful to track guid.
271 private final ClipBoardObserver cbObserver;
273 public static class SuggestionListener implements SpellCheckListener {
274 public boolean abortSpellCheck = false;
275 public boolean errorsFound = false;
276 private final SpellCheck spellCheckDialog;
279 private final BrowserWindow parent;
280 public SuggestionListener(BrowserWindow parent, SpellChecker checker) {
281 this.parent = parent;
282 spellCheckDialog = new SpellCheck(checker);
284 public void spellingError(SpellCheckEvent event) {
286 spellCheckDialog.setWord(event.getInvalidWord());
288 @SuppressWarnings("unchecked")
289 List<Word> suggestions = event.getSuggestions();
290 spellCheckDialog.clearSuggestions();
291 if (!suggestions.isEmpty()) {
292 // spellCheckDialog.setCurrentSuggestion(suggestions.get(0).getWord());
293 for (int i=0; i<suggestions.size(); i++) {
294 spellCheckDialog.addSuggestion(suggestions.get(i).getWord());
296 spellCheckDialog.setSelectedSuggestion(0);
298 spellCheckDialog.exec();
299 if (spellCheckDialog.cancelPressed()) {
300 abortSpellCheck = true;
304 if (spellCheckDialog.replacePressed()) {
305 QClipboard clipboard = QApplication.clipboard();
306 clipboard.setText(spellCheckDialog.getReplacementWord());
307 parent.pasteClicked();
315 public BrowserWindow(DatabaseConnection c, ClipBoardObserver cbObserver) {
316 logger = new ApplicationLogger("browser.log");
317 logger.log(logger.HIGH, "Setting up browser");
318 iconPath = new String("classpath:cx/fbn/nevernote/icons/");
319 forceTextPaste = false;
320 insertHyperlink = true;
322 insideEncryption = false;
324 fileWatcher = new QFileSystemWatcher();
325 // fileWatcher.fileChanged.connect(this, "fileChanged(String)");
326 noteSignal = new NoteSignal();
327 titleLabel = new QLineEdit();
328 evernoteLinkClicked = new Signal2<String,String>();
329 titleLabel.setMaxLength(Constants.EDAM_NOTE_TITLE_LEN_MAX);
330 urlText = new QLineEdit();
331 authorText = new QLineEdit();
332 geoBox = new QComboBox();
333 urlLabel = new QPushButton();
334 urlLabel.clicked.connect(this, "sourceUrlClicked()");
335 authorLabel = new QLabel();
338 this.cbObserver = cbObserver;
340 focusLost = new Signal0();
342 tagEdit = new TagLineEdit(allTags);
343 tagLabel = new QLabel(tr("Tags:"));
344 tagEdit.focusLost.connect(this, "modifyTagsTyping()");
346 createdCalendarWidget = new QCalendarWidget();
347 createdDate = new QDateEdit();
348 createdDate.setDisplayFormat(Global.getDateFormat());
349 createdDate.setCalendarPopup(true);
350 createdDate.setCalendarWidget(createdCalendarWidget);
351 createdTime = new QTimeEdit();
352 createdDate.dateChanged.connect(this, "createdChanged()");
353 createdTime.timeChanged.connect(this, "createdChanged()");
355 alteredCalendarWidget = new QCalendarWidget();
356 alteredDate = new QDateEdit();
357 alteredDate.setDisplayFormat(Global.getDateFormat());
358 alteredDate.setCalendarPopup(true);
359 alteredDate.setCalendarWidget(alteredCalendarWidget);
360 alteredTime = new QTimeEdit();
361 alteredLabel = new QLabel(tr("Altered:"));
362 alteredDate.dateChanged.connect(this, "alteredChanged()");
363 alteredTime.timeChanged.connect(this, "alteredChanged()");
365 subjectCalendarWidget = new QCalendarWidget();
366 subjectDate = new QDateEdit();
367 subjectDate.setDisplayFormat(Global.getDateFormat());
368 subjectDate.setCalendarPopup(true);
369 subjectDate.setCalendarWidget(subjectCalendarWidget);
370 subjectTime = new QTimeEdit();
371 subjectLabel = new QLabel(tr("Subject Date:"));
372 subjectDate.dateChanged.connect(this, "subjectDateTimeChanged()");
373 subjectTime.timeChanged.connect(this, "subjectDateTimeChanged()");
374 authorText.textChanged.connect(this, "authorChanged()");
375 urlText.textChanged.connect(this, "sourceUrlChanged()");
377 notebookBox = new QComboBox();
378 notebookLabel = new QLabel(tr("Notebook"));
379 createdLabel = new QLabel(tr("Created:"));
380 // selectedText = new String();
382 urlLabel.setVisible(false);
383 urlText.setVisible(false);
384 authorLabel.setVisible(false);
386 geoBox.setVisible(false);
387 geoBox.addItem(new QIcon(iconPath+"globe.png"), "");
388 geoBox.addItem(new String(tr("Set")));
389 geoBox.addItem(new String(tr("Clear")));
390 geoBox.addItem(new String(tr("View On Map")));
391 geoBox.activated.connect(this, "geoBoxChanged()");
393 authorText.setVisible(false);
394 createdDate.setVisible(false);
395 alteredLabel.setVisible(false);
396 //notebookBox.setVisible(false);
397 notebookLabel.setVisible(false);
398 createdLabel.setVisible(false);
399 createdTime.setVisible(false);
400 alteredDate.setVisible(false);
401 alteredTime.setVisible(false);
402 subjectLabel.setVisible(false);
403 subjectDate.setVisible(false);
404 subjectTime.setVisible(false);
406 buttonsVisible = true;
407 setAcceptDrops(true);
409 browser = new ContentView(this);
411 browser.page().setLinkDelegationPolicy(
412 QWebPage.LinkDelegationPolicy.DelegateAllLinks);
413 browser.linkClicked.connect(this, "linkClicked(QUrl)");
414 currentHyperlink = "";
416 //Setup the source editor
417 sourceEdit = new QTextEdit(this);
418 sourceEdit.setVisible(false);
419 sourceEdit.setTabChangesFocus(true);
420 sourceEdit.setLineWrapMode(LineWrapMode.NoWrap);
421 QFont font = new QFont();
422 font.setFamily("Courier");
423 font.setFixedPitch(true);
424 font.setPointSize(10);
425 sourceEdit.setFont(font);
426 syntaxHighlighter = new Highlighter(sourceEdit.document());
427 sourceEdit.textChanged.connect(this, "sourceEdited()");
429 QVBoxLayout v = new QVBoxLayout();
430 QFormLayout notebookLayout = new QFormLayout();
431 QGridLayout dateLayout = new QGridLayout();
432 titleLabel.setReadOnly(false);
433 titleLabel.editingFinished.connect(this, "titleEdited()");
434 browser.page().contentsChanged.connect(this, "contentChanged()");
435 browser.page().selectionChanged.connect(this, "selectionChanged()");
436 browser.page().mainFrame().javaScriptWindowObjectCleared.connect(this,
437 "exposeToJavascript()");
439 notebookBox.activated.connect(this, "notebookChanged()");
440 resourceSignal = new NoteResourceSignal();
442 QHBoxLayout tagLayout = new QHBoxLayout();
443 v.addWidget(titleLabel, 0);
444 notebookLayout.addRow(notebookLabel, notebookBox);
445 tagLayout.addLayout(notebookLayout, 0);
446 tagLayout.stretch(4);
447 tagLayout.addWidget(tagLabel, 0);
448 tagLayout.addWidget(tagEdit, 1);
449 v.addLayout(tagLayout);
451 QHBoxLayout urlLayout = new QHBoxLayout();
452 urlLayout.addWidget(urlLabel, 0);
453 urlLayout.addWidget(urlText, 0);
454 v.addLayout(urlLayout);
456 QHBoxLayout authorLayout = new QHBoxLayout();
457 authorLayout.addWidget(authorLabel, 0);
458 authorLayout.addWidget(authorText, 0);
459 authorLayout.addWidget(geoBox);
460 v.addLayout(authorLayout);
462 dateLayout.addWidget(createdLabel, 0, 0);
463 dateLayout.addWidget(createdDate, 0, 1);
464 dateLayout.addWidget(createdTime, 0, 2);
465 dateLayout.setColumnStretch(9, 100);
466 dateLayout.addWidget(alteredLabel, 0, 3);
467 dateLayout.addWidget(alteredDate, 0, 4);
468 dateLayout.addWidget(alteredTime, 0, 5);
469 dateLayout.addWidget(subjectLabel, 0, 6);
470 dateLayout.addWidget(subjectDate, 0, 7);
471 dateLayout.addWidget(subjectTime, 0, 8);
472 v.addLayout(dateLayout, 0);
474 undoButton = newEditorButton("undo", tr("Undo Change"));
475 redoButton = newEditorButton("redo", tr("Redo Change"));
476 cutButton = newEditorButton("cut", tr("Cut"));
477 copyButton = newEditorButton("copy", tr("Copy"));
478 pasteButton = newEditorButton("paste", tr("Paste"));
479 boldButton = newEditorButton("bold", tr("Bold"));
480 underlineButton = newEditorButton("underline", tr("Underline"));
481 italicButton = newEditorButton("italic", tr("Italic"));
483 rightAlignButton = newEditorButton("justifyRight", tr("Right Align"));
484 leftAlignButton = newEditorButton("justifyLeft", tr("Left Align"));
485 centerAlignButton = newEditorButton("justifyCenter", tr("Center Align"));
487 strikethroughButton = newEditorButton("strikethrough", tr("Strikethrough"));
488 hlineButton = newEditorButton("hline", tr("Insert Horizontal Line"));
489 indentButton = newEditorButton("indent", tr("Shift Right"));
490 outdentButton = newEditorButton("outdent", tr("Shift Left"));
491 bulletListButton = newEditorButton("bulletList", tr("Bullet List"));
492 numberListButton = newEditorButton("numberList", tr("Number List"));
493 spellCheckButton = newEditorButton("spellCheck", tr("Spell Check"));
494 todoButton = newEditorButton("todo", tr("To-do"));
497 buttonLayout = new EditorButtonBar();
498 v.addWidget(buttonLayout);
500 undoAction = buttonLayout.addWidget(undoButton);
501 buttonLayout.toggleUndoVisible.triggered.connect(this, "toggleUndoVisible(Boolean)");
502 redoAction = buttonLayout.addWidget(redoButton);
503 buttonLayout.toggleRedoVisible.triggered.connect(this, "toggleRedoVisible(Boolean)");
505 buttonLayout.addWidget(newSeparator());
506 cutAction = buttonLayout.addWidget(cutButton);
507 buttonLayout.toggleCutVisible.triggered.connect(this, "toggleCutVisible(Boolean)");
508 copyAction = buttonLayout.addWidget(copyButton);
509 buttonLayout.toggleCopyVisible.triggered.connect(this, "toggleCopyVisible(Boolean)");
510 pasteAction = buttonLayout.addWidget(pasteButton);
511 buttonLayout.togglePasteVisible.triggered.connect(this, "togglePasteVisible(Boolean)");
513 buttonLayout.addWidget(newSeparator());
514 boldAction = buttonLayout.addWidget(boldButton);
515 buttonLayout.toggleBoldVisible.triggered.connect(this, "toggleBoldVisible(Boolean)");
516 italicAction = buttonLayout.addWidget(italicButton);
517 buttonLayout.toggleItalicVisible.triggered.connect(this, "toggleItalicVisible(Boolean)");
518 underlineAction = buttonLayout.addWidget(underlineButton);
519 buttonLayout.toggleUnderlineVisible.triggered.connect(this, "toggleUnderlineVisible(Boolean)");
520 strikethroughAction = buttonLayout.addWidget(strikethroughButton);
521 buttonLayout.toggleStrikethroughVisible.triggered.connect(this, "toggleStrikethroughVisible(Boolean)");
524 buttonLayout.addWidget(newSeparator());
525 leftAlignAction = buttonLayout.addWidget(leftAlignButton);
526 buttonLayout.toggleLeftAlignVisible.triggered.connect(this, "toggleLeftAlignVisible(Boolean)");
527 centerAlignAction = buttonLayout.addWidget(centerAlignButton);
528 buttonLayout.toggleCenterAlignVisible.triggered.connect(this, "toggleCenterAlignVisible(Boolean)");
529 rightAlignAction = buttonLayout.addWidget(rightAlignButton);
530 buttonLayout.toggleRightAlignVisible.triggered.connect(this, "toggleRightAlignVisible(Boolean)");
532 buttonLayout.addWidget(newSeparator());
533 hlineAction = buttonLayout.addWidget(hlineButton);
534 buttonLayout.toggleHLineVisible.triggered.connect(this, "toggleHLineVisible(Boolean)");
536 indentAction = buttonLayout.addWidget(indentButton);
537 buttonLayout.toggleIndentVisible.triggered.connect(this, "toggleIndentVisible(Boolean)");
538 outdentAction = buttonLayout.addWidget(outdentButton);
539 buttonLayout.toggleOutdentVisible.triggered.connect(this, "toggleOutdentVisible(Boolean)");
540 bulletListAction = buttonLayout.addWidget(bulletListButton);
541 buttonLayout.toggleBulletListVisible.triggered.connect(this, "toggleBulletListVisible(Boolean)");
542 numberListAction = buttonLayout.addWidget(numberListButton);
543 buttonLayout.toggleNumberListVisible.triggered.connect(this, "toggleNumberListVisible(Boolean)");
545 // Setup the font & font size combo boxes
546 buttonLayout.addWidget(newSeparator());
547 fontList = new QComboBox();
548 fontSize = new QComboBox();
549 fontList.setMaximumWidth(130);
550 fontSize.setMaximumWidth(45);
551 fontList.setToolTip("Font");
552 fontSize.setToolTip("Font Size");
553 fontList.activated.connect(this, "fontChanged(String)");
554 fontSize.activated.connect(this, "fontSizeChanged(String)");
555 fontListAction = buttonLayout.addWidget(fontList);
556 buttonLayout.toggleFontVisible.triggered.connect(this, "toggleFontListVisible(Boolean)");
557 fontSizeAction = buttonLayout.addWidget(fontSize);
558 buttonLayout.toggleFontSizeVisible.triggered.connect(this, "toggleFontSizeVisible(Boolean)");
559 QFontDatabase fonts = new QFontDatabase();
560 List<String> fontFamilies = fonts.families();
561 for (int i = 0; i < fontFamilies.size(); i++) {
562 fontList.addItem(fontFamilies.get(i));
564 loadFontSize(fontFamilies.get(i));
568 // buttonLayout.addWidget(newSeparator(), 0);
569 fontColor = newToolButton("fontColor", tr("Font Color"));
570 fontColorMenu = new ColorMenu(this);
571 fontColor.setMenu(fontColorMenu.getMenu());
572 fontColor.setPopupMode(ToolButtonPopupMode.MenuButtonPopup);
573 fontColor.setAutoRaise(false);
574 fontColorMenu.getMenu().triggered.connect(this, "fontColorClicked()");
575 fontColorAction = buttonLayout.addWidget(fontColor);
576 buttonLayout.toggleFontColorVisible.triggered.connect(this, "toggleFontColorVisible(Boolean)");
577 fontHilight = newToolButton("fontHilight", tr("Font Hilight Color"));
578 fontHilight.setPopupMode(ToolButtonPopupMode.MenuButtonPopup);
579 fontHilight.setAutoRaise(false);
580 fontHilightColorMenu = new ColorMenu(this);
581 fontHilightColorMenu.setDefault(QColor.yellow);
582 fontHilight.setMenu(fontHilightColorMenu.getMenu());
583 fontHilightColorMenu.getMenu().triggered.connect(this, "fontHilightClicked()");
584 fontHilightAction = buttonLayout.addWidget(fontHilight);
585 fontHilightColorMenu.setDefault(QColor.yellow);
586 buttonLayout.toggleFontHilight.triggered.connect(this, "toggleFontHilightVisible(Boolean)");
588 spellCheckAction = buttonLayout.addWidget(spellCheckButton);
589 buttonLayout.toggleNumberListVisible.triggered.connect(this, "spellCheckClicked()");
590 buttonLayout.toggleSpellCheck.triggered.connect(this, "toggleSpellCheckVisible(Boolean)");
592 todoAction = buttonLayout.addWidget(todoButton);
593 buttonLayout.toggleNumberListVisible.triggered.connect(this, "todoClicked()");
594 buttonLayout.toggleTodo.triggered.connect(this, "toggleTodoVisible(Boolean)");
596 // Setup the source browser);
598 // buttonLayout.addWidget(new QLabel(), 1);
599 QSplitter editSplitter = new QSplitter(this);
600 editSplitter.addWidget(browser);
601 editSplitter.setOrientation(Qt.Orientation.Vertical);
602 editSplitter.addWidget(sourceEdit);
606 // v.addWidget(browser, 1);
607 // v.addWidget(sourceEdit);
608 v.addWidget(editSplitter);
611 browser.downloadAttachmentRequested.connect(this,
612 "downloadAttachment(QNetworkRequest)");
613 browser.downloadImageRequested.connect(this,
614 "downloadImage(QNetworkRequest)");
615 setTabOrder(notebookBox, tagEdit);
616 setTabOrder(tagEdit, browser);
618 focusNoteShortcut = new QShortcut(this);
619 setupShortcut(focusNoteShortcut, "Focus_Note");
620 focusNoteShortcut.activated.connect(this, "focusNote()");
621 focusTitleShortcut = new QShortcut(this);
622 setupShortcut(focusTitleShortcut, "Focus_Title");
623 focusTitleShortcut.activated.connect(this, "focusTitle()");
624 focusTagShortcut = new QShortcut(this);
625 setupShortcut(focusTagShortcut, "Focus_Tag");
626 focusTagShortcut.activated.connect(this, "focusTag()");
627 focusAuthorShortcut = new QShortcut(this);
628 setupShortcut(focusAuthorShortcut, "Focus_Author");
629 focusAuthorShortcut.activated.connect(this, "focusAuthor()");
630 focusUrlShortcut = new QShortcut(this);
631 setupShortcut(focusUrlShortcut, "Focus_Url");
632 focusUrlShortcut.activated.connect(this, "focusUrl()");
634 browser.page().mainFrame().setTextSizeMultiplier(Global.getTextSizeMultiplier());
635 browser.page().mainFrame().setZoomFactor(Global.getZoomFactor());
637 previewPageList = new HashMap<String,Integer>();
639 browser.page().microFocusChanged.connect(this, "microFocusChanged()");
643 QPalette pal = new QPalette();
644 pal.setColor(ColorRole.Text, QColor.black);
645 titleLabel.setPalette(pal);
646 authorText.setPalette(pal);
647 authorLabel.setPalette(pal);
648 urlLabel.setPalette(pal);
649 urlText.setPalette(pal);
650 createdDate.setPalette(pal);
651 createdTime.setPalette(pal);
652 alteredDate.setPalette(pal);
653 alteredTime.setPalette(pal);
654 subjectDate.setPalette(pal);
655 subjectTime.setPalette(pal);
656 tagEdit.setPalette(pal);
657 notebookBox.setPalette(pal);
659 blockApplication = new Signal1<BrowserWindow>();
660 unblockApplication = new Signal0();
662 setSourceTimer = new QTimer();
663 setSourceTimer.timeout.connect(this, "setSource()");
665 logger.log(logger.HIGH, "Browser setup complete");
670 private void setupShortcut(QShortcut action, String text) {
671 if (!Global.shortcutKeys.containsAction(text))
673 action.setKey(new QKeySequence(Global.shortcutKeys.getShortcut(text)));
679 // Getter for the QWebView
680 public QWebView getBrowser() {
684 // Block signals while loading data or things are flagged as dirty by
686 public void loadingData(boolean val) {
687 logger.log(logger.EXTREME, "Entering BrowserWindow.loadingData() " +val);
688 notebookBox.blockSignals(val);
689 browser.page().blockSignals(val);
690 browser.page().mainFrame().blockSignals(val);
691 titleLabel.blockSignals(val);
692 alteredDate.blockSignals(val);
693 alteredTime.blockSignals(val);
694 createdTime.blockSignals(val);
695 createdDate.blockSignals(val);
696 subjectDate.blockSignals(val);
697 subjectTime.blockSignals(val);
698 urlText.blockSignals(val);
699 authorText.blockSignals(val);
701 exposeToJavascript();
702 logger.log(logger.EXTREME, "Exiting BrowserWindow.loadingData() " +val);
706 public void setReadOnly(boolean v) {
708 titleLabel.setEnabled(!v);
709 notebookBox.setEnabled(!v);
710 tagEdit.setEnabled(!v);
711 authorLabel.setEnabled(!v);
712 geoBox.setEnabled(!v);
713 urlText.setEnabled(!v);
714 createdDate.setEnabled(!v);
715 subjectDate.setEnabled(!v);
716 alteredDate.setEnabled(!v);
717 authorText.setEnabled(!v);
718 createdTime.setEnabled(!v);
719 alteredTime.setEnabled(!v);
720 subjectTime.setEnabled(!v);
721 getBrowser().setEnabled(true);
722 getBrowser().page().setContentEditable(!v);
723 // getBrowser().setEnabled(!v);
726 // expose this class to Javascript on the web page
727 private void exposeToJavascript() {
728 browser.page().mainFrame().addToJavaScriptWindowObject("jambi", this);
731 // Custom event queue
733 public boolean event(QEvent e) {
734 if (e.type().equals(QEvent.Type.FocusOut)) {
735 logger.log(logger.EXTREME, "Focus lost");
738 return super.event(e);
742 public void clear() {
743 logger.log(logger.EXTREME, "Entering BrowserWindow.clear()");
745 setContent(new QByteArray());
747 tagEdit.tagCompleter.reset();
748 urlLabel.setText(tr("Source URL:"));
749 titleLabel.setText("");
750 logger.log(logger.EXTREME, "Exiting BrowserWindow.clear()");
753 public void setContent(QByteArray data) {
754 sourceEdit.blockSignals(true);
755 browser.setContent(data);
758 // get/set current note
759 public void setNote(Note n) {
763 saveNoteTitle = n.getTitle();
767 public Note getNote() {
772 private QPushButton newEditorButton(String name, String toolTip) {
773 QPushButton button = new QPushButton();
774 // QIcon icon = new QIcon(iconPath + name + ".gif");
775 QIcon icon = new QIcon(iconPath + name + ".png");
776 button.setIcon(icon);
777 button.setIconSize(new QSize(16, 16));
779 button.setToolTip(toolTip);
780 button.clicked.connect(this, name + "Clicked()");
784 private QToolButton newToolButton(String name, String toolTip) {
785 QToolButton button = new QToolButton();
786 // QIcon icon = new QIcon(iconPath + name + ".gif");
787 QIcon icon = new QIcon(iconPath + name + ".png");
788 button.setIcon(icon);
789 button.setIconSize(new QSize(16, 16));
791 button.setToolTip(toolTip);
792 button.clicked.connect(this, name + "Clicked()");
797 private QLabel newSeparator() {
798 return new QLabel(" ");
801 // Set the title in the window
802 public void setTitle(String t) {
803 titleLabel.setText(t);
808 // Return the current text title
809 public String getTitle() {
810 return titleLabel.text();
813 // Set the tag name string
814 public void setTag(String t) {
817 tagEdit.tagCompleter.reset();
820 // Set the source URL
821 public void setUrl(String t) {
822 urlLabel.setText(tr("Source URL:\t"));
826 // The user want's to launch a web browser on the source of the URL
827 public void sourceUrlClicked() {
828 // Make sure we have a valid URL
829 if (urlText.text().trim().equals(""))
832 String url = urlText.text();
833 if (!url.toLowerCase().startsWith(tr("http://")))
834 url = tr("http://") +url;
836 if (!QDesktopServices.openUrl(new QUrl(url))) {
837 logger.log(logger.LOW, "Error opening file :" +url);
841 public void setAuthor(String t) {
842 authorLabel.setText(tr("Author:\t"));
843 authorText.setText(t);
846 // Set the creation date
847 public void setCreation(long date) {
848 QDateTime dt = new QDateTime();
849 dt.setTime_t((int) (date / 1000));
850 createdDate.setDateTime(dt);
851 createdTime.setDateTime(dt);
852 createdDate.setDisplayFormat(Global.getDateFormat());
853 createdTime.setDisplayFormat(Global.getTimeFormat());
856 // Set the creation date
857 public void setAltered(long date) {
858 QDateTime dt = new QDateTime();
859 dt.setTime_t((int) (date / 1000));
860 alteredDate.setDateTime(dt);
861 alteredTime.setDateTime(dt);
862 alteredDate.setDisplayFormat(Global.getDateFormat());
863 alteredTime.setDisplayFormat(Global.getTimeFormat());
866 // Set the subject date
867 public void setSubjectDate(long date) {
868 QDateTime dt = new QDateTime();
869 dt.setTime_t((int) (date / 1000));
870 subjectDate.setDateTime(dt);
871 subjectTime.setDateTime(dt);
872 subjectDate.setDisplayFormat(Global.getDateFormat());
873 subjectTime.setDisplayFormat(Global.getTimeFormat());
876 // Toggle the extended attribute information
877 public void toggleInformation() {
883 urlLabel.setVisible(extendedOn);
884 urlText.setVisible(extendedOn);
885 authorText.setVisible(extendedOn);
886 geoBox.setVisible(extendedOn);
887 authorLabel.setVisible(extendedOn);
888 createdDate.setVisible(extendedOn);
889 createdTime.setVisible(extendedOn);
890 createdLabel.setVisible(extendedOn);
891 alteredLabel.setVisible(extendedOn);
892 alteredDate.setVisible(extendedOn);
893 alteredTime.setVisible(extendedOn);
894 //notebookBox.setVisible(extendedOn);
895 notebookLabel.setVisible(extendedOn);
896 subjectLabel.setVisible(extendedOn);
897 subjectDate.setVisible(extendedOn);
898 subjectTime.setVisible(extendedOn);
901 public void hideButtons() {
903 undoButton.parentWidget().setVisible(false);
904 buttonsVisible = false;
908 // Is the extended view on?
909 public boolean isExtended() {
913 // Listener for when a link is clicked
914 @SuppressWarnings("unused")
915 private void openFile() {
916 logger.log(logger.EXTREME, "Starting openFile()");
917 File fileHandle = new File(selectedFile);
918 URI fileURL = fileHandle.toURI();
919 String localURL = fileURL.toString();
920 QUrl url = new QUrl(localURL);
921 QFile file = new QFile(selectedFile);
923 logger.log(logger.EXTREME, "Adding to fileWatcher:"+file.fileName());
924 fileWatcher.addPath(file.fileName());
926 if (!QDesktopServices.openUrl(url)) {
927 logger.log(logger.LOW, "Error opening file :" +url);
932 // Listener for when a link is clicked
933 @SuppressWarnings("unused")
934 private void linkClicked(QUrl url) {
935 logger.log(logger.EXTREME, "URL Clicked: " +url.toString());
936 if (url.toString().startsWith("latex:")) {
937 int position = url.toString().lastIndexOf(".");
938 String guid = url.toString().substring(0,position);
939 position = guid.lastIndexOf("/");
940 guid = guid.substring(position+1);
944 if (url.toString().startsWith("evernote:/view/")) {
945 StringTokenizer tokens = new StringTokenizer(url.toString().replace("evernote:/view/", ""), "/");
948 String sid = tokens.nextToken();
949 String lid = tokens.nextToken();
951 // Emit that we want to switch to a new note
952 evernoteLinkClicked.emit(sid, lid);
956 if (url.toString().startsWith("nnres://")) {
957 logger.log(logger.EXTREME, "URL is NN resource");
958 if (url.toString().endsWith("/vnd.evernote.ink")) {
959 logger.log(logger.EXTREME, "Unable to open ink note");
960 QMessageBox.information(this, tr("Unable Open"), tr("This is an ink note.\n"+
961 "Ink notes are not supported since Evernote has not\n published any specifications on them\n" +
962 "and I'm too lazy to figure them out by myself."));
965 String fullName = url.toString().substring(8);
966 int index = fullName.indexOf(".");
970 type = fullName.substring(index+1);
971 guid = fullName.substring(0,index);
973 index = guid.indexOf(Global.attachmentNameDelimeter);
975 guid = guid.substring(0,index);
977 List<Resource> resList = currentNote.getResources();
979 for (int i=0; i<resList.size(); i++) {
980 if (resList.get(i).getGuid().equals(guid)) {
981 res = resList.get(i);
986 String resGuid = Global.resourceMap.get(guid);
988 res = conn.getNoteTable().noteResourceTable.getNoteResource(resGuid, true);
992 if (res.getAttributes() != null &&
993 res.getAttributes().getFileName() != null &&
994 !res.getAttributes().getFileName().trim().equals(""))
995 fileName = res.getGuid()+Global.attachmentNameDelimeter+res.getAttributes().getFileName();
997 fileName = res.getGuid()+"."+type;
998 QFile file = new QFile(Global.getFileManager().getResDirPath(fileName));
999 QFile.OpenMode mode = new QFile.OpenMode();
1000 mode.set(QFile.OpenModeFlag.WriteOnly);
1001 boolean openResult = file.open(mode);
1002 logger.log(logger.EXTREME, "File opened:" +openResult);
1003 QDataStream out = new QDataStream(file);
1004 Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(res.getGuid(), true);
1005 QByteArray binData = new QByteArray(resBinary.getData().getBody());
1007 logger.log(logger.EXTREME, "Writing resource");
1008 out.writeBytes(binData.toByteArray());
1011 String whichOS = System.getProperty("os.name");
1012 if (whichOS.contains("Windows"))
1013 url.setUrl("file:///"+file.fileName());
1015 url.setUrl("file://"+file.fileName());
1016 // fileWatcher.removePath(file.fileName());
1017 logger.log(logger.EXTREME, "Adding file watcher " +file.fileName());
1018 fileWatcher.addPath(file.fileName());
1020 // If we can't open it, then prompt the user to save it.
1021 if (!QDesktopServices.openUrl(url)) {
1022 logger.log(logger.EXTREME, "We can't handle this. Where do we put it?");
1023 QFileDialog dialog = new QFileDialog();
1025 if (dialog.exec()!=0) {
1026 List<String> fileNames = dialog.selectedFiles(); //gets all selected filenames
1027 if (fileNames.size() == 0)
1029 String sf = fileNames.get(0);
1030 QFile saveFile = new QFile(sf);
1031 mode.set(QFile.OpenModeFlag.WriteOnly);
1032 saveFile.open(mode);
1033 QDataStream saveOut = new QDataStream(saveFile);
1034 saveOut.writeBytes(binData.toByteArray());
1042 logger.log(logger.EXTREME, "Launching URL");
1043 QDesktopServices.openUrl(url);
1046 // Listener for when BOLD is clicked
1047 @SuppressWarnings("unused")
1048 private void undoClicked() {
1049 browser.page().triggerAction(WebAction.Undo);
1053 // Listener for when BOLD is clicked
1054 @SuppressWarnings("unused")
1055 private void redoClicked() {
1056 browser.page().triggerAction(WebAction.Redo);
1060 // Listener for when BOLD is clicked
1061 @SuppressWarnings("unused")
1062 private void boldClicked() {
1063 browser.page().triggerAction(WebAction.ToggleBold);
1064 microFocusChanged();
1068 // Listener for when Italics is clicked
1069 @SuppressWarnings("unused")
1070 private void italicClicked() {
1071 browser.page().triggerAction(WebAction.ToggleItalic);
1072 microFocusChanged();
1076 // Listener for when UNDERLINE is clicked
1077 @SuppressWarnings("unused")
1078 private void underlineClicked() {
1079 browser.page().triggerAction(WebAction.ToggleUnderline);
1080 microFocusChanged();
1084 // Listener for when Strikethrough is clicked
1085 @SuppressWarnings("unused")
1086 private void strikethroughClicked() {
1087 browser.page().mainFrame().evaluateJavaScript(
1088 "document.execCommand('strikeThrough', false, '');");
1092 // Listener for when cut is clicked
1093 @SuppressWarnings("unused")
1094 private void cutClicked() {
1095 cbObserver.setCopySourceGuid(currentNote.getGuid(), browser.page().selectedText());
1097 browser.page().triggerAction(WebAction.Cut);
1101 // Listener when COPY is clicked
1102 @SuppressWarnings("unused")
1103 private void copyClicked() {
1104 cbObserver.setCopySourceGuid(currentNote.getGuid(), browser.page().selectedText());
1106 browser.page().triggerAction(WebAction.Copy);
1110 // Listener when PASTE is clicked
1111 public void pasteClicked() {
1112 logger.log(logger.EXTREME, "Paste Clicked");
1113 if (forceTextPaste) {
1114 pasteWithoutFormattingClicked();
1118 // コピー&ペーストの操作履歴をデータベースに登録
1119 String srcGuid = cbObserver.getSourceGuid();
1120 String dstGuid = currentNote.getGuid();
1121 if(srcGuid != null && dstGuid != null){
1122 if(!srcGuid.equals(dstGuid)){
1123 conn.getHistoryTable().addHistory("copy & paste", srcGuid, dstGuid);
1127 QClipboard clipboard = QApplication.clipboard();
1128 QMimeData mime = clipboard.mimeData();
1130 if (mime.hasImage()) {
1131 logger.log(logger.EXTREME, "Image paste found");
1138 if (mime.hasUrls()) {
1139 logger.log(logger.EXTREME, "URL paste found");
1140 if (mime.text().startsWith("evernote:")) {
1141 handleNoteLink(mime);
1149 String text = mime.html();
1150 if (text.contains("en-tag") && mime.hasHtml()) {
1151 logger.log(logger.EXTREME, "Intra-note paste found");
1152 text = fixInternotePaste(text);
1154 clipboard.setMimeData(mime);
1157 logger.log(logger.EXTREME, "Final paste choice encountered");
1158 browser.page().triggerAction(WebAction.Paste);
1163 // Paste text without formatting
1164 private void pasteWithoutFormattingClicked() {
1165 logger.log(logger.EXTREME, "Paste without format clipped");
1166 QClipboard clipboard = QApplication.clipboard();
1167 QMimeData mime = clipboard.mimeData();
1168 if (!mime.hasText())
1171 // コピー&ペーストの操作履歴をデータベースに登録
1172 String srcGuid = cbObserver.getSourceGuid();
1173 String dstGuid = currentNote.getGuid();
1174 if(srcGuid != null && dstGuid != null){
1175 if(!srcGuid.equals(dstGuid)){
1176 conn.getHistoryTable().addHistory("copy & paste", srcGuid, dstGuid);
1180 String text = mime.text();
1182 clipboard.setText(text, Mode.Clipboard);
1183 browser.page().triggerAction(WebAction.Paste);
1185 // This is done because pasting into an encryption block
1186 // can cause multiple cells (which can't happen). It
1187 // just goes through the table, extracts the data, &
1188 // puts it back as one table cell.
1189 if (insideEncryption) {
1190 String js = new String( "function fixEncryption() { "
1191 +" var selObj = window.getSelection();"
1192 +" var selRange = selObj.getRangeAt(0);"
1193 +" var workingNode = window.getSelection().anchorNode;"
1194 +" while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { "
1195 +" workingNode = workingNode.parentNode;"
1197 +" workingNode.innerHTML = window.jambi.fixEncryptionPaste(workingNode.innerHTML);"
1198 +"} fixEncryption();");
1199 browser.page().mainFrame().evaluateJavaScript(js);
1203 // This basically removes all the table tags and returns just the contents.
1204 // This is called by JavaScript to fix encryption pastes.
1205 public String fixEncryptionPaste(String data) {
1206 data = data.replace("<tbody>", "");
1207 data = data.replace("</tbody>", "");
1208 data = data.replace("<tr>", "");
1209 data = data.replace("</tr>", "");
1210 data = data.replace("<td>", "");
1211 data = data.replace("</td>", "<br>");
1212 data = data.replace("<br><br>", "<br>");
1214 return "<tbody><tr><td>"+data+"</td></tr></tbody>";
1218 @SuppressWarnings("unused")
1219 private void insertDateTime() {
1220 String fmt = Global.getDateFormat() + " " + Global.getTimeFormat();
1221 String dateTimeFormat = new String(fmt);
1222 SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);
1223 Calendar cal = Calendar.getInstance();
1225 browser.page().mainFrame().evaluateJavaScript(
1226 "document.execCommand('insertHtml', false, '"+simple.format(cal.getTime())+"');");
1232 // Listener when Left is clicked
1233 @SuppressWarnings("unused")
1234 private void justifyLeftClicked() {
1235 browser.page().mainFrame().evaluateJavaScript(
1236 "document.execCommand('JustifyLeft', false, '');");
1240 // Listener when Center is clicked
1241 @SuppressWarnings("unused")
1242 private void justifyCenterClicked() {
1243 browser.page().mainFrame().evaluateJavaScript(
1244 "document.execCommand('JustifyCenter', false, '');");
1248 // Listener when Left is clicked
1249 @SuppressWarnings("unused")
1250 private void justifyRightClicked() {
1251 browser.page().mainFrame().evaluateJavaScript(
1252 "document.execCommand('JustifyRight', false, '');");
1256 // Listener when HLINE is clicked
1257 @SuppressWarnings("unused")
1258 private void hlineClicked() {
1259 browser.page().mainFrame().evaluateJavaScript(
1260 "document.execCommand('insertHorizontalRule', false, '');");
1264 // Listener when outdent is clicked
1265 private void outdentClicked() {
1266 browser.page().mainFrame().evaluateJavaScript(
1267 "document.execCommand('outdent', false, '');");
1271 // Listener when a bullet list is clicked
1272 @SuppressWarnings("unused")
1273 private void bulletListClicked() {
1274 browser.page().mainFrame().evaluateJavaScript(
1275 "document.execCommand('InsertUnorderedList', false, '');");
1279 // Listener when a bullet list is clicked
1280 @SuppressWarnings("unused")
1281 private void numberListClicked() {
1282 browser.page().mainFrame().evaluateJavaScript(
1283 "document.execCommand('InsertOrderedList', false, '');");
1287 // Listener when indent is clicked
1288 private void indentClicked() {
1289 browser.page().mainFrame().evaluateJavaScript(
1290 "document.execCommand('indent', false, '');");
1294 // Listener when the font name is changed
1295 @SuppressWarnings("unused")
1296 private void fontChanged(String font) {
1297 browser.page().mainFrame().evaluateJavaScript(
1298 "document.execCommand('fontName',false,'" + font + "');");
1302 // Listener when a font size is changed
1303 @SuppressWarnings("unused")
1304 private void fontSizeChanged(String font) {
1305 String text = browser.selectedText();
1306 if (text.trim().equalsIgnoreCase(""))
1309 String selectedText = browser.selectedText();
1310 String url = "<span style=\"font-size:" +font +"pt; \">"+selectedText +"</a>";
1311 String script = "document.execCommand('insertHtml', false, '"+url+"');";
1312 browser.page().mainFrame().evaluateJavaScript(script);
1313 /* browser.page().mainFrame().evaluateJavaScript(
1314 "document.execCommand('fontSize',false,'"
1320 // Load the font combo box based upon the font selected
1321 private void loadFontSize(String name) {
1322 QFontDatabase db = new QFontDatabase();
1324 List<Integer> points = db.pointSizes(name);
1325 for (int i=0; i<points.size(); i++) {
1326 fontSize.addItem(points.get(i).toString());
1329 fontSize.addItem("x-small");
1330 fontSize.addItem("small");
1331 fontSize.addItem("medium");
1332 fontSize.addItem("large");
1333 fontSize.addItem("x-large");
1334 fontSize.addItem("xx-large");
1335 fontSize.addItem("xxx-large");
1339 // Listener when a font size is changed
1340 @SuppressWarnings("unused")
1341 private void fontColorClicked() {
1342 // QColorDialog dialog = new QColorDialog();
1343 // QColor color = QColorDialog.getColor();
1344 QColor color = fontColorMenu.getColor();
1345 if (color.isValid())
1346 browser.page().mainFrame().evaluateJavaScript(
1347 "document.execCommand('foreColor',false,'" + color.name()
1352 // Listener for when a background color change is requested
1353 @SuppressWarnings("unused")
1354 private void fontHilightClicked() {
1355 // QColorDialog dialog = new QColorDialog();
1356 // QColor color = QColorDialog.getColor();
1357 QColor color = fontHilightColorMenu.getColor();
1358 if (color.isValid())
1359 browser.page().mainFrame().evaluateJavaScript(
1360 "document.execCommand('backColor',false,'" + color.name()
1365 // Listener for when a background color change is requested
1366 @SuppressWarnings("unused")
1367 private void superscriptClicked() {
1368 browser.page().mainFrame().evaluateJavaScript(
1369 "document.execCommand('superscript');");
1373 // Listener for when a background color change is requested
1374 @SuppressWarnings("unused")
1375 private void subscriptClicked() {
1376 browser.page().mainFrame().evaluateJavaScript(
1377 "document.execCommand('subscript');");
1380 // Insert a to-do checkbox
1381 @SuppressWarnings("unused")
1382 private void todoClicked() {
1383 FileNameMap fileNameMap = URLConnection.getFileNameMap();
1384 String script_start = new String(
1385 "document.execCommand('insertHtml', false, '");
1386 String script_end = new String("');");
1387 String todo = new String(
1388 "<input TYPE=\"CHECKBOX\" value=\"false\" " +
1389 "onMouseOver=\"style.cursor=\\'hand\\'\" " +
1390 "onClick=\"value=checked; window.jambi.contentChanged(); \" />");
1391 browser.page().mainFrame().evaluateJavaScript(
1392 script_start + todo + script_end);
1396 // Encrypt the selected text
1397 @SuppressWarnings("unused")
1398 private void encryptText() {
1399 String text = browser.selectedText();
1400 if (text.trim().equalsIgnoreCase(""))
1402 text = new String(text.replaceAll("\n", "<br/>"));
1404 EnCryptDialog dialog = new EnCryptDialog();
1406 if (!dialog.okPressed()) {
1410 EnCrypt crypt = new EnCrypt();
1411 String encrypted = crypt.encrypt(text, dialog.getPassword().trim(), 64);
1412 String decrypted = crypt.decrypt(encrypted, dialog.getPassword().trim(), 64);
1414 if (encrypted.trim().equals("")) {
1415 QMessageBox.information(this, tr("Error"), tr("Error Encrypting String"));
1418 StringBuffer buffer = new StringBuffer(encrypted.length() + 100);
1419 buffer.append("<img en-tag=\"en-crypt\" cipher=\"RC2\" hint=\""
1420 + dialog.getHint().replace("'","\\'") + "\" length=\"64\" ");
1421 buffer.append("contentEditable=\"false\" alt=\"");
1422 buffer.append(encrypted);
1423 buffer.append("\" src=\"").append(FileUtils.toForwardSlashedPath(Global.getFileManager().getImageDirPath("encrypt.png") +"\""));
1424 Global.cryptCounter++;
1425 buffer.append(" id=\"crypt"+Global.cryptCounter.toString() +"\"");
1426 buffer.append(" onMouseOver=\"style.cursor=\\'hand\\'\"");
1427 buffer.append(" onClick=\"window.jambi.decryptText(\\'crypt"+Global.cryptCounter.toString()
1428 +"\\', \\'"+encrypted+"\\', \\'"+dialog.getHint().replace("'", "\\&apos;")+"\\');\"");
1429 buffer.append("style=\"display:block\" />");
1431 String script_start = new String(
1432 "document.execCommand('insertHtml', false, '");
1433 String script_end = new String("');");
1434 browser.page().mainFrame().evaluateJavaScript(
1435 script_start + buffer.toString() + script_end);
1439 // Insert a Quick hyperlink
1440 public void insertQuickLink() {
1441 logger.log(logger.EXTREME, "Inserting link");
1442 String text = browser.selectedText();
1443 if (text.trim().equalsIgnoreCase(""))
1446 NoteQuickLinkDialog dialog = new NoteQuickLinkDialog(logger, conn, text, cbObserver);
1448 if (dialog.getResults().size() == 0) {
1449 QMessageBox.critical(null, tr("No Matches Found") ,tr("No matching notes found."));
1452 if (dialog.getResults().size() > 1) {
1454 if (!dialog.okPressed) {
1455 logger.log(logger.EXTREME, "Insert link canceled");
1460 User user = Global.getUserInformation();
1461 String dUrl = new String("evernote:///view/") + new String(user.getId() + "/" +user.getShardId() +"/"
1462 +dialog.getSelectedNote()+"/"+dialog.getSelectedNote() +"/ " +"style=\"color:#69aa35\"");
1464 String url = "<a title=\"" +dUrl
1467 String script = "document.execCommand('insertHtml', false, '"+url+"');";
1468 browser.page().mainFrame().evaluateJavaScript(script);
1472 // Insert a hyperlink
1473 public void insertLink() {
1474 logger.log(logger.EXTREME, "Inserting link");
1475 String text = browser.selectedText();
1476 if (text.trim().equalsIgnoreCase(""))
1479 InsertLinkDialog dialog = new InsertLinkDialog(insertHyperlink);
1480 if (currentHyperlink != null && currentHyperlink != "") {
1481 dialog.setUrl(currentHyperlink);
1484 if (!dialog.okPressed()) {
1485 logger.log(logger.EXTREME, "Insert link canceled");
1489 // Take care of inserting new links
1490 if (insertHyperlink) {
1491 String selectedText = browser.selectedText();
1492 if (dialog.getUrl().trim().equals(""))
1494 logger.log(logger.EXTREME, "Inserting link on text "+selectedText);
1495 logger.log(logger.EXTREME, "URL Link " +dialog.getUrl().trim());
1496 String dUrl = StringUtils.replace(dialog.getUrl().trim(), "'", "\\'");
1497 String url = "<a href=\"" +dUrl
1499 +" >"+selectedText +"</a>";
1500 String script = "document.execCommand('insertHtml', false, '"+url+"');";
1501 browser.page().mainFrame().evaluateJavaScript(script);
1505 // Edit existing links
1506 String js = new String( "function getCursorPos() {"
1508 +"if (window.getSelection) {"
1509 +" var selObj = window.getSelection();"
1510 +" var selRange = selObj.getRangeAt(0);"
1511 +" var workingNode = window.getSelection().anchorNode.parentNode;"
1512 +" while(workingNode != null) { "
1513 +" if (workingNode.nodeName.toLowerCase()=='a') workingNode.setAttribute('href','" +dialog.getUrl() +"');"
1514 +" workingNode = workingNode.parentNode;"
1517 +"} getCursorPos();");
1518 browser.page().mainFrame().evaluateJavaScript(js);
1520 if (!dialog.getUrl().trim().equals("")) {
1526 js = new String( "function getCursorPos() {"
1528 +"if (window.getSelection) {"
1529 +" var selObj = window.getSelection();"
1530 +" var selRange = selObj.getRangeAt(0);"
1531 +" var workingNode = window.getSelection().anchorNode.parentNode;"
1532 +" while(workingNode != null) { "
1533 +" if (workingNode.nodeName.toLowerCase()=='a') { "
1534 +" workingNode.removeAttribute('href');"
1535 +" workingNode.removeAttribute('title');"
1536 +" var text = document.createTextNode(workingNode.innerText);"
1537 +" workingNode.parentNode.insertBefore(text, workingNode);"
1538 +" workingNode.parentNode.removeChild(workingNode);"
1540 +" workingNode = workingNode.parentNode;"
1543 +"} getCursorPos();");
1544 browser.page().mainFrame().evaluateJavaScript(js);
1552 // Insert a hyperlink
1553 public void insertLatex() {
1556 public void editLatex(String guid) {
1557 logger.log(logger.EXTREME, "Inserting latex");
1558 String text = browser.selectedText();
1559 if (text.trim().equalsIgnoreCase("\n") || text.trim().equalsIgnoreCase("")) {
1560 InsertLatexImage dialog = new InsertLatexImage();
1562 String formula = conn.getNoteTable().noteResourceTable.getNoteSourceUrl(guid).replace("http://latex.codecogs.com/gif.latex?", "");
1563 dialog.setFormula(formula);
1566 if (!dialog.okPressed()) {
1567 logger.log(logger.EXTREME, "Edit LaTex canceled");
1570 text = dialog.getFormula().trim();
1572 blockApplication.emit(this);
1573 logger.log(logger.EXTREME, "Inserting LaTeX formula:" +text);
1575 text = StringUtils.replace(text, "'", "\\'");
1576 String url = "http://latex.codecogs.com/gif.latex?" +text;
1577 logger.log(logger.EXTREME, "Sending request to codecogs --> " + url);
1578 QNetworkAccessManager manager = new QNetworkAccessManager(this);
1579 manager.finished.connect(this, "insertLatexImageReady(QNetworkReply)");
1580 unblockTime = new GregorianCalendar().getTimeInMillis()+5000;
1581 awaitingHttpResponse = true;
1582 manager.get(new QNetworkRequest(new QUrl(url)));
1585 public void insertLatexImageReady(QNetworkReply reply) {
1586 logger.log(logger.EXTREME, "Response received from CodeCogs");
1587 if (reply.error() != NetworkError.NoError)
1591 if (!awaitingHttpResponse)
1594 awaitingHttpResponse = false;
1595 QUrl replyUrl = reply.url();
1596 QByteArray image = reply.readAll();
1598 logger.log(logger.EXTREME, "New image size: " +image.size());
1600 Resource newRes = null;
1603 if (latexGuid == null) {
1604 logger.log(logger.EXTREME, "Creating temporary gif");
1605 path = Global.getFileManager().getResDirPath("latex-temp.gif");
1606 tfile = new QFile(path);
1607 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
1608 logger.log(logger.EXTREME, "File Open: " +tfile.errorString());
1610 logger.log(logger.EXTREME, "Bytes writtes: "+tfile.size());
1612 logger.log(logger.EXTREME, "Creating resource");
1614 if (currentNote.getResources() != null || currentNote.getResources().size() > 0)
1615 sequence = currentNote.getResources().size();
1616 newRes = createResource(path,sequence ,"image/gif", false);
1617 QImage pix = new QImage();
1618 pix.loadFromData(image);
1619 newRes.setHeight(new Integer(pix.height()).shortValue());
1620 newRes.setWidth(new Integer(pix.width()).shortValue());
1621 logger.log(logger.EXTREME, "Renaming temporary file to " +newRes.getGuid()+".gif");
1622 path = Global.getFileManager().getResDirPath(newRes.getGuid()+".gif");
1625 newRes = conn.getNoteTable().noteResourceTable.getNoteResource(latexGuid, false);
1626 path = Global.getFileManager().getResDirPath(newRes.getGuid()+".gif");
1627 tfile = new QFile(path);
1628 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
1631 newRes.getData().setBody(image.toByteArray());
1632 // Calculate the new hash value
1635 logger.log(logger.EXTREME, "Generating MD5");
1637 md = MessageDigest.getInstance("MD5");
1638 md.update(image.toByteArray());
1639 byte[] hash = md.digest();
1640 newRes.getData().setBodyHash(hash);
1641 } catch (NoSuchAlgorithmException e) {
1642 e.printStackTrace();
1644 QImage pix = new QImage();
1645 pix.loadFromData(image);
1646 newRes.setHeight(new Integer(pix.height()).shortValue());
1647 newRes.setWidth(new Integer(pix.width()).shortValue());
1648 conn.getNoteTable().noteResourceTable.updateNoteResource(newRes, true);
1651 logger.log(logger.EXTREME, "Setting source: " +replyUrl.toString());
1652 newRes.getAttributes().setSourceURL(replyUrl.toString());
1653 conn.getNoteTable().noteResourceTable.updateNoteSourceUrl(newRes.getGuid(), replyUrl.toString(), true);
1655 for(int i=0; i<currentNote.getResourcesSize(); i++) {
1656 if (currentNote.getResources().get(i).getGuid().equals(newRes.getGuid())) {
1657 currentNote.getResources().remove(i);
1658 i=currentNote.getResourcesSize();
1661 currentNote.getResources().add(newRes);
1664 // do the actual insert into the note. We only do this on new formulas.
1665 if (latexGuid == null) {
1666 StringBuffer buffer = new StringBuffer(100);
1667 String formula = replyUrl.toString().toLowerCase().replace("http://latex.codecogs.com/gif.latex?", "");
1668 buffer.append("<a href=\"latex://"+path.replace("\\", "/")+"\" title=\""+formula+"\""
1670 buffer.append(path.replace("\\", "/"));
1671 buffer.append("\" en-tag=\"en-latex\" type=\"image/gif\""
1672 +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""
1673 +" guid=\"" +newRes.getGuid() +"\""
1676 String script_start = new String("document.execCommand('insertHTML', false, '");
1677 String script_end = new String("');");
1678 browser.page().mainFrame().evaluateJavaScript(
1679 script_start + buffer + script_end);
1681 HtmlTagModifier modifier = new HtmlTagModifier(getContent());
1682 modifier.modifyLatexTagHash(newRes);
1683 String newContent = modifier.getHtml();
1684 setContent(new QByteArray(newContent));
1687 logger.log(logger.EXTREME, "New HTML set\n" +browser.page().currentFrame().toHtml());
1688 QWebSettings.setMaximumPagesInCache(0);
1689 QWebSettings.setObjectCacheCapacities(0, 0, 0);
1691 browser.page().mainFrame().setHtml(browser.page().mainFrame().toHtml());
1694 // resourceSignal.contentChanged.emit(path);
1696 unblockApplication.emit();
1704 public void insertTable() {
1705 TableDialog dialog = new TableDialog();
1707 if (!dialog.okPressed()) {
1711 int cols = dialog.getCols();
1712 int rows = dialog.getRows();
1713 int width = dialog.getWidth();
1714 boolean percent = dialog.isPercent();
1716 String newHTML = "<table border=\"1\" width=\"" +new Integer(width).toString();
1718 newHTML = newHTML +"%";
1719 newHTML = newHTML + "\"><tbody>";
1721 for (int i=0; i<rows; i++) {
1722 newHTML = newHTML +"<tr>";
1723 for (int j=0; j<cols; j++) {
1724 newHTML = newHTML +"<td> </td>";
1726 newHTML = newHTML +"</tr>";
1728 newHTML = newHTML+"</tbody></table>";
1730 String script = "document.execCommand('insertHtml', false, '"+newHTML+"');";
1731 browser.page().mainFrame().evaluateJavaScript(script);
1735 // Text content changed
1736 @SuppressWarnings("unused")
1737 private void selectionChanged() {
1738 browser.encryptAction.setEnabled(true);
1739 browser.insertLinkAction.setEnabled(true);
1740 browser.insertQuickLinkAction.setEnabled(true);
1741 String scriptStart = "var selection_text = (window.getSelection()).toString();"
1742 + "var range = (window.getSelection()).getRangeAt(0);"
1743 + "var parent_html = range.commonAncestorContainer.innerHTML;"
1744 + "if (parent_html == undefined) {window.jambi.saveSelectedText(selection_text); return;}"
1745 + "var first_text = range.startContainer.nodeValue.substr(range.startOffset);"
1746 + "var last_text = (range.endContainer.nodeValue).substring(0,range.endOffset);"
1747 + "var start = parent_html.indexOf(first_text);"
1748 + "var end = parent_html.indexOf(last_text,start+1)+last_text.length;"
1749 + "var value = parent_html.substring(start,end);"
1750 + "window.jambi.saveSelectedText(value);" ;
1751 browser.page().mainFrame().evaluateJavaScript(scriptStart);
1755 public void saveSelectedText(String text) {
1756 boolean enabled = true;
1757 if (text.trim().length() == 0)
1759 if (text.indexOf("en-tag=\"en-crypt\"") >= 0)
1761 if (text.indexOf("<img en-tag=\"en-media\"") >= 0)
1763 if (text.indexOf("<a en-tag=\"en-media\"") >= 0)
1765 if (text.indexOf("<input ") >= 0)
1768 browser.encryptAction.setEnabled(enabled);
1769 browser.insertLinkAction.setEnabled(enabled);
1770 browser.insertQuickLinkAction.setEnabled(enabled);
1771 // selectedText = text;
1774 // Decrypt clicked text
1775 public void decryptText(String id, String text, String hint) {
1776 EnCrypt crypt = new EnCrypt();
1777 String plainText = null;
1778 Calendar currentTime = new GregorianCalendar();
1779 Long l = new Long(currentTime.getTimeInMillis());
1780 String slot = new String(Long.toString(l));
1782 // First, try to decrypt with any keys we already have
1783 for (int i=0; i<Global.passwordRemember.size(); i++) {
1784 plainText = crypt.decrypt(text, Global.passwordRemember.get(i).getFirst(), 64);
1785 if (plainText != null) {
1786 slot = new String(Long.toString(l));
1787 Global.passwordSafe.put(slot, Global.passwordRemember.get(i));
1788 removeEncryption(id, plainText, false, slot);
1794 EnDecryptDialog dialog = new EnDecryptDialog();
1795 dialog.setHint(hint);
1796 while (plainText == null || !dialog.okPressed()) {
1798 if (!dialog.okPressed()) {
1801 plainText = crypt.decrypt(text, dialog.getPassword().trim(), 64);
1802 if (plainText == null) {
1803 QMessageBox.warning(this, tr("Incorrect Password"), tr("The password entered is not correct"));
1806 Pair<String,String> passwordPair = new Pair<String,String>();
1807 passwordPair.setFirst(dialog.getPassword());
1808 passwordPair.setSecond(dialog.getHint());
1809 Global.passwordSafe.put(slot, passwordPair);
1810 // removeEncryption(id, plainText.replaceAll("\n", "<br/>"), dialog.permanentlyDecrypt(), slot);
1811 removeEncryption(id, plainText, dialog.permanentlyDecrypt(), slot);
1812 if (dialog.rememberPassword()) {
1813 Pair<String, String> pair = new Pair<String,String>();
1814 pair.setFirst(dialog.getPassword());
1815 pair.setSecond(dialog.getHint());
1816 Global.passwordRemember.add(pair);
1821 // Get the editor tag line
1822 public TagLineEdit getTagLine() {
1826 // Modify a note's tags
1827 @SuppressWarnings("unused")
1828 private void modifyTags() {
1829 TagAssign tagWindow = new TagAssign(allTags, currentTags, !conn.getNotebookTable().isLinked(currentNote.getNotebookGuid()));
1831 if (tagWindow.okClicked()) {
1832 currentTags.clear();
1833 StringBuffer tagDisplay = new StringBuffer();
1835 List<QListWidgetItem> newTags = tagWindow.getTagList()
1837 for (int i = 0; i < newTags.size(); i++) {
1838 currentTags.add(newTags.get(i).text());
1839 tagDisplay.append(newTags.get(i).text());
1840 if (i < newTags.size() - 1) {
1841 tagDisplay.append(Global.tagDelimeter + " ");
1844 tagEdit.setText(tagDisplay.toString());
1845 noteSignal.tagsChanged.emit(currentNote.getGuid(), currentTags);
1849 // Tag line has been modified by typing text
1850 @SuppressWarnings("unused")
1851 private void modifyTagsTyping() {
1852 String completionText = "";
1853 if (tagEdit.currentCompleterSelection != null && !tagEdit.currentCompleterSelection.equals("")) {
1854 completionText = tagEdit.currentCompleterSelection;
1855 tagEdit.currentCompleterSelection = "";
1858 if (tagEdit.text().equalsIgnoreCase(saveTagList))
1861 if (saveTagList == null) {
1865 // We know something has changed...
1866 String oldTagArray[] = saveTagList.split(Global.tagDelimeter);
1867 String newTagArray[];
1868 if (!completionText.equals("")) {
1869 String before = tagEdit.text().substring(0,tagEdit.cursorPosition());
1870 int lastDelimiter = before.lastIndexOf(Global.tagDelimeter);
1871 if (lastDelimiter > 0)
1872 before = before.substring(0,before.lastIndexOf(Global.tagDelimeter));
1875 String after = tagEdit.text().substring(tagEdit.cursorPosition());
1876 newTagArray = (before+Global.tagDelimeter+completionText+Global.tagDelimeter+after).split(Global.tagDelimeter);
1879 newTagArray = tagEdit.text().split(Global.tagDelimeter);
1882 // Remove any traling or leading blanks
1883 for (int i=0; i<newTagArray.length; i++)
1884 newTagArray[i] = newTagArray[i].trim().replaceAll("^\\s+", "");;
1886 // Remove any potential duplicates from the new list
1887 for (int i=0; i<newTagArray.length; i++) {
1888 boolean foundOnce = false;
1889 for (int j=0; j<newTagArray.length; j++) {
1890 if (newTagArray[j].equalsIgnoreCase(newTagArray[i])) {
1894 newTagArray[j] = "";
1899 List<String> newTagList = new ArrayList<String>();
1900 List<String> oldTagList = new ArrayList<String>();
1902 for (int i = 0; i < oldTagArray.length; i++)
1903 if (!oldTagArray[i].trim().equals(""))
1904 oldTagList.add(oldTagArray[i]);
1905 for (int i = 0; i < newTagArray.length; i++)
1906 if (!newTagArray[i].trim().equals(""))
1907 newTagList.add(newTagArray[i]);
1909 if (conn.getNotebookTable().isLinked(currentNote.getNotebookGuid())) {
1910 for (int i=newTagList.size()-1; i>=0; i--) {
1911 boolean found = false;
1912 for (int j=0; j<allTags.size(); j++) {
1913 if (allTags.get(j).getName().equalsIgnoreCase(newTagList.get(i))) {
1919 newTagList.remove(i);
1923 // Let's cleanup the appearance of the tag list
1924 Collections.sort(newTagList);
1925 String newDisplay = "";
1926 for (int i=0; i<newTagList.size(); i++) {
1927 newDisplay = newDisplay+newTagList.get(i);
1928 if (i<newTagList.size()-1)
1929 newDisplay = newDisplay+Global.tagDelimeter +" ";
1931 tagEdit.blockSignals(true);
1932 tagEdit.setText(newDisplay);
1933 tagEdit.blockSignals(false);
1935 // We now have lists of the new & old. Remove duplicates. If all
1936 // are removed from both then nothing has really changed
1937 for (int i = newTagList.size() - 1; i >= 0; i--) {
1938 String nTag = newTagList.get(i);
1939 for (int j = oldTagList.size() - 1; j >= 0; j--) {
1940 String oTag = oldTagList.get(j);
1941 if (oTag.equalsIgnoreCase(nTag)) {
1942 oldTagList.remove(j);
1943 newTagList.remove(i);
1949 if (oldTagList.size() != 0 || newTagList.size() != 0) {
1950 currentTags.clear();
1951 newTagArray = tagEdit.text().split(Global.tagDelimeter);
1952 for (int i = 0; i < newTagArray.length; i++)
1953 if (!newTagArray[i].trim().equals(""))
1954 currentTags.add(newTagArray[i].trim());
1956 noteSignal.tagsChanged.emit(currentNote.getGuid(), currentTags);
1961 // Tab button was pressed
1962 public void tabPressed() {
1963 if (insideEncryption)
1965 if (!insideList && !insideTable) {
1966 String script_start = new String(
1967 "document.execCommand('insertHtml', false, ' ');");
1968 browser.page().mainFrame().evaluateJavaScript(script_start);
1975 String js = new String( "function getCursorPosition() { "
1976 +" var selObj = window.getSelection();"
1977 +" var selRange = selObj.getRangeAt(0);"
1978 +" var workingNode = window.getSelection().anchorNode;"
1979 +" var rowCount = 0;"
1980 +" var colCount = 0;"
1981 +" while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { "
1982 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
1983 +" rowCount = rowCount+1;"
1985 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
1986 +" colCount = colCount+1;"
1988 +" if (workingNode.previousSibling != null)"
1989 +" workingNode = workingNode.previousSibling;"
1991 +" workingNode = workingNode.parentNode;"
1993 +" var nodes = workingNode.getElementsByTagName('tr');"
1994 +" var tableRows = nodes.length;"
1995 +" nodes = nodes[0].getElementsByTagName('td');"
1996 +" var tableColumns = nodes.length;"
1997 +" window.jambi.setTableCursorPositionTab(rowCount, colCount, tableRows, tableColumns);"
1998 +"} getCursorPosition();");
1999 browser.page().mainFrame().evaluateJavaScript(js);
2003 // If a user presses tab from within a table
2004 public void setTableCursorPositionTab(int currentRow, int currentCol, int tableRows, int tableColumns) {
2005 if (tableRows == currentRow && currentCol == tableColumns) {
2008 KeyboardModifiers modifiers = new KeyboardModifiers(KeyboardModifier.NoModifier);
2009 QKeyEvent right = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Right.value(), modifiers);
2010 QKeyEvent end = new QKeyEvent(Type.KeyPress, Qt.Key.Key_End.value(), modifiers);
2011 QKeyEvent end2 = new QKeyEvent(Type.KeyPress, Qt.Key.Key_End.value(), modifiers);
2012 getBrowser().focusWidget();
2013 QCoreApplication.postEvent(getBrowser(), end);
2014 QCoreApplication.postEvent(getBrowser(), right);
2015 QCoreApplication.postEvent(getBrowser(), end2);
2018 public void backtabPressed() {
2019 if (insideEncryption)
2024 String js = new String( "function getCursorPosition() { "
2025 +" var selObj = window.getSelection();"
2026 +" var selRange = selObj.getRangeAt(0);"
2027 +" var workingNode = window.getSelection().anchorNode;"
2028 +" var rowCount = 0;"
2029 +" var colCount = 0;"
2030 +" while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { "
2031 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
2032 +" rowCount = rowCount+1;"
2034 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
2035 +" colCount = colCount+1;"
2037 +" if (workingNode.previousSibling != null)"
2038 +" workingNode = workingNode.previousSibling;"
2040 +" workingNode = workingNode.parentNode;"
2042 +" var nodes = workingNode.getElementsByTagName('tr');"
2043 +" var tableRows = nodes.length;"
2044 +" nodes = nodes[0].getElementsByTagName('td');"
2045 +" var tableColumns = nodes.length;"
2046 +" window.jambi.setTableCursorPositionBackTab(rowCount, colCount, tableRows, tableColumns);"
2047 +"} getCursorPosition();");
2048 browser.page().mainFrame().evaluateJavaScript(js);
2053 // If a user presses backtab from within a table
2054 public void setTableCursorPositionBackTab(int currentRow, int currentCol, int tableRows, int tableColumns) {
2055 if (currentRow == 1 && currentCol == 1) {
2058 KeyboardModifiers modifiers = new KeyboardModifiers(KeyboardModifier.NoModifier);
2059 QKeyEvent left = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Left.value(), modifiers);
2060 QKeyEvent home = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Home.value(), modifiers);
2061 getBrowser().focusWidget();
2062 QCoreApplication.postEvent(getBrowser(), home);
2063 QCoreApplication.postEvent(getBrowser(), left);
2067 public void setInsideList() {
2071 // The title has been edited
2072 @SuppressWarnings("unused")
2073 private void titleEdited() {
2074 // If we don't have a good note, or if the current title
2075 // matches the old title then we don't need to do anything
2076 if (currentNote == null)
2078 if (currentNote.getTitle().trim().equals(titleLabel.text().trim()))
2081 // If we have a real change, we need to save it.
2082 String text = titleLabel.text().trim();
2083 if (text.equals(""))
2084 text = tr("Untitled Note");
2085 noteSignal.titleChanged.emit(currentNote.getGuid(), text);
2086 currentNote.setTitle(text);
2087 saveNoteTitle = text;
2091 // Set the list of note tags
2092 public void setAllTags(List<Tag> l) {
2094 tagEdit.setTagList(l);
2097 // Setter for the current tags
2098 public void setCurrentTags(List<String> s) {
2102 // Save the list of notebooks
2103 public void setNotebookList(List<Notebook> n) {
2108 // Load the notebook list and select the current notebook
2109 private void loadNotebookList() {
2110 if (notebookBox.count() != 0)
2111 notebookBox.clear();
2112 if (notebookList == null)
2115 for (int i = 0; i < notebookList.size(); i++) {
2116 notebookBox.addItem(notebookList.get(i).getName());
2117 if (currentNote != null) {
2118 if (currentNote.getNotebookGuid().equals(
2119 notebookList.get(i).getGuid())) {
2120 notebookBox.setCurrentIndex(i);
2127 // Set the notebook for a note
2128 public void setNotebook(String notebook) {
2129 currentNote.setNotebookGuid(notebook);
2133 // Get the contents of the editor
2134 public String getContent() {
2135 return browser.page().currentFrame().toHtml();
2138 // The note contents have changed
2139 public void contentChanged() {
2140 String content = getContent();
2142 // This puts in a 1/2 second delay
2143 // before updating the source editor.
2144 // It improves response when someone is doing
2145 // frequent updates on a large note.
2146 // If the source editor isn't visible, then there
2147 // is no point to doing any of this.
2148 if (sourceEdit.isVisible()) {
2149 setSourceTimer.stop();
2150 setSourceTimer.setInterval(500);
2151 setSourceTimer.setSingleShot(true);
2152 setSourceTimer.start();
2156 noteSignal.noteChanged.emit(currentNote.getGuid(), content);
2159 // The notebook selection has changed
2160 @SuppressWarnings("unused")
2161 private void notebookChanged() {
2162 boolean changed = false;
2163 String n = notebookBox.currentText();
2164 for (int i = 0; i < notebookList.size(); i++) {
2165 if (n.equals(notebookList.get(i).getName())) {
2166 if (!notebookList.get(i).getGuid().equals(currentNote.getNotebookGuid())) {
2167 String guid = conn.getNotebookTable().findNotebookByName(n);
2168 if (conn.getNotebookTable().isLinked(guid)) {
2169 tagEdit.setText("");
2170 noteSignal.tagsChanged.emit(currentNote.getGuid(), new ArrayList<String>());
2171 FilterEditorTags t = new FilterEditorTags(conn, logger);
2172 setAllTags(t.getValidTags(currentNote));
2174 currentNote.setNotebookGuid(notebookList.get(i).getGuid());
2177 i = notebookList.size();
2181 // If the notebook changed, signal the update
2183 noteSignal.notebookChanged.emit(currentNote.getGuid(), currentNote
2184 .getNotebookGuid());
2187 // Check the note title
2188 private void checkNoteTitle() {
2189 String text = browser.page().currentFrame().toPlainText();
2190 if (saveNoteTitle == null)
2191 saveNoteTitle = new String();
2193 if (!saveNoteTitle.trim().equals("") && !saveNoteTitle.trim().equals("Untitled Note"))
2194 text = saveNoteTitle.trim();
2195 int newLine = text.indexOf("\n");
2197 text = text.substring(0,newLine);
2198 if (saveNoteTitle.trim().equals("") || saveNoteTitle.trim().equals("Untitled Note")) {
2199 if (text.trim().equals(""))
2200 text = tr("Untitled Note");
2201 titleLabel.setText(text);
2203 if (text.length() > Constants.EDAM_NOTE_TITLE_LEN_MAX)
2204 titleLabel.setText(text.substring(0, Constants.EDAM_NOTE_TITLE_LEN_MAX));
2206 titleLabel.blockSignals(true);
2207 if (text.trim().equals(""))
2208 titleLabel.setText(tr("Untitled Note"));
2210 titleLabel.setText(text);
2211 titleLabel.blockSignals(false);
2214 if (currentNote != null && titleLabel != null && !currentNote.getTitle().equals(text))
2215 noteSignal.titleChanged.emit(currentNote.getGuid(), text);
2218 // Return the note contents so we can email them
2219 public String getContentsToEmail() {
2220 return browser.page().currentFrame().toPlainText().trim();
2222 * int body = browser.page().currentFrame().toHtml().indexOf("<body>");
2223 * String temp = browser.page().currentFrame().toHtml(); if (body == -1)
2224 * temp = "<html><body><b>Test</b></body></html>"; else temp =
2225 * "<html>"+temp.substring(body); return temp; // return
2226 * urlEncode(browser.page().currentFrame().toHtml());
2230 // Insert an image into the editor
2231 private void insertImage(QMimeData mime) {
2232 logger.log(logger.EXTREME, "Entering insertImage");
2233 QImage img = (QImage) mime.imageData();
2234 String script_start = new String(
2235 "document.execCommand('insertHTML', false, '");
2236 String script_end = new String("');");
2238 long now = new Date().getTime();
2239 String path = Global.getFileManager().getResDirPath(
2240 (new Long(now).toString()) + ".jpg");
2242 // This block is just a hack to make sure we wait at least 1ms so we
2244 // have collisions on image names
2245 long i = new Date().getTime();
2247 i = new Date().getTime();
2249 // Open the file & write the data
2250 QFile tfile = new QFile(path);
2251 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
2252 if (!img.save(tfile)) {
2258 Resource newRes = createResource(QUrl.fromLocalFile(path).toString(), 0, "image/jpeg", false);
2261 currentNote.getResources().add(newRes);
2263 // do the actual insert into the note
2264 StringBuffer buffer = new StringBuffer(100);
2265 buffer.append("<img src=\"");
2266 buffer.append(tfile.fileName());
2267 buffer.append("\" en-tag=en-media type=\"image/jpeg\""
2268 +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""
2269 +" guid=\"" +newRes.getGuid() +"\""
2270 +" onContextMenu=\"window.jambi.imageContextMenu(&." +tfile.fileName() +"&.);\""
2273 browser.page().mainFrame().evaluateJavaScript(
2274 script_start + buffer + script_end);
2279 // Handle pasting of a note-to-note link
2280 private void handleNoteLink(QMimeData mime) {
2281 for (int i=0; i<mime.urls().size(); i++) {
2282 StringTokenizer tokens = new StringTokenizer(mime.urls().get(i).toString().replace("evernote:///view/", ""), "/");
2285 String sid = tokens.nextToken();
2286 String lid = tokens.nextToken();
2288 if (!sid.equals(currentNote.getGuid()) && !lid.equals(currentNote.getGuid())) {
2290 Note note = conn.getNoteTable().getNote(sid, false, false, false, false, false);
2292 note = conn.getNoteTable().getNote(lid, false, false, false, false, false);
2297 // If we've gotten this far, we have a bunch of values. We need to build the link.
2298 StringBuffer url = new StringBuffer(100);
2299 String script_start = new String(
2300 "document.execCommand('insertHtml', false, '");
2301 String script_end = new String("');");
2303 url.append("<a href=\""+mime.urls().get(i).toString() +"\" style=\"color:#69aa35\">");
2304 url.append(note.getTitle());
2306 if (mime.urls().size() > 1)
2307 url.append(" ");
2308 browser.page().mainFrame().evaluateJavaScript(
2309 script_start + url + script_end);
2314 // Handle URLs that are trying to be pasted
2315 public void handleUrls(QMimeData mime) {
2316 logger.log(logger.EXTREME, "Starting handleUrls");
2317 FileNameMap fileNameMap = URLConnection.getFileNameMap();
2319 List<QUrl> urlList = mime.urls();
2320 String url = new String();
2321 String script_start = new String(
2322 "document.execCommand('createLink', false, '");
2323 String script_end = new String("');");
2325 for (int i = 0; i < urlList.size(); i++) {
2326 url = urlList.get(i).toString();
2327 // Find out what type of file we have
2328 String mimeType = fileNameMap.getContentTypeFor(url);
2330 // If null returned, we need to guess at the file type
2331 if (mimeType == null)
2332 mimeType = "application/"
2333 + url.substring(url.lastIndexOf(".") + 1);
2335 // Check if we have an image or some other type of file
2336 if (url.substring(0, 5).equalsIgnoreCase("file:")
2337 && mimeType.substring(0, 5).equalsIgnoreCase("image")) {
2338 handleLocalImageURLPaste(mime, mimeType);
2342 boolean smallEnough = checkFileAttachmentSize(url);
2344 && url.substring(0, 5).equalsIgnoreCase("file:")
2345 && !mimeType.substring(0, 5).equalsIgnoreCase("image")) {
2346 handleLocalAttachment(mime, mimeType);
2349 browser.page().mainFrame().evaluateJavaScript(
2350 script_start + url + script_end);
2355 // If a URL being pasted is an image URL, then attach the image
2356 private void handleLocalImageURLPaste(QMimeData mime, String mimeType) {
2357 List<QUrl> urlList = mime.urls();
2358 String url = new String();
2359 String script_start_image = new String(
2360 "document.execCommand('insertHtml', false, '");
2361 String script_end = new String("');");
2362 StringBuffer buffer;
2364 // Copy the image over into the resource directory and create a new resource
2365 // record for each url pasted
2366 for (int i = 0; i < urlList.size(); i++) {
2367 url = urlList.get(i).toString();
2369 Resource newRes = createResource(url, i, mimeType, false);
2372 currentNote.getResources().add(newRes);
2373 buffer = new StringBuffer(100);
2375 // Open the file & write the data
2376 String fileName = Global.getFileManager().getResDirPath(newRes.getGuid());
2377 QFile tfile = new QFile(fileName);
2378 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
2379 tfile.write(newRes.getData().getBody());
2381 buffer.append(script_start_image);
2382 buffer.append("<img src=\"" + FileUtils.toForwardSlashedPath(fileName));
2383 // if (mimeType.equalsIgnoreCase("image/jpg"))
2384 // mimeType = "image/jpeg";
2385 buffer.append("\" en-tag=\"en-media\" type=\"" + mimeType +"\""
2386 +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""
2387 +" guid=\"" +newRes.getGuid() +"\""
2388 +" onContextMenu=\"window.jambi.imageContextMenu('" +tfile.fileName() +"');\""
2390 buffer.append(script_end);
2391 browser.page().mainFrame().evaluateJavaScript(buffer.toString());
2397 // If a URL being pasted is a local file URL, then attach the file
2398 private void handleLocalAttachment(QMimeData mime, String mimeType) {
2399 logger.log(logger.EXTREME, "Attaching local file");
2400 List<QUrl> urlList = mime.urls();
2401 String script_start = new String(
2402 "document.execCommand('insertHtml', false, '");
2403 String script_end = new String("');");
2404 StringBuffer buffer;
2406 String[] type = mimeType.split("/");
2407 String icon = findIcon(type[1]);
2408 if (icon.equals("attachment.png"))
2409 icon = findIcon(type[0]);
2410 buffer = new StringBuffer(100);
2412 for (int i = 0; i < urlList.size(); i++) {
2413 String url = urlList.get(i).toString();
2415 // Start building the HTML
2416 if (icon.equals("attachment.png"))
2417 icon = findIcon(url.substring(url.lastIndexOf(".")+1));
2418 String imageURL = FileUtils.toFileURLString(Global.getFileManager().getImageDirFile(icon));
2420 logger.log(logger.EXTREME, "Creating resource ");
2421 Resource newRes = createResource(url, i, mimeType, true);
2424 logger.log(logger.EXTREME, "New resource size: " +newRes.getData().getSize());
2425 currentNote.getResources().add(newRes);
2427 String fileName = newRes.getGuid() + Global.attachmentNameDelimeter+newRes.getAttributes().getFileName();
2428 // If we have a PDF, we need to setup the preview.
2429 if (icon.equalsIgnoreCase("pdf.png") && Global.pdfPreview()) {
2430 logger.log(logger.EXTREME, "Setting up PDF preview");
2431 if (newRes.getAttributes() != null &&
2432 newRes.getAttributes().getFileName() != null &&
2433 !newRes.getAttributes().getFileName().trim().equals(""))
2434 fileName = newRes.getGuid()+Global.attachmentNameDelimeter+
2435 newRes.getAttributes().getFileName();
2437 fileName = newRes.getGuid()+".pdf";
2438 QFile file = new QFile(Global.getFileManager().getResDirPath(fileName));
2439 QFile.OpenMode mode = new QFile.OpenMode();
2440 mode.set(QFile.OpenModeFlag.WriteOnly);
2442 QDataStream out = new QDataStream(file);
2443 // Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(newRes.getGuid(), true);
2444 QByteArray binData = new QByteArray(newRes.getData().getBody());
2445 // resBinary = null;
2446 out.writeBytes(binData.toByteArray());
2449 PDFPreview pdfPreview = new PDFPreview();
2450 if (pdfPreview.setupPreview(Global.getFileManager().getResDirPath(fileName), "pdf",0)) {
2451 imageURL = file.fileName() + ".png";
2455 logger.log(logger.EXTREME, "Generating link tags");
2456 buffer.delete(0, buffer.length());
2457 buffer.append("<a en-tag=\"en-media\" guid=\"" +newRes.getGuid()+"\" ");
2458 buffer.append(" onContextMenu=\"window.jambi.imageContextMenu('")
2459 .append(Global.getFileManager().getResDirPath(fileName))
2460 .append("');\" ");
2461 buffer.append("type=\"" + mimeType + "\" href=\"nnres://" + fileName +"\" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\" >");
2462 buffer.append("<img src=\"" + imageURL + "\" title=\"" +newRes.getAttributes().getFileName());
2463 buffer.append("\"></img>");
2464 buffer.append("</a>");
2465 browser.page().mainFrame().evaluateJavaScript(
2466 script_start + buffer.toString() + script_end);
2471 private Resource createResource(String url, int sequence, String mime, boolean attachment) {
2472 logger.log(logger.EXTREME, "Inside create resource");
2474 //These two lines are added to handle odd characters in the name like #. Without it
2475 // toLocalFile() chokes and returns the wrong name.
2476 logger.log(logger.EXTREME, "File URL:" +url);
2477 String whichOS = System.getProperty("os.name");
2478 if (whichOS.contains("Windows"))
2479 url = url.replace("file:///", "");
2481 url = url.replace("file://", "");
2482 String urlTest = new QUrl(url).toLocalFile();
2483 logger.log(logger.EXTREME, "File URL toLocalFile():" +urlTest);
2485 if (!urlTest.equals(""))
2487 // url = url.replace("/", File.separator);
2488 logger.log(logger.EXTREME, "Reading from file to create resource:" +url);
2489 resourceFile = new QFile(url);
2490 resourceFile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly));
2491 logger.log(logger.EXTREME, "Error opening file "+url.toString() +": "+resourceFile.errorString());
2492 byte[] fileData = resourceFile.readAll().toByteArray();
2493 resourceFile.close();
2494 logger.log(logger.EXTREME, "File Length: " +fileData.length);
2495 if (fileData.length == 0)
2499 logger.log(logger.EXTREME, "Generating MD5");
2500 md = MessageDigest.getInstance("MD5");
2501 md.update(fileData);
2502 byte[] hash = md.digest();
2504 Resource r = new Resource();
2505 Calendar time = new GregorianCalendar();
2506 long prevTime = time.getTimeInMillis();
2507 while (prevTime == time.getTimeInMillis()) {
2508 time = new GregorianCalendar();
2510 r.setGuid(time.getTimeInMillis()+new Integer(sequence).toString());
2511 r.setNoteGuid(currentNote.getGuid());
2514 r.setUpdateSequenceNum(0);
2515 r.setWidth((short) 0);
2516 r.setHeight((short) 0);
2517 r.setDuration((short) 0);
2519 Data d = new Data();
2520 d.setBody(fileData);
2521 d.setBodyIsSet(true);
2522 d.setBodyHash(hash);
2523 d.setBodyHashIsSet(true);
2525 d.setSize(fileData.length);
2527 int fileNamePos = url.lastIndexOf(File.separator);
2528 if (fileNamePos == -1)
2529 fileNamePos = url.lastIndexOf("/");
2530 String fileName = url.substring(fileNamePos+1);
2531 ResourceAttributes a = new ResourceAttributes();
2533 a.setAltitudeIsSet(false);
2535 a.setLongitudeIsSet(false);
2537 a.setLatitudeIsSet(false);
2538 a.setCameraMake("");
2539 a.setCameraMakeIsSet(false);
2540 a.setCameraModel("");
2541 a.setCameraModelIsSet(false);
2542 a.setAttachment(attachment);
2543 a.setAttachmentIsSet(true);
2544 a.setClientWillIndex(false);
2545 a.setClientWillIndexIsSet(true);
2547 a.setRecoTypeIsSet(false);
2548 a.setSourceURL(url);
2549 a.setSourceURLIsSet(true);
2551 a.setTimestampIsSet(false);
2552 a.setFileName(fileName);
2553 a.setFileNameIsSet(true);
2556 conn.getNoteTable().noteResourceTable.saveNoteResource(r, true);
2557 logger.log(logger.EXTREME, "Resource created");
2559 } catch (NoSuchAlgorithmException e1) {
2560 e1.printStackTrace();
2566 // find the appropriate icon for an attachment
2567 private String findIcon(String appl) {
2568 appl = appl.toLowerCase();
2569 File f = Global.getFileManager().getImageDirFile(appl + ".png");
2572 return "attachment.png";
2577 // Check the file attachment to be sure it isn't over 25 mb
2578 private boolean checkFileAttachmentSize(String url) {
2579 String fileName = url.substring(8);
2580 QFile resourceFile = new QFile(fileName);
2581 resourceFile.open(new QIODevice.OpenMode(
2582 QIODevice.OpenModeFlag.ReadOnly));
2583 long size = resourceFile.size();
2584 resourceFile.close();
2585 size = size / 1024 / 1024;
2586 if (size < 50 && Global.isPremium())
2591 String error = tr("A file attachment may not exceed 25MB.");
2592 QMessageBox.information(this, tr("Attachment Size"), error);
2597 @SuppressWarnings("unused")
2598 private void createdChanged() {
2599 QDateTime dt = new QDateTime();
2600 dt.setDate(createdDate.date());
2601 dt.setTime(createdTime.time());
2602 noteSignal.createdDateChanged.emit(currentNote.getGuid(), dt);
2606 @SuppressWarnings("unused")
2607 private void alteredChanged() {
2608 QDateTime dt = new QDateTime();
2609 dt.setDate(alteredDate.date());
2610 dt.setTime(alteredTime.time());
2611 noteSignal.alteredDateChanged.emit(currentNote.getGuid(), dt);
2614 @SuppressWarnings("unused")
2615 private void subjectDateTimeChanged() {
2616 QDateTime dt = new QDateTime();
2617 dt.setDate(subjectDate.date());
2618 dt.setTime(subjectTime.time());
2619 noteSignal.subjectDateChanged.emit(currentNote.getGuid(), dt);
2623 @SuppressWarnings("unused")
2624 private void sourceUrlChanged() {
2625 noteSignal.sourceUrlChanged.emit(currentNote.getGuid(), urlText.text());
2628 @SuppressWarnings("unused")
2629 private void authorChanged() {
2630 noteSignal.authorChanged.emit(currentNote.getGuid(), authorText.text());
2633 @SuppressWarnings("unused")
2634 private void geoBoxChanged() {
2635 int index = geoBox.currentIndex();
2636 geoBox.setCurrentIndex(0);
2638 GeoDialog box = new GeoDialog();
2639 box.setLongitude(currentNote.getAttributes().getLongitude());
2640 box.setLatitude(currentNote.getAttributes().getLatitude());
2641 box.setAltitude(currentNote.getAttributes().getAltitude());
2643 if (!box.okPressed())
2645 double alt = box.getAltitude();
2646 double lat = box.getLatitude();
2647 double lon = box.getLongitude();
2648 if (alt != currentNote.getAttributes().getAltitude() ||
2649 lon != currentNote.getAttributes().getLongitude() ||
2650 lat != currentNote.getAttributes().getLatitude()) {
2651 noteSignal.geoChanged.emit(currentNote.getGuid(), lon, lat, alt);
2652 currentNote.getAttributes().setAltitude(alt);
2653 currentNote.getAttributes().setLongitude(lon);
2654 currentNote.getAttributes().setLatitude(lat);
2659 noteSignal.geoChanged.emit(currentNote.getGuid(), 0.0, 0.0, 0.0);
2660 currentNote.getAttributes().setAltitude(0.0);
2661 currentNote.getAttributes().setLongitude(0.0);
2662 currentNote.getAttributes().setLatitude(0.0);
2665 if (index == 3 || index == 0) {
2666 QDesktopServices.openUrl(new QUrl("http://maps.google.com/maps?z=6&q="+currentNote.getAttributes().getLatitude() +"," +currentNote.getAttributes().getLongitude()));
2670 // ************************************************************
2671 // * User chose to save an attachment. Pares out the request *
2672 // * into a guid & file. Save the result. *
2673 // ************************************************************
2674 public void downloadAttachment(QNetworkRequest request) {
2676 QFileDialog fd = new QFileDialog(this);
2677 fd.setFileMode(FileMode.AnyFile);
2678 fd.setConfirmOverwrite(true);
2679 fd.setWindowTitle(tr("Save File"));
2680 fd.setAcceptMode(AcceptMode.AcceptSave);
2681 fd.setDirectory(System.getProperty("user.home"));
2682 String name = request.url().toString();
2684 int pos = name.lastIndexOf(Global.attachmentNameDelimeter);
2686 guid = name.substring(0, pos).replace("nnres://", "");
2687 name = name.substring(pos +Global.attachmentNameDelimeter.length());
2688 fd.selectFile(name);
2689 pos = name.lastIndexOf('.');
2691 String mimeType = "(*." + name.substring(pos + 1)
2692 + ");; All Files (*)";
2693 fd.setFilter(tr(mimeType));
2699 // Strip URL prefix and base dir
2700 guid = guid.replace("nnres://", "")
2701 .replace(FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath()), "");
2702 guid = guid.replace("file://", "").replace("/", "")
2703 .replace(FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath()), "");
2705 pos = guid.lastIndexOf('.');
2707 guid = guid.substring(0,pos);
2708 if (fd.exec() != 0 && fd.selectedFiles().size() > 0) {
2709 name = name.replace('\\', '/');
2710 Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
2711 QFile saveFile = new QFile(fd.selectedFiles().get(0));
2712 QFile.OpenMode mode = new QFile.OpenMode();
2713 mode.set(QFile.OpenModeFlag.WriteOnly);
2714 saveFile.open(mode);
2715 QDataStream saveOut = new QDataStream(saveFile);
2716 QByteArray binData = new QByteArray(resBinary.getData().getBody());
2717 saveOut.writeBytes(binData.toByteArray());
2724 // ************************************************************
2725 // * User chose to save an attachment. Pares out the request *
2726 // * into a guid & file. Save the result. --- DONE FROM downloadAttachment now!!!!!
2727 // ************************************************************
2728 public void downloadImage(QNetworkRequest request) {
2729 QFileDialog fd = new QFileDialog(this);
2730 fd.setFileMode(FileMode.AnyFile);
2731 fd.setConfirmOverwrite(true);
2732 fd.setWindowTitle(tr("Save File"));
2733 fd.setAcceptMode(AcceptMode.AcceptSave);
2734 fd.setDirectory(System.getProperty("user.home"));
2735 String name = request.url().toString();
2736 name = name.replace("nnres://", "");
2737 String dPath = FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath());
2738 name = name.replace(dPath, "");
2739 int pos = name.lastIndexOf('.');
2742 String mimeType = "(*." + name.substring(pos + 1)
2743 + ");; All Files (*)";
2744 fd.setFilter(tr(mimeType));
2745 guid = guid.substring(0,pos);
2747 pos = name.lastIndexOf(Global.attachmentNameDelimeter);
2749 guid = name.substring(0, pos);
2750 fd.selectFile(name.substring(pos+Global.attachmentNameDelimeter.length()));
2752 if (fd.exec() != 0 && fd.selectedFiles().size() > 0) {
2753 Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
2754 String fileName = fd.selectedFiles().get(0);
2755 QFile saveFile = new QFile(fileName);
2756 QFile.OpenMode mode = new QFile.OpenMode();
2757 mode.set(QFile.OpenModeFlag.WriteOnly);
2758 saveFile.open(mode);
2759 QDataStream saveOut = new QDataStream(saveFile);
2760 QByteArray binData = new QByteArray(resBinary.getData().getBody());
2761 saveOut.writeBytes(binData.toByteArray());
2767 // *************************************************************
2768 // * decrypt any hidden text. We could do an XML parse, but
2769 // * it is quicker here just to scan for an <img tag & do the fix
2771 // *************************************************************
2772 private void removeEncryption(String id, String plainText, boolean permanent, String slot) {
2774 plainText = " <table class=\"en-crypt-temp\" slot=\""
2777 +"border=1 width=100%><tbody><tr><td>"
2778 +plainText+"</td></tr></tbody></table>";
2781 String html = browser.page().mainFrame().toHtml();
2783 int imagePos = html.indexOf("<img");
2785 for ( ;imagePos>0; ) {
2787 endPos = text.indexOf(">", imagePos);
2788 String tag = text.substring(imagePos-1,endPos);
2789 if (tag.indexOf("id=\""+id+"\"") > -1) {
2790 text = text.substring(0,imagePos) +plainText+text.substring(endPos+1);
2791 QTextCodec codec = QTextCodec.codecForName("UTF-8");
2792 QByteArray unicode = codec.fromUnicode(text);
2793 setContent(unicode);
2797 imagePos = text.indexOf("<img", imagePos+1);
2802 //****************************************************************
2804 //****************************************************************
2805 @SuppressWarnings("unused")
2806 private void focusTitle() {
2807 titleLabel.setFocus();
2809 @SuppressWarnings("unused")
2810 private void focusTag() {
2813 @SuppressWarnings("unused")
2814 private void focusNote() {
2817 @SuppressWarnings("unused")
2818 private void focusAuthor() {
2819 authorLabel.setFocus();
2821 @SuppressWarnings("unused")
2822 private void focusUrl() {
2823 urlLabel.setFocus();
2827 //*****************************************************************
2828 //* Set the document background color
2829 //*****************************************************************
2830 public void setBackgroundColor(String color) {
2831 String js = "function changeBackground(color) {"
2832 +"document.body.style.background = color;"
2834 +"changeBackground('" +color+"');";
2835 browser.page().mainFrame().evaluateJavaScript(js);
2840 //****************************************************************
2841 //* MicroFocus changed
2842 //****************************************************************
2843 private void microFocusChanged() {
2844 boldButton.setDown(false);
2845 italicButton.setDown(false);
2846 underlineButton.setDown(false);
2847 browser.openAction.setEnabled(false);
2848 browser.downloadAttachment.setEnabled(false);
2849 browser.downloadImage.setEnabled(false);
2850 browser.rotateImageLeft.setEnabled(false);
2851 browser.rotateImageRight.setEnabled(false);
2852 browser.insertTableAction.setEnabled(true);
2853 browser.deleteTableColumnAction.setEnabled(false);
2854 browser.insertTableRowAction.setEnabled(false);
2855 browser.insertTableColumnAction.setEnabled(false);
2856 browser.deleteTableRowAction.setEnabled(false);
2857 browser.insertLinkAction.setText(tr("Insert Hyperlink"));
2858 insertHyperlink = true;
2859 browser.insertQuickLinkAction.setEnabled(true);
2860 currentHyperlink ="";
2862 insideTable = false;
2863 insideEncryption = false;
2864 forceTextPaste = false;
2866 String js = new String( "function getCursorPos() {"
2868 +"if (window.getSelection) {"
2869 +" var selObj = window.getSelection();"
2870 +" var selRange = selObj.getRangeAt(0);"
2871 +" var workingNode = window.getSelection().anchorNode.parentNode;"
2872 +" while(workingNode != null) { "
2873 // +" window.jambi.printNode(workingNode.nodeName);"
2874 +" if (workingNode.nodeName=='TABLE') { if (workingNode.getAttribute('class').toLowerCase() == 'en-crypt-temp') window.jambi.insideEncryption(); }"
2875 +" if (workingNode.nodeName=='B') window.jambi.boldActive();"
2876 +" if (workingNode.nodeName=='I') window.jambi.italicActive();"
2877 +" if (workingNode.nodeName=='U') window.jambi.underlineActive();"
2878 +" if (workingNode.nodeName=='UL') window.jambi.setInsideList();"
2879 +" if (workingNode.nodeName=='OL') window.jambi.setInsideList();"
2880 +" if (workingNode.nodeName=='LI') window.jambi.setInsideList();"
2881 +" if (workingNode.nodeName=='TBODY') window.jambi.setInsideTable();"
2882 +" if (workingNode.nodeName=='A') {for(var x = 0; x < workingNode.attributes.length; x++ ) {if (workingNode.attributes[x].nodeName.toLowerCase() == 'href') window.jambi.setInsideLink(workingNode.attributes[x].nodeValue);}}"
2883 +" if (workingNode.nodeName=='SPAN') {"
2884 +" if (workingNode.getAttribute('style') == 'text-decoration: underline;') window.jambi.underlineActive();"
2886 +" workingNode = workingNode.parentNode;"
2889 +"} getCursorPos();");
2890 browser.page().mainFrame().evaluateJavaScript(js);
2893 public void printNode(String n) {
2894 System.out.println("Node Vaule: " +n);
2897 public void insideEncryption() {
2898 insideEncryption = true;
2902 //****************************************************************
2903 //* Insert a table row
2904 //****************************************************************
2905 public void insertTableRow() {
2907 String js = new String( "function insertTableRow() {"
2908 +" var selObj = window.getSelection();"
2909 +" var selRange = selObj.getRangeAt(0);"
2910 +" var workingNode = window.getSelection().anchorNode.parentNode;"
2911 +" var cellCount = 0;"
2912 +" while(workingNode != null) { "
2913 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
2914 +" row = document.createElement('TR');"
2915 +" var nodes = workingNode.getElementsByTagName('td');"
2916 +" for (j=0; j<nodes.length; j=j+1) {"
2917 +" cell = document.createElement('TD');"
2918 +" cell.innerHTML=' ';"
2919 +" row.appendChild(cell);"
2921 +" workingNode.parentNode.insertBefore(row,workingNode.nextSibling);"
2924 +" workingNode = workingNode.parentNode;"
2926 +"} insertTableRow();");
2927 browser.page().mainFrame().evaluateJavaScript(js);
2931 public void insertTableColumn() {
2932 String js = new String( "function insertTableColumn() {"
2933 +" var selObj = window.getSelection();"
2934 +" var selRange = selObj.getRangeAt(0);"
2935 +" var workingNode = window.getSelection().anchorNode.parentNode;"
2936 +" var current = 0;"
2937 +" while (workingNode.nodeName.toLowerCase() != 'table' && workingNode != null) {"
2938 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
2939 +" var td = workingNode;"
2940 +" while (td.previousSibling != null) { "
2941 +" current = current+1; td = td.previousSibling;"
2944 +" workingNode = workingNode.parentNode; "
2946 +" if (workingNode == null) return;"
2947 +" for (var i=0; i<workingNode.rows.length; i++) { "
2948 +" var cell = workingNode.rows[i].insertCell(current+1); "
2949 +" cell.innerHTML = ' '; "
2951 +"} insertTableColumn();");
2952 browser.page().mainFrame().evaluateJavaScript(js);
2956 //****************************************************************
2957 //* Delete a table row
2958 //****************************************************************
2959 public void deleteTableRow() {
2961 String js = new String( "function deleteTableRow() {"
2962 +" var selObj = window.getSelection();"
2963 +" var selRange = selObj.getRangeAt(0);"
2964 +" var workingNode = window.getSelection().anchorNode.parentNode;"
2965 +" var cellCount = 0;"
2966 +" while(workingNode != null) { "
2967 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
2968 +" workingNode.parentNode.removeChild(workingNode);"
2971 +" workingNode = workingNode.parentNode;"
2973 +"} deleteTableRow();");
2974 browser.page().mainFrame().evaluateJavaScript(js);
2978 public void deleteTableColumn() {
2979 String js = new String( "function deleteTableColumn() {"
2980 +" var selObj = window.getSelection();"
2981 +" var selRange = selObj.getRangeAt(0);"
2982 +" var workingNode = window.getSelection().anchorNode.parentNode;"
2983 +" var current = 0;"
2984 +" while (workingNode.nodeName.toLowerCase() != 'table' && workingNode != null) {"
2985 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
2986 +" var td = workingNode;"
2987 +" while (td.previousSibling != null) { "
2988 +" current = current+1; td = td.previousSibling;"
2991 +" workingNode = workingNode.parentNode; "
2993 +" if (workingNode == null) return;"
2994 +" for (var i=0; i<workingNode.rows.length; i++) { "
2995 +" workingNode.rows[i].deleteCell(current); "
2997 +"} deleteTableColumn();");
2998 browser.page().mainFrame().evaluateJavaScript(js);
3003 public void setInsideTable() {
3004 browser.insertTableRowAction.setEnabled(true);
3005 browser.insertTableColumnAction.setEnabled(true);
3006 browser.deleteTableRowAction.setEnabled(true);
3007 browser.deleteTableColumnAction.setEnabled(true);
3008 browser.insertTableAction.setEnabled(false);
3009 browser.encryptAction.setEnabled(false);
3013 public void setInsideLink(String link) {
3014 browser.insertLinkAction.setText(tr("Edit Hyperlink"));
3015 currentHyperlink = link;
3016 insertHyperlink = false;
3019 public void italicActive() {
3020 italicButton.setDown(true);
3022 public void boldActive() {
3023 boldButton.setDown(true);
3025 public void underlineActive() {
3026 underlineButton.setDown(true);
3028 public void forceTextPaste() {
3029 forceTextPaste = true;
3031 public void imageContextMenu(String f) {
3032 browser.downloadImage.setEnabled(true);
3033 browser.rotateImageRight.setEnabled(true);
3034 browser.rotateImageLeft.setEnabled(true);
3035 browser.openAction.setEnabled(true);
3038 public void rotateImageRight() {
3039 QWebSettings.setMaximumPagesInCache(0);
3040 QWebSettings.setObjectCacheCapacities(0, 0, 0);
3041 QImage image = new QImage(selectedFile);
3042 QMatrix matrix = new QMatrix();
3043 matrix.rotate( 90.0 );
3044 image = image.transformed(matrix);
3045 image.save(selectedFile);
3046 QWebSettings.setMaximumPagesInCache(0);
3047 QWebSettings.setObjectCacheCapacities(0, 0, 0);
3048 browser.setHtml(browser.page().mainFrame().toHtml());
3051 resourceSignal.contentChanged.emit(selectedFile);
3054 public void rotateImageLeft() {
3055 QImage image = new QImage(selectedFile);
3056 QMatrix matrix = new QMatrix();
3057 matrix.rotate( -90.0 );
3058 image = image.transformed(matrix);
3059 image.save(selectedFile);
3060 browser.setHtml(browser.page().mainFrame().toHtml());
3063 resourceSignal.contentChanged.emit(selectedFile);
3065 public void resourceContextMenu(String f) {
3066 browser.downloadAttachment.setEnabled(true);
3067 browser.openAction.setEnabled(true);
3070 public void latexContextMenu(String f) {
3071 browser.downloadImage.setEnabled(true);
3072 browser.rotateImageRight.setEnabled(true);
3073 browser.rotateImageLeft.setEnabled(true);
3074 browser.openAction.setEnabled(true);
3078 //****************************************************************
3079 //* Apply CSS style to specified word
3080 //****************************************************************
3081 /* public void applyStyleToWords(String word, String style) {
3082 QFile script = new QFile("D:\\NeverNote\\js\\hilight1.js");
3083 script.open(OpenModeFlag.ReadOnly);
3084 String s = script.readAll().toString();
3085 String js = new String(s +" findit('"+word+"', '"+style+"');");
3086 browser.page().mainFrame().evaluateJavaScript(js);
3087 System.out.println(getContent());
3090 //****************************************************************
3091 //* Someone tried to paste a resource between notes, so we need *
3092 //* to do some special handling. *
3093 //****************************************************************
3094 private String fixInternotePaste(String text) {
3095 logger.log(logger.EXTREME, "Fixing internote paste");
3096 String returnValue = fixInternotePasteSearch(text, "<img", "src=\"");
3097 return fixInternotePasteSearch(returnValue, "<a", "href=\"nnres://");
3099 private String fixInternotePasteSearch(String text, String type, String locTag) {
3101 // First, let's fix the images.
3102 int startPos = text.indexOf(type);
3104 for (; startPos>=0;) {
3105 endPos = text.indexOf(">", startPos+1);
3106 String segment = text.substring(startPos, endPos);
3107 if (segment.indexOf("en-tag") > -1) {
3108 String newSegment = segment;
3110 int guidStartPos = segment.indexOf("guid=\"");
3111 int guidEndPos = segment.indexOf("\"", guidStartPos+7);
3112 String guid = segment.substring(guidStartPos+6,guidEndPos);
3114 int mimeStartPos = segment.indexOf("type");
3115 int mimeEndPos = segment.indexOf("\"", mimeStartPos+7);
3116 String mime = segment.substring(mimeStartPos+6,mimeEndPos);
3118 int srcStartPos = segment.indexOf("src");
3119 int srcEndPos = segment.indexOf("\"", srcStartPos+6);
3120 String src = segment.substring(srcStartPos+5,srcEndPos);
3122 Calendar currentTime = new GregorianCalendar();
3123 Long l = new Long(currentTime.getTimeInMillis());
3125 while (l==prevTime) {
3126 currentTime = new GregorianCalendar();
3127 l= new Long(currentTime.getTimeInMillis());
3130 Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
3131 // if r==null, then the image doesn't exist (it was probably cut out of another note, so
3132 // we need to recereate it
3134 r = createResource(src, 1, mime, false);
3138 String randint = new String(Long.toString(l));
3139 String extension = null;
3140 if (r.getMime()!= null) {
3141 extension = r.getMime().toLowerCase();
3142 if (extension.indexOf("/")>-1)
3143 extension = extension.substring(extension.indexOf("/")+1);
3145 String newFile = randint;
3146 if (r.getAttributes().getFileName() != null && r.getAttributes().getFileName() != "")
3147 if (!locTag.startsWith("src"))
3148 newFile = newFile+Global.attachmentNameDelimeter+r.getAttributes().getFileName();
3149 r.setNoteGuid(currentNote.getGuid());
3152 conn.getNoteTable().noteResourceTable.saveNoteResource(r, true);
3153 QFile f = new QFile(Global.getFileManager().getResDirPath(newFile));
3154 QByteArray bin = new QByteArray(r.getData().getBody());
3155 f.open(QFile.OpenModeFlag.WriteOnly);
3158 newSegment = newSegment.replace("guid=\""+guid, "guid=\""+randint);
3159 currentNote.getResources().add(r);
3161 int startSrcPos = newSegment.indexOf(locTag);
3162 int endSrcPos = newSegment.indexOf("\"",startSrcPos+locTag.length()+1);
3164 if (locTag.startsWith("src")) {
3165 source = newSegment.substring(startSrcPos+locTag.length(),endSrcPos);
3166 newSegment = newSegment.replace(source,
3167 FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath(newFile)));
3169 source = newSegment.substring(startSrcPos+locTag.length(),endSrcPos);
3170 newSegment = newSegment.replace(source, newFile);
3173 text = text.substring(0,startPos) + newSegment + text.substring(endPos);
3175 startPos = text.indexOf(type, startPos+1);
3181 public void nextPage(String file) {
3182 logger.log(logger.EXTREME, "Starting nextPage()");
3185 if (previewPageList.containsKey(file))
3186 pageNumber = previewPageList.get(file)+1;
3189 previewPageList.remove(file);
3190 previewPageList.put(file, pageNumber);
3191 PDFPreview pdfPreview = new PDFPreview();
3192 boolean goodPreview = pdfPreview.setupPreview(file, "pdf", pageNumber);
3195 // String html = getContent();
3196 QWebSettings.setMaximumPagesInCache(0);
3197 QWebSettings.setObjectCacheCapacities(0, 0, 0);
3198 // browser.setContent(new QByteArray());
3199 browser.setHtml(browser.page().mainFrame().toHtml());
3201 // browser.setContent(new QByteArray(html));
3202 // browser.triggerPageAction(WebAction.Reload);
3203 // pdfMouseOver(selectedFile);
3207 public void previousPage(String file) {
3208 logger.log(logger.EXTREME, "Starting previousPage()");
3211 if (previewPageList.containsKey(file))
3212 pageNumber = previewPageList.get(file)-1;
3215 previewPageList.remove(file);
3216 previewPageList.put(file, pageNumber);
3217 PDFPreview pdfPreview = new PDFPreview();
3218 boolean goodPreview = pdfPreview.setupPreview(file, "pdf", pageNumber);
3221 // String html = getContent();
3222 QWebSettings.setMaximumPagesInCache(0);
3223 QWebSettings.setObjectCacheCapacities(0, 0, 0);
3224 browser.setHtml(browser.page().mainFrame().toHtml());
3226 // browser.setContent(new QByteArray(html));
3227 // browser.triggerPageAction(WebAction.Reload);
3231 /* public void pdfMouseOver(String name) {
3233 if (previewPageList.containsKey(selectedFile))
3234 pageNumber = previewPageList.get(selectedFile)+1;
3238 if (pageNumber <= 1)
3239 browser.previousPageAction.setEnabled(false);
3241 browser.previousPageAction.setEnabled(true);
3243 PDFPreview pdf = new PDFPreview();
3244 int totalPages = pdf.getPageCount(name);
3245 if (previewPageList.containsKey(selectedFile))
3246 pageNumber = previewPageList.get(selectedFile)+1;
3249 if (totalPages > pageNumber)
3250 browser.nextPageAction.setEnabled(true);
3252 browser.nextPageAction.setEnabled(false);
3256 public void pdfMouseOut() {
3257 // browser.nextPageAction.setVisible(false);
3258 // browser.previousPageAction.setVisible(false);
3262 @SuppressWarnings("unused")
3263 private void toggleUndoVisible(Boolean toggle) {
3264 undoAction.setVisible(toggle);
3265 Global.saveEditorButtonsVisible("undo", toggle);
3267 @SuppressWarnings("unused")
3268 private void toggleRedoVisible(Boolean toggle) {
3269 redoAction.setVisible(toggle);
3270 Global.saveEditorButtonsVisible("redo", toggle);
3272 @SuppressWarnings("unused")
3273 private void toggleCutVisible(Boolean toggle) {
3274 cutAction.setVisible(toggle);
3275 Global.saveEditorButtonsVisible("cut", toggle);
3277 @SuppressWarnings("unused")
3278 private void toggleCopyVisible(Boolean toggle) {
3279 copyAction.setVisible(toggle);
3280 Global.saveEditorButtonsVisible("copy", toggle);
3282 @SuppressWarnings("unused")
3283 private void togglePasteVisible(Boolean toggle) {
3284 pasteAction.setVisible(toggle);
3285 Global.saveEditorButtonsVisible("paste", toggle);
3287 @SuppressWarnings("unused")
3288 private void toggleBoldVisible(Boolean toggle) {
3289 boldAction.setVisible(toggle);
3290 Global.saveEditorButtonsVisible("bold", toggle);
3292 @SuppressWarnings("unused")
3293 private void toggleItalicVisible(Boolean toggle) {
3294 italicAction.setVisible(toggle);
3295 Global.saveEditorButtonsVisible("italic", toggle);
3297 @SuppressWarnings("unused")
3298 private void toggleUnderlineVisible(Boolean toggle) {
3299 underlineAction.setVisible(toggle);
3300 Global.saveEditorButtonsVisible("underline", toggle);
3302 @SuppressWarnings("unused")
3303 private void toggleStrikethroughVisible(Boolean toggle) {
3304 strikethroughAction.setVisible(toggle);
3305 Global.saveEditorButtonsVisible("strikethrough", toggle);
3307 @SuppressWarnings("unused")
3308 private void toggleLeftAlignVisible(Boolean toggle) {
3309 leftAlignAction.setVisible(toggle);
3310 Global.saveEditorButtonsVisible("alignLeft", toggle);
3312 @SuppressWarnings("unused")
3313 private void toggleRightAlignVisible(Boolean toggle) {
3314 rightAlignAction.setVisible(toggle);
3315 Global.saveEditorButtonsVisible("alignRight", toggle);
3317 @SuppressWarnings("unused")
3318 private void toggleCenterAlignVisible(Boolean toggle) {
3319 centerAlignAction.setVisible(toggle);
3320 Global.saveEditorButtonsVisible("alignCenter", toggle);
3322 @SuppressWarnings("unused")
3323 private void toggleHLineVisible(Boolean toggle) {
3324 hlineAction.setVisible(toggle);
3325 Global.saveEditorButtonsVisible("hline", toggle);
3327 @SuppressWarnings("unused")
3328 private void toggleIndentVisible(Boolean toggle) {
3329 indentAction.setVisible(toggle);
3330 Global.saveEditorButtonsVisible("indent", toggle);
3332 @SuppressWarnings("unused")
3333 private void toggleTodoVisible(Boolean toggle) {
3334 todoAction.setVisible(toggle);
3335 Global.saveEditorButtonsVisible("todo", toggle);
3337 @SuppressWarnings("unused")
3338 private void toggleOutdentVisible(Boolean toggle) {
3339 outdentAction.setVisible(toggle);
3340 Global.saveEditorButtonsVisible("outdent", toggle);
3342 @SuppressWarnings("unused")
3343 private void toggleBulletListVisible(Boolean toggle) {
3344 bulletListAction.setVisible(toggle);
3345 Global.saveEditorButtonsVisible("bulletList", toggle);
3347 @SuppressWarnings("unused")
3348 private void toggleNumberListVisible(Boolean toggle) {
3349 numberListAction.setVisible(toggle);
3350 Global.saveEditorButtonsVisible("numberList", toggle);
3352 @SuppressWarnings("unused")
3353 private void toggleFontListVisible(Boolean toggle) {
3354 fontListAction.setVisible(toggle);
3355 Global.saveEditorButtonsVisible("font", toggle);
3357 @SuppressWarnings("unused")
3358 private void toggleFontColorVisible(Boolean toggle) {
3359 fontColorAction.setVisible(toggle);
3360 Global.saveEditorButtonsVisible("fontColor", toggle);
3362 @SuppressWarnings("unused")
3363 private void toggleFontSizeVisible(Boolean toggle) {
3364 fontSizeAction.setVisible(toggle);
3365 Global.saveEditorButtonsVisible("fontSize", toggle);
3367 @SuppressWarnings("unused")
3368 private void toggleFontHilightVisible(Boolean toggle) {
3369 fontHilightAction.setVisible(toggle);
3370 Global.saveEditorButtonsVisible("fontHilight", toggle);
3372 @SuppressWarnings("unused")
3373 private void toggleSpellCheckVisible(Boolean toggle) {
3374 spellCheckAction.setVisible(toggle);
3375 Global.saveEditorButtonsVisible("spellCheck", toggle);
3379 private void setupDictionary() {
3380 File wordList = new File(Global.getFileManager().getSpellDirPath()+Locale.getDefault()+".dic");
3382 dictionary = new SpellDictionaryHashMap(wordList);
3383 spellChecker = new SpellChecker(dictionary);
3386 userWordList = new File(Global.getFileManager().getSpellDirPathUser()+"user.dic");
3388 // Get the local user spell dictionary
3390 userDictionary = new SpellDictionaryHashMap(userWordList);
3391 } catch (FileNotFoundException e) {
3392 userWordList.createNewFile();
3393 userDictionary = new SpellDictionaryHashMap(userWordList);
3394 } catch (IOException e) {
3395 userWordList.createNewFile();
3396 userDictionary = new SpellDictionaryHashMap(userWordList);
3399 spellListener = new SuggestionListener(this, spellChecker);
3401 // Add the user dictionary
3402 spellChecker.addSpellCheckListener(spellListener);
3403 spellChecker.setUserDictionary(userDictionary);
3405 } catch (FileNotFoundException e) {
3406 QMessageBox.critical(this, tr("Spell Check Error"),
3407 tr("Dictionary ")+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+
3408 tr(".dic was not found."));
3409 } catch (IOException e) {
3410 QMessageBox.critical(this, tr("Spell Check Error"),
3411 tr("Dictionary ")+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+
3412 tr(".dic is invalid."));
3417 // Invoke spell checker dialog
3418 @SuppressWarnings("unused")
3419 private void spellCheckClicked() {
3421 if (spellChecker == null) {
3425 // Read user settings
3426 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREDIGITWORDS,
3427 Global.getSpellSetting(Configuration.SPELL_IGNOREDIGITWORDS));
3428 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREINTERNETADDRESSES,
3429 Global.getSpellSetting(Configuration.SPELL_IGNOREINTERNETADDRESSES));
3430 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREMIXEDCASE,
3431 Global.getSpellSetting(Configuration.SPELL_IGNOREMIXEDCASE));
3432 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREUPPERCASE,
3433 Global.getSpellSetting(Configuration.SPELL_IGNOREUPPERCASE));
3434 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNORESENTENCECAPITALIZATION,
3435 Global.getSpellSetting(Configuration.SPELL_IGNORESENTENCECAPITALIZATION));
3437 spellListener.abortSpellCheck = false;
3438 spellListener.errorsFound = false;
3439 String content = getBrowser().page().mainFrame().toPlainText();
3440 StringWordTokenizer tokenizer = new StringWordTokenizer(content);
3441 if (!tokenizer.hasMoreWords())
3443 getBrowser().page().action(WebAction.MoveToStartOfDocument);
3445 getBrowser().setFocus();
3448 // Move to the start of page
3449 KeyboardModifiers ctrl = new KeyboardModifiers(KeyboardModifier.ControlModifier.value());
3450 QKeyEvent home = new QKeyEvent(Type.KeyPress, Key.Key_Home.value(), ctrl);
3451 browser.keyPressEvent(home);
3452 getBrowser().setFocus();
3454 tokenizer = new StringWordTokenizer(content);
3457 while(tokenizer.hasMoreWords()) {
3458 word = tokenizer.nextWord();
3459 found = getBrowser().page().findText(word);
3460 if (found && !spellListener.abortSpellCheck) {
3461 spellChecker.checkSpelling(new StringWordTokenizer(word));
3462 getBrowser().setFocus();
3466 // Go to the end of the document & finish up.
3467 home = new QKeyEvent(Type.KeyPress, Key.Key_End.value(), ctrl);
3468 browser.keyPressEvent(home);
3469 if (!spellListener.errorsFound)
3470 QMessageBox.information(this, tr("Spell Check Complete"),
3471 tr("No Errors Found"));
3476 @SuppressWarnings("unused")
3477 private void sourceEdited() {
3478 QTextCodec codec = QTextCodec.codecForLocale();
3479 codec = QTextCodec.codecForName("UTF-8");
3480 String content = codec.fromUnicode(sourceEdit.toHtml()).toString();
3481 content = StringEscapeUtils.unescapeHtml4(removeTags(content));
3482 QByteArray data = new QByteArray(sourceEditHeader+content+"</body></html>");
3483 getBrowser().setContent(data);
3485 if (currentNote != null && sourceEdit != null)
3486 noteSignal.noteChanged.emit(currentNote.getGuid(), sourceEdit.toPlainText());
3489 private void setSource() {
3490 String text = getContent();
3491 sourceEdit.blockSignals(true);
3492 int body = text.indexOf("<body");
3494 body = text.indexOf(">",body);
3496 sourceEditHeader =text.substring(0, body+1);
3497 text = text.substring(body+1);
3500 text = text.replace("</body></html>", "");
3501 sourceEdit.setPlainText(text);
3502 sourceEdit.setReadOnly(!getBrowser().page().isContentEditable());
3503 //syntaxHighlighter.rehighlight();
3504 sourceEdit.blockSignals(false);
3507 // show/hide view source window
3508 public void showSource(boolean value) {
3510 sourceEdit.setVisible(value);
3514 private String removeTags(String text) {
3515 StringBuffer buffer = new StringBuffer(text);
3516 boolean inTag = false;
3517 int bodyPosition = text.indexOf("<body");
3518 for (int i=buffer.length()-1; i>=0; i--) {
3519 if (buffer.charAt(i) == '>')
3521 if (buffer.charAt(i) == '<')
3523 if (inTag || buffer.charAt(i) == '<' || i<bodyPosition)
3524 buffer.deleteCharAt(i);
3527 return buffer.toString();