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
39 import java.util.StringTokenizer;
\r
41 import org.apache.commons.lang.StringUtils;
\r
43 import com.evernote.edam.limits.Constants;
\r
44 import com.evernote.edam.type.Data;
\r
45 import com.evernote.edam.type.Note;
\r
46 import com.evernote.edam.type.Notebook;
\r
47 import com.evernote.edam.type.Resource;
\r
48 import com.evernote.edam.type.ResourceAttributes;
\r
49 import com.evernote.edam.type.Tag;
\r
50 import com.swabunga.spell.engine.Configuration;
\r
51 import com.swabunga.spell.engine.SpellDictionary;
\r
52 import com.swabunga.spell.engine.SpellDictionaryHashMap;
\r
53 import com.swabunga.spell.engine.Word;
\r
54 import com.swabunga.spell.event.SpellCheckEvent;
\r
55 import com.swabunga.spell.event.SpellCheckListener;
\r
56 import com.swabunga.spell.event.SpellChecker;
\r
57 import com.swabunga.spell.event.StringWordTokenizer;
\r
58 import com.trolltech.qt.core.QByteArray;
\r
59 import com.trolltech.qt.core.QCoreApplication;
\r
60 import com.trolltech.qt.core.QDataStream;
\r
61 import com.trolltech.qt.core.QDateTime;
\r
62 import com.trolltech.qt.core.QEvent;
\r
63 import com.trolltech.qt.core.QEvent.Type;
\r
64 import com.trolltech.qt.core.QFile;
\r
65 import com.trolltech.qt.core.QFileSystemWatcher;
\r
66 import com.trolltech.qt.core.QIODevice;
\r
67 import com.trolltech.qt.core.QMimeData;
\r
68 import com.trolltech.qt.core.QTextCodec;
\r
69 import com.trolltech.qt.core.QUrl;
\r
70 import com.trolltech.qt.core.Qt;
\r
71 import com.trolltech.qt.core.Qt.Key;
\r
72 import com.trolltech.qt.core.Qt.KeyboardModifier;
\r
73 import com.trolltech.qt.core.Qt.KeyboardModifiers;
\r
74 import com.trolltech.qt.gui.QAction;
\r
75 import com.trolltech.qt.gui.QApplication;
\r
76 import com.trolltech.qt.gui.QCalendarWidget;
\r
77 import com.trolltech.qt.gui.QClipboard;
\r
78 import com.trolltech.qt.gui.QClipboard.Mode;
\r
79 import com.trolltech.qt.gui.QColor;
\r
80 import com.trolltech.qt.gui.QComboBox;
\r
81 import com.trolltech.qt.gui.QDateEdit;
\r
82 import com.trolltech.qt.gui.QDesktopServices;
\r
83 import com.trolltech.qt.gui.QFileDialog;
\r
84 import com.trolltech.qt.gui.QFileDialog.AcceptMode;
\r
85 import com.trolltech.qt.gui.QFileDialog.FileMode;
\r
86 import com.trolltech.qt.gui.QFontDatabase;
\r
87 import com.trolltech.qt.gui.QFormLayout;
\r
88 import com.trolltech.qt.gui.QGridLayout;
\r
89 import com.trolltech.qt.gui.QHBoxLayout;
\r
90 import com.trolltech.qt.gui.QIcon;
\r
91 import com.trolltech.qt.gui.QImage;
\r
92 import com.trolltech.qt.gui.QKeyEvent;
\r
93 import com.trolltech.qt.gui.QKeySequence;
\r
94 import com.trolltech.qt.gui.QLabel;
\r
95 import com.trolltech.qt.gui.QLineEdit;
\r
96 import com.trolltech.qt.gui.QListWidgetItem;
\r
97 import com.trolltech.qt.gui.QMatrix;
\r
98 import com.trolltech.qt.gui.QMessageBox;
\r
99 import com.trolltech.qt.gui.QPalette;
\r
100 import com.trolltech.qt.gui.QPalette.ColorRole;
\r
101 import com.trolltech.qt.gui.QPushButton;
\r
102 import com.trolltech.qt.gui.QShortcut;
\r
103 import com.trolltech.qt.gui.QTimeEdit;
\r
104 import com.trolltech.qt.gui.QToolButton;
\r
105 import com.trolltech.qt.gui.QToolButton.ToolButtonPopupMode;
\r
106 import com.trolltech.qt.gui.QVBoxLayout;
\r
107 import com.trolltech.qt.gui.QWidget;
\r
108 import com.trolltech.qt.network.QNetworkAccessManager;
\r
109 import com.trolltech.qt.network.QNetworkReply;
\r
110 import com.trolltech.qt.network.QNetworkReply.NetworkError;
\r
111 import com.trolltech.qt.network.QNetworkRequest;
\r
112 import com.trolltech.qt.webkit.QWebPage;
\r
113 import com.trolltech.qt.webkit.QWebPage.WebAction;
\r
114 import com.trolltech.qt.webkit.QWebSettings;
\r
115 import com.trolltech.qt.webkit.QWebView;
\r
117 import cx.fbn.nevernote.Global;
\r
118 import cx.fbn.nevernote.dialog.EnCryptDialog;
\r
119 import cx.fbn.nevernote.dialog.EnDecryptDialog;
\r
120 import cx.fbn.nevernote.dialog.GeoDialog;
\r
121 import cx.fbn.nevernote.dialog.InsertLatexImage;
\r
122 import cx.fbn.nevernote.dialog.InsertLinkDialog;
\r
123 import cx.fbn.nevernote.dialog.SpellCheck;
\r
124 import cx.fbn.nevernote.dialog.TableDialog;
\r
125 import cx.fbn.nevernote.dialog.TagAssign;
\r
126 import cx.fbn.nevernote.evernote.EnCrypt;
\r
127 import cx.fbn.nevernote.filters.FilterEditorTags;
\r
128 import cx.fbn.nevernote.signals.NoteResourceSignal;
\r
129 import cx.fbn.nevernote.signals.NoteSignal;
\r
130 import cx.fbn.nevernote.sql.DatabaseConnection;
\r
131 import cx.fbn.nevernote.utilities.ApplicationLogger;
\r
132 import cx.fbn.nevernote.utilities.FileUtils;
\r
133 import cx.fbn.nevernote.utilities.Pair;
\r
134 import cx.fbn.nevernote.xml.HtmlTagModifier;
\r
136 public class BrowserWindow extends QWidget {
\r
138 public final QLineEdit titleLabel;
\r
139 private final QLineEdit urlText;
\r
140 private final QLabel authorLabel;
\r
141 private final QLineEdit authorText;
\r
142 private final QComboBox geoBox;
\r
143 public final TagLineEdit tagEdit;
\r
144 public final QLabel tagLabel;
\r
145 private final QPushButton urlLabel;
\r
146 private final QLabel alteredLabel;
\r
147 private final QDateEdit alteredDate;
\r
148 private final QTimeEdit alteredTime;
\r
149 private final QDateEdit createdDate;
\r
150 private final QTimeEdit createdTime;
\r
151 private final QLabel subjectLabel;
\r
152 private final QDateEdit subjectDate;
\r
153 private final QTimeEdit subjectTime;
\r
154 public final QComboBox notebookBox;
\r
155 private final QLabel notebookLabel;
\r
156 private final QLabel createdLabel;
\r
157 public final QComboBox fontSize;
\r
158 public final QAction fontSizeAction;
\r
159 private boolean extendedOn;
\r
160 public boolean buttonsVisible;
\r
161 private final String iconPath = new String("classpath:cx/fbn/nevernote/icons/");
\r
162 private final ContentView browser;
\r
163 private List<Tag> allTags;
\r
164 private List<String> currentTags;
\r
165 public NoteSignal noteSignal;
\r
166 public Signal2<String,String> evernoteLinkClicked;
\r
167 private List<Notebook> notebookList;
\r
168 private Note currentNote;
\r
169 private String saveNoteTitle;
\r
170 private String saveTagList;
\r
171 private boolean insideList;
\r
172 private final DatabaseConnection conn;
\r
173 private final QCalendarWidget createdCalendarWidget;
\r
174 private final QCalendarWidget alteredCalendarWidget;
\r
175 private final QCalendarWidget subjectCalendarWidget;
\r
177 public final QPushButton undoButton;
\r
178 public final QAction undoAction;
\r
179 public final QPushButton redoButton;
\r
180 public final QAction redoAction;
\r
181 public final QPushButton cutButton;
\r
182 public final QAction cutAction;
\r
183 public final QPushButton copyButton;
\r
184 public final QAction copyAction;
\r
185 public final QPushButton pasteButton;
\r
186 public final QAction pasteAction;
\r
187 public final QPushButton boldButton;
\r
188 public final QAction boldAction;
\r
189 public final QPushButton underlineButton;
\r
190 public final QAction underlineAction;
\r
191 public final QPushButton italicButton;
\r
192 public final QAction italicAction;
\r
193 public final Signal0 focusLost;
\r
194 public final NoteResourceSignal resourceSignal;
\r
196 public QPushButton rightAlignButton;
\r
197 public final QAction rightAlignAction;
\r
198 public QPushButton leftAlignButton;
\r
199 public final QAction leftAlignAction;
\r
200 public QPushButton centerAlignButton;
\r
201 public final QAction centerAlignAction;
\r
203 public final QPushButton strikethroughButton;
\r
204 public final QAction strikethroughAction;
\r
205 public final QPushButton hlineButton;
\r
206 public final QAction hlineAction;
\r
207 public final QPushButton indentButton;
\r
208 public final QAction indentAction;
\r
209 public final QPushButton outdentButton;
\r
210 public final QAction outdentAction;
\r
211 public final QPushButton bulletListButton;
\r
212 public final QAction bulletListAction;
\r
213 public final QPushButton numberListButton;
\r
214 public final QAction numberListAction;
\r
215 public final QPushButton spellCheckButton;
\r
216 public final QAction spellCheckAction;
\r
217 public final QPushButton todoButton;
\r
218 public final QAction todoAction;
\r
220 public final QShortcut focusTitleShortcut;
\r
221 public final QShortcut focusTagShortcut;
\r
222 public final QShortcut focusNoteShortcut;
\r
223 public final QShortcut focusUrlShortcut;
\r
224 public final QShortcut focusAuthorShortcut;
\r
226 public EditorButtonBar buttonLayout;
\r
227 public final QComboBox fontList;
\r
228 public final QAction fontListAction;
\r
229 public final QToolButton fontColor;
\r
230 public final QAction fontColorAction;
\r
231 private final ColorMenu fontColorMenu;
\r
232 public final QToolButton fontHilight;
\r
233 public final QAction fontHilightAction;
\r
234 private final ColorMenu fontHilightColorMenu;
\r
235 public final QFileSystemWatcher fileWatcher;
\r
236 public int cursorPosition;
\r
237 private boolean forceTextPaste = false;
\r
238 private String selectedFile;
\r
239 private String currentHyperlink;
\r
240 public boolean keepPDFNavigationHidden;
\r
241 private final ApplicationLogger logger;
\r
242 SpellDictionary dictionary;
\r
243 SpellDictionary userDictionary;
\r
244 SpellChecker spellChecker;
\r
245 SuggestionListener spellListener;
\r
246 private final HashMap<String,Integer> previewPageList;
\r
247 boolean insertHyperlink = true;
\r
248 boolean insideTable = false;
\r
249 boolean insideEncryption = false;
\r
250 public Signal1<BrowserWindow> blockApplication;
\r
251 public Signal0 unblockApplication;
\r
252 public boolean awaitingHttpResponse;
\r
253 public long unblockTime;
\r
254 String latexGuid; // This is set if we are editing an existing LaTeX formula. Useful to track guid.
\r
257 public static class SuggestionListener implements SpellCheckListener {
\r
258 public boolean abortSpellCheck = false;
\r
259 public boolean errorsFound = false;
\r
260 private final SpellCheck spellCheckDialog;
\r
263 private final BrowserWindow parent;
\r
264 public SuggestionListener(BrowserWindow parent, SpellChecker checker) {
\r
265 this.parent = parent;
\r
266 spellCheckDialog = new SpellCheck(checker);
\r
268 public void spellingError(SpellCheckEvent event) {
\r
269 errorsFound = true;
\r
270 spellCheckDialog.setWord(event.getInvalidWord());
\r
272 @SuppressWarnings("unchecked")
\r
273 List<Word> suggestions = event.getSuggestions();
\r
274 spellCheckDialog.clearSuggestions();
\r
275 if (!suggestions.isEmpty()) {
\r
276 // spellCheckDialog.setCurrentSuggestion(suggestions.get(0).getWord());
\r
277 for (int i=0; i<suggestions.size(); i++) {
\r
278 spellCheckDialog.addSuggestion(suggestions.get(i).getWord());
\r
280 spellCheckDialog.setSelectedSuggestion(0);
\r
282 spellCheckDialog.exec();
\r
283 if (spellCheckDialog.cancelPressed()) {
\r
284 abortSpellCheck = true;
\r
288 if (spellCheckDialog.replacePressed()) {
\r
289 QClipboard clipboard = QApplication.clipboard();
\r
290 clipboard.setText(spellCheckDialog.getReplacementWord());
\r
291 parent.pasteClicked();
\r
299 public BrowserWindow(DatabaseConnection c) {
\r
300 logger = new ApplicationLogger("browser.log");
\r
301 logger.log(logger.HIGH, "Setting up browser");
\r
303 fileWatcher = new QFileSystemWatcher();
\r
304 // fileWatcher.fileChanged.connect(this, "fileChanged(String)");
\r
305 noteSignal = new NoteSignal();
\r
306 titleLabel = new QLineEdit();
\r
307 evernoteLinkClicked = new Signal2<String,String>();
\r
308 titleLabel.setMaxLength(Constants.EDAM_NOTE_TITLE_LEN_MAX);
\r
309 urlText = new QLineEdit();
\r
310 authorText = new QLineEdit();
\r
311 geoBox = new QComboBox();
\r
312 urlLabel = new QPushButton();
\r
313 urlLabel.clicked.connect(this, "sourceUrlClicked()");
\r
314 authorLabel = new QLabel();
\r
317 focusLost = new Signal0();
\r
319 tagEdit = new TagLineEdit(allTags);
\r
320 tagLabel = new QLabel(tr("Tags:"));
\r
321 tagEdit.focusLost.connect(this, "modifyTagsTyping()");
\r
323 createdCalendarWidget = new QCalendarWidget();
\r
324 createdDate = new QDateEdit();
\r
325 createdDate.setDisplayFormat(Global.getDateFormat());
\r
326 createdDate.setCalendarPopup(true);
\r
327 createdDate.setCalendarWidget(createdCalendarWidget);
\r
328 createdTime = new QTimeEdit();
\r
329 createdDate.dateChanged.connect(this, "createdChanged()");
\r
330 createdTime.timeChanged.connect(this, "createdChanged()");
\r
332 alteredCalendarWidget = new QCalendarWidget();
\r
333 alteredDate = new QDateEdit();
\r
334 alteredDate.setDisplayFormat(Global.getDateFormat());
\r
335 alteredDate.setCalendarPopup(true);
\r
336 alteredDate.setCalendarWidget(alteredCalendarWidget);
\r
337 alteredTime = new QTimeEdit();
\r
338 alteredLabel = new QLabel(tr("Altered:"));
\r
339 alteredDate.dateChanged.connect(this, "alteredChanged()");
\r
340 alteredTime.timeChanged.connect(this, "alteredChanged()");
\r
342 subjectCalendarWidget = new QCalendarWidget();
\r
343 subjectDate = new QDateEdit();
\r
344 subjectDate.setDisplayFormat(Global.getDateFormat());
\r
345 subjectDate.setCalendarPopup(true);
\r
346 subjectDate.setCalendarWidget(subjectCalendarWidget);
\r
347 subjectTime = new QTimeEdit();
\r
348 subjectLabel = new QLabel(tr("Subject Date:"));
\r
349 subjectDate.dateChanged.connect(this, "subjectDateTimeChanged()");
\r
350 subjectTime.timeChanged.connect(this, "subjectDateTimeChanged()");
\r
351 authorText.textChanged.connect(this, "authorChanged()");
\r
352 urlText.textChanged.connect(this, "sourceUrlChanged()");
\r
354 notebookBox = new QComboBox();
\r
355 notebookLabel = new QLabel(tr("Notebook"));
\r
356 createdLabel = new QLabel(tr("Created:"));
\r
357 // selectedText = new String();
\r
359 urlLabel.setVisible(false);
\r
360 urlText.setVisible(false);
\r
361 authorLabel.setVisible(false);
\r
363 geoBox.setVisible(false);
\r
364 geoBox.addItem(new QIcon(iconPath+"globe.png"), "");
\r
365 geoBox.addItem(new String(tr("Set")));
\r
366 geoBox.addItem(new String(tr("Clear")));
\r
367 geoBox.addItem(new String(tr("View On Map")));
\r
368 geoBox.activated.connect(this, "geoBoxChanged()");
\r
370 authorText.setVisible(false);
\r
371 createdDate.setVisible(false);
\r
372 alteredLabel.setVisible(false);
\r
373 //notebookBox.setVisible(false);
\r
374 notebookLabel.setVisible(false);
\r
375 createdLabel.setVisible(false);
\r
376 createdTime.setVisible(false);
\r
377 alteredDate.setVisible(false);
\r
378 alteredTime.setVisible(false);
\r
379 subjectLabel.setVisible(false);
\r
380 subjectDate.setVisible(false);
\r
381 subjectTime.setVisible(false);
\r
382 extendedOn = false;
\r
383 buttonsVisible = true;
\r
384 setAcceptDrops(true);
\r
386 browser = new ContentView(this);
\r
387 browser.page().setLinkDelegationPolicy(
\r
388 QWebPage.LinkDelegationPolicy.DelegateAllLinks);
\r
389 browser.linkClicked.connect(this, "linkClicked(QUrl)");
\r
390 currentHyperlink = "";
\r
392 QVBoxLayout v = new QVBoxLayout();
\r
393 QFormLayout notebookLayout = new QFormLayout();
\r
394 QGridLayout dateLayout = new QGridLayout();
\r
395 titleLabel.setReadOnly(false);
\r
396 titleLabel.editingFinished.connect(this, "titleEdited()");
\r
397 browser.page().contentsChanged.connect(this, "contentChanged()");
\r
398 browser.page().selectionChanged.connect(this, "selectionChanged()");
\r
399 browser.page().mainFrame().javaScriptWindowObjectCleared.connect(this,
\r
400 "exposeToJavascript()");
\r
402 notebookBox.activated.connect(this, "notebookChanged()");
\r
403 resourceSignal = new NoteResourceSignal();
\r
405 QHBoxLayout tagLayout = new QHBoxLayout();
\r
406 v.addWidget(titleLabel, 0);
\r
407 notebookLayout.addRow(notebookLabel, notebookBox);
\r
408 tagLayout.addLayout(notebookLayout, 0);
\r
409 tagLayout.stretch(4);
\r
410 tagLayout.addWidget(tagLabel, 0);
\r
411 tagLayout.addWidget(tagEdit, 1);
\r
412 v.addLayout(tagLayout);
\r
414 QHBoxLayout urlLayout = new QHBoxLayout();
\r
415 urlLayout.addWidget(urlLabel, 0);
\r
416 urlLayout.addWidget(urlText, 0);
\r
417 v.addLayout(urlLayout);
\r
419 QHBoxLayout authorLayout = new QHBoxLayout();
\r
420 authorLayout.addWidget(authorLabel, 0);
\r
421 authorLayout.addWidget(authorText, 0);
\r
422 authorLayout.addWidget(geoBox);
\r
423 v.addLayout(authorLayout);
\r
425 dateLayout.addWidget(createdLabel, 0, 0);
\r
426 dateLayout.addWidget(createdDate, 0, 1);
\r
427 dateLayout.addWidget(createdTime, 0, 2);
\r
428 dateLayout.setColumnStretch(9, 100);
\r
429 dateLayout.addWidget(alteredLabel, 0, 3);
\r
430 dateLayout.addWidget(alteredDate, 0, 4);
\r
431 dateLayout.addWidget(alteredTime, 0, 5);
\r
432 dateLayout.addWidget(subjectLabel, 0, 6);
\r
433 dateLayout.addWidget(subjectDate, 0, 7);
\r
434 dateLayout.addWidget(subjectTime, 0, 8);
\r
435 v.addLayout(dateLayout, 0);
\r
437 undoButton = newEditorButton("undo", tr("Undo Change"));
\r
438 redoButton = newEditorButton("redo", tr("Redo Change"));
\r
439 cutButton = newEditorButton("cut", tr("Cut"));
\r
440 copyButton = newEditorButton("copy", tr("Copy"));
\r
441 pasteButton = newEditorButton("paste", tr("Paste"));
\r
442 boldButton = newEditorButton("bold", tr("Bold"));
\r
443 underlineButton = newEditorButton("underline", tr("Underline"));
\r
444 italicButton = newEditorButton("italic", tr("Italic"));
\r
446 rightAlignButton = newEditorButton("justifyRight", tr("Right Align"));
\r
447 leftAlignButton = newEditorButton("justifyLeft", tr("Left Align"));
\r
448 centerAlignButton = newEditorButton("justifyCenter", tr("Center Align"));
\r
450 strikethroughButton = newEditorButton("strikethrough", tr("Strikethrough"));
\r
451 hlineButton = newEditorButton("hline", tr("Insert Horizontal Line"));
\r
452 indentButton = newEditorButton("indent", tr("Shift Right"));
\r
453 outdentButton = newEditorButton("outdent", tr("Shift Left"));
\r
454 bulletListButton = newEditorButton("bulletList", tr("Bullet List"));
\r
455 numberListButton = newEditorButton("numberList", tr("Number List"));
\r
456 spellCheckButton = newEditorButton("spellCheck", tr("Spell Check"));
\r
457 todoButton = newEditorButton("todo", tr("To-do"));
\r
460 buttonLayout = new EditorButtonBar();
\r
461 v.addWidget(buttonLayout);
\r
463 undoAction = buttonLayout.addWidget(undoButton);
\r
464 buttonLayout.toggleUndoVisible.triggered.connect(this, "toggleUndoVisible(Boolean)");
\r
465 redoAction = buttonLayout.addWidget(redoButton);
\r
466 buttonLayout.toggleRedoVisible.triggered.connect(this, "toggleRedoVisible(Boolean)");
\r
468 buttonLayout.addWidget(newSeparator());
\r
469 cutAction = buttonLayout.addWidget(cutButton);
\r
470 buttonLayout.toggleCutVisible.triggered.connect(this, "toggleCutVisible(Boolean)");
\r
471 copyAction = buttonLayout.addWidget(copyButton);
\r
472 buttonLayout.toggleCopyVisible.triggered.connect(this, "toggleCopyVisible(Boolean)");
\r
473 pasteAction = buttonLayout.addWidget(pasteButton);
\r
474 buttonLayout.togglePasteVisible.triggered.connect(this, "togglePasteVisible(Boolean)");
\r
476 buttonLayout.addWidget(newSeparator());
\r
477 boldAction = buttonLayout.addWidget(boldButton);
\r
478 buttonLayout.toggleBoldVisible.triggered.connect(this, "toggleBoldVisible(Boolean)");
\r
479 italicAction = buttonLayout.addWidget(italicButton);
\r
480 buttonLayout.toggleItalicVisible.triggered.connect(this, "toggleItalicVisible(Boolean)");
\r
481 underlineAction = buttonLayout.addWidget(underlineButton);
\r
482 buttonLayout.toggleUnderlineVisible.triggered.connect(this, "toggleUnderlineVisible(Boolean)");
\r
483 strikethroughAction = buttonLayout.addWidget(strikethroughButton);
\r
484 buttonLayout.toggleStrikethroughVisible.triggered.connect(this, "toggleStrikethroughVisible(Boolean)");
\r
487 buttonLayout.addWidget(newSeparator());
\r
488 leftAlignAction = buttonLayout.addWidget(leftAlignButton);
\r
489 buttonLayout.toggleLeftAlignVisible.triggered.connect(this, "toggleLeftAlignVisible(Boolean)");
\r
490 centerAlignAction = buttonLayout.addWidget(centerAlignButton);
\r
491 buttonLayout.toggleCenterAlignVisible.triggered.connect(this, "toggleCenterAlignVisible(Boolean)");
\r
492 rightAlignAction = buttonLayout.addWidget(rightAlignButton);
\r
493 buttonLayout.toggleRightAlignVisible.triggered.connect(this, "toggleRightAlignVisible(Boolean)");
\r
495 buttonLayout.addWidget(newSeparator());
\r
496 hlineAction = buttonLayout.addWidget(hlineButton);
\r
497 buttonLayout.toggleHLineVisible.triggered.connect(this, "toggleHLineVisible(Boolean)");
\r
499 indentAction = buttonLayout.addWidget(indentButton);
\r
500 buttonLayout.toggleIndentVisible.triggered.connect(this, "toggleIndentVisible(Boolean)");
\r
501 outdentAction = buttonLayout.addWidget(outdentButton);
\r
502 buttonLayout.toggleOutdentVisible.triggered.connect(this, "toggleOutdentVisible(Boolean)");
\r
503 bulletListAction = buttonLayout.addWidget(bulletListButton);
\r
504 buttonLayout.toggleBulletListVisible.triggered.connect(this, "toggleBulletListVisible(Boolean)");
\r
505 numberListAction = buttonLayout.addWidget(numberListButton);
\r
506 buttonLayout.toggleNumberListVisible.triggered.connect(this, "toggleNumberListVisible(Boolean)");
\r
508 // Setup the font & font size combo boxes
\r
509 buttonLayout.addWidget(newSeparator());
\r
510 fontList = new QComboBox();
\r
511 fontSize = new QComboBox();
\r
512 fontList.setToolTip("Font");
\r
513 fontSize.setToolTip("Font Size");
\r
514 fontList.activated.connect(this, "fontChanged(String)");
\r
515 fontSize.activated.connect(this, "fontSizeChanged(String)");
\r
516 fontListAction = buttonLayout.addWidget(fontList);
\r
517 buttonLayout.toggleFontVisible.triggered.connect(this, "toggleFontListVisible(Boolean)");
\r
518 fontSizeAction = buttonLayout.addWidget(fontSize);
\r
519 buttonLayout.toggleFontSizeVisible.triggered.connect(this, "toggleFontSizeVisible(Boolean)");
\r
520 QFontDatabase fonts = new QFontDatabase();
\r
521 List<String> fontFamilies = fonts.families();
\r
522 for (int i = 0; i < fontFamilies.size(); i++) {
\r
523 fontList.addItem(fontFamilies.get(i));
\r
525 loadFontSize(fontFamilies.get(i));
\r
529 // buttonLayout.addWidget(newSeparator(), 0);
\r
530 fontColor = newToolButton("fontColor", tr("Font Color"));
\r
531 fontColorMenu = new ColorMenu(this);
\r
532 fontColor.setMenu(fontColorMenu.getMenu());
\r
533 fontColor.setPopupMode(ToolButtonPopupMode.MenuButtonPopup);
\r
534 fontColor.setAutoRaise(false);
\r
535 fontColorMenu.getMenu().triggered.connect(this, "fontColorClicked()");
\r
536 fontColorAction = buttonLayout.addWidget(fontColor);
\r
537 buttonLayout.toggleFontColorVisible.triggered.connect(this, "toggleFontColorVisible(Boolean)");
\r
538 fontHilight = newToolButton("fontHilight", tr("Font Hilight Color"));
\r
539 fontHilight.setPopupMode(ToolButtonPopupMode.MenuButtonPopup);
\r
540 fontHilight.setAutoRaise(false);
\r
541 fontHilightColorMenu = new ColorMenu(this);
\r
542 fontHilightColorMenu.setDefault(QColor.yellow);
\r
543 fontHilight.setMenu(fontHilightColorMenu.getMenu());
\r
544 fontHilightColorMenu.getMenu().triggered.connect(this, "fontHilightClicked()");
\r
545 fontHilightAction = buttonLayout.addWidget(fontHilight);
\r
546 fontHilightColorMenu.setDefault(QColor.yellow);
\r
547 buttonLayout.toggleFontHilight.triggered.connect(this, "toggleFontHilightVisible(Boolean)");
\r
549 spellCheckAction = buttonLayout.addWidget(spellCheckButton);
\r
550 buttonLayout.toggleNumberListVisible.triggered.connect(this, "spellCheckClicked()");
\r
551 buttonLayout.toggleSpellCheck.triggered.connect(this, "toggleSpellCheckVisible(Boolean)");
\r
553 todoAction = buttonLayout.addWidget(todoButton);
\r
554 buttonLayout.toggleNumberListVisible.triggered.connect(this, "todoClicked()");
\r
555 buttonLayout.toggleTodo.triggered.connect(this, "toggleTodoVisible(Boolean)");
\r
558 // buttonLayout.addWidget(new QLabel(), 1);
\r
559 v.addWidget(browser, 1);
\r
562 browser.downloadAttachmentRequested.connect(this,
\r
563 "downloadAttachment(QNetworkRequest)");
\r
564 browser.downloadImageRequested.connect(this,
\r
565 "downloadImage(QNetworkRequest)");
\r
566 setTabOrder(notebookBox, tagEdit);
\r
567 setTabOrder(tagEdit, browser);
\r
569 focusNoteShortcut = new QShortcut(this);
\r
570 setupShortcut(focusNoteShortcut, "Focus_Note");
\r
571 focusNoteShortcut.activated.connect(this, "focusNote()");
\r
572 focusTitleShortcut = new QShortcut(this);
\r
573 setupShortcut(focusTitleShortcut, "Focus_Title");
\r
574 focusTitleShortcut.activated.connect(this, "focusTitle()");
\r
575 focusTagShortcut = new QShortcut(this);
\r
576 setupShortcut(focusTagShortcut, "Focus_Tag");
\r
577 focusTagShortcut.activated.connect(this, "focusTag()");
\r
578 focusAuthorShortcut = new QShortcut(this);
\r
579 setupShortcut(focusAuthorShortcut, "Focus_Author");
\r
580 focusAuthorShortcut.activated.connect(this, "focusAuthor()");
\r
581 focusUrlShortcut = new QShortcut(this);
\r
582 setupShortcut(focusUrlShortcut, "Focus_Url");
\r
583 focusUrlShortcut.activated.connect(this, "focusUrl()");
\r
585 browser.page().mainFrame().setTextSizeMultiplier(Global.getTextSizeMultiplier());
\r
586 browser.page().mainFrame().setZoomFactor(Global.getZoomFactor());
\r
588 previewPageList = new HashMap<String,Integer>();
\r
590 browser.page().microFocusChanged.connect(this, "microFocusChanged()");
\r
594 QPalette pal = new QPalette();
\r
595 pal.setColor(ColorRole.Text, QColor.black);
\r
596 titleLabel.setPalette(pal);
\r
597 authorText.setPalette(pal);
\r
598 authorLabel.setPalette(pal);
\r
599 urlLabel.setPalette(pal);
\r
600 urlText.setPalette(pal);
\r
601 createdDate.setPalette(pal);
\r
602 createdTime.setPalette(pal);
\r
603 alteredDate.setPalette(pal);
\r
604 alteredTime.setPalette(pal);
\r
605 subjectDate.setPalette(pal);
\r
606 subjectTime.setPalette(pal);
\r
607 tagEdit.setPalette(pal);
\r
608 notebookBox.setPalette(pal);
\r
610 blockApplication = new Signal1<BrowserWindow>();
\r
611 unblockApplication = new Signal0();
\r
613 logger.log(logger.HIGH, "Browser setup complete");
\r
618 private void setupShortcut(QShortcut action, String text) {
\r
619 if (!Global.shortcutKeys.containsAction(text))
\r
621 action.setKey(new QKeySequence(Global.shortcutKeys.getShortcut(text)));
\r
627 // Getter for the QWebView
\r
628 public QWebView getBrowser() {
\r
632 // Block signals while loading data or things are flagged as dirty by
\r
634 public void loadingData(boolean val) {
\r
635 logger.log(logger.EXTREME, "Entering BrowserWindow.loadingData() " +val);
\r
636 notebookBox.blockSignals(val);
\r
637 browser.page().blockSignals(val);
\r
638 browser.page().mainFrame().blockSignals(val);
\r
639 titleLabel.blockSignals(val);
\r
640 alteredDate.blockSignals(val);
\r
641 alteredTime.blockSignals(val);
\r
642 createdTime.blockSignals(val);
\r
643 createdDate.blockSignals(val);
\r
644 subjectDate.blockSignals(val);
\r
645 subjectTime.blockSignals(val);
\r
646 urlText.blockSignals(val);
\r
647 authorText.blockSignals(val);
\r
649 exposeToJavascript();
\r
650 logger.log(logger.EXTREME, "Exiting BrowserWindow.loadingData() " +val);
\r
654 public void setReadOnly(boolean v) {
\r
656 titleLabel.setEnabled(!v);
\r
657 notebookBox.setEnabled(!v);
\r
658 tagEdit.setEnabled(!v);
\r
659 authorLabel.setEnabled(!v);
\r
660 geoBox.setEnabled(!v);
\r
661 urlText.setEnabled(!v);
\r
662 createdDate.setEnabled(!v);
\r
663 subjectDate.setEnabled(!v);
\r
664 alteredDate.setEnabled(!v);
\r
665 authorText.setEnabled(!v);
\r
666 createdTime.setEnabled(!v);
\r
667 alteredTime.setEnabled(!v);
\r
668 subjectTime.setEnabled(!v);
\r
669 getBrowser().setEnabled(true);
\r
670 // getBrowser().setEnabled(!v);
\r
673 // expose this class to Javascript on the web page
\r
674 private void exposeToJavascript() {
\r
675 browser.page().mainFrame().addToJavaScriptWindowObject("jambi", this);
\r
678 // Custom event queue
\r
680 public boolean event(QEvent e) {
\r
681 if (e.type().equals(QEvent.Type.FocusOut)) {
\r
682 logger.log(logger.EXTREME, "Focus lost");
\r
685 return super.event(e);
\r
688 // clear out browser
\r
689 public void clear() {
\r
690 logger.log(logger.EXTREME, "Entering BrowserWindow.clear()");
\r
692 browser.setContent(new QByteArray());
\r
693 tagEdit.setText("");
\r
694 tagEdit.tagCompleter.reset();
\r
695 urlLabel.setText(tr("Source URL:"));
\r
696 titleLabel.setText("");
\r
697 logger.log(logger.EXTREME, "Exiting BrowserWindow.clear()");
\r
700 // get/set current note
\r
701 public void setNote(Note n) {
\r
705 saveNoteTitle = n.getTitle();
\r
709 public Note getNote() {
\r
710 return currentNote;
\r
713 // New Editor Button
\r
714 private QPushButton newEditorButton(String name, String toolTip) {
\r
715 QPushButton button = new QPushButton();
\r
716 // QIcon icon = new QIcon(iconPath + name + ".gif");
\r
717 QIcon icon = new QIcon(iconPath + name + ".png");
\r
718 button.setIcon(icon);
\r
719 button.setToolTip(toolTip);
\r
720 button.clicked.connect(this, name + "Clicked()");
\r
723 // New Editor Button
\r
724 private QToolButton newToolButton(String name, String toolTip) {
\r
725 QToolButton button = new QToolButton();
\r
726 // QIcon icon = new QIcon(iconPath + name + ".gif");
\r
727 QIcon icon = new QIcon(iconPath + name + ".png");
\r
728 button.setIcon(icon);
\r
729 button.setToolTip(toolTip);
\r
730 button.clicked.connect(this, name + "Clicked()");
\r
735 private QLabel newSeparator() {
\r
736 return new QLabel(" ");
\r
739 // Set the title in the window
\r
740 public void setTitle(String t) {
\r
741 titleLabel.setText(t);
\r
746 // Return the current text title
\r
747 public String getTitle() {
\r
748 return titleLabel.text();
\r
751 // Set the tag name string
\r
752 public void setTag(String t) {
\r
754 tagEdit.setText(t);
\r
755 tagEdit.tagCompleter.reset();
\r
758 // Set the source URL
\r
759 public void setUrl(String t) {
\r
760 urlLabel.setText(tr("Source URL:\t"));
\r
761 urlText.setText(t);
\r
764 // The user want's to launch a web browser on the source of the URL
\r
765 public void sourceUrlClicked() {
\r
766 // Make sure we have a valid URL
\r
767 if (urlText.text().trim().equals(""))
\r
770 String url = urlText.text();
\r
771 if (!url.toLowerCase().startsWith(tr("http://")))
\r
772 url = tr("http://") +url;
\r
774 if (!QDesktopServices.openUrl(new QUrl(url))) {
\r
775 logger.log(logger.LOW, "Error opening file :" +url);
\r
779 public void setAuthor(String t) {
\r
780 authorLabel.setText(tr("Author:\t"));
\r
781 authorText.setText(t);
\r
784 // Set the creation date
\r
785 public void setCreation(long date) {
\r
786 QDateTime dt = new QDateTime();
\r
787 dt.setTime_t((int) (date / 1000));
\r
788 createdDate.setDateTime(dt);
\r
789 createdTime.setDateTime(dt);
\r
790 createdDate.setDisplayFormat(Global.getDateFormat());
\r
791 createdTime.setDisplayFormat(Global.getTimeFormat());
\r
794 // Set the creation date
\r
795 public void setAltered(long date) {
\r
796 QDateTime dt = new QDateTime();
\r
797 dt.setTime_t((int) (date / 1000));
\r
798 alteredDate.setDateTime(dt);
\r
799 alteredTime.setDateTime(dt);
\r
800 alteredDate.setDisplayFormat(Global.getDateFormat());
\r
801 alteredTime.setDisplayFormat(Global.getTimeFormat());
\r
804 // Set the subject date
\r
805 public void setSubjectDate(long date) {
\r
806 QDateTime dt = new QDateTime();
\r
807 dt.setTime_t((int) (date / 1000));
\r
808 subjectDate.setDateTime(dt);
\r
809 subjectTime.setDateTime(dt);
\r
810 subjectDate.setDisplayFormat(Global.getDateFormat());
\r
811 subjectTime.setDisplayFormat(Global.getTimeFormat());
\r
814 // Toggle the extended attribute information
\r
815 public void toggleInformation() {
\r
817 extendedOn = false;
\r
821 urlLabel.setVisible(extendedOn);
\r
822 urlText.setVisible(extendedOn);
\r
823 authorText.setVisible(extendedOn);
\r
824 geoBox.setVisible(extendedOn);
\r
825 authorLabel.setVisible(extendedOn);
\r
826 createdDate.setVisible(extendedOn);
\r
827 createdTime.setVisible(extendedOn);
\r
828 createdLabel.setVisible(extendedOn);
\r
829 alteredLabel.setVisible(extendedOn);
\r
830 alteredDate.setVisible(extendedOn);
\r
831 alteredTime.setVisible(extendedOn);
\r
832 //notebookBox.setVisible(extendedOn);
\r
833 notebookLabel.setVisible(extendedOn);
\r
834 subjectLabel.setVisible(extendedOn);
\r
835 subjectDate.setVisible(extendedOn);
\r
836 subjectTime.setVisible(extendedOn);
\r
839 public void hideButtons() {
\r
841 undoButton.parentWidget().setVisible(false);
\r
842 buttonsVisible = false;
\r
846 // Is the extended view on?
\r
847 public boolean isExtended() {
\r
851 // Listener for when a link is clicked
\r
852 @SuppressWarnings("unused")
\r
853 private void openFile() {
\r
854 logger.log(logger.EXTREME, "Starting openFile()");
\r
855 File fileHandle = new File(selectedFile);
\r
856 URI fileURL = fileHandle.toURI();
\r
857 String localURL = fileURL.toString();
\r
858 QUrl url = new QUrl(localURL);
\r
859 QFile file = new QFile(selectedFile);
\r
861 logger.log(logger.EXTREME, "Adding to fileWatcher:"+file.fileName());
\r
862 fileWatcher.addPath(file.fileName());
\r
864 if (!QDesktopServices.openUrl(url)) {
\r
865 logger.log(logger.LOW, "Error opening file :" +url);
\r
870 // Listener for when a link is clicked
\r
871 @SuppressWarnings("unused")
\r
872 private void linkClicked(QUrl url) {
\r
873 logger.log(logger.EXTREME, "URL Clicked: " +url.toString());
\r
874 if (url.toString().startsWith("latex:")) {
\r
875 int position = url.toString().lastIndexOf(".");
\r
876 String guid = url.toString().substring(0,position);
\r
877 position = guid.lastIndexOf("/");
\r
878 guid = guid.substring(position+1);
\r
882 if (url.toString().startsWith("evernote:/view/")) {
\r
883 StringTokenizer tokens = new StringTokenizer(url.toString().replace("evernote:/view/", ""), "/");
\r
884 tokens.nextToken();
\r
885 tokens.nextToken();
\r
886 String sid = tokens.nextToken();
\r
887 String lid = tokens.nextToken();
\r
889 // Emit that we want to switch to a new note
\r
890 evernoteLinkClicked.emit(sid, lid);
\r
894 if (url.toString().startsWith("nnres://")) {
\r
895 logger.log(logger.EXTREME, "URL is NN resource");
\r
896 if (url.toString().endsWith("/vnd.evernote.ink")) {
\r
897 logger.log(logger.EXTREME, "Unable to open ink note");
\r
898 QMessageBox.information(this, tr("Unable Open"), tr("This is an ink note.\n"+
\r
899 "Ink notes are not supported since Evernote has not\n published any specifications on them\n" +
\r
900 "and I'm too lazy to figure them out by myself."));
\r
903 String fullName = url.toString().substring(8);
\r
904 int index = fullName.indexOf(".");
\r
908 type = fullName.substring(index+1);
\r
909 guid = fullName.substring(0,index);
\r
911 index = guid.indexOf(Global.attachmentNameDelimeter);
\r
913 guid = guid.substring(0,index);
\r
915 List<Resource> resList = currentNote.getResources();
\r
916 Resource res = null;
\r
917 for (int i=0; i<resList.size(); i++) {
\r
918 if (resList.get(i).getGuid().equals(guid)) {
\r
919 res = resList.get(i);
\r
924 String resGuid = Global.resourceMap.get(guid);
\r
925 if (resGuid != null)
\r
926 res = conn.getNoteTable().noteResourceTable.getNoteResource(resGuid, true);
\r
930 if (res.getAttributes() != null &&
\r
931 res.getAttributes().getFileName() != null &&
\r
932 !res.getAttributes().getFileName().trim().equals(""))
\r
933 fileName = res.getGuid()+Global.attachmentNameDelimeter+res.getAttributes().getFileName();
\r
935 fileName = res.getGuid()+"."+type;
\r
936 QFile file = new QFile(Global.getFileManager().getResDirPath(fileName));
\r
937 QFile.OpenMode mode = new QFile.OpenMode();
\r
938 mode.set(QFile.OpenModeFlag.WriteOnly);
\r
939 boolean openResult = file.open(mode);
\r
940 logger.log(logger.EXTREME, "File opened:" +openResult);
\r
941 QDataStream out = new QDataStream(file);
\r
942 Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(res.getGuid(), true);
\r
943 QByteArray binData = new QByteArray(resBinary.getData().getBody());
\r
945 logger.log(logger.EXTREME, "Writing resource");
\r
946 out.writeBytes(binData.toByteArray());
\r
949 String whichOS = System.getProperty("os.name");
\r
950 if (whichOS.contains("Windows"))
\r
951 url.setUrl("file:///"+file.fileName());
\r
953 url.setUrl("file://"+file.fileName());
\r
954 // fileWatcher.removePath(file.fileName());
\r
955 logger.log(logger.EXTREME, "Adding file watcher " +file.fileName());
\r
956 fileWatcher.addPath(file.fileName());
\r
958 // If we can't open it, then prompt the user to save it.
\r
959 if (!QDesktopServices.openUrl(url)) {
\r
960 logger.log(logger.EXTREME, "We can't handle this. Where do we put it?");
\r
961 QFileDialog dialog = new QFileDialog();
\r
963 if (dialog.exec()!=0) {
\r
964 List<String> fileNames = dialog.selectedFiles(); //gets all selected filenames
\r
965 if (fileNames.size() == 0)
\r
967 String sf = fileNames.get(0);
\r
968 QFile saveFile = new QFile(sf);
\r
969 mode.set(QFile.OpenModeFlag.WriteOnly);
\r
970 saveFile.open(mode);
\r
971 QDataStream saveOut = new QDataStream(saveFile);
\r
972 saveOut.writeBytes(binData.toByteArray());
\r
980 logger.log(logger.EXTREME, "Launching URL");
\r
981 QDesktopServices.openUrl(url);
\r
984 // Listener for when BOLD is clicked
\r
985 @SuppressWarnings("unused")
\r
986 private void undoClicked() {
\r
987 browser.page().triggerAction(WebAction.Undo);
\r
988 browser.setFocus();
\r
991 // Listener for when BOLD is clicked
\r
992 @SuppressWarnings("unused")
\r
993 private void redoClicked() {
\r
994 browser.page().triggerAction(WebAction.Redo);
\r
995 browser.setFocus();
\r
998 // Listener for when BOLD is clicked
\r
999 @SuppressWarnings("unused")
\r
1000 private void boldClicked() {
\r
1001 browser.page().triggerAction(WebAction.ToggleBold);
\r
1002 microFocusChanged();
\r
1003 browser.setFocus();
\r
1006 // Listener for when Italics is clicked
\r
1007 @SuppressWarnings("unused")
\r
1008 private void italicClicked() {
\r
1009 browser.page().triggerAction(WebAction.ToggleItalic);
\r
1010 microFocusChanged();
\r
1011 browser.setFocus();
\r
1014 // Listener for when UNDERLINE is clicked
\r
1015 @SuppressWarnings("unused")
\r
1016 private void underlineClicked() {
\r
1017 browser.page().triggerAction(WebAction.ToggleUnderline);
\r
1018 microFocusChanged();
\r
1019 browser.setFocus();
\r
1022 // Listener for when Strikethrough is clicked
\r
1023 @SuppressWarnings("unused")
\r
1024 private void strikethroughClicked() {
\r
1025 browser.page().mainFrame().evaluateJavaScript(
\r
1026 "document.execCommand('strikeThrough', false, '');");
\r
1027 browser.setFocus();
\r
1030 // Listener for when cut is clicked
\r
1031 @SuppressWarnings("unused")
\r
1032 private void cutClicked() {
\r
1033 browser.page().triggerAction(WebAction.Cut);
\r
1034 browser.setFocus();
\r
1037 // Listener when COPY is clicked
\r
1038 @SuppressWarnings("unused")
\r
1039 private void copyClicked() {
\r
1040 browser.page().triggerAction(WebAction.Copy);
\r
1041 browser.setFocus();
\r
1044 // Listener when PASTE is clicked
\r
1045 public void pasteClicked() {
\r
1046 logger.log(logger.EXTREME, "Paste Clicked");
\r
1047 if (forceTextPaste) {
\r
1048 pasteWithoutFormattingClicked();
\r
1051 QClipboard clipboard = QApplication.clipboard();
\r
1052 QMimeData mime = clipboard.mimeData();
\r
1054 // String x = mime.html();
\r
1056 if (mime.hasImage()) {
\r
1057 logger.log(logger.EXTREME, "Image paste found");
\r
1058 browser.setFocus();
\r
1059 insertImage(mime);
\r
1060 browser.setFocus();
\r
1064 if (mime.hasUrls()) {
\r
1065 logger.log(logger.EXTREME, "URL paste found");
\r
1066 if (!mime.text().startsWith("evernote:")) {
\r
1067 handleNoteLink(mime);
\r
1070 browser.setFocus();
\r
1075 String text = mime.html();
\r
1076 if (text.contains("en-tag") && mime.hasHtml()) {
\r
1077 logger.log(logger.EXTREME, "Intra-note paste found");
\r
1078 text = fixInternotePaste(text);
\r
1079 mime.setHtml(text);
\r
1080 clipboard.setMimeData(mime);
\r
1083 logger.log(logger.EXTREME, "Final paste choice encountered");
\r
1084 browser.page().triggerAction(WebAction.Paste);
\r
1085 browser.setFocus();
\r
1089 // Paste text without formatting
\r
1090 private void pasteWithoutFormattingClicked() {
\r
1091 logger.log(logger.EXTREME, "Paste without format clipped");
\r
1092 QClipboard clipboard = QApplication.clipboard();
\r
1093 QMimeData mime = clipboard.mimeData();
\r
1094 if (!mime.hasText())
\r
1096 String text = mime.text();
\r
1097 clipboard.clear();
\r
1098 clipboard.setText(text, Mode.Clipboard);
\r
1099 browser.page().triggerAction(WebAction.Paste);
\r
1101 // This is done because pasting into an encryption block
\r
1102 // can cause multiple cells (which can't happen). It
\r
1103 // just goes through the table, extracts the data, &
\r
1104 // puts it back as one table cell.
\r
1105 if (insideEncryption) {
\r
1106 String js = new String( "function fixEncryption() { "
\r
1107 +" var selObj = window.getSelection();"
\r
1108 +" var selRange = selObj.getRangeAt(0);"
\r
1109 +" var workingNode = window.getSelection().anchorNode;"
\r
1110 +" while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { "
\r
1111 +" workingNode = workingNode.parentNode;"
\r
1113 +" workingNode.innerHTML = window.jambi.fixEncryptionPaste(workingNode.innerHTML);"
\r
1114 +"} fixEncryption();");
\r
1115 browser.page().mainFrame().evaluateJavaScript(js);
\r
1119 // This basically removes all the table tags and returns just the contents.
\r
1120 // This is called by JavaScript to fix encryption pastes.
\r
1121 public String fixEncryptionPaste(String data) {
\r
1122 data = data.replace("<tbody>", "");
\r
1123 data = data.replace("</tbody>", "");
\r
1124 data = data.replace("<tr>", "");
\r
1125 data = data.replace("</tr>", "");
\r
1126 data = data.replace("<td>", "");
\r
1127 data = data.replace("</td>", "<br>");
\r
1128 data = data.replace("<br><br>", "<br>");
\r
1130 return "<tbody><tr><td>"+data+"</td></tr></tbody>";
\r
1133 // insert date/time
\r
1134 @SuppressWarnings("unused")
\r
1135 private void insertDateTime() {
\r
1136 String fmt = Global.getDateFormat() + " " + Global.getTimeFormat();
\r
1137 String dateTimeFormat = new String(fmt);
\r
1138 SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);
\r
1139 Calendar cal = Calendar.getInstance();
\r
1141 browser.page().mainFrame().evaluateJavaScript(
\r
1142 "document.execCommand('insertHtml', false, '"+simple.format(cal.getTime())+"');");
\r
1144 browser.setFocus();
\r
1148 // Listener when Left is clicked
\r
1149 @SuppressWarnings("unused")
\r
1150 private void justifyLeftClicked() {
\r
1151 browser.page().mainFrame().evaluateJavaScript(
\r
1152 "document.execCommand('JustifyLeft', false, '');");
\r
1153 browser.setFocus();
\r
1156 // Listener when Center is clicked
\r
1157 @SuppressWarnings("unused")
\r
1158 private void justifyCenterClicked() {
\r
1159 browser.page().mainFrame().evaluateJavaScript(
\r
1160 "document.execCommand('JustifyCenter', false, '');");
\r
1161 browser.setFocus();
\r
1164 // Listener when Left is clicked
\r
1165 @SuppressWarnings("unused")
\r
1166 private void justifyRightClicked() {
\r
1167 browser.page().mainFrame().evaluateJavaScript(
\r
1168 "document.execCommand('JustifyRight', false, '');");
\r
1169 browser.setFocus();
\r
1172 // Listener when HLINE is clicked
\r
1173 @SuppressWarnings("unused")
\r
1174 private void hlineClicked() {
\r
1175 browser.page().mainFrame().evaluateJavaScript(
\r
1176 "document.execCommand('insertHorizontalRule', false, '');");
\r
1177 browser.setFocus();
\r
1180 // Listener when outdent is clicked
\r
1181 private void outdentClicked() {
\r
1182 browser.page().mainFrame().evaluateJavaScript(
\r
1183 "document.execCommand('outdent', false, '');");
\r
1184 browser.setFocus();
\r
1187 // Listener when a bullet list is clicked
\r
1188 @SuppressWarnings("unused")
\r
1189 private void bulletListClicked() {
\r
1190 browser.page().mainFrame().evaluateJavaScript(
\r
1191 "document.execCommand('InsertUnorderedList', false, '');");
\r
1192 browser.setFocus();
\r
1195 // Listener when a bullet list is clicked
\r
1196 @SuppressWarnings("unused")
\r
1197 private void numberListClicked() {
\r
1198 browser.page().mainFrame().evaluateJavaScript(
\r
1199 "document.execCommand('InsertOrderedList', false, '');");
\r
1200 browser.setFocus();
\r
1203 // Listener when indent is clicked
\r
1204 private void indentClicked() {
\r
1205 browser.page().mainFrame().evaluateJavaScript(
\r
1206 "document.execCommand('indent', false, '');");
\r
1207 browser.setFocus();
\r
1210 // Listener when the font name is changed
\r
1211 @SuppressWarnings("unused")
\r
1212 private void fontChanged(String font) {
\r
1213 browser.page().mainFrame().evaluateJavaScript(
\r
1214 "document.execCommand('fontName',false,'" + font + "');");
\r
1215 browser.setFocus();
\r
1218 // Listener when a font size is changed
\r
1219 @SuppressWarnings("unused")
\r
1220 private void fontSizeChanged(String font) {
\r
1221 String text = browser.selectedText();
\r
1222 if (text.trim().equalsIgnoreCase(""))
\r
1225 String selectedText = browser.selectedText();
\r
1226 String url = "<span style=\"font-size:" +font +"pt; \">"+selectedText +"</a>";
\r
1227 String script = "document.execCommand('insertHtml', false, '"+url+"');";
\r
1228 browser.page().mainFrame().evaluateJavaScript(script);
\r
1229 /* browser.page().mainFrame().evaluateJavaScript(
\r
1230 "document.execCommand('fontSize',false,'"
\r
1233 browser.setFocus();
\r
1236 // Load the font combo box based upon the font selected
\r
1237 private void loadFontSize(String name) {
\r
1238 QFontDatabase db = new QFontDatabase();
\r
1240 List<Integer> points = db.pointSizes(name);
\r
1241 for (int i=0; i<points.size(); i++) {
\r
1242 fontSize.addItem(points.get(i).toString());
\r
1245 fontSize.addItem("x-small");
\r
1246 fontSize.addItem("small");
\r
1247 fontSize.addItem("medium");
\r
1248 fontSize.addItem("large");
\r
1249 fontSize.addItem("x-large");
\r
1250 fontSize.addItem("xx-large");
\r
1251 fontSize.addItem("xxx-large");
\r
1255 // Listener when a font size is changed
\r
1256 @SuppressWarnings("unused")
\r
1257 private void fontColorClicked() {
\r
1258 // QColorDialog dialog = new QColorDialog();
\r
1259 // QColor color = QColorDialog.getColor();
\r
1260 QColor color = fontColorMenu.getColor();
\r
1261 if (color.isValid())
\r
1262 browser.page().mainFrame().evaluateJavaScript(
\r
1263 "document.execCommand('foreColor',false,'" + color.name()
\r
1265 browser.setFocus();
\r
1268 // Listener for when a background color change is requested
\r
1269 @SuppressWarnings("unused")
\r
1270 private void fontHilightClicked() {
\r
1271 // QColorDialog dialog = new QColorDialog();
\r
1272 // QColor color = QColorDialog.getColor();
\r
1273 QColor color = fontHilightColorMenu.getColor();
\r
1274 if (color.isValid())
\r
1275 browser.page().mainFrame().evaluateJavaScript(
\r
1276 "document.execCommand('backColor',false,'" + color.name()
\r
1278 browser.setFocus();
\r
1281 // Listener for when a background color change is requested
\r
1282 @SuppressWarnings("unused")
\r
1283 private void superscriptClicked() {
\r
1284 browser.page().mainFrame().evaluateJavaScript(
\r
1285 "document.execCommand('superscript');");
\r
1286 browser.setFocus();
\r
1289 // Listener for when a background color change is requested
\r
1290 @SuppressWarnings("unused")
\r
1291 private void subscriptClicked() {
\r
1292 browser.page().mainFrame().evaluateJavaScript(
\r
1293 "document.execCommand('subscript');");
\r
1294 browser.setFocus();
\r
1296 // Insert a to-do checkbox
\r
1297 @SuppressWarnings("unused")
\r
1298 private void todoClicked() {
\r
1299 FileNameMap fileNameMap = URLConnection.getFileNameMap();
\r
1300 String script_start = new String(
\r
1301 "document.execCommand('insertHtml', false, '");
\r
1302 String script_end = new String("');");
\r
1303 String todo = new String(
\r
1304 "<input TYPE=\"CHECKBOX\" value=\"false\" " +
\r
1305 "onMouseOver=\"style.cursor=\\'hand\\'\" " +
\r
1306 "onClick=\"value=checked; window.jambi.contentChanged(); \" />");
\r
1307 browser.page().mainFrame().evaluateJavaScript(
\r
1308 script_start + todo + script_end);
\r
1309 browser.setFocus();
\r
1312 // Encrypt the selected text
\r
1313 @SuppressWarnings("unused")
\r
1314 private void encryptText() {
\r
1315 String text = browser.selectedText();
\r
1316 if (text.trim().equalsIgnoreCase(""))
\r
1318 text = new String(text.replaceAll("\n", "<br/>"));
\r
1320 EnCryptDialog dialog = new EnCryptDialog();
\r
1322 if (!dialog.okPressed()) {
\r
1326 EnCrypt crypt = new EnCrypt();
\r
1327 String encrypted = crypt.encrypt(text, dialog.getPassword().trim(), 64);
\r
1328 String decrypted = crypt.decrypt(encrypted, dialog.getPassword().trim(), 64);
\r
1330 if (encrypted.trim().equals("")) {
\r
1331 QMessageBox.information(this, tr("Error"), tr("Error Encrypting String"));
\r
1334 StringBuffer buffer = new StringBuffer(encrypted.length() + 100);
\r
1335 buffer.append("<img en-tag=\"en-crypt\" cipher=\"RC2\" hint=\""
\r
1336 + dialog.getHint().replace("'","\\'") + "\" length=\"64\" ");
\r
1337 buffer.append("contentEditable=\"false\" alt=\"");
\r
1338 buffer.append(encrypted);
\r
1339 buffer.append("\" src=\"").append(FileUtils.toForwardSlashedPath(Global.getFileManager().getImageDirPath("encrypt.png") +"\""));
\r
1340 Global.cryptCounter++;
\r
1341 buffer.append(" id=\"crypt"+Global.cryptCounter.toString() +"\"");
\r
1342 buffer.append(" onMouseOver=\"style.cursor=\\'hand\\'\"");
\r
1343 buffer.append(" onClick=\"window.jambi.decryptText(\\'crypt"+Global.cryptCounter.toString()
\r
1344 +"\\', \\'"+encrypted+"\\', \\'"+dialog.getHint().replace("'", "\\&apos;")+"\\');\"");
\r
1345 buffer.append("style=\"display:block\" />");
\r
1347 String script_start = new String(
\r
1348 "document.execCommand('insertHtml', false, '");
\r
1349 String script_end = new String("');");
\r
1350 browser.page().mainFrame().evaluateJavaScript(
\r
1351 script_start + buffer.toString() + script_end);
\r
1355 // Insert a hyperlink
\r
1356 public void insertLink() {
\r
1357 logger.log(logger.EXTREME, "Inserting link");
\r
1358 String text = browser.selectedText();
\r
1359 if (text.trim().equalsIgnoreCase(""))
\r
1362 InsertLinkDialog dialog = new InsertLinkDialog(insertHyperlink);
\r
1363 if (currentHyperlink != null && currentHyperlink != "") {
\r
1364 dialog.setUrl(currentHyperlink);
\r
1367 if (!dialog.okPressed()) {
\r
1368 logger.log(logger.EXTREME, "Insert link canceled");
\r
1372 // Take care of inserting new links
\r
1373 if (insertHyperlink) {
\r
1374 String selectedText = browser.selectedText();
\r
1375 if (dialog.getUrl().trim().equals(""))
\r
1377 logger.log(logger.EXTREME, "Inserting link on text "+selectedText);
\r
1378 logger.log(logger.EXTREME, "URL Link " +dialog.getUrl().trim());
\r
1379 String dUrl = StringUtils.replace(dialog.getUrl().trim(), "'", "\\'");
\r
1380 String url = "<a href=\"" +dUrl
\r
1381 +"\" title=" +dUrl
\r
1382 +" >"+selectedText +"</a>";
\r
1383 String script = "document.execCommand('insertHtml', false, '"+url+"');";
\r
1384 browser.page().mainFrame().evaluateJavaScript(script);
\r
1388 // Edit existing links
\r
1389 String js = new String( "function getCursorPos() {"
\r
1391 +"if (window.getSelection) {"
\r
1392 +" var selObj = window.getSelection();"
\r
1393 +" var selRange = selObj.getRangeAt(0);"
\r
1394 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
1395 +" while(workingNode != null) { "
\r
1396 +" if (workingNode.nodeName.toLowerCase()=='a') workingNode.setAttribute('href','" +dialog.getUrl() +"');"
\r
1397 +" workingNode = workingNode.parentNode;"
\r
1400 +"} getCursorPos();");
\r
1401 browser.page().mainFrame().evaluateJavaScript(js);
\r
1403 if (!dialog.getUrl().trim().equals("")) {
\r
1409 js = new String( "function getCursorPos() {"
\r
1411 +"if (window.getSelection) {"
\r
1412 +" var selObj = window.getSelection();"
\r
1413 +" var selRange = selObj.getRangeAt(0);"
\r
1414 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
1415 +" while(workingNode != null) { "
\r
1416 +" if (workingNode.nodeName.toLowerCase()=='a') { "
\r
1417 +" workingNode.removeAttribute('href');"
\r
1418 +" workingNode.removeAttribute('title');"
\r
1419 +" var text = document.createTextNode(workingNode.innerText);"
\r
1420 +" workingNode.parentNode.insertBefore(text, workingNode);"
\r
1421 +" workingNode.parentNode.removeChild(workingNode);"
\r
1423 +" workingNode = workingNode.parentNode;"
\r
1426 +"} getCursorPos();");
\r
1427 browser.page().mainFrame().evaluateJavaScript(js);
\r
1435 // Insert a hyperlink
\r
1436 public void insertLatex() {
\r
1439 public void editLatex(String guid) {
\r
1440 logger.log(logger.EXTREME, "Inserting latex");
\r
1441 String text = browser.selectedText();
\r
1442 if (text.trim().equalsIgnoreCase("")) {
\r
1443 InsertLatexImage dialog = new InsertLatexImage();
\r
1444 if (guid != null) {
\r
1445 String formula = conn.getNoteTable().noteResourceTable.getNoteSourceUrl(guid).replace("http://latex.codecogs.com/gif.latex?", "");
\r
1446 dialog.setFormula(formula);
\r
1449 if (!dialog.okPressed()) {
\r
1450 logger.log(logger.EXTREME, "Edit LaTex canceled");
\r
1453 text = dialog.getFormula().trim();
\r
1455 blockApplication.emit(this);
\r
1456 logger.log(logger.EXTREME, "Inserting LaTeX formula:" +text);
\r
1458 text = StringUtils.replace(text, "'", "\\'");
\r
1459 String url = "http://latex.codecogs.com/gif.latex?" +text;
\r
1460 logger.log(logger.EXTREME, "Sending request to codecogs --> " + url);
\r
1461 QNetworkAccessManager manager = new QNetworkAccessManager(this);
\r
1462 manager.finished.connect(this, "insertLatexImageReady(QNetworkReply)");
\r
1463 unblockTime = new GregorianCalendar().getTimeInMillis()+5000;
\r
1464 awaitingHttpResponse = true;
\r
1465 manager.get(new QNetworkRequest(new QUrl(url)));
\r
1468 public void insertLatexImageReady(QNetworkReply reply) {
\r
1469 logger.log(logger.EXTREME, "Response received from CodeCogs");
\r
1470 if (reply.error() != NetworkError.NoError)
\r
1474 if (!awaitingHttpResponse)
\r
1477 awaitingHttpResponse = false;
\r
1478 QUrl replyUrl = reply.url();
\r
1479 QByteArray image = reply.readAll();
\r
1481 logger.log(logger.EXTREME, "New image size: " +image.size());
\r
1483 Resource newRes = null;
\r
1486 if (latexGuid == null) {
\r
1487 logger.log(logger.EXTREME, "Creating temporary gif");
\r
1488 path = Global.getFileManager().getResDirPath("latex-temp.gif");
\r
1489 tfile = new QFile(path);
\r
1490 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
\r
1491 logger.log(logger.EXTREME, "File Open: " +tfile.errorString());
\r
1492 tfile.write(image);
\r
1493 logger.log(logger.EXTREME, "Bytes writtes: "+tfile.size());
\r
1495 logger.log(logger.EXTREME, "Creating resource");
\r
1497 if (currentNote.getResources() != null || currentNote.getResources().size() > 0)
\r
1498 sequence = currentNote.getResources().size();
\r
1499 newRes = createResource(path,sequence ,"image/gif", false);
\r
1500 QImage pix = new QImage();
\r
1501 pix.loadFromData(image);
\r
1502 newRes.setHeight(new Integer(pix.height()).shortValue());
\r
1503 newRes.setWidth(new Integer(pix.width()).shortValue());
\r
1504 logger.log(logger.EXTREME, "Renaming temporary file to " +newRes.getGuid()+".gif");
\r
1505 path = Global.getFileManager().getResDirPath(newRes.getGuid()+".gif");
\r
1506 tfile.rename(path);
\r
1508 newRes = conn.getNoteTable().noteResourceTable.getNoteResource(latexGuid, false);
\r
1509 path = Global.getFileManager().getResDirPath(newRes.getGuid()+".gif");
\r
1510 tfile = new QFile(path);
\r
1511 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
\r
1512 tfile.write(image);
\r
1514 newRes.getData().setBody(image.toByteArray());
\r
1515 // Calculate the new hash value
\r
1518 logger.log(logger.EXTREME, "Generating MD5");
\r
1520 md = MessageDigest.getInstance("MD5");
\r
1521 md.update(image.toByteArray());
\r
1522 byte[] hash = md.digest();
\r
1523 newRes.getData().setBodyHash(hash);
\r
1524 } catch (NoSuchAlgorithmException e) {
\r
1525 e.printStackTrace();
\r
1527 QImage pix = new QImage();
\r
1528 pix.loadFromData(image);
\r
1529 newRes.setHeight(new Integer(pix.height()).shortValue());
\r
1530 newRes.setWidth(new Integer(pix.width()).shortValue());
\r
1531 conn.getNoteTable().noteResourceTable.updateNoteResource(newRes, true);
\r
1534 logger.log(logger.EXTREME, "Setting source: " +replyUrl.toString());
\r
1535 newRes.getAttributes().setSourceURL(replyUrl.toString());
\r
1536 conn.getNoteTable().noteResourceTable.updateNoteSourceUrl(newRes.getGuid(), replyUrl.toString(), true);
\r
1538 for(int i=0; i<currentNote.getResourcesSize(); i++) {
\r
1539 if (currentNote.getResources().get(i).getGuid().equals(newRes.getGuid())) {
\r
1540 currentNote.getResources().remove(i);
\r
1541 i=currentNote.getResourcesSize();
\r
1544 currentNote.getResources().add(newRes);
\r
1547 // do the actual insert into the note. We only do this on new formulas.
\r
1548 if (latexGuid == null) {
\r
1549 StringBuffer buffer = new StringBuffer(100);
\r
1550 String formula = replyUrl.toString().toLowerCase().replace("http://latex.codecogs.com/gif.latex?", "");
\r
1551 buffer.append("<a href=\"latex://"+path.replace("\\", "/")+"\" title=\""+formula+"\""
\r
1553 buffer.append(path.replace("\\", "/"));
\r
1554 buffer.append("\" en-tag=\"en-latex\" type=\"image/gif\""
\r
1555 +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""
\r
1556 +" guid=\"" +newRes.getGuid() +"\""
\r
1559 String script_start = new String("document.execCommand('insertHTML', false, '");
\r
1560 String script_end = new String("');");
\r
1561 browser.page().mainFrame().evaluateJavaScript(
\r
1562 script_start + buffer + script_end);
\r
1564 HtmlTagModifier modifier = new HtmlTagModifier(getContent());
\r
1565 modifier.modifyLatexTagHash(newRes);
\r
1566 String newContent = modifier.getHtml();
\r
1567 browser.setContent(new QByteArray(newContent));
\r
1570 logger.log(logger.EXTREME, "New HTML set\n" +browser.page().currentFrame().toHtml());
\r
1571 QWebSettings.setMaximumPagesInCache(0);
\r
1572 QWebSettings.setObjectCacheCapacities(0, 0, 0);
\r
1574 browser.page().mainFrame().setHtml(browser.page().mainFrame().toHtml());
\r
1577 // resourceSignal.contentChanged.emit(path);
\r
1579 unblockApplication.emit();
\r
1587 public void insertTable() {
\r
1588 TableDialog dialog = new TableDialog();
\r
1590 if (!dialog.okPressed()) {
\r
1594 int cols = dialog.getCols();
\r
1595 int rows = dialog.getRows();
\r
1596 int width = dialog.getWidth();
\r
1597 boolean percent = dialog.isPercent();
\r
1599 String newHTML = "<table border=\"1\" width=\"" +new Integer(width).toString();
\r
1601 newHTML = newHTML +"%";
\r
1602 newHTML = newHTML + "\"><tbody>";
\r
1604 for (int i=0; i<rows; i++) {
\r
1605 newHTML = newHTML +"<tr>";
\r
1606 for (int j=0; j<cols; j++) {
\r
1607 newHTML = newHTML +"<td> </td>";
\r
1609 newHTML = newHTML +"</tr>";
\r
1611 newHTML = newHTML+"</tbody></table>";
\r
1613 String script = "document.execCommand('insertHtml', false, '"+newHTML+"');";
\r
1614 browser.page().mainFrame().evaluateJavaScript(script);
\r
1618 // Text content changed
\r
1619 @SuppressWarnings("unused")
\r
1620 private void selectionChanged() {
\r
1621 browser.encryptAction.setEnabled(true);
\r
1622 browser.insertLinkAction.setEnabled(true);
\r
1623 String scriptStart = "var selection_text = (window.getSelection()).toString();"
\r
1624 + "var range = (window.getSelection()).getRangeAt(0);"
\r
1625 + "var parent_html = range.commonAncestorContainer.innerHTML;"
\r
1626 + "if (parent_html == undefined) {window.jambi.saveSelectedText(selection_text); return;}"
\r
1627 + "var first_text = range.startContainer.nodeValue.substr(range.startOffset);"
\r
1628 + "var last_text = (range.endContainer.nodeValue).substring(0,range.endOffset);"
\r
1629 + "var start = parent_html.indexOf(first_text);"
\r
1630 + "var end = parent_html.indexOf(last_text,start+1)+last_text.length;"
\r
1631 + "var value = parent_html.substring(start,end);"
\r
1632 + "window.jambi.saveSelectedText(value);" ;
\r
1633 browser.page().mainFrame().evaluateJavaScript(scriptStart);
\r
1637 public void saveSelectedText(String text) {
\r
1638 boolean enabled = true;
\r
1639 if (text.trim().length() == 0)
\r
1641 if (text.indexOf("en-tag=\"en-crypt\"") >= 0)
\r
1643 if (text.indexOf("<img en-tag=\"en-media\"") >= 0)
\r
1645 if (text.indexOf("<a en-tag=\"en-media\"") >= 0)
\r
1647 if (text.indexOf("<input ") >= 0)
\r
1650 browser.encryptAction.setEnabled(enabled);
\r
1651 browser.insertLinkAction.setEnabled(enabled);
\r
1652 // selectedText = text;
\r
1655 // Decrypt clicked text
\r
1656 public void decryptText(String id, String text, String hint) {
\r
1657 EnCrypt crypt = new EnCrypt();
\r
1658 String plainText = null;
\r
1659 Calendar currentTime = new GregorianCalendar();
\r
1660 Long l = new Long(currentTime.getTimeInMillis());
\r
1661 String slot = new String(Long.toString(l));
\r
1663 // First, try to decrypt with any keys we already have
\r
1664 for (int i=0; i<Global.passwordRemember.size(); i++) {
\r
1665 plainText = crypt.decrypt(text, Global.passwordRemember.get(i).getFirst(), 64);
\r
1666 if (plainText != null) {
\r
1667 slot = new String(Long.toString(l));
\r
1668 Global.passwordSafe.put(slot, Global.passwordRemember.get(i));
\r
1669 removeEncryption(id, plainText, false, slot);
\r
1675 EnDecryptDialog dialog = new EnDecryptDialog();
\r
1676 dialog.setHint(hint);
\r
1677 while (plainText == null || !dialog.okPressed()) {
\r
1679 if (!dialog.okPressed()) {
\r
1682 plainText = crypt.decrypt(text, dialog.getPassword().trim(), 64);
\r
1683 if (plainText == null) {
\r
1684 QMessageBox.warning(this, tr("Incorrect Password"), tr("The password entered is not correct"));
\r
1687 Pair<String,String> passwordPair = new Pair<String,String>();
\r
1688 passwordPair.setFirst(dialog.getPassword());
\r
1689 passwordPair.setSecond(dialog.getHint());
\r
1690 Global.passwordSafe.put(slot, passwordPair);
\r
1691 // removeEncryption(id, plainText.replaceAll("\n", "<br/>"), dialog.permanentlyDecrypt(), slot);
\r
1692 removeEncryption(id, plainText, dialog.permanentlyDecrypt(), slot);
\r
1693 if (dialog.rememberPassword()) {
\r
1694 Pair<String, String> pair = new Pair<String,String>();
\r
1695 pair.setFirst(dialog.getPassword());
\r
1696 pair.setSecond(dialog.getHint());
\r
1697 Global.passwordRemember.add(pair);
\r
1702 // Get the editor tag line
\r
1703 public TagLineEdit getTagLine() {
\r
1707 // Modify a note's tags
\r
1708 @SuppressWarnings("unused")
\r
1709 private void modifyTags() {
\r
1710 TagAssign tagWindow = new TagAssign(allTags, currentTags, !conn.getNotebookTable().isLinked(currentNote.getNotebookGuid()));
\r
1712 if (tagWindow.okClicked()) {
\r
1713 currentTags.clear();
\r
1714 StringBuffer tagDisplay = new StringBuffer();
\r
1716 List<QListWidgetItem> newTags = tagWindow.getTagList()
\r
1718 for (int i = 0; i < newTags.size(); i++) {
\r
1719 currentTags.add(newTags.get(i).text());
\r
1720 tagDisplay.append(newTags.get(i).text());
\r
1721 if (i < newTags.size() - 1) {
\r
1722 tagDisplay.append(Global.tagDelimeter + " ");
\r
1725 tagEdit.setText(tagDisplay.toString());
\r
1726 noteSignal.tagsChanged.emit(currentNote.getGuid(), currentTags);
\r
1730 // Tag line has been modified by typing text
\r
1731 @SuppressWarnings("unused")
\r
1732 private void modifyTagsTyping() {
\r
1733 String completionText = "";
\r
1734 if (tagEdit.currentCompleterSelection != null && !tagEdit.currentCompleterSelection.equals("")) {
\r
1735 completionText = tagEdit.currentCompleterSelection;
\r
1736 tagEdit.currentCompleterSelection = "";
\r
1739 if (tagEdit.text().equalsIgnoreCase(saveTagList))
\r
1742 // We know something has changed...
\r
1743 String oldTagArray[] = saveTagList.split(Global.tagDelimeter);
\r
1744 String newTagArray[];
\r
1745 if (!completionText.equals("")) {
\r
1746 String before = tagEdit.text().substring(0,tagEdit.cursorPosition());
\r
1747 int lastDelimiter = before.lastIndexOf(Global.tagDelimeter);
\r
1748 if (lastDelimiter > 0)
\r
1749 before = before.substring(0,before.lastIndexOf(Global.tagDelimeter));
\r
1752 String after = tagEdit.text().substring(tagEdit.cursorPosition());
\r
1753 newTagArray = (before+Global.tagDelimeter+completionText+Global.tagDelimeter+after).split(Global.tagDelimeter);
\r
1756 newTagArray = tagEdit.text().split(Global.tagDelimeter);
\r
1759 // Remove any traling or leading blanks
\r
1760 for (int i=0; i<newTagArray.length; i++)
\r
1761 newTagArray[i] = newTagArray[i].trim().replaceAll("^\\s+", "");;
\r
1763 // Remove any potential duplicates from the new list
\r
1764 for (int i=0; i<newTagArray.length; i++) {
\r
1765 boolean foundOnce = false;
\r
1766 for (int j=0; j<newTagArray.length; j++) {
\r
1767 if (newTagArray[j].equalsIgnoreCase(newTagArray[i])) {
\r
1771 newTagArray[j] = "";
\r
1776 List<String> newTagList = new ArrayList<String>();
\r
1777 List<String> oldTagList = new ArrayList<String>();
\r
1779 for (int i = 0; i < oldTagArray.length; i++)
\r
1780 if (!oldTagArray[i].trim().equals(""))
\r
1781 oldTagList.add(oldTagArray[i]);
\r
1782 for (int i = 0; i < newTagArray.length; i++)
\r
1783 if (!newTagArray[i].trim().equals(""))
\r
1784 newTagList.add(newTagArray[i]);
\r
1786 if (conn.getNotebookTable().isLinked(currentNote.getNotebookGuid())) {
\r
1787 for (int i=newTagList.size()-1; i>=0; i--) {
\r
1788 boolean found = false;
\r
1789 for (int j=0; j<allTags.size(); j++) {
\r
1790 if (allTags.get(j).getName().equalsIgnoreCase(newTagList.get(i))) {
\r
1796 newTagList.remove(i);
\r
1800 // Let's cleanup the appearance of the tag list
\r
1801 Collections.sort(newTagList);
\r
1802 String newDisplay = "";
\r
1803 for (int i=0; i<newTagList.size(); i++) {
\r
1804 newDisplay = newDisplay+newTagList.get(i);
\r
1805 if (i<newTagList.size()-1)
\r
1806 newDisplay = newDisplay+Global.tagDelimeter +" ";
\r
1808 tagEdit.blockSignals(true);
\r
1809 tagEdit.setText(newDisplay);
\r
1810 tagEdit.blockSignals(false);
\r
1812 // We now have lists of the new & old. Remove duplicates. If all
\r
1813 // are removed from both then nothing has really changed
\r
1814 for (int i = newTagList.size() - 1; i >= 0; i--) {
\r
1815 String nTag = newTagList.get(i);
\r
1816 for (int j = oldTagList.size() - 1; j >= 0; j--) {
\r
1817 String oTag = oldTagList.get(j);
\r
1818 if (oTag.equalsIgnoreCase(nTag)) {
\r
1819 oldTagList.remove(j);
\r
1820 newTagList.remove(i);
\r
1826 if (oldTagList.size() != 0 || newTagList.size() != 0) {
\r
1827 currentTags.clear();
\r
1828 newTagArray = tagEdit.text().split(Global.tagDelimeter);
\r
1829 for (int i = 0; i < newTagArray.length; i++)
\r
1830 if (!newTagArray[i].trim().equals(""))
\r
1831 currentTags.add(newTagArray[i].trim());
\r
1833 noteSignal.tagsChanged.emit(currentNote.getGuid(), currentTags);
\r
1838 // Tab button was pressed
\r
1839 public void tabPressed() {
\r
1840 if (insideEncryption)
\r
1842 if (!insideList && !insideTable) {
\r
1843 String script_start = new String(
\r
1844 "document.execCommand('insertHtml', false, ' ');");
\r
1845 browser.page().mainFrame().evaluateJavaScript(script_start);
\r
1851 if (insideTable) {
\r
1852 String js = new String( "function getCursorPosition() { "
\r
1853 +" var selObj = window.getSelection();"
\r
1854 +" var selRange = selObj.getRangeAt(0);"
\r
1855 +" var workingNode = window.getSelection().anchorNode;"
\r
1856 +" var rowCount = 0;"
\r
1857 +" var colCount = 0;"
\r
1858 +" while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { "
\r
1859 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
\r
1860 +" rowCount = rowCount+1;"
\r
1862 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
\r
1863 +" colCount = colCount+1;"
\r
1865 +" if (workingNode.previousSibling != null)"
\r
1866 +" workingNode = workingNode.previousSibling;"
\r
1868 +" workingNode = workingNode.parentNode;"
\r
1870 +" var nodes = workingNode.getElementsByTagName('tr');"
\r
1871 +" var tableRows = nodes.length;"
\r
1872 +" nodes = nodes[0].getElementsByTagName('td');"
\r
1873 +" var tableColumns = nodes.length;"
\r
1874 +" window.jambi.setTableCursorPositionTab(rowCount, colCount, tableRows, tableColumns);"
\r
1875 +"} getCursorPosition();");
\r
1876 browser.page().mainFrame().evaluateJavaScript(js);
\r
1880 // If a user presses tab from within a table
\r
1881 public void setTableCursorPositionTab(int currentRow, int currentCol, int tableRows, int tableColumns) {
\r
1882 if (tableRows == currentRow && currentCol == tableColumns) {
\r
1885 KeyboardModifiers modifiers = new KeyboardModifiers(KeyboardModifier.NoModifier);
\r
1886 QKeyEvent right = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Right.value(), modifiers);
\r
1887 QKeyEvent end = new QKeyEvent(Type.KeyPress, Qt.Key.Key_End.value(), modifiers);
\r
1888 QKeyEvent end2 = new QKeyEvent(Type.KeyPress, Qt.Key.Key_End.value(), modifiers);
\r
1889 getBrowser().focusWidget();
\r
1890 QCoreApplication.postEvent(getBrowser(), end);
\r
1891 QCoreApplication.postEvent(getBrowser(), right);
\r
1892 QCoreApplication.postEvent(getBrowser(), end2);
\r
1895 public void backtabPressed() {
\r
1896 if (insideEncryption)
\r
1900 if (insideTable) {
\r
1901 String js = new String( "function getCursorPosition() { "
\r
1902 +" var selObj = window.getSelection();"
\r
1903 +" var selRange = selObj.getRangeAt(0);"
\r
1904 +" var workingNode = window.getSelection().anchorNode;"
\r
1905 +" var rowCount = 0;"
\r
1906 +" var colCount = 0;"
\r
1907 +" while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { "
\r
1908 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
\r
1909 +" rowCount = rowCount+1;"
\r
1911 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
\r
1912 +" colCount = colCount+1;"
\r
1914 +" if (workingNode.previousSibling != null)"
\r
1915 +" workingNode = workingNode.previousSibling;"
\r
1917 +" workingNode = workingNode.parentNode;"
\r
1919 +" var nodes = workingNode.getElementsByTagName('tr');"
\r
1920 +" var tableRows = nodes.length;"
\r
1921 +" nodes = nodes[0].getElementsByTagName('td');"
\r
1922 +" var tableColumns = nodes.length;"
\r
1923 +" window.jambi.setTableCursorPositionBackTab(rowCount, colCount, tableRows, tableColumns);"
\r
1924 +"} getCursorPosition();");
\r
1925 browser.page().mainFrame().evaluateJavaScript(js);
\r
1930 // If a user presses backtab from within a table
\r
1931 public void setTableCursorPositionBackTab(int currentRow, int currentCol, int tableRows, int tableColumns) {
\r
1932 if (currentRow == 1 && currentCol == 1) {
\r
1935 KeyboardModifiers modifiers = new KeyboardModifiers(KeyboardModifier.NoModifier);
\r
1936 QKeyEvent left = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Left.value(), modifiers);
\r
1937 QKeyEvent home = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Home.value(), modifiers);
\r
1938 getBrowser().focusWidget();
\r
1939 QCoreApplication.postEvent(getBrowser(), home);
\r
1940 QCoreApplication.postEvent(getBrowser(), left);
\r
1944 public void setInsideList() {
\r
1945 insideList = true;
\r
1948 // The title has been edited
\r
1949 @SuppressWarnings("unused")
\r
1950 private void titleEdited() {
\r
1951 // If we don't have a good note, or if the current title
\r
1952 // matches the old title then we don't need to do anything
\r
1953 if (currentNote == null)
\r
1955 if (currentNote.getTitle().trim().equals(titleLabel.text().trim()))
\r
1958 // If we have a real change, we need to save it.
\r
1959 noteSignal.titleChanged.emit(currentNote.getGuid(), titleLabel.text());
\r
1960 currentNote.setTitle(titleLabel.text());
\r
1961 saveNoteTitle = titleLabel.text();
\r
1965 // Set the list of note tags
\r
1966 public void setAllTags(List<Tag> l) {
\r
1968 tagEdit.setTagList(l);
\r
1971 // Setter for the current tags
\r
1972 public void setCurrentTags(List<String> s) {
\r
1976 // Save the list of notebooks
\r
1977 public void setNotebookList(List<Notebook> n) {
\r
1979 loadNotebookList();
\r
1982 // Load the notebook list and select the current notebook
\r
1983 private void loadNotebookList() {
\r
1984 if (notebookBox.count() != 0)
\r
1985 notebookBox.clear();
\r
1986 if (notebookList == null)
\r
1989 for (int i = 0; i < notebookList.size(); i++) {
\r
1990 notebookBox.addItem(notebookList.get(i).getName());
\r
1991 if (currentNote != null) {
\r
1992 if (currentNote.getNotebookGuid().equals(
\r
1993 notebookList.get(i).getGuid())) {
\r
1994 notebookBox.setCurrentIndex(i);
\r
2001 // Set the notebook for a note
\r
2002 public void setNotebook(String notebook) {
\r
2003 currentNote.setNotebookGuid(notebook);
\r
2004 loadNotebookList();
\r
2007 // Get the contents of the editor
\r
2008 public String getContent() {
\r
2009 return browser.page().currentFrame().toHtml();
\r
2012 // The note contents have changed
\r
2013 public void contentChanged() {
\r
2014 String content = getContent();
\r
2016 noteSignal.noteChanged.emit(currentNote.getGuid(), content);
\r
2019 // The notebook selection has changed
\r
2020 @SuppressWarnings("unused")
\r
2021 private void notebookChanged() {
\r
2022 boolean changed = false;
\r
2023 String n = notebookBox.currentText();
\r
2024 for (int i = 0; i < notebookList.size(); i++) {
\r
2025 if (n.equals(notebookList.get(i).getName())) {
\r
2026 if (!notebookList.get(i).getGuid().equals(currentNote.getNotebookGuid())) {
\r
2027 String guid = conn.getNotebookTable().findNotebookByName(n);
\r
2028 if (conn.getNotebookTable().isLinked(guid)) {
\r
2029 tagEdit.setText("");
\r
2030 noteSignal.tagsChanged.emit(currentNote.getGuid(), new ArrayList<String>());
\r
2031 FilterEditorTags t = new FilterEditorTags(conn, logger);
\r
2032 setAllTags(t.getValidTags(currentNote));
\r
2034 currentNote.setNotebookGuid(notebookList.get(i).getGuid());
\r
2037 i = notebookList.size();
\r
2041 // If the notebook changed, signal the update
\r
2043 noteSignal.notebookChanged.emit(currentNote.getGuid(), currentNote
\r
2044 .getNotebookGuid());
\r
2047 // Check the note title
\r
2048 private void checkNoteTitle() {
\r
2049 String text = browser.page().currentFrame().toPlainText();
\r
2050 if (saveNoteTitle.trim().equals("") || saveNoteTitle.trim().equals("Untitled Note")) {
\r
2051 int newLine = text.indexOf("\n");
\r
2052 if (newLine > 0) {
\r
2053 text = text.substring(0, newLine);
\r
2054 if (text.trim().equals(""))
\r
2055 text = tr("Untitled Note");
\r
2056 titleLabel.setText(text);
\r
2058 if (text.length() > Constants.EDAM_NOTE_TITLE_LEN_MAX)
\r
2059 titleLabel.setText(text.substring(0, Constants.EDAM_NOTE_TITLE_LEN_MAX));
\r
2061 titleLabel.blockSignals(true);
\r
2062 if (text.trim().equals(""))
\r
2063 titleLabel.setText(tr("Untitled Note"));
\r
2065 titleLabel.setText(text);
\r
2066 titleLabel.blockSignals(false);
\r
2069 noteSignal.titleChanged.emit(currentNote.getGuid(), titleLabel
\r
2074 // Return the note contents so we can email them
\r
2075 public String getContentsToEmail() {
\r
2076 return browser.page().currentFrame().toPlainText().trim();
\r
2078 * int body = browser.page().currentFrame().toHtml().indexOf("<body>");
\r
2079 * String temp = browser.page().currentFrame().toHtml(); if (body == -1)
\r
2080 * temp = "<html><body><b>Test</b></body></html>"; else temp =
\r
2081 * "<html>"+temp.substring(body); return temp; // return
\r
2082 * urlEncode(browser.page().currentFrame().toHtml());
\r
2086 // Insert an image into the editor
\r
2087 private void insertImage(QMimeData mime) {
\r
2088 logger.log(logger.EXTREME, "Entering insertImage");
\r
2089 QImage img = (QImage) mime.imageData();
\r
2090 String script_start = new String(
\r
2091 "document.execCommand('insertHTML', false, '");
\r
2092 String script_end = new String("');");
\r
2094 long now = new Date().getTime();
\r
2095 String path = Global.getFileManager().getResDirPath(
\r
2096 (new Long(now).toString()) + ".jpg");
\r
2098 // This block is just a hack to make sure we wait at least 1ms so we
\r
2100 // have collisions on image names
\r
2101 long i = new Date().getTime();
\r
2103 i = new Date().getTime();
\r
2105 // Open the file & write the data
\r
2106 QFile tfile = new QFile(path);
\r
2107 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
\r
2108 if (!img.save(tfile)) {
\r
2114 Resource newRes = createResource(QUrl.fromLocalFile(path).toString(), 0, "image/jpeg", false);
\r
2115 if (newRes == null)
\r
2117 currentNote.getResources().add(newRes);
\r
2119 // do the actual insert into the note
\r
2120 StringBuffer buffer = new StringBuffer(100);
\r
2121 buffer.append("<img src=\"");
\r
2122 buffer.append(tfile.fileName());
\r
2123 buffer.append("\" en-tag=en-media type=\"image/jpeg\""
\r
2124 +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""
\r
2125 +" guid=\"" +newRes.getGuid() +"\""
\r
2126 +" onContextMenu=\"window.jambi.imageContextMenu(&." +tfile.fileName() +"&.);\""
\r
2129 browser.page().mainFrame().evaluateJavaScript(
\r
2130 script_start + buffer + script_end);
\r
2135 // Handle pasting of a note-to-note link
\r
2136 private void handleNoteLink(QMimeData mime) {
\r
2137 for (int i=0; i<mime.urls().size(); i++) {
\r
2138 StringTokenizer tokens = new StringTokenizer(mime.urls().get(i).toString().replace("evernote:///view/", ""), "/");
\r
2139 tokens.nextToken();
\r
2140 tokens.nextToken();
\r
2141 String sid = tokens.nextToken();
\r
2142 String lid = tokens.nextToken();
\r
2144 if (!sid.equals(currentNote.getGuid()) && !lid.equals(currentNote.getGuid())) {
\r
2146 Note note = conn.getNoteTable().getNote(sid, false, false, false, false, false);
\r
2148 note = conn.getNoteTable().getNote(lid, false, false, false, false, false);
\r
2153 // If we've gotten this far, we have a bunch of values. We need to build the link.
\r
2154 StringBuffer url = new StringBuffer(100);
\r
2155 String script_start = new String(
\r
2156 "document.execCommand('insertHtml', false, '");
\r
2157 String script_end = new String("');");
\r
2159 url.append("<a href=\""+mime.urls().get(i).toString() +"\" style=\"color:#69aa35\">");
\r
2160 url.append(note.getTitle());
\r
2161 url.append("</a>");
\r
2162 if (mime.urls().size() > 1)
\r
2163 url.append(" ");
\r
2164 browser.page().mainFrame().evaluateJavaScript(
\r
2165 script_start + url + script_end);
\r
2170 // Handle URLs that are trying to be pasted
\r
2171 public void handleUrls(QMimeData mime) {
\r
2172 logger.log(logger.EXTREME, "Starting handleUrls");
\r
2173 FileNameMap fileNameMap = URLConnection.getFileNameMap();
\r
2175 List<QUrl> urlList = mime.urls();
\r
2176 String url = new String();
\r
2177 String script_start = new String(
\r
2178 "document.execCommand('createLink', false, '");
\r
2179 String script_end = new String("');");
\r
2181 for (int i = 0; i < urlList.size(); i++) {
\r
2182 url = urlList.get(i).toString();
\r
2183 // Find out what type of file we have
\r
2184 String mimeType = fileNameMap.getContentTypeFor(url);
\r
2186 // If null returned, we need to guess at the file type
\r
2187 if (mimeType == null)
\r
2188 mimeType = "application/"
\r
2189 + url.substring(url.lastIndexOf(".") + 1);
\r
2191 // Check if we have an image or some other type of file
\r
2192 if (url.substring(0, 5).equalsIgnoreCase("file:")
\r
2193 && mimeType.substring(0, 5).equalsIgnoreCase("image")) {
\r
2194 handleLocalImageURLPaste(mime, mimeType);
\r
2197 String[] type = mimeType.split("/");
\r
2198 boolean valid = validAttachment(type[1]);
\r
2199 boolean smallEnough = checkFileAttachmentSize(url);
\r
2200 if (smallEnough && valid
\r
2201 && url.substring(0, 5).equalsIgnoreCase("file:")
\r
2202 && !mimeType.substring(0, 5).equalsIgnoreCase("image")) {
\r
2203 handleLocalAttachment(mime, mimeType);
\r
2206 browser.page().mainFrame().evaluateJavaScript(
\r
2207 script_start + url + script_end);
\r
2212 // If a URL being pasted is an image URL, then attach the image
\r
2213 private void handleLocalImageURLPaste(QMimeData mime, String mimeType) {
\r
2214 List<QUrl> urlList = mime.urls();
\r
2215 String url = new String();
\r
2216 String script_start_image = new String(
\r
2217 "document.execCommand('insertHtml', false, '");
\r
2218 String script_end = new String("');");
\r
2219 StringBuffer buffer;
\r
2221 // Copy the image over into the resource directory and create a new resource
\r
2222 // record for each url pasted
\r
2223 for (int i = 0; i < urlList.size(); i++) {
\r
2224 url = urlList.get(i).toString();
\r
2226 Resource newRes = createResource(url, i, mimeType, false);
\r
2227 if (newRes == null)
\r
2229 currentNote.getResources().add(newRes);
\r
2230 buffer = new StringBuffer(100);
\r
2232 // Open the file & write the data
\r
2233 String fileName = Global.getFileManager().getResDirPath(newRes.getGuid());
\r
2234 QFile tfile = new QFile(fileName);
\r
2235 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
\r
2236 tfile.write(newRes.getData().getBody());
\r
2238 buffer.append(script_start_image);
\r
2239 buffer.append("<img src=\"" + FileUtils.toForwardSlashedPath(fileName));
\r
2240 // if (mimeType.equalsIgnoreCase("image/jpg"))
\r
2241 // mimeType = "image/jpeg";
\r
2242 buffer.append("\" en-tag=\"en-media\" type=\"" + mimeType +"\""
\r
2243 +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""
\r
2244 +" guid=\"" +newRes.getGuid() +"\""
\r
2245 +" onContextMenu=\"window.jambi.imageContextMenu('" +tfile.fileName() +"');\""
\r
2247 buffer.append(script_end);
\r
2248 browser.page().mainFrame().evaluateJavaScript(buffer.toString());
\r
2254 // If a URL being pasted is a local file URL, then attach the file
\r
2255 private void handleLocalAttachment(QMimeData mime, String mimeType) {
\r
2256 logger.log(logger.EXTREME, "Attaching local file");
\r
2257 List<QUrl> urlList = mime.urls();
\r
2258 String script_start = new String(
\r
2259 "document.execCommand('insertHtml', false, '");
\r
2260 String script_end = new String("');");
\r
2261 StringBuffer buffer;
\r
2263 String[] type = mimeType.split("/");
\r
2264 String icon = findIcon(type[1]);
\r
2265 if (icon.equals("attachment.png"))
\r
2266 icon = findIcon(type[0]);
\r
2267 buffer = new StringBuffer(100);
\r
2269 for (int i = 0; i < urlList.size(); i++) {
\r
2270 String url = urlList.get(i).toString();
\r
2272 // Start building the HTML
\r
2273 if (icon.equals("attachment.png"))
\r
2274 icon = findIcon(url.substring(url.lastIndexOf(".")+1));
\r
2275 String imageURL = FileUtils.toFileURLString(Global.getFileManager().getImageDirFile(icon));
\r
2277 logger.log(logger.EXTREME, "Creating resource ");
\r
2278 Resource newRes = createResource(url, i, mimeType, true);
\r
2279 if (newRes == null)
\r
2281 logger.log(logger.EXTREME, "New resource size: " +newRes.getData().getSize());
\r
2282 currentNote.getResources().add(newRes);
\r
2284 String fileName = newRes.getGuid() + Global.attachmentNameDelimeter+newRes.getAttributes().getFileName();
\r
2285 // If we have a PDF, we need to setup the preview.
\r
2286 if (icon.equalsIgnoreCase("pdf.png") && Global.pdfPreview()) {
\r
2287 logger.log(logger.EXTREME, "Setting up PDF preview");
\r
2288 if (newRes.getAttributes() != null &&
\r
2289 newRes.getAttributes().getFileName() != null &&
\r
2290 !newRes.getAttributes().getFileName().trim().equals(""))
\r
2291 fileName = newRes.getGuid()+Global.attachmentNameDelimeter+
\r
2292 newRes.getAttributes().getFileName();
\r
2294 fileName = newRes.getGuid()+".pdf";
\r
2295 QFile file = new QFile(Global.getFileManager().getResDirPath(fileName));
\r
2296 QFile.OpenMode mode = new QFile.OpenMode();
\r
2297 mode.set(QFile.OpenModeFlag.WriteOnly);
\r
2299 QDataStream out = new QDataStream(file);
\r
2300 // Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(newRes.getGuid(), true);
\r
2301 QByteArray binData = new QByteArray(newRes.getData().getBody());
\r
2302 // resBinary = null;
\r
2303 out.writeBytes(binData.toByteArray());
\r
2306 PDFPreview pdfPreview = new PDFPreview();
\r
2307 if (pdfPreview.setupPreview(Global.getFileManager().getResDirPath(fileName), "pdf",0)) {
\r
2308 imageURL = file.fileName() + ".png";
\r
2312 logger.log(logger.EXTREME, "Generating link tags");
\r
2313 buffer.delete(0, buffer.length());
\r
2314 buffer.append("<a en-tag=\"en-media\" guid=\"" +newRes.getGuid()+"\" ");
\r
2315 buffer.append(" onContextMenu=\"window.jambi.imageContextMenu('")
\r
2316 .append(Global.getFileManager().getResDirPath(fileName))
\r
2317 .append("');\" "); buffer.append("type=\"" + mimeType + "\" href=\"nnres://" + fileName +"\" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\" >");
\r
2318 buffer.append("<img src=\"" + imageURL + "\" title=\"" +newRes.getAttributes().getFileName());
\r
2319 buffer.append("\"></img>");
\r
2320 buffer.append("</a>");
\r
2321 browser.page().mainFrame().evaluateJavaScript(
\r
2322 script_start + buffer.toString() + script_end);
\r
2327 private Resource createResource(String url, int sequence, String mime, boolean attachment) {
\r
2328 logger.log(logger.EXTREME, "Inside create resource");
\r
2329 QFile resourceFile;
\r
2330 String urlTest = new QUrl(url).toLocalFile();
\r
2331 if (!urlTest.equals(""))
\r
2333 url = url.replace("/", File.separator);
\r
2334 logger.log(logger.EXTREME, "Reading from file to create resource");
\r
2335 resourceFile = new QFile(url);
\r
2336 resourceFile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly));
\r
2337 // logger.log(logger.EXTREME, "Error opening file "+url.toString() +": "+resourceFile.errorString());
\r
2338 byte[] fileData = resourceFile.readAll().toByteArray();
\r
2339 resourceFile.close();
\r
2340 if (fileData.length == 0)
\r
2344 logger.log(logger.EXTREME, "Generating MD5");
\r
2345 md = MessageDigest.getInstance("MD5");
\r
2346 md.update(fileData);
\r
2347 byte[] hash = md.digest();
\r
2349 Resource r = new Resource();
\r
2350 Calendar time = new GregorianCalendar();
\r
2351 long prevTime = time.getTimeInMillis();
\r
2352 while (prevTime == time.getTimeInMillis()) {
\r
2353 time = new GregorianCalendar();
\r
2355 r.setGuid(time.getTimeInMillis()+new Integer(sequence).toString());
\r
2356 r.setNoteGuid(currentNote.getGuid());
\r
2358 r.setActive(true);
\r
2359 r.setUpdateSequenceNum(0);
\r
2360 r.setWidth((short) 0);
\r
2361 r.setHeight((short) 0);
\r
2362 r.setDuration((short) 0);
\r
2364 Data d = new Data();
\r
2365 d.setBody(fileData);
\r
2366 d.setBodyIsSet(true);
\r
2367 d.setBodyHash(hash);
\r
2368 d.setBodyHashIsSet(true);
\r
2370 d.setSize(fileData.length);
\r
2372 int fileNamePos = url.lastIndexOf(File.separator);
\r
2373 if (fileNamePos == -1)
\r
2374 fileNamePos = url.lastIndexOf("/");
\r
2375 String fileName = url.substring(fileNamePos+1);
\r
2376 ResourceAttributes a = new ResourceAttributes();
\r
2378 a.setAltitudeIsSet(false);
\r
2379 a.setLongitude(0);
\r
2380 a.setLongitudeIsSet(false);
\r
2382 a.setLatitudeIsSet(false);
\r
2383 a.setCameraMake("");
\r
2384 a.setCameraMakeIsSet(false);
\r
2385 a.setCameraModel("");
\r
2386 a.setCameraModelIsSet(false);
\r
2387 a.setAttachment(attachment);
\r
2388 a.setAttachmentIsSet(true);
\r
2389 a.setClientWillIndex(false);
\r
2390 a.setClientWillIndexIsSet(true);
\r
2391 a.setRecoType("");
\r
2392 a.setRecoTypeIsSet(false);
\r
2393 a.setSourceURL(url);
\r
2394 a.setSourceURLIsSet(true);
\r
2395 a.setTimestamp(0);
\r
2396 a.setTimestampIsSet(false);
\r
2397 a.setFileName(fileName);
\r
2398 a.setFileNameIsSet(true);
\r
2399 r.setAttributes(a);
\r
2401 conn.getNoteTable().noteResourceTable.saveNoteResource(r, true);
\r
2402 logger.log(logger.EXTREME, "Resource created");
\r
2404 } catch (NoSuchAlgorithmException e1) {
\r
2405 e1.printStackTrace();
\r
2411 // find the appropriate icon for an attachment
\r
2412 private String findIcon(String appl) {
\r
2413 appl = appl.toLowerCase();
\r
2414 File f = Global.getFileManager().getImageDirFile(appl + ".png");
\r
2416 return appl+".png";
\r
2417 return "attachment.png";
\r
2420 // Check if the account supports this type of attachment
\r
2421 private boolean validAttachment(String type) {
\r
2422 if (Global.isPremium())
\r
2424 if (type.equalsIgnoreCase("JPG"))
\r
2426 if (type.equalsIgnoreCase("PNG"))
\r
2428 if (type.equalsIgnoreCase("GIF"))
\r
2430 if (type.equalsIgnoreCase("MP3"))
\r
2432 if (type.equalsIgnoreCase("WAV"))
\r
2434 if (type.equalsIgnoreCase("AMR"))
\r
2436 if (type.equalsIgnoreCase("PDF"))
\r
2438 String error = tr("Non-premium accounts can only attach JPG, PNG, GIF, MP3, WAV, AMR, or PDF files.");
\r
2439 QMessageBox.information(this, tr("Non-Premium Account"), error);
\r
2444 // Check the file attachment to be sure it isn't over 25 mb
\r
2445 private boolean checkFileAttachmentSize(String url) {
\r
2446 String fileName = url.substring(8);
\r
2447 QFile resourceFile = new QFile(fileName);
\r
2448 resourceFile.open(new QIODevice.OpenMode(
\r
2449 QIODevice.OpenModeFlag.ReadOnly));
\r
2450 long size = resourceFile.size();
\r
2451 resourceFile.close();
\r
2452 size = size / 1024 / 1024;
\r
2453 if (size < 50 && Global.isPremium())
\r
2458 String error = tr("A file attachment may not exceed 25MB.");
\r
2459 QMessageBox.information(this, tr("Attachment Size"), error);
\r
2464 @SuppressWarnings("unused")
\r
2465 private void createdChanged() {
\r
2466 QDateTime dt = new QDateTime();
\r
2467 dt.setDate(createdDate.date());
\r
2468 dt.setTime(createdTime.time());
\r
2469 noteSignal.createdDateChanged.emit(currentNote.getGuid(), dt);
\r
2473 @SuppressWarnings("unused")
\r
2474 private void alteredChanged() {
\r
2475 QDateTime dt = new QDateTime();
\r
2476 dt.setDate(alteredDate.date());
\r
2477 dt.setTime(alteredTime.time());
\r
2478 noteSignal.alteredDateChanged.emit(currentNote.getGuid(), dt);
\r
2481 @SuppressWarnings("unused")
\r
2482 private void subjectDateTimeChanged() {
\r
2483 QDateTime dt = new QDateTime();
\r
2484 dt.setDate(subjectDate.date());
\r
2485 dt.setTime(subjectTime.time());
\r
2486 noteSignal.subjectDateChanged.emit(currentNote.getGuid(), dt);
\r
2490 @SuppressWarnings("unused")
\r
2491 private void sourceUrlChanged() {
\r
2492 noteSignal.sourceUrlChanged.emit(currentNote.getGuid(), urlText.text());
\r
2495 @SuppressWarnings("unused")
\r
2496 private void authorChanged() {
\r
2497 noteSignal.authorChanged.emit(currentNote.getGuid(), authorText.text());
\r
2500 @SuppressWarnings("unused")
\r
2501 private void geoBoxChanged() {
\r
2502 int index = geoBox.currentIndex();
\r
2503 geoBox.setCurrentIndex(0);
\r
2505 GeoDialog box = new GeoDialog();
\r
2506 box.setLongitude(currentNote.getAttributes().getLongitude());
\r
2507 box.setLatitude(currentNote.getAttributes().getLatitude());
\r
2508 box.setAltitude(currentNote.getAttributes().getAltitude());
\r
2510 if (!box.okPressed())
\r
2512 double alt = box.getAltitude();
\r
2513 double lat = box.getLatitude();
\r
2514 double lon = box.getLongitude();
\r
2515 if (alt != currentNote.getAttributes().getAltitude() ||
\r
2516 lon != currentNote.getAttributes().getLongitude() ||
\r
2517 lat != currentNote.getAttributes().getLatitude()) {
\r
2518 noteSignal.geoChanged.emit(currentNote.getGuid(), lon, lat, alt);
\r
2519 currentNote.getAttributes().setAltitude(alt);
\r
2520 currentNote.getAttributes().setLongitude(lon);
\r
2521 currentNote.getAttributes().setLatitude(lat);
\r
2526 noteSignal.geoChanged.emit(currentNote.getGuid(), 0.0, 0.0, 0.0);
\r
2527 currentNote.getAttributes().setAltitude(0.0);
\r
2528 currentNote.getAttributes().setLongitude(0.0);
\r
2529 currentNote.getAttributes().setLatitude(0.0);
\r
2532 if (index == 3 || index == 0) {
\r
2533 QDesktopServices.openUrl(new QUrl("http://maps.google.com/maps?z=6&q="+currentNote.getAttributes().getLatitude() +"," +currentNote.getAttributes().getLongitude()));
\r
2537 // ************************************************************
\r
2538 // * User chose to save an attachment. Pares out the request *
\r
2539 // * into a guid & file. Save the result. *
\r
2540 // ************************************************************
\r
2541 public void downloadAttachment(QNetworkRequest request) {
\r
2543 QFileDialog fd = new QFileDialog(this);
\r
2544 fd.setFileMode(FileMode.AnyFile);
\r
2545 fd.setConfirmOverwrite(true);
\r
2546 fd.setWindowTitle(tr("Save File"));
\r
2547 fd.setAcceptMode(AcceptMode.AcceptSave);
\r
2548 fd.setDirectory(System.getProperty("user.home"));
\r
2549 String name = request.url().toString();
\r
2551 int pos = name.lastIndexOf(Global.attachmentNameDelimeter);
\r
2553 guid = name.substring(0, pos).replace("nnres://", "");
\r
2554 name = name.substring(pos +Global.attachmentNameDelimeter.length());
\r
2555 fd.selectFile(name);
\r
2556 pos = name.lastIndexOf('.');
\r
2558 String mimeType = "(*." + name.substring(pos + 1)
\r
2559 + ");; All Files (*)";
\r
2560 fd.setFilter(tr(mimeType));
\r
2566 // Strip URL prefix and base dir
\r
2567 guid = guid.replace("nnres://", "")
\r
2568 .replace(FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath()), "");
\r
2569 guid = guid.replace("file://", "").replace("/", "")
\r
2570 .replace(FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath()), "");
\r
2572 pos = guid.lastIndexOf('.');
\r
2574 guid = guid.substring(0,pos);
\r
2575 if (fd.exec() != 0 && fd.selectedFiles().size() > 0) {
\r
2576 name = name.replace('\\', '/');
\r
2577 Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
\r
2578 QFile saveFile = new QFile(fd.selectedFiles().get(0));
\r
2579 QFile.OpenMode mode = new QFile.OpenMode();
\r
2580 mode.set(QFile.OpenModeFlag.WriteOnly);
\r
2581 saveFile.open(mode);
\r
2582 QDataStream saveOut = new QDataStream(saveFile);
\r
2583 QByteArray binData = new QByteArray(resBinary.getData().getBody());
\r
2584 saveOut.writeBytes(binData.toByteArray());
\r
2591 // ************************************************************
\r
2592 // * User chose to save an attachment. Pares out the request *
\r
2593 // * into a guid & file. Save the result. --- DONE FROM downloadAttachment now!!!!!
\r
2594 // ************************************************************
\r
2595 public void downloadImage(QNetworkRequest request) {
\r
2596 QFileDialog fd = new QFileDialog(this);
\r
2597 fd.setFileMode(FileMode.AnyFile);
\r
2598 fd.setConfirmOverwrite(true);
\r
2599 fd.setWindowTitle(tr("Save File"));
\r
2600 fd.setAcceptMode(AcceptMode.AcceptSave);
\r
2601 fd.setDirectory(System.getProperty("user.home"));
\r
2602 String name = request.url().toString();
\r
2603 name = name.replace("nnres://", "");
\r
2604 String dPath = FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath());
\r
2605 name = name.replace(dPath, "");
\r
2606 int pos = name.lastIndexOf('.');
\r
2607 String guid = name;
\r
2609 String mimeType = "(*." + name.substring(pos + 1)
\r
2610 + ");; All Files (*)";
\r
2611 fd.setFilter(tr(mimeType));
\r
2612 guid = guid.substring(0,pos);
\r
2614 pos = name.lastIndexOf(Global.attachmentNameDelimeter);
\r
2616 guid = name.substring(0, pos);
\r
2617 fd.selectFile(name.substring(pos+Global.attachmentNameDelimeter.length()));
\r
2619 if (fd.exec() != 0 && fd.selectedFiles().size() > 0) {
\r
2620 Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
\r
2621 String fileName = fd.selectedFiles().get(0);
\r
2622 QFile saveFile = new QFile(fileName);
\r
2623 QFile.OpenMode mode = new QFile.OpenMode();
\r
2624 mode.set(QFile.OpenModeFlag.WriteOnly);
\r
2625 saveFile.open(mode);
\r
2626 QDataStream saveOut = new QDataStream(saveFile);
\r
2627 QByteArray binData = new QByteArray(resBinary.getData().getBody());
\r
2628 saveOut.writeBytes(binData.toByteArray());
\r
2634 // *************************************************************
\r
2635 // * decrypt any hidden text. We could do an XML parse, but
\r
2636 // * it is quicker here just to scan for an <img tag & do the fix
\r
2637 // * the manual way
\r
2638 // *************************************************************
\r
2639 private void removeEncryption(String id, String plainText, boolean permanent, String slot) {
\r
2641 plainText = " <table class=\"en-crypt-temp\" slot=\""
\r
2644 +"border=1 width=100%><tbody><tr><td>"
\r
2645 +plainText+"</td></tr></tbody></table>";
\r
2648 String html = browser.page().mainFrame().toHtml();
\r
2649 String text = html;
\r
2650 int imagePos = html.indexOf("<img");
\r
2652 for ( ;imagePos>0; ) {
\r
2653 // Find the end tag
\r
2654 endPos = text.indexOf(">", imagePos);
\r
2655 String tag = text.substring(imagePos-1,endPos);
\r
2656 if (tag.indexOf("id=\""+id+"\"") > -1) {
\r
2657 text = text.substring(0,imagePos) +plainText+text.substring(endPos+1);
\r
2658 QTextCodec codec = QTextCodec.codecForName("UTF-8");
\r
2659 QByteArray unicode = codec.fromUnicode(text);
\r
2660 browser.setContent(unicode);
\r
2664 imagePos = text.indexOf("<img", imagePos+1);
\r
2669 //****************************************************************
\r
2670 //* Focus shortcuts
\r
2671 //****************************************************************
\r
2672 @SuppressWarnings("unused")
\r
2673 private void focusTitle() {
\r
2674 titleLabel.setFocus();
\r
2676 @SuppressWarnings("unused")
\r
2677 private void focusTag() {
\r
2678 tagEdit.setFocus();
\r
2680 @SuppressWarnings("unused")
\r
2681 private void focusNote() {
\r
2682 browser.setFocus();
\r
2684 @SuppressWarnings("unused")
\r
2685 private void focusAuthor() {
\r
2686 authorLabel.setFocus();
\r
2688 @SuppressWarnings("unused")
\r
2689 private void focusUrl() {
\r
2690 urlLabel.setFocus();
\r
2694 //*****************************************************************
\r
2695 //* Set the document background color
\r
2696 //*****************************************************************
\r
2697 public void setBackgroundColor(String color) {
\r
2698 String js = "function changeBackground(color) {"
\r
2699 +"document.body.style.background = color;"
\r
2701 +"changeBackground('" +color+"');";
\r
2702 browser.page().mainFrame().evaluateJavaScript(js);
\r
2707 //****************************************************************
\r
2708 //* MicroFocus changed
\r
2709 //****************************************************************
\r
2710 private void microFocusChanged() {
\r
2711 boldButton.setDown(false);
\r
2712 italicButton.setDown(false);
\r
2713 underlineButton.setDown(false);
\r
2714 browser.openAction.setEnabled(false);
\r
2715 browser.downloadAttachment.setEnabled(false);
\r
2716 browser.downloadImage.setEnabled(false);
\r
2717 browser.rotateImageLeft.setEnabled(false);
\r
2718 browser.rotateImageRight.setEnabled(false);
\r
2719 browser.insertTableAction.setEnabled(true);
\r
2720 browser.deleteTableColumnAction.setEnabled(false);
\r
2721 browser.insertTableRowAction.setEnabled(false);
\r
2722 browser.insertTableColumnAction.setEnabled(false);
\r
2723 browser.deleteTableRowAction.setEnabled(false);
\r
2724 browser.insertLinkAction.setText(tr("Insert Hyperlink"));
\r
2725 insertHyperlink = true;
\r
2726 currentHyperlink ="";
\r
2727 insideList = false;
\r
2728 insideTable = false;
\r
2729 insideEncryption = false;
\r
2730 forceTextPaste = false;
\r
2732 String js = new String( "function getCursorPos() {"
\r
2734 +"if (window.getSelection) {"
\r
2735 +" var selObj = window.getSelection();"
\r
2736 +" var selRange = selObj.getRangeAt(0);"
\r
2737 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
2738 +" while(workingNode != null) { "
\r
2739 // +" window.jambi.printNode(workingNode.nodeName);"
\r
2740 +" if (workingNode.nodeName=='TABLE') { if (workingNode.getAttribute('class').toLowerCase() == 'en-crypt-temp') window.jambi.insideEncryption(); }"
\r
2741 +" if (workingNode.nodeName=='B') window.jambi.boldActive();"
\r
2742 +" if (workingNode.nodeName=='I') window.jambi.italicActive();"
\r
2743 +" if (workingNode.nodeName=='U') window.jambi.underlineActive();"
\r
2744 +" if (workingNode.nodeName=='UL') window.jambi.setInsideList();"
\r
2745 +" if (workingNode.nodeName=='OL') window.jambi.setInsideList();"
\r
2746 +" if (workingNode.nodeName=='LI') window.jambi.setInsideList();"
\r
2747 +" if (workingNode.nodeName=='TBODY') window.jambi.setInsideTable();"
\r
2748 +" 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
2749 +" if (workingNode.nodeName=='SPAN') {"
\r
2750 +" if (workingNode.getAttribute('style') == 'text-decoration: underline;') window.jambi.underlineActive();"
\r
2752 +" workingNode = workingNode.parentNode;"
\r
2755 +"} getCursorPos();");
\r
2756 browser.page().mainFrame().evaluateJavaScript(js);
\r
2759 public void printNode(String n) {
\r
2760 System.out.println("Node Vaule: " +n);
\r
2763 public void insideEncryption() {
\r
2764 insideEncryption = true;
\r
2768 //****************************************************************
\r
2769 //* Insert a table row
\r
2770 //****************************************************************
\r
2771 public void insertTableRow() {
\r
2773 String js = new String( "function insertTableRow() {"
\r
2774 +" var selObj = window.getSelection();"
\r
2775 +" var selRange = selObj.getRangeAt(0);"
\r
2776 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
2777 +" var cellCount = 0;"
\r
2778 +" while(workingNode != null) { "
\r
2779 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
\r
2780 +" row = document.createElement('TR');"
\r
2781 +" var nodes = workingNode.getElementsByTagName('td');"
\r
2782 +" for (j=0; j<nodes.length; j=j+1) {"
\r
2783 +" cell = document.createElement('TD');"
\r
2784 +" cell.innerHTML=' ';"
\r
2785 +" row.appendChild(cell);"
\r
2787 +" workingNode.parentNode.insertBefore(row,workingNode.nextSibling);"
\r
2790 +" workingNode = workingNode.parentNode;"
\r
2792 +"} insertTableRow();");
\r
2793 browser.page().mainFrame().evaluateJavaScript(js);
\r
2797 public void insertTableColumn() {
\r
2798 String js = new String( "function insertTableColumn() {"
\r
2799 +" var selObj = window.getSelection();"
\r
2800 +" var selRange = selObj.getRangeAt(0);"
\r
2801 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
2802 +" var current = 0;"
\r
2803 +" while (workingNode.nodeName.toLowerCase() != 'table' && workingNode != null) {"
\r
2804 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
\r
2805 +" var td = workingNode;"
\r
2806 +" while (td.previousSibling != null) { "
\r
2807 +" current = current+1; td = td.previousSibling;"
\r
2810 +" workingNode = workingNode.parentNode; "
\r
2812 +" if (workingNode == null) return;"
\r
2813 +" for (var i=0; i<workingNode.rows.length; i++) { "
\r
2814 +" var cell = workingNode.rows[i].insertCell(current+1); "
\r
2815 +" cell.innerHTML = ' '; "
\r
2817 +"} insertTableColumn();");
\r
2818 browser.page().mainFrame().evaluateJavaScript(js);
\r
2822 //****************************************************************
\r
2823 //* Delete a table row
\r
2824 //****************************************************************
\r
2825 public void deleteTableRow() {
\r
2827 String js = new String( "function deleteTableRow() {"
\r
2828 +" var selObj = window.getSelection();"
\r
2829 +" var selRange = selObj.getRangeAt(0);"
\r
2830 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
2831 +" var cellCount = 0;"
\r
2832 +" while(workingNode != null) { "
\r
2833 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
\r
2834 +" workingNode.parentNode.removeChild(workingNode);"
\r
2837 +" workingNode = workingNode.parentNode;"
\r
2839 +"} deleteTableRow();");
\r
2840 browser.page().mainFrame().evaluateJavaScript(js);
\r
2844 public void deleteTableColumn() {
\r
2845 String js = new String( "function deleteTableColumn() {"
\r
2846 +" var selObj = window.getSelection();"
\r
2847 +" var selRange = selObj.getRangeAt(0);"
\r
2848 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
2849 +" var current = 0;"
\r
2850 +" while (workingNode.nodeName.toLowerCase() != 'table' && workingNode != null) {"
\r
2851 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
\r
2852 +" var td = workingNode;"
\r
2853 +" while (td.previousSibling != null) { "
\r
2854 +" current = current+1; td = td.previousSibling;"
\r
2857 +" workingNode = workingNode.parentNode; "
\r
2859 +" if (workingNode == null) return;"
\r
2860 +" for (var i=0; i<workingNode.rows.length; i++) { "
\r
2861 +" workingNode.rows[i].deleteCell(current); "
\r
2863 +"} deleteTableColumn();");
\r
2864 browser.page().mainFrame().evaluateJavaScript(js);
\r
2869 public void setInsideTable() {
\r
2870 browser.insertTableRowAction.setEnabled(true);
\r
2871 browser.insertTableColumnAction.setEnabled(true);
\r
2872 browser.deleteTableRowAction.setEnabled(true);
\r
2873 browser.deleteTableColumnAction.setEnabled(true);
\r
2874 browser.insertTableAction.setEnabled(false);
\r
2875 browser.encryptAction.setEnabled(false);
\r
2876 insideTable = true;
\r
2879 public void setInsideLink(String link) {
\r
2880 browser.insertLinkAction.setText(tr("Edit Hyperlink"));
\r
2881 currentHyperlink = link;
\r
2882 insertHyperlink = false;
\r
2885 public void italicActive() {
\r
2886 italicButton.setDown(true);
\r
2888 public void boldActive() {
\r
2889 boldButton.setDown(true);
\r
2891 public void underlineActive() {
\r
2892 underlineButton.setDown(true);
\r
2894 public void forceTextPaste() {
\r
2895 forceTextPaste = true;
\r
2897 public void imageContextMenu(String f) {
\r
2898 browser.downloadImage.setEnabled(true);
\r
2899 browser.rotateImageRight.setEnabled(true);
\r
2900 browser.rotateImageLeft.setEnabled(true);
\r
2901 browser.openAction.setEnabled(true);
\r
2904 public void rotateImageRight() {
\r
2905 QWebSettings.setMaximumPagesInCache(0);
\r
2906 QWebSettings.setObjectCacheCapacities(0, 0, 0);
\r
2907 QImage image = new QImage(selectedFile);
\r
2908 QMatrix matrix = new QMatrix();
\r
2909 matrix.rotate( 90.0 );
\r
2910 image = image.transformed(matrix);
\r
2911 image.save(selectedFile);
\r
2912 QWebSettings.setMaximumPagesInCache(0);
\r
2913 QWebSettings.setObjectCacheCapacities(0, 0, 0);
\r
2914 browser.setHtml(browser.page().mainFrame().toHtml());
\r
2917 resourceSignal.contentChanged.emit(selectedFile);
\r
2920 public void rotateImageLeft() {
\r
2921 QImage image = new QImage(selectedFile);
\r
2922 QMatrix matrix = new QMatrix();
\r
2923 matrix.rotate( -90.0 );
\r
2924 image = image.transformed(matrix);
\r
2925 image.save(selectedFile);
\r
2926 browser.setHtml(browser.page().mainFrame().toHtml());
\r
2929 resourceSignal.contentChanged.emit(selectedFile);
\r
2931 public void resourceContextMenu(String f) {
\r
2932 browser.downloadAttachment.setEnabled(true);
\r
2933 browser.openAction.setEnabled(true);
\r
2936 public void latexContextMenu(String f) {
\r
2937 browser.downloadImage.setEnabled(true);
\r
2938 browser.rotateImageRight.setEnabled(true);
\r
2939 browser.rotateImageLeft.setEnabled(true);
\r
2940 browser.openAction.setEnabled(true);
\r
2944 //****************************************************************
\r
2945 //* Apply CSS style to specified word
\r
2946 //****************************************************************
\r
2947 /* public void applyStyleToWords(String word, String style) {
\r
2948 QFile script = new QFile("D:\\NeverNote\\js\\hilight1.js");
\r
2949 script.open(OpenModeFlag.ReadOnly);
\r
2950 String s = script.readAll().toString();
\r
2951 String js = new String(s +" findit('"+word+"', '"+style+"');");
\r
2952 browser.page().mainFrame().evaluateJavaScript(js);
\r
2953 System.out.println(getContent());
\r
2956 //****************************************************************
\r
2957 //* Someone tried to paste a resource between notes, so we need *
\r
2958 //* to do some special handling. *
\r
2959 //****************************************************************
\r
2960 private String fixInternotePaste(String text) {
\r
2961 logger.log(logger.EXTREME, "Fixing internote paste");
\r
2962 String returnValue = fixInternotePasteSearch(text, "<img", "src=\"");
\r
2963 return fixInternotePasteSearch(returnValue, "<a", "href=\"nnres://");
\r
2965 private String fixInternotePasteSearch(String text, String type, String locTag) {
\r
2967 // First, let's fix the images.
\r
2968 int startPos = text.indexOf(type);
\r
2970 for (; startPos>=0;) {
\r
2971 endPos = text.indexOf(">", startPos+1);
\r
2972 String segment = text.substring(startPos, endPos);
\r
2973 if (segment.indexOf("en-tag") > -1) {
\r
2974 String newSegment = segment;
\r
2976 int guidStartPos = segment.indexOf("guid=\"");
\r
2977 int guidEndPos = segment.indexOf("\"", guidStartPos+7);
\r
2978 String guid = segment.substring(guidStartPos+6,guidEndPos);
\r
2980 int mimeStartPos = segment.indexOf("type");
\r
2981 int mimeEndPos = segment.indexOf("\"", mimeStartPos+7);
\r
2982 String mime = segment.substring(mimeStartPos+6,mimeEndPos);
\r
2984 int srcStartPos = segment.indexOf("src");
\r
2985 int srcEndPos = segment.indexOf("\"", srcStartPos+6);
\r
2986 String src = segment.substring(srcStartPos+5,srcEndPos);
\r
2988 Calendar currentTime = new GregorianCalendar();
\r
2989 Long l = new Long(currentTime.getTimeInMillis());
\r
2990 long prevTime = l;
\r
2991 while (l==prevTime) {
\r
2992 currentTime = new GregorianCalendar();
\r
2993 l= new Long(currentTime.getTimeInMillis());
\r
2996 Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
\r
2997 // if r==null, then the image doesn't exist (it was probably cut out of another note, so
\r
2998 // we need to recereate it
\r
3000 r = createResource(src, 1, mime, false);
\r
3004 String randint = new String(Long.toString(l));
\r
3005 String extension = null;
\r
3006 if (r.getMime()!= null) {
\r
3007 extension = r.getMime().toLowerCase();
\r
3008 if (extension.indexOf("/")>-1)
\r
3009 extension = extension.substring(extension.indexOf("/")+1);
\r
3011 String newFile = randint;
\r
3012 if (r.getAttributes().getFileName() != null && r.getAttributes().getFileName() != "")
\r
3013 if (!locTag.startsWith("src"))
\r
3014 newFile = newFile+Global.attachmentNameDelimeter+r.getAttributes().getFileName();
\r
3015 r.setNoteGuid(currentNote.getGuid());
\r
3017 r.setGuid(randint);
\r
3018 conn.getNoteTable().noteResourceTable.saveNoteResource(r, true);
\r
3019 QFile f = new QFile(Global.getFileManager().getResDirPath(newFile));
\r
3020 QByteArray bin = new QByteArray(r.getData().getBody());
\r
3021 f.open(QFile.OpenModeFlag.WriteOnly);
\r
3024 newSegment = newSegment.replace("guid=\""+guid, "guid=\""+randint);
\r
3025 currentNote.getResources().add(r);
\r
3027 int startSrcPos = newSegment.indexOf(locTag);
\r
3028 int endSrcPos = newSegment.indexOf("\"",startSrcPos+locTag.length()+1);
\r
3030 if (locTag.startsWith("src")) {
\r
3031 source = newSegment.substring(startSrcPos+locTag.length(),endSrcPos);
\r
3032 newSegment = newSegment.replace(source,
\r
3033 FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath(newFile)));
\r
3035 source = newSegment.substring(startSrcPos+locTag.length(),endSrcPos);
\r
3036 newSegment = newSegment.replace(source, newFile);
\r
3039 text = text.substring(0,startPos) + newSegment + text.substring(endPos);
\r
3041 startPos = text.indexOf(type, startPos+1);
\r
3047 public void nextPage(String file) {
\r
3048 logger.log(logger.EXTREME, "Starting nextPage()");
\r
3050 Integer pageNumber;
\r
3051 if (previewPageList.containsKey(file))
\r
3052 pageNumber = previewPageList.get(file)+1;
\r
3055 previewPageList.remove(file);
\r
3056 previewPageList.put(file, pageNumber);
\r
3057 PDFPreview pdfPreview = new PDFPreview();
\r
3058 boolean goodPreview = pdfPreview.setupPreview(file, "pdf", pageNumber);
\r
3059 if (goodPreview) {
\r
3061 // String html = getContent();
\r
3062 QWebSettings.setMaximumPagesInCache(0);
\r
3063 QWebSettings.setObjectCacheCapacities(0, 0, 0);
\r
3064 // browser.setContent(new QByteArray());
\r
3065 browser.setHtml(browser.page().mainFrame().toHtml());
\r
3067 // browser.setContent(new QByteArray(html));
\r
3068 // browser.triggerPageAction(WebAction.Reload);
\r
3069 // pdfMouseOver(selectedFile);
\r
3073 public void previousPage(String file) {
\r
3074 logger.log(logger.EXTREME, "Starting previousPage()");
\r
3076 Integer pageNumber;
\r
3077 if (previewPageList.containsKey(file))
\r
3078 pageNumber = previewPageList.get(file)-1;
\r
3081 previewPageList.remove(file);
\r
3082 previewPageList.put(file, pageNumber);
\r
3083 PDFPreview pdfPreview = new PDFPreview();
\r
3084 boolean goodPreview = pdfPreview.setupPreview(file, "pdf", pageNumber);
\r
3085 if (goodPreview) {
\r
3087 // String html = getContent();
\r
3088 QWebSettings.setMaximumPagesInCache(0);
\r
3089 QWebSettings.setObjectCacheCapacities(0, 0, 0);
\r
3090 browser.setHtml(browser.page().mainFrame().toHtml());
\r
3092 // browser.setContent(new QByteArray(html));
\r
3093 // browser.triggerPageAction(WebAction.Reload);
\r
3097 /* public void pdfMouseOver(String name) {
\r
3099 if (previewPageList.containsKey(selectedFile))
\r
3100 pageNumber = previewPageList.get(selectedFile)+1;
\r
3104 if (pageNumber <= 1)
\r
3105 browser.previousPageAction.setEnabled(false);
\r
3107 browser.previousPageAction.setEnabled(true);
\r
3109 PDFPreview pdf = new PDFPreview();
\r
3110 int totalPages = pdf.getPageCount(name);
\r
3111 if (previewPageList.containsKey(selectedFile))
\r
3112 pageNumber = previewPageList.get(selectedFile)+1;
\r
3115 if (totalPages > pageNumber)
\r
3116 browser.nextPageAction.setEnabled(true);
\r
3118 browser.nextPageAction.setEnabled(false);
\r
3122 public void pdfMouseOut() {
\r
3123 // browser.nextPageAction.setVisible(false);
\r
3124 // browser.previousPageAction.setVisible(false);
\r
3128 @SuppressWarnings("unused")
\r
3129 private void toggleUndoVisible(Boolean toggle) {
\r
3130 undoAction.setVisible(toggle);
\r
3131 Global.saveEditorButtonsVisible("undo", toggle);
\r
3133 @SuppressWarnings("unused")
\r
3134 private void toggleRedoVisible(Boolean toggle) {
\r
3135 redoAction.setVisible(toggle);
\r
3136 Global.saveEditorButtonsVisible("redo", toggle);
\r
3138 @SuppressWarnings("unused")
\r
3139 private void toggleCutVisible(Boolean toggle) {
\r
3140 cutAction.setVisible(toggle);
\r
3141 Global.saveEditorButtonsVisible("cut", toggle);
\r
3143 @SuppressWarnings("unused")
\r
3144 private void toggleCopyVisible(Boolean toggle) {
\r
3145 copyAction.setVisible(toggle);
\r
3146 Global.saveEditorButtonsVisible("copy", toggle);
\r
3148 @SuppressWarnings("unused")
\r
3149 private void togglePasteVisible(Boolean toggle) {
\r
3150 pasteAction.setVisible(toggle);
\r
3151 Global.saveEditorButtonsVisible("paste", toggle);
\r
3153 @SuppressWarnings("unused")
\r
3154 private void toggleBoldVisible(Boolean toggle) {
\r
3155 boldAction.setVisible(toggle);
\r
3156 Global.saveEditorButtonsVisible("bold", toggle);
\r
3158 @SuppressWarnings("unused")
\r
3159 private void toggleItalicVisible(Boolean toggle) {
\r
3160 italicAction.setVisible(toggle);
\r
3161 Global.saveEditorButtonsVisible("italic", toggle);
\r
3163 @SuppressWarnings("unused")
\r
3164 private void toggleUnderlineVisible(Boolean toggle) {
\r
3165 underlineAction.setVisible(toggle);
\r
3166 Global.saveEditorButtonsVisible("underline", toggle);
\r
3168 @SuppressWarnings("unused")
\r
3169 private void toggleStrikethroughVisible(Boolean toggle) {
\r
3170 strikethroughAction.setVisible(toggle);
\r
3171 Global.saveEditorButtonsVisible("strikethrough", toggle);
\r
3173 @SuppressWarnings("unused")
\r
3174 private void toggleLeftAlignVisible(Boolean toggle) {
\r
3175 leftAlignAction.setVisible(toggle);
\r
3176 Global.saveEditorButtonsVisible("alignLeft", toggle);
\r
3178 @SuppressWarnings("unused")
\r
3179 private void toggleRightAlignVisible(Boolean toggle) {
\r
3180 rightAlignAction.setVisible(toggle);
\r
3181 Global.saveEditorButtonsVisible("alignRight", toggle);
\r
3183 @SuppressWarnings("unused")
\r
3184 private void toggleCenterAlignVisible(Boolean toggle) {
\r
3185 centerAlignAction.setVisible(toggle);
\r
3186 Global.saveEditorButtonsVisible("alignCenter", toggle);
\r
3188 @SuppressWarnings("unused")
\r
3189 private void toggleHLineVisible(Boolean toggle) {
\r
3190 hlineAction.setVisible(toggle);
\r
3191 Global.saveEditorButtonsVisible("hline", toggle);
\r
3193 @SuppressWarnings("unused")
\r
3194 private void toggleIndentVisible(Boolean toggle) {
\r
3195 indentAction.setVisible(toggle);
\r
3196 Global.saveEditorButtonsVisible("indent", toggle);
\r
3198 @SuppressWarnings("unused")
\r
3199 private void toggleTodoVisible(Boolean toggle) {
\r
3200 todoAction.setVisible(toggle);
\r
3201 Global.saveEditorButtonsVisible("todo", toggle);
\r
3203 @SuppressWarnings("unused")
\r
3204 private void toggleOutdentVisible(Boolean toggle) {
\r
3205 outdentAction.setVisible(toggle);
\r
3206 Global.saveEditorButtonsVisible("outdent", toggle);
\r
3208 @SuppressWarnings("unused")
\r
3209 private void toggleBulletListVisible(Boolean toggle) {
\r
3210 bulletListAction.setVisible(toggle);
\r
3211 Global.saveEditorButtonsVisible("bulletList", toggle);
\r
3213 @SuppressWarnings("unused")
\r
3214 private void toggleNumberListVisible(Boolean toggle) {
\r
3215 numberListAction.setVisible(toggle);
\r
3216 Global.saveEditorButtonsVisible("numberList", toggle);
\r
3218 @SuppressWarnings("unused")
\r
3219 private void toggleFontListVisible(Boolean toggle) {
\r
3220 fontListAction.setVisible(toggle);
\r
3221 Global.saveEditorButtonsVisible("font", toggle);
\r
3223 @SuppressWarnings("unused")
\r
3224 private void toggleFontColorVisible(Boolean toggle) {
\r
3225 fontColorAction.setVisible(toggle);
\r
3226 Global.saveEditorButtonsVisible("fontColor", toggle);
\r
3228 @SuppressWarnings("unused")
\r
3229 private void toggleFontSizeVisible(Boolean toggle) {
\r
3230 fontSizeAction.setVisible(toggle);
\r
3231 Global.saveEditorButtonsVisible("fontSize", toggle);
\r
3233 @SuppressWarnings("unused")
\r
3234 private void toggleFontHilightVisible(Boolean toggle) {
\r
3235 fontHilightAction.setVisible(toggle);
\r
3236 Global.saveEditorButtonsVisible("fontHilight", toggle);
\r
3238 @SuppressWarnings("unused")
\r
3239 private void toggleSpellCheckVisible(Boolean toggle) {
\r
3240 spellCheckAction.setVisible(toggle);
\r
3241 Global.saveEditorButtonsVisible("spellCheck", toggle);
\r
3245 private void setupDictionary() {
\r
3246 File wordList = new File(Global.getFileManager().getSpellDirPath()+Locale.getDefault()+".dic");
\r
3248 dictionary = new SpellDictionaryHashMap(wordList);
\r
3249 spellChecker = new SpellChecker(dictionary);
\r
3251 File userWordList;
\r
3252 userWordList = new File(Global.getFileManager().getSpellDirPathUser()+"user.dic");
\r
3254 // Get the local user spell dictionary
\r
3256 userDictionary = new SpellDictionaryHashMap(userWordList);
\r
3257 } catch (FileNotFoundException e) {
\r
3258 userWordList.createNewFile();
\r
3259 userDictionary = new SpellDictionaryHashMap(userWordList);
\r
3260 } catch (IOException e) {
\r
3261 userWordList.createNewFile();
\r
3262 userDictionary = new SpellDictionaryHashMap(userWordList);
\r
3265 spellListener = new SuggestionListener(this, spellChecker);
\r
3267 // Add the user dictionary
\r
3268 spellChecker.addSpellCheckListener(spellListener);
\r
3269 spellChecker.setUserDictionary(userDictionary);
\r
3271 } catch (FileNotFoundException e) {
\r
3272 QMessageBox.critical(this, tr("Spell Check Error"),
\r
3273 tr("Dictionary ")+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+
\r
3274 tr(".dic was not found."));
\r
3275 } catch (IOException e) {
\r
3276 QMessageBox.critical(this, tr("Spell Check Error"),
\r
3277 tr("Dictionary ")+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+
\r
3278 tr(".dic is invalid."));
\r
3283 // Invoke spell checker dialog
\r
3284 @SuppressWarnings("unused")
\r
3285 private void spellCheckClicked() {
\r
3287 if (spellChecker == null) {
\r
3288 setupDictionary();
\r
3291 // Read user settings
\r
3292 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREDIGITWORDS,
\r
3293 Global.getSpellSetting(Configuration.SPELL_IGNOREDIGITWORDS));
\r
3294 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREINTERNETADDRESSES,
\r
3295 Global.getSpellSetting(Configuration.SPELL_IGNOREINTERNETADDRESSES));
\r
3296 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREMIXEDCASE,
\r
3297 Global.getSpellSetting(Configuration.SPELL_IGNOREMIXEDCASE));
\r
3298 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREUPPERCASE,
\r
3299 Global.getSpellSetting(Configuration.SPELL_IGNOREUPPERCASE));
\r
3300 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNORESENTENCECAPITALIZATION,
\r
3301 Global.getSpellSetting(Configuration.SPELL_IGNORESENTENCECAPITALIZATION));
\r
3303 spellListener.abortSpellCheck = false;
\r
3304 spellListener.errorsFound = false;
\r
3305 String content = getBrowser().page().mainFrame().toPlainText();
\r
3306 StringWordTokenizer tokenizer = new StringWordTokenizer(content);
\r
3307 if (!tokenizer.hasMoreWords())
\r
3309 getBrowser().page().action(WebAction.MoveToStartOfDocument);
\r
3311 getBrowser().setFocus();
\r
3314 // Move to the start of page
\r
3315 KeyboardModifiers ctrl = new KeyboardModifiers(KeyboardModifier.ControlModifier.value());
\r
3316 QKeyEvent home = new QKeyEvent(Type.KeyPress, Key.Key_Home.value(), ctrl);
\r
3317 browser.keyPressEvent(home);
\r
3318 getBrowser().setFocus();
\r
3320 tokenizer = new StringWordTokenizer(content);
\r
3323 while(tokenizer.hasMoreWords()) {
\r
3324 word = tokenizer.nextWord();
\r
3325 found = getBrowser().page().findText(word);
\r
3326 if (found && !spellListener.abortSpellCheck) {
\r
3327 spellChecker.checkSpelling(new StringWordTokenizer(word));
\r
3328 getBrowser().setFocus();
\r
3332 // Go to the end of the document & finish up.
\r
3333 home = new QKeyEvent(Type.KeyPress, Key.Key_End.value(), ctrl);
\r
3334 browser.keyPressEvent(home);
\r
3335 if (!spellListener.errorsFound)
\r
3336 QMessageBox.information(this, tr("Spell Check Complete"),
\r
3337 tr("No Errors Found"));
\r