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 // We know something has changed...
1862 String oldTagArray[] = saveTagList.split(Global.tagDelimeter);
1863 String newTagArray[];
1864 if (!completionText.equals("")) {
1865 String before = tagEdit.text().substring(0,tagEdit.cursorPosition());
1866 int lastDelimiter = before.lastIndexOf(Global.tagDelimeter);
1867 if (lastDelimiter > 0)
1868 before = before.substring(0,before.lastIndexOf(Global.tagDelimeter));
1871 String after = tagEdit.text().substring(tagEdit.cursorPosition());
1872 newTagArray = (before+Global.tagDelimeter+completionText+Global.tagDelimeter+after).split(Global.tagDelimeter);
1875 newTagArray = tagEdit.text().split(Global.tagDelimeter);
1878 // Remove any traling or leading blanks
1879 for (int i=0; i<newTagArray.length; i++)
1880 newTagArray[i] = newTagArray[i].trim().replaceAll("^\\s+", "");;
1882 // Remove any potential duplicates from the new list
1883 for (int i=0; i<newTagArray.length; i++) {
1884 boolean foundOnce = false;
1885 for (int j=0; j<newTagArray.length; j++) {
1886 if (newTagArray[j].equalsIgnoreCase(newTagArray[i])) {
1890 newTagArray[j] = "";
1895 List<String> newTagList = new ArrayList<String>();
1896 List<String> oldTagList = new ArrayList<String>();
1898 for (int i = 0; i < oldTagArray.length; i++)
1899 if (!oldTagArray[i].trim().equals(""))
1900 oldTagList.add(oldTagArray[i]);
1901 for (int i = 0; i < newTagArray.length; i++)
1902 if (!newTagArray[i].trim().equals(""))
1903 newTagList.add(newTagArray[i]);
1905 if (conn.getNotebookTable().isLinked(currentNote.getNotebookGuid())) {
1906 for (int i=newTagList.size()-1; i>=0; i--) {
1907 boolean found = false;
1908 for (int j=0; j<allTags.size(); j++) {
1909 if (allTags.get(j).getName().equalsIgnoreCase(newTagList.get(i))) {
1915 newTagList.remove(i);
1919 // Let's cleanup the appearance of the tag list
1920 Collections.sort(newTagList);
1921 String newDisplay = "";
1922 for (int i=0; i<newTagList.size(); i++) {
1923 newDisplay = newDisplay+newTagList.get(i);
1924 if (i<newTagList.size()-1)
1925 newDisplay = newDisplay+Global.tagDelimeter +" ";
1927 tagEdit.blockSignals(true);
1928 tagEdit.setText(newDisplay);
1929 tagEdit.blockSignals(false);
1931 // We now have lists of the new & old. Remove duplicates. If all
1932 // are removed from both then nothing has really changed
1933 for (int i = newTagList.size() - 1; i >= 0; i--) {
1934 String nTag = newTagList.get(i);
1935 for (int j = oldTagList.size() - 1; j >= 0; j--) {
1936 String oTag = oldTagList.get(j);
1937 if (oTag.equalsIgnoreCase(nTag)) {
1938 oldTagList.remove(j);
1939 newTagList.remove(i);
1945 if (oldTagList.size() != 0 || newTagList.size() != 0) {
1946 currentTags.clear();
1947 newTagArray = tagEdit.text().split(Global.tagDelimeter);
1948 for (int i = 0; i < newTagArray.length; i++)
1949 if (!newTagArray[i].trim().equals(""))
1950 currentTags.add(newTagArray[i].trim());
1952 noteSignal.tagsChanged.emit(currentNote.getGuid(), currentTags);
1957 // Tab button was pressed
1958 public void tabPressed() {
1959 if (insideEncryption)
1961 if (!insideList && !insideTable) {
1962 String script_start = new String(
1963 "document.execCommand('insertHtml', false, ' ');");
1964 browser.page().mainFrame().evaluateJavaScript(script_start);
1971 String js = new String( "function getCursorPosition() { "
1972 +" var selObj = window.getSelection();"
1973 +" var selRange = selObj.getRangeAt(0);"
1974 +" var workingNode = window.getSelection().anchorNode;"
1975 +" var rowCount = 0;"
1976 +" var colCount = 0;"
1977 +" while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { "
1978 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
1979 +" rowCount = rowCount+1;"
1981 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
1982 +" colCount = colCount+1;"
1984 +" if (workingNode.previousSibling != null)"
1985 +" workingNode = workingNode.previousSibling;"
1987 +" workingNode = workingNode.parentNode;"
1989 +" var nodes = workingNode.getElementsByTagName('tr');"
1990 +" var tableRows = nodes.length;"
1991 +" nodes = nodes[0].getElementsByTagName('td');"
1992 +" var tableColumns = nodes.length;"
1993 +" window.jambi.setTableCursorPositionTab(rowCount, colCount, tableRows, tableColumns);"
1994 +"} getCursorPosition();");
1995 browser.page().mainFrame().evaluateJavaScript(js);
1999 // If a user presses tab from within a table
2000 public void setTableCursorPositionTab(int currentRow, int currentCol, int tableRows, int tableColumns) {
2001 if (tableRows == currentRow && currentCol == tableColumns) {
2004 KeyboardModifiers modifiers = new KeyboardModifiers(KeyboardModifier.NoModifier);
2005 QKeyEvent right = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Right.value(), modifiers);
2006 QKeyEvent end = new QKeyEvent(Type.KeyPress, Qt.Key.Key_End.value(), modifiers);
2007 QKeyEvent end2 = new QKeyEvent(Type.KeyPress, Qt.Key.Key_End.value(), modifiers);
2008 getBrowser().focusWidget();
2009 QCoreApplication.postEvent(getBrowser(), end);
2010 QCoreApplication.postEvent(getBrowser(), right);
2011 QCoreApplication.postEvent(getBrowser(), end2);
2014 public void backtabPressed() {
2015 if (insideEncryption)
2020 String js = new String( "function getCursorPosition() { "
2021 +" var selObj = window.getSelection();"
2022 +" var selRange = selObj.getRangeAt(0);"
2023 +" var workingNode = window.getSelection().anchorNode;"
2024 +" var rowCount = 0;"
2025 +" var colCount = 0;"
2026 +" while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { "
2027 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
2028 +" rowCount = rowCount+1;"
2030 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
2031 +" colCount = colCount+1;"
2033 +" if (workingNode.previousSibling != null)"
2034 +" workingNode = workingNode.previousSibling;"
2036 +" workingNode = workingNode.parentNode;"
2038 +" var nodes = workingNode.getElementsByTagName('tr');"
2039 +" var tableRows = nodes.length;"
2040 +" nodes = nodes[0].getElementsByTagName('td');"
2041 +" var tableColumns = nodes.length;"
2042 +" window.jambi.setTableCursorPositionBackTab(rowCount, colCount, tableRows, tableColumns);"
2043 +"} getCursorPosition();");
2044 browser.page().mainFrame().evaluateJavaScript(js);
2049 // If a user presses backtab from within a table
2050 public void setTableCursorPositionBackTab(int currentRow, int currentCol, int tableRows, int tableColumns) {
2051 if (currentRow == 1 && currentCol == 1) {
2054 KeyboardModifiers modifiers = new KeyboardModifiers(KeyboardModifier.NoModifier);
2055 QKeyEvent left = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Left.value(), modifiers);
2056 QKeyEvent home = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Home.value(), modifiers);
2057 getBrowser().focusWidget();
2058 QCoreApplication.postEvent(getBrowser(), home);
2059 QCoreApplication.postEvent(getBrowser(), left);
2063 public void setInsideList() {
2067 // The title has been edited
2068 @SuppressWarnings("unused")
2069 private void titleEdited() {
2070 // If we don't have a good note, or if the current title
2071 // matches the old title then we don't need to do anything
2072 if (currentNote == null)
2074 if (currentNote.getTitle().trim().equals(titleLabel.text().trim()))
2077 // If we have a real change, we need to save it.
2078 String text = titleLabel.text().trim();
2079 if (text.equals(""))
2080 text = tr("Untitled Note");
2081 noteSignal.titleChanged.emit(currentNote.getGuid(), text);
2082 currentNote.setTitle(text);
2083 saveNoteTitle = text;
2087 // Set the list of note tags
2088 public void setAllTags(List<Tag> l) {
2090 tagEdit.setTagList(l);
2093 // Setter for the current tags
2094 public void setCurrentTags(List<String> s) {
2098 // Save the list of notebooks
2099 public void setNotebookList(List<Notebook> n) {
2104 // Load the notebook list and select the current notebook
2105 private void loadNotebookList() {
2106 if (notebookBox.count() != 0)
2107 notebookBox.clear();
2108 if (notebookList == null)
2111 for (int i = 0; i < notebookList.size(); i++) {
2112 notebookBox.addItem(notebookList.get(i).getName());
2113 if (currentNote != null) {
2114 if (currentNote.getNotebookGuid().equals(
2115 notebookList.get(i).getGuid())) {
2116 notebookBox.setCurrentIndex(i);
2123 // Set the notebook for a note
2124 public void setNotebook(String notebook) {
2125 currentNote.setNotebookGuid(notebook);
2129 // Get the contents of the editor
2130 public String getContent() {
2131 return browser.page().currentFrame().toHtml();
2134 // The note contents have changed
2135 public void contentChanged() {
2136 String content = getContent();
2138 // This puts in a 1/2 second delay
2139 // before updating the source editor.
2140 // It improves response when someone is doing
2141 // frequent updates on a large note.
2142 // If the source editor isn't visible, then there
2143 // is no point to doing any of this.
2144 if (sourceEdit.isVisible()) {
2145 setSourceTimer.stop();
2146 setSourceTimer.setInterval(500);
2147 setSourceTimer.setSingleShot(true);
2148 setSourceTimer.start();
2152 noteSignal.noteChanged.emit(currentNote.getGuid(), content);
2155 // The notebook selection has changed
2156 @SuppressWarnings("unused")
2157 private void notebookChanged() {
2158 boolean changed = false;
2159 String n = notebookBox.currentText();
2160 for (int i = 0; i < notebookList.size(); i++) {
2161 if (n.equals(notebookList.get(i).getName())) {
2162 if (!notebookList.get(i).getGuid().equals(currentNote.getNotebookGuid())) {
2163 String guid = conn.getNotebookTable().findNotebookByName(n);
2164 if (conn.getNotebookTable().isLinked(guid)) {
2165 tagEdit.setText("");
2166 noteSignal.tagsChanged.emit(currentNote.getGuid(), new ArrayList<String>());
2167 FilterEditorTags t = new FilterEditorTags(conn, logger);
2168 setAllTags(t.getValidTags(currentNote));
2170 currentNote.setNotebookGuid(notebookList.get(i).getGuid());
2173 i = notebookList.size();
2177 // If the notebook changed, signal the update
2179 noteSignal.notebookChanged.emit(currentNote.getGuid(), currentNote
2180 .getNotebookGuid());
2183 // Check the note title
2184 private void checkNoteTitle() {
2185 String text = browser.page().currentFrame().toPlainText();
2186 if (saveNoteTitle == null)
2187 saveNoteTitle = new String();
2189 if (!saveNoteTitle.trim().equals("") && !saveNoteTitle.trim().equals("Untitled Note"))
2190 text = saveNoteTitle.trim();
2191 int newLine = text.indexOf("\n");
2193 text = text.substring(0,newLine);
2194 if (saveNoteTitle.trim().equals("") || saveNoteTitle.trim().equals("Untitled Note")) {
2195 if (text.trim().equals(""))
2196 text = tr("Untitled Note");
2197 titleLabel.setText(text);
2199 if (text.length() > Constants.EDAM_NOTE_TITLE_LEN_MAX)
2200 titleLabel.setText(text.substring(0, Constants.EDAM_NOTE_TITLE_LEN_MAX));
2202 titleLabel.blockSignals(true);
2203 if (text.trim().equals(""))
2204 titleLabel.setText(tr("Untitled Note"));
2206 titleLabel.setText(text);
2207 titleLabel.blockSignals(false);
2210 if (currentNote != null && titleLabel != null && !currentNote.getTitle().equals(text))
2211 noteSignal.titleChanged.emit(currentNote.getGuid(), text);
2214 // Return the note contents so we can email them
2215 public String getContentsToEmail() {
2216 return browser.page().currentFrame().toPlainText().trim();
2218 * int body = browser.page().currentFrame().toHtml().indexOf("<body>");
2219 * String temp = browser.page().currentFrame().toHtml(); if (body == -1)
2220 * temp = "<html><body><b>Test</b></body></html>"; else temp =
2221 * "<html>"+temp.substring(body); return temp; // return
2222 * urlEncode(browser.page().currentFrame().toHtml());
2226 // Insert an image into the editor
2227 private void insertImage(QMimeData mime) {
2228 logger.log(logger.EXTREME, "Entering insertImage");
2229 QImage img = (QImage) mime.imageData();
2230 String script_start = new String(
2231 "document.execCommand('insertHTML', false, '");
2232 String script_end = new String("');");
2234 long now = new Date().getTime();
2235 String path = Global.getFileManager().getResDirPath(
2236 (new Long(now).toString()) + ".jpg");
2238 // This block is just a hack to make sure we wait at least 1ms so we
2240 // have collisions on image names
2241 long i = new Date().getTime();
2243 i = new Date().getTime();
2245 // Open the file & write the data
2246 QFile tfile = new QFile(path);
2247 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
2248 if (!img.save(tfile)) {
2254 Resource newRes = createResource(QUrl.fromLocalFile(path).toString(), 0, "image/jpeg", false);
2257 currentNote.getResources().add(newRes);
2259 // do the actual insert into the note
2260 StringBuffer buffer = new StringBuffer(100);
2261 buffer.append("<img src=\"");
2262 buffer.append(tfile.fileName());
2263 buffer.append("\" en-tag=en-media type=\"image/jpeg\""
2264 +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""
2265 +" guid=\"" +newRes.getGuid() +"\""
2266 +" onContextMenu=\"window.jambi.imageContextMenu(&." +tfile.fileName() +"&.);\""
2269 browser.page().mainFrame().evaluateJavaScript(
2270 script_start + buffer + script_end);
2275 // Handle pasting of a note-to-note link
2276 private void handleNoteLink(QMimeData mime) {
2277 for (int i=0; i<mime.urls().size(); i++) {
2278 StringTokenizer tokens = new StringTokenizer(mime.urls().get(i).toString().replace("evernote:///view/", ""), "/");
2281 String sid = tokens.nextToken();
2282 String lid = tokens.nextToken();
2284 if (!sid.equals(currentNote.getGuid()) && !lid.equals(currentNote.getGuid())) {
2286 Note note = conn.getNoteTable().getNote(sid, false, false, false, false, false);
2288 note = conn.getNoteTable().getNote(lid, false, false, false, false, false);
2293 // If we've gotten this far, we have a bunch of values. We need to build the link.
2294 StringBuffer url = new StringBuffer(100);
2295 String script_start = new String(
2296 "document.execCommand('insertHtml', false, '");
2297 String script_end = new String("');");
2299 url.append("<a href=\""+mime.urls().get(i).toString() +"\" style=\"color:#69aa35\">");
2300 url.append(note.getTitle());
2302 if (mime.urls().size() > 1)
2303 url.append(" ");
2304 browser.page().mainFrame().evaluateJavaScript(
2305 script_start + url + script_end);
2310 // Handle URLs that are trying to be pasted
2311 public void handleUrls(QMimeData mime) {
2312 logger.log(logger.EXTREME, "Starting handleUrls");
2313 FileNameMap fileNameMap = URLConnection.getFileNameMap();
2315 List<QUrl> urlList = mime.urls();
2316 String url = new String();
2317 String script_start = new String(
2318 "document.execCommand('createLink', false, '");
2319 String script_end = new String("');");
2321 for (int i = 0; i < urlList.size(); i++) {
2322 url = urlList.get(i).toString();
2323 // Find out what type of file we have
2324 String mimeType = fileNameMap.getContentTypeFor(url);
2326 // If null returned, we need to guess at the file type
2327 if (mimeType == null)
2328 mimeType = "application/"
2329 + url.substring(url.lastIndexOf(".") + 1);
2331 // Check if we have an image or some other type of file
2332 if (url.substring(0, 5).equalsIgnoreCase("file:")
2333 && mimeType.substring(0, 5).equalsIgnoreCase("image")) {
2334 handleLocalImageURLPaste(mime, mimeType);
2338 boolean smallEnough = checkFileAttachmentSize(url);
2340 && url.substring(0, 5).equalsIgnoreCase("file:")
2341 && !mimeType.substring(0, 5).equalsIgnoreCase("image")) {
2342 handleLocalAttachment(mime, mimeType);
2345 browser.page().mainFrame().evaluateJavaScript(
2346 script_start + url + script_end);
2351 // If a URL being pasted is an image URL, then attach the image
2352 private void handleLocalImageURLPaste(QMimeData mime, String mimeType) {
2353 List<QUrl> urlList = mime.urls();
2354 String url = new String();
2355 String script_start_image = new String(
2356 "document.execCommand('insertHtml', false, '");
2357 String script_end = new String("');");
2358 StringBuffer buffer;
2360 // Copy the image over into the resource directory and create a new resource
2361 // record for each url pasted
2362 for (int i = 0; i < urlList.size(); i++) {
2363 url = urlList.get(i).toString();
2365 Resource newRes = createResource(url, i, mimeType, false);
2368 currentNote.getResources().add(newRes);
2369 buffer = new StringBuffer(100);
2371 // Open the file & write the data
2372 String fileName = Global.getFileManager().getResDirPath(newRes.getGuid());
2373 QFile tfile = new QFile(fileName);
2374 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
2375 tfile.write(newRes.getData().getBody());
2377 buffer.append(script_start_image);
2378 buffer.append("<img src=\"" + FileUtils.toForwardSlashedPath(fileName));
2379 // if (mimeType.equalsIgnoreCase("image/jpg"))
2380 // mimeType = "image/jpeg";
2381 buffer.append("\" en-tag=\"en-media\" type=\"" + mimeType +"\""
2382 +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""
2383 +" guid=\"" +newRes.getGuid() +"\""
2384 +" onContextMenu=\"window.jambi.imageContextMenu('" +tfile.fileName() +"');\""
2386 buffer.append(script_end);
2387 browser.page().mainFrame().evaluateJavaScript(buffer.toString());
2393 // If a URL being pasted is a local file URL, then attach the file
2394 private void handleLocalAttachment(QMimeData mime, String mimeType) {
2395 logger.log(logger.EXTREME, "Attaching local file");
2396 List<QUrl> urlList = mime.urls();
2397 String script_start = new String(
2398 "document.execCommand('insertHtml', false, '");
2399 String script_end = new String("');");
2400 StringBuffer buffer;
2402 String[] type = mimeType.split("/");
2403 String icon = findIcon(type[1]);
2404 if (icon.equals("attachment.png"))
2405 icon = findIcon(type[0]);
2406 buffer = new StringBuffer(100);
2408 for (int i = 0; i < urlList.size(); i++) {
2409 String url = urlList.get(i).toString();
2411 // Start building the HTML
2412 if (icon.equals("attachment.png"))
2413 icon = findIcon(url.substring(url.lastIndexOf(".")+1));
2414 String imageURL = FileUtils.toFileURLString(Global.getFileManager().getImageDirFile(icon));
2416 logger.log(logger.EXTREME, "Creating resource ");
2417 Resource newRes = createResource(url, i, mimeType, true);
2420 logger.log(logger.EXTREME, "New resource size: " +newRes.getData().getSize());
2421 currentNote.getResources().add(newRes);
2423 String fileName = newRes.getGuid() + Global.attachmentNameDelimeter+newRes.getAttributes().getFileName();
2424 // If we have a PDF, we need to setup the preview.
2425 if (icon.equalsIgnoreCase("pdf.png") && Global.pdfPreview()) {
2426 logger.log(logger.EXTREME, "Setting up PDF preview");
2427 if (newRes.getAttributes() != null &&
2428 newRes.getAttributes().getFileName() != null &&
2429 !newRes.getAttributes().getFileName().trim().equals(""))
2430 fileName = newRes.getGuid()+Global.attachmentNameDelimeter+
2431 newRes.getAttributes().getFileName();
2433 fileName = newRes.getGuid()+".pdf";
2434 QFile file = new QFile(Global.getFileManager().getResDirPath(fileName));
2435 QFile.OpenMode mode = new QFile.OpenMode();
2436 mode.set(QFile.OpenModeFlag.WriteOnly);
2438 QDataStream out = new QDataStream(file);
2439 // Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(newRes.getGuid(), true);
2440 QByteArray binData = new QByteArray(newRes.getData().getBody());
2441 // resBinary = null;
2442 out.writeBytes(binData.toByteArray());
2445 PDFPreview pdfPreview = new PDFPreview();
2446 if (pdfPreview.setupPreview(Global.getFileManager().getResDirPath(fileName), "pdf",0)) {
2447 imageURL = file.fileName() + ".png";
2451 logger.log(logger.EXTREME, "Generating link tags");
2452 buffer.delete(0, buffer.length());
2453 buffer.append("<a en-tag=\"en-media\" guid=\"" +newRes.getGuid()+"\" ");
2454 buffer.append(" onContextMenu=\"window.jambi.imageContextMenu('")
2455 .append(Global.getFileManager().getResDirPath(fileName))
2456 .append("');\" ");
2457 buffer.append("type=\"" + mimeType + "\" href=\"nnres://" + fileName +"\" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\" >");
2458 buffer.append("<img src=\"" + imageURL + "\" title=\"" +newRes.getAttributes().getFileName());
2459 buffer.append("\"></img>");
2460 buffer.append("</a>");
2461 browser.page().mainFrame().evaluateJavaScript(
2462 script_start + buffer.toString() + script_end);
2467 private Resource createResource(String url, int sequence, String mime, boolean attachment) {
2468 logger.log(logger.EXTREME, "Inside create resource");
2470 //These two lines are added to handle odd characters in the name like #. Without it
2471 // toLocalFile() chokes and returns the wrong name.
2472 logger.log(logger.EXTREME, "File URL:" +url);
2473 String whichOS = System.getProperty("os.name");
2474 if (whichOS.contains("Windows"))
2475 url = url.replace("file:///", "");
2477 url = url.replace("file://", "");
2478 String urlTest = new QUrl(url).toLocalFile();
2479 logger.log(logger.EXTREME, "File URL toLocalFile():" +urlTest);
2481 if (!urlTest.equals(""))
2483 // url = url.replace("/", File.separator);
2484 logger.log(logger.EXTREME, "Reading from file to create resource:" +url);
2485 resourceFile = new QFile(url);
2486 resourceFile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly));
2487 logger.log(logger.EXTREME, "Error opening file "+url.toString() +": "+resourceFile.errorString());
2488 byte[] fileData = resourceFile.readAll().toByteArray();
2489 resourceFile.close();
2490 logger.log(logger.EXTREME, "File Length: " +fileData.length);
2491 if (fileData.length == 0)
2495 logger.log(logger.EXTREME, "Generating MD5");
2496 md = MessageDigest.getInstance("MD5");
2497 md.update(fileData);
2498 byte[] hash = md.digest();
2500 Resource r = new Resource();
2501 Calendar time = new GregorianCalendar();
2502 long prevTime = time.getTimeInMillis();
2503 while (prevTime == time.getTimeInMillis()) {
2504 time = new GregorianCalendar();
2506 r.setGuid(time.getTimeInMillis()+new Integer(sequence).toString());
2507 r.setNoteGuid(currentNote.getGuid());
2510 r.setUpdateSequenceNum(0);
2511 r.setWidth((short) 0);
2512 r.setHeight((short) 0);
2513 r.setDuration((short) 0);
2515 Data d = new Data();
2516 d.setBody(fileData);
2517 d.setBodyIsSet(true);
2518 d.setBodyHash(hash);
2519 d.setBodyHashIsSet(true);
2521 d.setSize(fileData.length);
2523 int fileNamePos = url.lastIndexOf(File.separator);
2524 if (fileNamePos == -1)
2525 fileNamePos = url.lastIndexOf("/");
2526 String fileName = url.substring(fileNamePos+1);
2527 ResourceAttributes a = new ResourceAttributes();
2529 a.setAltitudeIsSet(false);
2531 a.setLongitudeIsSet(false);
2533 a.setLatitudeIsSet(false);
2534 a.setCameraMake("");
2535 a.setCameraMakeIsSet(false);
2536 a.setCameraModel("");
2537 a.setCameraModelIsSet(false);
2538 a.setAttachment(attachment);
2539 a.setAttachmentIsSet(true);
2540 a.setClientWillIndex(false);
2541 a.setClientWillIndexIsSet(true);
2543 a.setRecoTypeIsSet(false);
2544 a.setSourceURL(url);
2545 a.setSourceURLIsSet(true);
2547 a.setTimestampIsSet(false);
2548 a.setFileName(fileName);
2549 a.setFileNameIsSet(true);
2552 conn.getNoteTable().noteResourceTable.saveNoteResource(r, true);
2553 logger.log(logger.EXTREME, "Resource created");
2555 } catch (NoSuchAlgorithmException e1) {
2556 e1.printStackTrace();
2562 // find the appropriate icon for an attachment
2563 private String findIcon(String appl) {
2564 appl = appl.toLowerCase();
2565 File f = Global.getFileManager().getImageDirFile(appl + ".png");
2568 return "attachment.png";
2573 // Check the file attachment to be sure it isn't over 25 mb
2574 private boolean checkFileAttachmentSize(String url) {
2575 String fileName = url.substring(8);
2576 QFile resourceFile = new QFile(fileName);
2577 resourceFile.open(new QIODevice.OpenMode(
2578 QIODevice.OpenModeFlag.ReadOnly));
2579 long size = resourceFile.size();
2580 resourceFile.close();
2581 size = size / 1024 / 1024;
2582 if (size < 50 && Global.isPremium())
2587 String error = tr("A file attachment may not exceed 25MB.");
2588 QMessageBox.information(this, tr("Attachment Size"), error);
2593 @SuppressWarnings("unused")
2594 private void createdChanged() {
2595 QDateTime dt = new QDateTime();
2596 dt.setDate(createdDate.date());
2597 dt.setTime(createdTime.time());
2598 noteSignal.createdDateChanged.emit(currentNote.getGuid(), dt);
2602 @SuppressWarnings("unused")
2603 private void alteredChanged() {
2604 QDateTime dt = new QDateTime();
2605 dt.setDate(alteredDate.date());
2606 dt.setTime(alteredTime.time());
2607 noteSignal.alteredDateChanged.emit(currentNote.getGuid(), dt);
2610 @SuppressWarnings("unused")
2611 private void subjectDateTimeChanged() {
2612 QDateTime dt = new QDateTime();
2613 dt.setDate(subjectDate.date());
2614 dt.setTime(subjectTime.time());
2615 noteSignal.subjectDateChanged.emit(currentNote.getGuid(), dt);
2619 @SuppressWarnings("unused")
2620 private void sourceUrlChanged() {
2621 noteSignal.sourceUrlChanged.emit(currentNote.getGuid(), urlText.text());
2624 @SuppressWarnings("unused")
2625 private void authorChanged() {
2626 noteSignal.authorChanged.emit(currentNote.getGuid(), authorText.text());
2629 @SuppressWarnings("unused")
2630 private void geoBoxChanged() {
2631 int index = geoBox.currentIndex();
2632 geoBox.setCurrentIndex(0);
2634 GeoDialog box = new GeoDialog();
2635 box.setLongitude(currentNote.getAttributes().getLongitude());
2636 box.setLatitude(currentNote.getAttributes().getLatitude());
2637 box.setAltitude(currentNote.getAttributes().getAltitude());
2639 if (!box.okPressed())
2641 double alt = box.getAltitude();
2642 double lat = box.getLatitude();
2643 double lon = box.getLongitude();
2644 if (alt != currentNote.getAttributes().getAltitude() ||
2645 lon != currentNote.getAttributes().getLongitude() ||
2646 lat != currentNote.getAttributes().getLatitude()) {
2647 noteSignal.geoChanged.emit(currentNote.getGuid(), lon, lat, alt);
2648 currentNote.getAttributes().setAltitude(alt);
2649 currentNote.getAttributes().setLongitude(lon);
2650 currentNote.getAttributes().setLatitude(lat);
2655 noteSignal.geoChanged.emit(currentNote.getGuid(), 0.0, 0.0, 0.0);
2656 currentNote.getAttributes().setAltitude(0.0);
2657 currentNote.getAttributes().setLongitude(0.0);
2658 currentNote.getAttributes().setLatitude(0.0);
2661 if (index == 3 || index == 0) {
2662 QDesktopServices.openUrl(new QUrl("http://maps.google.com/maps?z=6&q="+currentNote.getAttributes().getLatitude() +"," +currentNote.getAttributes().getLongitude()));
2666 // ************************************************************
2667 // * User chose to save an attachment. Pares out the request *
2668 // * into a guid & file. Save the result. *
2669 // ************************************************************
2670 public void downloadAttachment(QNetworkRequest request) {
2672 QFileDialog fd = new QFileDialog(this);
2673 fd.setFileMode(FileMode.AnyFile);
2674 fd.setConfirmOverwrite(true);
2675 fd.setWindowTitle(tr("Save File"));
2676 fd.setAcceptMode(AcceptMode.AcceptSave);
2677 fd.setDirectory(System.getProperty("user.home"));
2678 String name = request.url().toString();
2680 int pos = name.lastIndexOf(Global.attachmentNameDelimeter);
2682 guid = name.substring(0, pos).replace("nnres://", "");
2683 name = name.substring(pos +Global.attachmentNameDelimeter.length());
2684 fd.selectFile(name);
2685 pos = name.lastIndexOf('.');
2687 String mimeType = "(*." + name.substring(pos + 1)
2688 + ");; All Files (*)";
2689 fd.setFilter(tr(mimeType));
2695 // Strip URL prefix and base dir
2696 guid = guid.replace("nnres://", "")
2697 .replace(FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath()), "");
2698 guid = guid.replace("file://", "").replace("/", "")
2699 .replace(FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath()), "");
2701 pos = guid.lastIndexOf('.');
2703 guid = guid.substring(0,pos);
2704 if (fd.exec() != 0 && fd.selectedFiles().size() > 0) {
2705 name = name.replace('\\', '/');
2706 Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
2707 QFile saveFile = new QFile(fd.selectedFiles().get(0));
2708 QFile.OpenMode mode = new QFile.OpenMode();
2709 mode.set(QFile.OpenModeFlag.WriteOnly);
2710 saveFile.open(mode);
2711 QDataStream saveOut = new QDataStream(saveFile);
2712 QByteArray binData = new QByteArray(resBinary.getData().getBody());
2713 saveOut.writeBytes(binData.toByteArray());
2720 // ************************************************************
2721 // * User chose to save an attachment. Pares out the request *
2722 // * into a guid & file. Save the result. --- DONE FROM downloadAttachment now!!!!!
2723 // ************************************************************
2724 public void downloadImage(QNetworkRequest request) {
2725 QFileDialog fd = new QFileDialog(this);
2726 fd.setFileMode(FileMode.AnyFile);
2727 fd.setConfirmOverwrite(true);
2728 fd.setWindowTitle(tr("Save File"));
2729 fd.setAcceptMode(AcceptMode.AcceptSave);
2730 fd.setDirectory(System.getProperty("user.home"));
2731 String name = request.url().toString();
2732 name = name.replace("nnres://", "");
2733 String dPath = FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath());
2734 name = name.replace(dPath, "");
2735 int pos = name.lastIndexOf('.');
2738 String mimeType = "(*." + name.substring(pos + 1)
2739 + ");; All Files (*)";
2740 fd.setFilter(tr(mimeType));
2741 guid = guid.substring(0,pos);
2743 pos = name.lastIndexOf(Global.attachmentNameDelimeter);
2745 guid = name.substring(0, pos);
2746 fd.selectFile(name.substring(pos+Global.attachmentNameDelimeter.length()));
2748 if (fd.exec() != 0 && fd.selectedFiles().size() > 0) {
2749 Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
2750 String fileName = fd.selectedFiles().get(0);
2751 QFile saveFile = new QFile(fileName);
2752 QFile.OpenMode mode = new QFile.OpenMode();
2753 mode.set(QFile.OpenModeFlag.WriteOnly);
2754 saveFile.open(mode);
2755 QDataStream saveOut = new QDataStream(saveFile);
2756 QByteArray binData = new QByteArray(resBinary.getData().getBody());
2757 saveOut.writeBytes(binData.toByteArray());
2763 // *************************************************************
2764 // * decrypt any hidden text. We could do an XML parse, but
2765 // * it is quicker here just to scan for an <img tag & do the fix
2767 // *************************************************************
2768 private void removeEncryption(String id, String plainText, boolean permanent, String slot) {
2770 plainText = " <table class=\"en-crypt-temp\" slot=\""
2773 +"border=1 width=100%><tbody><tr><td>"
2774 +plainText+"</td></tr></tbody></table>";
2777 String html = browser.page().mainFrame().toHtml();
2779 int imagePos = html.indexOf("<img");
2781 for ( ;imagePos>0; ) {
2783 endPos = text.indexOf(">", imagePos);
2784 String tag = text.substring(imagePos-1,endPos);
2785 if (tag.indexOf("id=\""+id+"\"") > -1) {
2786 text = text.substring(0,imagePos) +plainText+text.substring(endPos+1);
2787 QTextCodec codec = QTextCodec.codecForName("UTF-8");
2788 QByteArray unicode = codec.fromUnicode(text);
2789 setContent(unicode);
2793 imagePos = text.indexOf("<img", imagePos+1);
2798 //****************************************************************
2800 //****************************************************************
2801 @SuppressWarnings("unused")
2802 private void focusTitle() {
2803 titleLabel.setFocus();
2805 @SuppressWarnings("unused")
2806 private void focusTag() {
2809 @SuppressWarnings("unused")
2810 private void focusNote() {
2813 @SuppressWarnings("unused")
2814 private void focusAuthor() {
2815 authorLabel.setFocus();
2817 @SuppressWarnings("unused")
2818 private void focusUrl() {
2819 urlLabel.setFocus();
2823 //*****************************************************************
2824 //* Set the document background color
2825 //*****************************************************************
2826 public void setBackgroundColor(String color) {
2827 String js = "function changeBackground(color) {"
2828 +"document.body.style.background = color;"
2830 +"changeBackground('" +color+"');";
2831 browser.page().mainFrame().evaluateJavaScript(js);
2836 //****************************************************************
2837 //* MicroFocus changed
2838 //****************************************************************
2839 private void microFocusChanged() {
2840 boldButton.setDown(false);
2841 italicButton.setDown(false);
2842 underlineButton.setDown(false);
2843 browser.openAction.setEnabled(false);
2844 browser.downloadAttachment.setEnabled(false);
2845 browser.downloadImage.setEnabled(false);
2846 browser.rotateImageLeft.setEnabled(false);
2847 browser.rotateImageRight.setEnabled(false);
2848 browser.insertTableAction.setEnabled(true);
2849 browser.deleteTableColumnAction.setEnabled(false);
2850 browser.insertTableRowAction.setEnabled(false);
2851 browser.insertTableColumnAction.setEnabled(false);
2852 browser.deleteTableRowAction.setEnabled(false);
2853 browser.insertLinkAction.setText(tr("Insert Hyperlink"));
2854 insertHyperlink = true;
2855 browser.insertQuickLinkAction.setEnabled(true);
2856 currentHyperlink ="";
2858 insideTable = false;
2859 insideEncryption = false;
2860 forceTextPaste = false;
2862 String js = new String( "function getCursorPos() {"
2864 +"if (window.getSelection) {"
2865 +" var selObj = window.getSelection();"
2866 +" var selRange = selObj.getRangeAt(0);"
2867 +" var workingNode = window.getSelection().anchorNode.parentNode;"
2868 +" while(workingNode != null) { "
2869 // +" window.jambi.printNode(workingNode.nodeName);"
2870 +" if (workingNode.nodeName=='TABLE') { if (workingNode.getAttribute('class').toLowerCase() == 'en-crypt-temp') window.jambi.insideEncryption(); }"
2871 +" if (workingNode.nodeName=='B') window.jambi.boldActive();"
2872 +" if (workingNode.nodeName=='I') window.jambi.italicActive();"
2873 +" if (workingNode.nodeName=='U') window.jambi.underlineActive();"
2874 +" if (workingNode.nodeName=='UL') window.jambi.setInsideList();"
2875 +" if (workingNode.nodeName=='OL') window.jambi.setInsideList();"
2876 +" if (workingNode.nodeName=='LI') window.jambi.setInsideList();"
2877 +" if (workingNode.nodeName=='TBODY') window.jambi.setInsideTable();"
2878 +" 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);}}"
2879 +" if (workingNode.nodeName=='SPAN') {"
2880 +" if (workingNode.getAttribute('style') == 'text-decoration: underline;') window.jambi.underlineActive();"
2882 +" workingNode = workingNode.parentNode;"
2885 +"} getCursorPos();");
2886 browser.page().mainFrame().evaluateJavaScript(js);
2889 public void printNode(String n) {
2890 System.out.println("Node Vaule: " +n);
2893 public void insideEncryption() {
2894 insideEncryption = true;
2898 //****************************************************************
2899 //* Insert a table row
2900 //****************************************************************
2901 public void insertTableRow() {
2903 String js = new String( "function insertTableRow() {"
2904 +" var selObj = window.getSelection();"
2905 +" var selRange = selObj.getRangeAt(0);"
2906 +" var workingNode = window.getSelection().anchorNode.parentNode;"
2907 +" var cellCount = 0;"
2908 +" while(workingNode != null) { "
2909 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
2910 +" row = document.createElement('TR');"
2911 +" var nodes = workingNode.getElementsByTagName('td');"
2912 +" for (j=0; j<nodes.length; j=j+1) {"
2913 +" cell = document.createElement('TD');"
2914 +" cell.innerHTML=' ';"
2915 +" row.appendChild(cell);"
2917 +" workingNode.parentNode.insertBefore(row,workingNode.nextSibling);"
2920 +" workingNode = workingNode.parentNode;"
2922 +"} insertTableRow();");
2923 browser.page().mainFrame().evaluateJavaScript(js);
2927 public void insertTableColumn() {
2928 String js = new String( "function insertTableColumn() {"
2929 +" var selObj = window.getSelection();"
2930 +" var selRange = selObj.getRangeAt(0);"
2931 +" var workingNode = window.getSelection().anchorNode.parentNode;"
2932 +" var current = 0;"
2933 +" while (workingNode.nodeName.toLowerCase() != 'table' && workingNode != null) {"
2934 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
2935 +" var td = workingNode;"
2936 +" while (td.previousSibling != null) { "
2937 +" current = current+1; td = td.previousSibling;"
2940 +" workingNode = workingNode.parentNode; "
2942 +" if (workingNode == null) return;"
2943 +" for (var i=0; i<workingNode.rows.length; i++) { "
2944 +" var cell = workingNode.rows[i].insertCell(current+1); "
2945 +" cell.innerHTML = ' '; "
2947 +"} insertTableColumn();");
2948 browser.page().mainFrame().evaluateJavaScript(js);
2952 //****************************************************************
2953 //* Delete a table row
2954 //****************************************************************
2955 public void deleteTableRow() {
2957 String js = new String( "function deleteTableRow() {"
2958 +" var selObj = window.getSelection();"
2959 +" var selRange = selObj.getRangeAt(0);"
2960 +" var workingNode = window.getSelection().anchorNode.parentNode;"
2961 +" var cellCount = 0;"
2962 +" while(workingNode != null) { "
2963 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
2964 +" workingNode.parentNode.removeChild(workingNode);"
2967 +" workingNode = workingNode.parentNode;"
2969 +"} deleteTableRow();");
2970 browser.page().mainFrame().evaluateJavaScript(js);
2974 public void deleteTableColumn() {
2975 String js = new String( "function deleteTableColumn() {"
2976 +" var selObj = window.getSelection();"
2977 +" var selRange = selObj.getRangeAt(0);"
2978 +" var workingNode = window.getSelection().anchorNode.parentNode;"
2979 +" var current = 0;"
2980 +" while (workingNode.nodeName.toLowerCase() != 'table' && workingNode != null) {"
2981 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
2982 +" var td = workingNode;"
2983 +" while (td.previousSibling != null) { "
2984 +" current = current+1; td = td.previousSibling;"
2987 +" workingNode = workingNode.parentNode; "
2989 +" if (workingNode == null) return;"
2990 +" for (var i=0; i<workingNode.rows.length; i++) { "
2991 +" workingNode.rows[i].deleteCell(current); "
2993 +"} deleteTableColumn();");
2994 browser.page().mainFrame().evaluateJavaScript(js);
2999 public void setInsideTable() {
3000 browser.insertTableRowAction.setEnabled(true);
3001 browser.insertTableColumnAction.setEnabled(true);
3002 browser.deleteTableRowAction.setEnabled(true);
3003 browser.deleteTableColumnAction.setEnabled(true);
3004 browser.insertTableAction.setEnabled(false);
3005 browser.encryptAction.setEnabled(false);
3009 public void setInsideLink(String link) {
3010 browser.insertLinkAction.setText(tr("Edit Hyperlink"));
3011 currentHyperlink = link;
3012 insertHyperlink = false;
3015 public void italicActive() {
3016 italicButton.setDown(true);
3018 public void boldActive() {
3019 boldButton.setDown(true);
3021 public void underlineActive() {
3022 underlineButton.setDown(true);
3024 public void forceTextPaste() {
3025 forceTextPaste = true;
3027 public void imageContextMenu(String f) {
3028 browser.downloadImage.setEnabled(true);
3029 browser.rotateImageRight.setEnabled(true);
3030 browser.rotateImageLeft.setEnabled(true);
3031 browser.openAction.setEnabled(true);
3034 public void rotateImageRight() {
3035 QWebSettings.setMaximumPagesInCache(0);
3036 QWebSettings.setObjectCacheCapacities(0, 0, 0);
3037 QImage image = new QImage(selectedFile);
3038 QMatrix matrix = new QMatrix();
3039 matrix.rotate( 90.0 );
3040 image = image.transformed(matrix);
3041 image.save(selectedFile);
3042 QWebSettings.setMaximumPagesInCache(0);
3043 QWebSettings.setObjectCacheCapacities(0, 0, 0);
3044 browser.setHtml(browser.page().mainFrame().toHtml());
3047 resourceSignal.contentChanged.emit(selectedFile);
3050 public void rotateImageLeft() {
3051 QImage image = new QImage(selectedFile);
3052 QMatrix matrix = new QMatrix();
3053 matrix.rotate( -90.0 );
3054 image = image.transformed(matrix);
3055 image.save(selectedFile);
3056 browser.setHtml(browser.page().mainFrame().toHtml());
3059 resourceSignal.contentChanged.emit(selectedFile);
3061 public void resourceContextMenu(String f) {
3062 browser.downloadAttachment.setEnabled(true);
3063 browser.openAction.setEnabled(true);
3066 public void latexContextMenu(String f) {
3067 browser.downloadImage.setEnabled(true);
3068 browser.rotateImageRight.setEnabled(true);
3069 browser.rotateImageLeft.setEnabled(true);
3070 browser.openAction.setEnabled(true);
3074 //****************************************************************
3075 //* Apply CSS style to specified word
3076 //****************************************************************
3077 /* public void applyStyleToWords(String word, String style) {
3078 QFile script = new QFile("D:\\NeverNote\\js\\hilight1.js");
3079 script.open(OpenModeFlag.ReadOnly);
3080 String s = script.readAll().toString();
3081 String js = new String(s +" findit('"+word+"', '"+style+"');");
3082 browser.page().mainFrame().evaluateJavaScript(js);
3083 System.out.println(getContent());
3086 //****************************************************************
3087 //* Someone tried to paste a resource between notes, so we need *
3088 //* to do some special handling. *
3089 //****************************************************************
3090 private String fixInternotePaste(String text) {
3091 logger.log(logger.EXTREME, "Fixing internote paste");
3092 String returnValue = fixInternotePasteSearch(text, "<img", "src=\"");
3093 return fixInternotePasteSearch(returnValue, "<a", "href=\"nnres://");
3095 private String fixInternotePasteSearch(String text, String type, String locTag) {
3097 // First, let's fix the images.
3098 int startPos = text.indexOf(type);
3100 for (; startPos>=0;) {
3101 endPos = text.indexOf(">", startPos+1);
3102 String segment = text.substring(startPos, endPos);
3103 if (segment.indexOf("en-tag") > -1) {
3104 String newSegment = segment;
3106 int guidStartPos = segment.indexOf("guid=\"");
3107 int guidEndPos = segment.indexOf("\"", guidStartPos+7);
3108 String guid = segment.substring(guidStartPos+6,guidEndPos);
3110 int mimeStartPos = segment.indexOf("type");
3111 int mimeEndPos = segment.indexOf("\"", mimeStartPos+7);
3112 String mime = segment.substring(mimeStartPos+6,mimeEndPos);
3114 int srcStartPos = segment.indexOf("src");
3115 int srcEndPos = segment.indexOf("\"", srcStartPos+6);
3116 String src = segment.substring(srcStartPos+5,srcEndPos);
3118 Calendar currentTime = new GregorianCalendar();
3119 Long l = new Long(currentTime.getTimeInMillis());
3121 while (l==prevTime) {
3122 currentTime = new GregorianCalendar();
3123 l= new Long(currentTime.getTimeInMillis());
3126 Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
3127 // if r==null, then the image doesn't exist (it was probably cut out of another note, so
3128 // we need to recereate it
3130 r = createResource(src, 1, mime, false);
3134 String randint = new String(Long.toString(l));
3135 String extension = null;
3136 if (r.getMime()!= null) {
3137 extension = r.getMime().toLowerCase();
3138 if (extension.indexOf("/")>-1)
3139 extension = extension.substring(extension.indexOf("/")+1);
3141 String newFile = randint;
3142 if (r.getAttributes().getFileName() != null && r.getAttributes().getFileName() != "")
3143 if (!locTag.startsWith("src"))
3144 newFile = newFile+Global.attachmentNameDelimeter+r.getAttributes().getFileName();
3145 r.setNoteGuid(currentNote.getGuid());
3148 conn.getNoteTable().noteResourceTable.saveNoteResource(r, true);
3149 QFile f = new QFile(Global.getFileManager().getResDirPath(newFile));
3150 QByteArray bin = new QByteArray(r.getData().getBody());
3151 f.open(QFile.OpenModeFlag.WriteOnly);
3154 newSegment = newSegment.replace("guid=\""+guid, "guid=\""+randint);
3155 currentNote.getResources().add(r);
3157 int startSrcPos = newSegment.indexOf(locTag);
3158 int endSrcPos = newSegment.indexOf("\"",startSrcPos+locTag.length()+1);
3160 if (locTag.startsWith("src")) {
3161 source = newSegment.substring(startSrcPos+locTag.length(),endSrcPos);
3162 newSegment = newSegment.replace(source,
3163 FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath(newFile)));
3165 source = newSegment.substring(startSrcPos+locTag.length(),endSrcPos);
3166 newSegment = newSegment.replace(source, newFile);
3169 text = text.substring(0,startPos) + newSegment + text.substring(endPos);
3171 startPos = text.indexOf(type, startPos+1);
3177 public void nextPage(String file) {
3178 logger.log(logger.EXTREME, "Starting nextPage()");
3181 if (previewPageList.containsKey(file))
3182 pageNumber = previewPageList.get(file)+1;
3185 previewPageList.remove(file);
3186 previewPageList.put(file, pageNumber);
3187 PDFPreview pdfPreview = new PDFPreview();
3188 boolean goodPreview = pdfPreview.setupPreview(file, "pdf", pageNumber);
3191 // String html = getContent();
3192 QWebSettings.setMaximumPagesInCache(0);
3193 QWebSettings.setObjectCacheCapacities(0, 0, 0);
3194 // browser.setContent(new QByteArray());
3195 browser.setHtml(browser.page().mainFrame().toHtml());
3197 // browser.setContent(new QByteArray(html));
3198 // browser.triggerPageAction(WebAction.Reload);
3199 // pdfMouseOver(selectedFile);
3203 public void previousPage(String file) {
3204 logger.log(logger.EXTREME, "Starting previousPage()");
3207 if (previewPageList.containsKey(file))
3208 pageNumber = previewPageList.get(file)-1;
3211 previewPageList.remove(file);
3212 previewPageList.put(file, pageNumber);
3213 PDFPreview pdfPreview = new PDFPreview();
3214 boolean goodPreview = pdfPreview.setupPreview(file, "pdf", pageNumber);
3217 // String html = getContent();
3218 QWebSettings.setMaximumPagesInCache(0);
3219 QWebSettings.setObjectCacheCapacities(0, 0, 0);
3220 browser.setHtml(browser.page().mainFrame().toHtml());
3222 // browser.setContent(new QByteArray(html));
3223 // browser.triggerPageAction(WebAction.Reload);
3227 /* public void pdfMouseOver(String name) {
3229 if (previewPageList.containsKey(selectedFile))
3230 pageNumber = previewPageList.get(selectedFile)+1;
3234 if (pageNumber <= 1)
3235 browser.previousPageAction.setEnabled(false);
3237 browser.previousPageAction.setEnabled(true);
3239 PDFPreview pdf = new PDFPreview();
3240 int totalPages = pdf.getPageCount(name);
3241 if (previewPageList.containsKey(selectedFile))
3242 pageNumber = previewPageList.get(selectedFile)+1;
3245 if (totalPages > pageNumber)
3246 browser.nextPageAction.setEnabled(true);
3248 browser.nextPageAction.setEnabled(false);
3252 public void pdfMouseOut() {
3253 // browser.nextPageAction.setVisible(false);
3254 // browser.previousPageAction.setVisible(false);
3258 @SuppressWarnings("unused")
3259 private void toggleUndoVisible(Boolean toggle) {
3260 undoAction.setVisible(toggle);
3261 Global.saveEditorButtonsVisible("undo", toggle);
3263 @SuppressWarnings("unused")
3264 private void toggleRedoVisible(Boolean toggle) {
3265 redoAction.setVisible(toggle);
3266 Global.saveEditorButtonsVisible("redo", toggle);
3268 @SuppressWarnings("unused")
3269 private void toggleCutVisible(Boolean toggle) {
3270 cutAction.setVisible(toggle);
3271 Global.saveEditorButtonsVisible("cut", toggle);
3273 @SuppressWarnings("unused")
3274 private void toggleCopyVisible(Boolean toggle) {
3275 copyAction.setVisible(toggle);
3276 Global.saveEditorButtonsVisible("copy", toggle);
3278 @SuppressWarnings("unused")
3279 private void togglePasteVisible(Boolean toggle) {
3280 pasteAction.setVisible(toggle);
3281 Global.saveEditorButtonsVisible("paste", toggle);
3283 @SuppressWarnings("unused")
3284 private void toggleBoldVisible(Boolean toggle) {
3285 boldAction.setVisible(toggle);
3286 Global.saveEditorButtonsVisible("bold", toggle);
3288 @SuppressWarnings("unused")
3289 private void toggleItalicVisible(Boolean toggle) {
3290 italicAction.setVisible(toggle);
3291 Global.saveEditorButtonsVisible("italic", toggle);
3293 @SuppressWarnings("unused")
3294 private void toggleUnderlineVisible(Boolean toggle) {
3295 underlineAction.setVisible(toggle);
3296 Global.saveEditorButtonsVisible("underline", toggle);
3298 @SuppressWarnings("unused")
3299 private void toggleStrikethroughVisible(Boolean toggle) {
3300 strikethroughAction.setVisible(toggle);
3301 Global.saveEditorButtonsVisible("strikethrough", toggle);
3303 @SuppressWarnings("unused")
3304 private void toggleLeftAlignVisible(Boolean toggle) {
3305 leftAlignAction.setVisible(toggle);
3306 Global.saveEditorButtonsVisible("alignLeft", toggle);
3308 @SuppressWarnings("unused")
3309 private void toggleRightAlignVisible(Boolean toggle) {
3310 rightAlignAction.setVisible(toggle);
3311 Global.saveEditorButtonsVisible("alignRight", toggle);
3313 @SuppressWarnings("unused")
3314 private void toggleCenterAlignVisible(Boolean toggle) {
3315 centerAlignAction.setVisible(toggle);
3316 Global.saveEditorButtonsVisible("alignCenter", toggle);
3318 @SuppressWarnings("unused")
3319 private void toggleHLineVisible(Boolean toggle) {
3320 hlineAction.setVisible(toggle);
3321 Global.saveEditorButtonsVisible("hline", toggle);
3323 @SuppressWarnings("unused")
3324 private void toggleIndentVisible(Boolean toggle) {
3325 indentAction.setVisible(toggle);
3326 Global.saveEditorButtonsVisible("indent", toggle);
3328 @SuppressWarnings("unused")
3329 private void toggleTodoVisible(Boolean toggle) {
3330 todoAction.setVisible(toggle);
3331 Global.saveEditorButtonsVisible("todo", toggle);
3333 @SuppressWarnings("unused")
3334 private void toggleOutdentVisible(Boolean toggle) {
3335 outdentAction.setVisible(toggle);
3336 Global.saveEditorButtonsVisible("outdent", toggle);
3338 @SuppressWarnings("unused")
3339 private void toggleBulletListVisible(Boolean toggle) {
3340 bulletListAction.setVisible(toggle);
3341 Global.saveEditorButtonsVisible("bulletList", toggle);
3343 @SuppressWarnings("unused")
3344 private void toggleNumberListVisible(Boolean toggle) {
3345 numberListAction.setVisible(toggle);
3346 Global.saveEditorButtonsVisible("numberList", toggle);
3348 @SuppressWarnings("unused")
3349 private void toggleFontListVisible(Boolean toggle) {
3350 fontListAction.setVisible(toggle);
3351 Global.saveEditorButtonsVisible("font", toggle);
3353 @SuppressWarnings("unused")
3354 private void toggleFontColorVisible(Boolean toggle) {
3355 fontColorAction.setVisible(toggle);
3356 Global.saveEditorButtonsVisible("fontColor", toggle);
3358 @SuppressWarnings("unused")
3359 private void toggleFontSizeVisible(Boolean toggle) {
3360 fontSizeAction.setVisible(toggle);
3361 Global.saveEditorButtonsVisible("fontSize", toggle);
3363 @SuppressWarnings("unused")
3364 private void toggleFontHilightVisible(Boolean toggle) {
3365 fontHilightAction.setVisible(toggle);
3366 Global.saveEditorButtonsVisible("fontHilight", toggle);
3368 @SuppressWarnings("unused")
3369 private void toggleSpellCheckVisible(Boolean toggle) {
3370 spellCheckAction.setVisible(toggle);
3371 Global.saveEditorButtonsVisible("spellCheck", toggle);
3375 private void setupDictionary() {
3376 File wordList = new File(Global.getFileManager().getSpellDirPath()+Locale.getDefault()+".dic");
3378 dictionary = new SpellDictionaryHashMap(wordList);
3379 spellChecker = new SpellChecker(dictionary);
3382 userWordList = new File(Global.getFileManager().getSpellDirPathUser()+"user.dic");
3384 // Get the local user spell dictionary
3386 userDictionary = new SpellDictionaryHashMap(userWordList);
3387 } catch (FileNotFoundException e) {
3388 userWordList.createNewFile();
3389 userDictionary = new SpellDictionaryHashMap(userWordList);
3390 } catch (IOException e) {
3391 userWordList.createNewFile();
3392 userDictionary = new SpellDictionaryHashMap(userWordList);
3395 spellListener = new SuggestionListener(this, spellChecker);
3397 // Add the user dictionary
3398 spellChecker.addSpellCheckListener(spellListener);
3399 spellChecker.setUserDictionary(userDictionary);
3401 } catch (FileNotFoundException e) {
3402 QMessageBox.critical(this, tr("Spell Check Error"),
3403 tr("Dictionary ")+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+
3404 tr(".dic was not found."));
3405 } catch (IOException e) {
3406 QMessageBox.critical(this, tr("Spell Check Error"),
3407 tr("Dictionary ")+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+
3408 tr(".dic is invalid."));
3413 // Invoke spell checker dialog
3414 @SuppressWarnings("unused")
3415 private void spellCheckClicked() {
3417 if (spellChecker == null) {
3421 // Read user settings
3422 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREDIGITWORDS,
3423 Global.getSpellSetting(Configuration.SPELL_IGNOREDIGITWORDS));
3424 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREINTERNETADDRESSES,
3425 Global.getSpellSetting(Configuration.SPELL_IGNOREINTERNETADDRESSES));
3426 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREMIXEDCASE,
3427 Global.getSpellSetting(Configuration.SPELL_IGNOREMIXEDCASE));
3428 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREUPPERCASE,
3429 Global.getSpellSetting(Configuration.SPELL_IGNOREUPPERCASE));
3430 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNORESENTENCECAPITALIZATION,
3431 Global.getSpellSetting(Configuration.SPELL_IGNORESENTENCECAPITALIZATION));
3433 spellListener.abortSpellCheck = false;
3434 spellListener.errorsFound = false;
3435 String content = getBrowser().page().mainFrame().toPlainText();
3436 StringWordTokenizer tokenizer = new StringWordTokenizer(content);
3437 if (!tokenizer.hasMoreWords())
3439 getBrowser().page().action(WebAction.MoveToStartOfDocument);
3441 getBrowser().setFocus();
3444 // Move to the start of page
3445 KeyboardModifiers ctrl = new KeyboardModifiers(KeyboardModifier.ControlModifier.value());
3446 QKeyEvent home = new QKeyEvent(Type.KeyPress, Key.Key_Home.value(), ctrl);
3447 browser.keyPressEvent(home);
3448 getBrowser().setFocus();
3450 tokenizer = new StringWordTokenizer(content);
3453 while(tokenizer.hasMoreWords()) {
3454 word = tokenizer.nextWord();
3455 found = getBrowser().page().findText(word);
3456 if (found && !spellListener.abortSpellCheck) {
3457 spellChecker.checkSpelling(new StringWordTokenizer(word));
3458 getBrowser().setFocus();
3462 // Go to the end of the document & finish up.
3463 home = new QKeyEvent(Type.KeyPress, Key.Key_End.value(), ctrl);
3464 browser.keyPressEvent(home);
3465 if (!spellListener.errorsFound)
3466 QMessageBox.information(this, tr("Spell Check Complete"),
3467 tr("No Errors Found"));
3472 @SuppressWarnings("unused")
3473 private void sourceEdited() {
3474 QTextCodec codec = QTextCodec.codecForLocale();
3475 codec = QTextCodec.codecForName("UTF-8");
3476 String content = codec.fromUnicode(sourceEdit.toHtml()).toString();
3477 content = StringEscapeUtils.unescapeHtml4(removeTags(content));
3478 QByteArray data = new QByteArray(sourceEditHeader+content+"</body></html>");
3479 getBrowser().setContent(data);
3481 if (currentNote != null && sourceEdit != null)
3482 noteSignal.noteChanged.emit(currentNote.getGuid(), sourceEdit.toPlainText());
3485 private void setSource() {
3486 String text = getContent();
3487 sourceEdit.blockSignals(true);
3488 int body = text.indexOf("<body");
3490 body = text.indexOf(">",body);
3492 sourceEditHeader =text.substring(0, body+1);
3493 text = text.substring(body+1);
3496 text = text.replace("</body></html>", "");
3497 sourceEdit.setPlainText(text);
3498 sourceEdit.setReadOnly(!getBrowser().page().isContentEditable());
3499 //syntaxHighlighter.rehighlight();
3500 sourceEdit.blockSignals(false);
3503 // show/hide view source window
3504 public void showSource(boolean value) {
3506 sourceEdit.setVisible(value);
3510 private String removeTags(String text) {
3511 StringBuffer buffer = new StringBuffer(text);
3512 boolean inTag = false;
3513 int bodyPosition = text.indexOf("<body");
3514 for (int i=buffer.length()-1; i>=0; i--) {
3515 if (buffer.charAt(i) == '>')
3517 if (buffer.charAt(i) == '<')
3519 if (inTag || buffer.charAt(i) == '<' || i<bodyPosition)
3520 buffer.deleteCharAt(i);
3523 return buffer.toString();