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.dialog.EnCryptDialog;
128 import cx.fbn.nevernote.dialog.EnDecryptDialog;
129 import cx.fbn.nevernote.dialog.GeoDialog;
130 import cx.fbn.nevernote.dialog.InsertLatexImage;
131 import cx.fbn.nevernote.dialog.InsertLinkDialog;
132 import cx.fbn.nevernote.dialog.NoteQuickLinkDialog;
133 import cx.fbn.nevernote.dialog.SpellCheck;
134 import cx.fbn.nevernote.dialog.TableDialog;
135 import cx.fbn.nevernote.dialog.TagAssign;
136 import cx.fbn.nevernote.evernote.EnCrypt;
137 import cx.fbn.nevernote.filters.FilterEditorTags;
138 import cx.fbn.nevernote.neighbornote.ClipBoardObserver;
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.
272 private final ClipBoardObserver cbObserver;
274 public static class SuggestionListener implements SpellCheckListener {
275 public boolean abortSpellCheck = false;
276 public boolean errorsFound = false;
277 private final SpellCheck spellCheckDialog;
280 private final BrowserWindow parent;
281 public SuggestionListener(BrowserWindow parent, SpellChecker checker) {
282 this.parent = parent;
283 spellCheckDialog = new SpellCheck(checker);
285 public void spellingError(SpellCheckEvent event) {
287 spellCheckDialog.setWord(event.getInvalidWord());
289 @SuppressWarnings("unchecked")
290 List<Word> suggestions = event.getSuggestions();
291 spellCheckDialog.clearSuggestions();
292 if (!suggestions.isEmpty()) {
293 // spellCheckDialog.setCurrentSuggestion(suggestions.get(0).getWord());
294 for (int i=0; i<suggestions.size(); i++) {
295 spellCheckDialog.addSuggestion(suggestions.get(i).getWord());
297 spellCheckDialog.setSelectedSuggestion(0);
299 spellCheckDialog.exec();
300 if (spellCheckDialog.cancelPressed()) {
301 abortSpellCheck = true;
305 if (spellCheckDialog.replacePressed()) {
306 QClipboard clipboard = QApplication.clipboard();
307 clipboard.setText(spellCheckDialog.getReplacementWord());
308 parent.pasteClicked();
315 // ICHANGED 引数にcbObserverを追加
316 public BrowserWindow(DatabaseConnection c, ClipBoardObserver cbObserver) {
317 logger = new ApplicationLogger("browser.log");
318 logger.log(logger.HIGH, "Setting up browser");
319 iconPath = new String("classpath:cx/fbn/nevernote/icons/");
320 forceTextPaste = false;
321 insertHyperlink = true;
323 insideEncryption = false;
325 fileWatcher = new QFileSystemWatcher();
326 // fileWatcher.fileChanged.connect(this, "fileChanged(String)");
327 noteSignal = new NoteSignal();
328 titleLabel = new QLineEdit();
329 evernoteLinkClicked = new Signal2<String,String>();
330 titleLabel.setMaxLength(Constants.EDAM_NOTE_TITLE_LEN_MAX);
331 urlText = new QLineEdit();
332 authorText = new QLineEdit();
333 geoBox = new QComboBox();
334 urlLabel = new QPushButton();
335 urlLabel.clicked.connect(this, "sourceUrlClicked()");
336 authorLabel = new QLabel();
340 this.cbObserver = cbObserver;
342 focusLost = new Signal0();
344 tagEdit = new TagLineEdit(allTags);
345 tagLabel = new QLabel(tr("Tags:"));
346 tagEdit.focusLost.connect(this, "modifyTagsTyping()");
348 createdCalendarWidget = new QCalendarWidget();
349 createdDate = new QDateEdit();
350 createdDate.setDisplayFormat(Global.getDateFormat());
351 createdDate.setCalendarPopup(true);
352 createdDate.setCalendarWidget(createdCalendarWidget);
353 createdTime = new QTimeEdit();
354 createdDate.dateChanged.connect(this, "createdChanged()");
355 createdTime.timeChanged.connect(this, "createdChanged()");
357 alteredCalendarWidget = new QCalendarWidget();
358 alteredDate = new QDateEdit();
359 alteredDate.setDisplayFormat(Global.getDateFormat());
360 alteredDate.setCalendarPopup(true);
361 alteredDate.setCalendarWidget(alteredCalendarWidget);
362 alteredTime = new QTimeEdit();
363 alteredLabel = new QLabel(tr("Altered:"));
364 alteredDate.dateChanged.connect(this, "alteredChanged()");
365 alteredTime.timeChanged.connect(this, "alteredChanged()");
367 subjectCalendarWidget = new QCalendarWidget();
368 subjectDate = new QDateEdit();
369 subjectDate.setDisplayFormat(Global.getDateFormat());
370 subjectDate.setCalendarPopup(true);
371 subjectDate.setCalendarWidget(subjectCalendarWidget);
372 subjectTime = new QTimeEdit();
373 subjectLabel = new QLabel(tr("Subject Date:"));
374 subjectDate.dateChanged.connect(this, "subjectDateTimeChanged()");
375 subjectTime.timeChanged.connect(this, "subjectDateTimeChanged()");
376 authorText.textChanged.connect(this, "authorChanged()");
377 urlText.textChanged.connect(this, "sourceUrlChanged()");
379 notebookBox = new QComboBox();
380 notebookLabel = new QLabel(tr("Notebook"));
381 createdLabel = new QLabel(tr("Created:"));
382 // selectedText = new String();
384 urlLabel.setVisible(false);
385 urlText.setVisible(false);
386 authorLabel.setVisible(false);
388 geoBox.setVisible(false);
389 geoBox.addItem(new QIcon(iconPath+"globe.png"), "");
390 geoBox.addItem(new String(tr("Set")));
391 geoBox.addItem(new String(tr("Clear")));
392 geoBox.addItem(new String(tr("View On Map")));
393 geoBox.activated.connect(this, "geoBoxChanged()");
395 authorText.setVisible(false);
396 createdDate.setVisible(false);
397 alteredLabel.setVisible(false);
398 //notebookBox.setVisible(false);
399 notebookLabel.setVisible(false);
400 createdLabel.setVisible(false);
401 createdTime.setVisible(false);
402 alteredDate.setVisible(false);
403 alteredTime.setVisible(false);
404 subjectLabel.setVisible(false);
405 subjectDate.setVisible(false);
406 subjectTime.setVisible(false);
408 buttonsVisible = true;
409 setAcceptDrops(true);
411 browser = new ContentView(this);
413 browser.page().setLinkDelegationPolicy(
414 QWebPage.LinkDelegationPolicy.DelegateAllLinks);
415 browser.linkClicked.connect(this, "linkClicked(QUrl)");
416 currentHyperlink = "";
418 //Setup the source editor
419 sourceEdit = new QTextEdit(this);
420 sourceEdit.setVisible(false);
421 sourceEdit.setTabChangesFocus(true);
422 sourceEdit.setLineWrapMode(LineWrapMode.NoWrap);
423 QFont font = new QFont();
424 font.setFamily("Courier");
425 font.setFixedPitch(true);
426 font.setPointSize(10);
427 sourceEdit.setFont(font);
428 syntaxHighlighter = new Highlighter(sourceEdit.document());
429 sourceEdit.textChanged.connect(this, "sourceEdited()");
431 QVBoxLayout v = new QVBoxLayout();
432 QFormLayout notebookLayout = new QFormLayout();
433 QGridLayout dateLayout = new QGridLayout();
434 titleLabel.setReadOnly(false);
435 titleLabel.editingFinished.connect(this, "titleEdited()");
436 browser.page().contentsChanged.connect(this, "contentChanged()");
437 browser.page().selectionChanged.connect(this, "selectionChanged()");
438 browser.page().mainFrame().javaScriptWindowObjectCleared.connect(this,
439 "exposeToJavascript()");
441 notebookBox.activated.connect(this, "notebookChanged()");
442 resourceSignal = new NoteResourceSignal();
444 QHBoxLayout tagLayout = new QHBoxLayout();
445 v.addWidget(titleLabel, 0);
446 notebookLayout.addRow(notebookLabel, notebookBox);
447 tagLayout.addLayout(notebookLayout, 0);
448 tagLayout.stretch(4);
449 tagLayout.addWidget(tagLabel, 0);
450 tagLayout.addWidget(tagEdit, 1);
451 v.addLayout(tagLayout);
453 QHBoxLayout urlLayout = new QHBoxLayout();
454 urlLayout.addWidget(urlLabel, 0);
455 urlLayout.addWidget(urlText, 0);
456 v.addLayout(urlLayout);
458 QHBoxLayout authorLayout = new QHBoxLayout();
459 authorLayout.addWidget(authorLabel, 0);
460 authorLayout.addWidget(authorText, 0);
461 authorLayout.addWidget(geoBox);
462 v.addLayout(authorLayout);
464 dateLayout.addWidget(createdLabel, 0, 0);
465 dateLayout.addWidget(createdDate, 0, 1);
466 dateLayout.addWidget(createdTime, 0, 2);
467 dateLayout.setColumnStretch(9, 100);
468 dateLayout.addWidget(alteredLabel, 0, 3);
469 dateLayout.addWidget(alteredDate, 0, 4);
470 dateLayout.addWidget(alteredTime, 0, 5);
471 dateLayout.addWidget(subjectLabel, 0, 6);
472 dateLayout.addWidget(subjectDate, 0, 7);
473 dateLayout.addWidget(subjectTime, 0, 8);
474 v.addLayout(dateLayout, 0);
476 undoButton = newEditorButton("undo", tr("Undo Change"));
477 redoButton = newEditorButton("redo", tr("Redo Change"));
478 cutButton = newEditorButton("cut", tr("Cut"));
479 copyButton = newEditorButton("copy", tr("Copy"));
480 pasteButton = newEditorButton("paste", tr("Paste"));
481 boldButton = newEditorButton("bold", tr("Bold"));
482 underlineButton = newEditorButton("underline", tr("Underline"));
483 italicButton = newEditorButton("italic", tr("Italic"));
485 rightAlignButton = newEditorButton("justifyRight", tr("Right Align"));
486 leftAlignButton = newEditorButton("justifyLeft", tr("Left Align"));
487 centerAlignButton = newEditorButton("justifyCenter", tr("Center Align"));
489 strikethroughButton = newEditorButton("strikethrough", tr("Strikethrough"));
490 hlineButton = newEditorButton("hline", tr("Insert Horizontal Line"));
491 indentButton = newEditorButton("indent", tr("Shift Right"));
492 outdentButton = newEditorButton("outdent", tr("Shift Left"));
493 bulletListButton = newEditorButton("bulletList", tr("Bullet List"));
494 numberListButton = newEditorButton("numberList", tr("Number List"));
495 spellCheckButton = newEditorButton("spellCheck", tr("Spell Check"));
496 todoButton = newEditorButton("todo", tr("To-do"));
499 buttonLayout = new EditorButtonBar();
500 v.addWidget(buttonLayout);
502 undoAction = buttonLayout.addWidget(undoButton);
503 buttonLayout.toggleUndoVisible.triggered.connect(this, "toggleUndoVisible(Boolean)");
504 redoAction = buttonLayout.addWidget(redoButton);
505 buttonLayout.toggleRedoVisible.triggered.connect(this, "toggleRedoVisible(Boolean)");
507 buttonLayout.addWidget(newSeparator());
508 cutAction = buttonLayout.addWidget(cutButton);
509 buttonLayout.toggleCutVisible.triggered.connect(this, "toggleCutVisible(Boolean)");
510 copyAction = buttonLayout.addWidget(copyButton);
511 buttonLayout.toggleCopyVisible.triggered.connect(this, "toggleCopyVisible(Boolean)");
512 pasteAction = buttonLayout.addWidget(pasteButton);
513 buttonLayout.togglePasteVisible.triggered.connect(this, "togglePasteVisible(Boolean)");
515 buttonLayout.addWidget(newSeparator());
516 boldAction = buttonLayout.addWidget(boldButton);
517 buttonLayout.toggleBoldVisible.triggered.connect(this, "toggleBoldVisible(Boolean)");
518 italicAction = buttonLayout.addWidget(italicButton);
519 buttonLayout.toggleItalicVisible.triggered.connect(this, "toggleItalicVisible(Boolean)");
520 underlineAction = buttonLayout.addWidget(underlineButton);
521 buttonLayout.toggleUnderlineVisible.triggered.connect(this, "toggleUnderlineVisible(Boolean)");
522 strikethroughAction = buttonLayout.addWidget(strikethroughButton);
523 buttonLayout.toggleStrikethroughVisible.triggered.connect(this, "toggleStrikethroughVisible(Boolean)");
526 buttonLayout.addWidget(newSeparator());
527 leftAlignAction = buttonLayout.addWidget(leftAlignButton);
528 buttonLayout.toggleLeftAlignVisible.triggered.connect(this, "toggleLeftAlignVisible(Boolean)");
529 centerAlignAction = buttonLayout.addWidget(centerAlignButton);
530 buttonLayout.toggleCenterAlignVisible.triggered.connect(this, "toggleCenterAlignVisible(Boolean)");
531 rightAlignAction = buttonLayout.addWidget(rightAlignButton);
532 buttonLayout.toggleRightAlignVisible.triggered.connect(this, "toggleRightAlignVisible(Boolean)");
534 buttonLayout.addWidget(newSeparator());
535 hlineAction = buttonLayout.addWidget(hlineButton);
536 buttonLayout.toggleHLineVisible.triggered.connect(this, "toggleHLineVisible(Boolean)");
538 indentAction = buttonLayout.addWidget(indentButton);
539 buttonLayout.toggleIndentVisible.triggered.connect(this, "toggleIndentVisible(Boolean)");
540 outdentAction = buttonLayout.addWidget(outdentButton);
541 buttonLayout.toggleOutdentVisible.triggered.connect(this, "toggleOutdentVisible(Boolean)");
542 bulletListAction = buttonLayout.addWidget(bulletListButton);
543 buttonLayout.toggleBulletListVisible.triggered.connect(this, "toggleBulletListVisible(Boolean)");
544 numberListAction = buttonLayout.addWidget(numberListButton);
545 buttonLayout.toggleNumberListVisible.triggered.connect(this, "toggleNumberListVisible(Boolean)");
547 // Setup the font & font size combo boxes
548 buttonLayout.addWidget(newSeparator());
549 fontList = new QComboBox();
550 fontSize = new QComboBox();
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);
778 button.setIconSize(new QSize(16, 16));
780 button.setToolTip(toolTip);
781 button.clicked.connect(this, name + "Clicked()");
785 private QToolButton newToolButton(String name, String toolTip) {
786 QToolButton button = new QToolButton();
787 // QIcon icon = new QIcon(iconPath + name + ".gif");
788 QIcon icon = new QIcon(iconPath + name + ".png");
789 button.setIcon(icon);
791 button.setIconSize(new QSize(16, 16));
793 button.setToolTip(toolTip);
794 button.clicked.connect(this, name + "Clicked()");
799 private QLabel newSeparator() {
800 return new QLabel(" ");
803 // Set the title in the window
804 public void setTitle(String t) {
805 titleLabel.setText(t);
810 // Return the current text title
811 public String getTitle() {
812 return titleLabel.text();
815 // Set the tag name string
816 public void setTag(String t) {
819 tagEdit.tagCompleter.reset();
822 // Set the source URL
823 public void setUrl(String t) {
824 urlLabel.setText(tr("Source URL:\t"));
828 // The user want's to launch a web browser on the source of the URL
829 public void sourceUrlClicked() {
830 // Make sure we have a valid URL
831 if (urlText.text().trim().equals(""))
834 String url = urlText.text();
835 if (!url.toLowerCase().startsWith(tr("http://")))
836 url = tr("http://") +url;
838 if (!QDesktopServices.openUrl(new QUrl(url))) {
839 logger.log(logger.LOW, "Error opening file :" +url);
843 public void setAuthor(String t) {
844 authorLabel.setText(tr("Author:\t"));
845 authorText.setText(t);
848 // Set the creation date
849 public void setCreation(long date) {
850 QDateTime dt = new QDateTime();
851 dt.setTime_t((int) (date / 1000));
852 createdDate.setDateTime(dt);
853 createdTime.setDateTime(dt);
854 createdDate.setDisplayFormat(Global.getDateFormat());
855 createdTime.setDisplayFormat(Global.getTimeFormat());
858 // Set the creation date
859 public void setAltered(long date) {
860 QDateTime dt = new QDateTime();
861 dt.setTime_t((int) (date / 1000));
862 alteredDate.setDateTime(dt);
863 alteredTime.setDateTime(dt);
864 alteredDate.setDisplayFormat(Global.getDateFormat());
865 alteredTime.setDisplayFormat(Global.getTimeFormat());
868 // Set the subject date
869 public void setSubjectDate(long date) {
870 QDateTime dt = new QDateTime();
871 dt.setTime_t((int) (date / 1000));
872 subjectDate.setDateTime(dt);
873 subjectTime.setDateTime(dt);
874 subjectDate.setDisplayFormat(Global.getDateFormat());
875 subjectTime.setDisplayFormat(Global.getTimeFormat());
878 // Toggle the extended attribute information
879 public void toggleInformation() {
885 urlLabel.setVisible(extendedOn);
886 urlText.setVisible(extendedOn);
887 authorText.setVisible(extendedOn);
888 geoBox.setVisible(extendedOn);
889 authorLabel.setVisible(extendedOn);
890 createdDate.setVisible(extendedOn);
891 createdTime.setVisible(extendedOn);
892 createdLabel.setVisible(extendedOn);
893 alteredLabel.setVisible(extendedOn);
894 alteredDate.setVisible(extendedOn);
895 alteredTime.setVisible(extendedOn);
896 //notebookBox.setVisible(extendedOn);
897 notebookLabel.setVisible(extendedOn);
898 subjectLabel.setVisible(extendedOn);
899 subjectDate.setVisible(extendedOn);
900 subjectTime.setVisible(extendedOn);
903 public void hideButtons() {
905 undoButton.parentWidget().setVisible(false);
906 buttonsVisible = false;
910 // Is the extended view on?
911 public boolean isExtended() {
915 // Listener for when a link is clicked
916 @SuppressWarnings("unused")
917 private void openFile() {
918 logger.log(logger.EXTREME, "Starting openFile()");
919 File fileHandle = new File(selectedFile);
920 URI fileURL = fileHandle.toURI();
921 String localURL = fileURL.toString();
922 QUrl url = new QUrl(localURL);
923 QFile file = new QFile(selectedFile);
925 logger.log(logger.EXTREME, "Adding to fileWatcher:"+file.fileName());
926 fileWatcher.addPath(file.fileName());
928 if (!QDesktopServices.openUrl(url)) {
929 logger.log(logger.LOW, "Error opening file :" +url);
934 // Listener for when a link is clicked
935 @SuppressWarnings("unused")
936 private void linkClicked(QUrl url) {
937 logger.log(logger.EXTREME, "URL Clicked: " +url.toString());
938 if (url.toString().startsWith("latex:")) {
939 int position = url.toString().lastIndexOf(".");
940 String guid = url.toString().substring(0,position);
941 position = guid.lastIndexOf("/");
942 guid = guid.substring(position+1);
946 if (url.toString().startsWith("evernote:/view/")) {
947 StringTokenizer tokens = new StringTokenizer(url.toString().replace("evernote:/view/", ""), "/");
950 String sid = tokens.nextToken();
951 String lid = tokens.nextToken();
953 // Emit that we want to switch to a new note
954 evernoteLinkClicked.emit(sid, lid);
958 if (url.toString().startsWith("nnres://")) {
959 logger.log(logger.EXTREME, "URL is NN resource");
960 if (url.toString().endsWith("/vnd.evernote.ink")) {
961 logger.log(logger.EXTREME, "Unable to open ink note");
962 QMessageBox.information(this, tr("Unable Open"), tr("This is an ink note.\n"+
963 "Ink notes are not supported since Evernote has not\n published any specifications on them\n" +
964 "and I'm too lazy to figure them out by myself."));
967 String fullName = url.toString().substring(8);
968 int index = fullName.indexOf(".");
972 type = fullName.substring(index+1);
973 guid = fullName.substring(0,index);
975 index = guid.indexOf(Global.attachmentNameDelimeter);
977 guid = guid.substring(0,index);
979 List<Resource> resList = currentNote.getResources();
981 for (int i=0; i<resList.size(); i++) {
982 if (resList.get(i).getGuid().equals(guid)) {
983 res = resList.get(i);
988 String resGuid = Global.resourceMap.get(guid);
990 res = conn.getNoteTable().noteResourceTable.getNoteResource(resGuid, true);
994 if (res.getAttributes() != null &&
995 res.getAttributes().getFileName() != null &&
996 !res.getAttributes().getFileName().trim().equals(""))
997 fileName = res.getGuid()+Global.attachmentNameDelimeter+res.getAttributes().getFileName();
999 fileName = res.getGuid()+"."+type;
1000 QFile file = new QFile(Global.getFileManager().getResDirPath(fileName));
1001 QFile.OpenMode mode = new QFile.OpenMode();
1002 mode.set(QFile.OpenModeFlag.WriteOnly);
1003 boolean openResult = file.open(mode);
1004 logger.log(logger.EXTREME, "File opened:" +openResult);
1005 QDataStream out = new QDataStream(file);
1006 Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(res.getGuid(), true);
1007 QByteArray binData = new QByteArray(resBinary.getData().getBody());
1009 logger.log(logger.EXTREME, "Writing resource");
1010 out.writeBytes(binData.toByteArray());
1013 String whichOS = System.getProperty("os.name");
1014 if (whichOS.contains("Windows"))
1015 url.setUrl("file:///"+file.fileName());
1017 url.setUrl("file://"+file.fileName());
1018 // fileWatcher.removePath(file.fileName());
1019 logger.log(logger.EXTREME, "Adding file watcher " +file.fileName());
1020 fileWatcher.addPath(file.fileName());
1022 // If we can't open it, then prompt the user to save it.
1023 if (!QDesktopServices.openUrl(url)) {
1024 logger.log(logger.EXTREME, "We can't handle this. Where do we put it?");
1025 QFileDialog dialog = new QFileDialog();
1027 if (dialog.exec()!=0) {
1028 List<String> fileNames = dialog.selectedFiles(); //gets all selected filenames
1029 if (fileNames.size() == 0)
1031 String sf = fileNames.get(0);
1032 QFile saveFile = new QFile(sf);
1033 mode.set(QFile.OpenModeFlag.WriteOnly);
1034 saveFile.open(mode);
1035 QDataStream saveOut = new QDataStream(saveFile);
1036 saveOut.writeBytes(binData.toByteArray());
1044 logger.log(logger.EXTREME, "Launching URL");
1045 QDesktopServices.openUrl(url);
1048 // Listener for when BOLD is clicked
1049 @SuppressWarnings("unused")
1050 private void undoClicked() {
1051 browser.page().triggerAction(WebAction.Undo);
1055 // Listener for when BOLD is clicked
1056 @SuppressWarnings("unused")
1057 private void redoClicked() {
1058 browser.page().triggerAction(WebAction.Redo);
1062 // Listener for when BOLD is clicked
1063 @SuppressWarnings("unused")
1064 private void boldClicked() {
1065 browser.page().triggerAction(WebAction.ToggleBold);
1066 microFocusChanged();
1070 // Listener for when Italics is clicked
1071 @SuppressWarnings("unused")
1072 private void italicClicked() {
1073 browser.page().triggerAction(WebAction.ToggleItalic);
1074 microFocusChanged();
1078 // Listener for when UNDERLINE is clicked
1079 @SuppressWarnings("unused")
1080 private void underlineClicked() {
1081 browser.page().triggerAction(WebAction.ToggleUnderline);
1082 microFocusChanged();
1086 // Listener for when Strikethrough is clicked
1087 @SuppressWarnings("unused")
1088 private void strikethroughClicked() {
1089 browser.page().mainFrame().evaluateJavaScript(
1090 "document.execCommand('strikeThrough', false, '');");
1094 // Listener for when cut is clicked
1095 @SuppressWarnings("unused")
1096 private void cutClicked() {
1098 cbObserver.setCopySourceGuid(currentNote.getGuid(), browser.page().selectedText());
1100 browser.page().triggerAction(WebAction.Cut);
1104 // Listener when COPY is clicked
1105 @SuppressWarnings("unused")
1106 private void copyClicked() {
1108 cbObserver.setCopySourceGuid(currentNote.getGuid(), browser.page().selectedText());
1110 browser.page().triggerAction(WebAction.Copy);
1114 // Listener when PASTE is clicked
1115 public void pasteClicked() {
1116 logger.log(logger.EXTREME, "Paste Clicked");
1117 if (forceTextPaste) {
1118 pasteWithoutFormattingClicked();
1122 // ICHANGED コピー&ペーストの操作履歴をデータベースに登録
1123 String srcGuid = cbObserver.getSourceGuid();
1124 String dstGuid = currentNote.getGuid();
1125 if(srcGuid != null && dstGuid != null){
1126 if(!srcGuid.equals(dstGuid)){
1127 conn.getHistoryTable().addHistory("copy & paste", srcGuid, dstGuid);
1131 QClipboard clipboard = QApplication.clipboard();
1132 QMimeData mime = clipboard.mimeData();
1134 if (mime.hasImage()) {
1135 logger.log(logger.EXTREME, "Image paste found");
1142 if (mime.hasUrls()) {
1143 logger.log(logger.EXTREME, "URL paste found");
1144 if (mime.text().startsWith("evernote:")) {
1145 handleNoteLink(mime);
1153 String text = mime.html();
1154 if (text.contains("en-tag") && mime.hasHtml()) {
1155 logger.log(logger.EXTREME, "Intra-note paste found");
1156 text = fixInternotePaste(text);
1158 clipboard.setMimeData(mime);
1161 logger.log(logger.EXTREME, "Final paste choice encountered");
1162 browser.page().triggerAction(WebAction.Paste);
1167 // Paste text without formatting
1168 private void pasteWithoutFormattingClicked() {
1169 logger.log(logger.EXTREME, "Paste without format clipped");
1170 QClipboard clipboard = QApplication.clipboard();
1171 QMimeData mime = clipboard.mimeData();
1172 if (!mime.hasText())
1175 // ICHANGED コピー&ペーストの操作履歴をデータベースに登録
1176 String srcGuid = cbObserver.getSourceGuid();
1177 String dstGuid = currentNote.getGuid();
1178 if(srcGuid != null && dstGuid != null){
1179 if(!srcGuid.equals(dstGuid)){
1180 conn.getHistoryTable().addHistory("copy & paste", srcGuid, dstGuid);
1184 String text = mime.text();
1186 clipboard.setText(text, Mode.Clipboard);
1187 browser.page().triggerAction(WebAction.Paste);
1189 // This is done because pasting into an encryption block
1190 // can cause multiple cells (which can't happen). It
1191 // just goes through the table, extracts the data, &
1192 // puts it back as one table cell.
1193 if (insideEncryption) {
1194 String js = new String( "function fixEncryption() { "
1195 +" var selObj = window.getSelection();"
1196 +" var selRange = selObj.getRangeAt(0);"
1197 +" var workingNode = window.getSelection().anchorNode;"
1198 +" while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { "
1199 +" workingNode = workingNode.parentNode;"
1201 +" workingNode.innerHTML = window.jambi.fixEncryptionPaste(workingNode.innerHTML);"
1202 +"} fixEncryption();");
1203 browser.page().mainFrame().evaluateJavaScript(js);
1207 // This basically removes all the table tags and returns just the contents.
1208 // This is called by JavaScript to fix encryption pastes.
1209 public String fixEncryptionPaste(String data) {
1210 data = data.replace("<tbody>", "");
1211 data = data.replace("</tbody>", "");
1212 data = data.replace("<tr>", "");
1213 data = data.replace("</tr>", "");
1214 data = data.replace("<td>", "");
1215 data = data.replace("</td>", "<br>");
1216 data = data.replace("<br><br>", "<br>");
1218 return "<tbody><tr><td>"+data+"</td></tr></tbody>";
1222 @SuppressWarnings("unused")
1223 private void insertDateTime() {
1224 String fmt = Global.getDateFormat() + " " + Global.getTimeFormat();
1225 String dateTimeFormat = new String(fmt);
1226 SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);
1227 Calendar cal = Calendar.getInstance();
1229 browser.page().mainFrame().evaluateJavaScript(
1230 "document.execCommand('insertHtml', false, '"+simple.format(cal.getTime())+"');");
1236 // Listener when Left is clicked
1237 @SuppressWarnings("unused")
1238 private void justifyLeftClicked() {
1239 browser.page().mainFrame().evaluateJavaScript(
1240 "document.execCommand('JustifyLeft', false, '');");
1244 // Listener when Center is clicked
1245 @SuppressWarnings("unused")
1246 private void justifyCenterClicked() {
1247 browser.page().mainFrame().evaluateJavaScript(
1248 "document.execCommand('JustifyCenter', false, '');");
1252 // Listener when Left is clicked
1253 @SuppressWarnings("unused")
1254 private void justifyRightClicked() {
1255 browser.page().mainFrame().evaluateJavaScript(
1256 "document.execCommand('JustifyRight', false, '');");
1260 // Listener when HLINE is clicked
1261 @SuppressWarnings("unused")
1262 private void hlineClicked() {
1263 browser.page().mainFrame().evaluateJavaScript(
1264 "document.execCommand('insertHorizontalRule', false, '');");
1268 // Listener when outdent is clicked
1269 private void outdentClicked() {
1270 browser.page().mainFrame().evaluateJavaScript(
1271 "document.execCommand('outdent', false, '');");
1275 // Listener when a bullet list is clicked
1276 @SuppressWarnings("unused")
1277 private void bulletListClicked() {
1278 browser.page().mainFrame().evaluateJavaScript(
1279 "document.execCommand('InsertUnorderedList', false, '');");
1283 // Listener when a bullet list is clicked
1284 @SuppressWarnings("unused")
1285 private void numberListClicked() {
1286 browser.page().mainFrame().evaluateJavaScript(
1287 "document.execCommand('InsertOrderedList', false, '');");
1291 // Listener when indent is clicked
1292 private void indentClicked() {
1293 browser.page().mainFrame().evaluateJavaScript(
1294 "document.execCommand('indent', false, '');");
1298 // Listener when the font name is changed
1299 @SuppressWarnings("unused")
1300 private void fontChanged(String font) {
1301 browser.page().mainFrame().evaluateJavaScript(
1302 "document.execCommand('fontName',false,'" + font + "');");
1306 // Listener when a font size is changed
1307 @SuppressWarnings("unused")
1308 private void fontSizeChanged(String font) {
1309 String text = browser.selectedText();
1310 if (text.trim().equalsIgnoreCase(""))
1313 String selectedText = browser.selectedText();
1314 String url = "<span style=\"font-size:" +font +"pt; \">"+selectedText +"</a>";
1315 String script = "document.execCommand('insertHtml', false, '"+url+"');";
1316 browser.page().mainFrame().evaluateJavaScript(script);
1317 /* browser.page().mainFrame().evaluateJavaScript(
1318 "document.execCommand('fontSize',false,'"
1324 // Load the font combo box based upon the font selected
1325 private void loadFontSize(String name) {
1326 QFontDatabase db = new QFontDatabase();
1328 List<Integer> points = db.pointSizes(name);
1329 for (int i=0; i<points.size(); i++) {
1330 fontSize.addItem(points.get(i).toString());
1333 fontSize.addItem("x-small");
1334 fontSize.addItem("small");
1335 fontSize.addItem("medium");
1336 fontSize.addItem("large");
1337 fontSize.addItem("x-large");
1338 fontSize.addItem("xx-large");
1339 fontSize.addItem("xxx-large");
1343 // Listener when a font size is changed
1344 @SuppressWarnings("unused")
1345 private void fontColorClicked() {
1346 // QColorDialog dialog = new QColorDialog();
1347 // QColor color = QColorDialog.getColor();
1348 QColor color = fontColorMenu.getColor();
1349 if (color.isValid())
1350 browser.page().mainFrame().evaluateJavaScript(
1351 "document.execCommand('foreColor',false,'" + color.name()
1356 // Listener for when a background color change is requested
1357 @SuppressWarnings("unused")
1358 private void fontHilightClicked() {
1359 // QColorDialog dialog = new QColorDialog();
1360 // QColor color = QColorDialog.getColor();
1361 QColor color = fontHilightColorMenu.getColor();
1362 if (color.isValid())
1363 browser.page().mainFrame().evaluateJavaScript(
1364 "document.execCommand('backColor',false,'" + color.name()
1369 // Listener for when a background color change is requested
1370 @SuppressWarnings("unused")
1371 private void superscriptClicked() {
1372 browser.page().mainFrame().evaluateJavaScript(
1373 "document.execCommand('superscript');");
1377 // Listener for when a background color change is requested
1378 @SuppressWarnings("unused")
1379 private void subscriptClicked() {
1380 browser.page().mainFrame().evaluateJavaScript(
1381 "document.execCommand('subscript');");
1384 // Insert a to-do checkbox
1385 @SuppressWarnings("unused")
1386 private void todoClicked() {
1387 FileNameMap fileNameMap = URLConnection.getFileNameMap();
1388 String script_start = new String(
1389 "document.execCommand('insertHtml', false, '");
1390 String script_end = new String("');");
1391 String todo = new String(
1392 "<input TYPE=\"CHECKBOX\" value=\"false\" " +
1393 "onMouseOver=\"style.cursor=\\'hand\\'\" " +
1394 "onClick=\"value=checked; window.jambi.contentChanged(); \" />");
1395 browser.page().mainFrame().evaluateJavaScript(
1396 script_start + todo + script_end);
1400 // Encrypt the selected text
1401 @SuppressWarnings("unused")
1402 private void encryptText() {
1403 String text = browser.selectedText();
1404 if (text.trim().equalsIgnoreCase(""))
1406 text = new String(text.replaceAll("\n", "<br/>"));
1408 EnCryptDialog dialog = new EnCryptDialog();
1410 if (!dialog.okPressed()) {
1414 EnCrypt crypt = new EnCrypt();
1415 String encrypted = crypt.encrypt(text, dialog.getPassword().trim(), 64);
1416 String decrypted = crypt.decrypt(encrypted, dialog.getPassword().trim(), 64);
1418 if (encrypted.trim().equals("")) {
1419 QMessageBox.information(this, tr("Error"), tr("Error Encrypting String"));
1422 StringBuffer buffer = new StringBuffer(encrypted.length() + 100);
1423 buffer.append("<img en-tag=\"en-crypt\" cipher=\"RC2\" hint=\""
1424 + dialog.getHint().replace("'","\\'") + "\" length=\"64\" ");
1425 buffer.append("contentEditable=\"false\" alt=\"");
1426 buffer.append(encrypted);
1427 buffer.append("\" src=\"").append(FileUtils.toForwardSlashedPath(Global.getFileManager().getImageDirPath("encrypt.png") +"\""));
1428 Global.cryptCounter++;
1429 buffer.append(" id=\"crypt"+Global.cryptCounter.toString() +"\"");
1430 buffer.append(" onMouseOver=\"style.cursor=\\'hand\\'\"");
1431 buffer.append(" onClick=\"window.jambi.decryptText(\\'crypt"+Global.cryptCounter.toString()
1432 +"\\', \\'"+encrypted+"\\', \\'"+dialog.getHint().replace("'", "\\&apos;")+"\\');\"");
1433 buffer.append("style=\"display:block\" />");
1435 String script_start = new String(
1436 "document.execCommand('insertHtml', false, '");
1437 String script_end = new String("');");
1438 browser.page().mainFrame().evaluateJavaScript(
1439 script_start + buffer.toString() + script_end);
1443 // Insert a Quick hyperlink
1444 public void insertQuickLink() {
1445 logger.log(logger.EXTREME, "Inserting link");
1446 String text = browser.selectedText();
1447 if (text.trim().equalsIgnoreCase(""))
1451 NoteQuickLinkDialog dialog = new NoteQuickLinkDialog(logger, conn, text, cbObserver);
1453 if (dialog.getResults().size() == 0) {
1454 QMessageBox.critical(null, tr("No Matches Found") ,tr("No matching notes found."));
1457 if (dialog.getResults().size() > 1) {
1459 if (!dialog.okPressed) {
1460 logger.log(logger.EXTREME, "Insert link canceled");
1465 User user = Global.getUserInformation();
1466 String dUrl = new String("evernote:///view/") + new String(user.getId() + "/" +user.getShardId() +"/"
1467 +dialog.getSelectedNote()+"/"+dialog.getSelectedNote() +"/ " +"style=\"color:#69aa35\"");
1469 String url = "<a title=\"" +dUrl
1472 String script = "document.execCommand('insertHtml', false, '"+url+"');";
1473 browser.page().mainFrame().evaluateJavaScript(script);
1477 // Insert a hyperlink
1478 public void insertLink() {
1479 logger.log(logger.EXTREME, "Inserting link");
1480 String text = browser.selectedText();
1481 if (text.trim().equalsIgnoreCase(""))
1484 InsertLinkDialog dialog = new InsertLinkDialog(insertHyperlink);
1485 if (currentHyperlink != null && currentHyperlink != "") {
1486 dialog.setUrl(currentHyperlink);
1489 if (!dialog.okPressed()) {
1490 logger.log(logger.EXTREME, "Insert link canceled");
1494 // Take care of inserting new links
1495 if (insertHyperlink) {
1496 String selectedText = browser.selectedText();
1497 if (dialog.getUrl().trim().equals(""))
1499 logger.log(logger.EXTREME, "Inserting link on text "+selectedText);
1500 logger.log(logger.EXTREME, "URL Link " +dialog.getUrl().trim());
1501 String dUrl = StringUtils.replace(dialog.getUrl().trim(), "'", "\\'");
1502 String url = "<a href=\"" +dUrl
1504 +" >"+selectedText +"</a>";
1505 String script = "document.execCommand('insertHtml', false, '"+url+"');";
1506 browser.page().mainFrame().evaluateJavaScript(script);
1510 // Edit existing links
1511 String js = new String( "function getCursorPos() {"
1513 +"if (window.getSelection) {"
1514 +" var selObj = window.getSelection();"
1515 +" var selRange = selObj.getRangeAt(0);"
1516 +" var workingNode = window.getSelection().anchorNode.parentNode;"
1517 +" while(workingNode != null) { "
1518 +" if (workingNode.nodeName.toLowerCase()=='a') workingNode.setAttribute('href','" +dialog.getUrl() +"');"
1519 +" workingNode = workingNode.parentNode;"
1522 +"} getCursorPos();");
1523 browser.page().mainFrame().evaluateJavaScript(js);
1525 if (!dialog.getUrl().trim().equals("")) {
1531 js = new String( "function getCursorPos() {"
1533 +"if (window.getSelection) {"
1534 +" var selObj = window.getSelection();"
1535 +" var selRange = selObj.getRangeAt(0);"
1536 +" var workingNode = window.getSelection().anchorNode.parentNode;"
1537 +" while(workingNode != null) { "
1538 +" if (workingNode.nodeName.toLowerCase()=='a') { "
1539 +" workingNode.removeAttribute('href');"
1540 +" workingNode.removeAttribute('title');"
1541 +" var text = document.createTextNode(workingNode.innerText);"
1542 +" workingNode.parentNode.insertBefore(text, workingNode);"
1543 +" workingNode.parentNode.removeChild(workingNode);"
1545 +" workingNode = workingNode.parentNode;"
1548 +"} getCursorPos();");
1549 browser.page().mainFrame().evaluateJavaScript(js);
1557 // Insert a hyperlink
1558 public void insertLatex() {
1561 public void editLatex(String guid) {
1562 logger.log(logger.EXTREME, "Inserting latex");
1563 String text = browser.selectedText();
1564 if (text.trim().equalsIgnoreCase("\n") || text.trim().equalsIgnoreCase("")) {
1565 InsertLatexImage dialog = new InsertLatexImage();
1567 String formula = conn.getNoteTable().noteResourceTable.getNoteSourceUrl(guid).replace("http://latex.codecogs.com/gif.latex?", "");
1568 dialog.setFormula(formula);
1571 if (!dialog.okPressed()) {
1572 logger.log(logger.EXTREME, "Edit LaTex canceled");
1575 text = dialog.getFormula().trim();
1577 blockApplication.emit(this);
1578 logger.log(logger.EXTREME, "Inserting LaTeX formula:" +text);
1580 text = StringUtils.replace(text, "'", "\\'");
1581 String url = "http://latex.codecogs.com/gif.latex?" +text;
1582 logger.log(logger.EXTREME, "Sending request to codecogs --> " + url);
1583 QNetworkAccessManager manager = new QNetworkAccessManager(this);
1584 manager.finished.connect(this, "insertLatexImageReady(QNetworkReply)");
1585 unblockTime = new GregorianCalendar().getTimeInMillis()+5000;
1586 awaitingHttpResponse = true;
1587 manager.get(new QNetworkRequest(new QUrl(url)));
1590 public void insertLatexImageReady(QNetworkReply reply) {
1591 logger.log(logger.EXTREME, "Response received from CodeCogs");
1592 if (reply.error() != NetworkError.NoError)
1596 if (!awaitingHttpResponse)
1599 awaitingHttpResponse = false;
1600 QUrl replyUrl = reply.url();
1601 QByteArray image = reply.readAll();
1603 logger.log(logger.EXTREME, "New image size: " +image.size());
1605 Resource newRes = null;
1608 if (latexGuid == null) {
1609 logger.log(logger.EXTREME, "Creating temporary gif");
1610 path = Global.getFileManager().getResDirPath("latex-temp.gif");
1611 tfile = new QFile(path);
1612 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
1613 logger.log(logger.EXTREME, "File Open: " +tfile.errorString());
1615 logger.log(logger.EXTREME, "Bytes writtes: "+tfile.size());
1617 logger.log(logger.EXTREME, "Creating resource");
1619 if (currentNote.getResources() != null || currentNote.getResources().size() > 0)
1620 sequence = currentNote.getResources().size();
1621 newRes = createResource(path,sequence ,"image/gif", false);
1622 QImage pix = new QImage();
1623 pix.loadFromData(image);
1624 newRes.setHeight(new Integer(pix.height()).shortValue());
1625 newRes.setWidth(new Integer(pix.width()).shortValue());
1626 logger.log(logger.EXTREME, "Renaming temporary file to " +newRes.getGuid()+".gif");
1627 path = Global.getFileManager().getResDirPath(newRes.getGuid()+".gif");
1630 newRes = conn.getNoteTable().noteResourceTable.getNoteResource(latexGuid, false);
1631 path = Global.getFileManager().getResDirPath(newRes.getGuid()+".gif");
1632 tfile = new QFile(path);
1633 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
1636 newRes.getData().setBody(image.toByteArray());
1637 // Calculate the new hash value
1640 logger.log(logger.EXTREME, "Generating MD5");
1642 md = MessageDigest.getInstance("MD5");
1643 md.update(image.toByteArray());
1644 byte[] hash = md.digest();
1645 newRes.getData().setBodyHash(hash);
1646 } catch (NoSuchAlgorithmException e) {
1647 e.printStackTrace();
1649 QImage pix = new QImage();
1650 pix.loadFromData(image);
1651 newRes.setHeight(new Integer(pix.height()).shortValue());
1652 newRes.setWidth(new Integer(pix.width()).shortValue());
1653 conn.getNoteTable().noteResourceTable.updateNoteResource(newRes, true);
1656 logger.log(logger.EXTREME, "Setting source: " +replyUrl.toString());
1657 newRes.getAttributes().setSourceURL(replyUrl.toString());
1658 conn.getNoteTable().noteResourceTable.updateNoteSourceUrl(newRes.getGuid(), replyUrl.toString(), true);
1660 for(int i=0; i<currentNote.getResourcesSize(); i++) {
1661 if (currentNote.getResources().get(i).getGuid().equals(newRes.getGuid())) {
1662 currentNote.getResources().remove(i);
1663 i=currentNote.getResourcesSize();
1666 currentNote.getResources().add(newRes);
1669 // do the actual insert into the note. We only do this on new formulas.
1670 if (latexGuid == null) {
1671 StringBuffer buffer = new StringBuffer(100);
1672 String formula = replyUrl.toString().toLowerCase().replace("http://latex.codecogs.com/gif.latex?", "");
1673 buffer.append("<a href=\"latex://"+path.replace("\\", "/")+"\" title=\""+formula+"\""
1675 buffer.append(path.replace("\\", "/"));
1676 buffer.append("\" en-tag=\"en-latex\" type=\"image/gif\""
1677 +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""
1678 +" guid=\"" +newRes.getGuid() +"\""
1681 String script_start = new String("document.execCommand('insertHTML', false, '");
1682 String script_end = new String("');");
1683 browser.page().mainFrame().evaluateJavaScript(
1684 script_start + buffer + script_end);
1686 HtmlTagModifier modifier = new HtmlTagModifier(getContent());
1687 modifier.modifyLatexTagHash(newRes);
1688 String newContent = modifier.getHtml();
1689 setContent(new QByteArray(newContent));
1692 logger.log(logger.EXTREME, "New HTML set\n" +browser.page().currentFrame().toHtml());
1693 QWebSettings.setMaximumPagesInCache(0);
1694 QWebSettings.setObjectCacheCapacities(0, 0, 0);
1696 browser.page().mainFrame().setHtml(browser.page().mainFrame().toHtml());
1699 // resourceSignal.contentChanged.emit(path);
1701 unblockApplication.emit();
1709 public void insertTable() {
1710 TableDialog dialog = new TableDialog();
1712 if (!dialog.okPressed()) {
1716 int cols = dialog.getCols();
1717 int rows = dialog.getRows();
1718 int width = dialog.getWidth();
1719 boolean percent = dialog.isPercent();
1721 String newHTML = "<table border=\"1\" width=\"" +new Integer(width).toString();
1723 newHTML = newHTML +"%";
1724 newHTML = newHTML + "\"><tbody>";
1726 for (int i=0; i<rows; i++) {
1727 newHTML = newHTML +"<tr>";
1728 for (int j=0; j<cols; j++) {
1729 newHTML = newHTML +"<td> </td>";
1731 newHTML = newHTML +"</tr>";
1733 newHTML = newHTML+"</tbody></table>";
1735 String script = "document.execCommand('insertHtml', false, '"+newHTML+"');";
1736 browser.page().mainFrame().evaluateJavaScript(script);
1740 // Text content changed
1741 @SuppressWarnings("unused")
1742 private void selectionChanged() {
1743 browser.encryptAction.setEnabled(true);
1744 browser.insertLinkAction.setEnabled(true);
1745 browser.insertQuickLinkAction.setEnabled(true);
1746 String scriptStart = "var selection_text = (window.getSelection()).toString();"
1747 + "var range = (window.getSelection()).getRangeAt(0);"
1748 + "var parent_html = range.commonAncestorContainer.innerHTML;"
1749 + "if (parent_html == undefined) {window.jambi.saveSelectedText(selection_text); return;}"
1750 + "var first_text = range.startContainer.nodeValue.substr(range.startOffset);"
1751 + "var last_text = (range.endContainer.nodeValue).substring(0,range.endOffset);"
1752 + "var start = parent_html.indexOf(first_text);"
1753 + "var end = parent_html.indexOf(last_text,start+1)+last_text.length;"
1754 + "var value = parent_html.substring(start,end);"
1755 + "window.jambi.saveSelectedText(value);" ;
1756 browser.page().mainFrame().evaluateJavaScript(scriptStart);
1760 public void saveSelectedText(String text) {
1761 boolean enabled = true;
1762 if (text.trim().length() == 0)
1764 if (text.indexOf("en-tag=\"en-crypt\"") >= 0)
1766 if (text.indexOf("<img en-tag=\"en-media\"") >= 0)
1768 if (text.indexOf("<a en-tag=\"en-media\"") >= 0)
1770 if (text.indexOf("<input ") >= 0)
1773 browser.encryptAction.setEnabled(enabled);
1774 browser.insertLinkAction.setEnabled(enabled);
1775 browser.insertQuickLinkAction.setEnabled(enabled);
1776 // selectedText = text;
1779 // Decrypt clicked text
1780 public void decryptText(String id, String text, String hint) {
1781 EnCrypt crypt = new EnCrypt();
1782 String plainText = null;
1783 Calendar currentTime = new GregorianCalendar();
1784 Long l = new Long(currentTime.getTimeInMillis());
1785 String slot = new String(Long.toString(l));
1787 // First, try to decrypt with any keys we already have
1788 for (int i=0; i<Global.passwordRemember.size(); i++) {
1789 plainText = crypt.decrypt(text, Global.passwordRemember.get(i).getFirst(), 64);
1790 if (plainText != null) {
1791 slot = new String(Long.toString(l));
1792 Global.passwordSafe.put(slot, Global.passwordRemember.get(i));
1793 removeEncryption(id, plainText, false, slot);
1799 EnDecryptDialog dialog = new EnDecryptDialog();
1800 dialog.setHint(hint);
1801 while (plainText == null || !dialog.okPressed()) {
1803 if (!dialog.okPressed()) {
1806 plainText = crypt.decrypt(text, dialog.getPassword().trim(), 64);
1807 if (plainText == null) {
1808 QMessageBox.warning(this, tr("Incorrect Password"), tr("The password entered is not correct"));
1811 Pair<String,String> passwordPair = new Pair<String,String>();
1812 passwordPair.setFirst(dialog.getPassword());
1813 passwordPair.setSecond(dialog.getHint());
1814 Global.passwordSafe.put(slot, passwordPair);
1815 // removeEncryption(id, plainText.replaceAll("\n", "<br/>"), dialog.permanentlyDecrypt(), slot);
1816 removeEncryption(id, plainText, dialog.permanentlyDecrypt(), slot);
1817 if (dialog.rememberPassword()) {
1818 Pair<String, String> pair = new Pair<String,String>();
1819 pair.setFirst(dialog.getPassword());
1820 pair.setSecond(dialog.getHint());
1821 Global.passwordRemember.add(pair);
1826 // Get the editor tag line
1827 public TagLineEdit getTagLine() {
1831 // Modify a note's tags
1832 @SuppressWarnings("unused")
1833 private void modifyTags() {
1834 TagAssign tagWindow = new TagAssign(allTags, currentTags, !conn.getNotebookTable().isLinked(currentNote.getNotebookGuid()));
1836 if (tagWindow.okClicked()) {
1837 currentTags.clear();
1838 StringBuffer tagDisplay = new StringBuffer();
1840 List<QListWidgetItem> newTags = tagWindow.getTagList()
1842 for (int i = 0; i < newTags.size(); i++) {
1843 currentTags.add(newTags.get(i).text());
1844 tagDisplay.append(newTags.get(i).text());
1845 if (i < newTags.size() - 1) {
1846 tagDisplay.append(Global.tagDelimeter + " ");
1849 tagEdit.setText(tagDisplay.toString());
1850 noteSignal.tagsChanged.emit(currentNote.getGuid(), currentTags);
1854 // Tag line has been modified by typing text
1855 @SuppressWarnings("unused")
1856 private void modifyTagsTyping() {
1857 String completionText = "";
1858 if (tagEdit.currentCompleterSelection != null && !tagEdit.currentCompleterSelection.equals("")) {
1859 completionText = tagEdit.currentCompleterSelection;
1860 tagEdit.currentCompleterSelection = "";
1863 if (tagEdit.text().equalsIgnoreCase(saveTagList))
1866 // We know something has changed...
1867 String oldTagArray[] = saveTagList.split(Global.tagDelimeter);
1868 String newTagArray[];
1869 if (!completionText.equals("")) {
1870 String before = tagEdit.text().substring(0,tagEdit.cursorPosition());
1871 int lastDelimiter = before.lastIndexOf(Global.tagDelimeter);
1872 if (lastDelimiter > 0)
1873 before = before.substring(0,before.lastIndexOf(Global.tagDelimeter));
1876 String after = tagEdit.text().substring(tagEdit.cursorPosition());
1877 newTagArray = (before+Global.tagDelimeter+completionText+Global.tagDelimeter+after).split(Global.tagDelimeter);
1880 newTagArray = tagEdit.text().split(Global.tagDelimeter);
1883 // Remove any traling or leading blanks
1884 for (int i=0; i<newTagArray.length; i++)
1885 newTagArray[i] = newTagArray[i].trim().replaceAll("^\\s+", "");;
1887 // Remove any potential duplicates from the new list
1888 for (int i=0; i<newTagArray.length; i++) {
1889 boolean foundOnce = false;
1890 for (int j=0; j<newTagArray.length; j++) {
1891 if (newTagArray[j].equalsIgnoreCase(newTagArray[i])) {
1895 newTagArray[j] = "";
1900 List<String> newTagList = new ArrayList<String>();
1901 List<String> oldTagList = new ArrayList<String>();
1903 for (int i = 0; i < oldTagArray.length; i++)
1904 if (!oldTagArray[i].trim().equals(""))
1905 oldTagList.add(oldTagArray[i]);
1906 for (int i = 0; i < newTagArray.length; i++)
1907 if (!newTagArray[i].trim().equals(""))
1908 newTagList.add(newTagArray[i]);
1910 if (conn.getNotebookTable().isLinked(currentNote.getNotebookGuid())) {
1911 for (int i=newTagList.size()-1; i>=0; i--) {
1912 boolean found = false;
1913 for (int j=0; j<allTags.size(); j++) {
1914 if (allTags.get(j).getName().equalsIgnoreCase(newTagList.get(i))) {
1920 newTagList.remove(i);
1924 // Let's cleanup the appearance of the tag list
1925 Collections.sort(newTagList);
1926 String newDisplay = "";
1927 for (int i=0; i<newTagList.size(); i++) {
1928 newDisplay = newDisplay+newTagList.get(i);
1929 if (i<newTagList.size()-1)
1930 newDisplay = newDisplay+Global.tagDelimeter +" ";
1932 tagEdit.blockSignals(true);
1933 tagEdit.setText(newDisplay);
1934 tagEdit.blockSignals(false);
1936 // We now have lists of the new & old. Remove duplicates. If all
1937 // are removed from both then nothing has really changed
1938 for (int i = newTagList.size() - 1; i >= 0; i--) {
1939 String nTag = newTagList.get(i);
1940 for (int j = oldTagList.size() - 1; j >= 0; j--) {
1941 String oTag = oldTagList.get(j);
1942 if (oTag.equalsIgnoreCase(nTag)) {
1943 oldTagList.remove(j);
1944 newTagList.remove(i);
1950 if (oldTagList.size() != 0 || newTagList.size() != 0) {
1951 currentTags.clear();
1952 newTagArray = tagEdit.text().split(Global.tagDelimeter);
1953 for (int i = 0; i < newTagArray.length; i++)
1954 if (!newTagArray[i].trim().equals(""))
1955 currentTags.add(newTagArray[i].trim());
1957 noteSignal.tagsChanged.emit(currentNote.getGuid(), currentTags);
1962 // Tab button was pressed
1963 public void tabPressed() {
1964 if (insideEncryption)
1966 if (!insideList && !insideTable) {
1967 String script_start = new String(
1968 "document.execCommand('insertHtml', false, ' ');");
1969 browser.page().mainFrame().evaluateJavaScript(script_start);
1976 String js = new String( "function getCursorPosition() { "
1977 +" var selObj = window.getSelection();"
1978 +" var selRange = selObj.getRangeAt(0);"
1979 +" var workingNode = window.getSelection().anchorNode;"
1980 +" var rowCount = 0;"
1981 +" var colCount = 0;"
1982 +" while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { "
1983 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
1984 +" rowCount = rowCount+1;"
1986 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
1987 +" colCount = colCount+1;"
1989 +" if (workingNode.previousSibling != null)"
1990 +" workingNode = workingNode.previousSibling;"
1992 +" workingNode = workingNode.parentNode;"
1994 +" var nodes = workingNode.getElementsByTagName('tr');"
1995 +" var tableRows = nodes.length;"
1996 +" nodes = nodes[0].getElementsByTagName('td');"
1997 +" var tableColumns = nodes.length;"
1998 +" window.jambi.setTableCursorPositionTab(rowCount, colCount, tableRows, tableColumns);"
1999 +"} getCursorPosition();");
2000 browser.page().mainFrame().evaluateJavaScript(js);
2004 // If a user presses tab from within a table
2005 public void setTableCursorPositionTab(int currentRow, int currentCol, int tableRows, int tableColumns) {
2006 if (tableRows == currentRow && currentCol == tableColumns) {
2009 KeyboardModifiers modifiers = new KeyboardModifiers(KeyboardModifier.NoModifier);
2010 QKeyEvent right = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Right.value(), modifiers);
2011 QKeyEvent end = new QKeyEvent(Type.KeyPress, Qt.Key.Key_End.value(), modifiers);
2012 QKeyEvent end2 = new QKeyEvent(Type.KeyPress, Qt.Key.Key_End.value(), modifiers);
2013 getBrowser().focusWidget();
2014 QCoreApplication.postEvent(getBrowser(), end);
2015 QCoreApplication.postEvent(getBrowser(), right);
2016 QCoreApplication.postEvent(getBrowser(), end2);
2019 public void backtabPressed() {
2020 if (insideEncryption)
2025 String js = new String( "function getCursorPosition() { "
2026 +" var selObj = window.getSelection();"
2027 +" var selRange = selObj.getRangeAt(0);"
2028 +" var workingNode = window.getSelection().anchorNode;"
2029 +" var rowCount = 0;"
2030 +" var colCount = 0;"
2031 +" while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { "
2032 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
2033 +" rowCount = rowCount+1;"
2035 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
2036 +" colCount = colCount+1;"
2038 +" if (workingNode.previousSibling != null)"
2039 +" workingNode = workingNode.previousSibling;"
2041 +" workingNode = workingNode.parentNode;"
2043 +" var nodes = workingNode.getElementsByTagName('tr');"
2044 +" var tableRows = nodes.length;"
2045 +" nodes = nodes[0].getElementsByTagName('td');"
2046 +" var tableColumns = nodes.length;"
2047 +" window.jambi.setTableCursorPositionBackTab(rowCount, colCount, tableRows, tableColumns);"
2048 +"} getCursorPosition();");
2049 browser.page().mainFrame().evaluateJavaScript(js);
2054 // If a user presses backtab from within a table
2055 public void setTableCursorPositionBackTab(int currentRow, int currentCol, int tableRows, int tableColumns) {
2056 if (currentRow == 1 && currentCol == 1) {
2059 KeyboardModifiers modifiers = new KeyboardModifiers(KeyboardModifier.NoModifier);
2060 QKeyEvent left = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Left.value(), modifiers);
2061 QKeyEvent home = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Home.value(), modifiers);
2062 getBrowser().focusWidget();
2063 QCoreApplication.postEvent(getBrowser(), home);
2064 QCoreApplication.postEvent(getBrowser(), left);
2068 public void setInsideList() {
2072 // The title has been edited
2073 @SuppressWarnings("unused")
2074 private void titleEdited() {
2075 // If we don't have a good note, or if the current title
2076 // matches the old title then we don't need to do anything
2077 if (currentNote == null)
2079 if (currentNote.getTitle().trim().equals(titleLabel.text().trim()))
2082 // If we have a real change, we need to save it.
2083 String text = titleLabel.text().trim();
2084 if (text.equals(""))
2085 text = tr("Untitled Note");
2086 noteSignal.titleChanged.emit(currentNote.getGuid(), text);
2087 currentNote.setTitle(text);
2088 saveNoteTitle = text;
2092 // Set the list of note tags
2093 public void setAllTags(List<Tag> l) {
2095 tagEdit.setTagList(l);
2098 // Setter for the current tags
2099 public void setCurrentTags(List<String> s) {
2103 // Save the list of notebooks
2104 public void setNotebookList(List<Notebook> n) {
2109 // Load the notebook list and select the current notebook
2110 private void loadNotebookList() {
2111 if (notebookBox.count() != 0)
2112 notebookBox.clear();
2113 if (notebookList == null)
2116 for (int i = 0; i < notebookList.size(); i++) {
2117 notebookBox.addItem(notebookList.get(i).getName());
2118 if (currentNote != null) {
2119 if (currentNote.getNotebookGuid().equals(
2120 notebookList.get(i).getGuid())) {
2121 notebookBox.setCurrentIndex(i);
2128 // Set the notebook for a note
2129 public void setNotebook(String notebook) {
2130 currentNote.setNotebookGuid(notebook);
2134 // Get the contents of the editor
2135 public String getContent() {
2136 return browser.page().currentFrame().toHtml();
2139 // The note contents have changed
2140 public void contentChanged() {
2141 String content = getContent();
2143 // This puts in a 1/2 second delay
2144 // before updating the source editor.
2145 // It improves response when someone is doing
2146 // frequent updates on a large note.
2147 // If the source editor isn't visible, then there
2148 // is no point to doing any of this.
2149 if (sourceEdit.isVisible()) {
2150 setSourceTimer.stop();
2151 setSourceTimer.setInterval(500);
2152 setSourceTimer.setSingleShot(true);
2153 setSourceTimer.start();
2157 noteSignal.noteChanged.emit(currentNote.getGuid(), content);
2160 // The notebook selection has changed
2161 @SuppressWarnings("unused")
2162 private void notebookChanged() {
2163 boolean changed = false;
2164 String n = notebookBox.currentText();
2165 for (int i = 0; i < notebookList.size(); i++) {
2166 if (n.equals(notebookList.get(i).getName())) {
2167 if (!notebookList.get(i).getGuid().equals(currentNote.getNotebookGuid())) {
2168 String guid = conn.getNotebookTable().findNotebookByName(n);
2169 if (conn.getNotebookTable().isLinked(guid)) {
2170 tagEdit.setText("");
2171 noteSignal.tagsChanged.emit(currentNote.getGuid(), new ArrayList<String>());
2172 FilterEditorTags t = new FilterEditorTags(conn, logger);
2173 setAllTags(t.getValidTags(currentNote));
2175 currentNote.setNotebookGuid(notebookList.get(i).getGuid());
2178 i = notebookList.size();
2182 // If the notebook changed, signal the update
2184 noteSignal.notebookChanged.emit(currentNote.getGuid(), currentNote
2185 .getNotebookGuid());
2188 // Check the note title
2189 private void checkNoteTitle() {
2190 String text = browser.page().currentFrame().toPlainText();
2191 if (saveNoteTitle == null)
2192 saveNoteTitle = new String();
2194 if (!saveNoteTitle.trim().equals("") && !saveNoteTitle.trim().equals("Untitled Note"))
2195 text = saveNoteTitle.trim();
2196 int newLine = text.indexOf("\n");
2198 text = text.substring(0,newLine);
2199 if (saveNoteTitle.trim().equals("") || saveNoteTitle.trim().equals("Untitled Note")) {
2200 if (text.trim().equals(""))
2201 text = tr("Untitled Note");
2202 titleLabel.setText(text);
2204 if (text.length() > Constants.EDAM_NOTE_TITLE_LEN_MAX)
2205 titleLabel.setText(text.substring(0, Constants.EDAM_NOTE_TITLE_LEN_MAX));
2207 titleLabel.blockSignals(true);
2208 if (text.trim().equals(""))
2209 titleLabel.setText(tr("Untitled Note"));
2211 titleLabel.setText(text);
2212 titleLabel.blockSignals(false);
2215 if (currentNote != null && titleLabel != null && !currentNote.getTitle().equals(text))
2216 noteSignal.titleChanged.emit(currentNote.getGuid(), text);
2219 // Return the note contents so we can email them
2220 public String getContentsToEmail() {
2221 return browser.page().currentFrame().toPlainText().trim();
2223 * int body = browser.page().currentFrame().toHtml().indexOf("<body>");
2224 * String temp = browser.page().currentFrame().toHtml(); if (body == -1)
2225 * temp = "<html><body><b>Test</b></body></html>"; else temp =
2226 * "<html>"+temp.substring(body); return temp; // return
2227 * urlEncode(browser.page().currentFrame().toHtml());
2231 // Insert an image into the editor
2232 private void insertImage(QMimeData mime) {
2233 logger.log(logger.EXTREME, "Entering insertImage");
2234 QImage img = (QImage) mime.imageData();
2235 String script_start = new String(
2236 "document.execCommand('insertHTML', false, '");
2237 String script_end = new String("');");
2239 long now = new Date().getTime();
2240 String path = Global.getFileManager().getResDirPath(
2241 (new Long(now).toString()) + ".jpg");
2243 // This block is just a hack to make sure we wait at least 1ms so we
2245 // have collisions on image names
2246 long i = new Date().getTime();
2248 i = new Date().getTime();
2250 // Open the file & write the data
2251 QFile tfile = new QFile(path);
2252 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
2253 if (!img.save(tfile)) {
2259 Resource newRes = createResource(QUrl.fromLocalFile(path).toString(), 0, "image/jpeg", false);
2262 currentNote.getResources().add(newRes);
2264 // do the actual insert into the note
2265 StringBuffer buffer = new StringBuffer(100);
2266 buffer.append("<img src=\"");
2267 buffer.append(tfile.fileName());
2268 buffer.append("\" en-tag=en-media type=\"image/jpeg\""
2269 +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""
2270 +" guid=\"" +newRes.getGuid() +"\""
2271 +" onContextMenu=\"window.jambi.imageContextMenu(&." +tfile.fileName() +"&.);\""
2274 browser.page().mainFrame().evaluateJavaScript(
2275 script_start + buffer + script_end);
2280 // Handle pasting of a note-to-note link
2281 private void handleNoteLink(QMimeData mime) {
2282 for (int i=0; i<mime.urls().size(); i++) {
2283 StringTokenizer tokens = new StringTokenizer(mime.urls().get(i).toString().replace("evernote:///view/", ""), "/");
2286 String sid = tokens.nextToken();
2287 String lid = tokens.nextToken();
2289 if (!sid.equals(currentNote.getGuid()) && !lid.equals(currentNote.getGuid())) {
2291 Note note = conn.getNoteTable().getNote(sid, false, false, false, false, false);
2293 note = conn.getNoteTable().getNote(lid, false, false, false, false, false);
2298 // If we've gotten this far, we have a bunch of values. We need to build the link.
2299 StringBuffer url = new StringBuffer(100);
2300 String script_start = new String(
2301 "document.execCommand('insertHtml', false, '");
2302 String script_end = new String("');");
2304 url.append("<a href=\""+mime.urls().get(i).toString() +"\" style=\"color:#69aa35\">");
2305 url.append(note.getTitle());
2307 if (mime.urls().size() > 1)
2308 url.append(" ");
2309 browser.page().mainFrame().evaluateJavaScript(
2310 script_start + url + script_end);
2315 // Handle URLs that are trying to be pasted
2316 public void handleUrls(QMimeData mime) {
2317 logger.log(logger.EXTREME, "Starting handleUrls");
2318 FileNameMap fileNameMap = URLConnection.getFileNameMap();
2320 List<QUrl> urlList = mime.urls();
2321 String url = new String();
2322 String script_start = new String(
2323 "document.execCommand('createLink', false, '");
2324 String script_end = new String("');");
2326 for (int i = 0; i < urlList.size(); i++) {
2327 url = urlList.get(i).toString();
2328 // Find out what type of file we have
2329 String mimeType = fileNameMap.getContentTypeFor(url);
2331 // If null returned, we need to guess at the file type
2332 if (mimeType == null)
2333 mimeType = "application/"
2334 + url.substring(url.lastIndexOf(".") + 1);
2336 // Check if we have an image or some other type of file
2337 if (url.substring(0, 5).equalsIgnoreCase("file:")
2338 && mimeType.substring(0, 5).equalsIgnoreCase("image")) {
2339 handleLocalImageURLPaste(mime, mimeType);
2343 boolean smallEnough = checkFileAttachmentSize(url);
2345 && url.substring(0, 5).equalsIgnoreCase("file:")
2346 && !mimeType.substring(0, 5).equalsIgnoreCase("image")) {
2347 handleLocalAttachment(mime, mimeType);
2350 browser.page().mainFrame().evaluateJavaScript(
2351 script_start + url + script_end);
2356 // If a URL being pasted is an image URL, then attach the image
2357 private void handleLocalImageURLPaste(QMimeData mime, String mimeType) {
2358 List<QUrl> urlList = mime.urls();
2359 String url = new String();
2360 String script_start_image = new String(
2361 "document.execCommand('insertHtml', false, '");
2362 String script_end = new String("');");
2363 StringBuffer buffer;
2365 // Copy the image over into the resource directory and create a new resource
2366 // record for each url pasted
2367 for (int i = 0; i < urlList.size(); i++) {
2368 url = urlList.get(i).toString();
2370 Resource newRes = createResource(url, i, mimeType, false);
2373 currentNote.getResources().add(newRes);
2374 buffer = new StringBuffer(100);
2376 // Open the file & write the data
2377 String fileName = Global.getFileManager().getResDirPath(newRes.getGuid());
2378 QFile tfile = new QFile(fileName);
2379 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
2380 tfile.write(newRes.getData().getBody());
2382 buffer.append(script_start_image);
2383 buffer.append("<img src=\"" + FileUtils.toForwardSlashedPath(fileName));
2384 // if (mimeType.equalsIgnoreCase("image/jpg"))
2385 // mimeType = "image/jpeg";
2386 buffer.append("\" en-tag=\"en-media\" type=\"" + mimeType +"\""
2387 +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""
2388 +" guid=\"" +newRes.getGuid() +"\""
2389 +" onContextMenu=\"window.jambi.imageContextMenu('" +tfile.fileName() +"');\""
2391 buffer.append(script_end);
2392 browser.page().mainFrame().evaluateJavaScript(buffer.toString());
2398 // If a URL being pasted is a local file URL, then attach the file
2399 private void handleLocalAttachment(QMimeData mime, String mimeType) {
2400 logger.log(logger.EXTREME, "Attaching local file");
2401 List<QUrl> urlList = mime.urls();
2402 String script_start = new String(
2403 "document.execCommand('insertHtml', false, '");
2404 String script_end = new String("');");
2405 StringBuffer buffer;
2407 String[] type = mimeType.split("/");
2408 String icon = findIcon(type[1]);
2409 if (icon.equals("attachment.png"))
2410 icon = findIcon(type[0]);
2411 buffer = new StringBuffer(100);
2413 for (int i = 0; i < urlList.size(); i++) {
2414 String url = urlList.get(i).toString();
2416 // Start building the HTML
2417 if (icon.equals("attachment.png"))
2418 icon = findIcon(url.substring(url.lastIndexOf(".")+1));
2419 String imageURL = FileUtils.toFileURLString(Global.getFileManager().getImageDirFile(icon));
2421 logger.log(logger.EXTREME, "Creating resource ");
2422 Resource newRes = createResource(url, i, mimeType, true);
2425 logger.log(logger.EXTREME, "New resource size: " +newRes.getData().getSize());
2426 currentNote.getResources().add(newRes);
2428 String fileName = newRes.getGuid() + Global.attachmentNameDelimeter+newRes.getAttributes().getFileName();
2429 // If we have a PDF, we need to setup the preview.
2430 if (icon.equalsIgnoreCase("pdf.png") && Global.pdfPreview()) {
2431 logger.log(logger.EXTREME, "Setting up PDF preview");
2432 if (newRes.getAttributes() != null &&
2433 newRes.getAttributes().getFileName() != null &&
2434 !newRes.getAttributes().getFileName().trim().equals(""))
2435 fileName = newRes.getGuid()+Global.attachmentNameDelimeter+
2436 newRes.getAttributes().getFileName();
2438 fileName = newRes.getGuid()+".pdf";
2439 QFile file = new QFile(Global.getFileManager().getResDirPath(fileName));
2440 QFile.OpenMode mode = new QFile.OpenMode();
2441 mode.set(QFile.OpenModeFlag.WriteOnly);
2443 QDataStream out = new QDataStream(file);
2444 // Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(newRes.getGuid(), true);
2445 QByteArray binData = new QByteArray(newRes.getData().getBody());
2446 // resBinary = null;
2447 out.writeBytes(binData.toByteArray());
2450 PDFPreview pdfPreview = new PDFPreview();
2451 if (pdfPreview.setupPreview(Global.getFileManager().getResDirPath(fileName), "pdf",0)) {
2452 imageURL = file.fileName() + ".png";
2456 logger.log(logger.EXTREME, "Generating link tags");
2457 buffer.delete(0, buffer.length());
2458 buffer.append("<a en-tag=\"en-media\" guid=\"" +newRes.getGuid()+"\" ");
2459 buffer.append(" onContextMenu=\"window.jambi.imageContextMenu('")
2460 .append(Global.getFileManager().getResDirPath(fileName))
2461 .append("');\" ");
2462 buffer.append("type=\"" + mimeType + "\" href=\"nnres://" + fileName +"\" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\" >");
2463 buffer.append("<img src=\"" + imageURL + "\" title=\"" +newRes.getAttributes().getFileName());
2464 buffer.append("\"></img>");
2465 buffer.append("</a>");
2466 browser.page().mainFrame().evaluateJavaScript(
2467 script_start + buffer.toString() + script_end);
2472 private Resource createResource(String url, int sequence, String mime, boolean attachment) {
2473 logger.log(logger.EXTREME, "Inside create resource");
2475 //These two lines are added to handle odd characters in the name like #. Without it
2476 // toLocalFile() chokes and returns the wrong name.
2477 logger.log(logger.EXTREME, "File URL:" +url);
2478 String whichOS = System.getProperty("os.name");
2479 if (whichOS.contains("Windows"))
2480 url = url.replace("file:///", "");
2482 url = url.replace("file://", "");
2483 String urlTest = new QUrl(url).toLocalFile();
2484 logger.log(logger.EXTREME, "File URL toLocalFile():" +urlTest);
2486 if (!urlTest.equals(""))
2488 // url = url.replace("/", File.separator);
2489 logger.log(logger.EXTREME, "Reading from file to create resource:" +url);
2490 resourceFile = new QFile(url);
2491 resourceFile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly));
2492 logger.log(logger.EXTREME, "Error opening file "+url.toString() +": "+resourceFile.errorString());
2493 byte[] fileData = resourceFile.readAll().toByteArray();
2494 resourceFile.close();
2495 logger.log(logger.EXTREME, "File Length: " +fileData.length);
2496 if (fileData.length == 0)
2500 logger.log(logger.EXTREME, "Generating MD5");
2501 md = MessageDigest.getInstance("MD5");
2502 md.update(fileData);
2503 byte[] hash = md.digest();
2505 Resource r = new Resource();
2506 Calendar time = new GregorianCalendar();
2507 long prevTime = time.getTimeInMillis();
2508 while (prevTime == time.getTimeInMillis()) {
2509 time = new GregorianCalendar();
2511 r.setGuid(time.getTimeInMillis()+new Integer(sequence).toString());
2512 r.setNoteGuid(currentNote.getGuid());
2515 r.setUpdateSequenceNum(0);
2516 r.setWidth((short) 0);
2517 r.setHeight((short) 0);
2518 r.setDuration((short) 0);
2520 Data d = new Data();
2521 d.setBody(fileData);
2522 d.setBodyIsSet(true);
2523 d.setBodyHash(hash);
2524 d.setBodyHashIsSet(true);
2526 d.setSize(fileData.length);
2528 int fileNamePos = url.lastIndexOf(File.separator);
2529 if (fileNamePos == -1)
2530 fileNamePos = url.lastIndexOf("/");
2531 String fileName = url.substring(fileNamePos+1);
2532 ResourceAttributes a = new ResourceAttributes();
2534 a.setAltitudeIsSet(false);
2536 a.setLongitudeIsSet(false);
2538 a.setLatitudeIsSet(false);
2539 a.setCameraMake("");
2540 a.setCameraMakeIsSet(false);
2541 a.setCameraModel("");
2542 a.setCameraModelIsSet(false);
2543 a.setAttachment(attachment);
2544 a.setAttachmentIsSet(true);
2545 a.setClientWillIndex(false);
2546 a.setClientWillIndexIsSet(true);
2548 a.setRecoTypeIsSet(false);
2549 a.setSourceURL(url);
2550 a.setSourceURLIsSet(true);
2552 a.setTimestampIsSet(false);
2553 a.setFileName(fileName);
2554 a.setFileNameIsSet(true);
2557 conn.getNoteTable().noteResourceTable.saveNoteResource(r, true);
2558 logger.log(logger.EXTREME, "Resource created");
2560 } catch (NoSuchAlgorithmException e1) {
2561 e1.printStackTrace();
2567 // find the appropriate icon for an attachment
2568 private String findIcon(String appl) {
2569 appl = appl.toLowerCase();
2570 File f = Global.getFileManager().getImageDirFile(appl + ".png");
2573 return "attachment.png";
2578 // Check the file attachment to be sure it isn't over 25 mb
2579 private boolean checkFileAttachmentSize(String url) {
2580 String fileName = url.substring(8);
2581 QFile resourceFile = new QFile(fileName);
2582 resourceFile.open(new QIODevice.OpenMode(
2583 QIODevice.OpenModeFlag.ReadOnly));
2584 long size = resourceFile.size();
2585 resourceFile.close();
2586 size = size / 1024 / 1024;
2587 if (size < 50 && Global.isPremium())
2592 String error = tr("A file attachment may not exceed 25MB.");
2593 QMessageBox.information(this, tr("Attachment Size"), error);
2598 @SuppressWarnings("unused")
2599 private void createdChanged() {
2600 QDateTime dt = new QDateTime();
2601 dt.setDate(createdDate.date());
2602 dt.setTime(createdTime.time());
2603 noteSignal.createdDateChanged.emit(currentNote.getGuid(), dt);
2607 @SuppressWarnings("unused")
2608 private void alteredChanged() {
2609 QDateTime dt = new QDateTime();
2610 dt.setDate(alteredDate.date());
2611 dt.setTime(alteredTime.time());
2612 noteSignal.alteredDateChanged.emit(currentNote.getGuid(), dt);
2615 @SuppressWarnings("unused")
2616 private void subjectDateTimeChanged() {
2617 QDateTime dt = new QDateTime();
2618 dt.setDate(subjectDate.date());
2619 dt.setTime(subjectTime.time());
2620 noteSignal.subjectDateChanged.emit(currentNote.getGuid(), dt);
2624 @SuppressWarnings("unused")
2625 private void sourceUrlChanged() {
2626 noteSignal.sourceUrlChanged.emit(currentNote.getGuid(), urlText.text());
2629 @SuppressWarnings("unused")
2630 private void authorChanged() {
2631 noteSignal.authorChanged.emit(currentNote.getGuid(), authorText.text());
2634 @SuppressWarnings("unused")
2635 private void geoBoxChanged() {
2636 int index = geoBox.currentIndex();
2637 geoBox.setCurrentIndex(0);
2639 GeoDialog box = new GeoDialog();
2640 box.setLongitude(currentNote.getAttributes().getLongitude());
2641 box.setLatitude(currentNote.getAttributes().getLatitude());
2642 box.setAltitude(currentNote.getAttributes().getAltitude());
2644 if (!box.okPressed())
2646 double alt = box.getAltitude();
2647 double lat = box.getLatitude();
2648 double lon = box.getLongitude();
2649 if (alt != currentNote.getAttributes().getAltitude() ||
2650 lon != currentNote.getAttributes().getLongitude() ||
2651 lat != currentNote.getAttributes().getLatitude()) {
2652 noteSignal.geoChanged.emit(currentNote.getGuid(), lon, lat, alt);
2653 currentNote.getAttributes().setAltitude(alt);
2654 currentNote.getAttributes().setLongitude(lon);
2655 currentNote.getAttributes().setLatitude(lat);
2660 noteSignal.geoChanged.emit(currentNote.getGuid(), 0.0, 0.0, 0.0);
2661 currentNote.getAttributes().setAltitude(0.0);
2662 currentNote.getAttributes().setLongitude(0.0);
2663 currentNote.getAttributes().setLatitude(0.0);
2666 if (index == 3 || index == 0) {
2667 QDesktopServices.openUrl(new QUrl("http://maps.google.com/maps?z=6&q="+currentNote.getAttributes().getLatitude() +"," +currentNote.getAttributes().getLongitude()));
2671 // ************************************************************
2672 // * User chose to save an attachment. Pares out the request *
2673 // * into a guid & file. Save the result. *
2674 // ************************************************************
2675 public void downloadAttachment(QNetworkRequest request) {
2677 QFileDialog fd = new QFileDialog(this);
2678 fd.setFileMode(FileMode.AnyFile);
2679 fd.setConfirmOverwrite(true);
2680 fd.setWindowTitle(tr("Save File"));
2681 fd.setAcceptMode(AcceptMode.AcceptSave);
2682 fd.setDirectory(System.getProperty("user.home"));
2683 String name = request.url().toString();
2685 int pos = name.lastIndexOf(Global.attachmentNameDelimeter);
2687 guid = name.substring(0, pos).replace("nnres://", "");
2688 name = name.substring(pos +Global.attachmentNameDelimeter.length());
2689 fd.selectFile(name);
2690 pos = name.lastIndexOf('.');
2692 String mimeType = "(*." + name.substring(pos + 1)
2693 + ");; All Files (*)";
2694 fd.setFilter(tr(mimeType));
2700 // Strip URL prefix and base dir
2701 guid = guid.replace("nnres://", "")
2702 .replace(FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath()), "");
2703 guid = guid.replace("file://", "").replace("/", "")
2704 .replace(FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath()), "");
2706 pos = guid.lastIndexOf('.');
2708 guid = guid.substring(0,pos);
2709 if (fd.exec() != 0 && fd.selectedFiles().size() > 0) {
2710 name = name.replace('\\', '/');
2711 Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
2712 QFile saveFile = new QFile(fd.selectedFiles().get(0));
2713 QFile.OpenMode mode = new QFile.OpenMode();
2714 mode.set(QFile.OpenModeFlag.WriteOnly);
2715 saveFile.open(mode);
2716 QDataStream saveOut = new QDataStream(saveFile);
2717 QByteArray binData = new QByteArray(resBinary.getData().getBody());
2718 saveOut.writeBytes(binData.toByteArray());
2725 // ************************************************************
2726 // * User chose to save an attachment. Pares out the request *
2727 // * into a guid & file. Save the result. --- DONE FROM downloadAttachment now!!!!!
2728 // ************************************************************
2729 public void downloadImage(QNetworkRequest request) {
2730 QFileDialog fd = new QFileDialog(this);
2731 fd.setFileMode(FileMode.AnyFile);
2732 fd.setConfirmOverwrite(true);
2733 fd.setWindowTitle(tr("Save File"));
2734 fd.setAcceptMode(AcceptMode.AcceptSave);
2735 fd.setDirectory(System.getProperty("user.home"));
2736 String name = request.url().toString();
2737 name = name.replace("nnres://", "");
2738 String dPath = FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath());
2739 name = name.replace(dPath, "");
2740 int pos = name.lastIndexOf('.');
2743 String mimeType = "(*." + name.substring(pos + 1)
2744 + ");; All Files (*)";
2745 fd.setFilter(tr(mimeType));
2746 guid = guid.substring(0,pos);
2748 pos = name.lastIndexOf(Global.attachmentNameDelimeter);
2750 guid = name.substring(0, pos);
2751 fd.selectFile(name.substring(pos+Global.attachmentNameDelimeter.length()));
2753 if (fd.exec() != 0 && fd.selectedFiles().size() > 0) {
2754 Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
2755 String fileName = fd.selectedFiles().get(0);
2756 QFile saveFile = new QFile(fileName);
2757 QFile.OpenMode mode = new QFile.OpenMode();
2758 mode.set(QFile.OpenModeFlag.WriteOnly);
2759 saveFile.open(mode);
2760 QDataStream saveOut = new QDataStream(saveFile);
2761 QByteArray binData = new QByteArray(resBinary.getData().getBody());
2762 saveOut.writeBytes(binData.toByteArray());
2768 // *************************************************************
2769 // * decrypt any hidden text. We could do an XML parse, but
2770 // * it is quicker here just to scan for an <img tag & do the fix
2772 // *************************************************************
2773 private void removeEncryption(String id, String plainText, boolean permanent, String slot) {
2775 plainText = " <table class=\"en-crypt-temp\" slot=\""
2778 +"border=1 width=100%><tbody><tr><td>"
2779 +plainText+"</td></tr></tbody></table>";
2782 String html = browser.page().mainFrame().toHtml();
2784 int imagePos = html.indexOf("<img");
2786 for ( ;imagePos>0; ) {
2788 endPos = text.indexOf(">", imagePos);
2789 String tag = text.substring(imagePos-1,endPos);
2790 if (tag.indexOf("id=\""+id+"\"") > -1) {
2791 text = text.substring(0,imagePos) +plainText+text.substring(endPos+1);
2792 QTextCodec codec = QTextCodec.codecForName("UTF-8");
2793 QByteArray unicode = codec.fromUnicode(text);
2794 setContent(unicode);
2798 imagePos = text.indexOf("<img", imagePos+1);
2803 //****************************************************************
2805 //****************************************************************
2806 @SuppressWarnings("unused")
2807 private void focusTitle() {
2808 titleLabel.setFocus();
2810 @SuppressWarnings("unused")
2811 private void focusTag() {
2814 @SuppressWarnings("unused")
2815 private void focusNote() {
2818 @SuppressWarnings("unused")
2819 private void focusAuthor() {
2820 authorLabel.setFocus();
2822 @SuppressWarnings("unused")
2823 private void focusUrl() {
2824 urlLabel.setFocus();
2828 //*****************************************************************
2829 //* Set the document background color
2830 //*****************************************************************
2831 public void setBackgroundColor(String color) {
2832 String js = "function changeBackground(color) {"
2833 +"document.body.style.background = color;"
2835 +"changeBackground('" +color+"');";
2836 browser.page().mainFrame().evaluateJavaScript(js);
2841 //****************************************************************
2842 //* MicroFocus changed
2843 //****************************************************************
2844 private void microFocusChanged() {
2845 boldButton.setDown(false);
2846 italicButton.setDown(false);
2847 underlineButton.setDown(false);
2848 browser.openAction.setEnabled(false);
2849 browser.downloadAttachment.setEnabled(false);
2850 browser.downloadImage.setEnabled(false);
2851 browser.rotateImageLeft.setEnabled(false);
2852 browser.rotateImageRight.setEnabled(false);
2853 browser.insertTableAction.setEnabled(true);
2854 browser.deleteTableColumnAction.setEnabled(false);
2855 browser.insertTableRowAction.setEnabled(false);
2856 browser.insertTableColumnAction.setEnabled(false);
2857 browser.deleteTableRowAction.setEnabled(false);
2858 browser.insertLinkAction.setText(tr("Insert Hyperlink"));
2859 insertHyperlink = true;
2860 browser.insertQuickLinkAction.setEnabled(true);
2861 currentHyperlink ="";
2863 insideTable = false;
2864 insideEncryption = false;
2865 forceTextPaste = false;
2867 String js = new String( "function getCursorPos() {"
2869 +"if (window.getSelection) {"
2870 +" var selObj = window.getSelection();"
2871 +" var selRange = selObj.getRangeAt(0);"
2872 +" var workingNode = window.getSelection().anchorNode.parentNode;"
2873 +" while(workingNode != null) { "
2874 // +" window.jambi.printNode(workingNode.nodeName);"
2875 +" if (workingNode.nodeName=='TABLE') { if (workingNode.getAttribute('class').toLowerCase() == 'en-crypt-temp') window.jambi.insideEncryption(); }"
2876 +" if (workingNode.nodeName=='B') window.jambi.boldActive();"
2877 +" if (workingNode.nodeName=='I') window.jambi.italicActive();"
2878 +" if (workingNode.nodeName=='U') window.jambi.underlineActive();"
2879 +" if (workingNode.nodeName=='UL') window.jambi.setInsideList();"
2880 +" if (workingNode.nodeName=='OL') window.jambi.setInsideList();"
2881 +" if (workingNode.nodeName=='LI') window.jambi.setInsideList();"
2882 +" if (workingNode.nodeName=='TBODY') window.jambi.setInsideTable();"
2883 +" 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);}}"
2884 +" if (workingNode.nodeName=='SPAN') {"
2885 +" if (workingNode.getAttribute('style') == 'text-decoration: underline;') window.jambi.underlineActive();"
2887 +" workingNode = workingNode.parentNode;"
2890 +"} getCursorPos();");
2891 browser.page().mainFrame().evaluateJavaScript(js);
2894 public void printNode(String n) {
2895 System.out.println("Node Vaule: " +n);
2898 public void insideEncryption() {
2899 insideEncryption = true;
2903 //****************************************************************
2904 //* Insert a table row
2905 //****************************************************************
2906 public void insertTableRow() {
2908 String js = new String( "function insertTableRow() {"
2909 +" var selObj = window.getSelection();"
2910 +" var selRange = selObj.getRangeAt(0);"
2911 +" var workingNode = window.getSelection().anchorNode.parentNode;"
2912 +" var cellCount = 0;"
2913 +" while(workingNode != null) { "
2914 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
2915 +" row = document.createElement('TR');"
2916 +" var nodes = workingNode.getElementsByTagName('td');"
2917 +" for (j=0; j<nodes.length; j=j+1) {"
2918 +" cell = document.createElement('TD');"
2919 +" cell.innerHTML=' ';"
2920 +" row.appendChild(cell);"
2922 +" workingNode.parentNode.insertBefore(row,workingNode.nextSibling);"
2925 +" workingNode = workingNode.parentNode;"
2927 +"} insertTableRow();");
2928 browser.page().mainFrame().evaluateJavaScript(js);
2932 public void insertTableColumn() {
2933 String js = new String( "function insertTableColumn() {"
2934 +" var selObj = window.getSelection();"
2935 +" var selRange = selObj.getRangeAt(0);"
2936 +" var workingNode = window.getSelection().anchorNode.parentNode;"
2937 +" var current = 0;"
2938 +" while (workingNode.nodeName.toLowerCase() != 'table' && workingNode != null) {"
2939 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
2940 +" var td = workingNode;"
2941 +" while (td.previousSibling != null) { "
2942 +" current = current+1; td = td.previousSibling;"
2945 +" workingNode = workingNode.parentNode; "
2947 +" if (workingNode == null) return;"
2948 +" for (var i=0; i<workingNode.rows.length; i++) { "
2949 +" var cell = workingNode.rows[i].insertCell(current+1); "
2950 +" cell.innerHTML = ' '; "
2952 +"} insertTableColumn();");
2953 browser.page().mainFrame().evaluateJavaScript(js);
2957 //****************************************************************
2958 //* Delete a table row
2959 //****************************************************************
2960 public void deleteTableRow() {
2962 String js = new String( "function deleteTableRow() {"
2963 +" var selObj = window.getSelection();"
2964 +" var selRange = selObj.getRangeAt(0);"
2965 +" var workingNode = window.getSelection().anchorNode.parentNode;"
2966 +" var cellCount = 0;"
2967 +" while(workingNode != null) { "
2968 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
2969 +" workingNode.parentNode.removeChild(workingNode);"
2972 +" workingNode = workingNode.parentNode;"
2974 +"} deleteTableRow();");
2975 browser.page().mainFrame().evaluateJavaScript(js);
2979 public void deleteTableColumn() {
2980 String js = new String( "function deleteTableColumn() {"
2981 +" var selObj = window.getSelection();"
2982 +" var selRange = selObj.getRangeAt(0);"
2983 +" var workingNode = window.getSelection().anchorNode.parentNode;"
2984 +" var current = 0;"
2985 +" while (workingNode.nodeName.toLowerCase() != 'table' && workingNode != null) {"
2986 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
2987 +" var td = workingNode;"
2988 +" while (td.previousSibling != null) { "
2989 +" current = current+1; td = td.previousSibling;"
2992 +" workingNode = workingNode.parentNode; "
2994 +" if (workingNode == null) return;"
2995 +" for (var i=0; i<workingNode.rows.length; i++) { "
2996 +" workingNode.rows[i].deleteCell(current); "
2998 +"} deleteTableColumn();");
2999 browser.page().mainFrame().evaluateJavaScript(js);
3004 public void setInsideTable() {
3005 browser.insertTableRowAction.setEnabled(true);
3006 browser.insertTableColumnAction.setEnabled(true);
3007 browser.deleteTableRowAction.setEnabled(true);
3008 browser.deleteTableColumnAction.setEnabled(true);
3009 browser.insertTableAction.setEnabled(false);
3010 browser.encryptAction.setEnabled(false);
3014 public void setInsideLink(String link) {
3015 browser.insertLinkAction.setText(tr("Edit Hyperlink"));
3016 currentHyperlink = link;
3017 insertHyperlink = false;
3020 public void italicActive() {
3021 italicButton.setDown(true);
3023 public void boldActive() {
3024 boldButton.setDown(true);
3026 public void underlineActive() {
3027 underlineButton.setDown(true);
3029 public void forceTextPaste() {
3030 forceTextPaste = true;
3032 public void imageContextMenu(String f) {
3033 browser.downloadImage.setEnabled(true);
3034 browser.rotateImageRight.setEnabled(true);
3035 browser.rotateImageLeft.setEnabled(true);
3036 browser.openAction.setEnabled(true);
3039 public void rotateImageRight() {
3040 QWebSettings.setMaximumPagesInCache(0);
3041 QWebSettings.setObjectCacheCapacities(0, 0, 0);
3042 QImage image = new QImage(selectedFile);
3043 QMatrix matrix = new QMatrix();
3044 matrix.rotate( 90.0 );
3045 image = image.transformed(matrix);
3046 image.save(selectedFile);
3047 QWebSettings.setMaximumPagesInCache(0);
3048 QWebSettings.setObjectCacheCapacities(0, 0, 0);
3049 browser.setHtml(browser.page().mainFrame().toHtml());
3052 resourceSignal.contentChanged.emit(selectedFile);
3055 public void rotateImageLeft() {
3056 QImage image = new QImage(selectedFile);
3057 QMatrix matrix = new QMatrix();
3058 matrix.rotate( -90.0 );
3059 image = image.transformed(matrix);
3060 image.save(selectedFile);
3061 browser.setHtml(browser.page().mainFrame().toHtml());
3064 resourceSignal.contentChanged.emit(selectedFile);
3066 public void resourceContextMenu(String f) {
3067 browser.downloadAttachment.setEnabled(true);
3068 browser.openAction.setEnabled(true);
3071 public void latexContextMenu(String f) {
3072 browser.downloadImage.setEnabled(true);
3073 browser.rotateImageRight.setEnabled(true);
3074 browser.rotateImageLeft.setEnabled(true);
3075 browser.openAction.setEnabled(true);
3079 //****************************************************************
3080 //* Apply CSS style to specified word
3081 //****************************************************************
3082 /* public void applyStyleToWords(String word, String style) {
3083 QFile script = new QFile("D:\\NeverNote\\js\\hilight1.js");
3084 script.open(OpenModeFlag.ReadOnly);
3085 String s = script.readAll().toString();
3086 String js = new String(s +" findit('"+word+"', '"+style+"');");
3087 browser.page().mainFrame().evaluateJavaScript(js);
3088 System.out.println(getContent());
3091 //****************************************************************
3092 //* Someone tried to paste a resource between notes, so we need *
3093 //* to do some special handling. *
3094 //****************************************************************
3095 private String fixInternotePaste(String text) {
3096 logger.log(logger.EXTREME, "Fixing internote paste");
3097 String returnValue = fixInternotePasteSearch(text, "<img", "src=\"");
3098 return fixInternotePasteSearch(returnValue, "<a", "href=\"nnres://");
3100 private String fixInternotePasteSearch(String text, String type, String locTag) {
3102 // First, let's fix the images.
3103 int startPos = text.indexOf(type);
3105 for (; startPos>=0;) {
3106 endPos = text.indexOf(">", startPos+1);
3107 String segment = text.substring(startPos, endPos);
3108 if (segment.indexOf("en-tag") > -1) {
3109 String newSegment = segment;
3111 int guidStartPos = segment.indexOf("guid=\"");
3112 int guidEndPos = segment.indexOf("\"", guidStartPos+7);
3113 String guid = segment.substring(guidStartPos+6,guidEndPos);
3115 int mimeStartPos = segment.indexOf("type");
3116 int mimeEndPos = segment.indexOf("\"", mimeStartPos+7);
3117 String mime = segment.substring(mimeStartPos+6,mimeEndPos);
3119 int srcStartPos = segment.indexOf("src");
3120 int srcEndPos = segment.indexOf("\"", srcStartPos+6);
3121 String src = segment.substring(srcStartPos+5,srcEndPos);
3123 Calendar currentTime = new GregorianCalendar();
3124 Long l = new Long(currentTime.getTimeInMillis());
3126 while (l==prevTime) {
3127 currentTime = new GregorianCalendar();
3128 l= new Long(currentTime.getTimeInMillis());
3131 Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
3132 // if r==null, then the image doesn't exist (it was probably cut out of another note, so
3133 // we need to recereate it
3135 r = createResource(src, 1, mime, false);
3139 String randint = new String(Long.toString(l));
3140 String extension = null;
3141 if (r.getMime()!= null) {
3142 extension = r.getMime().toLowerCase();
3143 if (extension.indexOf("/")>-1)
3144 extension = extension.substring(extension.indexOf("/")+1);
3146 String newFile = randint;
3147 if (r.getAttributes().getFileName() != null && r.getAttributes().getFileName() != "")
3148 if (!locTag.startsWith("src"))
3149 newFile = newFile+Global.attachmentNameDelimeter+r.getAttributes().getFileName();
3150 r.setNoteGuid(currentNote.getGuid());
3153 conn.getNoteTable().noteResourceTable.saveNoteResource(r, true);
3154 QFile f = new QFile(Global.getFileManager().getResDirPath(newFile));
3155 QByteArray bin = new QByteArray(r.getData().getBody());
3156 f.open(QFile.OpenModeFlag.WriteOnly);
3159 newSegment = newSegment.replace("guid=\""+guid, "guid=\""+randint);
3160 currentNote.getResources().add(r);
3162 int startSrcPos = newSegment.indexOf(locTag);
3163 int endSrcPos = newSegment.indexOf("\"",startSrcPos+locTag.length()+1);
3165 if (locTag.startsWith("src")) {
3166 source = newSegment.substring(startSrcPos+locTag.length(),endSrcPos);
3167 newSegment = newSegment.replace(source,
3168 FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath(newFile)));
3170 source = newSegment.substring(startSrcPos+locTag.length(),endSrcPos);
3171 newSegment = newSegment.replace(source, newFile);
3174 text = text.substring(0,startPos) + newSegment + text.substring(endPos);
3176 startPos = text.indexOf(type, startPos+1);
3182 public void nextPage(String file) {
3183 logger.log(logger.EXTREME, "Starting nextPage()");
3186 if (previewPageList.containsKey(file))
3187 pageNumber = previewPageList.get(file)+1;
3190 previewPageList.remove(file);
3191 previewPageList.put(file, pageNumber);
3192 PDFPreview pdfPreview = new PDFPreview();
3193 boolean goodPreview = pdfPreview.setupPreview(file, "pdf", pageNumber);
3196 // String html = getContent();
3197 QWebSettings.setMaximumPagesInCache(0);
3198 QWebSettings.setObjectCacheCapacities(0, 0, 0);
3199 // browser.setContent(new QByteArray());
3200 browser.setHtml(browser.page().mainFrame().toHtml());
3202 // browser.setContent(new QByteArray(html));
3203 // browser.triggerPageAction(WebAction.Reload);
3204 // pdfMouseOver(selectedFile);
3208 public void previousPage(String file) {
3209 logger.log(logger.EXTREME, "Starting previousPage()");
3212 if (previewPageList.containsKey(file))
3213 pageNumber = previewPageList.get(file)-1;
3216 previewPageList.remove(file);
3217 previewPageList.put(file, pageNumber);
3218 PDFPreview pdfPreview = new PDFPreview();
3219 boolean goodPreview = pdfPreview.setupPreview(file, "pdf", pageNumber);
3222 // String html = getContent();
3223 QWebSettings.setMaximumPagesInCache(0);
3224 QWebSettings.setObjectCacheCapacities(0, 0, 0);
3225 browser.setHtml(browser.page().mainFrame().toHtml());
3227 // browser.setContent(new QByteArray(html));
3228 // browser.triggerPageAction(WebAction.Reload);
3232 /* public void pdfMouseOver(String name) {
3234 if (previewPageList.containsKey(selectedFile))
3235 pageNumber = previewPageList.get(selectedFile)+1;
3239 if (pageNumber <= 1)
3240 browser.previousPageAction.setEnabled(false);
3242 browser.previousPageAction.setEnabled(true);
3244 PDFPreview pdf = new PDFPreview();
3245 int totalPages = pdf.getPageCount(name);
3246 if (previewPageList.containsKey(selectedFile))
3247 pageNumber = previewPageList.get(selectedFile)+1;
3250 if (totalPages > pageNumber)
3251 browser.nextPageAction.setEnabled(true);
3253 browser.nextPageAction.setEnabled(false);
3257 public void pdfMouseOut() {
3258 // browser.nextPageAction.setVisible(false);
3259 // browser.previousPageAction.setVisible(false);
3263 @SuppressWarnings("unused")
3264 private void toggleUndoVisible(Boolean toggle) {
3265 undoAction.setVisible(toggle);
3266 Global.saveEditorButtonsVisible("undo", toggle);
3268 @SuppressWarnings("unused")
3269 private void toggleRedoVisible(Boolean toggle) {
3270 redoAction.setVisible(toggle);
3271 Global.saveEditorButtonsVisible("redo", toggle);
3273 @SuppressWarnings("unused")
3274 private void toggleCutVisible(Boolean toggle) {
3275 cutAction.setVisible(toggle);
3276 Global.saveEditorButtonsVisible("cut", toggle);
3278 @SuppressWarnings("unused")
3279 private void toggleCopyVisible(Boolean toggle) {
3280 copyAction.setVisible(toggle);
3281 Global.saveEditorButtonsVisible("copy", toggle);
3283 @SuppressWarnings("unused")
3284 private void togglePasteVisible(Boolean toggle) {
3285 pasteAction.setVisible(toggle);
3286 Global.saveEditorButtonsVisible("paste", toggle);
3288 @SuppressWarnings("unused")
3289 private void toggleBoldVisible(Boolean toggle) {
3290 boldAction.setVisible(toggle);
3291 Global.saveEditorButtonsVisible("bold", toggle);
3293 @SuppressWarnings("unused")
3294 private void toggleItalicVisible(Boolean toggle) {
3295 italicAction.setVisible(toggle);
3296 Global.saveEditorButtonsVisible("italic", toggle);
3298 @SuppressWarnings("unused")
3299 private void toggleUnderlineVisible(Boolean toggle) {
3300 underlineAction.setVisible(toggle);
3301 Global.saveEditorButtonsVisible("underline", toggle);
3303 @SuppressWarnings("unused")
3304 private void toggleStrikethroughVisible(Boolean toggle) {
3305 strikethroughAction.setVisible(toggle);
3306 Global.saveEditorButtonsVisible("strikethrough", toggle);
3308 @SuppressWarnings("unused")
3309 private void toggleLeftAlignVisible(Boolean toggle) {
3310 leftAlignAction.setVisible(toggle);
3311 Global.saveEditorButtonsVisible("alignLeft", toggle);
3313 @SuppressWarnings("unused")
3314 private void toggleRightAlignVisible(Boolean toggle) {
3315 rightAlignAction.setVisible(toggle);
3316 Global.saveEditorButtonsVisible("alignRight", toggle);
3318 @SuppressWarnings("unused")
3319 private void toggleCenterAlignVisible(Boolean toggle) {
3320 centerAlignAction.setVisible(toggle);
3321 Global.saveEditorButtonsVisible("alignCenter", toggle);
3323 @SuppressWarnings("unused")
3324 private void toggleHLineVisible(Boolean toggle) {
3325 hlineAction.setVisible(toggle);
3326 Global.saveEditorButtonsVisible("hline", toggle);
3328 @SuppressWarnings("unused")
3329 private void toggleIndentVisible(Boolean toggle) {
3330 indentAction.setVisible(toggle);
3331 Global.saveEditorButtonsVisible("indent", toggle);
3333 @SuppressWarnings("unused")
3334 private void toggleTodoVisible(Boolean toggle) {
3335 todoAction.setVisible(toggle);
3336 Global.saveEditorButtonsVisible("todo", toggle);
3338 @SuppressWarnings("unused")
3339 private void toggleOutdentVisible(Boolean toggle) {
3340 outdentAction.setVisible(toggle);
3341 Global.saveEditorButtonsVisible("outdent", toggle);
3343 @SuppressWarnings("unused")
3344 private void toggleBulletListVisible(Boolean toggle) {
3345 bulletListAction.setVisible(toggle);
3346 Global.saveEditorButtonsVisible("bulletList", toggle);
3348 @SuppressWarnings("unused")
3349 private void toggleNumberListVisible(Boolean toggle) {
3350 numberListAction.setVisible(toggle);
3351 Global.saveEditorButtonsVisible("numberList", toggle);
3353 @SuppressWarnings("unused")
3354 private void toggleFontListVisible(Boolean toggle) {
3355 fontListAction.setVisible(toggle);
3356 Global.saveEditorButtonsVisible("font", toggle);
3358 @SuppressWarnings("unused")
3359 private void toggleFontColorVisible(Boolean toggle) {
3360 fontColorAction.setVisible(toggle);
3361 Global.saveEditorButtonsVisible("fontColor", toggle);
3363 @SuppressWarnings("unused")
3364 private void toggleFontSizeVisible(Boolean toggle) {
3365 fontSizeAction.setVisible(toggle);
3366 Global.saveEditorButtonsVisible("fontSize", toggle);
3368 @SuppressWarnings("unused")
3369 private void toggleFontHilightVisible(Boolean toggle) {
3370 fontHilightAction.setVisible(toggle);
3371 Global.saveEditorButtonsVisible("fontHilight", toggle);
3373 @SuppressWarnings("unused")
3374 private void toggleSpellCheckVisible(Boolean toggle) {
3375 spellCheckAction.setVisible(toggle);
3376 Global.saveEditorButtonsVisible("spellCheck", toggle);
3380 private void setupDictionary() {
3381 File wordList = new File(Global.getFileManager().getSpellDirPath()+Locale.getDefault()+".dic");
3383 dictionary = new SpellDictionaryHashMap(wordList);
3384 spellChecker = new SpellChecker(dictionary);
3387 userWordList = new File(Global.getFileManager().getSpellDirPathUser()+"user.dic");
3389 // Get the local user spell dictionary
3391 userDictionary = new SpellDictionaryHashMap(userWordList);
3392 } catch (FileNotFoundException e) {
3393 userWordList.createNewFile();
3394 userDictionary = new SpellDictionaryHashMap(userWordList);
3395 } catch (IOException e) {
3396 userWordList.createNewFile();
3397 userDictionary = new SpellDictionaryHashMap(userWordList);
3400 spellListener = new SuggestionListener(this, spellChecker);
3402 // Add the user dictionary
3403 spellChecker.addSpellCheckListener(spellListener);
3404 spellChecker.setUserDictionary(userDictionary);
3406 } catch (FileNotFoundException e) {
3407 QMessageBox.critical(this, tr("Spell Check Error"),
3408 tr("Dictionary ")+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+
3409 tr(".dic was not found."));
3410 } catch (IOException e) {
3411 QMessageBox.critical(this, tr("Spell Check Error"),
3412 tr("Dictionary ")+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+
3413 tr(".dic is invalid."));
3418 // Invoke spell checker dialog
3419 @SuppressWarnings("unused")
3420 private void spellCheckClicked() {
3422 if (spellChecker == null) {
3426 // Read user settings
3427 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREDIGITWORDS,
3428 Global.getSpellSetting(Configuration.SPELL_IGNOREDIGITWORDS));
3429 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREINTERNETADDRESSES,
3430 Global.getSpellSetting(Configuration.SPELL_IGNOREINTERNETADDRESSES));
3431 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREMIXEDCASE,
3432 Global.getSpellSetting(Configuration.SPELL_IGNOREMIXEDCASE));
3433 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREUPPERCASE,
3434 Global.getSpellSetting(Configuration.SPELL_IGNOREUPPERCASE));
3435 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNORESENTENCECAPITALIZATION,
3436 Global.getSpellSetting(Configuration.SPELL_IGNORESENTENCECAPITALIZATION));
3438 spellListener.abortSpellCheck = false;
3439 spellListener.errorsFound = false;
3440 String content = getBrowser().page().mainFrame().toPlainText();
3441 StringWordTokenizer tokenizer = new StringWordTokenizer(content);
3442 if (!tokenizer.hasMoreWords())
3444 getBrowser().page().action(WebAction.MoveToStartOfDocument);
3446 getBrowser().setFocus();
3449 // Move to the start of page
3450 KeyboardModifiers ctrl = new KeyboardModifiers(KeyboardModifier.ControlModifier.value());
3451 QKeyEvent home = new QKeyEvent(Type.KeyPress, Key.Key_Home.value(), ctrl);
3452 browser.keyPressEvent(home);
3453 getBrowser().setFocus();
3455 tokenizer = new StringWordTokenizer(content);
3458 while(tokenizer.hasMoreWords()) {
3459 word = tokenizer.nextWord();
3460 found = getBrowser().page().findText(word);
3461 if (found && !spellListener.abortSpellCheck) {
3462 spellChecker.checkSpelling(new StringWordTokenizer(word));
3463 getBrowser().setFocus();
3467 // Go to the end of the document & finish up.
3468 home = new QKeyEvent(Type.KeyPress, Key.Key_End.value(), ctrl);
3469 browser.keyPressEvent(home);
3470 if (!spellListener.errorsFound)
3471 QMessageBox.information(this, tr("Spell Check Complete"),
3472 tr("No Errors Found"));
3477 @SuppressWarnings("unused")
3478 private void sourceEdited() {
3479 QTextCodec codec = QTextCodec.codecForLocale();
3480 codec = QTextCodec.codecForName("UTF-8");
3481 String content = codec.fromUnicode(sourceEdit.toHtml()).toString();
3482 content = StringEscapeUtils.unescapeHtml4(removeTags(content));
3483 QByteArray data = new QByteArray(sourceEditHeader+content+"</body></html>");
3484 getBrowser().setContent(data);
3486 if (currentNote != null && sourceEdit != null)
3487 noteSignal.noteChanged.emit(currentNote.getGuid(), sourceEdit.toPlainText());
3490 private void setSource() {
3491 String text = getContent();
3492 sourceEdit.blockSignals(true);
3493 int body = text.indexOf("<body");
3495 body = text.indexOf(">",body);
3497 sourceEditHeader =text.substring(0, body+1);
3498 text = text.substring(body+1);
3501 text = text.replace("</body></html>", "");
3502 sourceEdit.setPlainText(text);
3503 sourceEdit.setReadOnly(!getBrowser().page().isContentEditable());
3504 //syntaxHighlighter.rehighlight();
3505 sourceEdit.blockSignals(false);
3508 // show/hide view source window
3509 public void showSource(boolean value) {
3511 sourceEdit.setVisible(value);
3515 private String removeTags(String text) {
3516 StringBuffer buffer = new StringBuffer(text);
3517 boolean inTag = false;
3518 int bodyPosition = text.indexOf("<body");
3519 for (int i=buffer.length()-1; i>=0; i--) {
3520 if (buffer.charAt(i) == '>')
3522 if (buffer.charAt(i) == '<')
3524 if (inTag || buffer.charAt(i) == '<' || i<bodyPosition)
3525 buffer.deleteCharAt(i);
3528 return buffer.toString();