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.Configuration;
\r
50 import com.swabunga.spell.engine.SpellDictionary;
\r
51 import com.swabunga.spell.engine.SpellDictionaryHashMap;
\r
52 import com.swabunga.spell.engine.Word;
\r
53 import com.swabunga.spell.event.SpellCheckEvent;
\r
54 import com.swabunga.spell.event.SpellCheckListener;
\r
55 import com.swabunga.spell.event.SpellChecker;
\r
56 import com.swabunga.spell.event.StringWordTokenizer;
\r
57 import com.trolltech.qt.core.QByteArray;
\r
58 import com.trolltech.qt.core.QCoreApplication;
\r
59 import com.trolltech.qt.core.QDataStream;
\r
60 import com.trolltech.qt.core.QDateTime;
\r
61 import com.trolltech.qt.core.QEvent;
\r
62 import com.trolltech.qt.core.QEvent.Type;
\r
63 import com.trolltech.qt.core.QFile;
\r
64 import com.trolltech.qt.core.QFileSystemWatcher;
\r
65 import com.trolltech.qt.core.QIODevice;
\r
66 import com.trolltech.qt.core.QMimeData;
\r
67 import com.trolltech.qt.core.QTextCodec;
\r
68 import com.trolltech.qt.core.QUrl;
\r
69 import com.trolltech.qt.core.Qt;
\r
70 import com.trolltech.qt.core.Qt.Key;
\r
71 import com.trolltech.qt.core.Qt.KeyboardModifier;
\r
72 import com.trolltech.qt.core.Qt.KeyboardModifiers;
\r
73 import com.trolltech.qt.gui.QAction;
\r
74 import com.trolltech.qt.gui.QApplication;
\r
75 import com.trolltech.qt.gui.QCalendarWidget;
\r
76 import com.trolltech.qt.gui.QClipboard;
\r
77 import com.trolltech.qt.gui.QClipboard.Mode;
\r
78 import com.trolltech.qt.gui.QColor;
\r
79 import com.trolltech.qt.gui.QComboBox;
\r
80 import com.trolltech.qt.gui.QDateEdit;
\r
81 import com.trolltech.qt.gui.QDesktopServices;
\r
82 import com.trolltech.qt.gui.QFileDialog;
\r
83 import com.trolltech.qt.gui.QFileDialog.AcceptMode;
\r
84 import com.trolltech.qt.gui.QFileDialog.FileMode;
\r
85 import com.trolltech.qt.gui.QFontDatabase;
\r
86 import com.trolltech.qt.gui.QFormLayout;
\r
87 import com.trolltech.qt.gui.QGridLayout;
\r
88 import com.trolltech.qt.gui.QHBoxLayout;
\r
89 import com.trolltech.qt.gui.QIcon;
\r
90 import com.trolltech.qt.gui.QImage;
\r
91 import com.trolltech.qt.gui.QKeyEvent;
\r
92 import com.trolltech.qt.gui.QKeySequence;
\r
93 import com.trolltech.qt.gui.QLabel;
\r
94 import com.trolltech.qt.gui.QLineEdit;
\r
95 import com.trolltech.qt.gui.QListWidgetItem;
\r
96 import com.trolltech.qt.gui.QMatrix;
\r
97 import com.trolltech.qt.gui.QMessageBox;
\r
98 import com.trolltech.qt.gui.QPalette;
\r
99 import com.trolltech.qt.gui.QPalette.ColorRole;
\r
100 import com.trolltech.qt.gui.QPushButton;
\r
101 import com.trolltech.qt.gui.QShortcut;
\r
102 import com.trolltech.qt.gui.QTimeEdit;
\r
103 import com.trolltech.qt.gui.QToolButton;
\r
104 import com.trolltech.qt.gui.QToolButton.ToolButtonPopupMode;
\r
105 import com.trolltech.qt.gui.QVBoxLayout;
\r
106 import com.trolltech.qt.gui.QWidget;
\r
107 import com.trolltech.qt.network.QNetworkAccessManager;
\r
108 import com.trolltech.qt.network.QNetworkReply;
\r
109 import com.trolltech.qt.network.QNetworkReply.NetworkError;
\r
110 import com.trolltech.qt.network.QNetworkRequest;
\r
111 import com.trolltech.qt.webkit.QWebPage;
\r
112 import com.trolltech.qt.webkit.QWebPage.WebAction;
\r
113 import com.trolltech.qt.webkit.QWebSettings;
\r
114 import com.trolltech.qt.webkit.QWebView;
\r
116 import cx.fbn.nevernote.Global;
\r
117 import cx.fbn.nevernote.dialog.EnCryptDialog;
\r
118 import cx.fbn.nevernote.dialog.EnDecryptDialog;
\r
119 import cx.fbn.nevernote.dialog.GeoDialog;
\r
120 import cx.fbn.nevernote.dialog.InsertLatexImage;
\r
121 import cx.fbn.nevernote.dialog.InsertLinkDialog;
\r
122 import cx.fbn.nevernote.dialog.SpellCheck;
\r
123 import cx.fbn.nevernote.dialog.TableDialog;
\r
124 import cx.fbn.nevernote.dialog.TagAssign;
\r
125 import cx.fbn.nevernote.evernote.EnCrypt;
\r
126 import cx.fbn.nevernote.filters.FilterEditorTags;
\r
127 import cx.fbn.nevernote.signals.NoteResourceSignal;
\r
128 import cx.fbn.nevernote.signals.NoteSignal;
\r
129 import cx.fbn.nevernote.sql.DatabaseConnection;
\r
130 import cx.fbn.nevernote.utilities.ApplicationLogger;
\r
131 import cx.fbn.nevernote.utilities.FileUtils;
\r
132 import cx.fbn.nevernote.utilities.Pair;
\r
134 public class BrowserWindow extends QWidget {
\r
136 public final QLineEdit titleLabel;
\r
137 private final QLineEdit urlText;
\r
138 private final QLabel authorLabel;
\r
139 private final QLineEdit authorText;
\r
140 private final QComboBox geoBox;
\r
141 public final TagLineEdit tagEdit;
\r
142 public final QLabel tagLabel;
\r
143 private final QPushButton urlLabel;
\r
144 private final QLabel alteredLabel;
\r
145 private final QDateEdit alteredDate;
\r
146 private final QTimeEdit alteredTime;
\r
147 private final QDateEdit createdDate;
\r
148 private final QTimeEdit createdTime;
\r
149 private final QLabel subjectLabel;
\r
150 private final QDateEdit subjectDate;
\r
151 private final QTimeEdit subjectTime;
\r
152 public final QComboBox notebookBox;
\r
153 private final QLabel notebookLabel;
\r
154 private final QLabel createdLabel;
\r
155 public final QComboBox fontSize;
\r
156 public final QAction fontSizeAction;
\r
157 private boolean extendedOn;
\r
158 public boolean buttonsVisible;
\r
159 private final String iconPath = new String("classpath:cx/fbn/nevernote/icons/");
\r
160 private final ContentView browser;
\r
161 private List<Tag> allTags;
\r
162 private List<String> currentTags;
\r
163 public NoteSignal noteSignal;
\r
164 private List<Notebook> notebookList;
\r
165 private Note currentNote;
\r
166 private String saveNoteTitle;
\r
167 private String saveTagList;
\r
168 private boolean insideList;
\r
169 private final DatabaseConnection conn;
\r
170 private final QCalendarWidget createdCalendarWidget;
\r
171 private final QCalendarWidget alteredCalendarWidget;
\r
172 private final QCalendarWidget subjectCalendarWidget;
\r
174 public final QPushButton undoButton;
\r
175 public final QAction undoAction;
\r
176 public final QPushButton redoButton;
\r
177 public final QAction redoAction;
\r
178 public final QPushButton cutButton;
\r
179 public final QAction cutAction;
\r
180 public final QPushButton copyButton;
\r
181 public final QAction copyAction;
\r
182 public final QPushButton pasteButton;
\r
183 public final QAction pasteAction;
\r
184 public final QPushButton boldButton;
\r
185 public final QAction boldAction;
\r
186 public final QPushButton underlineButton;
\r
187 public final QAction underlineAction;
\r
188 public final QPushButton italicButton;
\r
189 public final QAction italicAction;
\r
190 public final Signal0 focusLost;
\r
191 public final NoteResourceSignal resourceSignal;
\r
193 public QPushButton rightAlignButton;
\r
194 public final QAction rightAlignAction;
\r
195 public QPushButton leftAlignButton;
\r
196 public final QAction leftAlignAction;
\r
197 public QPushButton centerAlignButton;
\r
198 public final QAction centerAlignAction;
\r
200 public final QPushButton strikethroughButton;
\r
201 public final QAction strikethroughAction;
\r
202 public final QPushButton hlineButton;
\r
203 public final QAction hlineAction;
\r
204 public final QPushButton indentButton;
\r
205 public final QAction indentAction;
\r
206 public final QPushButton outdentButton;
\r
207 public final QAction outdentAction;
\r
208 public final QPushButton bulletListButton;
\r
209 public final QAction bulletListAction;
\r
210 public final QPushButton numberListButton;
\r
211 public final QAction numberListAction;
\r
212 public final QPushButton spellCheckButton;
\r
213 public final QAction spellCheckAction;
\r
214 public final QPushButton todoButton;
\r
215 public final QAction todoAction;
\r
217 public final QShortcut focusTitleShortcut;
\r
218 public final QShortcut focusTagShortcut;
\r
219 public final QShortcut focusNoteShortcut;
\r
220 public final QShortcut focusUrlShortcut;
\r
221 public final QShortcut focusAuthorShortcut;
\r
223 public EditorButtonBar buttonLayout;
\r
224 public final QComboBox fontList;
\r
225 public final QAction fontListAction;
\r
226 public final QToolButton fontColor;
\r
227 public final QAction fontColorAction;
\r
228 private final ColorMenu fontColorMenu;
\r
229 public final QToolButton fontHilight;
\r
230 public final QAction fontHilightAction;
\r
231 private final ColorMenu fontHilightColorMenu;
\r
232 public final QFileSystemWatcher fileWatcher;
\r
233 public int cursorPosition;
\r
234 private boolean forceTextPaste = false;
\r
235 private String selectedFile;
\r
236 private String currentHyperlink;
\r
237 public boolean keepPDFNavigationHidden;
\r
238 private final ApplicationLogger logger;
\r
239 SpellDictionary dictionary;
\r
240 SpellDictionary userDictionary;
\r
241 SpellChecker spellChecker;
\r
242 SuggestionListener spellListener;
\r
243 private final HashMap<String,Integer> previewPageList;
\r
244 boolean insertHyperlink = true;
\r
245 boolean insideTable = false;
\r
246 boolean insideEncryption = false;
\r
247 public Signal1<Long> blockApplication;
\r
248 public Signal0 unblockApplication;
\r
249 String latexGuid; // This is set if we are editing an existing LaTeX formula. Useful to track guid.
\r
252 public static class SuggestionListener implements SpellCheckListener {
\r
253 public boolean abortSpellCheck = false;
\r
254 public boolean errorsFound = false;
\r
255 private final SpellCheck spellCheckDialog;
\r
258 private final BrowserWindow parent;
\r
259 public SuggestionListener(BrowserWindow parent, SpellChecker checker) {
\r
260 this.parent = parent;
\r
261 spellCheckDialog = new SpellCheck(checker);
\r
263 public void spellingError(SpellCheckEvent event) {
\r
264 errorsFound = true;
\r
265 spellCheckDialog.setWord(event.getInvalidWord());
\r
267 @SuppressWarnings("unchecked")
\r
268 List<Word> suggestions = event.getSuggestions();
\r
269 spellCheckDialog.clearSuggestions();
\r
270 if (!suggestions.isEmpty()) {
\r
271 // spellCheckDialog.setCurrentSuggestion(suggestions.get(0).getWord());
\r
272 for (int i=0; i<suggestions.size(); i++) {
\r
273 spellCheckDialog.addSuggestion(suggestions.get(i).getWord());
\r
275 spellCheckDialog.setSelectedSuggestion(0);
\r
277 spellCheckDialog.exec();
\r
278 if (spellCheckDialog.cancelPressed()) {
\r
279 abortSpellCheck = true;
\r
283 if (spellCheckDialog.replacePressed()) {
\r
284 QClipboard clipboard = QApplication.clipboard();
\r
285 clipboard.setText(spellCheckDialog.getReplacementWord());
\r
286 parent.pasteClicked();
\r
294 public BrowserWindow(DatabaseConnection c) {
\r
295 logger = new ApplicationLogger("browser.log");
\r
296 logger.log(logger.HIGH, "Setting up browser");
\r
298 fileWatcher = new QFileSystemWatcher();
\r
299 // fileWatcher.fileChanged.connect(this, "fileChanged(String)");
\r
300 noteSignal = new NoteSignal();
\r
301 titleLabel = new QLineEdit();
\r
302 titleLabel.setMaxLength(Constants.EDAM_NOTE_TITLE_LEN_MAX);
\r
303 urlText = new QLineEdit();
\r
304 authorText = new QLineEdit();
\r
305 geoBox = new QComboBox();
\r
306 urlLabel = new QPushButton();
\r
307 urlLabel.clicked.connect(this, "sourceUrlClicked()");
\r
308 authorLabel = new QLabel();
\r
311 focusLost = new Signal0();
\r
313 tagEdit = new TagLineEdit(allTags);
\r
314 tagLabel = new QLabel("Tags:");
\r
315 tagEdit.focusLost.connect(this, "modifyTagsTyping()");
\r
317 createdCalendarWidget = new QCalendarWidget();
\r
318 createdDate = new QDateEdit();
\r
319 createdDate.setDisplayFormat(Global.getDateFormat());
\r
320 createdDate.setCalendarPopup(true);
\r
321 createdDate.setCalendarWidget(createdCalendarWidget);
\r
322 createdTime = new QTimeEdit();
\r
323 createdDate.dateChanged.connect(this, "createdChanged()");
\r
324 createdTime.timeChanged.connect(this, "createdChanged()");
\r
326 alteredCalendarWidget = new QCalendarWidget();
\r
327 alteredDate = new QDateEdit();
\r
328 alteredDate.setDisplayFormat(Global.getDateFormat());
\r
329 alteredDate.setCalendarPopup(true);
\r
330 alteredDate.setCalendarWidget(alteredCalendarWidget);
\r
331 alteredTime = new QTimeEdit();
\r
332 alteredLabel = new QLabel("Altered:");
\r
333 alteredDate.dateChanged.connect(this, "alteredChanged()");
\r
334 alteredTime.timeChanged.connect(this, "alteredChanged()");
\r
336 subjectCalendarWidget = new QCalendarWidget();
\r
337 subjectDate = new QDateEdit();
\r
338 subjectDate.setDisplayFormat(Global.getDateFormat());
\r
339 subjectDate.setCalendarPopup(true);
\r
340 subjectDate.setCalendarWidget(subjectCalendarWidget);
\r
341 subjectTime = new QTimeEdit();
\r
342 subjectLabel = new QLabel(tr("Subject Date:"));
\r
343 subjectDate.dateChanged.connect(this, "subjectDateTimeChanged()");
\r
344 subjectTime.timeChanged.connect(this, "subjectDateTimeChanged()");
\r
345 authorText.textChanged.connect(this, "authorChanged()");
\r
346 urlText.textChanged.connect(this, "sourceUrlChanged()");
\r
348 notebookBox = new QComboBox();
\r
349 notebookLabel = new QLabel(tr("Notebook"));
\r
350 createdLabel = new QLabel(tr("Created:"));
\r
351 // selectedText = new String();
\r
353 urlLabel.setVisible(false);
\r
354 urlText.setVisible(false);
\r
355 authorLabel.setVisible(false);
\r
357 geoBox.setVisible(false);
\r
358 geoBox.addItem(new QIcon(iconPath+"globe.png"), "");
\r
359 geoBox.addItem(new String(tr("Set")));
\r
360 geoBox.addItem(new String(tr("Clear")));
\r
361 geoBox.addItem(new String(tr("View On Map")));
\r
362 geoBox.activated.connect(this, "geoBoxChanged()");
\r
364 authorText.setVisible(false);
\r
365 createdDate.setVisible(false);
\r
366 alteredLabel.setVisible(false);
\r
367 //notebookBox.setVisible(false);
\r
368 notebookLabel.setVisible(false);
\r
369 createdLabel.setVisible(false);
\r
370 createdTime.setVisible(false);
\r
371 alteredDate.setVisible(false);
\r
372 alteredTime.setVisible(false);
\r
373 subjectLabel.setVisible(false);
\r
374 subjectDate.setVisible(false);
\r
375 subjectTime.setVisible(false);
\r
376 extendedOn = false;
\r
377 buttonsVisible = true;
\r
378 setAcceptDrops(true);
\r
380 browser = new ContentView(this);
\r
381 browser.page().setLinkDelegationPolicy(
\r
382 QWebPage.LinkDelegationPolicy.DelegateAllLinks);
\r
383 browser.linkClicked.connect(this, "linkClicked(QUrl)");
\r
384 currentHyperlink = "";
\r
386 QVBoxLayout v = new QVBoxLayout();
\r
387 QFormLayout notebookLayout = new QFormLayout();
\r
388 QGridLayout dateLayout = new QGridLayout();
\r
389 titleLabel.setReadOnly(false);
\r
390 titleLabel.editingFinished.connect(this, "titleEdited()");
\r
391 browser.page().contentsChanged.connect(this, "contentChanged()");
\r
392 browser.page().selectionChanged.connect(this, "selectionChanged()");
\r
393 browser.page().mainFrame().javaScriptWindowObjectCleared.connect(this,
\r
394 "exposeToJavascript()");
\r
396 notebookBox.activated.connect(this, "notebookChanged()");
\r
397 resourceSignal = new NoteResourceSignal();
\r
399 QHBoxLayout tagLayout = new QHBoxLayout();
\r
400 v.addWidget(titleLabel, 0);
\r
401 notebookLayout.addRow(notebookLabel, notebookBox);
\r
402 tagLayout.addLayout(notebookLayout, 0);
\r
403 tagLayout.stretch(4);
\r
404 tagLayout.addWidget(tagLabel, 0);
\r
405 tagLayout.addWidget(tagEdit, 1);
\r
406 v.addLayout(tagLayout);
\r
408 QHBoxLayout urlLayout = new QHBoxLayout();
\r
409 urlLayout.addWidget(urlLabel, 0);
\r
410 urlLayout.addWidget(urlText, 0);
\r
411 v.addLayout(urlLayout);
\r
413 QHBoxLayout authorLayout = new QHBoxLayout();
\r
414 authorLayout.addWidget(authorLabel, 0);
\r
415 authorLayout.addWidget(authorText, 0);
\r
416 authorLayout.addWidget(geoBox);
\r
417 v.addLayout(authorLayout);
\r
419 dateLayout.addWidget(createdLabel, 0, 0);
\r
420 dateLayout.addWidget(createdDate, 0, 1);
\r
421 dateLayout.addWidget(createdTime, 0, 2);
\r
422 dateLayout.setColumnStretch(9, 100);
\r
423 dateLayout.addWidget(alteredLabel, 0, 3);
\r
424 dateLayout.addWidget(alteredDate, 0, 4);
\r
425 dateLayout.addWidget(alteredTime, 0, 5);
\r
426 dateLayout.addWidget(subjectLabel, 0, 6);
\r
427 dateLayout.addWidget(subjectDate, 0, 7);
\r
428 dateLayout.addWidget(subjectTime, 0, 8);
\r
429 v.addLayout(dateLayout, 0);
\r
431 undoButton = newEditorButton("undo", tr("Undo Change"));
\r
432 redoButton = newEditorButton("redo", tr("Redo Change"));
\r
433 cutButton = newEditorButton("cut", tr("Cut"));
\r
434 copyButton = newEditorButton("copy", tr("Copy"));
\r
435 pasteButton = newEditorButton("paste", tr("Paste"));
\r
436 boldButton = newEditorButton("bold", tr("Bold"));
\r
437 underlineButton = newEditorButton("underline", tr("Underline"));
\r
438 italicButton = newEditorButton("italic", tr("Italic"));
\r
440 rightAlignButton = newEditorButton("justifyRight", tr("Right Align"));
\r
441 leftAlignButton = newEditorButton("justifyLeft", tr("Left Align"));
\r
442 centerAlignButton = newEditorButton("justifyCenter", tr("Center Align"));
\r
444 strikethroughButton = newEditorButton("strikethrough", tr("Strikethrough"));
\r
445 hlineButton = newEditorButton("hline", tr("Insert Horizontal Line"));
\r
446 indentButton = newEditorButton("indent", tr("Shift Right"));
\r
447 outdentButton = newEditorButton("outdent", tr("Shift Left"));
\r
448 bulletListButton = newEditorButton("bulletList", tr("Bullet List"));
\r
449 numberListButton = newEditorButton("numberList", tr("Number List"));
\r
450 spellCheckButton = newEditorButton("spellCheck", tr("Spell Check"));
\r
451 todoButton = newEditorButton("todo", tr("To-do"));
\r
454 buttonLayout = new EditorButtonBar();
\r
455 v.addWidget(buttonLayout);
\r
457 undoAction = buttonLayout.addWidget(undoButton);
\r
458 buttonLayout.toggleUndoVisible.triggered.connect(this, "toggleUndoVisible(Boolean)");
\r
459 redoAction = buttonLayout.addWidget(redoButton);
\r
460 buttonLayout.toggleRedoVisible.triggered.connect(this, "toggleRedoVisible(Boolean)");
\r
462 buttonLayout.addWidget(newSeparator());
\r
463 cutAction = buttonLayout.addWidget(cutButton);
\r
464 buttonLayout.toggleCutVisible.triggered.connect(this, "toggleCutVisible(Boolean)");
\r
465 copyAction = buttonLayout.addWidget(copyButton);
\r
466 buttonLayout.toggleCopyVisible.triggered.connect(this, "toggleCopyVisible(Boolean)");
\r
467 pasteAction = buttonLayout.addWidget(pasteButton);
\r
468 buttonLayout.togglePasteVisible.triggered.connect(this, "togglePasteVisible(Boolean)");
\r
470 buttonLayout.addWidget(newSeparator());
\r
471 boldAction = buttonLayout.addWidget(boldButton);
\r
472 buttonLayout.toggleBoldVisible.triggered.connect(this, "toggleBoldVisible(Boolean)");
\r
473 italicAction = buttonLayout.addWidget(italicButton);
\r
474 buttonLayout.toggleItalicVisible.triggered.connect(this, "toggleItalicVisible(Boolean)");
\r
475 underlineAction = buttonLayout.addWidget(underlineButton);
\r
476 buttonLayout.toggleUnderlineVisible.triggered.connect(this, "toggleUnderlineVisible(Boolean)");
\r
477 strikethroughAction = buttonLayout.addWidget(strikethroughButton);
\r
478 buttonLayout.toggleStrikethroughVisible.triggered.connect(this, "toggleStrikethroughVisible(Boolean)");
\r
481 buttonLayout.addWidget(newSeparator());
\r
482 leftAlignAction = buttonLayout.addWidget(leftAlignButton);
\r
483 buttonLayout.toggleLeftAlignVisible.triggered.connect(this, "toggleLeftAlignVisible(Boolean)");
\r
484 centerAlignAction = buttonLayout.addWidget(centerAlignButton);
\r
485 buttonLayout.toggleCenterAlignVisible.triggered.connect(this, "toggleCenterAlignVisible(Boolean)");
\r
486 rightAlignAction = buttonLayout.addWidget(rightAlignButton);
\r
487 buttonLayout.toggleRightAlignVisible.triggered.connect(this, "toggleRightAlignVisible(Boolean)");
\r
489 buttonLayout.addWidget(newSeparator());
\r
490 hlineAction = buttonLayout.addWidget(hlineButton);
\r
491 buttonLayout.toggleHLineVisible.triggered.connect(this, "toggleHLineVisible(Boolean)");
\r
493 indentAction = buttonLayout.addWidget(indentButton);
\r
494 buttonLayout.toggleIndentVisible.triggered.connect(this, "toggleIndentVisible(Boolean)");
\r
495 outdentAction = buttonLayout.addWidget(outdentButton);
\r
496 buttonLayout.toggleOutdentVisible.triggered.connect(this, "toggleOutdentVisible(Boolean)");
\r
497 bulletListAction = buttonLayout.addWidget(bulletListButton);
\r
498 buttonLayout.toggleBulletListVisible.triggered.connect(this, "toggleBulletListVisible(Boolean)");
\r
499 numberListAction = buttonLayout.addWidget(numberListButton);
\r
500 buttonLayout.toggleNumberListVisible.triggered.connect(this, "toggleNumberListVisible(Boolean)");
\r
502 // Setup the font & font size combo boxes
\r
503 buttonLayout.addWidget(newSeparator());
\r
504 fontList = new QComboBox();
\r
505 fontSize = new QComboBox();
\r
506 fontList.setToolTip("Font");
\r
507 fontSize.setToolTip("Font Size");
\r
508 fontList.activated.connect(this, "fontChanged(String)");
\r
509 fontSize.activated.connect(this, "fontSizeChanged(String)");
\r
510 fontListAction = buttonLayout.addWidget(fontList);
\r
511 buttonLayout.toggleFontVisible.triggered.connect(this, "toggleFontListVisible(Boolean)");
\r
512 fontSizeAction = buttonLayout.addWidget(fontSize);
\r
513 buttonLayout.toggleFontSizeVisible.triggered.connect(this, "toggleFontSizeVisible(Boolean)");
\r
514 QFontDatabase fonts = new QFontDatabase();
\r
515 List<String> fontFamilies = fonts.families();
\r
516 for (int i = 0; i < fontFamilies.size(); i++) {
\r
517 fontList.addItem(fontFamilies.get(i));
\r
519 loadFontSize(fontFamilies.get(i));
\r
523 // buttonLayout.addWidget(newSeparator(), 0);
\r
524 fontColor = newToolButton("fontColor", tr("Font Color"));
\r
525 fontColorMenu = new ColorMenu(this);
\r
526 fontColor.setMenu(fontColorMenu.getMenu());
\r
527 fontColor.setPopupMode(ToolButtonPopupMode.MenuButtonPopup);
\r
528 fontColor.setAutoRaise(false);
\r
529 fontColorMenu.getMenu().triggered.connect(this, "fontColorClicked()");
\r
530 fontColorAction = buttonLayout.addWidget(fontColor);
\r
531 buttonLayout.toggleFontColorVisible.triggered.connect(this, "toggleFontColorVisible(Boolean)");
\r
532 fontHilight = newToolButton("fontHilight", tr("Font Hilight Color"));
\r
533 fontHilight.setPopupMode(ToolButtonPopupMode.MenuButtonPopup);
\r
534 fontHilight.setAutoRaise(false);
\r
535 fontHilightColorMenu = new ColorMenu(this);
\r
536 fontHilightColorMenu.setDefault(QColor.yellow);
\r
537 fontHilight.setMenu(fontHilightColorMenu.getMenu());
\r
538 fontHilightColorMenu.getMenu().triggered.connect(this, "fontHilightClicked()");
\r
539 fontHilightAction = buttonLayout.addWidget(fontHilight);
\r
540 fontHilightColorMenu.setDefault(QColor.yellow);
\r
541 buttonLayout.toggleFontHilight.triggered.connect(this, "toggleFontHilightVisible(Boolean)");
\r
543 spellCheckAction = buttonLayout.addWidget(spellCheckButton);
\r
544 buttonLayout.toggleNumberListVisible.triggered.connect(this, "spellCheckClicked()");
\r
545 buttonLayout.toggleSpellCheck.triggered.connect(this, "toggleSpellCheckVisible(Boolean)");
\r
547 todoAction = buttonLayout.addWidget(todoButton);
\r
548 buttonLayout.toggleNumberListVisible.triggered.connect(this, "todoClicked()");
\r
549 buttonLayout.toggleTodo.triggered.connect(this, "toggleTodoVisible(Boolean)");
\r
552 // buttonLayout.addWidget(new QLabel(), 1);
\r
553 v.addWidget(browser, 1);
\r
556 browser.downloadAttachmentRequested.connect(this,
\r
557 "downloadAttachment(QNetworkRequest)");
\r
558 browser.downloadImageRequested.connect(this,
\r
559 "downloadImage(QNetworkRequest)");
\r
560 setTabOrder(notebookBox, tagEdit);
\r
561 setTabOrder(tagEdit, browser);
\r
563 focusNoteShortcut = new QShortcut(this);
\r
564 setupShortcut(focusNoteShortcut, "Focus_Note");
\r
565 focusNoteShortcut.activated.connect(this, "focusNote()");
\r
566 focusTitleShortcut = new QShortcut(this);
\r
567 setupShortcut(focusTitleShortcut, "Focus_Title");
\r
568 focusTitleShortcut.activated.connect(this, "focusTitle()");
\r
569 focusTagShortcut = new QShortcut(this);
\r
570 setupShortcut(focusTagShortcut, "Focus_Tag");
\r
571 focusTagShortcut.activated.connect(this, "focusTag()");
\r
572 focusAuthorShortcut = new QShortcut(this);
\r
573 setupShortcut(focusAuthorShortcut, "Focus_Author");
\r
574 focusAuthorShortcut.activated.connect(this, "focusAuthor()");
\r
575 focusUrlShortcut = new QShortcut(this);
\r
576 setupShortcut(focusUrlShortcut, "Focus_Url");
\r
577 focusUrlShortcut.activated.connect(this, "focusUrl()");
\r
579 browser.page().mainFrame().setTextSizeMultiplier(Global.getTextSizeMultiplier());
\r
580 browser.page().mainFrame().setZoomFactor(Global.getZoomFactor());
\r
582 previewPageList = new HashMap<String,Integer>();
\r
584 browser.page().microFocusChanged.connect(this, "microFocusChanged()");
\r
588 QPalette pal = new QPalette();
\r
589 pal.setColor(ColorRole.Text, QColor.black);
\r
590 titleLabel.setPalette(pal);
\r
591 authorText.setPalette(pal);
\r
592 authorLabel.setPalette(pal);
\r
593 urlLabel.setPalette(pal);
\r
594 urlText.setPalette(pal);
\r
595 createdDate.setPalette(pal);
\r
596 createdTime.setPalette(pal);
\r
597 alteredDate.setPalette(pal);
\r
598 alteredTime.setPalette(pal);
\r
599 subjectDate.setPalette(pal);
\r
600 subjectTime.setPalette(pal);
\r
601 tagEdit.setPalette(pal);
\r
602 notebookBox.setPalette(pal);
\r
604 blockApplication = new Signal1<Long>();
\r
605 unblockApplication = new Signal0();
\r
607 logger.log(logger.HIGH, "Browser setup complete");
\r
612 private void setupShortcut(QShortcut action, String text) {
\r
613 if (!Global.shortcutKeys.containsAction(text))
\r
615 action.setKey(new QKeySequence(Global.shortcutKeys.getShortcut(text)));
\r
621 // Getter for the QWebView
\r
622 public QWebView getBrowser() {
\r
626 // Block signals while loading data or things are flagged as dirty by
\r
628 public void loadingData(boolean val) {
\r
629 logger.log(logger.EXTREME, "Entering BrowserWindow.loadingData() " +val);
\r
630 notebookBox.blockSignals(val);
\r
631 browser.page().blockSignals(val);
\r
632 browser.page().mainFrame().blockSignals(val);
\r
633 titleLabel.blockSignals(val);
\r
634 alteredDate.blockSignals(val);
\r
635 alteredTime.blockSignals(val);
\r
636 createdTime.blockSignals(val);
\r
637 createdDate.blockSignals(val);
\r
638 subjectDate.blockSignals(val);
\r
639 subjectTime.blockSignals(val);
\r
640 urlText.blockSignals(val);
\r
641 authorText.blockSignals(val);
\r
643 exposeToJavascript();
\r
644 logger.log(logger.EXTREME, "Exiting BrowserWindow.loadingData() " +val);
\r
648 public void setReadOnly(boolean v) {
\r
650 titleLabel.setEnabled(!v);
\r
651 notebookBox.setEnabled(!v);
\r
652 tagEdit.setEnabled(!v);
\r
653 authorLabel.setEnabled(!v);
\r
654 geoBox.setEnabled(!v);
\r
655 urlText.setEnabled(!v);
\r
656 createdDate.setEnabled(!v);
\r
657 subjectDate.setEnabled(!v);
\r
658 alteredDate.setEnabled(!v);
\r
659 authorText.setEnabled(!v);
\r
660 createdTime.setEnabled(!v);
\r
661 alteredTime.setEnabled(!v);
\r
662 subjectTime.setEnabled(!v);
\r
663 getBrowser().setEnabled(true);
\r
664 getBrowser().setEnabled(!v);
\r
667 // expose this class to Javascript on the web page
\r
668 private void exposeToJavascript() {
\r
669 browser.page().mainFrame().addToJavaScriptWindowObject("jambi", this);
\r
672 // Custom event queue
\r
674 public boolean event(QEvent e) {
\r
675 if (e.type().equals(QEvent.Type.FocusOut)) {
\r
676 logger.log(logger.EXTREME, "Focus lost");
\r
679 return super.event(e);
\r
682 // clear out browser
\r
683 public void clear() {
\r
684 logger.log(logger.EXTREME, "Entering BrowserWindow.clear()");
\r
686 browser.setContent(new QByteArray());
\r
687 tagEdit.setText("");
\r
688 tagEdit.tagCompleter.reset();
\r
689 urlLabel.setText(tr("Source URL:"));
\r
690 titleLabel.setText("");
\r
691 logger.log(logger.EXTREME, "Exiting BrowserWindow.clear()");
\r
694 // get/set current note
\r
695 public void setNote(Note n) {
\r
699 saveNoteTitle = n.getTitle();
\r
703 public Note getNote() {
\r
704 return currentNote;
\r
707 // New Editor Button
\r
708 private QPushButton newEditorButton(String name, String toolTip) {
\r
709 QPushButton button = new QPushButton();
\r
710 // QIcon icon = new QIcon(iconPath + name + ".gif");
\r
711 QIcon icon = new QIcon(iconPath + name + ".png");
\r
712 button.setIcon(icon);
\r
713 button.setToolTip(toolTip);
\r
714 button.clicked.connect(this, name + "Clicked()");
\r
717 // New Editor Button
\r
718 private QToolButton newToolButton(String name, String toolTip) {
\r
719 QToolButton button = new QToolButton();
\r
720 // QIcon icon = new QIcon(iconPath + name + ".gif");
\r
721 QIcon icon = new QIcon(iconPath + name + ".png");
\r
722 button.setIcon(icon);
\r
723 button.setToolTip(toolTip);
\r
724 button.clicked.connect(this, name + "Clicked()");
\r
729 private QLabel newSeparator() {
\r
730 return new QLabel(" ");
\r
733 // Set the title in the window
\r
734 public void setTitle(String t) {
\r
735 titleLabel.setText(t);
\r
740 // Return the current text title
\r
741 public String getTitle() {
\r
742 return titleLabel.text();
\r
745 // Set the tag name string
\r
746 public void setTag(String t) {
\r
748 tagEdit.setText(t);
\r
749 tagEdit.tagCompleter.reset();
\r
752 // Set the source URL
\r
753 public void setUrl(String t) {
\r
754 urlLabel.setText(tr("Source URL:\t"));
\r
755 urlText.setText(t);
\r
758 // The user want's to launch a web browser on the source of the URL
\r
759 public void sourceUrlClicked() {
\r
760 // Make sure we have a valid URL
\r
761 if (urlText.text().trim().equals(""))
\r
764 String url = urlText.text();
\r
765 if (!url.toLowerCase().startsWith(tr("http://")))
\r
766 url = tr("http://") +url;
\r
768 if (!QDesktopServices.openUrl(new QUrl(url))) {
\r
769 logger.log(logger.LOW, "Error opening file :" +url);
\r
773 public void setAuthor(String t) {
\r
774 authorLabel.setText(tr("Author:\t"));
\r
775 authorText.setText(t);
\r
778 // Set the creation date
\r
779 public void setCreation(long date) {
\r
780 QDateTime dt = new QDateTime();
\r
781 dt.setTime_t((int) (date / 1000));
\r
782 createdDate.setDateTime(dt);
\r
783 createdTime.setDateTime(dt);
\r
784 createdDate.setDisplayFormat(Global.getDateFormat());
\r
785 createdTime.setDisplayFormat(Global.getTimeFormat());
\r
788 // Set the creation date
\r
789 public void setAltered(long date) {
\r
790 QDateTime dt = new QDateTime();
\r
791 dt.setTime_t((int) (date / 1000));
\r
792 alteredDate.setDateTime(dt);
\r
793 alteredTime.setDateTime(dt);
\r
794 alteredDate.setDisplayFormat(Global.getDateFormat());
\r
795 alteredTime.setDisplayFormat(Global.getTimeFormat());
\r
798 // Set the subject date
\r
799 public void setSubjectDate(long date) {
\r
800 QDateTime dt = new QDateTime();
\r
801 dt.setTime_t((int) (date / 1000));
\r
802 subjectDate.setDateTime(dt);
\r
803 subjectTime.setDateTime(dt);
\r
804 subjectDate.setDisplayFormat(Global.getDateFormat());
\r
805 subjectTime.setDisplayFormat(Global.getTimeFormat());
\r
808 // Toggle the extended attribute information
\r
809 public void toggleInformation() {
\r
811 extendedOn = false;
\r
815 urlLabel.setVisible(extendedOn);
\r
816 urlText.setVisible(extendedOn);
\r
817 authorText.setVisible(extendedOn);
\r
818 geoBox.setVisible(extendedOn);
\r
819 authorLabel.setVisible(extendedOn);
\r
820 createdDate.setVisible(extendedOn);
\r
821 createdTime.setVisible(extendedOn);
\r
822 createdLabel.setVisible(extendedOn);
\r
823 alteredLabel.setVisible(extendedOn);
\r
824 alteredDate.setVisible(extendedOn);
\r
825 alteredTime.setVisible(extendedOn);
\r
826 //notebookBox.setVisible(extendedOn);
\r
827 notebookLabel.setVisible(extendedOn);
\r
828 subjectLabel.setVisible(extendedOn);
\r
829 subjectDate.setVisible(extendedOn);
\r
830 subjectTime.setVisible(extendedOn);
\r
833 public void hideButtons() {
\r
835 undoButton.parentWidget().setVisible(false);
\r
836 buttonsVisible = false;
\r
840 // Is the extended view on?
\r
841 public boolean isExtended() {
\r
845 // Listener for when a link is clicked
\r
846 @SuppressWarnings("unused")
\r
847 private void openFile() {
\r
848 logger.log(logger.EXTREME, "Starting openFile()");
\r
849 File fileHandle = new File(selectedFile);
\r
850 URI fileURL = fileHandle.toURI();
\r
851 String localURL = fileURL.toString();
\r
852 QUrl url = new QUrl(localURL);
\r
853 QFile file = new QFile(selectedFile);
\r
855 logger.log(logger.EXTREME, "Adding to fileWatcher:"+file.fileName());
\r
856 fileWatcher.addPath(file.fileName());
\r
858 if (!QDesktopServices.openUrl(url)) {
\r
859 logger.log(logger.LOW, "Error opening file :" +url);
\r
864 // Listener for when a link is clicked
\r
865 @SuppressWarnings("unused")
\r
866 private void linkClicked(QUrl url) {
\r
867 logger.log(logger.EXTREME, "URL Clicked: " +url.toString());
\r
868 if (url.toString().startsWith("latex://")) {
\r
869 int position = url.toString().lastIndexOf(".");
\r
870 String guid = url.toString().substring(0,position);
\r
871 position = guid.lastIndexOf("/");
\r
872 guid = guid.substring(position+1);
\r
876 if (url.toString().startsWith("nnres://")) {
\r
877 logger.log(logger.EXTREME, "URL is NN resource");
\r
878 if (url.toString().endsWith("/vnd.evernote.ink")) {
\r
879 logger.log(logger.EXTREME, "Unable to open ink note");
\r
880 QMessageBox.information(this, tr("Unable Open"), tr("This is an ink note.\n"+
\r
881 "Ink notes are not supported since Evernote has not\n published any specifications on them\n" +
\r
882 "and I'm too lazy to figure them out by myself."));
\r
885 String fullName = url.toString().substring(8);
\r
886 int index = fullName.indexOf(".");
\r
890 type = fullName.substring(index+1);
\r
891 guid = fullName.substring(0,index);
\r
893 index = guid.indexOf(Global.attachmentNameDelimeter);
\r
895 guid = guid.substring(0,index);
\r
897 List<Resource> resList = currentNote.getResources();
\r
898 Resource res = null;
\r
899 for (int i=0; i<resList.size(); i++) {
\r
900 if (resList.get(i).getGuid().equals(guid)) {
\r
901 res = resList.get(i);
\r
906 String resGuid = Global.resourceMap.get(guid);
\r
907 if (resGuid != null)
\r
908 res = conn.getNoteTable().noteResourceTable.getNoteResource(resGuid, true);
\r
912 if (res.getAttributes() != null &&
\r
913 res.getAttributes().getFileName() != null &&
\r
914 !res.getAttributes().getFileName().trim().equals(""))
\r
915 fileName = res.getGuid()+Global.attachmentNameDelimeter+res.getAttributes().getFileName();
\r
917 fileName = res.getGuid()+"."+type;
\r
918 QFile file = new QFile(Global.getFileManager().getResDirPath(fileName));
\r
919 QFile.OpenMode mode = new QFile.OpenMode();
\r
920 mode.set(QFile.OpenModeFlag.WriteOnly);
\r
921 boolean openResult = file.open(mode);
\r
922 logger.log(logger.EXTREME, "File opened:" +openResult);
\r
923 QDataStream out = new QDataStream(file);
\r
924 Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(res.getGuid(), true);
\r
925 QByteArray binData = new QByteArray(resBinary.getData().getBody());
\r
927 logger.log(logger.EXTREME, "Writing resource");
\r
928 out.writeBytes(binData.toByteArray());
\r
931 String whichOS = System.getProperty("os.name");
\r
932 if (whichOS.contains("Windows"))
\r
933 url.setUrl("file:///"+file.fileName());
\r
935 url.setUrl("file://"+file.fileName());
\r
936 // fileWatcher.removePath(file.fileName());
\r
937 logger.log(logger.EXTREME, "Adding file watcher " +file.fileName());
\r
938 fileWatcher.addPath(file.fileName());
\r
940 // If we can't open it, then prompt the user to save it.
\r
941 if (!QDesktopServices.openUrl(url)) {
\r
942 logger.log(logger.EXTREME, "We can't handle this. Where do we put it?");
\r
943 QFileDialog dialog = new QFileDialog();
\r
945 if (dialog.exec()!=0) {
\r
946 List<String> fileNames = dialog.selectedFiles(); //gets all selected filenames
\r
947 if (fileNames.size() == 0)
\r
949 String sf = fileNames.get(0);
\r
950 QFile saveFile = new QFile(sf);
\r
951 mode.set(QFile.OpenModeFlag.WriteOnly);
\r
952 saveFile.open(mode);
\r
953 QDataStream saveOut = new QDataStream(saveFile);
\r
954 saveOut.writeBytes(binData.toByteArray());
\r
962 logger.log(logger.EXTREME, "Launching URL");
\r
963 QDesktopServices.openUrl(url);
\r
966 // Listener for when BOLD is clicked
\r
967 @SuppressWarnings("unused")
\r
968 private void undoClicked() {
\r
969 browser.page().triggerAction(WebAction.Undo);
\r
970 browser.setFocus();
\r
973 // Listener for when BOLD is clicked
\r
974 @SuppressWarnings("unused")
\r
975 private void redoClicked() {
\r
976 browser.page().triggerAction(WebAction.Redo);
\r
977 browser.setFocus();
\r
980 // Listener for when BOLD is clicked
\r
981 @SuppressWarnings("unused")
\r
982 private void boldClicked() {
\r
983 browser.page().triggerAction(WebAction.ToggleBold);
\r
984 microFocusChanged();
\r
985 browser.setFocus();
\r
988 // Listener for when Italics is clicked
\r
989 @SuppressWarnings("unused")
\r
990 private void italicClicked() {
\r
991 browser.page().triggerAction(WebAction.ToggleItalic);
\r
992 microFocusChanged();
\r
993 browser.setFocus();
\r
996 // Listener for when UNDERLINE is clicked
\r
997 @SuppressWarnings("unused")
\r
998 private void underlineClicked() {
\r
999 browser.page().triggerAction(WebAction.ToggleUnderline);
\r
1000 microFocusChanged();
\r
1001 browser.setFocus();
\r
1004 // Listener for when Strikethrough is clicked
\r
1005 @SuppressWarnings("unused")
\r
1006 private void strikethroughClicked() {
\r
1007 browser.page().mainFrame().evaluateJavaScript(
\r
1008 "document.execCommand('strikeThrough', false, '');");
\r
1009 browser.setFocus();
\r
1012 // Listener for when cut is clicked
\r
1013 @SuppressWarnings("unused")
\r
1014 private void cutClicked() {
\r
1015 browser.page().triggerAction(WebAction.Cut);
\r
1016 browser.setFocus();
\r
1019 // Listener when COPY is clicked
\r
1020 @SuppressWarnings("unused")
\r
1021 private void copyClicked() {
\r
1022 browser.page().triggerAction(WebAction.Copy);
\r
1023 browser.setFocus();
\r
1026 // Listener when PASTE is clicked
\r
1027 public void pasteClicked() {
\r
1028 logger.log(logger.EXTREME, "Paste Clicked");
\r
1029 if (forceTextPaste) {
\r
1030 pasteWithoutFormattingClicked();
\r
1033 QClipboard clipboard = QApplication.clipboard();
\r
1034 QMimeData mime = clipboard.mimeData();
\r
1036 // String x = mime.html();
\r
1038 if (mime.hasImage()) {
\r
1039 logger.log(logger.EXTREME, "Image paste found");
\r
1040 browser.setFocus();
\r
1041 insertImage(mime);
\r
1042 browser.setFocus();
\r
1046 if (mime.hasUrls()) {
\r
1047 logger.log(logger.EXTREME, "URL paste found");
\r
1049 browser.setFocus();
\r
1053 String text = mime.html();
\r
1054 if (text.contains("en-tag") && mime.hasHtml()) {
\r
1055 logger.log(logger.EXTREME, "Intra-note paste found");
\r
1056 text = fixInternotePaste(text);
\r
1057 mime.setHtml(text);
\r
1058 clipboard.setMimeData(mime);
\r
1061 logger.log(logger.EXTREME, "Final paste choice encountered");
\r
1062 browser.page().triggerAction(WebAction.Paste);
\r
1063 browser.setFocus();
\r
1067 // Paste text without formatting
\r
1068 private void pasteWithoutFormattingClicked() {
\r
1069 logger.log(logger.EXTREME, "Paste without format clipped");
\r
1070 QClipboard clipboard = QApplication.clipboard();
\r
1071 QMimeData mime = clipboard.mimeData();
\r
1072 if (!mime.hasText())
\r
1074 String text = mime.text();
\r
1075 clipboard.clear();
\r
1076 clipboard.setText(text, Mode.Clipboard);
\r
1077 browser.page().triggerAction(WebAction.Paste);
\r
1079 // This is done because pasting into an encryption block
\r
1080 // can cause multiple cells (which can't happen). It
\r
1081 // just goes through the table, extracts the data, &
\r
1082 // puts it back as one table cell.
\r
1083 if (insideEncryption) {
\r
1084 String js = new String( "function fixEncryption() { "
\r
1085 +" var selObj = window.getSelection();"
\r
1086 +" var selRange = selObj.getRangeAt(0);"
\r
1087 +" var workingNode = window.getSelection().anchorNode;"
\r
1088 +" while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { "
\r
1089 +" workingNode = workingNode.parentNode;"
\r
1091 +" workingNode.innerHTML = window.jambi.fixEncryptionPaste(workingNode.innerHTML);"
\r
1092 +"} fixEncryption();");
\r
1093 browser.page().mainFrame().evaluateJavaScript(js);
\r
1097 // This basically removes all the table tags and returns just the contents.
\r
1098 // This is called by JavaScript to fix encryption pastes.
\r
1099 public String fixEncryptionPaste(String data) {
\r
1100 data = data.replace("<tbody>", "");
\r
1101 data = data.replace("</tbody>", "");
\r
1102 data = data.replace("<tr>", "");
\r
1103 data = data.replace("</tr>", "");
\r
1104 data = data.replace("<td>", "");
\r
1105 data = data.replace("</td>", "<br>");
\r
1106 data = data.replace("<br><br>", "<br>");
\r
1108 return "<tbody><tr><td>"+data+"</td></tr></tbody>";
\r
1111 // insert date/time
\r
1112 @SuppressWarnings("unused")
\r
1113 private void insertDateTime() {
\r
1114 String fmt = Global.getDateFormat() + " " + Global.getTimeFormat();
\r
1115 String dateTimeFormat = new String(fmt);
\r
1116 SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);
\r
1117 Calendar cal = Calendar.getInstance();
\r
1119 browser.page().mainFrame().evaluateJavaScript(
\r
1120 "document.execCommand('insertHtml', false, '"+simple.format(cal.getTime())+"');");
\r
1122 browser.setFocus();
\r
1126 // Listener when Left is clicked
\r
1127 @SuppressWarnings("unused")
\r
1128 private void justifyLeftClicked() {
\r
1129 browser.page().mainFrame().evaluateJavaScript(
\r
1130 "document.execCommand('JustifyLeft', false, '');");
\r
1131 browser.setFocus();
\r
1134 // Listener when Center is clicked
\r
1135 @SuppressWarnings("unused")
\r
1136 private void justifyCenterClicked() {
\r
1137 browser.page().mainFrame().evaluateJavaScript(
\r
1138 "document.execCommand('JustifyCenter', false, '');");
\r
1139 browser.setFocus();
\r
1142 // Listener when Left is clicked
\r
1143 @SuppressWarnings("unused")
\r
1144 private void justifyRightClicked() {
\r
1145 browser.page().mainFrame().evaluateJavaScript(
\r
1146 "document.execCommand('JustifyRight', false, '');");
\r
1147 browser.setFocus();
\r
1150 // Listener when HLINE is clicked
\r
1151 @SuppressWarnings("unused")
\r
1152 private void hlineClicked() {
\r
1153 browser.page().mainFrame().evaluateJavaScript(
\r
1154 "document.execCommand('insertHorizontalRule', false, '');");
\r
1155 browser.setFocus();
\r
1158 // Listener when outdent is clicked
\r
1159 private void outdentClicked() {
\r
1160 browser.page().mainFrame().evaluateJavaScript(
\r
1161 "document.execCommand('outdent', false, '');");
\r
1162 browser.setFocus();
\r
1165 // Listener when a bullet list is clicked
\r
1166 @SuppressWarnings("unused")
\r
1167 private void bulletListClicked() {
\r
1168 browser.page().mainFrame().evaluateJavaScript(
\r
1169 "document.execCommand('InsertUnorderedList', false, '');");
\r
1170 browser.setFocus();
\r
1173 // Listener when a bullet list is clicked
\r
1174 @SuppressWarnings("unused")
\r
1175 private void numberListClicked() {
\r
1176 browser.page().mainFrame().evaluateJavaScript(
\r
1177 "document.execCommand('InsertOrderedList', false, '');");
\r
1178 browser.setFocus();
\r
1181 // Listener when indent is clicked
\r
1182 private void indentClicked() {
\r
1183 browser.page().mainFrame().evaluateJavaScript(
\r
1184 "document.execCommand('indent', false, '');");
\r
1185 browser.setFocus();
\r
1188 // Listener when the font name is changed
\r
1189 @SuppressWarnings("unused")
\r
1190 private void fontChanged(String font) {
\r
1191 browser.page().mainFrame().evaluateJavaScript(
\r
1192 "document.execCommand('fontName',false,'" + font + "');");
\r
1193 browser.setFocus();
\r
1196 // Listener when a font size is changed
\r
1197 @SuppressWarnings("unused")
\r
1198 private void fontSizeChanged(String font) {
\r
1199 String text = browser.selectedText();
\r
1200 if (text.trim().equalsIgnoreCase(""))
\r
1203 String selectedText = browser.selectedText();
\r
1204 String url = "<span style=\"font-size:" +font +"pt; \">"+selectedText +"</a>";
\r
1205 String script = "document.execCommand('insertHtml', false, '"+url+"');";
\r
1206 browser.page().mainFrame().evaluateJavaScript(script);
\r
1207 /* browser.page().mainFrame().evaluateJavaScript(
\r
1208 "document.execCommand('fontSize',false,'"
\r
1211 browser.setFocus();
\r
1214 // Load the font combo box based upon the font selected
\r
1215 private void loadFontSize(String name) {
\r
1216 QFontDatabase db = new QFontDatabase();
\r
1218 List<Integer> points = db.pointSizes(name);
\r
1219 for (int i=0; i<points.size(); i++) {
\r
1220 fontSize.addItem(points.get(i).toString());
\r
1223 fontSize.addItem("x-small");
\r
1224 fontSize.addItem("small");
\r
1225 fontSize.addItem("medium");
\r
1226 fontSize.addItem("large");
\r
1227 fontSize.addItem("x-large");
\r
1228 fontSize.addItem("xx-large");
\r
1229 fontSize.addItem("xxx-large");
\r
1233 // Listener when a font size is changed
\r
1234 @SuppressWarnings("unused")
\r
1235 private void fontColorClicked() {
\r
1236 // QColorDialog dialog = new QColorDialog();
\r
1237 // QColor color = QColorDialog.getColor();
\r
1238 QColor color = fontColorMenu.getColor();
\r
1239 if (color.isValid())
\r
1240 browser.page().mainFrame().evaluateJavaScript(
\r
1241 "document.execCommand('foreColor',false,'" + color.name()
\r
1243 browser.setFocus();
\r
1246 // Listener for when a background color change is requested
\r
1247 @SuppressWarnings("unused")
\r
1248 private void fontHilightClicked() {
\r
1249 // QColorDialog dialog = new QColorDialog();
\r
1250 // QColor color = QColorDialog.getColor();
\r
1251 QColor color = fontHilightColorMenu.getColor();
\r
1252 if (color.isValid())
\r
1253 browser.page().mainFrame().evaluateJavaScript(
\r
1254 "document.execCommand('backColor',false,'" + color.name()
\r
1256 browser.setFocus();
\r
1259 // Listener for when a background color change is requested
\r
1260 @SuppressWarnings("unused")
\r
1261 private void superscriptClicked() {
\r
1262 browser.page().mainFrame().evaluateJavaScript(
\r
1263 "document.execCommand('superscript');");
\r
1264 browser.setFocus();
\r
1267 // Listener for when a background color change is requested
\r
1268 @SuppressWarnings("unused")
\r
1269 private void subscriptClicked() {
\r
1270 browser.page().mainFrame().evaluateJavaScript(
\r
1271 "document.execCommand('subscript');");
\r
1272 browser.setFocus();
\r
1274 // Insert a to-do checkbox
\r
1275 @SuppressWarnings("unused")
\r
1276 private void todoClicked() {
\r
1277 FileNameMap fileNameMap = URLConnection.getFileNameMap();
\r
1278 String script_start = new String(
\r
1279 "document.execCommand('insertHtml', false, '");
\r
1280 String script_end = new String("');");
\r
1281 String todo = new String(
\r
1282 "<input TYPE=\"CHECKBOX\" value=\"false\" " +
\r
1283 "onMouseOver=\"style.cursor=\\'hand\\'\" " +
\r
1284 "onClick=\"value=checked; window.jambi.contentChanged(); \" />");
\r
1285 browser.page().mainFrame().evaluateJavaScript(
\r
1286 script_start + todo + script_end);
\r
1287 browser.setFocus();
\r
1290 // Encrypt the selected text
\r
1291 @SuppressWarnings("unused")
\r
1292 private void encryptText() {
\r
1293 String text = browser.selectedText();
\r
1294 if (text.trim().equalsIgnoreCase(""))
\r
1296 text = new String(text.replaceAll("\n", "<br/>"));
\r
1298 EnCryptDialog dialog = new EnCryptDialog();
\r
1300 if (!dialog.okPressed()) {
\r
1304 EnCrypt crypt = new EnCrypt();
\r
1305 String encrypted = crypt.encrypt(text, dialog.getPassword().trim(), 64);
\r
1306 String decrypted = crypt.decrypt(encrypted, dialog.getPassword().trim(), 64);
\r
1308 if (encrypted.trim().equals("")) {
\r
1309 QMessageBox.information(this, tr("Error"), tr("Error Encrypting String"));
\r
1312 StringBuffer buffer = new StringBuffer(encrypted.length() + 100);
\r
1313 buffer.append("<img en-tag=\"en-crypt\" cipher=\"RC2\" hint=\""
\r
1314 + dialog.getHint().replace("'","\\'") + "\" length=\"64\" ");
\r
1315 buffer.append("contentEditable=\"false\" alt=\"");
\r
1316 buffer.append(encrypted);
\r
1317 buffer.append("\" src=\"").append(FileUtils.toForwardSlashedPath(Global.getFileManager().getImageDirPath("encrypt.png") +"\""));
\r
1318 Global.cryptCounter++;
\r
1319 buffer.append(" id=\"crypt"+Global.cryptCounter.toString() +"\"");
\r
1320 buffer.append(" onMouseOver=\"style.cursor=\\'hand\\'\"");
\r
1321 buffer.append(" onClick=\"window.jambi.decryptText(\\'crypt"+Global.cryptCounter.toString()
\r
1322 +"\\', \\'"+encrypted+"\\', \\'"+dialog.getHint().replace("'", "\\&apos;")+"\\');\"");
\r
1323 buffer.append("style=\"display:block\" />");
\r
1325 String script_start = new String(
\r
1326 "document.execCommand('insertHtml', false, '");
\r
1327 String script_end = new String("');");
\r
1328 browser.page().mainFrame().evaluateJavaScript(
\r
1329 script_start + buffer.toString() + script_end);
\r
1333 // Insert a hyperlink
\r
1334 public void insertLink() {
\r
1335 logger.log(logger.EXTREME, "Inserting link");
\r
1336 String text = browser.selectedText();
\r
1337 if (text.trim().equalsIgnoreCase(""))
\r
1340 InsertLinkDialog dialog = new InsertLinkDialog(insertHyperlink);
\r
1341 if (currentHyperlink != null && currentHyperlink != "") {
\r
1342 dialog.setUrl(currentHyperlink);
\r
1345 if (!dialog.okPressed()) {
\r
1346 logger.log(logger.EXTREME, "Insert link canceled");
\r
1350 // Take care of inserting new links
\r
1351 if (insertHyperlink) {
\r
1352 String selectedText = browser.selectedText();
\r
1353 if (dialog.getUrl().trim().equals(""))
\r
1355 logger.log(logger.EXTREME, "Inserting link on text "+selectedText);
\r
1356 logger.log(logger.EXTREME, "URL Link " +dialog.getUrl().trim());
\r
1357 String dUrl = StringUtils.replace(dialog.getUrl().trim(), "'", "\\'");
\r
1358 String url = "<a href=\"" +dUrl
\r
1359 +"\" title=" +dUrl
\r
1360 +" >"+selectedText +"</a>";
\r
1361 String script = "document.execCommand('insertHtml', false, '"+url+"');";
\r
1362 browser.page().mainFrame().evaluateJavaScript(script);
\r
1366 // Edit existing links
\r
1367 String js = new String( "function getCursorPos() {"
\r
1369 +"if (window.getSelection) {"
\r
1370 +" var selObj = window.getSelection();"
\r
1371 +" var selRange = selObj.getRangeAt(0);"
\r
1372 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
1373 +" while(workingNode != null) { "
\r
1374 +" if (workingNode.nodeName.toLowerCase()=='a') workingNode.setAttribute('href','" +dialog.getUrl() +"');"
\r
1375 +" workingNode = workingNode.parentNode;"
\r
1378 +"} getCursorPos();");
\r
1379 browser.page().mainFrame().evaluateJavaScript(js);
\r
1381 if (!dialog.getUrl().trim().equals("")) {
\r
1387 js = new String( "function getCursorPos() {"
\r
1389 +"if (window.getSelection) {"
\r
1390 +" var selObj = window.getSelection();"
\r
1391 +" var selRange = selObj.getRangeAt(0);"
\r
1392 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
1393 +" while(workingNode != null) { "
\r
1394 +" if (workingNode.nodeName.toLowerCase()=='a') { "
\r
1395 +" workingNode.removeAttribute('href');"
\r
1396 +" workingNode.removeAttribute('title');"
\r
1397 +" var text = document.createTextNode(workingNode.innerText);"
\r
1398 +" workingNode.parentNode.insertBefore(text, workingNode);"
\r
1399 +" workingNode.parentNode.removeChild(workingNode);"
\r
1401 +" workingNode = workingNode.parentNode;"
\r
1404 +"} getCursorPos();");
\r
1405 browser.page().mainFrame().evaluateJavaScript(js);
\r
1413 // Insert a hyperlink
\r
1414 public void insertLatex() {
\r
1417 public void editLatex(String guid) {
\r
1418 logger.log(logger.EXTREME, "Inserting latex");
\r
1419 String text = browser.selectedText();
\r
1420 if (text.trim().equalsIgnoreCase("")) {
\r
1421 InsertLatexImage dialog = new InsertLatexImage();
\r
1422 if (guid != null) {
\r
1423 String formula = conn.getNoteTable().noteResourceTable.getNoteSourceUrl(guid).replace("http://latex.codecogs.com/gif.latex?", "");
\r
1424 dialog.setFormula(formula);
\r
1427 if (!dialog.okPressed()) {
\r
1428 logger.log(logger.EXTREME, "Edit LaTex canceled");
\r
1431 text = dialog.getFormula().trim();
\r
1433 blockApplication.emit(new Long(5000));
\r
1434 logger.log(logger.EXTREME, "Inserting LaTeX formula:" +text);
\r
1436 text = StringUtils.replace(text, "'", "\\'");
\r
1437 String url = "http://latex.codecogs.com/gif.latex?" +text;
\r
1438 QNetworkAccessManager manager = new QNetworkAccessManager(this);
\r
1439 manager.finished.connect(this, "insertLatexImageReady(QNetworkReply)");
\r
1440 manager.get(new QNetworkRequest(new QUrl(url)));
\r
1443 public void insertLatexImageReady(QNetworkReply reply) {
\r
1444 if (reply.error() != NetworkError.NoError)
\r
1447 QByteArray image = reply.readAll();
\r
1450 Resource newRes = null;
\r
1453 if (latexGuid == null) {
\r
1454 path = Global.getFileManager().getResDirPath("latex-temp.gif");
\r
1455 tfile = new QFile(path);
\r
1456 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
\r
1457 tfile.write(image);
\r
1459 newRes = createResource(path,0,"image/gif", false);
\r
1460 path = Global.getFileManager().getResDirPath(newRes.getGuid()+".gif");
\r
1461 tfile.rename(path);
\r
1463 newRes = conn.getNoteTable().noteResourceTable.getNoteResource(latexGuid, false);
\r
1464 path = Global.getFileManager().getResDirPath(newRes.getGuid()+".gif");
\r
1465 tfile = new QFile(path);
\r
1466 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
\r
1467 tfile.write(image);
\r
1472 newRes.getAttributes().setSourceURL(reply.url().toString());
\r
1473 // newRes.getData().setBody(image.toByteArray());
\r
1474 // conn.getNoteTable().noteResourceTable.updateNoteResource(newRes, true);
\r
1475 conn.getNoteTable().noteResourceTable.updateNoteSourceUrl(newRes.getGuid(), reply.url().toString(), true);
\r
1477 for(int i=0; i<currentNote.getResourcesSize(); i++) {
\r
1478 if (currentNote.getResources().get(i).getGuid().equals(newRes.getGuid())) {
\r
1479 currentNote.getResources().remove(i);
\r
1480 i=currentNote.getResourcesSize();
\r
1483 currentNote.getResources().add(newRes);
\r
1486 // do the actual insert into the note. We only do this on new formulas. Existing ones we
\r
1487 // just write out the file (which is aleady done) and reload.
\r
1488 if (latexGuid == null) {
\r
1489 StringBuffer buffer = new StringBuffer(100);
\r
1490 String formula = reply.url().toString().toLowerCase().replace("http://latex.codecogs.com/gif.latex?", "");
\r
1491 buffer.append("<a href=\"latex://"+path.replace("\\", "/")+"\" title=\""+formula+"\"><img src=\"");
\r
1492 buffer.append(path.replace("\\", "/"));
\r
1493 buffer.append("\" en-tag=en-media type=\"image/gif\""
\r
1494 +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""
\r
1495 +" guid=\"" +newRes.getGuid() +"\""
\r
1498 String script_start = new String("document.execCommand('insertHTML', false, '");
\r
1499 String script_end = new String("');");
\r
1500 browser.page().mainFrame().evaluateJavaScript(
\r
1501 script_start + buffer + script_end);
\r
1503 QWebSettings.setMaximumPagesInCache(0);
\r
1504 QWebSettings.setObjectCacheCapacities(0, 0, 0);
\r
1505 browser.setHtml(browser.page().mainFrame().toHtml());
\r
1508 resourceSignal.contentChanged.emit(path);
\r
1509 unblockApplication.emit();
\r
1517 public void insertTable() {
\r
1518 TableDialog dialog = new TableDialog();
\r
1520 if (!dialog.okPressed()) {
\r
1524 int cols = dialog.getCols();
\r
1525 int rows = dialog.getRows();
\r
1526 int width = dialog.getWidth();
\r
1527 boolean percent = dialog.isPercent();
\r
1529 String newHTML = "<table border=\"1\" width=\"" +new Integer(width).toString();
\r
1531 newHTML = newHTML +"%";
\r
1532 newHTML = newHTML + "\"><tbody>";
\r
1534 for (int i=0; i<rows; i++) {
\r
1535 newHTML = newHTML +"<tr>";
\r
1536 for (int j=0; j<cols; j++) {
\r
1537 newHTML = newHTML +"<td> </td>";
\r
1539 newHTML = newHTML +"</tr>";
\r
1541 newHTML = newHTML+"</tbody></table>";
\r
1543 String script = "document.execCommand('insertHtml', false, '"+newHTML+"');";
\r
1544 browser.page().mainFrame().evaluateJavaScript(script);
\r
1548 // Text content changed
\r
1549 @SuppressWarnings("unused")
\r
1550 private void selectionChanged() {
\r
1551 browser.encryptAction.setEnabled(true);
\r
1552 browser.insertLinkAction.setEnabled(true);
\r
1553 String scriptStart = "var selection_text = (window.getSelection()).toString();"
\r
1554 + "var range = (window.getSelection()).getRangeAt(0);"
\r
1555 + "var parent_html = range.commonAncestorContainer.innerHTML;"
\r
1556 + "if (parent_html == undefined) {window.jambi.saveSelectedText(selection_text); return;}"
\r
1557 + "var first_text = range.startContainer.nodeValue.substr(range.startOffset);"
\r
1558 + "var last_text = (range.endContainer.nodeValue).substring(0,range.endOffset);"
\r
1559 + "var start = parent_html.indexOf(first_text);"
\r
1560 + "var end = parent_html.indexOf(last_text,start+1)+last_text.length;"
\r
1561 + "var value = parent_html.substring(start,end);"
\r
1562 + "window.jambi.saveSelectedText(value);" ;
\r
1563 browser.page().mainFrame().evaluateJavaScript(scriptStart);
\r
1567 public void saveSelectedText(String text) {
\r
1568 boolean enabled = true;
\r
1569 if (text.trim().length() == 0)
\r
1571 if (text.indexOf("en-tag=\"en-crypt\"") >= 0)
\r
1573 if (text.indexOf("<img en-tag=\"en-media\"") >= 0)
\r
1575 if (text.indexOf("<a en-tag=\"en-media\"") >= 0)
\r
1577 if (text.indexOf("<input ") >= 0)
\r
1580 browser.encryptAction.setEnabled(enabled);
\r
1581 browser.insertLinkAction.setEnabled(enabled);
\r
1582 // selectedText = text;
\r
1585 // Decrypt clicked text
\r
1586 public void decryptText(String id, String text, String hint) {
\r
1587 EnCrypt crypt = new EnCrypt();
\r
1588 String plainText = null;
\r
1589 Calendar currentTime = new GregorianCalendar();
\r
1590 Long l = new Long(currentTime.getTimeInMillis());
\r
1591 String slot = new String(Long.toString(l));
\r
1593 // First, try to decrypt with any keys we already have
\r
1594 for (int i=0; i<Global.passwordRemember.size(); i++) {
\r
1595 plainText = crypt.decrypt(text, Global.passwordRemember.get(i).getFirst(), 64);
\r
1596 if (plainText != null) {
\r
1597 slot = new String(Long.toString(l));
\r
1598 Global.passwordSafe.put(slot, Global.passwordRemember.get(i));
\r
1599 removeEncryption(id, plainText, false, slot);
\r
1605 EnDecryptDialog dialog = new EnDecryptDialog();
\r
1606 dialog.setHint(hint);
\r
1607 while (plainText == null || !dialog.okPressed()) {
\r
1609 if (!dialog.okPressed()) {
\r
1612 plainText = crypt.decrypt(text, dialog.getPassword().trim(), 64);
\r
1613 if (plainText == null) {
\r
1614 QMessageBox.warning(this, "Incorrect Password", "The password entered is not correct");
\r
1617 Pair<String,String> passwordPair = new Pair<String,String>();
\r
1618 passwordPair.setFirst(dialog.getPassword());
\r
1619 passwordPair.setSecond(dialog.getHint());
\r
1620 Global.passwordSafe.put(slot, passwordPair);
\r
1621 // removeEncryption(id, plainText.replaceAll("\n", "<br/>"), dialog.permanentlyDecrypt(), slot);
\r
1622 removeEncryption(id, plainText, dialog.permanentlyDecrypt(), slot);
\r
1623 if (dialog.rememberPassword()) {
\r
1624 Pair<String, String> pair = new Pair<String,String>();
\r
1625 pair.setFirst(dialog.getPassword());
\r
1626 pair.setSecond(dialog.getHint());
\r
1627 Global.passwordRemember.add(pair);
\r
1632 // Get the editor tag line
\r
1633 public TagLineEdit getTagLine() {
\r
1637 // Modify a note's tags
\r
1638 @SuppressWarnings("unused")
\r
1639 private void modifyTags() {
\r
1640 TagAssign tagWindow = new TagAssign(allTags, currentTags, !conn.getNotebookTable().isLinked(currentNote.getNotebookGuid()));
\r
1642 if (tagWindow.okClicked()) {
\r
1643 currentTags.clear();
\r
1644 StringBuffer tagDisplay = new StringBuffer();
\r
1646 List<QListWidgetItem> newTags = tagWindow.getTagList()
\r
1648 for (int i = 0; i < newTags.size(); i++) {
\r
1649 currentTags.add(newTags.get(i).text());
\r
1650 tagDisplay.append(newTags.get(i).text());
\r
1651 if (i < newTags.size() - 1) {
\r
1652 tagDisplay.append(Global.tagDelimeter + " ");
\r
1655 tagEdit.setText(tagDisplay.toString());
\r
1656 noteSignal.tagsChanged.emit(currentNote.getGuid(), currentTags);
\r
1660 // Tag line has been modified by typing text
\r
1661 @SuppressWarnings("unused")
\r
1662 private void modifyTagsTyping() {
\r
1663 String completionText = "";
\r
1664 if (tagEdit.currentCompleterSelection != null && !tagEdit.currentCompleterSelection.equals("")) {
\r
1665 completionText = tagEdit.currentCompleterSelection;
\r
1666 tagEdit.currentCompleterSelection = "";
\r
1669 if (tagEdit.text().equalsIgnoreCase(saveTagList))
\r
1672 // We know something has changed...
\r
1673 String oldTagArray[] = saveTagList.split(Global.tagDelimeter);
\r
1674 String newTagArray[];
\r
1675 if (!completionText.equals("")) {
\r
1676 String before = tagEdit.text().substring(0,tagEdit.cursorPosition());
\r
1677 int lastDelimiter = before.lastIndexOf(Global.tagDelimeter);
\r
1678 if (lastDelimiter > 0)
\r
1679 before = before.substring(0,before.lastIndexOf(Global.tagDelimeter));
\r
1682 String after = tagEdit.text().substring(tagEdit.cursorPosition());
\r
1683 newTagArray = (before+Global.tagDelimeter+completionText+Global.tagDelimeter+after).split(Global.tagDelimeter);
\r
1686 newTagArray = tagEdit.text().split(Global.tagDelimeter);
\r
1689 // Remove any traling or leading blanks
\r
1690 for (int i=0; i<newTagArray.length; i++)
\r
1691 newTagArray[i] = newTagArray[i].trim().replaceAll("^\\s+", "");;
\r
1693 // Remove any potential duplicates from the new list
\r
1694 for (int i=0; i<newTagArray.length; i++) {
\r
1695 boolean foundOnce = false;
\r
1696 for (int j=0; j<newTagArray.length; j++) {
\r
1697 if (newTagArray[j].equalsIgnoreCase(newTagArray[i])) {
\r
1701 newTagArray[j] = "";
\r
1706 List<String> newTagList = new ArrayList<String>();
\r
1707 List<String> oldTagList = new ArrayList<String>();
\r
1709 for (int i = 0; i < oldTagArray.length; i++)
\r
1710 if (!oldTagArray[i].trim().equals(""))
\r
1711 oldTagList.add(oldTagArray[i]);
\r
1712 for (int i = 0; i < newTagArray.length; i++)
\r
1713 if (!newTagArray[i].trim().equals(""))
\r
1714 newTagList.add(newTagArray[i]);
\r
1716 if (conn.getNotebookTable().isLinked(currentNote.getNotebookGuid())) {
\r
1717 for (int i=newTagList.size()-1; i>=0; i--) {
\r
1718 boolean found = false;
\r
1719 for (int j=0; j<allTags.size(); j++) {
\r
1720 if (allTags.get(j).getName().equalsIgnoreCase(newTagList.get(i))) {
\r
1726 newTagList.remove(i);
\r
1730 // Let's cleanup the appearance of the tag list
\r
1731 Collections.sort(newTagList);
\r
1732 String newDisplay = "";
\r
1733 for (int i=0; i<newTagList.size(); i++) {
\r
1734 newDisplay = newDisplay+newTagList.get(i);
\r
1735 if (i<newTagList.size()-1)
\r
1736 newDisplay = newDisplay+Global.tagDelimeter +" ";
\r
1738 tagEdit.blockSignals(true);
\r
1739 tagEdit.setText(newDisplay);
\r
1740 tagEdit.blockSignals(false);
\r
1742 // We now have lists of the new & old. Remove duplicates. If all
\r
1743 // are removed from both then nothing has really changed
\r
1744 for (int i = newTagList.size() - 1; i >= 0; i--) {
\r
1745 String nTag = newTagList.get(i);
\r
1746 for (int j = oldTagList.size() - 1; j >= 0; j--) {
\r
1747 String oTag = oldTagList.get(j);
\r
1748 if (oTag.equalsIgnoreCase(nTag)) {
\r
1749 oldTagList.remove(j);
\r
1750 newTagList.remove(i);
\r
1756 if (oldTagList.size() != 0 || newTagList.size() != 0) {
\r
1757 currentTags.clear();
\r
1758 newTagArray = tagEdit.text().split(Global.tagDelimeter);
\r
1759 for (int i = 0; i < newTagArray.length; i++)
\r
1760 if (!newTagArray[i].trim().equals(""))
\r
1761 currentTags.add(newTagArray[i].trim());
\r
1763 noteSignal.tagsChanged.emit(currentNote.getGuid(), currentTags);
\r
1768 // Tab button was pressed
\r
1769 public void tabPressed() {
\r
1770 if (insideEncryption)
\r
1772 if (!insideList && !insideTable) {
\r
1773 String script_start = new String(
\r
1774 "document.execCommand('insertHtml', false, ' ');");
\r
1775 browser.page().mainFrame().evaluateJavaScript(script_start);
\r
1781 if (insideTable) {
\r
1782 String js = new String( "function getCursorPosition() { "
\r
1783 +" var selObj = window.getSelection();"
\r
1784 +" var selRange = selObj.getRangeAt(0);"
\r
1785 +" var workingNode = window.getSelection().anchorNode;"
\r
1786 +" var rowCount = 0;"
\r
1787 +" var colCount = 0;"
\r
1788 +" while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { "
\r
1789 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
\r
1790 +" rowCount = rowCount+1;"
\r
1792 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
\r
1793 +" colCount = colCount+1;"
\r
1795 +" if (workingNode.previousSibling != null)"
\r
1796 +" workingNode = workingNode.previousSibling;"
\r
1798 +" workingNode = workingNode.parentNode;"
\r
1800 +" var nodes = workingNode.getElementsByTagName('tr');"
\r
1801 +" var tableRows = nodes.length;"
\r
1802 +" nodes = nodes[0].getElementsByTagName('td');"
\r
1803 +" var tableColumns = nodes.length;"
\r
1804 +" window.jambi.setTableCursorPositionTab(rowCount, colCount, tableRows, tableColumns);"
\r
1805 +"} getCursorPosition();");
\r
1806 browser.page().mainFrame().evaluateJavaScript(js);
\r
1810 // If a user presses tab from within a table
\r
1811 public void setTableCursorPositionTab(int currentRow, int currentCol, int tableRows, int tableColumns) {
\r
1812 if (tableRows == currentRow && currentCol == tableColumns) {
\r
1815 KeyboardModifiers modifiers = new KeyboardModifiers(KeyboardModifier.NoModifier);
\r
1816 QKeyEvent right = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Right.value(), modifiers);
\r
1817 QKeyEvent end = new QKeyEvent(Type.KeyPress, Qt.Key.Key_End.value(), modifiers);
\r
1818 QKeyEvent end2 = new QKeyEvent(Type.KeyPress, Qt.Key.Key_End.value(), modifiers);
\r
1819 getBrowser().focusWidget();
\r
1820 QCoreApplication.postEvent(getBrowser(), end);
\r
1821 QCoreApplication.postEvent(getBrowser(), right);
\r
1822 QCoreApplication.postEvent(getBrowser(), end2);
\r
1825 public void backtabPressed() {
\r
1826 if (insideEncryption)
\r
1830 if (insideTable) {
\r
1831 String js = new String( "function getCursorPosition() { "
\r
1832 +" var selObj = window.getSelection();"
\r
1833 +" var selRange = selObj.getRangeAt(0);"
\r
1834 +" var workingNode = window.getSelection().anchorNode;"
\r
1835 +" var rowCount = 0;"
\r
1836 +" var colCount = 0;"
\r
1837 +" while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { "
\r
1838 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
\r
1839 +" rowCount = rowCount+1;"
\r
1841 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
\r
1842 +" colCount = colCount+1;"
\r
1844 +" if (workingNode.previousSibling != null)"
\r
1845 +" workingNode = workingNode.previousSibling;"
\r
1847 +" workingNode = workingNode.parentNode;"
\r
1849 +" var nodes = workingNode.getElementsByTagName('tr');"
\r
1850 +" var tableRows = nodes.length;"
\r
1851 +" nodes = nodes[0].getElementsByTagName('td');"
\r
1852 +" var tableColumns = nodes.length;"
\r
1853 +" window.jambi.setTableCursorPositionBackTab(rowCount, colCount, tableRows, tableColumns);"
\r
1854 +"} getCursorPosition();");
\r
1855 browser.page().mainFrame().evaluateJavaScript(js);
\r
1860 // If a user presses backtab from within a table
\r
1861 public void setTableCursorPositionBackTab(int currentRow, int currentCol, int tableRows, int tableColumns) {
\r
1862 if (currentRow == 1 && currentCol == 1) {
\r
1865 KeyboardModifiers modifiers = new KeyboardModifiers(KeyboardModifier.NoModifier);
\r
1866 QKeyEvent left = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Left.value(), modifiers);
\r
1867 QKeyEvent home = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Home.value(), modifiers);
\r
1868 getBrowser().focusWidget();
\r
1869 QCoreApplication.postEvent(getBrowser(), home);
\r
1870 QCoreApplication.postEvent(getBrowser(), left);
\r
1874 public void setInsideList() {
\r
1875 insideList = true;
\r
1878 // The title has been edited
\r
1879 @SuppressWarnings("unused")
\r
1880 private void titleEdited() {
\r
1881 // If we don't have a good note, or if the current title
\r
1882 // matches the old title then we don't need to do anything
\r
1883 if (currentNote == null)
\r
1885 if (currentNote.getTitle().trim().equals(titleLabel.text().trim()))
\r
1888 // If we have a real change, we need to save it.
\r
1889 noteSignal.titleChanged.emit(currentNote.getGuid(), titleLabel.text());
\r
1890 currentNote.setTitle(titleLabel.text());
\r
1891 saveNoteTitle = titleLabel.text();
\r
1895 // Set the list of note tags
\r
1896 public void setAllTags(List<Tag> l) {
\r
1898 tagEdit.setTagList(l);
\r
1901 // Setter for the current tags
\r
1902 public void setCurrentTags(List<String> s) {
\r
1906 // Save the list of notebooks
\r
1907 public void setNotebookList(List<Notebook> n) {
\r
1909 loadNotebookList();
\r
1912 // Load the notebook list and select the current notebook
\r
1913 private void loadNotebookList() {
\r
1914 if (notebookBox.count() != 0)
\r
1915 notebookBox.clear();
\r
1916 if (notebookList == null)
\r
1919 for (int i = 0; i < notebookList.size(); i++) {
\r
1920 notebookBox.addItem(notebookList.get(i).getName());
\r
1921 if (currentNote != null) {
\r
1922 if (currentNote.getNotebookGuid().equals(
\r
1923 notebookList.get(i).getGuid())) {
\r
1924 notebookBox.setCurrentIndex(i);
\r
1931 // Set the notebook for a note
\r
1932 public void setNotebook(String notebook) {
\r
1933 currentNote.setNotebookGuid(notebook);
\r
1934 loadNotebookList();
\r
1937 // Get the contents of the editor
\r
1938 public String getContent() {
\r
1939 return browser.page().currentFrame().toHtml();
\r
1942 // The note contents have changed
\r
1943 public void contentChanged() {
\r
1944 String content = getContent();
\r
1946 noteSignal.noteChanged.emit(currentNote.getGuid(), content);
\r
1949 // The notebook selection has changed
\r
1950 @SuppressWarnings("unused")
\r
1951 private void notebookChanged() {
\r
1952 boolean changed = false;
\r
1953 String n = notebookBox.currentText();
\r
1954 for (int i = 0; i < notebookList.size(); i++) {
\r
1955 if (n.equals(notebookList.get(i).getName())) {
\r
1956 if (!notebookList.get(i).getGuid().equals(currentNote.getNotebookGuid())) {
\r
1957 String guid = conn.getNotebookTable().findNotebookByName(n);
\r
1958 if (conn.getNotebookTable().isLinked(guid)) {
\r
1959 tagEdit.setText("");
\r
1960 noteSignal.tagsChanged.emit(currentNote.getGuid(), new ArrayList<String>());
\r
1961 FilterEditorTags t = new FilterEditorTags(conn, logger);
\r
1962 setAllTags(t.getValidTags(currentNote));
\r
1964 currentNote.setNotebookGuid(notebookList.get(i).getGuid());
\r
1967 i = notebookList.size();
\r
1971 // If the notebook changed, signal the update
\r
1973 noteSignal.notebookChanged.emit(currentNote.getGuid(), currentNote
\r
1974 .getNotebookGuid());
\r
1977 // Check the note title
\r
1978 private void checkNoteTitle() {
\r
1979 String text = browser.page().currentFrame().toPlainText();
\r
1980 if (saveNoteTitle.trim().equals("") || saveNoteTitle.trim().equals("Untitled Note")) {
\r
1981 int newLine = text.indexOf("\n");
\r
1982 if (newLine > 0) {
\r
1983 text = text.substring(0, newLine);
\r
1984 if (text.trim().equals(""))
\r
1985 text = tr("Untitled Note");
\r
1986 titleLabel.setText(text);
\r
1988 if (text.length() > Constants.EDAM_NOTE_TITLE_LEN_MAX)
\r
1989 titleLabel.setText(text.substring(0, Constants.EDAM_NOTE_TITLE_LEN_MAX));
\r
1991 titleLabel.blockSignals(true);
\r
1992 if (text.trim().equals(""))
\r
1993 titleLabel.setText(tr("Untitled Note"));
\r
1995 titleLabel.setText(text);
\r
1996 titleLabel.blockSignals(false);
\r
1999 noteSignal.titleChanged.emit(currentNote.getGuid(), titleLabel
\r
2004 // Return the note contents so we can email them
\r
2005 public String getContentsToEmail() {
\r
2006 return browser.page().currentFrame().toPlainText().trim();
\r
2008 * int body = browser.page().currentFrame().toHtml().indexOf("<body>");
\r
2009 * String temp = browser.page().currentFrame().toHtml(); if (body == -1)
\r
2010 * temp = "<html><body><b>Test</b></body></html>"; else temp =
\r
2011 * "<html>"+temp.substring(body); return temp; // return
\r
2012 * urlEncode(browser.page().currentFrame().toHtml());
\r
2016 // Insert an image into the editor
\r
2017 private void insertImage(QMimeData mime) {
\r
2018 logger.log(logger.EXTREME, "Entering insertImage");
\r
2019 QImage img = (QImage) mime.imageData();
\r
2020 String script_start = new String(
\r
2021 "document.execCommand('insertHTML', false, '");
\r
2022 String script_end = new String("');");
\r
2024 long now = new Date().getTime();
\r
2025 String path = Global.getFileManager().getResDirPath(
\r
2026 (new Long(now).toString()) + ".jpg");
\r
2028 // This block is just a hack to make sure we wait at least 1ms so we
\r
2030 // have collisions on image names
\r
2031 long i = new Date().getTime();
\r
2033 i = new Date().getTime();
\r
2035 // Open the file & write the data
\r
2036 QFile tfile = new QFile(path);
\r
2037 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
\r
2038 if (!img.save(tfile)) {
\r
2044 Resource newRes = createResource(QUrl.fromLocalFile(path).toString(), 0, "image/jpeg", false);
\r
2045 if (newRes == null)
\r
2047 currentNote.getResources().add(newRes);
\r
2049 // do the actual insert into the note
\r
2050 StringBuffer buffer = new StringBuffer(100);
\r
2051 buffer.append("<img src=\"");
\r
2052 buffer.append(tfile.fileName());
\r
2053 buffer.append("\" en-tag=en-media type=\"image/jpeg\""
\r
2054 +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""
\r
2055 +" guid=\"" +newRes.getGuid() +"\""
\r
2056 +" onContextMenu=\"window.jambi.imageContextMenu(&." +tfile.fileName() +"&.);\""
\r
2059 browser.page().mainFrame().evaluateJavaScript(
\r
2060 script_start + buffer + script_end);
\r
2065 // Handle URLs that are trying to be pasted
\r
2066 public void handleUrls(QMimeData mime) {
\r
2067 logger.log(logger.EXTREME, "Starting handleUrls");
\r
2068 FileNameMap fileNameMap = URLConnection.getFileNameMap();
\r
2070 List<QUrl> urlList = mime.urls();
\r
2071 String url = new String();
\r
2072 String script_start = new String(
\r
2073 "document.execCommand('createLink', false, '");
\r
2074 String script_end = new String("');");
\r
2076 for (int i = 0; i < urlList.size(); i++) {
\r
2077 url = urlList.get(i).toString();
\r
2078 // Find out what type of file we have
\r
2079 String mimeType = fileNameMap.getContentTypeFor(url);
\r
2081 // If null returned, we need to guess at the file type
\r
2082 if (mimeType == null)
\r
2083 mimeType = "application/"
\r
2084 + url.substring(url.lastIndexOf(".") + 1);
\r
2086 // Check if we have an image or some other type of file
\r
2087 if (url.substring(0, 5).equalsIgnoreCase("file:")
\r
2088 && mimeType.substring(0, 5).equalsIgnoreCase("image")) {
\r
2089 handleLocalImageURLPaste(mime, mimeType);
\r
2092 String[] type = mimeType.split("/");
\r
2093 boolean valid = validAttachment(type[1]);
\r
2094 boolean smallEnough = checkFileAttachmentSize(url);
\r
2095 if (smallEnough && valid
\r
2096 && url.substring(0, 5).equalsIgnoreCase("file:")
\r
2097 && !mimeType.substring(0, 5).equalsIgnoreCase("image")) {
\r
2098 handleLocalAttachment(mime, mimeType);
\r
2101 browser.page().mainFrame().evaluateJavaScript(
\r
2102 script_start + url + script_end);
\r
2107 // If a URL being pasted is an image URL, then attach the image
\r
2108 private void handleLocalImageURLPaste(QMimeData mime, String mimeType) {
\r
2109 List<QUrl> urlList = mime.urls();
\r
2110 String url = new String();
\r
2111 String script_start_image = new String(
\r
2112 "document.execCommand('insertHtml', false, '");
\r
2113 String script_end = new String("');");
\r
2114 StringBuffer buffer;
\r
2116 // Copy the image over into the resource directory and create a new resource
\r
2117 // record for each url pasted
\r
2118 for (int i = 0; i < urlList.size(); i++) {
\r
2119 url = urlList.get(i).toString();
\r
2121 Resource newRes = createResource(url, i, mimeType, false);
\r
2122 if (newRes == null)
\r
2124 currentNote.getResources().add(newRes);
\r
2125 buffer = new StringBuffer(100);
\r
2127 // Open the file & write the data
\r
2128 String fileName = Global.getFileManager().getResDirPath(newRes.getGuid());
\r
2129 QFile tfile = new QFile(fileName);
\r
2130 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
\r
2131 tfile.write(newRes.getData().getBody());
\r
2133 buffer.append(script_start_image);
\r
2134 buffer.append("<img src=\"" + FileUtils.toForwardSlashedPath(fileName));
\r
2135 // if (mimeType.equalsIgnoreCase("image/jpg"))
\r
2136 // mimeType = "image/jpeg";
\r
2137 buffer.append("\" en-tag=\"en-media\" type=\"" + mimeType +"\""
\r
2138 +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""
\r
2139 +" guid=\"" +newRes.getGuid() +"\""
\r
2140 +" onContextMenu=\"window.jambi.imageContextMenu('" +tfile.fileName() +"');\""
\r
2142 buffer.append(script_end);
\r
2143 browser.page().mainFrame().evaluateJavaScript(buffer.toString());
\r
2149 // If a URL being pasted is a local file URL, then attach the file
\r
2150 private void handleLocalAttachment(QMimeData mime, String mimeType) {
\r
2151 logger.log(logger.EXTREME, "Attaching local file");
\r
2152 List<QUrl> urlList = mime.urls();
\r
2153 String script_start = new String(
\r
2154 "document.execCommand('insertHtml', false, '");
\r
2155 String script_end = new String("');");
\r
2156 StringBuffer buffer;
\r
2158 String[] type = mimeType.split("/");
\r
2159 String icon = findIcon(type[1]);
\r
2160 if (icon.equals("attachment.png"))
\r
2161 icon = findIcon(type[0]);
\r
2162 buffer = new StringBuffer(100);
\r
2164 for (int i = 0; i < urlList.size(); i++) {
\r
2165 String url = urlList.get(i).toString();
\r
2167 // Start building the HTML
\r
2168 if (icon.equals("attachment.png"))
\r
2169 icon = findIcon(url.substring(url.lastIndexOf(".")+1));
\r
2170 String imageURL = FileUtils.toFileURLString(Global.getFileManager().getImageDirFile(icon));
\r
2172 logger.log(logger.EXTREME, "Creating resource ");
\r
2173 Resource newRes = createResource(url, i, mimeType, true);
\r
2174 if (newRes == null)
\r
2176 logger.log(logger.EXTREME, "New resource size: " +newRes.getData().getSize());
\r
2177 currentNote.getResources().add(newRes);
\r
2179 String fileName = newRes.getGuid() + Global.attachmentNameDelimeter+newRes.getAttributes().getFileName();
\r
2180 // If we have a PDF, we need to setup the preview.
\r
2181 if (icon.equalsIgnoreCase("pdf.png") && Global.pdfPreview()) {
\r
2182 logger.log(logger.EXTREME, "Setting up PDF preview");
\r
2183 if (newRes.getAttributes() != null &&
\r
2184 newRes.getAttributes().getFileName() != null &&
\r
2185 !newRes.getAttributes().getFileName().trim().equals(""))
\r
2186 fileName = newRes.getGuid()+Global.attachmentNameDelimeter+
\r
2187 newRes.getAttributes().getFileName();
\r
2189 fileName = newRes.getGuid()+".pdf";
\r
2190 QFile file = new QFile(Global.getFileManager().getResDirPath(fileName));
\r
2191 QFile.OpenMode mode = new QFile.OpenMode();
\r
2192 mode.set(QFile.OpenModeFlag.WriteOnly);
\r
2194 QDataStream out = new QDataStream(file);
\r
2195 // Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(newRes.getGuid(), true);
\r
2196 QByteArray binData = new QByteArray(newRes.getData().getBody());
\r
2197 // resBinary = null;
\r
2198 out.writeBytes(binData.toByteArray());
\r
2201 PDFPreview pdfPreview = new PDFPreview();
\r
2202 if (pdfPreview.setupPreview(Global.getFileManager().getResDirPath(fileName), "pdf",0)) {
\r
2203 imageURL = file.fileName() + ".png";
\r
2207 logger.log(logger.EXTREME, "Generating link tags");
\r
2208 buffer.delete(0, buffer.length());
\r
2209 buffer.append("<a en-tag=\"en-media\" guid=\"" +newRes.getGuid()+"\" ");
\r
2210 buffer.append(" onContextMenu=\"window.jambi.imageContextMenu('")
\r
2211 .append(Global.getFileManager().getResDirPath(fileName))
\r
2212 .append("');\" "); buffer.append("type=\"" + mimeType + "\" href=\"nnres://" + fileName +"\" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\" >");
\r
2213 buffer.append("<img src=\"" + imageURL + "\" title=\"" +newRes.getAttributes().getFileName());
\r
2214 buffer.append("\"></img>");
\r
2215 buffer.append("</a>");
\r
2216 browser.page().mainFrame().evaluateJavaScript(
\r
2217 script_start + buffer.toString() + script_end);
\r
2222 private Resource createResource(String url, int sequence, String mime, boolean attachment) {
\r
2223 logger.log(logger.EXTREME, "Inside create resource");
\r
2224 QFile resourceFile;
\r
2225 String urlTest = new QUrl(url).toLocalFile();
\r
2226 if (!urlTest.equals(""))
\r
2228 url = url.replace("/", File.separator);
\r
2229 resourceFile = new QFile(url);
\r
2230 resourceFile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly));
\r
2231 byte[] fileData = resourceFile.readAll().toByteArray();
\r
2232 resourceFile.close();
\r
2233 if (fileData.length == 0)
\r
2237 md = MessageDigest.getInstance("MD5");
\r
2238 md.update(fileData);
\r
2239 byte[] hash = md.digest();
\r
2241 Resource r = new Resource();
\r
2242 Calendar time = new GregorianCalendar();
\r
2243 long prevTime = time.getTimeInMillis();
\r
2244 while (prevTime == time.getTimeInMillis()) {
\r
2245 time = new GregorianCalendar();
\r
2247 r.setGuid(time.getTimeInMillis()+new Integer(sequence).toString());
\r
2248 r.setNoteGuid(currentNote.getGuid());
\r
2250 r.setActive(true);
\r
2251 r.setUpdateSequenceNum(0);
\r
2252 r.setWidth((short) 0);
\r
2253 r.setHeight((short) 0);
\r
2254 r.setDuration((short) 0);
\r
2256 Data d = new Data();
\r
2257 d.setBody(fileData);
\r
2258 d.setBodyIsSet(true);
\r
2259 d.setBodyHash(hash);
\r
2260 d.setBodyHashIsSet(true);
\r
2262 d.setSize(fileData.length);
\r
2264 int fileNamePos = url.lastIndexOf(File.separator);
\r
2265 if (fileNamePos == -1)
\r
2266 fileNamePos = url.lastIndexOf("/");
\r
2267 String fileName = url.substring(fileNamePos+1);
\r
2268 ResourceAttributes a = new ResourceAttributes();
\r
2270 a.setAltitudeIsSet(false);
\r
2271 a.setLongitude(0);
\r
2272 a.setLongitudeIsSet(false);
\r
2274 a.setLatitudeIsSet(false);
\r
2275 a.setCameraMake("");
\r
2276 a.setCameraMakeIsSet(false);
\r
2277 a.setCameraModel("");
\r
2278 a.setCameraModelIsSet(false);
\r
2279 a.setAttachment(attachment);
\r
2280 a.setAttachmentIsSet(true);
\r
2281 a.setClientWillIndex(false);
\r
2282 a.setClientWillIndexIsSet(true);
\r
2283 a.setRecoType("");
\r
2284 a.setRecoTypeIsSet(false);
\r
2285 a.setSourceURL(url);
\r
2286 a.setSourceURLIsSet(true);
\r
2287 a.setTimestamp(0);
\r
2288 a.setTimestampIsSet(false);
\r
2289 a.setFileName(fileName);
\r
2290 a.setFileNameIsSet(true);
\r
2291 r.setAttributes(a);
\r
2293 conn.getNoteTable().noteResourceTable.saveNoteResource(r, true);
\r
2295 } catch (NoSuchAlgorithmException e1) {
\r
2296 e1.printStackTrace();
\r
2302 // find the appropriate icon for an attachment
\r
2303 private String findIcon(String appl) {
\r
2304 appl = appl.toLowerCase();
\r
2305 File f = Global.getFileManager().getImageDirFile(appl + ".png");
\r
2307 return appl+".png";
\r
2308 return "attachment.png";
\r
2311 // Check if the account supports this type of attachment
\r
2312 private boolean validAttachment(String type) {
\r
2313 if (Global.isPremium())
\r
2315 if (type.equalsIgnoreCase("JPG"))
\r
2317 if (type.equalsIgnoreCase("PNG"))
\r
2319 if (type.equalsIgnoreCase("GIF"))
\r
2321 if (type.equalsIgnoreCase("MP3"))
\r
2323 if (type.equalsIgnoreCase("WAV"))
\r
2325 if (type.equalsIgnoreCase("AMR"))
\r
2327 if (type.equalsIgnoreCase("PDF"))
\r
2329 String error = tr("Non-premium accounts can only attach JPG, PNG, GIF, MP3, WAV, AMR, or PDF files.");
\r
2330 QMessageBox.information(this, tr("Non-Premium Account"), error);
\r
2335 // Check the file attachment to be sure it isn't over 25 mb
\r
2336 private boolean checkFileAttachmentSize(String url) {
\r
2337 String fileName = url.substring(8);
\r
2338 QFile resourceFile = new QFile(fileName);
\r
2339 resourceFile.open(new QIODevice.OpenMode(
\r
2340 QIODevice.OpenModeFlag.ReadOnly));
\r
2341 long size = resourceFile.size();
\r
2342 resourceFile.close();
\r
2343 size = size / 1024 / 1024;
\r
2344 if (size < 50 && Global.isPremium())
\r
2349 String error = tr("A file attachment may not exceed 25MB.");
\r
2350 QMessageBox.information(this, tr("Attachment Size"), error);
\r
2355 @SuppressWarnings("unused")
\r
2356 private void createdChanged() {
\r
2357 QDateTime dt = new QDateTime();
\r
2358 dt.setDate(createdDate.date());
\r
2359 dt.setTime(createdTime.time());
\r
2360 noteSignal.createdDateChanged.emit(currentNote.getGuid(), dt);
\r
2364 @SuppressWarnings("unused")
\r
2365 private void alteredChanged() {
\r
2366 QDateTime dt = new QDateTime();
\r
2367 dt.setDate(alteredDate.date());
\r
2368 dt.setTime(alteredTime.time());
\r
2369 noteSignal.alteredDateChanged.emit(currentNote.getGuid(), dt);
\r
2372 @SuppressWarnings("unused")
\r
2373 private void subjectDateTimeChanged() {
\r
2374 QDateTime dt = new QDateTime();
\r
2375 dt.setDate(subjectDate.date());
\r
2376 dt.setTime(subjectTime.time());
\r
2377 noteSignal.subjectDateChanged.emit(currentNote.getGuid(), dt);
\r
2381 @SuppressWarnings("unused")
\r
2382 private void sourceUrlChanged() {
\r
2383 noteSignal.sourceUrlChanged.emit(currentNote.getGuid(), urlText.text());
\r
2386 @SuppressWarnings("unused")
\r
2387 private void authorChanged() {
\r
2388 noteSignal.authorChanged.emit(currentNote.getGuid(), authorText.text());
\r
2391 @SuppressWarnings("unused")
\r
2392 private void geoBoxChanged() {
\r
2393 int index = geoBox.currentIndex();
\r
2394 geoBox.setCurrentIndex(0);
\r
2396 GeoDialog box = new GeoDialog();
\r
2397 box.setLongitude(currentNote.getAttributes().getLongitude());
\r
2398 box.setLatitude(currentNote.getAttributes().getLatitude());
\r
2399 box.setAltitude(currentNote.getAttributes().getAltitude());
\r
2401 if (!box.okPressed())
\r
2403 double alt = box.getAltitude();
\r
2404 double lat = box.getLatitude();
\r
2405 double lon = box.getLongitude();
\r
2406 if (alt != currentNote.getAttributes().getAltitude() ||
\r
2407 lon != currentNote.getAttributes().getLongitude() ||
\r
2408 lat != currentNote.getAttributes().getLatitude()) {
\r
2409 noteSignal.geoChanged.emit(currentNote.getGuid(), lon, lat, alt);
\r
2410 currentNote.getAttributes().setAltitude(alt);
\r
2411 currentNote.getAttributes().setLongitude(lon);
\r
2412 currentNote.getAttributes().setLatitude(lat);
\r
2417 noteSignal.geoChanged.emit(currentNote.getGuid(), 0.0, 0.0, 0.0);
\r
2418 currentNote.getAttributes().setAltitude(0.0);
\r
2419 currentNote.getAttributes().setLongitude(0.0);
\r
2420 currentNote.getAttributes().setLatitude(0.0);
\r
2423 if (index == 3 || index == 0) {
\r
2424 QDesktopServices.openUrl(new QUrl("http://maps.google.com/maps?z=6&q="+currentNote.getAttributes().getLatitude() +"," +currentNote.getAttributes().getLongitude()));
\r
2428 // ************************************************************
\r
2429 // * User chose to save an attachment. Pares out the request *
\r
2430 // * into a guid & file. Save the result. *
\r
2431 // ************************************************************
\r
2432 public void downloadAttachment(QNetworkRequest request) {
\r
2434 QFileDialog fd = new QFileDialog(this);
\r
2435 fd.setFileMode(FileMode.AnyFile);
\r
2436 fd.setConfirmOverwrite(true);
\r
2437 fd.setWindowTitle(tr("Save File"));
\r
2438 fd.setAcceptMode(AcceptMode.AcceptSave);
\r
2439 fd.setDirectory(System.getProperty("user.home"));
\r
2440 String name = request.url().toString();
\r
2442 int pos = name.lastIndexOf(Global.attachmentNameDelimeter);
\r
2444 guid = name.substring(0, pos).replace("nnres://", "");
\r
2445 name = name.substring(pos +Global.attachmentNameDelimeter.length());
\r
2446 fd.selectFile(name);
\r
2447 pos = name.lastIndexOf('.');
\r
2449 String mimeType = "(*." + name.substring(pos + 1)
\r
2450 + ");; All Files (*)";
\r
2451 fd.setFilter(tr(mimeType));
\r
2457 // Strip URL prefix and base dir
\r
2458 guid = guid.replace("nnres://", "")
\r
2459 .replace(FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath()), "");
\r
2460 guid = guid.replace("file://", "").replace("/", "")
\r
2461 .replace(FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath()), "");
\r
2463 pos = guid.lastIndexOf('.');
\r
2465 guid = guid.substring(0,pos);
\r
2466 if (fd.exec() != 0 && fd.selectedFiles().size() > 0) {
\r
2467 name = name.replace('\\', '/');
\r
2468 Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
\r
2469 QFile saveFile = new QFile(fd.selectedFiles().get(0));
\r
2470 QFile.OpenMode mode = new QFile.OpenMode();
\r
2471 mode.set(QFile.OpenModeFlag.WriteOnly);
\r
2472 saveFile.open(mode);
\r
2473 QDataStream saveOut = new QDataStream(saveFile);
\r
2474 QByteArray binData = new QByteArray(resBinary.getData().getBody());
\r
2475 saveOut.writeBytes(binData.toByteArray());
\r
2482 // ************************************************************
\r
2483 // * User chose to save an attachment. Pares out the request *
\r
2484 // * into a guid & file. Save the result. --- DONE FROM downloadAttachment now!!!!!
\r
2485 // ************************************************************
\r
2486 public void downloadImage(QNetworkRequest request) {
\r
2487 QFileDialog fd = new QFileDialog(this);
\r
2488 fd.setFileMode(FileMode.AnyFile);
\r
2489 fd.setConfirmOverwrite(true);
\r
2490 fd.setWindowTitle(tr("Save File"));
\r
2491 fd.setAcceptMode(AcceptMode.AcceptSave);
\r
2492 fd.setDirectory(System.getProperty("user.home"));
\r
2493 String name = request.url().toString();
\r
2494 name = name.replace("nnres://", "");
\r
2495 String dPath = FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath());
\r
2496 name = name.replace(dPath, "");
\r
2497 int pos = name.lastIndexOf('.');
\r
2498 String guid = name;
\r
2500 String mimeType = "(*." + name.substring(pos + 1)
\r
2501 + ");; All Files (*)";
\r
2502 fd.setFilter(tr(mimeType));
\r
2503 guid = guid.substring(0,pos);
\r
2505 pos = name.lastIndexOf(Global.attachmentNameDelimeter);
\r
2507 guid = name.substring(0, pos);
\r
2508 fd.selectFile(name.substring(pos+Global.attachmentNameDelimeter.length()));
\r
2510 if (fd.exec() != 0 && fd.selectedFiles().size() > 0) {
\r
2511 Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
\r
2512 String fileName = fd.selectedFiles().get(0);
\r
2513 QFile saveFile = new QFile(fileName);
\r
2514 QFile.OpenMode mode = new QFile.OpenMode();
\r
2515 mode.set(QFile.OpenModeFlag.WriteOnly);
\r
2516 saveFile.open(mode);
\r
2517 QDataStream saveOut = new QDataStream(saveFile);
\r
2518 QByteArray binData = new QByteArray(resBinary.getData().getBody());
\r
2519 saveOut.writeBytes(binData.toByteArray());
\r
2525 // *************************************************************
\r
2526 // * decrypt any hidden text. We could do an XML parse, but
\r
2527 // * it is quicker here just to scan for an <img tag & do the fix
\r
2528 // * the manual way
\r
2529 // *************************************************************
\r
2530 private void removeEncryption(String id, String plainText, boolean permanent, String slot) {
\r
2532 plainText = " <table class=\"en-crypt-temp\" slot=\""
\r
2535 +"border=1 width=100%><tbody><tr><td>"
\r
2536 +plainText+"</td></tr></tbody></table>";
\r
2539 String html = browser.page().mainFrame().toHtml();
\r
2540 String text = html;
\r
2541 int imagePos = html.indexOf("<img");
\r
2543 for ( ;imagePos>0; ) {
\r
2544 // Find the end tag
\r
2545 endPos = text.indexOf(">", imagePos);
\r
2546 String tag = text.substring(imagePos-1,endPos);
\r
2547 if (tag.indexOf("id=\""+id+"\"") > -1) {
\r
2548 text = text.substring(0,imagePos) +plainText+text.substring(endPos+1);
\r
2549 QTextCodec codec = QTextCodec.codecForName("UTF-8");
\r
2550 QByteArray unicode = codec.fromUnicode(text);
\r
2551 browser.setContent(unicode);
\r
2555 imagePos = text.indexOf("<img", imagePos+1);
\r
2560 //****************************************************************
\r
2561 //* Focus shortcuts
\r
2562 //****************************************************************
\r
2563 @SuppressWarnings("unused")
\r
2564 private void focusTitle() {
\r
2565 titleLabel.setFocus();
\r
2567 @SuppressWarnings("unused")
\r
2568 private void focusTag() {
\r
2569 tagEdit.setFocus();
\r
2571 @SuppressWarnings("unused")
\r
2572 private void focusNote() {
\r
2573 browser.setFocus();
\r
2575 @SuppressWarnings("unused")
\r
2576 private void focusAuthor() {
\r
2577 authorLabel.setFocus();
\r
2579 @SuppressWarnings("unused")
\r
2580 private void focusUrl() {
\r
2581 urlLabel.setFocus();
\r
2585 //*****************************************************************
\r
2586 //* Set the document background color
\r
2587 //*****************************************************************
\r
2588 public void setBackgroundColor(String color) {
\r
2589 String js = "function changeBackground(color) {"
\r
2590 +"document.body.style.background = color;"
\r
2592 +"changeBackground('" +color+"');";
\r
2593 browser.page().mainFrame().evaluateJavaScript(js);
\r
2598 //****************************************************************
\r
2599 //* MicroFocus changed
\r
2600 //****************************************************************
\r
2601 private void microFocusChanged() {
\r
2602 boldButton.setDown(false);
\r
2603 italicButton.setDown(false);
\r
2604 underlineButton.setDown(false);
\r
2605 browser.openAction.setEnabled(false);
\r
2606 browser.downloadAttachment.setEnabled(false);
\r
2607 browser.downloadImage.setEnabled(false);
\r
2608 browser.rotateImageLeft.setEnabled(false);
\r
2609 browser.rotateImageRight.setEnabled(false);
\r
2610 browser.insertTableAction.setEnabled(true);
\r
2611 browser.deleteTableColumnAction.setEnabled(false);
\r
2612 browser.insertTableRowAction.setEnabled(false);
\r
2613 browser.insertTableColumnAction.setEnabled(false);
\r
2614 browser.deleteTableRowAction.setEnabled(false);
\r
2615 browser.insertLinkAction.setText(tr("Insert Hyperlink"));
\r
2616 insertHyperlink = true;
\r
2617 currentHyperlink ="";
\r
2618 insideList = false;
\r
2619 insideTable = false;
\r
2620 insideEncryption = false;
\r
2621 forceTextPaste = false;
\r
2623 String js = new String( "function getCursorPos() {"
\r
2625 +"if (window.getSelection) {"
\r
2626 +" var selObj = window.getSelection();"
\r
2627 +" var selRange = selObj.getRangeAt(0);"
\r
2628 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
2629 +" while(workingNode != null) { "
\r
2630 // +" window.jambi.printNode(workingNode.nodeName);"
\r
2631 +" if (workingNode.nodeName=='TABLE') { if (workingNode.getAttribute('class').toLowerCase() == 'en-crypt-temp') window.jambi.insideEncryption(); }"
\r
2632 +" if (workingNode.nodeName=='B') window.jambi.boldActive();"
\r
2633 +" if (workingNode.nodeName=='I') window.jambi.italicActive();"
\r
2634 +" if (workingNode.nodeName=='U') window.jambi.underlineActive();"
\r
2635 +" if (workingNode.nodeName=='UL') window.jambi.setInsideList();"
\r
2636 +" if (workingNode.nodeName=='OL') window.jambi.setInsideList();"
\r
2637 +" if (workingNode.nodeName=='LI') window.jambi.setInsideList();"
\r
2638 +" if (workingNode.nodeName=='TBODY') window.jambi.setInsideTable();"
\r
2639 +" 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
2640 +" if (workingNode.nodeName=='SPAN') {"
\r
2641 +" if (workingNode.getAttribute('style') == 'text-decoration: underline;') window.jambi.underlineActive();"
\r
2643 +" workingNode = workingNode.parentNode;"
\r
2646 +"} getCursorPos();");
\r
2647 browser.page().mainFrame().evaluateJavaScript(js);
\r
2650 public void printNode(String n) {
\r
2651 System.out.println("Node Vaule: " +n);
\r
2654 public void insideEncryption() {
\r
2655 insideEncryption = true;
\r
2659 //****************************************************************
\r
2660 //* Insert a table row
\r
2661 //****************************************************************
\r
2662 public void insertTableRow() {
\r
2664 String js = new String( "function insertTableRow() {"
\r
2665 +" var selObj = window.getSelection();"
\r
2666 +" var selRange = selObj.getRangeAt(0);"
\r
2667 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
2668 +" var cellCount = 0;"
\r
2669 +" while(workingNode != null) { "
\r
2670 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
\r
2671 +" row = document.createElement('TR');"
\r
2672 +" var nodes = workingNode.getElementsByTagName('td');"
\r
2673 +" for (j=0; j<nodes.length; j=j+1) {"
\r
2674 +" cell = document.createElement('TD');"
\r
2675 +" cell.innerHTML=' ';"
\r
2676 +" row.appendChild(cell);"
\r
2678 +" workingNode.parentNode.insertBefore(row,workingNode.nextSibling);"
\r
2681 +" workingNode = workingNode.parentNode;"
\r
2683 +"} insertTableRow();");
\r
2684 browser.page().mainFrame().evaluateJavaScript(js);
\r
2688 public void insertTableColumn() {
\r
2689 String js = new String( "function insertTableColumn() {"
\r
2690 +" var selObj = window.getSelection();"
\r
2691 +" var selRange = selObj.getRangeAt(0);"
\r
2692 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
2693 +" var current = 0;"
\r
2694 +" while (workingNode.nodeName.toLowerCase() != 'table' && workingNode != null) {"
\r
2695 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
\r
2696 +" var td = workingNode;"
\r
2697 +" while (td.previousSibling != null) { "
\r
2698 +" current = current+1; td = td.previousSibling;"
\r
2701 +" workingNode = workingNode.parentNode; "
\r
2703 +" if (workingNode == null) return;"
\r
2704 +" for (var i=0; i<workingNode.rows.length; i++) { "
\r
2705 +" var cell = workingNode.rows[i].insertCell(current+1); "
\r
2706 +" cell.innerHTML = ' '; "
\r
2708 +"} insertTableColumn();");
\r
2709 browser.page().mainFrame().evaluateJavaScript(js);
\r
2713 //****************************************************************
\r
2714 //* Delete a table row
\r
2715 //****************************************************************
\r
2716 public void deleteTableRow() {
\r
2718 String js = new String( "function deleteTableRow() {"
\r
2719 +" var selObj = window.getSelection();"
\r
2720 +" var selRange = selObj.getRangeAt(0);"
\r
2721 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
2722 +" var cellCount = 0;"
\r
2723 +" while(workingNode != null) { "
\r
2724 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
\r
2725 +" workingNode.parentNode.removeChild(workingNode);"
\r
2728 +" workingNode = workingNode.parentNode;"
\r
2730 +"} deleteTableRow();");
\r
2731 browser.page().mainFrame().evaluateJavaScript(js);
\r
2735 public void deleteTableColumn() {
\r
2736 String js = new String( "function deleteTableColumn() {"
\r
2737 +" var selObj = window.getSelection();"
\r
2738 +" var selRange = selObj.getRangeAt(0);"
\r
2739 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
2740 +" var current = 0;"
\r
2741 +" while (workingNode.nodeName.toLowerCase() != 'table' && workingNode != null) {"
\r
2742 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
\r
2743 +" var td = workingNode;"
\r
2744 +" while (td.previousSibling != null) { "
\r
2745 +" current = current+1; td = td.previousSibling;"
\r
2748 +" workingNode = workingNode.parentNode; "
\r
2750 +" if (workingNode == null) return;"
\r
2751 +" for (var i=0; i<workingNode.rows.length; i++) { "
\r
2752 +" workingNode.rows[i].deleteCell(current); "
\r
2754 +"} deleteTableColumn();");
\r
2755 browser.page().mainFrame().evaluateJavaScript(js);
\r
2760 public void setInsideTable() {
\r
2761 browser.insertTableRowAction.setEnabled(true);
\r
2762 browser.insertTableColumnAction.setEnabled(true);
\r
2763 browser.deleteTableRowAction.setEnabled(true);
\r
2764 browser.deleteTableColumnAction.setEnabled(true);
\r
2765 browser.insertTableAction.setEnabled(false);
\r
2766 browser.encryptAction.setEnabled(false);
\r
2767 insideTable = true;
\r
2770 public void setInsideLink(String link) {
\r
2771 browser.insertLinkAction.setText(tr("Edit Hyperlink"));
\r
2772 currentHyperlink = link;
\r
2773 insertHyperlink = false;
\r
2776 public void italicActive() {
\r
2777 italicButton.setDown(true);
\r
2779 public void boldActive() {
\r
2780 boldButton.setDown(true);
\r
2782 public void underlineActive() {
\r
2783 underlineButton.setDown(true);
\r
2785 public void forceTextPaste() {
\r
2786 forceTextPaste = true;
\r
2788 public void imageContextMenu(String f) {
\r
2789 browser.downloadImage.setEnabled(true);
\r
2790 browser.rotateImageRight.setEnabled(true);
\r
2791 browser.rotateImageLeft.setEnabled(true);
\r
2792 browser.openAction.setEnabled(true);
\r
2795 public void rotateImageRight() {
\r
2796 QWebSettings.setMaximumPagesInCache(0);
\r
2797 QWebSettings.setObjectCacheCapacities(0, 0, 0);
\r
2798 QImage image = new QImage(selectedFile);
\r
2799 QMatrix matrix = new QMatrix();
\r
2800 matrix.rotate( 90.0 );
\r
2801 image = image.transformed(matrix);
\r
2802 image.save(selectedFile);
\r
2803 QWebSettings.setMaximumPagesInCache(0);
\r
2804 QWebSettings.setObjectCacheCapacities(0, 0, 0);
\r
2805 browser.setHtml(browser.page().mainFrame().toHtml());
\r
2808 resourceSignal.contentChanged.emit(selectedFile);
\r
2811 public void rotateImageLeft() {
\r
2812 QImage image = new QImage(selectedFile);
\r
2813 QMatrix matrix = new QMatrix();
\r
2814 matrix.rotate( -90.0 );
\r
2815 image = image.transformed(matrix);
\r
2816 image.save(selectedFile);
\r
2817 browser.setHtml(browser.page().mainFrame().toHtml());
\r
2820 resourceSignal.contentChanged.emit(selectedFile);
\r
2822 public void resourceContextMenu(String f) {
\r
2823 browser.downloadAttachment.setEnabled(true);
\r
2824 browser.openAction.setEnabled(true);
\r
2827 public void latexContextMenu(String f) {
\r
2828 browser.downloadImage.setEnabled(true);
\r
2829 browser.rotateImageRight.setEnabled(true);
\r
2830 browser.rotateImageLeft.setEnabled(true);
\r
2831 browser.openAction.setEnabled(true);
\r
2835 //****************************************************************
\r
2836 //* Apply CSS style to specified word
\r
2837 //****************************************************************
\r
2838 /* public void applyStyleToWords(String word, String style) {
\r
2839 QFile script = new QFile("D:\\NeverNote\\js\\hilight1.js");
\r
2840 script.open(OpenModeFlag.ReadOnly);
\r
2841 String s = script.readAll().toString();
\r
2842 String js = new String(s +" findit('"+word+"', '"+style+"');");
\r
2843 browser.page().mainFrame().evaluateJavaScript(js);
\r
2844 System.out.println(getContent());
\r
2847 //****************************************************************
\r
2848 //* Someone tried to paste a resource between notes, so we need *
\r
2849 //* to do some special handling. *
\r
2850 //****************************************************************
\r
2851 private String fixInternotePaste(String text) {
\r
2852 logger.log(logger.EXTREME, "Fixing internote paste");
\r
2853 String returnValue = fixInternotePasteSearch(text, "<img", "src=\"");
\r
2854 return fixInternotePasteSearch(returnValue, "<a", "href=\"nnres://");
\r
2856 private String fixInternotePasteSearch(String text, String type, String locTag) {
\r
2858 // First, let's fix the images.
\r
2859 int startPos = text.indexOf(type);
\r
2861 for (; startPos>=0;) {
\r
2862 endPos = text.indexOf(">", startPos+1);
\r
2863 String segment = text.substring(startPos, endPos);
\r
2864 if (segment.indexOf("en-tag") > -1) {
\r
2865 String newSegment = segment;
\r
2867 int guidStartPos = segment.indexOf("guid=\"");
\r
2868 int guidEndPos = segment.indexOf("\"", guidStartPos+7);
\r
2869 String guid = segment.substring(guidStartPos+6,guidEndPos);
\r
2871 int mimeStartPos = segment.indexOf("type");
\r
2872 int mimeEndPos = segment.indexOf("\"", mimeStartPos+7);
\r
2873 String mime = segment.substring(mimeStartPos+6,mimeEndPos);
\r
2875 int srcStartPos = segment.indexOf("src");
\r
2876 int srcEndPos = segment.indexOf("\"", srcStartPos+6);
\r
2877 String src = segment.substring(srcStartPos+5,srcEndPos);
\r
2879 Calendar currentTime = new GregorianCalendar();
\r
2880 Long l = new Long(currentTime.getTimeInMillis());
\r
2881 long prevTime = l;
\r
2882 while (l==prevTime) {
\r
2883 currentTime = new GregorianCalendar();
\r
2884 l= new Long(currentTime.getTimeInMillis());
\r
2887 Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
\r
2888 // if r==null, then the image doesn't exist (it was probably cut out of another note, so
\r
2889 // we need to recereate it
\r
2891 r = createResource(src, 1, mime, false);
\r
2895 String randint = new String(Long.toString(l));
\r
2896 String extension = null;
\r
2897 if (r.getMime()!= null) {
\r
2898 extension = r.getMime().toLowerCase();
\r
2899 if (extension.indexOf("/")>-1)
\r
2900 extension = extension.substring(extension.indexOf("/")+1);
\r
2902 String newFile = randint;
\r
2903 if (r.getAttributes().getFileName() != null && r.getAttributes().getFileName() != "")
\r
2904 if (!locTag.startsWith("src"))
\r
2905 newFile = newFile+Global.attachmentNameDelimeter+r.getAttributes().getFileName();
\r
2906 r.setNoteGuid(currentNote.getGuid());
\r
2908 r.setGuid(randint);
\r
2909 conn.getNoteTable().noteResourceTable.saveNoteResource(r, true);
\r
2910 QFile f = new QFile(Global.getFileManager().getResDirPath(newFile));
\r
2911 QByteArray bin = new QByteArray(r.getData().getBody());
\r
2912 f.open(QFile.OpenModeFlag.WriteOnly);
\r
2915 newSegment = newSegment.replace("guid=\""+guid, "guid=\""+randint);
\r
2916 currentNote.getResources().add(r);
\r
2918 int startSrcPos = newSegment.indexOf(locTag);
\r
2919 int endSrcPos = newSegment.indexOf("\"",startSrcPos+locTag.length()+1);
\r
2921 if (locTag.startsWith("src")) {
\r
2922 source = newSegment.substring(startSrcPos+locTag.length(),endSrcPos);
\r
2923 newSegment = newSegment.replace(source,
\r
2924 FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath(newFile)));
\r
2926 source = newSegment.substring(startSrcPos+locTag.length(),endSrcPos);
\r
2927 newSegment = newSegment.replace(source, newFile);
\r
2930 text = text.substring(0,startPos) + newSegment + text.substring(endPos);
\r
2932 startPos = text.indexOf(type, startPos+1);
\r
2938 public void nextPage(String file) {
\r
2939 logger.log(logger.EXTREME, "Starting nextPage()");
\r
2941 Integer pageNumber;
\r
2942 if (previewPageList.containsKey(file))
\r
2943 pageNumber = previewPageList.get(file)+1;
\r
2946 previewPageList.remove(file);
\r
2947 previewPageList.put(file, pageNumber);
\r
2948 PDFPreview pdfPreview = new PDFPreview();
\r
2949 boolean goodPreview = pdfPreview.setupPreview(file, "pdf", pageNumber);
\r
2950 if (goodPreview) {
\r
2952 // String html = getContent();
\r
2953 QWebSettings.setMaximumPagesInCache(0);
\r
2954 QWebSettings.setObjectCacheCapacities(0, 0, 0);
\r
2955 // browser.setContent(new QByteArray());
\r
2956 browser.setHtml(browser.page().mainFrame().toHtml());
\r
2958 // browser.setContent(new QByteArray(html));
\r
2959 // browser.triggerPageAction(WebAction.Reload);
\r
2960 // pdfMouseOver(selectedFile);
\r
2964 public void previousPage(String file) {
\r
2965 logger.log(logger.EXTREME, "Starting previousPage()");
\r
2967 Integer pageNumber;
\r
2968 if (previewPageList.containsKey(file))
\r
2969 pageNumber = previewPageList.get(file)-1;
\r
2972 previewPageList.remove(file);
\r
2973 previewPageList.put(file, pageNumber);
\r
2974 PDFPreview pdfPreview = new PDFPreview();
\r
2975 boolean goodPreview = pdfPreview.setupPreview(file, "pdf", pageNumber);
\r
2976 if (goodPreview) {
\r
2978 // String html = getContent();
\r
2979 QWebSettings.setMaximumPagesInCache(0);
\r
2980 QWebSettings.setObjectCacheCapacities(0, 0, 0);
\r
2981 browser.setHtml(browser.page().mainFrame().toHtml());
\r
2983 // browser.setContent(new QByteArray(html));
\r
2984 // browser.triggerPageAction(WebAction.Reload);
\r
2988 /* public void pdfMouseOver(String name) {
\r
2990 if (previewPageList.containsKey(selectedFile))
\r
2991 pageNumber = previewPageList.get(selectedFile)+1;
\r
2995 if (pageNumber <= 1)
\r
2996 browser.previousPageAction.setEnabled(false);
\r
2998 browser.previousPageAction.setEnabled(true);
\r
3000 PDFPreview pdf = new PDFPreview();
\r
3001 int totalPages = pdf.getPageCount(name);
\r
3002 if (previewPageList.containsKey(selectedFile))
\r
3003 pageNumber = previewPageList.get(selectedFile)+1;
\r
3006 if (totalPages > pageNumber)
\r
3007 browser.nextPageAction.setEnabled(true);
\r
3009 browser.nextPageAction.setEnabled(false);
\r
3013 public void pdfMouseOut() {
\r
3014 // browser.nextPageAction.setVisible(false);
\r
3015 // browser.previousPageAction.setVisible(false);
\r
3019 @SuppressWarnings("unused")
\r
3020 private void toggleUndoVisible(Boolean toggle) {
\r
3021 undoAction.setVisible(toggle);
\r
3022 Global.saveEditorButtonsVisible("undo", toggle);
\r
3024 @SuppressWarnings("unused")
\r
3025 private void toggleRedoVisible(Boolean toggle) {
\r
3026 redoAction.setVisible(toggle);
\r
3027 Global.saveEditorButtonsVisible("redo", toggle);
\r
3029 @SuppressWarnings("unused")
\r
3030 private void toggleCutVisible(Boolean toggle) {
\r
3031 cutAction.setVisible(toggle);
\r
3032 Global.saveEditorButtonsVisible("cut", toggle);
\r
3034 @SuppressWarnings("unused")
\r
3035 private void toggleCopyVisible(Boolean toggle) {
\r
3036 copyAction.setVisible(toggle);
\r
3037 Global.saveEditorButtonsVisible("copy", toggle);
\r
3039 @SuppressWarnings("unused")
\r
3040 private void togglePasteVisible(Boolean toggle) {
\r
3041 pasteAction.setVisible(toggle);
\r
3042 Global.saveEditorButtonsVisible("paste", toggle);
\r
3044 @SuppressWarnings("unused")
\r
3045 private void toggleBoldVisible(Boolean toggle) {
\r
3046 boldAction.setVisible(toggle);
\r
3047 Global.saveEditorButtonsVisible("bold", toggle);
\r
3049 @SuppressWarnings("unused")
\r
3050 private void toggleItalicVisible(Boolean toggle) {
\r
3051 italicAction.setVisible(toggle);
\r
3052 Global.saveEditorButtonsVisible("italic", toggle);
\r
3054 @SuppressWarnings("unused")
\r
3055 private void toggleUnderlineVisible(Boolean toggle) {
\r
3056 underlineAction.setVisible(toggle);
\r
3057 Global.saveEditorButtonsVisible("underline", toggle);
\r
3059 @SuppressWarnings("unused")
\r
3060 private void toggleStrikethroughVisible(Boolean toggle) {
\r
3061 strikethroughAction.setVisible(toggle);
\r
3062 Global.saveEditorButtonsVisible("strikethrough", toggle);
\r
3064 @SuppressWarnings("unused")
\r
3065 private void toggleLeftAlignVisible(Boolean toggle) {
\r
3066 leftAlignAction.setVisible(toggle);
\r
3067 Global.saveEditorButtonsVisible("alignLeft", toggle);
\r
3069 @SuppressWarnings("unused")
\r
3070 private void toggleRightAlignVisible(Boolean toggle) {
\r
3071 rightAlignAction.setVisible(toggle);
\r
3072 Global.saveEditorButtonsVisible("alignRight", toggle);
\r
3074 @SuppressWarnings("unused")
\r
3075 private void toggleCenterAlignVisible(Boolean toggle) {
\r
3076 centerAlignAction.setVisible(toggle);
\r
3077 Global.saveEditorButtonsVisible("alignCenter", toggle);
\r
3079 @SuppressWarnings("unused")
\r
3080 private void toggleHLineVisible(Boolean toggle) {
\r
3081 hlineAction.setVisible(toggle);
\r
3082 Global.saveEditorButtonsVisible("hline", toggle);
\r
3084 @SuppressWarnings("unused")
\r
3085 private void toggleIndentVisible(Boolean toggle) {
\r
3086 indentAction.setVisible(toggle);
\r
3087 Global.saveEditorButtonsVisible("indent", toggle);
\r
3089 @SuppressWarnings("unused")
\r
3090 private void toggleTodoVisible(Boolean toggle) {
\r
3091 todoAction.setVisible(toggle);
\r
3092 Global.saveEditorButtonsVisible("todo", toggle);
\r
3094 @SuppressWarnings("unused")
\r
3095 private void toggleOutdentVisible(Boolean toggle) {
\r
3096 outdentAction.setVisible(toggle);
\r
3097 Global.saveEditorButtonsVisible("outdent", toggle);
\r
3099 @SuppressWarnings("unused")
\r
3100 private void toggleBulletListVisible(Boolean toggle) {
\r
3101 bulletListAction.setVisible(toggle);
\r
3102 Global.saveEditorButtonsVisible("bulletList", toggle);
\r
3104 @SuppressWarnings("unused")
\r
3105 private void toggleNumberListVisible(Boolean toggle) {
\r
3106 numberListAction.setVisible(toggle);
\r
3107 Global.saveEditorButtonsVisible("numberList", toggle);
\r
3109 @SuppressWarnings("unused")
\r
3110 private void toggleFontListVisible(Boolean toggle) {
\r
3111 fontListAction.setVisible(toggle);
\r
3112 Global.saveEditorButtonsVisible("font", toggle);
\r
3114 @SuppressWarnings("unused")
\r
3115 private void toggleFontColorVisible(Boolean toggle) {
\r
3116 fontColorAction.setVisible(toggle);
\r
3117 Global.saveEditorButtonsVisible("fontColor", toggle);
\r
3119 @SuppressWarnings("unused")
\r
3120 private void toggleFontSizeVisible(Boolean toggle) {
\r
3121 fontSizeAction.setVisible(toggle);
\r
3122 Global.saveEditorButtonsVisible("fontSize", toggle);
\r
3124 @SuppressWarnings("unused")
\r
3125 private void toggleFontHilightVisible(Boolean toggle) {
\r
3126 fontHilightAction.setVisible(toggle);
\r
3127 Global.saveEditorButtonsVisible("fontHilight", toggle);
\r
3129 @SuppressWarnings("unused")
\r
3130 private void toggleSpellCheckVisible(Boolean toggle) {
\r
3131 spellCheckAction.setVisible(toggle);
\r
3132 Global.saveEditorButtonsVisible("spellCheck", toggle);
\r
3136 private void setupDictionary() {
\r
3137 File wordList = new File(Global.getFileManager().getSpellDirPath()+Locale.getDefault()+".dic");
\r
3139 dictionary = new SpellDictionaryHashMap(wordList);
\r
3140 spellChecker = new SpellChecker(dictionary);
\r
3142 File userWordList;
\r
3143 userWordList = new File(Global.getFileManager().getSpellDirPathUser()+"user.dic");
\r
3145 // Get the local user spell dictionary
\r
3147 userDictionary = new SpellDictionaryHashMap(userWordList);
\r
3148 } catch (FileNotFoundException e) {
\r
3149 userWordList.createNewFile();
\r
3150 userDictionary = new SpellDictionaryHashMap(userWordList);
\r
3151 } catch (IOException e) {
\r
3152 userWordList.createNewFile();
\r
3153 userDictionary = new SpellDictionaryHashMap(userWordList);
\r
3156 spellListener = new SuggestionListener(this, spellChecker);
\r
3158 // Add the user dictionary
\r
3159 spellChecker.addSpellCheckListener(spellListener);
\r
3160 spellChecker.setUserDictionary(userDictionary);
\r
3162 } catch (FileNotFoundException e) {
\r
3163 QMessageBox.critical(this, tr("Spell Check Error"),
\r
3164 tr("Dictionary "+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+
\r
3165 ".dic was not found."));
\r
3166 } catch (IOException e) {
\r
3167 QMessageBox.critical(this, tr("Spell Check Error"),
\r
3168 tr("Dictionary "+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+
\r
3169 ".dic is invalid."));
\r
3174 // Invoke spell checker dialog
\r
3175 @SuppressWarnings("unused")
\r
3176 private void spellCheckClicked() {
\r
3178 if (spellChecker == null) {
\r
3179 setupDictionary();
\r
3182 // Read user settings
\r
3183 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREDIGITWORDS,
\r
3184 Global.getSpellSetting(Configuration.SPELL_IGNOREDIGITWORDS));
\r
3185 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREINTERNETADDRESSES,
\r
3186 Global.getSpellSetting(Configuration.SPELL_IGNOREINTERNETADDRESSES));
\r
3187 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREMIXEDCASE,
\r
3188 Global.getSpellSetting(Configuration.SPELL_IGNOREMIXEDCASE));
\r
3189 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREUPPERCASE,
\r
3190 Global.getSpellSetting(Configuration.SPELL_IGNOREUPPERCASE));
\r
3191 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNORESENTENCECAPITALIZATION,
\r
3192 Global.getSpellSetting(Configuration.SPELL_IGNORESENTENCECAPITALIZATION));
\r
3194 spellListener.abortSpellCheck = false;
\r
3195 spellListener.errorsFound = false;
\r
3196 String content = getBrowser().page().mainFrame().toPlainText();
\r
3197 StringWordTokenizer tokenizer = new StringWordTokenizer(content);
\r
3198 if (!tokenizer.hasMoreWords())
\r
3200 getBrowser().page().action(WebAction.MoveToStartOfDocument);
\r
3202 getBrowser().setFocus();
\r
3205 // Move to the start of page
\r
3206 KeyboardModifiers ctrl = new KeyboardModifiers(KeyboardModifier.ControlModifier.value());
\r
3207 QKeyEvent home = new QKeyEvent(Type.KeyPress, Key.Key_Home.value(), ctrl);
\r
3208 browser.keyPressEvent(home);
\r
3209 getBrowser().setFocus();
\r
3211 tokenizer = new StringWordTokenizer(content);
\r
3214 while(tokenizer.hasMoreWords()) {
\r
3215 word = tokenizer.nextWord();
\r
3216 found = getBrowser().page().findText(word);
\r
3217 if (found && !spellListener.abortSpellCheck) {
\r
3218 spellChecker.checkSpelling(new StringWordTokenizer(word));
\r
3219 getBrowser().setFocus();
\r
3223 // Go to the end of the document & finish up.
\r
3224 home = new QKeyEvent(Type.KeyPress, Key.Key_End.value(), ctrl);
\r
3225 browser.keyPressEvent(home);
\r
3226 if (!spellListener.errorsFound)
\r
3227 QMessageBox.information(this, tr("Spell Check Complete"),
\r
3228 tr("No Errors Found"));
\r