2 * This file is part of NeverNote
\r
3 * Copyright 2009 Randy Baumgarte
\r
5 * This file may be licensed under the terms of of the
\r
6 * GNU General Public License Version 2 (the ``GPL'').
\r
8 * Software distributed under the License is distributed
\r
9 * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
\r
10 * express or implied. See the GPL for the specific language
\r
11 * governing rights and limitations.
\r
13 * You should have received a copy of the GPL along with this
\r
14 * program. If not, go to http://www.gnu.org/licenses/gpl.html
\r
15 * or write to the Free Software Foundation, Inc.,
\r
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
\r
20 package cx.fbn.nevernote.gui;
\r
22 import java.io.File;
\r
23 import java.io.FileNotFoundException;
\r
24 import java.io.IOException;
\r
25 import java.net.FileNameMap;
\r
26 import java.net.URI;
\r
27 import java.net.URLConnection;
\r
28 import java.security.MessageDigest;
\r
29 import java.security.NoSuchAlgorithmException;
\r
30 import java.text.SimpleDateFormat;
\r
31 import java.util.ArrayList;
\r
32 import java.util.Calendar;
\r
33 import java.util.Collections;
\r
34 import java.util.Date;
\r
35 import java.util.GregorianCalendar;
\r
36 import java.util.HashMap;
\r
37 import java.util.List;
\r
38 import java.util.Locale;
\r
40 import org.apache.commons.lang.StringUtils;
\r
42 import com.evernote.edam.limits.Constants;
\r
43 import com.evernote.edam.type.Data;
\r
44 import com.evernote.edam.type.Note;
\r
45 import com.evernote.edam.type.Notebook;
\r
46 import com.evernote.edam.type.Resource;
\r
47 import com.evernote.edam.type.ResourceAttributes;
\r
48 import com.evernote.edam.type.Tag;
\r
49 import com.swabunga.spell.engine.SpellDictionary;
\r
50 import com.swabunga.spell.engine.SpellDictionaryHashMap;
\r
51 import com.swabunga.spell.engine.Word;
\r
52 import com.swabunga.spell.event.SpellCheckEvent;
\r
53 import com.swabunga.spell.event.SpellCheckListener;
\r
54 import com.swabunga.spell.event.SpellChecker;
\r
55 import com.swabunga.spell.event.StringWordTokenizer;
\r
56 import com.trolltech.qt.core.QByteArray;
\r
57 import com.trolltech.qt.core.QDataStream;
\r
58 import com.trolltech.qt.core.QDateTime;
\r
59 import com.trolltech.qt.core.QEvent;
\r
60 import com.trolltech.qt.core.QEvent.Type;
\r
61 import com.trolltech.qt.core.QFile;
\r
62 import com.trolltech.qt.core.QFileSystemWatcher;
\r
63 import com.trolltech.qt.core.QIODevice;
\r
64 import com.trolltech.qt.core.QMimeData;
\r
65 import com.trolltech.qt.core.QUrl;
\r
66 import com.trolltech.qt.core.Qt.Key;
\r
67 import com.trolltech.qt.core.Qt.KeyboardModifier;
\r
68 import com.trolltech.qt.core.Qt.KeyboardModifiers;
\r
69 import com.trolltech.qt.gui.QAction;
\r
70 import com.trolltech.qt.gui.QApplication;
\r
71 import com.trolltech.qt.gui.QCalendarWidget;
\r
72 import com.trolltech.qt.gui.QClipboard;
\r
73 import com.trolltech.qt.gui.QColor;
\r
74 import com.trolltech.qt.gui.QComboBox;
\r
75 import com.trolltech.qt.gui.QDateEdit;
\r
76 import com.trolltech.qt.gui.QDesktopServices;
\r
77 import com.trolltech.qt.gui.QFileDialog;
\r
78 import com.trolltech.qt.gui.QFileDialog.AcceptMode;
\r
79 import com.trolltech.qt.gui.QFileDialog.FileMode;
\r
80 import com.trolltech.qt.gui.QFontDatabase;
\r
81 import com.trolltech.qt.gui.QFormLayout;
\r
82 import com.trolltech.qt.gui.QGridLayout;
\r
83 import com.trolltech.qt.gui.QHBoxLayout;
\r
84 import com.trolltech.qt.gui.QIcon;
\r
85 import com.trolltech.qt.gui.QImage;
\r
86 import com.trolltech.qt.gui.QKeyEvent;
\r
87 import com.trolltech.qt.gui.QKeySequence;
\r
88 import com.trolltech.qt.gui.QLabel;
\r
89 import com.trolltech.qt.gui.QLineEdit;
\r
90 import com.trolltech.qt.gui.QListWidgetItem;
\r
91 import com.trolltech.qt.gui.QMatrix;
\r
92 import com.trolltech.qt.gui.QMessageBox;
\r
93 import com.trolltech.qt.gui.QPushButton;
\r
94 import com.trolltech.qt.gui.QShortcut;
\r
95 import com.trolltech.qt.gui.QTimeEdit;
\r
96 import com.trolltech.qt.gui.QToolButton;
\r
97 import com.trolltech.qt.gui.QToolButton.ToolButtonPopupMode;
\r
98 import com.trolltech.qt.gui.QVBoxLayout;
\r
99 import com.trolltech.qt.gui.QWidget;
\r
100 import com.trolltech.qt.network.QNetworkRequest;
\r
101 import com.trolltech.qt.webkit.QWebPage;
\r
102 import com.trolltech.qt.webkit.QWebPage.WebAction;
\r
103 import com.trolltech.qt.webkit.QWebSettings;
\r
104 import com.trolltech.qt.webkit.QWebView;
\r
106 import cx.fbn.nevernote.Global;
\r
107 import cx.fbn.nevernote.dialog.EnCryptDialog;
\r
108 import cx.fbn.nevernote.dialog.EnDecryptDialog;
\r
109 import cx.fbn.nevernote.dialog.GeoDialog;
\r
110 import cx.fbn.nevernote.dialog.InsertLinkDialog;
\r
111 import cx.fbn.nevernote.dialog.SpellCheck;
\r
112 import cx.fbn.nevernote.dialog.TableDialog;
\r
113 import cx.fbn.nevernote.dialog.TagAssign;
\r
114 import cx.fbn.nevernote.evernote.EnCrypt;
\r
115 import cx.fbn.nevernote.signals.NoteResourceSignal;
\r
116 import cx.fbn.nevernote.signals.NoteSignal;
\r
117 import cx.fbn.nevernote.sql.DatabaseConnection;
\r
118 import cx.fbn.nevernote.utilities.ApplicationLogger;
\r
119 import cx.fbn.nevernote.utilities.FileUtils;
\r
121 public class BrowserWindow extends QWidget {
\r
123 public final QLineEdit titleLabel;
\r
124 private final QLineEdit urlText;
\r
125 private final QLabel authorLabel;
\r
126 private final QLineEdit authorText;
\r
127 private final QComboBox geoBox;
\r
128 public final TagLineEdit tagEdit;
\r
129 public final QLabel tagLabel;
\r
130 private final QPushButton urlLabel;
\r
131 private final QLabel alteredLabel;
\r
132 private final QDateEdit alteredDate;
\r
133 private final QTimeEdit alteredTime;
\r
134 private final QDateEdit createdDate;
\r
135 private final QTimeEdit createdTime;
\r
136 private final QLabel subjectLabel;
\r
137 private final QDateEdit subjectDate;
\r
138 private final QTimeEdit subjectTime;
\r
139 public final QComboBox notebookBox;
\r
140 private final QLabel notebookLabel;
\r
141 private final QLabel createdLabel;
\r
142 public final QComboBox fontSize;
\r
143 public final QAction fontSizeAction;
\r
144 private boolean extendedOn;
\r
145 public boolean buttonsVisible;
\r
146 private final String iconPath = new String("classpath:cx/fbn/nevernote/icons/");
\r
147 private final ContentView browser;
\r
148 private List<Tag> allTags;
\r
149 private List<String> currentTags;
\r
150 public NoteSignal noteSignal;
\r
151 private List<Notebook> notebookList;
\r
152 private Note currentNote;
\r
153 private String saveNoteTitle;
\r
154 private String saveTagList;
\r
155 private boolean insideList;
\r
156 // private String selectedText;
\r
157 private final DatabaseConnection conn;
\r
158 private final QCalendarWidget createdCalendarWidget;
\r
159 private final QCalendarWidget alteredCalendarWidget;
\r
160 private final QCalendarWidget subjectCalendarWidget;
\r
162 public final QPushButton undoButton;
\r
163 public final QAction undoAction;
\r
164 public final QPushButton redoButton;
\r
165 public final QAction redoAction;
\r
166 public final QPushButton cutButton;
\r
167 public final QAction cutAction;
\r
168 public final QPushButton copyButton;
\r
169 public final QAction copyAction;
\r
170 public final QPushButton pasteButton;
\r
171 public final QAction pasteAction;
\r
172 public final QPushButton boldButton;
\r
173 public final QAction boldAction;
\r
174 public final QPushButton underlineButton;
\r
175 public final QAction underlineAction;
\r
176 public final QPushButton italicButton;
\r
177 public final QAction italicAction;
\r
178 public final Signal0 focusLost;
\r
179 public final NoteResourceSignal resourceSignal;
\r
181 public QPushButton rightAlignButton;
\r
182 public final QAction rightAlignAction;
\r
183 public QPushButton leftAlignButton;
\r
184 public final QAction leftAlignAction;
\r
185 public QPushButton centerAlignButton;
\r
186 public final QAction centerAlignAction;
\r
188 public final QPushButton strikethroughButton;
\r
189 public final QAction strikethroughAction;
\r
190 public final QPushButton hlineButton;
\r
191 public final QAction hlineAction;
\r
192 public final QPushButton indentButton;
\r
193 public final QAction indentAction;
\r
194 public final QPushButton outdentButton;
\r
195 public final QAction outdentAction;
\r
196 public final QPushButton bulletListButton;
\r
197 public final QAction bulletListAction;
\r
198 public final QPushButton numberListButton;
\r
199 public final QAction numberListAction;
\r
200 public final QPushButton spellCheckButton;
\r
201 public final QAction spellCheckAction;
\r
202 public final QPushButton todoButton;
\r
203 public final QAction todoAction;
\r
205 public final QShortcut focusTitleShortcut;
\r
206 public final QShortcut focusTagShortcut;
\r
207 public final QShortcut focusNoteShortcut;
\r
208 public final QShortcut focusUrlShortcut;
\r
209 public final QShortcut focusAuthorShortcut;
\r
211 public EditorButtonBar buttonLayout;
\r
212 public final QComboBox fontList;
\r
213 public final QAction fontListAction;
\r
214 public final QToolButton fontColor;
\r
215 public final QAction fontColorAction;
\r
216 private final ColorMenu fontColorMenu;
\r
217 public final QToolButton fontHilight;
\r
218 public final QAction fontHilightAction;
\r
219 private final ColorMenu fontHilightColorMenu;
\r
220 public final QFileSystemWatcher fileWatcher;
\r
221 public int cursorPosition;
\r
222 private boolean forceTextPaste = false;
\r
223 private String selectedFile;
\r
224 private String currentHyperlink;
\r
225 public boolean keepPDFNavigationHidden;
\r
226 private final ApplicationLogger logger;
\r
227 SpellDictionary dictionary;
\r
228 SpellDictionary userDictionary;
\r
229 SpellChecker spellChecker;
\r
230 SuggestionListener spellListener;
\r
231 private final HashMap<String,Integer> previewPageList;
\r
234 public static class SuggestionListener implements SpellCheckListener {
\r
235 public boolean abortSpellCheck = false;
\r
236 public boolean errorsFound = false;
\r
237 private final SpellCheck spellCheckDialog;
\r
238 private final SpellChecker checker;
\r
241 private final BrowserWindow parent;
\r
242 public SuggestionListener(BrowserWindow parent, SpellChecker checker) {
\r
243 this.parent = parent;
\r
244 spellCheckDialog = new SpellCheck(checker);
\r
245 this.checker = checker;
\r
247 public void spellingError(SpellCheckEvent event) {
\r
248 errorsFound = true;
\r
249 spellCheckDialog.setWord(event.getInvalidWord());
\r
251 List<Word> suggestions = event.getSuggestions();
\r
252 if (suggestions.isEmpty()) {
\r
253 spellCheckDialog.setNoSuggestions(true);
\r
255 spellCheckDialog.setCurrentSuggestion(suggestions.get(0).getWord());
\r
256 for (int i=0; i<suggestions.size(); i++) {
\r
257 spellCheckDialog.addSuggestion(suggestions.get(i).getWord());
\r
259 spellCheckDialog.setSelectedSuggestion(0);
\r
261 spellCheckDialog.exec();
\r
262 if (spellCheckDialog.cancelPressed()) {
\r
263 abortSpellCheck = true;
\r
266 if (spellCheckDialog.replacePressed()) {
\r
267 QClipboard clipboard = QApplication.clipboard();
\r
268 clipboard.setText(spellCheckDialog.getReplacementWord());
\r
269 parent.pasteClicked();
\r
276 public BrowserWindow(DatabaseConnection c) {
\r
277 logger = new ApplicationLogger("browser.log");
\r
278 logger.log(logger.HIGH, "Setting up browser");
\r
280 fileWatcher = new QFileSystemWatcher();
\r
281 // fileWatcher.fileChanged.connect(this, "fileChanged(String)");
\r
282 noteSignal = new NoteSignal();
\r
283 titleLabel = new QLineEdit();
\r
284 titleLabel.setMaxLength(Constants.EDAM_NOTE_TITLE_LEN_MAX);
\r
285 urlText = new QLineEdit();
\r
286 authorText = new QLineEdit();
\r
287 geoBox = new QComboBox();
\r
288 urlLabel = new QPushButton();
\r
289 urlLabel.clicked.connect(this, "sourceUrlClicked()");
\r
290 authorLabel = new QLabel();
\r
293 focusLost = new Signal0();
\r
295 tagEdit = new TagLineEdit(allTags);
\r
296 tagLabel = new QLabel("Tags:");
\r
297 tagEdit.focusLost.connect(this, "modifyTagsTyping()");
\r
299 createdCalendarWidget = new QCalendarWidget();
\r
300 createdDate = new QDateEdit();
\r
301 createdDate.setDisplayFormat(Global.getDateFormat());
\r
302 createdDate.setCalendarPopup(true);
\r
303 createdDate.setCalendarWidget(createdCalendarWidget);
\r
304 createdTime = new QTimeEdit();
\r
305 createdDate.dateChanged.connect(this, "createdChanged()");
\r
306 createdTime.timeChanged.connect(this, "createdChanged()");
\r
308 alteredCalendarWidget = new QCalendarWidget();
\r
309 alteredDate = new QDateEdit();
\r
310 alteredDate.setDisplayFormat(Global.getDateFormat());
\r
311 alteredDate.setCalendarPopup(true);
\r
312 alteredDate.setCalendarWidget(alteredCalendarWidget);
\r
313 alteredTime = new QTimeEdit();
\r
314 alteredLabel = new QLabel("Altered:");
\r
315 alteredDate.dateChanged.connect(this, "alteredChanged()");
\r
316 alteredTime.timeChanged.connect(this, "alteredChanged()");
\r
318 subjectCalendarWidget = new QCalendarWidget();
\r
319 subjectDate = new QDateEdit();
\r
320 subjectDate.setDisplayFormat(Global.getDateFormat());
\r
321 subjectDate.setCalendarPopup(true);
\r
322 subjectDate.setCalendarWidget(subjectCalendarWidget);
\r
323 subjectTime = new QTimeEdit();
\r
324 subjectLabel = new QLabel(tr("Subject Date:"));
\r
325 subjectDate.dateChanged.connect(this, "subjectDateTimeChanged()");
\r
326 subjectTime.timeChanged.connect(this, "subjectDateTimeChanged()");
\r
327 authorText.textChanged.connect(this, "authorChanged()");
\r
328 urlText.textChanged.connect(this, "sourceUrlChanged()");
\r
330 notebookBox = new QComboBox();
\r
331 notebookLabel = new QLabel(tr("Notebook"));
\r
332 createdLabel = new QLabel(tr("Created:"));
\r
333 // selectedText = new String();
\r
335 urlLabel.setVisible(false);
\r
336 urlText.setVisible(false);
\r
337 authorLabel.setVisible(false);
\r
339 geoBox.setVisible(false);
\r
340 geoBox.addItem(new QIcon(iconPath+"globe.png"), "");
\r
341 geoBox.addItem(new String(tr("Set")));
\r
342 geoBox.addItem(new String(tr("Clear")));
\r
343 geoBox.addItem(new String(tr("View On Map")));
\r
344 geoBox.activated.connect(this, "geoBoxChanged()");
\r
346 authorText.setVisible(false);
\r
347 createdDate.setVisible(false);
\r
348 alteredLabel.setVisible(false);
\r
349 //notebookBox.setVisible(false);
\r
350 notebookLabel.setVisible(false);
\r
351 createdLabel.setVisible(false);
\r
352 createdTime.setVisible(false);
\r
353 alteredDate.setVisible(false);
\r
354 alteredTime.setVisible(false);
\r
355 subjectLabel.setVisible(false);
\r
356 subjectDate.setVisible(false);
\r
357 subjectTime.setVisible(false);
\r
358 extendedOn = false;
\r
359 buttonsVisible = true;
\r
360 setAcceptDrops(true);
\r
362 browser = new ContentView(this);
\r
363 browser.page().setLinkDelegationPolicy(
\r
364 QWebPage.LinkDelegationPolicy.DelegateAllLinks);
\r
365 browser.linkClicked.connect(this, "linkClicked(QUrl)");
\r
366 currentHyperlink = "";
\r
368 QVBoxLayout v = new QVBoxLayout();
\r
369 QFormLayout notebookLayout = new QFormLayout();
\r
370 QGridLayout dateLayout = new QGridLayout();
\r
371 titleLabel.setReadOnly(false);
\r
372 titleLabel.editingFinished.connect(this, "titleEdited()");
\r
373 browser.page().contentsChanged.connect(this, "contentChanged()");
\r
374 browser.page().selectionChanged.connect(this, "selectionChanged()");
\r
375 browser.page().mainFrame().javaScriptWindowObjectCleared.connect(this,
\r
376 "exposeToJavascript()");
\r
378 notebookBox.activated.connect(this, "notebookChanged()");
\r
379 resourceSignal = new NoteResourceSignal();
\r
381 QHBoxLayout tagLayout = new QHBoxLayout();
\r
382 v.addWidget(titleLabel, 0);
\r
383 notebookLayout.addRow(notebookLabel, notebookBox);
\r
384 tagLayout.addLayout(notebookLayout, 0);
\r
385 tagLayout.stretch(4);
\r
386 tagLayout.addWidget(tagLabel, 0);
\r
387 tagLayout.addWidget(tagEdit, 1);
\r
388 v.addLayout(tagLayout);
\r
390 QHBoxLayout urlLayout = new QHBoxLayout();
\r
391 urlLayout.addWidget(urlLabel, 0);
\r
392 urlLayout.addWidget(urlText, 0);
\r
393 v.addLayout(urlLayout);
\r
395 QHBoxLayout authorLayout = new QHBoxLayout();
\r
396 authorLayout.addWidget(authorLabel, 0);
\r
397 authorLayout.addWidget(authorText, 0);
\r
398 authorLayout.addWidget(geoBox);
\r
399 v.addLayout(authorLayout);
\r
401 dateLayout.addWidget(createdLabel, 0, 0);
\r
402 dateLayout.addWidget(createdDate, 0, 1);
\r
403 dateLayout.addWidget(createdTime, 0, 2);
\r
404 dateLayout.setColumnStretch(9, 100);
\r
405 dateLayout.addWidget(alteredLabel, 0, 3);
\r
406 dateLayout.addWidget(alteredDate, 0, 4);
\r
407 dateLayout.addWidget(alteredTime, 0, 5);
\r
408 dateLayout.addWidget(subjectLabel, 0, 6);
\r
409 dateLayout.addWidget(subjectDate, 0, 7);
\r
410 dateLayout.addWidget(subjectTime, 0, 8);
\r
411 v.addLayout(dateLayout, 0);
\r
413 undoButton = newEditorButton("undo", tr("Undo Change"));
\r
414 redoButton = newEditorButton("redo", tr("Redo Change"));
\r
415 cutButton = newEditorButton("cut", tr("Cut"));
\r
416 copyButton = newEditorButton("copy", tr("Copy"));
\r
417 pasteButton = newEditorButton("paste", tr("Paste"));
\r
418 boldButton = newEditorButton("bold", tr("Bold"));
\r
419 underlineButton = newEditorButton("underline", tr("Underline"));
\r
420 italicButton = newEditorButton("italic", tr("Italic"));
\r
422 rightAlignButton = newEditorButton("justifyRight", tr("Right Align"));
\r
423 leftAlignButton = newEditorButton("justifyLeft", tr("Left Align"));
\r
424 centerAlignButton = newEditorButton("justifyCenter", tr("Center Align"));
\r
426 strikethroughButton = newEditorButton("strikethrough", tr("Strikethrough"));
\r
427 hlineButton = newEditorButton("hline", tr("Insert Horizontal Line"));
\r
428 indentButton = newEditorButton("indent", tr("Shift Right"));
\r
429 outdentButton = newEditorButton("outdent", tr("Shift Left"));
\r
430 bulletListButton = newEditorButton("bulletList", tr("Bullet List"));
\r
431 numberListButton = newEditorButton("numberList", tr("Number List"));
\r
432 spellCheckButton = newEditorButton("spellCheck", tr("Spell Check"));
\r
433 todoButton = newEditorButton("todo", tr("To-do"));
\r
436 buttonLayout = new EditorButtonBar();
\r
437 v.addWidget(buttonLayout);
\r
439 undoAction = buttonLayout.addWidget(undoButton);
\r
440 buttonLayout.toggleUndoVisible.triggered.connect(this, "toggleUndoVisible(Boolean)");
\r
441 redoAction = buttonLayout.addWidget(redoButton);
\r
442 buttonLayout.toggleRedoVisible.triggered.connect(this, "toggleRedoVisible(Boolean)");
\r
444 buttonLayout.addWidget(newSeparator());
\r
445 cutAction = buttonLayout.addWidget(cutButton);
\r
446 buttonLayout.toggleCutVisible.triggered.connect(this, "toggleCutVisible(Boolean)");
\r
447 copyAction = buttonLayout.addWidget(copyButton);
\r
448 buttonLayout.toggleCopyVisible.triggered.connect(this, "toggleCopyVisible(Boolean)");
\r
449 pasteAction = buttonLayout.addWidget(pasteButton);
\r
450 buttonLayout.togglePasteVisible.triggered.connect(this, "togglePasteVisible(Boolean)");
\r
452 buttonLayout.addWidget(newSeparator());
\r
453 boldAction = buttonLayout.addWidget(boldButton);
\r
454 buttonLayout.toggleBoldVisible.triggered.connect(this, "toggleBoldVisible(Boolean)");
\r
455 italicAction = buttonLayout.addWidget(italicButton);
\r
456 buttonLayout.toggleItalicVisible.triggered.connect(this, "toggleItalicVisible(Boolean)");
\r
457 underlineAction = buttonLayout.addWidget(underlineButton);
\r
458 buttonLayout.toggleUnderlineVisible.triggered.connect(this, "toggleUnderlineVisible(Boolean)");
\r
459 strikethroughAction = buttonLayout.addWidget(strikethroughButton);
\r
460 buttonLayout.toggleStrikethroughVisible.triggered.connect(this, "toggleStrikethroughVisible(Boolean)");
\r
463 buttonLayout.addWidget(newSeparator());
\r
464 leftAlignAction = buttonLayout.addWidget(leftAlignButton);
\r
465 buttonLayout.toggleLeftAlignVisible.triggered.connect(this, "toggleLeftAlignVisible(Boolean)");
\r
466 centerAlignAction = buttonLayout.addWidget(centerAlignButton);
\r
467 buttonLayout.toggleCenterAlignVisible.triggered.connect(this, "toggleCenterAlignVisible(Boolean)");
\r
468 rightAlignAction = buttonLayout.addWidget(rightAlignButton);
\r
469 buttonLayout.toggleRightAlignVisible.triggered.connect(this, "toggleRightAlignVisible(Boolean)");
\r
471 buttonLayout.addWidget(newSeparator());
\r
472 hlineAction = buttonLayout.addWidget(hlineButton);
\r
473 buttonLayout.toggleHLineVisible.triggered.connect(this, "toggleHLineVisible(Boolean)");
\r
475 indentAction = buttonLayout.addWidget(indentButton);
\r
476 buttonLayout.toggleIndentVisible.triggered.connect(this, "toggleIndentVisible(Boolean)");
\r
477 outdentAction = buttonLayout.addWidget(outdentButton);
\r
478 buttonLayout.toggleOutdentVisible.triggered.connect(this, "toggleOutdentVisible(Boolean)");
\r
479 bulletListAction = buttonLayout.addWidget(bulletListButton);
\r
480 buttonLayout.toggleBulletListVisible.triggered.connect(this, "toggleBulletListVisible(Boolean)");
\r
481 numberListAction = buttonLayout.addWidget(numberListButton);
\r
482 buttonLayout.toggleNumberListVisible.triggered.connect(this, "toggleNumberListVisible(Boolean)");
\r
484 // Setup the font & font size combo boxes
\r
485 buttonLayout.addWidget(newSeparator());
\r
486 fontList = new QComboBox();
\r
487 fontSize = new QComboBox();
\r
488 fontList.setToolTip("Font");
\r
489 fontSize.setToolTip("Font Size");
\r
490 fontList.activated.connect(this, "fontChanged(String)");
\r
491 fontSize.activated.connect(this, "fontSizeChanged(String)");
\r
492 fontListAction = buttonLayout.addWidget(fontList);
\r
493 buttonLayout.toggleFontVisible.triggered.connect(this, "toggleFontListVisible(Boolean)");
\r
494 fontSizeAction = buttonLayout.addWidget(fontSize);
\r
495 buttonLayout.toggleFontSizeVisible.triggered.connect(this, "toggleFontSizeVisible(Boolean)");
\r
496 QFontDatabase fonts = new QFontDatabase();
\r
497 List<String> fontFamilies = fonts.families();
\r
498 for (int i = 0; i < fontFamilies.size(); i++) {
\r
499 fontList.addItem(fontFamilies.get(i));
\r
501 loadFontSize(fontFamilies.get(i));
\r
505 // buttonLayout.addWidget(newSeparator(), 0);
\r
506 fontColor = newToolButton("fontColor", tr("Font Color"));
\r
507 fontColorMenu = new ColorMenu(this);
\r
508 fontColor.setMenu(fontColorMenu.getMenu());
\r
509 fontColor.setPopupMode(ToolButtonPopupMode.MenuButtonPopup);
\r
510 fontColor.setAutoRaise(false);
\r
511 fontColorMenu.getMenu().triggered.connect(this, "fontColorClicked()");
\r
512 fontColorAction = buttonLayout.addWidget(fontColor);
\r
513 buttonLayout.toggleFontColorVisible.triggered.connect(this, "toggleFontColorVisible(Boolean)");
\r
514 fontHilight = newToolButton("fontHilight", tr("Font Hilight Color"));
\r
515 fontHilight.setPopupMode(ToolButtonPopupMode.MenuButtonPopup);
\r
516 fontHilight.setAutoRaise(false);
\r
517 fontHilightColorMenu = new ColorMenu(this);
\r
518 fontHilightColorMenu.setDefault(QColor.yellow);
\r
519 fontHilight.setMenu(fontHilightColorMenu.getMenu());
\r
520 fontHilightColorMenu.getMenu().triggered.connect(this, "fontHilightClicked()");
\r
521 fontHilightAction = buttonLayout.addWidget(fontHilight);
\r
522 fontHilightColorMenu.setDefault(QColor.yellow);
\r
523 buttonLayout.toggleFontHilight.triggered.connect(this, "toggleFontHilightVisible(Boolean)");
\r
525 spellCheckAction = buttonLayout.addWidget(spellCheckButton);
\r
526 buttonLayout.toggleNumberListVisible.triggered.connect(this, "spellCheckClicked()");
\r
527 buttonLayout.toggleSpellCheck.triggered.connect(this, "toggleSpellCheckVisible(Boolean)");
\r
529 todoAction = buttonLayout.addWidget(todoButton);
\r
530 buttonLayout.toggleNumberListVisible.triggered.connect(this, "todoClicked()");
\r
531 buttonLayout.toggleTodo.triggered.connect(this, "toggleTodoVisible(Boolean)");
\r
534 // buttonLayout.addWidget(new QLabel(), 1);
\r
535 v.addWidget(browser, 1);
\r
538 browser.downloadAttachmentRequested.connect(this,
\r
539 "downloadAttachment(QNetworkRequest)");
\r
540 browser.downloadImageRequested.connect(this,
\r
541 "downloadImage(QNetworkRequest)");
\r
542 setTabOrder(notebookBox, tagEdit);
\r
543 setTabOrder(tagEdit, browser);
\r
545 focusNoteShortcut = new QShortcut(this);
\r
546 setupShortcut(focusNoteShortcut, "Focus_Note");
\r
547 focusNoteShortcut.activated.connect(this, "focusNote()");
\r
548 focusTitleShortcut = new QShortcut(this);
\r
549 setupShortcut(focusTitleShortcut, "Focus_Title");
\r
550 focusTitleShortcut.activated.connect(this, "focusTitle()");
\r
551 focusTagShortcut = new QShortcut(this);
\r
552 setupShortcut(focusTagShortcut, "Focus_Tag");
\r
553 focusTagShortcut.activated.connect(this, "focusTag()");
\r
554 focusAuthorShortcut = new QShortcut(this);
\r
555 setupShortcut(focusAuthorShortcut, "Focus_Author");
\r
556 focusAuthorShortcut.activated.connect(this, "focusAuthor()");
\r
557 focusUrlShortcut = new QShortcut(this);
\r
558 setupShortcut(focusUrlShortcut, "Focus_Url");
\r
559 focusUrlShortcut.activated.connect(this, "focusUrl()");
\r
561 browser.page().mainFrame().setTextSizeMultiplier(Global.getTextSizeMultiplier());
\r
562 browser.page().mainFrame().setZoomFactor(Global.getZoomFactor());
\r
564 previewPageList = new HashMap<String,Integer>();
\r
566 browser.page().microFocusChanged.connect(this, "microFocusChanged()");
\r
568 logger.log(logger.HIGH, "Browser setup complete");
\r
573 private void setupShortcut(QShortcut action, String text) {
\r
574 if (!Global.shortcutKeys.containsAction(text))
\r
576 action.setKey(new QKeySequence(Global.shortcutKeys.getShortcut(text)));
\r
582 // Getter for the QWebView
\r
583 public QWebView getBrowser() {
\r
587 // Block signals while loading data or things are flagged as dirty by
\r
589 public void loadingData(boolean val) {
\r
590 logger.log(logger.EXTREME, "Entering BrowserWindow.loadingData() " +val);
\r
591 notebookBox.blockSignals(val);
\r
592 browser.page().blockSignals(val);
\r
593 browser.page().mainFrame().blockSignals(val);
\r
594 titleLabel.blockSignals(val);
\r
595 alteredDate.blockSignals(val);
\r
596 alteredTime.blockSignals(val);
\r
597 createdTime.blockSignals(val);
\r
598 createdDate.blockSignals(val);
\r
599 subjectDate.blockSignals(val);
\r
600 subjectTime.blockSignals(val);
\r
601 urlText.blockSignals(val);
\r
602 authorText.blockSignals(val);
\r
604 exposeToJavascript();
\r
605 logger.log(logger.EXTREME, "Exiting BrowserWindow.loadingData() " +val);
\r
609 public void setReadOnly(boolean v) {
\r
611 titleLabel.setEnabled(!v);
\r
612 notebookBox.setEnabled(!v);
\r
613 tagEdit.setEnabled(!v);
\r
614 authorLabel.setEnabled(!v);
\r
615 geoBox.setEnabled(!v);
\r
616 urlText.setEnabled(!v);
\r
617 createdDate.setEnabled(!v);
\r
618 subjectDate.setEnabled(!v);
\r
619 alteredDate.setEnabled(!v);
\r
620 getBrowser().setEnabled(true);
\r
623 // expose this class to Javascript on the web page
\r
624 private void exposeToJavascript() {
\r
625 browser.page().mainFrame().addToJavaScriptWindowObject("jambi", this);
\r
628 // Custom event queue
\r
630 public boolean event(QEvent e) {
\r
631 if (e.type().equals(QEvent.Type.FocusOut)) {
\r
632 logger.log(logger.EXTREME, "Focus lost");
\r
635 return super.event(e);
\r
638 // clear out browser
\r
639 public void clear() {
\r
640 logger.log(logger.EXTREME, "Entering BrowserWindow.clear()");
\r
642 browser.setContent(new QByteArray());
\r
643 tagEdit.setText("");
\r
644 tagEdit.tagCompleter.reset();
\r
645 urlLabel.setText(tr("Source URL:"));
\r
646 titleLabel.setText("");
\r
647 logger.log(logger.EXTREME, "Exiting BrowserWindow.clear()");
\r
650 // get/set current note
\r
651 public void setNote(Note n) {
\r
655 saveNoteTitle = n.getTitle();
\r
659 public Note getNote() {
\r
660 return currentNote;
\r
663 // New Editor Button
\r
664 private QPushButton newEditorButton(String name, String toolTip) {
\r
665 QPushButton button = new QPushButton();
\r
666 QIcon icon = new QIcon(iconPath + name + ".gif");
\r
667 button.setIcon(icon);
\r
668 button.setToolTip(toolTip);
\r
669 button.clicked.connect(this, name + "Clicked()");
\r
672 // New Editor Button
\r
673 private QToolButton newToolButton(String name, String toolTip) {
\r
674 QToolButton button = new QToolButton();
\r
675 QIcon icon = new QIcon(iconPath + name + ".gif");
\r
676 button.setIcon(icon);
\r
677 button.setToolTip(toolTip);
\r
678 button.clicked.connect(this, name + "Clicked()");
\r
683 private QLabel newSeparator() {
\r
684 return new QLabel(" ");
\r
687 // Set the title in the window
\r
688 public void setTitle(String t) {
\r
689 titleLabel.setText(t);
\r
694 // Return the current text title
\r
695 public String getTitle() {
\r
696 return titleLabel.text();
\r
699 // Set the tag name string
\r
700 public void setTag(String t) {
\r
702 tagEdit.setText(t);
\r
703 tagEdit.tagCompleter.reset();
\r
706 // Set the source URL
\r
707 public void setUrl(String t) {
\r
708 urlLabel.setText(tr("Source URL:\t"));
\r
709 urlText.setText(t);
\r
712 // The user want's to launch a web browser on the source of the URL
\r
713 public void sourceUrlClicked() {
\r
714 // Make sure we have a valid URL
\r
715 if (urlText.text().trim().equals(""))
\r
718 String url = urlText.text();
\r
719 if (!url.toLowerCase().startsWith(tr("http://")))
\r
720 url = tr("http://") +url;
\r
722 if (!QDesktopServices.openUrl(new QUrl(url))) {
\r
723 logger.log(logger.LOW, "Error opening file :" +url);
\r
727 public void setAuthor(String t) {
\r
728 authorLabel.setText(tr("Author:\t"));
\r
729 authorText.setText(t);
\r
732 // Set the creation date
\r
733 public void setCreation(long date) {
\r
734 QDateTime dt = new QDateTime();
\r
735 dt.setTime_t((int) (date / 1000));
\r
736 createdDate.setDateTime(dt);
\r
737 createdTime.setDateTime(dt);
\r
738 createdDate.setDisplayFormat(Global.getDateFormat());
\r
739 createdTime.setDisplayFormat(Global.getTimeFormat());
\r
742 // Set the creation date
\r
743 public void setAltered(long date) {
\r
744 QDateTime dt = new QDateTime();
\r
745 dt.setTime_t((int) (date / 1000));
\r
746 alteredDate.setDateTime(dt);
\r
747 alteredTime.setDateTime(dt);
\r
748 alteredDate.setDisplayFormat(Global.getDateFormat());
\r
749 alteredTime.setDisplayFormat(Global.getTimeFormat());
\r
752 // Set the subject date
\r
753 public void setSubjectDate(long date) {
\r
754 QDateTime dt = new QDateTime();
\r
755 dt.setTime_t((int) (date / 1000));
\r
756 subjectDate.setDateTime(dt);
\r
757 subjectTime.setDateTime(dt);
\r
758 subjectDate.setDisplayFormat(Global.getDateFormat());
\r
759 subjectTime.setDisplayFormat(Global.getTimeFormat());
\r
762 // Toggle the extended attribute information
\r
763 public void toggleInformation() {
\r
765 extendedOn = false;
\r
769 urlLabel.setVisible(extendedOn);
\r
770 urlText.setVisible(extendedOn);
\r
771 authorText.setVisible(extendedOn);
\r
772 geoBox.setVisible(extendedOn);
\r
773 authorLabel.setVisible(extendedOn);
\r
774 createdDate.setVisible(extendedOn);
\r
775 createdTime.setVisible(extendedOn);
\r
776 createdLabel.setVisible(extendedOn);
\r
777 alteredLabel.setVisible(extendedOn);
\r
778 alteredDate.setVisible(extendedOn);
\r
779 alteredTime.setVisible(extendedOn);
\r
780 //notebookBox.setVisible(extendedOn);
\r
781 notebookLabel.setVisible(extendedOn);
\r
782 subjectLabel.setVisible(extendedOn);
\r
783 subjectDate.setVisible(extendedOn);
\r
784 subjectTime.setVisible(extendedOn);
\r
787 public void hideButtons() {
\r
789 undoButton.parentWidget().setVisible(false);
\r
790 buttonsVisible = false;
\r
794 // Is the extended view on?
\r
795 public boolean isExtended() {
\r
799 // Listener for when a link is clicked
\r
800 @SuppressWarnings("unused")
\r
801 private void openFile() {
\r
802 logger.log(logger.EXTREME, "Starting openFile()");
\r
803 File fileHandle = new File(selectedFile);
\r
804 URI fileURL = fileHandle.toURI();
\r
805 String localURL = fileURL.toString();
\r
806 QUrl url = new QUrl(localURL);
\r
807 QFile file = new QFile(selectedFile);
\r
809 logger.log(logger.EXTREME, "Adding to fileWatcher:"+file.fileName());
\r
810 fileWatcher.addPath(file.fileName());
\r
812 if (!QDesktopServices.openUrl(url)) {
\r
813 logger.log(logger.LOW, "Error opening file :" +url);
\r
818 // Listener for when a link is clicked
\r
819 @SuppressWarnings("unused")
\r
820 private void linkClicked(QUrl url) {
\r
821 logger.log(logger.EXTREME, "URL Clicked: " +url.toString());
\r
822 if (url.toString().substring(0,8).equals("nnres://")) {
\r
823 logger.log(logger.EXTREME, "URL is NN resource");
\r
824 if (url.toString().endsWith("/vnd.evernote.ink")) {
\r
825 logger.log(logger.EXTREME, "Unable to open ink note");
\r
826 QMessageBox.information(this, tr("Unable Open"), tr("This is an ink note.\n"+
\r
827 "Ink notes are not supported since Evernote has not\n published any specifications on them\n" +
\r
828 "and I'm too lazy to figure them out by myself."));
\r
831 String fullName = url.toString().substring(8);
\r
832 int index = fullName.indexOf(".");
\r
836 type = fullName.substring(index+1);
\r
837 guid = fullName.substring(0,index);
\r
839 index = guid.indexOf(Global.attachmentNameDelimeter);
\r
841 guid = guid.substring(0,index);
\r
843 List<Resource> resList = currentNote.getResources();
\r
844 Resource res = null;
\r
845 for (int i=0; i<resList.size(); i++) {
\r
846 if (resList.get(i).getGuid().equals(guid)) {
\r
847 res = resList.get(i);
\r
852 String resGuid = Global.resourceMap.get(guid);
\r
853 if (resGuid != null)
\r
854 res = conn.getNoteTable().noteResourceTable.getNoteResource(resGuid, true);
\r
858 if (res.getAttributes() != null &&
\r
859 res.getAttributes().getFileName() != null &&
\r
860 !res.getAttributes().getFileName().trim().equals(""))
\r
861 fileName = res.getGuid()+Global.attachmentNameDelimeter+res.getAttributes().getFileName();
\r
863 fileName = res.getGuid()+"."+type;
\r
864 QFile file = new QFile(Global.getFileManager().getResDirPath(fileName));
\r
865 QFile.OpenMode mode = new QFile.OpenMode();
\r
866 mode.set(QFile.OpenModeFlag.WriteOnly);
\r
867 boolean openResult = file.open(mode);
\r
868 logger.log(logger.EXTREME, "File opened:" +openResult);
\r
869 QDataStream out = new QDataStream(file);
\r
870 Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(res.getGuid(), true);
\r
871 QByteArray binData = new QByteArray(resBinary.getData().getBody());
\r
873 logger.log(logger.EXTREME, "Writing resource");
\r
874 out.writeBytes(binData.toByteArray());
\r
877 String whichOS = System.getProperty("os.name");
\r
878 if (whichOS.contains("Windows"))
\r
879 url.setUrl("file:///"+file.fileName());
\r
881 url.setUrl("file://"+file.fileName());
\r
882 // fileWatcher.removePath(file.fileName());
\r
883 logger.log(logger.EXTREME, "Adding file watcher " +file.fileName());
\r
884 fileWatcher.addPath(file.fileName());
\r
886 // If we can't open it, then prompt the user to save it.
\r
887 if (!QDesktopServices.openUrl(url)) {
\r
888 logger.log(logger.EXTREME, "We can't handle this. Where do we put it?");
\r
889 QFileDialog dialog = new QFileDialog();
\r
891 if (dialog.exec()!=0) {
\r
892 List<String> fileNames = dialog.selectedFiles(); //gets all selected filenames
\r
893 if (fileNames.size() == 0)
\r
895 String sf = fileNames.get(0);
\r
896 QFile saveFile = new QFile(sf);
\r
897 mode.set(QFile.OpenModeFlag.WriteOnly);
\r
898 saveFile.open(mode);
\r
899 QDataStream saveOut = new QDataStream(saveFile);
\r
900 saveOut.writeBytes(binData.toByteArray());
\r
908 logger.log(logger.EXTREME, "Launching URL");
\r
909 QDesktopServices.openUrl(url);
\r
912 // Listener for when BOLD is clicked
\r
913 @SuppressWarnings("unused")
\r
914 private void undoClicked() {
\r
915 browser.page().triggerAction(WebAction.Undo);
\r
916 browser.setFocus();
\r
919 // Listener for when BOLD is clicked
\r
920 @SuppressWarnings("unused")
\r
921 private void redoClicked() {
\r
922 browser.page().triggerAction(WebAction.Redo);
\r
923 browser.setFocus();
\r
926 // Listener for when BOLD is clicked
\r
927 @SuppressWarnings("unused")
\r
928 private void boldClicked() {
\r
929 browser.page().triggerAction(WebAction.ToggleBold);
\r
930 microFocusChanged();
\r
931 browser.setFocus();
\r
934 // Listener for when Italics is clicked
\r
935 @SuppressWarnings("unused")
\r
936 private void italicClicked() {
\r
937 browser.page().triggerAction(WebAction.ToggleItalic);
\r
938 microFocusChanged();
\r
939 browser.setFocus();
\r
942 // Listener for when UNDERLINE is clicked
\r
943 @SuppressWarnings("unused")
\r
944 private void underlineClicked() {
\r
945 browser.page().triggerAction(WebAction.ToggleUnderline);
\r
946 microFocusChanged();
\r
947 browser.setFocus();
\r
950 // Listener for when Strikethrough is clicked
\r
951 @SuppressWarnings("unused")
\r
952 private void strikethroughClicked() {
\r
953 browser.page().mainFrame().evaluateJavaScript(
\r
954 "document.execCommand('strikeThrough', false, '');");
\r
955 browser.setFocus();
\r
958 // Listener for when cut is clicked
\r
959 @SuppressWarnings("unused")
\r
960 private void cutClicked() {
\r
961 browser.page().triggerAction(WebAction.Cut);
\r
962 browser.setFocus();
\r
965 // Listener when COPY is clicked
\r
966 @SuppressWarnings("unused")
\r
967 private void copyClicked() {
\r
968 browser.page().triggerAction(WebAction.Copy);
\r
969 browser.setFocus();
\r
972 // Listener when PASTE is clicked
\r
973 public void pasteClicked() {
\r
974 logger.log(logger.EXTREME, "Paste Clicked");
\r
975 if (forceTextPaste) {
\r
976 pasteWithoutFormattingClicked();
\r
979 QClipboard clipboard = QApplication.clipboard();
\r
980 QMimeData mime = clipboard.mimeData();
\r
982 // String x = mime.html();
\r
984 if (mime.hasImage()) {
\r
985 logger.log(logger.EXTREME, "Image paste found");
\r
987 browser.setFocus();
\r
991 if (mime.hasUrls()) {
\r
992 logger.log(logger.EXTREME, "URL paste found");
\r
994 browser.setFocus();
\r
998 String text = mime.html();
\r
999 if (text.contains("en-tag") && mime.hasHtml()) {
\r
1000 logger.log(logger.EXTREME, "Intra-note paste found");
\r
1001 text = fixInternotePaste(text);
\r
1002 mime.setHtml(text);
\r
1003 clipboard.setMimeData(mime);
\r
1006 logger.log(logger.EXTREME, "Final paste choice encountered");
\r
1007 browser.page().triggerAction(WebAction.Paste);
\r
1008 browser.setFocus();
\r
1012 // Paste text without formatting
\r
1013 private void pasteWithoutFormattingClicked() {
\r
1014 logger.log(logger.EXTREME, "Paste without format clipped");
\r
1015 QClipboard clipboard = QApplication.clipboard();
\r
1016 QMimeData mime = clipboard.mimeData();
\r
1017 if (!mime.hasText())
\r
1019 String text = mime.text();
\r
1020 clipboard.setText(text);
\r
1021 browser.page().triggerAction(WebAction.Paste);
\r
1022 QApplication.clipboard().setMimeData(mime);
\r
1023 browser.setFocus();
\r
1027 // insert date/time
\r
1028 @SuppressWarnings("unused")
\r
1029 private void insertDateTime() {
\r
1030 String fmt = Global.getDateFormat() + " " + Global.getTimeFormat();
\r
1031 String dateTimeFormat = new String(fmt);
\r
1032 SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);
\r
1033 Calendar cal = Calendar.getInstance();
\r
1035 browser.page().mainFrame().evaluateJavaScript(
\r
1036 "document.execCommand('insertHtml', false, '"+simple.format(cal.getTime())+"');");
\r
1038 browser.setFocus();
\r
1042 // Listener when Left is clicked
\r
1043 @SuppressWarnings("unused")
\r
1044 private void justifyLeftClicked() {
\r
1045 browser.page().mainFrame().evaluateJavaScript(
\r
1046 "document.execCommand('JustifyLeft', false, '');");
\r
1047 browser.setFocus();
\r
1050 // Listener when Center is clicked
\r
1051 @SuppressWarnings("unused")
\r
1052 private void justifyCenterClicked() {
\r
1053 browser.page().mainFrame().evaluateJavaScript(
\r
1054 "document.execCommand('JustifyCenter', false, '');");
\r
1055 browser.setFocus();
\r
1058 // Listener when Left is clicked
\r
1059 @SuppressWarnings("unused")
\r
1060 private void justifyRightClicked() {
\r
1061 browser.page().mainFrame().evaluateJavaScript(
\r
1062 "document.execCommand('JustifyRight', false, '');");
\r
1063 browser.setFocus();
\r
1066 // Listener when HLINE is clicked
\r
1067 @SuppressWarnings("unused")
\r
1068 private void hlineClicked() {
\r
1069 browser.page().mainFrame().evaluateJavaScript(
\r
1070 "document.execCommand('insertHorizontalRule', false, '');");
\r
1071 browser.setFocus();
\r
1074 // Listener when outdent is clicked
\r
1075 private void outdentClicked() {
\r
1076 browser.page().mainFrame().evaluateJavaScript(
\r
1077 "document.execCommand('outdent', false, '');");
\r
1078 browser.setFocus();
\r
1081 // Listener when a bullet list is clicked
\r
1082 @SuppressWarnings("unused")
\r
1083 private void bulletListClicked() {
\r
1084 browser.page().mainFrame().evaluateJavaScript(
\r
1085 "document.execCommand('InsertUnorderedList', false, '');");
\r
1086 browser.setFocus();
\r
1089 // Listener when a bullet list is clicked
\r
1090 @SuppressWarnings("unused")
\r
1091 private void numberListClicked() {
\r
1092 browser.page().mainFrame().evaluateJavaScript(
\r
1093 "document.execCommand('InsertOrderedList', false, '');");
\r
1094 browser.setFocus();
\r
1097 // Listener when indent is clicked
\r
1098 private void indentClicked() {
\r
1099 browser.page().mainFrame().evaluateJavaScript(
\r
1100 "document.execCommand('indent', false, '');");
\r
1101 browser.setFocus();
\r
1104 // Listener when the font name is changed
\r
1105 @SuppressWarnings("unused")
\r
1106 private void fontChanged(String font) {
\r
1107 browser.page().mainFrame().evaluateJavaScript(
\r
1108 "document.execCommand('fontName',false,'" + font + "');");
\r
1109 browser.setFocus();
\r
1112 // Listener when a font size is changed
\r
1113 @SuppressWarnings("unused")
\r
1114 private void fontSizeChanged(String font) {
\r
1115 String text = browser.selectedText();
\r
1116 if (text.trim().equalsIgnoreCase(""))
\r
1119 String selectedText = browser.selectedText();
\r
1120 String url = "<span style=\"font-size:" +font +"pt; \">"+selectedText +"</a>";
\r
1121 String script = "document.execCommand('insertHtml', false, '"+url+"');";
\r
1122 browser.page().mainFrame().evaluateJavaScript(script);
\r
1123 /* browser.page().mainFrame().evaluateJavaScript(
\r
1124 "document.execCommand('fontSize',false,'"
\r
1127 browser.setFocus();
\r
1130 // Load the font combo box based upon the font selected
\r
1131 private void loadFontSize(String name) {
\r
1132 QFontDatabase db = new QFontDatabase();
\r
1134 List<Integer> points = db.pointSizes(name);
\r
1135 for (int i=0; i<points.size(); i++) {
\r
1136 fontSize.addItem(points.get(i).toString());
\r
1139 fontSize.addItem("x-small");
\r
1140 fontSize.addItem("small");
\r
1141 fontSize.addItem("medium");
\r
1142 fontSize.addItem("large");
\r
1143 fontSize.addItem("x-large");
\r
1144 fontSize.addItem("xx-large");
\r
1145 fontSize.addItem("xxx-large");
\r
1149 // Listener when a font size is changed
\r
1150 @SuppressWarnings("unused")
\r
1151 private void fontColorClicked() {
\r
1152 // QColorDialog dialog = new QColorDialog();
\r
1153 // QColor color = QColorDialog.getColor();
\r
1154 QColor color = fontColorMenu.getColor();
\r
1155 if (color.isValid())
\r
1156 browser.page().mainFrame().evaluateJavaScript(
\r
1157 "document.execCommand('foreColor',false,'" + color.name()
\r
1159 browser.setFocus();
\r
1162 // Listener for when a background color change is requested
\r
1163 @SuppressWarnings("unused")
\r
1164 private void fontHilightClicked() {
\r
1165 // QColorDialog dialog = new QColorDialog();
\r
1166 // QColor color = QColorDialog.getColor();
\r
1167 QColor color = fontHilightColorMenu.getColor();
\r
1168 if (color.isValid())
\r
1169 browser.page().mainFrame().evaluateJavaScript(
\r
1170 "document.execCommand('backColor',false,'" + color.name()
\r
1172 browser.setFocus();
\r
1175 // Listener for when a background color change is requested
\r
1176 @SuppressWarnings("unused")
\r
1177 private void superscriptClicked() {
\r
1178 browser.page().mainFrame().evaluateJavaScript(
\r
1179 "document.execCommand('superscript');");
\r
1180 browser.setFocus();
\r
1183 // Listener for when a background color change is requested
\r
1184 @SuppressWarnings("unused")
\r
1185 private void subscriptClicked() {
\r
1186 browser.page().mainFrame().evaluateJavaScript(
\r
1187 "document.execCommand('subscript');");
\r
1188 browser.setFocus();
\r
1190 // Insert a to-do checkbox
\r
1191 @SuppressWarnings("unused")
\r
1192 private void todoClicked() {
\r
1193 FileNameMap fileNameMap = URLConnection.getFileNameMap();
\r
1194 String script_start = new String(
\r
1195 "document.execCommand('insertHtml', false, '");
\r
1196 String script_end = new String("');");
\r
1197 String todo = new String(
\r
1198 "<input TYPE=\"CHECKBOX\" value=\"false\" onClick=\"value=checked; window.jambi.contentChanged(); \" />");
\r
1199 browser.page().mainFrame().evaluateJavaScript(
\r
1200 script_start + todo + script_end);
\r
1201 browser.setFocus();
\r
1204 // Encrypt the selected text
\r
1205 @SuppressWarnings("unused")
\r
1206 private void encryptText() {
\r
1207 String text = browser.selectedText();
\r
1208 if (text.trim().equalsIgnoreCase(""))
\r
1211 EnCryptDialog dialog = new EnCryptDialog();
\r
1213 if (!dialog.okPressed()) {
\r
1217 EnCrypt crypt = new EnCrypt();
\r
1218 String encrypted = crypt.encrypt(text, dialog.getPassword().trim(), 64);
\r
1220 if (encrypted.trim().equals("")) {
\r
1221 QMessageBox.information(this, tr("Error"), tr("Error Encrypting String"));
\r
1224 StringBuffer buffer = new StringBuffer(encrypted.length() + 100);
\r
1225 buffer.append("<img en-tag=\"en-crypt\" cipher=\"RC2\" hint=\""
\r
1226 + dialog.getHint().replace("'","\\'") + "\" length=\"64\" ");
\r
1227 buffer.append("contentEditable=\"false\" alt=\"");
\r
1228 buffer.append(encrypted);
\r
1229 // NFC FIXME: should this be a file URL like in handleLocalAttachment and importAttachment?
\r
1230 buffer.append("\" src=\"").append(FileUtils.toForwardSlashedPath(Global.getFileManager().getImageDirPath("encrypt.png") +"\""));
\r
1231 Global.cryptCounter++;
\r
1232 buffer.append(" id=\"crypt"+Global.cryptCounter.toString() +"\"");
\r
1233 buffer.append(" onMouseOver=\"style.cursor=\\'hand\\'\"");
\r
1234 buffer.append(" onClick=\"window.jambi.decryptText(\\'crypt"+Global.cryptCounter.toString()
\r
1235 +"\\', \\'"+encrypted+"\\', \\'"+dialog.getHint().replace("'", "\\&apos;")+"\\');\"");
\r
1236 buffer.append("style=\"display:block\" />");
\r
1238 String script_start = new String(
\r
1239 "document.execCommand('insertHtml', false, '");
\r
1240 String script_end = new String("');");
\r
1241 browser.page().mainFrame().evaluateJavaScript(
\r
1242 script_start + buffer.toString() + script_end);
\r
1246 // Insert a hyperlink
\r
1247 public void insertLink() {
\r
1248 logger.log(logger.EXTREME, "Inserting link");
\r
1249 String text = browser.selectedText();
\r
1250 if (text.trim().equalsIgnoreCase(""))
\r
1253 InsertLinkDialog dialog = new InsertLinkDialog();
\r
1254 if (currentHyperlink != null && currentHyperlink != "") {
\r
1255 dialog.setUrl(currentHyperlink);
\r
1258 if (!dialog.okPressed()) {
\r
1259 logger.log(logger.EXTREME, "Insert link canceled");
\r
1262 if (browser.insertLinkAction.text().equalsIgnoreCase("Insert Hyperlink")) {
\r
1263 String selectedText = browser.selectedText();
\r
1264 logger.log(logger.EXTREME, "Inserting link on text "+selectedText);
\r
1265 logger.log(logger.EXTREME, "URL Link " +dialog.getUrl().trim());
\r
1266 String dUrl = StringUtils.replace(dialog.getUrl().trim(), "'", "\\'");
\r
1267 String url = "<a href=\"" +dUrl
\r
1268 +"\" title=" +dUrl
\r
1269 +" >"+selectedText +"</a>";
\r
1270 String script = "document.execCommand('insertHtml', false, '"+url+"');";
\r
1271 browser.page().mainFrame().evaluateJavaScript(script);
\r
1274 String js = new String( "function getCursorPos() {"
\r
1276 +"if (window.getSelection) {"
\r
1277 +" var selObj = window.getSelection();"
\r
1278 +" var selRange = selObj.getRangeAt(0);"
\r
1279 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
1280 +" while(workingNode != null) { "
\r
1281 +" if (workingNode.nodeName.toLowerCase()=='a') workingNode.setAttribute('href','" +dialog.getUrl() +"');"
\r
1282 +" workingNode = workingNode.parentNode;"
\r
1285 +"} getCursorPos();");
\r
1286 browser.page().mainFrame().evaluateJavaScript(js);
\r
1293 public void insertTable() {
\r
1294 TableDialog dialog = new TableDialog();
\r
1296 if (!dialog.okPressed()) {
\r
1300 int cols = dialog.getCols();
\r
1301 int rows = dialog.getRows();
\r
1302 int width = dialog.getWidth();
\r
1303 boolean percent = dialog.isPercent();
\r
1305 String newHTML = "<table border=\"1\" width=\"" +new Integer(width).toString();
\r
1307 newHTML = newHTML +"%";
\r
1308 newHTML = newHTML + "\"><tbody>";
\r
1310 for (int i=0; i<rows; i++) {
\r
1311 newHTML = newHTML +"<tr>";
\r
1312 for (int j=0; j<cols; j++) {
\r
1313 newHTML = newHTML +"<td> </td>";
\r
1315 newHTML = newHTML +"</tr>";
\r
1317 newHTML = newHTML+"</tbody></table>";
\r
1319 String script = "document.execCommand('insertHtml', false, '"+newHTML+"');";
\r
1320 browser.page().mainFrame().evaluateJavaScript(script);
\r
1324 // Text content changed
\r
1325 @SuppressWarnings("unused")
\r
1326 private void selectionChanged() {
\r
1327 browser.encryptAction.setEnabled(true);
\r
1328 browser.insertLinkAction.setEnabled(true);
\r
1329 String scriptStart = "var selection_text = (window.getSelection()).toString();"
\r
1330 + "var range = (window.getSelection()).getRangeAt(0);"
\r
1331 + "var parent_html = range.commonAncestorContainer.innerHTML;"
\r
1332 + "if (parent_html == undefined) {window.jambi.saveSelectedText(selection_text); return;}"
\r
1333 + "var first_text = range.startContainer.nodeValue.substr(range.startOffset);"
\r
1334 + "var last_text = (range.endContainer.nodeValue).substring(0,range.endOffset);"
\r
1335 + "var start = parent_html.indexOf(first_text);"
\r
1336 + "var end = parent_html.indexOf(last_text,start+1)+last_text.length;"
\r
1337 + "var value = parent_html.substring(start,end);"
\r
1338 + "window.jambi.saveSelectedText(value);" ;
\r
1339 browser.page().mainFrame().evaluateJavaScript(scriptStart);
\r
1343 public void saveSelectedText(String text) {
\r
1344 boolean enabled = true;
\r
1345 if (text.trim().length() == 0)
\r
1347 if (text.indexOf("en-tag=\"en-crypt\"") >= 0)
\r
1349 if (text.indexOf("<img en-tag=\"en-media\"") >= 0)
\r
1351 if (text.indexOf("<a en-tag=\"en-media\"") >= 0)
\r
1353 if (text.indexOf("<input ") >= 0)
\r
1356 browser.encryptAction.setEnabled(enabled);
\r
1357 browser.insertLinkAction.setEnabled(enabled);
\r
1358 // selectedText = text;
\r
1361 // Decrypt clicked text
\r
1362 public void decryptText(String id, String text, String hint) {
\r
1363 EnCrypt crypt = new EnCrypt();
\r
1364 String plainText = null;
\r
1365 Calendar currentTime = new GregorianCalendar();
\r
1366 Long l = new Long(currentTime.getTimeInMillis());
\r
1367 String slot = new String(Long.toString(l));
\r
1369 // First, try to decrypt with any keys we already have
\r
1370 for (int i=0; i<Global.passwordRemember.size(); i++) {
\r
1371 plainText = crypt.decrypt(text, Global.passwordRemember.get(i), 64);
\r
1372 if (plainText != null) {
\r
1373 slot = new String(Long.toString(l));
\r
1374 Global.passwordSafe.put(slot, Global.passwordRemember.get(i));
\r
1375 removeEncryption(id, plainText, false, slot);
\r
1381 EnDecryptDialog dialog = new EnDecryptDialog();
\r
1382 dialog.setHint(hint);
\r
1383 while (plainText == null || !dialog.okPressed()) {
\r
1385 if (!dialog.okPressed()) {
\r
1388 plainText = crypt.decrypt(text, dialog.getPassword().trim(), 64);
\r
1389 if (plainText == null) {
\r
1390 QMessageBox.warning(this, "Incorrect Password", "The password entered is not correct");
\r
1393 Global.passwordSafe.put(slot, dialog.getPassword());
\r
1394 removeEncryption(id, plainText, dialog.permanentlyDecrypt(), slot);
\r
1395 if (dialog.rememberPassword())
\r
1396 Global.passwordRemember.add(dialog.getPassword());
\r
1400 // Get the editor tag line
\r
1401 public TagLineEdit getTagLine() {
\r
1405 // Modify a note's tags
\r
1406 @SuppressWarnings("unused")
\r
1407 private void modifyTags() {
\r
1408 TagAssign tagWindow = new TagAssign(allTags, currentTags);
\r
1410 if (tagWindow.okClicked()) {
\r
1411 currentTags.clear();
\r
1412 StringBuffer tagDisplay = new StringBuffer();
\r
1414 List<QListWidgetItem> newTags = tagWindow.getTagList()
\r
1416 for (int i = 0; i < newTags.size(); i++) {
\r
1417 currentTags.add(newTags.get(i).text());
\r
1418 tagDisplay.append(newTags.get(i).text());
\r
1419 if (i < newTags.size() - 1) {
\r
1420 tagDisplay.append(Global.tagDelimeter + " ");
\r
1423 tagEdit.setText(tagDisplay.toString());
\r
1424 noteSignal.tagsChanged.emit(currentNote.getGuid(), currentTags);
\r
1428 // Tag line has been modified by typing text
\r
1429 @SuppressWarnings("unused")
\r
1430 private void modifyTagsTyping() {
\r
1431 String completionText = "";
\r
1432 if (tagEdit.currentCompleterSelection != null && !tagEdit.currentCompleterSelection.equals("")) {
\r
1433 completionText = tagEdit.currentCompleterSelection;
\r
1434 tagEdit.currentCompleterSelection = "";
\r
1437 if (tagEdit.text().equalsIgnoreCase(saveTagList))
\r
1440 // We know something has changed...
\r
1441 String oldTagArray[] = saveTagList.split(Global.tagDelimeter);
\r
1442 String newTagArray[] = tagEdit.text().split(Global.tagDelimeter);
\r
1444 if (!completionText.equals("") && newTagArray.length > 0) {
\r
1445 newTagArray[newTagArray.length-1] = completionText;
\r
1447 // Remove any potential duplicates from the new list
\r
1448 for (int i=0; i<newTagArray.length; i++) {
\r
1449 boolean foundOnce = false;
\r
1450 for (int j=0; j<newTagArray.length; j++) {
\r
1451 if (newTagArray[j].equalsIgnoreCase(newTagArray[i])) {
\r
1455 newTagArray[j] = "";
\r
1460 List<String> newTagList = new ArrayList<String>();
\r
1461 List<String> oldTagList = new ArrayList<String>();
\r
1463 for (int i = 0; i < oldTagArray.length; i++)
\r
1464 if (!oldTagArray[i].trim().equals(""))
\r
1465 oldTagList.add(oldTagArray[i]);
\r
1466 for (int i = 0; i < newTagArray.length; i++)
\r
1467 if (!newTagArray[i].trim().equals(""))
\r
1468 newTagList.add(newTagArray[i]);
\r
1470 // Let's cleanup the appearance of the tag list
\r
1471 Collections.sort(newTagList);
\r
1472 String newDisplay = "";
\r
1473 for (int i=0; i<newTagList.size(); i++) {
\r
1474 newDisplay = newDisplay+newTagList.get(i);
\r
1475 if (i<newTagList.size()-1)
\r
1476 newDisplay = newDisplay+", ";
\r
1478 tagEdit.blockSignals(true);
\r
1479 tagEdit.setText(newDisplay);
\r
1480 tagEdit.blockSignals(false);
\r
1482 // We now have lists of the new & old. Remove duplicates. If all
\r
1483 // are removed from both then nothing has really changed
\r
1484 for (int i = newTagList.size() - 1; i >= 0; i--) {
\r
1485 String nTag = newTagList.get(i);
\r
1486 for (int j = oldTagList.size() - 1; j >= 0; j--) {
\r
1487 String oTag = oldTagList.get(j);
\r
1488 if (oTag.equalsIgnoreCase(nTag)) {
\r
1489 oldTagList.remove(j);
\r
1490 newTagList.remove(i);
\r
1496 if (oldTagList.size() != 0 || newTagList.size() != 0) {
\r
1497 currentTags.clear();
\r
1498 newTagArray = tagEdit.text().split(Global.tagDelimeter);
\r
1499 for (int i = 0; i < newTagArray.length; i++)
\r
1500 if (!newTagArray[i].trim().equals(""))
\r
1501 currentTags.add(newTagArray[i].trim());
\r
1503 noteSignal.tagsChanged.emit(currentNote.getGuid(), currentTags);
\r
1508 // Tab button was pressed
\r
1509 public void tabPressed() {
\r
1510 if (!insideList) {
\r
1511 String script_start = new String(
\r
1512 "document.execCommand('insertHtml', false, ' ');");
\r
1513 browser.page().mainFrame().evaluateJavaScript(script_start);
\r
1518 public void backtabPressed() {
\r
1523 public void setInsideList() {
\r
1524 insideList = true;
\r
1527 // The title has been edited
\r
1528 @SuppressWarnings("unused")
\r
1529 private void titleEdited() {
\r
1530 // If we don't have a good note, or if the current title
\r
1531 // matches the old title then we don't need to do anything
\r
1532 if (currentNote == null)
\r
1534 if (currentNote.getTitle().trim().equals(titleLabel.text().trim()))
\r
1537 // If we have a real change, we need to save it.
\r
1538 noteSignal.titleChanged.emit(currentNote.getGuid(), titleLabel.text());
\r
1539 currentNote.setTitle(titleLabel.text());
\r
1540 saveNoteTitle = titleLabel.text();
\r
1544 // Set the list of note tags
\r
1545 public void setAllTags(List<Tag> l) {
\r
1547 tagEdit.setTagList(l);
\r
1550 // Setter for the current tags
\r
1551 public void setCurrentTags(List<String> s) {
\r
1555 // Save the list of notebooks
\r
1556 public void setNotebookList(List<Notebook> n) {
\r
1558 loadNotebookList();
\r
1561 // Load the notebook list and select the current notebook
\r
1562 private void loadNotebookList() {
\r
1563 if (notebookBox.count() != 0)
\r
1564 notebookBox.clear();
\r
1565 if (notebookList == null)
\r
1568 for (int i = 0; i < notebookList.size(); i++) {
\r
1569 notebookBox.addItem(notebookList.get(i).getName());
\r
1570 if (currentNote != null) {
\r
1571 if (currentNote.getNotebookGuid().equals(
\r
1572 notebookList.get(i).getGuid())) {
\r
1573 notebookBox.setCurrentIndex(i);
\r
1579 // Get the contents of the editor
\r
1580 public String getContent() {
\r
1581 return browser.page().currentFrame().toHtml();
\r
1584 // The note contents have changed
\r
1585 public void contentChanged() {
\r
1586 String content = getContent();
\r
1588 noteSignal.noteChanged.emit(currentNote.getGuid(), content);
\r
1591 // The notebook selection has changed
\r
1592 @SuppressWarnings("unused")
\r
1593 private void notebookChanged() {
\r
1594 boolean changed = false;
\r
1595 String n = notebookBox.currentText();
\r
1596 for (int i = 0; i < notebookList.size(); i++) {
\r
1597 if (n.equals(notebookList.get(i).getName())) {
\r
1598 if (!notebookList.get(i).getGuid().equals(currentNote.getNotebookGuid())) {
\r
1599 currentNote.setNotebookGuid(notebookList.get(i).getGuid());
\r
1602 i = notebookList.size();
\r
1606 // If the notebook changed, signal the update
\r
1608 noteSignal.notebookChanged.emit(currentNote.getGuid(), currentNote
\r
1609 .getNotebookGuid());
\r
1612 // Check the note title
\r
1613 private void checkNoteTitle() {
\r
1614 String text = browser.page().currentFrame().toPlainText();
\r
1615 if (saveNoteTitle.trim().equals("") || saveNoteTitle.trim().equals("Untitled Note")) {
\r
1616 int newLine = text.indexOf("\n");
\r
1617 if (newLine > 0) {
\r
1618 text = text.substring(0, newLine);
\r
1619 if (text.trim().equals(""))
\r
1620 text = tr("Untitled Note");
\r
1621 titleLabel.setText(text);
\r
1623 if (text.length() > Constants.EDAM_NOTE_TITLE_LEN_MAX)
\r
1624 titleLabel.setText(text.substring(0, Constants.EDAM_NOTE_TITLE_LEN_MAX));
\r
1626 titleLabel.blockSignals(true);
\r
1627 if (text.trim().equals(""))
\r
1628 titleLabel.setText(tr("Untitled Note"));
\r
1630 titleLabel.setText(text);
\r
1631 titleLabel.blockSignals(false);
\r
1634 noteSignal.titleChanged.emit(currentNote.getGuid(), titleLabel
\r
1639 // Return the note contents so we can email them
\r
1640 public String getContentsToEmail() {
\r
1641 return browser.page().currentFrame().toPlainText().trim();
\r
1643 * int body = browser.page().currentFrame().toHtml().indexOf("<body>");
\r
1644 * String temp = browser.page().currentFrame().toHtml(); if (body == -1)
\r
1645 * temp = "<html><body><b>Test</b></body></html>"; else temp =
\r
1646 * "<html>"+temp.substring(body); return temp; // return
\r
1647 * urlEncode(browser.page().currentFrame().toHtml());
\r
1651 // Insert an image into the editor
\r
1652 private void insertImage(QMimeData mime) {
\r
1653 logger.log(logger.EXTREME, "Entering insertImage");
\r
1654 QImage img = (QImage) mime.imageData();
\r
1655 String script_start = new String(
\r
1656 "document.execCommand('insertHTML', false, '");
\r
1657 String script_end = new String("');");
\r
1659 long now = new Date().getTime();
\r
1660 String path = Global.getFileManager().getResDirPath(
\r
1661 (new Long(now).toString()) + ".jpg");
\r
1663 // This block is just a hack to make sure we wait at least 1ms so we
\r
1665 // have collisions on image names
\r
1666 long i = new Date().getTime();
\r
1668 i = new Date().getTime();
\r
1670 // Open the file & write the data
\r
1671 QFile tfile = new QFile(path);
\r
1672 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
\r
1676 Resource newRes = createResource(QUrl.fromLocalFile(path).toString(), 0, "image/jpeg", false);
\r
1677 if (newRes == null)
\r
1679 currentNote.getResources().add(newRes);
\r
1681 // do the actual insert into the note
\r
1682 StringBuffer buffer = new StringBuffer(100);
\r
1683 buffer.append("<img src=\"");
\r
1684 buffer.append(tfile.fileName());
\r
1685 buffer.append("\" en-tag=en-media type=\"image/jpeg\""
\r
1686 +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""
\r
1687 +" guid=\"" +newRes.getGuid() +"\""
\r
1688 // +" onContextMenu=\"window.jambi.imageContextMenu('" +tfile.fileName() +"');\""
\r
1689 +" onContextMenu=\"window.jambi.imageContextMenu(&." +tfile.fileName() +"&.);\""
\r
1692 browser.page().mainFrame().evaluateJavaScript(
\r
1693 script_start + buffer + script_end);
\r
1698 // Handle URLs that are trying to be pasted
\r
1699 public void handleUrls(QMimeData mime) {
\r
1700 logger.log(logger.EXTREME, "Starting handleUrls");
\r
1701 FileNameMap fileNameMap = URLConnection.getFileNameMap();
\r
1703 List<QUrl> urlList = mime.urls();
\r
1704 String url = new String();
\r
1705 String script_start = new String(
\r
1706 "document.execCommand('createLink', false, '");
\r
1707 String script_end = new String("');");
\r
1709 for (int i = 0; i < urlList.size(); i++) {
\r
1710 url = urlList.get(i).toString();
\r
1711 // Find out what type of file we have
\r
1712 String mimeType = fileNameMap.getContentTypeFor(url);
\r
1714 // If null returned, we need to guess at the file type
\r
1715 if (mimeType == null)
\r
1716 mimeType = "application/"
\r
1717 + url.substring(url.lastIndexOf(".") + 1);
\r
1719 // Check if we have an image or some other type of file
\r
1720 if (url.substring(0, 5).equalsIgnoreCase("file:")
\r
1721 && mimeType.substring(0, 5).equalsIgnoreCase("image")) {
\r
1722 handleLocalImageURLPaste(mime, mimeType);
\r
1725 String[] type = mimeType.split("/");
\r
1726 boolean valid = validAttachment(type[1]);
\r
1727 boolean smallEnough = checkFileAttachmentSize(url);
\r
1728 if (smallEnough && valid
\r
1729 && url.substring(0, 5).equalsIgnoreCase("file:")
\r
1730 && !mimeType.substring(0, 5).equalsIgnoreCase("image")) {
\r
1731 handleLocalAttachment(mime, mimeType);
\r
1734 browser.page().mainFrame().evaluateJavaScript(
\r
1735 script_start + url + script_end);
\r
1740 // If a URL being pasted is an image URL, then attach the image
\r
1741 private void handleLocalImageURLPaste(QMimeData mime, String mimeType) {
\r
1742 List<QUrl> urlList = mime.urls();
\r
1743 String url = new String();
\r
1744 String script_start_image = new String(
\r
1745 "document.execCommand('insertHtml', false, '");
\r
1746 String script_end = new String("');");
\r
1747 StringBuffer buffer;
\r
1749 // Copy the image over into the resource directory and create a new resource
\r
1750 // record for each url pasted
\r
1751 for (int i = 0; i < urlList.size(); i++) {
\r
1752 url = urlList.get(i).toString();
\r
1754 Resource newRes = createResource(url, i, mimeType, false);
\r
1755 if (newRes == null)
\r
1757 currentNote.getResources().add(newRes);
\r
1758 buffer = new StringBuffer(100);
\r
1760 // Open the file & write the data
\r
1761 String fileName = Global.getFileManager().getResDirPath(newRes.getGuid());
\r
1762 QFile tfile = new QFile(fileName);
\r
1763 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
\r
1764 tfile.write(newRes.getData().getBody());
\r
1766 buffer.append(script_start_image);
\r
1767 buffer.append("<img src=\"" + FileUtils.toForwardSlashedPath(fileName));
\r
1768 // if (mimeType.equalsIgnoreCase("image/jpg"))
\r
1769 // mimeType = "image/jpeg";
\r
1770 buffer.append("\" en-tag=\"en-media\" type=\"" + mimeType +"\""
\r
1771 +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""
\r
1772 +" guid=\"" +newRes.getGuid() +"\""
\r
1773 +" onContextMenu=\"window.jambi.imageContextMenu('" +tfile.fileName() +"');\""
\r
1775 buffer.append(script_end);
\r
1776 browser.page().mainFrame().evaluateJavaScript(buffer.toString());
\r
1782 // If a URL being pasted is a local file URL, then attach the file
\r
1783 private void handleLocalAttachment(QMimeData mime, String mimeType) {
\r
1784 logger.log(logger.EXTREME, "Attaching local file");
\r
1785 List<QUrl> urlList = mime.urls();
\r
1786 String script_start = new String(
\r
1787 "document.execCommand('insertHtml', false, '");
\r
1788 String script_end = new String("');");
\r
1789 StringBuffer buffer;
\r
1791 String[] type = mimeType.split("/");
\r
1792 String icon = findIcon(type[1]);
\r
1793 if (icon.equals("attachment.png"))
\r
1794 icon = findIcon(type[0]);
\r
1795 buffer = new StringBuffer(100);
\r
1797 for (int i = 0; i < urlList.size(); i++) {
\r
1798 String url = urlList.get(i).toString();
\r
1800 // Start building the HTML
\r
1801 if (icon.equals("attachment.png"))
\r
1802 icon = findIcon(url.substring(url.lastIndexOf(".")+1));
\r
1803 String imageURL = FileUtils.toFileURLString(Global.getFileManager().getImageDirFile(icon));
\r
1805 logger.log(logger.EXTREME, "Creating resource ");
\r
1806 Resource newRes = createResource(url, i, mimeType, true);
\r
1807 if (newRes == null)
\r
1809 logger.log(logger.EXTREME, "New resource size: " +newRes.getData().getSize());
\r
1810 currentNote.getResources().add(newRes);
\r
1812 String fileName = newRes.getGuid() + Global.attachmentNameDelimeter+newRes.getAttributes().getFileName();
\r
1813 // If we have a PDF, we need to setup the preview.
\r
1814 if (icon.equalsIgnoreCase("pdf.png") && Global.pdfPreview()) {
\r
1815 logger.log(logger.EXTREME, "Setting up PDF preview");
\r
1816 if (newRes.getAttributes() != null &&
\r
1817 newRes.getAttributes().getFileName() != null &&
\r
1818 !newRes.getAttributes().getFileName().trim().equals(""))
\r
1819 fileName = newRes.getGuid()+Global.attachmentNameDelimeter+
\r
1820 newRes.getAttributes().getFileName();
\r
1822 fileName = newRes.getGuid()+".pdf";
\r
1823 QFile file = new QFile(Global.getFileManager().getResDirPath(fileName));
\r
1824 QFile.OpenMode mode = new QFile.OpenMode();
\r
1825 mode.set(QFile.OpenModeFlag.WriteOnly);
\r
1827 QDataStream out = new QDataStream(file);
\r
1828 // Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(newRes.getGuid(), true);
\r
1829 QByteArray binData = new QByteArray(newRes.getData().getBody());
\r
1830 // resBinary = null;
\r
1831 out.writeBytes(binData.toByteArray());
\r
1834 PDFPreview pdfPreview = new PDFPreview();
\r
1835 if (pdfPreview.setupPreview(Global.getFileManager().getResDirPath(fileName), "pdf",0)) {
\r
1836 // NFC TODO: should this be a 'file://' url like the ones above?
\r
1837 imageURL = file.fileName() + ".png";
\r
1841 logger.log(logger.EXTREME, "Generating link tags");
\r
1842 buffer.delete(0, buffer.length());
\r
1843 buffer.append("<a en-tag=\"en-media\" guid=\"" +newRes.getGuid()+"\" ");
\r
1844 buffer.append(" onContextMenu=\"window.jambi.imageContextMenu('")
\r
1845 .append(Global.getFileManager().getResDirPath(fileName))
\r
1846 .append("');\" "); buffer.append("type=\"" + mimeType + "\" href=\"nnres://" + fileName +"\" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\" >");
\r
1847 buffer.append("<img src=\"" + imageURL + "\" title=\"" +newRes.getAttributes().getFileName());
\r
1848 buffer.append("\"></img>");
\r
1849 buffer.append("</a>");
\r
1850 browser.page().mainFrame().evaluateJavaScript(
\r
1851 script_start + buffer.toString() + script_end);
\r
1856 private Resource createResource(String url, int sequence, String mime, boolean attachment) {
\r
1857 logger.log(logger.EXTREME, "Inside create resource");
\r
1858 QFile resourceFile;
\r
1859 String urlTest = new QUrl(url).toLocalFile();
\r
1860 if (!urlTest.equals(""))
\r
1862 url = url.replace("/", File.separator);
\r
1863 resourceFile = new QFile(url);
\r
1864 resourceFile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly));
\r
1865 byte[] fileData = resourceFile.readAll().toByteArray();
\r
1866 resourceFile.close();
\r
1867 if (fileData.length == 0)
\r
1871 md = MessageDigest.getInstance("MD5");
\r
1872 md.update(fileData);
\r
1873 byte[] hash = md.digest();
\r
1875 Resource r = new Resource();
\r
1876 Calendar time = new GregorianCalendar();
\r
1877 long prevTime = time.getTimeInMillis();
\r
1878 while (prevTime == time.getTimeInMillis()) {
\r
1879 time = new GregorianCalendar();
\r
1881 r.setGuid(time.getTimeInMillis()+new Integer(sequence).toString());
\r
1882 r.setNoteGuid(currentNote.getGuid());
\r
1884 r.setActive(true);
\r
1885 r.setUpdateSequenceNum(0);
\r
1886 r.setWidth((short) 0);
\r
1887 r.setHeight((short) 0);
\r
1888 r.setDuration((short) 0);
\r
1890 Data d = new Data();
\r
1891 d.setBody(fileData);
\r
1892 d.setBodyIsSet(true);
\r
1893 d.setBodyHash(hash);
\r
1894 d.setBodyHashIsSet(true);
\r
1896 d.setSize(fileData.length);
\r
1898 int fileNamePos = url.lastIndexOf(File.separator);
\r
1899 if (fileNamePos == -1)
\r
1900 fileNamePos = url.lastIndexOf("/");
\r
1901 String fileName = url.substring(fileNamePos+1);
\r
1902 ResourceAttributes a = new ResourceAttributes();
\r
1904 a.setAltitudeIsSet(false);
\r
1905 a.setLongitude(0);
\r
1906 a.setLongitudeIsSet(false);
\r
1908 a.setLatitudeIsSet(false);
\r
1909 a.setCameraMake("");
\r
1910 a.setCameraMakeIsSet(false);
\r
1911 a.setCameraModel("");
\r
1912 a.setCameraModelIsSet(false);
\r
1913 a.setAttachment(attachment);
\r
1914 a.setAttachmentIsSet(true);
\r
1915 a.setClientWillIndex(false);
\r
1916 a.setClientWillIndexIsSet(true);
\r
1917 a.setRecoType("");
\r
1918 a.setRecoTypeIsSet(false);
\r
1919 a.setSourceURL(url);
\r
1920 a.setSourceURLIsSet(true);
\r
1921 a.setTimestamp(0);
\r
1922 a.setTimestampIsSet(false);
\r
1923 a.setFileName(fileName);
\r
1924 a.setFileNameIsSet(true);
\r
1925 r.setAttributes(a);
\r
1927 conn.getNoteTable().noteResourceTable.saveNoteResource(r, true);
\r
1929 } catch (NoSuchAlgorithmException e1) {
\r
1930 e1.printStackTrace();
\r
1936 // find the appropriate icon for an attachment
\r
1937 private String findIcon(String appl) {
\r
1938 appl = appl.toLowerCase();
\r
1939 File f = Global.getFileManager().getImageDirFile(appl + ".png");
\r
1941 return appl+".png";
\r
1942 return "attachment.png";
\r
1945 // Check if the account supports this type of attachment
\r
1946 private boolean validAttachment(String type) {
\r
1947 if (Global.isPremium())
\r
1949 if (type.equalsIgnoreCase("JPG"))
\r
1951 if (type.equalsIgnoreCase("PNG"))
\r
1953 if (type.equalsIgnoreCase("GIF"))
\r
1955 if (type.equalsIgnoreCase("MP3"))
\r
1957 if (type.equalsIgnoreCase("WAV"))
\r
1959 if (type.equalsIgnoreCase("AMR"))
\r
1961 if (type.equalsIgnoreCase("PDF"))
\r
1963 String error = tr("Non-premium accounts can only attach JPG, PNG, GIF, MP3, WAV, AMR, or PDF files.");
\r
1964 QMessageBox.information(this, tr("Non-Premium Account"), error);
\r
1969 // Check the file attachment to be sure it isn't over 25 mb
\r
1970 private boolean checkFileAttachmentSize(String url) {
\r
1971 String fileName = url.substring(8);
\r
1972 QFile resourceFile = new QFile(fileName);
\r
1973 resourceFile.open(new QIODevice.OpenMode(
\r
1974 QIODevice.OpenModeFlag.ReadOnly));
\r
1975 long size = resourceFile.size();
\r
1976 resourceFile.close();
\r
1977 size = size / 1024 / 1024;
\r
1978 if (size < 50 && Global.isPremium())
\r
1983 String error = tr("A file attachment may not exceed 25MB.");
\r
1984 QMessageBox.information(this, tr("Attachment Size"), error);
\r
1989 @SuppressWarnings("unused")
\r
1990 private void createdChanged() {
\r
1991 QDateTime dt = new QDateTime();
\r
1992 dt.setDate(createdDate.date());
\r
1993 dt.setTime(createdTime.time());
\r
1994 noteSignal.createdDateChanged.emit(currentNote.getGuid(), dt);
\r
1998 @SuppressWarnings("unused")
\r
1999 private void alteredChanged() {
\r
2000 QDateTime dt = new QDateTime();
\r
2001 dt.setDate(alteredDate.date());
\r
2002 dt.setTime(alteredTime.time());
\r
2003 noteSignal.alteredDateChanged.emit(currentNote.getGuid(), dt);
\r
2006 @SuppressWarnings("unused")
\r
2007 private void subjectDateTimeChanged() {
\r
2008 QDateTime dt = new QDateTime();
\r
2009 dt.setDate(subjectDate.date());
\r
2010 dt.setTime(subjectTime.time());
\r
2011 noteSignal.subjectDateChanged.emit(currentNote.getGuid(), dt);
\r
2015 @SuppressWarnings("unused")
\r
2016 private void sourceUrlChanged() {
\r
2017 noteSignal.sourceUrlChanged.emit(currentNote.getGuid(), urlText.text());
\r
2020 @SuppressWarnings("unused")
\r
2021 private void authorChanged() {
\r
2022 noteSignal.authorChanged.emit(currentNote.getGuid(), authorText.text());
\r
2025 @SuppressWarnings("unused")
\r
2026 private void geoBoxChanged() {
\r
2027 int index = geoBox.currentIndex();
\r
2028 geoBox.setCurrentIndex(0);
\r
2030 GeoDialog box = new GeoDialog();
\r
2031 box.setLongitude(currentNote.getAttributes().getLongitude());
\r
2032 box.setLatitude(currentNote.getAttributes().getLatitude());
\r
2033 box.setAltitude(currentNote.getAttributes().getAltitude());
\r
2035 if (!box.okPressed())
\r
2037 double alt = box.getAltitude();
\r
2038 double lat = box.getLatitude();
\r
2039 double lon = box.getLongitude();
\r
2040 if (alt != currentNote.getAttributes().getAltitude() ||
\r
2041 lon != currentNote.getAttributes().getLongitude() ||
\r
2042 lat != currentNote.getAttributes().getLatitude()) {
\r
2043 noteSignal.geoChanged.emit(currentNote.getGuid(), lon, lat, alt);
\r
2044 currentNote.getAttributes().setAltitude(alt);
\r
2045 currentNote.getAttributes().setLongitude(lon);
\r
2046 currentNote.getAttributes().setLatitude(lat);
\r
2051 noteSignal.geoChanged.emit(currentNote.getGuid(), 0.0, 0.0, 0.0);
\r
2052 currentNote.getAttributes().setAltitude(0.0);
\r
2053 currentNote.getAttributes().setLongitude(0.0);
\r
2054 currentNote.getAttributes().setLatitude(0.0);
\r
2057 if (index == 3 || index == 0) {
\r
2058 QDesktopServices.openUrl(new QUrl("http://maps.google.com/maps?z=6&q="+currentNote.getAttributes().getLatitude() +"," +currentNote.getAttributes().getLongitude()));
\r
2062 // ************************************************************
\r
2063 // * User chose to save an attachment. Pares out the request *
\r
2064 // * into a guid & file. Save the result. *
\r
2065 // ************************************************************
\r
2066 public void downloadAttachment(QNetworkRequest request) {
\r
2068 QFileDialog fd = new QFileDialog(this);
\r
2069 fd.setFileMode(FileMode.AnyFile);
\r
2070 fd.setConfirmOverwrite(true);
\r
2071 fd.setWindowTitle(tr("Save File"));
\r
2072 fd.setAcceptMode(AcceptMode.AcceptSave);
\r
2073 fd.setDirectory(System.getProperty("user.home"));
\r
2074 String name = request.url().toString();
\r
2076 int pos = name.lastIndexOf(Global.attachmentNameDelimeter);
\r
2078 guid = name.substring(0, pos).replace("nnres://", "");
\r
2079 name = name.substring(pos +Global.attachmentNameDelimeter.length());
\r
2080 fd.selectFile(name);
\r
2081 pos = name.lastIndexOf('.');
\r
2083 String mimeType = "(*." + name.substring(pos + 1)
\r
2084 + ");; All Files (*)";
\r
2085 fd.setFilter(tr(mimeType));
\r
2091 // Strip URL prefix and base dir
\r
2092 guid = guid.replace("nnres://", "")
\r
2093 .replace(FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath()), "");
\r
2095 pos = guid.lastIndexOf('.');
\r
2097 guid = guid.substring(0,pos);
\r
2098 if (fd.exec() != 0 && fd.selectedFiles().size() > 0) {
\r
2099 name = name.replace('\\', '/');
\r
2100 Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
\r
2101 QFile saveFile = new QFile(fd.selectedFiles().get(0));
\r
2102 QFile.OpenMode mode = new QFile.OpenMode();
\r
2103 mode.set(QFile.OpenModeFlag.WriteOnly);
\r
2104 saveFile.open(mode);
\r
2105 QDataStream saveOut = new QDataStream(saveFile);
\r
2106 QByteArray binData = new QByteArray(resBinary.getData().getBody());
\r
2107 saveOut.writeBytes(binData.toByteArray());
\r
2114 // ************************************************************
\r
2115 // * User chose to save an attachment. Pares out the request *
\r
2116 // * into a guid & file. Save the result. --- DONE FROM downloadAttachment now!!!!!
\r
2117 // ************************************************************
\r
2118 // NFC TODO: unused? remove
\r
2119 public void downloadImage(QNetworkRequest request) {
\r
2120 QFileDialog fd = new QFileDialog(this);
\r
2121 fd.setFileMode(FileMode.AnyFile);
\r
2122 fd.setConfirmOverwrite(true);
\r
2123 fd.setWindowTitle(tr("Save File"));
\r
2124 fd.setAcceptMode(AcceptMode.AcceptSave);
\r
2125 fd.setDirectory(System.getProperty("user.home"));
\r
2126 String name = request.url().toString();
\r
2127 name = name.replace("nnres://", "");
\r
2128 String dPath = FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath());
\r
2129 name = name.replace(dPath, "");
\r
2130 int pos = name.lastIndexOf('.');
\r
2131 String guid = name;
\r
2133 String mimeType = "(*." + name.substring(pos + 1)
\r
2134 + ");; All Files (*)";
\r
2135 fd.setFilter(tr(mimeType));
\r
2136 guid = guid.substring(0,pos);
\r
2138 pos = name.lastIndexOf(Global.attachmentNameDelimeter);
\r
2140 guid = name.substring(0, pos);
\r
2141 fd.selectFile(name.substring(pos+Global.attachmentNameDelimeter.length()));
\r
2143 if (fd.exec() != 0 && fd.selectedFiles().size() > 0) {
\r
2144 Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
\r
2145 String fileName = fd.selectedFiles().get(0);
\r
2146 QFile saveFile = new QFile(fileName);
\r
2147 QFile.OpenMode mode = new QFile.OpenMode();
\r
2148 mode.set(QFile.OpenModeFlag.WriteOnly);
\r
2149 saveFile.open(mode);
\r
2150 QDataStream saveOut = new QDataStream(saveFile);
\r
2151 QByteArray binData = new QByteArray(resBinary.getData().getBody());
\r
2152 saveOut.writeBytes(binData.toByteArray());
\r
2158 // *************************************************************
\r
2159 // * decrypt any hidden text. We could do an XML parse, but
\r
2160 // * it is quicker here just to scan for an <img tag & do the fix
\r
2161 // * the manual way
\r
2162 // *************************************************************
\r
2163 private void removeEncryption(String id, String plainText, boolean permanent, String slot) {
\r
2165 plainText = " <en-crypt-temp slot=\""+slot +"\">" +plainText+"</en-crypt-temp> ";
\r
2168 String html = browser.page().mainFrame().toHtml();
\r
2169 String text = html;
\r
2170 int imagePos = html.indexOf("<img");
\r
2172 for ( ;imagePos>0; ) {
\r
2173 // Find the end tag
\r
2174 endPos = text.indexOf(">", imagePos);
\r
2175 String tag = text.substring(imagePos-1,endPos);
\r
2176 if (tag.indexOf("id=\""+id+"\"") > -1) {
\r
2177 text = text.substring(0,imagePos) +plainText+text.substring(endPos+1);
\r
2179 browser.setContent(new QByteArray(text));
\r
2182 imagePos = text.indexOf("<img", imagePos+1);
\r
2187 //****************************************************************
\r
2188 //* Focus shortcuts
\r
2189 //****************************************************************
\r
2190 @SuppressWarnings("unused")
\r
2191 private void focusTitle() {
\r
2192 titleLabel.setFocus();
\r
2194 @SuppressWarnings("unused")
\r
2195 private void focusTag() {
\r
2196 tagEdit.setFocus();
\r
2198 @SuppressWarnings("unused")
\r
2199 private void focusNote() {
\r
2200 browser.setFocus();
\r
2202 @SuppressWarnings("unused")
\r
2203 private void focusAuthor() {
\r
2204 authorLabel.setFocus();
\r
2206 @SuppressWarnings("unused")
\r
2207 private void focusUrl() {
\r
2208 urlLabel.setFocus();
\r
2212 //*****************************************************************
\r
2213 //* Set the document background color
\r
2214 //*****************************************************************
\r
2215 public void setBackgroundColor(String color) {
\r
2216 String js = "function changeBackground(color) {"
\r
2217 +"document.body.style.background = color;"
\r
2219 +"changeBackground('" +color+"');";
\r
2220 browser.page().mainFrame().evaluateJavaScript(js);
\r
2225 //****************************************************************
\r
2226 //* MicroFocus changed
\r
2227 //****************************************************************
\r
2228 private void microFocusChanged() {
\r
2229 boldButton.setDown(false);
\r
2230 italicButton.setDown(false);
\r
2231 underlineButton.setDown(false);
\r
2232 browser.openAction.setEnabled(false);
\r
2233 browser.downloadAttachment.setEnabled(false);
\r
2234 browser.downloadImage.setEnabled(false);
\r
2235 browser.rotateImageLeft.setEnabled(false);
\r
2236 browser.rotateImageRight.setEnabled(false);
\r
2237 browser.insertTableAction.setEnabled(true);
\r
2238 browser.insertTableRowAction.setEnabled(false);
\r
2239 browser.deleteTableRowAction.setEnabled(false);
\r
2240 browser.insertLinkAction.setText(tr("Insert Hyperlink"));
\r
2241 currentHyperlink ="";
\r
2242 insideList = false;
\r
2243 forceTextPaste = false;
\r
2245 String js = new String( "function getCursorPos() {"
\r
2247 +"if (window.getSelection) {"
\r
2248 +" var selObj = window.getSelection();"
\r
2249 +" var selRange = selObj.getRangeAt(0);"
\r
2250 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
2251 +" while(workingNode != null) { "
\r
2252 // +" window.jambi.printNode(workingNode.nodeName);"
\r
2253 +" if (workingNode.nodeName=='EN-CRYPT-TEMP') window.jambi.forceTextPaste();"
\r
2254 +" if (workingNode.nodeName=='B') window.jambi.boldActive();"
\r
2255 +" if (workingNode.nodeName=='I') window.jambi.italicActive();"
\r
2256 +" if (workingNode.nodeName=='U') window.jambi.underlineActive();"
\r
2257 +" if (workingNode.nodeName=='UL') window.jambi.setInsideList();"
\r
2258 +" if (workingNode.nodeName=='OL') window.jambi.setInsideList();"
\r
2259 +" if (workingNode.nodeName=='LI') window.jambi.setInsideList();"
\r
2260 +" if (workingNode.nodeName=='TBODY') window.jambi.setInsideTable();"
\r
2261 +" 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);}}"
\r
2262 +" if (workingNode.nodeName=='SPAN') {"
\r
2263 +" if (workingNode.getAttribute('style') == 'text-decoration: underline;') window.jambi.underlineActive();"
\r
2265 +" workingNode = workingNode.parentNode;"
\r
2268 +"} getCursorPos();");
\r
2269 browser.page().mainFrame().evaluateJavaScript(js);
\r
2272 public void printNode(String n) {
\r
2273 System.out.println("Node Vaule: " +n);
\r
2277 //****************************************************************
\r
2278 //* Insert a table row
\r
2279 //****************************************************************
\r
2280 public void insertTableRow() {
\r
2282 String js = new String( "function insertTableRow() {"
\r
2283 +" var selObj = window.getSelection();"
\r
2284 +" var selRange = selObj.getRangeAt(0);"
\r
2285 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
2286 +" var cellCount = 0;"
\r
2287 +" while(workingNode != null) { "
\r
2288 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
\r
2289 +" row = document.createElement('TR');"
\r
2290 +" var nodes = workingNode.getElementsByTagName('td');"
\r
2291 +" for (j=0; j<nodes.length; j=j+1) {"
\r
2292 +" cell = document.createElement('TD');"
\r
2293 +" cell.innerHTML=' ';"
\r
2294 +" row.appendChild(cell);"
\r
2296 +" workingNode.parentNode.insertBefore(row,workingNode.nextSibling);"
\r
2299 +" workingNode = workingNode.parentNode;"
\r
2301 +"} insertTableRow();");
\r
2302 browser.page().mainFrame().evaluateJavaScript(js);
\r
2305 //****************************************************************
\r
2306 //* Insert a table row
\r
2307 //****************************************************************
\r
2308 public void deleteTableRow() {
\r
2310 String js = new String( "function deleteTableRow() {"
\r
2311 +" var selObj = window.getSelection();"
\r
2312 +" var selRange = selObj.getRangeAt(0);"
\r
2313 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
2314 +" var cellCount = 0;"
\r
2315 +" while(workingNode != null) { "
\r
2316 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
\r
2317 +" workingNode.parentNode.removeChild(workingNode);"
\r
2320 +" workingNode = workingNode.parentNode;"
\r
2322 +"} deleteTableRow();");
\r
2323 browser.page().mainFrame().evaluateJavaScript(js);
\r
2326 public void setInsideTable() {
\r
2327 browser.insertTableRowAction.setEnabled(true);
\r
2328 browser.deleteTableRowAction.setEnabled(true);
\r
2329 browser.insertTableAction.setEnabled(false);
\r
2330 browser.encryptAction.setEnabled(false);
\r
2333 public void setInsideLink(String link) {
\r
2334 browser.insertLinkAction.setText(tr("Edit Hyperlink"));
\r
2335 currentHyperlink = link;
\r
2338 public void italicActive() {
\r
2339 italicButton.setDown(true);
\r
2341 public void boldActive() {
\r
2342 boldButton.setDown(true);
\r
2344 public void underlineActive() {
\r
2345 underlineButton.setDown(true);
\r
2347 public void forceTextPaste() {
\r
2348 forceTextPaste = true;
\r
2350 public void imageContextMenu(String f) {
\r
2351 browser.downloadImage.setEnabled(true);
\r
2352 browser.rotateImageRight.setEnabled(true);
\r
2353 browser.rotateImageLeft.setEnabled(true);
\r
2354 browser.openAction.setEnabled(true);
\r
2357 public void rotateImageRight() {
\r
2358 QWebSettings.setMaximumPagesInCache(0);
\r
2359 QWebSettings.setObjectCacheCapacities(0, 0, 0);
\r
2360 QImage image = new QImage(selectedFile);
\r
2361 QMatrix matrix = new QMatrix();
\r
2362 matrix.rotate( 90.0 );
\r
2363 image = image.transformed(matrix);
\r
2364 image.save(selectedFile);
\r
2365 QWebSettings.setMaximumPagesInCache(0);
\r
2366 QWebSettings.setObjectCacheCapacities(0, 0, 0);
\r
2367 browser.setHtml(browser.page().mainFrame().toHtml());
\r
2370 // resourceSignal.contentChanged.emit(selectedFile);
\r
2373 public void rotateImageLeft() {
\r
2374 QImage image = new QImage(selectedFile);
\r
2375 QMatrix matrix = new QMatrix();
\r
2376 matrix.rotate( -90.0 );
\r
2377 image = image.transformed(matrix);
\r
2378 image.save(selectedFile);
\r
2379 browser.setHtml(browser.page().mainFrame().toHtml());
\r
2382 // resourceSignal.contentChanged.emit(selectedFile);
\r
2384 public void resourceContextMenu(String f) {
\r
2385 browser.downloadAttachment.setEnabled(true);
\r
2386 browser.openAction.setEnabled(true);
\r
2391 //****************************************************************
\r
2392 //* Apply CSS style to specified word
\r
2393 //****************************************************************
\r
2394 /* public void applyStyleToWords(String word, String style) {
\r
2395 QFile script = new QFile("D:\\NeverNote\\js\\hilight1.js");
\r
2396 script.open(OpenModeFlag.ReadOnly);
\r
2397 String s = script.readAll().toString();
\r
2398 String js = new String(s +" findit('"+word+"', '"+style+"');");
\r
2399 browser.page().mainFrame().evaluateJavaScript(js);
\r
2400 System.out.println(getContent());
\r
2403 //****************************************************************
\r
2404 //* Someone tried to paste a resource between notes, so we need *
\r
2405 //* to do some special handling. *
\r
2406 //****************************************************************
\r
2407 private String fixInternotePaste(String text) {
\r
2408 logger.log(logger.EXTREME, "Fixing internote paste");
\r
2409 String returnValue = fixInternotePasteSearch(text, "<img", "src=\"");
\r
2410 return fixInternotePasteSearch(returnValue, "<a", "href=\"nnres://");
\r
2412 private String fixInternotePasteSearch(String text, String type, String locTag) {
\r
2414 // First, let's fix the images.
\r
2415 int startPos = text.indexOf(type);
\r
2417 for (; startPos>=0;) {
\r
2418 endPos = text.indexOf(">", startPos+1);
\r
2419 String segment = text.substring(startPos, endPos);
\r
2420 if (segment.indexOf("en-tag") > -1) {
\r
2421 String newSegment = segment;
\r
2423 int guidStartPos = segment.indexOf("guid=\"");
\r
2424 int guidEndPos = segment.indexOf("\"", guidStartPos+7);
\r
2425 String guid = segment.substring(guidStartPos+6,guidEndPos);
\r
2427 int mimeStartPos = segment.indexOf("type");
\r
2428 int mimeEndPos = segment.indexOf("\"", mimeStartPos+7);
\r
2429 String mime = segment.substring(mimeStartPos+6,mimeEndPos);
\r
2431 int srcStartPos = segment.indexOf("src");
\r
2432 int srcEndPos = segment.indexOf("\"", srcStartPos+6);
\r
2433 String src = segment.substring(srcStartPos+5,srcEndPos);
\r
2435 Calendar currentTime = new GregorianCalendar();
\r
2436 Long l = new Long(currentTime.getTimeInMillis());
\r
2437 long prevTime = l;
\r
2438 while (l==prevTime) {
\r
2439 currentTime = new GregorianCalendar();
\r
2440 l= new Long(currentTime.getTimeInMillis());
\r
2443 Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
\r
2444 // if r==null, then the image doesn't exist (it was probably cut out of another note, so
\r
2445 // we need to recereate it
\r
2447 r = createResource(src, 1, mime, false);
\r
2451 String randint = new String(Long.toString(l));
\r
2452 String extension = null;
\r
2453 if (r.getMime()!= null) {
\r
2454 extension = r.getMime().toLowerCase();
\r
2455 if (extension.indexOf("/")>-1)
\r
2456 extension = extension.substring(extension.indexOf("/")+1);
\r
2458 String newFile = randint;
\r
2459 if (r.getAttributes().getFileName() != null && r.getAttributes().getFileName() != "")
\r
2460 if (!locTag.startsWith("src"))
\r
2461 newFile = newFile+Global.attachmentNameDelimeter+r.getAttributes().getFileName();
\r
2462 r.setNoteGuid(currentNote.getGuid());
\r
2464 r.setGuid(randint);
\r
2465 conn.getNoteTable().noteResourceTable.saveNoteResource(r, true);
\r
2466 QFile f = new QFile(Global.getFileManager().getResDirPath(newFile));
\r
2467 QByteArray bin = new QByteArray(r.getData().getBody());
\r
2468 f.open(QFile.OpenModeFlag.WriteOnly);
\r
2471 newSegment = newSegment.replace("guid=\""+guid, "guid=\""+randint);
\r
2472 currentNote.getResources().add(r);
\r
2474 int startSrcPos = newSegment.indexOf(locTag);
\r
2475 int endSrcPos = newSegment.indexOf("\"",startSrcPos+locTag.length()+1);
\r
2477 if (locTag.startsWith("src")) {
\r
2478 source = newSegment.substring(startSrcPos+locTag.length(),endSrcPos);
\r
2479 newSegment = newSegment.replace(source,
\r
2480 FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath(newFile)));
\r
2482 source = newSegment.substring(startSrcPos+locTag.length(),endSrcPos);
\r
2483 newSegment = newSegment.replace(source, newFile);
\r
2486 text = text.substring(0,startPos) + newSegment + text.substring(endPos);
\r
2488 startPos = text.indexOf(type, startPos+1);
\r
2494 public void nextPage(String file) {
\r
2495 logger.log(logger.EXTREME, "Starting nextPage()");
\r
2497 Integer pageNumber;
\r
2498 if (previewPageList.containsKey(file))
\r
2499 pageNumber = previewPageList.get(file)+1;
\r
2502 previewPageList.remove(file);
\r
2503 previewPageList.put(file, pageNumber);
\r
2504 PDFPreview pdfPreview = new PDFPreview();
\r
2505 boolean goodPreview = pdfPreview.setupPreview(file, "pdf", pageNumber);
\r
2506 if (goodPreview) {
\r
2508 // String html = getContent();
\r
2509 QWebSettings.setMaximumPagesInCache(0);
\r
2510 QWebSettings.setObjectCacheCapacities(0, 0, 0);
\r
2511 // browser.setContent(new QByteArray());
\r
2512 browser.setHtml(browser.page().mainFrame().toHtml());
\r
2514 // browser.setContent(new QByteArray(html));
\r
2515 // browser.triggerPageAction(WebAction.Reload);
\r
2516 // pdfMouseOver(selectedFile);
\r
2520 public void previousPage(String file) {
\r
2521 logger.log(logger.EXTREME, "Starting previousPage()");
\r
2523 Integer pageNumber;
\r
2524 if (previewPageList.containsKey(file))
\r
2525 pageNumber = previewPageList.get(file)-1;
\r
2528 previewPageList.remove(file);
\r
2529 previewPageList.put(file, pageNumber);
\r
2530 PDFPreview pdfPreview = new PDFPreview();
\r
2531 boolean goodPreview = pdfPreview.setupPreview(file, "pdf", pageNumber);
\r
2532 if (goodPreview) {
\r
2534 // String html = getContent();
\r
2535 QWebSettings.setMaximumPagesInCache(0);
\r
2536 QWebSettings.setObjectCacheCapacities(0, 0, 0);
\r
2537 browser.setHtml(browser.page().mainFrame().toHtml());
\r
2539 // browser.setContent(new QByteArray(html));
\r
2540 // browser.triggerPageAction(WebAction.Reload);
\r
2544 /* public void pdfMouseOver(String name) {
\r
2546 if (previewPageList.containsKey(selectedFile))
\r
2547 pageNumber = previewPageList.get(selectedFile)+1;
\r
2551 if (pageNumber <= 1)
\r
2552 browser.previousPageAction.setEnabled(false);
\r
2554 browser.previousPageAction.setEnabled(true);
\r
2556 PDFPreview pdf = new PDFPreview();
\r
2557 int totalPages = pdf.getPageCount(name);
\r
2558 if (previewPageList.containsKey(selectedFile))
\r
2559 pageNumber = previewPageList.get(selectedFile)+1;
\r
2562 if (totalPages > pageNumber)
\r
2563 browser.nextPageAction.setEnabled(true);
\r
2565 browser.nextPageAction.setEnabled(false);
\r
2569 public void pdfMouseOut() {
\r
2570 // browser.nextPageAction.setVisible(false);
\r
2571 // browser.previousPageAction.setVisible(false);
\r
2575 private void toggleUndoVisible(Boolean toggle) {
\r
2576 undoAction.setVisible(toggle);
\r
2577 Global.saveEditorButtonsVisible("undo", toggle);
\r
2579 private void toggleRedoVisible(Boolean toggle) {
\r
2580 redoAction.setVisible(toggle);
\r
2581 Global.saveEditorButtonsVisible("redo", toggle);
\r
2583 private void toggleCutVisible(Boolean toggle) {
\r
2584 cutAction.setVisible(toggle);
\r
2585 Global.saveEditorButtonsVisible("cut", toggle);
\r
2587 private void toggleCopyVisible(Boolean toggle) {
\r
2588 copyAction.setVisible(toggle);
\r
2589 Global.saveEditorButtonsVisible("copy", toggle);
\r
2591 private void togglePasteVisible(Boolean toggle) {
\r
2592 pasteAction.setVisible(toggle);
\r
2593 Global.saveEditorButtonsVisible("paste", toggle);
\r
2595 private void toggleBoldVisible(Boolean toggle) {
\r
2596 boldAction.setVisible(toggle);
\r
2597 Global.saveEditorButtonsVisible("bold", toggle);
\r
2599 private void toggleItalicVisible(Boolean toggle) {
\r
2600 italicAction.setVisible(toggle);
\r
2601 Global.saveEditorButtonsVisible("italic", toggle);
\r
2603 private void toggleUnderlineVisible(Boolean toggle) {
\r
2604 underlineAction.setVisible(toggle);
\r
2605 Global.saveEditorButtonsVisible("underline", toggle);
\r
2607 private void toggleStrikethroughVisible(Boolean toggle) {
\r
2608 strikethroughAction.setVisible(toggle);
\r
2609 Global.saveEditorButtonsVisible("strikethrough", toggle);
\r
2611 private void toggleLeftAlignVisible(Boolean toggle) {
\r
2612 leftAlignAction.setVisible(toggle);
\r
2613 Global.saveEditorButtonsVisible("alignLeft", toggle);
\r
2615 private void toggleRightAlignVisible(Boolean toggle) {
\r
2616 rightAlignAction.setVisible(toggle);
\r
2617 Global.saveEditorButtonsVisible("alignRight", toggle);
\r
2619 private void toggleCenterAlignVisible(Boolean toggle) {
\r
2620 centerAlignAction.setVisible(toggle);
\r
2621 Global.saveEditorButtonsVisible("alignCenter", toggle);
\r
2623 private void toggleHLineVisible(Boolean toggle) {
\r
2624 hlineAction.setVisible(toggle);
\r
2625 Global.saveEditorButtonsVisible("hline", toggle);
\r
2627 private void toggleIndentVisible(Boolean toggle) {
\r
2628 indentAction.setVisible(toggle);
\r
2629 Global.saveEditorButtonsVisible("indent", toggle);
\r
2631 private void toggleTodoVisible(Boolean toggle) {
\r
2632 todoAction.setVisible(toggle);
\r
2633 Global.saveEditorButtonsVisible("todo", toggle);
\r
2635 private void toggleOutdentVisible(Boolean toggle) {
\r
2636 outdentAction.setVisible(toggle);
\r
2637 Global.saveEditorButtonsVisible("outdent", toggle);
\r
2639 private void toggleBulletListVisible(Boolean toggle) {
\r
2640 bulletListAction.setVisible(toggle);
\r
2641 Global.saveEditorButtonsVisible("bulletList", toggle);
\r
2643 private void toggleNumberListVisible(Boolean toggle) {
\r
2644 numberListAction.setVisible(toggle);
\r
2645 Global.saveEditorButtonsVisible("numberList", toggle);
\r
2647 private void toggleFontListVisible(Boolean toggle) {
\r
2648 fontListAction.setVisible(toggle);
\r
2649 Global.saveEditorButtonsVisible("font", toggle);
\r
2651 private void toggleFontColorVisible(Boolean toggle) {
\r
2652 fontColorAction.setVisible(toggle);
\r
2653 Global.saveEditorButtonsVisible("fontColor", toggle);
\r
2655 private void toggleFontSizeVisible(Boolean toggle) {
\r
2656 fontSizeAction.setVisible(toggle);
\r
2657 Global.saveEditorButtonsVisible("fontSize", toggle);
\r
2659 private void toggleFontHilightVisible(Boolean toggle) {
\r
2660 fontHilightAction.setVisible(toggle);
\r
2661 Global.saveEditorButtonsVisible("fontHilight", toggle);
\r
2663 private void toggleSpellCheckVisible(Boolean toggle) {
\r
2664 spellCheckAction.setVisible(toggle);
\r
2665 Global.saveEditorButtonsVisible("spellCheck", toggle);
\r
2669 private void setupDictionary() {
\r
2670 File wordList = new File(Global.getFileManager().getSpellDirPath()+Locale.getDefault()+".dic");
\r
2672 dictionary = new SpellDictionaryHashMap(wordList);
\r
2673 spellChecker = new SpellChecker(dictionary);
\r
2674 File userWordList;
\r
2675 userWordList = new File(Global.getFileManager().getSpellDirPathUser()+"user.dic");
\r
2677 // Get the local user spell dictionary
\r
2679 userDictionary = new SpellDictionaryHashMap(userWordList);
\r
2680 } catch (FileNotFoundException e) {
\r
2681 userWordList.createNewFile();
\r
2682 userDictionary = new SpellDictionaryHashMap(userWordList);
\r
2683 } catch (IOException e) {
\r
2684 userWordList.createNewFile();
\r
2685 userDictionary = new SpellDictionaryHashMap(userWordList);
\r
2688 spellListener = new SuggestionListener(this, spellChecker);
\r
2690 // Add the user dictionary
\r
2691 spellChecker.addSpellCheckListener(spellListener);
\r
2692 spellChecker.setUserDictionary(userDictionary);
\r
2694 } catch (FileNotFoundException e) {
\r
2695 QMessageBox.critical(this, tr("Spell Check Error"),
\r
2696 tr("Dictionary "+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+
\r
2697 ".dic was not found."));
\r
2698 } catch (IOException e) {
\r
2699 QMessageBox.critical(this, tr("Spell Check Error"),
\r
2700 tr("Dictionary "+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+
\r
2701 ".dic is invalid."));
\r
2706 // Invoke spell checker dialog
\r
2707 private void spellCheckClicked() {
\r
2709 if (spellChecker == null) {
\r
2710 setupDictionary();
\r
2713 spellListener.abortSpellCheck = false;
\r
2714 String content = getBrowser().page().mainFrame().toPlainText();
\r
2715 StringWordTokenizer tokenizer = new StringWordTokenizer(content);
\r
2716 if (!tokenizer.hasMoreWords())
\r
2718 getBrowser().page().action(WebAction.MoveToStartOfDocument);
\r
2720 getBrowser().setFocus();
\r
2723 // Move to the start of page
\r
2724 KeyboardModifiers ctrl = new KeyboardModifiers(KeyboardModifier.ControlModifier.value());
\r
2725 QKeyEvent home = new QKeyEvent(Type.KeyPress, Key.Key_Home.value(), ctrl);
\r
2726 browser.keyPressEvent(home);
\r
2727 getBrowser().setFocus();
\r
2729 tokenizer = new StringWordTokenizer(content);
\r
2732 while(tokenizer.hasMoreWords()) {
\r
2733 word = tokenizer.nextWord();
\r
2734 found = getBrowser().page().findText(word);
\r
2735 if (found && !spellListener.abortSpellCheck) {
\r
2736 spellChecker.checkSpelling(new StringWordTokenizer(word));
\r
2737 getBrowser().setFocus();
\r
2741 // Go to the end of the document & finish up.
\r
2742 home = new QKeyEvent(Type.KeyPress, Key.Key_End.value(), ctrl);
\r
2743 browser.keyPressEvent(home);
\r
2744 if (!spellListener.errorsFound)
\r
2745 QMessageBox.information(this, tr("Spell Check Complete"),
\r
2746 tr("No spelling errors found"));
\r