2 * This file is part of NeverNote
\r
3 * Copyright 2009 Randy Baumgarte
\r
5 * This file may be licensed under the terms of of the
\r
6 * GNU General Public License Version 2 (the ``GPL'').
\r
8 * Software distributed under the License is distributed
\r
9 * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
\r
10 * express or implied. See the GPL for the specific language
\r
11 * governing rights and limitations.
\r
13 * You should have received a copy of the GPL along with this
\r
14 * program. If not, go to http://www.gnu.org/licenses/gpl.html
\r
15 * or write to the Free Software Foundation, Inc.,
\r
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
\r
20 package cx.fbn.nevernote.gui;
\r
22 import java.io.File;
\r
23 import java.io.FileNotFoundException;
\r
24 import java.io.IOException;
\r
25 import java.net.FileNameMap;
\r
26 import java.net.URI;
\r
27 import java.net.URLConnection;
\r
28 import java.security.MessageDigest;
\r
29 import java.security.NoSuchAlgorithmException;
\r
30 import java.text.SimpleDateFormat;
\r
31 import java.util.ArrayList;
\r
32 import java.util.Calendar;
\r
33 import java.util.Collections;
\r
34 import java.util.Date;
\r
35 import java.util.GregorianCalendar;
\r
36 import java.util.HashMap;
\r
37 import java.util.List;
\r
38 import java.util.Locale;
\r
40 import org.apache.commons.lang.StringUtils;
\r
42 import com.evernote.edam.limits.Constants;
\r
43 import com.evernote.edam.type.Data;
\r
44 import com.evernote.edam.type.Note;
\r
45 import com.evernote.edam.type.Notebook;
\r
46 import com.evernote.edam.type.Resource;
\r
47 import com.evernote.edam.type.ResourceAttributes;
\r
48 import com.evernote.edam.type.Tag;
\r
49 import com.swabunga.spell.engine.Configuration;
\r
50 import com.swabunga.spell.engine.SpellDictionary;
\r
51 import com.swabunga.spell.engine.SpellDictionaryHashMap;
\r
52 import com.swabunga.spell.engine.Word;
\r
53 import com.swabunga.spell.event.SpellCheckEvent;
\r
54 import com.swabunga.spell.event.SpellCheckListener;
\r
55 import com.swabunga.spell.event.SpellChecker;
\r
56 import com.swabunga.spell.event.StringWordTokenizer;
\r
57 import com.trolltech.qt.core.QByteArray;
\r
58 import com.trolltech.qt.core.QCoreApplication;
\r
59 import com.trolltech.qt.core.QDataStream;
\r
60 import com.trolltech.qt.core.QDateTime;
\r
61 import com.trolltech.qt.core.QEvent;
\r
62 import com.trolltech.qt.core.QEvent.Type;
\r
63 import com.trolltech.qt.core.QFile;
\r
64 import com.trolltech.qt.core.QFileSystemWatcher;
\r
65 import com.trolltech.qt.core.QIODevice;
\r
66 import com.trolltech.qt.core.QMimeData;
\r
67 import com.trolltech.qt.core.QTextCodec;
\r
68 import com.trolltech.qt.core.QUrl;
\r
69 import com.trolltech.qt.core.Qt;
\r
70 import com.trolltech.qt.core.Qt.Key;
\r
71 import com.trolltech.qt.core.Qt.KeyboardModifier;
\r
72 import com.trolltech.qt.core.Qt.KeyboardModifiers;
\r
73 import com.trolltech.qt.gui.QAction;
\r
74 import com.trolltech.qt.gui.QApplication;
\r
75 import com.trolltech.qt.gui.QCalendarWidget;
\r
76 import com.trolltech.qt.gui.QClipboard;
\r
77 import com.trolltech.qt.gui.QClipboard.Mode;
\r
78 import com.trolltech.qt.gui.QColor;
\r
79 import com.trolltech.qt.gui.QComboBox;
\r
80 import com.trolltech.qt.gui.QDateEdit;
\r
81 import com.trolltech.qt.gui.QDesktopServices;
\r
82 import com.trolltech.qt.gui.QFileDialog;
\r
83 import com.trolltech.qt.gui.QFileDialog.AcceptMode;
\r
84 import com.trolltech.qt.gui.QFileDialog.FileMode;
\r
85 import com.trolltech.qt.gui.QFontDatabase;
\r
86 import com.trolltech.qt.gui.QFormLayout;
\r
87 import com.trolltech.qt.gui.QGridLayout;
\r
88 import com.trolltech.qt.gui.QHBoxLayout;
\r
89 import com.trolltech.qt.gui.QIcon;
\r
90 import com.trolltech.qt.gui.QImage;
\r
91 import com.trolltech.qt.gui.QKeyEvent;
\r
92 import com.trolltech.qt.gui.QKeySequence;
\r
93 import com.trolltech.qt.gui.QLabel;
\r
94 import com.trolltech.qt.gui.QLineEdit;
\r
95 import com.trolltech.qt.gui.QListWidgetItem;
\r
96 import com.trolltech.qt.gui.QMatrix;
\r
97 import com.trolltech.qt.gui.QMessageBox;
\r
98 import com.trolltech.qt.gui.QPalette;
\r
99 import com.trolltech.qt.gui.QPalette.ColorRole;
\r
100 import com.trolltech.qt.gui.QPushButton;
\r
101 import com.trolltech.qt.gui.QShortcut;
\r
102 import com.trolltech.qt.gui.QTimeEdit;
\r
103 import com.trolltech.qt.gui.QToolButton;
\r
104 import com.trolltech.qt.gui.QToolButton.ToolButtonPopupMode;
\r
105 import com.trolltech.qt.gui.QVBoxLayout;
\r
106 import com.trolltech.qt.gui.QWidget;
\r
107 import com.trolltech.qt.network.QNetworkAccessManager;
\r
108 import com.trolltech.qt.network.QNetworkReply;
\r
109 import com.trolltech.qt.network.QNetworkReply.NetworkError;
\r
110 import com.trolltech.qt.network.QNetworkRequest;
\r
111 import com.trolltech.qt.webkit.QWebPage;
\r
112 import com.trolltech.qt.webkit.QWebPage.WebAction;
\r
113 import com.trolltech.qt.webkit.QWebSettings;
\r
114 import com.trolltech.qt.webkit.QWebView;
\r
116 import cx.fbn.nevernote.Global;
\r
117 import cx.fbn.nevernote.dialog.EnCryptDialog;
\r
118 import cx.fbn.nevernote.dialog.EnDecryptDialog;
\r
119 import cx.fbn.nevernote.dialog.GeoDialog;
\r
120 import cx.fbn.nevernote.dialog.InsertLatexImage;
\r
121 import cx.fbn.nevernote.dialog.InsertLinkDialog;
\r
122 import cx.fbn.nevernote.dialog.SpellCheck;
\r
123 import cx.fbn.nevernote.dialog.TableDialog;
\r
124 import cx.fbn.nevernote.dialog.TagAssign;
\r
125 import cx.fbn.nevernote.evernote.EnCrypt;
\r
126 import cx.fbn.nevernote.filters.FilterEditorTags;
\r
127 import cx.fbn.nevernote.signals.NoteResourceSignal;
\r
128 import cx.fbn.nevernote.signals.NoteSignal;
\r
129 import cx.fbn.nevernote.sql.DatabaseConnection;
\r
130 import cx.fbn.nevernote.utilities.ApplicationLogger;
\r
131 import cx.fbn.nevernote.utilities.FileUtils;
\r
132 import cx.fbn.nevernote.utilities.Pair;
\r
133 import cx.fbn.nevernote.xml.HtmlTagModifier;
\r
135 public class BrowserWindow extends QWidget {
\r
137 public final QLineEdit titleLabel;
\r
138 private final QLineEdit urlText;
\r
139 private final QLabel authorLabel;
\r
140 private final QLineEdit authorText;
\r
141 private final QComboBox geoBox;
\r
142 public final TagLineEdit tagEdit;
\r
143 public final QLabel tagLabel;
\r
144 private final QPushButton urlLabel;
\r
145 private final QLabel alteredLabel;
\r
146 private final QDateEdit alteredDate;
\r
147 private final QTimeEdit alteredTime;
\r
148 private final QDateEdit createdDate;
\r
149 private final QTimeEdit createdTime;
\r
150 private final QLabel subjectLabel;
\r
151 private final QDateEdit subjectDate;
\r
152 private final QTimeEdit subjectTime;
\r
153 public final QComboBox notebookBox;
\r
154 private final QLabel notebookLabel;
\r
155 private final QLabel createdLabel;
\r
156 public final QComboBox fontSize;
\r
157 public final QAction fontSizeAction;
\r
158 private boolean extendedOn;
\r
159 public boolean buttonsVisible;
\r
160 private final String iconPath = new String("classpath:cx/fbn/nevernote/icons/");
\r
161 private final ContentView browser;
\r
162 private List<Tag> allTags;
\r
163 private List<String> currentTags;
\r
164 public NoteSignal noteSignal;
\r
165 private List<Notebook> notebookList;
\r
166 private Note currentNote;
\r
167 private String saveNoteTitle;
\r
168 private String saveTagList;
\r
169 private boolean insideList;
\r
170 private final DatabaseConnection conn;
\r
171 private final QCalendarWidget createdCalendarWidget;
\r
172 private final QCalendarWidget alteredCalendarWidget;
\r
173 private final QCalendarWidget subjectCalendarWidget;
\r
175 public final QPushButton undoButton;
\r
176 public final QAction undoAction;
\r
177 public final QPushButton redoButton;
\r
178 public final QAction redoAction;
\r
179 public final QPushButton cutButton;
\r
180 public final QAction cutAction;
\r
181 public final QPushButton copyButton;
\r
182 public final QAction copyAction;
\r
183 public final QPushButton pasteButton;
\r
184 public final QAction pasteAction;
\r
185 public final QPushButton boldButton;
\r
186 public final QAction boldAction;
\r
187 public final QPushButton underlineButton;
\r
188 public final QAction underlineAction;
\r
189 public final QPushButton italicButton;
\r
190 public final QAction italicAction;
\r
191 public final Signal0 focusLost;
\r
192 public final NoteResourceSignal resourceSignal;
\r
194 public QPushButton rightAlignButton;
\r
195 public final QAction rightAlignAction;
\r
196 public QPushButton leftAlignButton;
\r
197 public final QAction leftAlignAction;
\r
198 public QPushButton centerAlignButton;
\r
199 public final QAction centerAlignAction;
\r
201 public final QPushButton strikethroughButton;
\r
202 public final QAction strikethroughAction;
\r
203 public final QPushButton hlineButton;
\r
204 public final QAction hlineAction;
\r
205 public final QPushButton indentButton;
\r
206 public final QAction indentAction;
\r
207 public final QPushButton outdentButton;
\r
208 public final QAction outdentAction;
\r
209 public final QPushButton bulletListButton;
\r
210 public final QAction bulletListAction;
\r
211 public final QPushButton numberListButton;
\r
212 public final QAction numberListAction;
\r
213 public final QPushButton spellCheckButton;
\r
214 public final QAction spellCheckAction;
\r
215 public final QPushButton todoButton;
\r
216 public final QAction todoAction;
\r
218 public final QShortcut focusTitleShortcut;
\r
219 public final QShortcut focusTagShortcut;
\r
220 public final QShortcut focusNoteShortcut;
\r
221 public final QShortcut focusUrlShortcut;
\r
222 public final QShortcut focusAuthorShortcut;
\r
224 public EditorButtonBar buttonLayout;
\r
225 public final QComboBox fontList;
\r
226 public final QAction fontListAction;
\r
227 public final QToolButton fontColor;
\r
228 public final QAction fontColorAction;
\r
229 private final ColorMenu fontColorMenu;
\r
230 public final QToolButton fontHilight;
\r
231 public final QAction fontHilightAction;
\r
232 private final ColorMenu fontHilightColorMenu;
\r
233 public final QFileSystemWatcher fileWatcher;
\r
234 public int cursorPosition;
\r
235 private boolean forceTextPaste = false;
\r
236 private String selectedFile;
\r
237 private String currentHyperlink;
\r
238 public boolean keepPDFNavigationHidden;
\r
239 private final ApplicationLogger logger;
\r
240 SpellDictionary dictionary;
\r
241 SpellDictionary userDictionary;
\r
242 SpellChecker spellChecker;
\r
243 SuggestionListener spellListener;
\r
244 private final HashMap<String,Integer> previewPageList;
\r
245 boolean insertHyperlink = true;
\r
246 boolean insideTable = false;
\r
247 boolean insideEncryption = false;
\r
248 public Signal1<BrowserWindow> blockApplication;
\r
249 public Signal0 unblockApplication;
\r
250 public boolean awaitingHttpResponse;
\r
251 public long unblockTime;
\r
252 String latexGuid; // This is set if we are editing an existing LaTeX formula. Useful to track guid.
\r
255 public static class SuggestionListener implements SpellCheckListener {
\r
256 public boolean abortSpellCheck = false;
\r
257 public boolean errorsFound = false;
\r
258 private final SpellCheck spellCheckDialog;
\r
261 private final BrowserWindow parent;
\r
262 public SuggestionListener(BrowserWindow parent, SpellChecker checker) {
\r
263 this.parent = parent;
\r
264 spellCheckDialog = new SpellCheck(checker);
\r
266 public void spellingError(SpellCheckEvent event) {
\r
267 errorsFound = true;
\r
268 spellCheckDialog.setWord(event.getInvalidWord());
\r
270 @SuppressWarnings("unchecked")
\r
271 List<Word> suggestions = event.getSuggestions();
\r
272 spellCheckDialog.clearSuggestions();
\r
273 if (!suggestions.isEmpty()) {
\r
274 // spellCheckDialog.setCurrentSuggestion(suggestions.get(0).getWord());
\r
275 for (int i=0; i<suggestions.size(); i++) {
\r
276 spellCheckDialog.addSuggestion(suggestions.get(i).getWord());
\r
278 spellCheckDialog.setSelectedSuggestion(0);
\r
280 spellCheckDialog.exec();
\r
281 if (spellCheckDialog.cancelPressed()) {
\r
282 abortSpellCheck = true;
\r
286 if (spellCheckDialog.replacePressed()) {
\r
287 QClipboard clipboard = QApplication.clipboard();
\r
288 clipboard.setText(spellCheckDialog.getReplacementWord());
\r
289 parent.pasteClicked();
\r
297 public BrowserWindow(DatabaseConnection c) {
\r
298 logger = new ApplicationLogger("browser.log");
\r
299 logger.log(logger.HIGH, "Setting up browser");
\r
301 fileWatcher = new QFileSystemWatcher();
\r
302 // fileWatcher.fileChanged.connect(this, "fileChanged(String)");
\r
303 noteSignal = new NoteSignal();
\r
304 titleLabel = new QLineEdit();
\r
305 titleLabel.setMaxLength(Constants.EDAM_NOTE_TITLE_LEN_MAX);
\r
306 urlText = new QLineEdit();
\r
307 authorText = new QLineEdit();
\r
308 geoBox = new QComboBox();
\r
309 urlLabel = new QPushButton();
\r
310 urlLabel.clicked.connect(this, "sourceUrlClicked()");
\r
311 authorLabel = new QLabel();
\r
314 focusLost = new Signal0();
\r
316 tagEdit = new TagLineEdit(allTags);
\r
317 tagLabel = new QLabel("Tags:");
\r
318 tagEdit.focusLost.connect(this, "modifyTagsTyping()");
\r
320 createdCalendarWidget = new QCalendarWidget();
\r
321 createdDate = new QDateEdit();
\r
322 createdDate.setDisplayFormat(Global.getDateFormat());
\r
323 createdDate.setCalendarPopup(true);
\r
324 createdDate.setCalendarWidget(createdCalendarWidget);
\r
325 createdTime = new QTimeEdit();
\r
326 createdDate.dateChanged.connect(this, "createdChanged()");
\r
327 createdTime.timeChanged.connect(this, "createdChanged()");
\r
329 alteredCalendarWidget = new QCalendarWidget();
\r
330 alteredDate = new QDateEdit();
\r
331 alteredDate.setDisplayFormat(Global.getDateFormat());
\r
332 alteredDate.setCalendarPopup(true);
\r
333 alteredDate.setCalendarWidget(alteredCalendarWidget);
\r
334 alteredTime = new QTimeEdit();
\r
335 alteredLabel = new QLabel("Altered:");
\r
336 alteredDate.dateChanged.connect(this, "alteredChanged()");
\r
337 alteredTime.timeChanged.connect(this, "alteredChanged()");
\r
339 subjectCalendarWidget = new QCalendarWidget();
\r
340 subjectDate = new QDateEdit();
\r
341 subjectDate.setDisplayFormat(Global.getDateFormat());
\r
342 subjectDate.setCalendarPopup(true);
\r
343 subjectDate.setCalendarWidget(subjectCalendarWidget);
\r
344 subjectTime = new QTimeEdit();
\r
345 subjectLabel = new QLabel(tr("Subject Date:"));
\r
346 subjectDate.dateChanged.connect(this, "subjectDateTimeChanged()");
\r
347 subjectTime.timeChanged.connect(this, "subjectDateTimeChanged()");
\r
348 authorText.textChanged.connect(this, "authorChanged()");
\r
349 urlText.textChanged.connect(this, "sourceUrlChanged()");
\r
351 notebookBox = new QComboBox();
\r
352 notebookLabel = new QLabel(tr("Notebook"));
\r
353 createdLabel = new QLabel(tr("Created:"));
\r
354 // selectedText = new String();
\r
356 urlLabel.setVisible(false);
\r
357 urlText.setVisible(false);
\r
358 authorLabel.setVisible(false);
\r
360 geoBox.setVisible(false);
\r
361 geoBox.addItem(new QIcon(iconPath+"globe.png"), "");
\r
362 geoBox.addItem(new String(tr("Set")));
\r
363 geoBox.addItem(new String(tr("Clear")));
\r
364 geoBox.addItem(new String(tr("View On Map")));
\r
365 geoBox.activated.connect(this, "geoBoxChanged()");
\r
367 authorText.setVisible(false);
\r
368 createdDate.setVisible(false);
\r
369 alteredLabel.setVisible(false);
\r
370 //notebookBox.setVisible(false);
\r
371 notebookLabel.setVisible(false);
\r
372 createdLabel.setVisible(false);
\r
373 createdTime.setVisible(false);
\r
374 alteredDate.setVisible(false);
\r
375 alteredTime.setVisible(false);
\r
376 subjectLabel.setVisible(false);
\r
377 subjectDate.setVisible(false);
\r
378 subjectTime.setVisible(false);
\r
379 extendedOn = false;
\r
380 buttonsVisible = true;
\r
381 setAcceptDrops(true);
\r
383 browser = new ContentView(this);
\r
384 browser.page().setLinkDelegationPolicy(
\r
385 QWebPage.LinkDelegationPolicy.DelegateAllLinks);
\r
386 browser.linkClicked.connect(this, "linkClicked(QUrl)");
\r
387 currentHyperlink = "";
\r
389 QVBoxLayout v = new QVBoxLayout();
\r
390 QFormLayout notebookLayout = new QFormLayout();
\r
391 QGridLayout dateLayout = new QGridLayout();
\r
392 titleLabel.setReadOnly(false);
\r
393 titleLabel.editingFinished.connect(this, "titleEdited()");
\r
394 browser.page().contentsChanged.connect(this, "contentChanged()");
\r
395 browser.page().selectionChanged.connect(this, "selectionChanged()");
\r
396 browser.page().mainFrame().javaScriptWindowObjectCleared.connect(this,
\r
397 "exposeToJavascript()");
\r
399 notebookBox.activated.connect(this, "notebookChanged()");
\r
400 resourceSignal = new NoteResourceSignal();
\r
402 QHBoxLayout tagLayout = new QHBoxLayout();
\r
403 v.addWidget(titleLabel, 0);
\r
404 notebookLayout.addRow(notebookLabel, notebookBox);
\r
405 tagLayout.addLayout(notebookLayout, 0);
\r
406 tagLayout.stretch(4);
\r
407 tagLayout.addWidget(tagLabel, 0);
\r
408 tagLayout.addWidget(tagEdit, 1);
\r
409 v.addLayout(tagLayout);
\r
411 QHBoxLayout urlLayout = new QHBoxLayout();
\r
412 urlLayout.addWidget(urlLabel, 0);
\r
413 urlLayout.addWidget(urlText, 0);
\r
414 v.addLayout(urlLayout);
\r
416 QHBoxLayout authorLayout = new QHBoxLayout();
\r
417 authorLayout.addWidget(authorLabel, 0);
\r
418 authorLayout.addWidget(authorText, 0);
\r
419 authorLayout.addWidget(geoBox);
\r
420 v.addLayout(authorLayout);
\r
422 dateLayout.addWidget(createdLabel, 0, 0);
\r
423 dateLayout.addWidget(createdDate, 0, 1);
\r
424 dateLayout.addWidget(createdTime, 0, 2);
\r
425 dateLayout.setColumnStretch(9, 100);
\r
426 dateLayout.addWidget(alteredLabel, 0, 3);
\r
427 dateLayout.addWidget(alteredDate, 0, 4);
\r
428 dateLayout.addWidget(alteredTime, 0, 5);
\r
429 dateLayout.addWidget(subjectLabel, 0, 6);
\r
430 dateLayout.addWidget(subjectDate, 0, 7);
\r
431 dateLayout.addWidget(subjectTime, 0, 8);
\r
432 v.addLayout(dateLayout, 0);
\r
434 undoButton = newEditorButton("undo", tr("Undo Change"));
\r
435 redoButton = newEditorButton("redo", tr("Redo Change"));
\r
436 cutButton = newEditorButton("cut", tr("Cut"));
\r
437 copyButton = newEditorButton("copy", tr("Copy"));
\r
438 pasteButton = newEditorButton("paste", tr("Paste"));
\r
439 boldButton = newEditorButton("bold", tr("Bold"));
\r
440 underlineButton = newEditorButton("underline", tr("Underline"));
\r
441 italicButton = newEditorButton("italic", tr("Italic"));
\r
443 rightAlignButton = newEditorButton("justifyRight", tr("Right Align"));
\r
444 leftAlignButton = newEditorButton("justifyLeft", tr("Left Align"));
\r
445 centerAlignButton = newEditorButton("justifyCenter", tr("Center Align"));
\r
447 strikethroughButton = newEditorButton("strikethrough", tr("Strikethrough"));
\r
448 hlineButton = newEditorButton("hline", tr("Insert Horizontal Line"));
\r
449 indentButton = newEditorButton("indent", tr("Shift Right"));
\r
450 outdentButton = newEditorButton("outdent", tr("Shift Left"));
\r
451 bulletListButton = newEditorButton("bulletList", tr("Bullet List"));
\r
452 numberListButton = newEditorButton("numberList", tr("Number List"));
\r
453 spellCheckButton = newEditorButton("spellCheck", tr("Spell Check"));
\r
454 todoButton = newEditorButton("todo", tr("To-do"));
\r
457 buttonLayout = new EditorButtonBar();
\r
458 v.addWidget(buttonLayout);
\r
460 undoAction = buttonLayout.addWidget(undoButton);
\r
461 buttonLayout.toggleUndoVisible.triggered.connect(this, "toggleUndoVisible(Boolean)");
\r
462 redoAction = buttonLayout.addWidget(redoButton);
\r
463 buttonLayout.toggleRedoVisible.triggered.connect(this, "toggleRedoVisible(Boolean)");
\r
465 buttonLayout.addWidget(newSeparator());
\r
466 cutAction = buttonLayout.addWidget(cutButton);
\r
467 buttonLayout.toggleCutVisible.triggered.connect(this, "toggleCutVisible(Boolean)");
\r
468 copyAction = buttonLayout.addWidget(copyButton);
\r
469 buttonLayout.toggleCopyVisible.triggered.connect(this, "toggleCopyVisible(Boolean)");
\r
470 pasteAction = buttonLayout.addWidget(pasteButton);
\r
471 buttonLayout.togglePasteVisible.triggered.connect(this, "togglePasteVisible(Boolean)");
\r
473 buttonLayout.addWidget(newSeparator());
\r
474 boldAction = buttonLayout.addWidget(boldButton);
\r
475 buttonLayout.toggleBoldVisible.triggered.connect(this, "toggleBoldVisible(Boolean)");
\r
476 italicAction = buttonLayout.addWidget(italicButton);
\r
477 buttonLayout.toggleItalicVisible.triggered.connect(this, "toggleItalicVisible(Boolean)");
\r
478 underlineAction = buttonLayout.addWidget(underlineButton);
\r
479 buttonLayout.toggleUnderlineVisible.triggered.connect(this, "toggleUnderlineVisible(Boolean)");
\r
480 strikethroughAction = buttonLayout.addWidget(strikethroughButton);
\r
481 buttonLayout.toggleStrikethroughVisible.triggered.connect(this, "toggleStrikethroughVisible(Boolean)");
\r
484 buttonLayout.addWidget(newSeparator());
\r
485 leftAlignAction = buttonLayout.addWidget(leftAlignButton);
\r
486 buttonLayout.toggleLeftAlignVisible.triggered.connect(this, "toggleLeftAlignVisible(Boolean)");
\r
487 centerAlignAction = buttonLayout.addWidget(centerAlignButton);
\r
488 buttonLayout.toggleCenterAlignVisible.triggered.connect(this, "toggleCenterAlignVisible(Boolean)");
\r
489 rightAlignAction = buttonLayout.addWidget(rightAlignButton);
\r
490 buttonLayout.toggleRightAlignVisible.triggered.connect(this, "toggleRightAlignVisible(Boolean)");
\r
492 buttonLayout.addWidget(newSeparator());
\r
493 hlineAction = buttonLayout.addWidget(hlineButton);
\r
494 buttonLayout.toggleHLineVisible.triggered.connect(this, "toggleHLineVisible(Boolean)");
\r
496 indentAction = buttonLayout.addWidget(indentButton);
\r
497 buttonLayout.toggleIndentVisible.triggered.connect(this, "toggleIndentVisible(Boolean)");
\r
498 outdentAction = buttonLayout.addWidget(outdentButton);
\r
499 buttonLayout.toggleOutdentVisible.triggered.connect(this, "toggleOutdentVisible(Boolean)");
\r
500 bulletListAction = buttonLayout.addWidget(bulletListButton);
\r
501 buttonLayout.toggleBulletListVisible.triggered.connect(this, "toggleBulletListVisible(Boolean)");
\r
502 numberListAction = buttonLayout.addWidget(numberListButton);
\r
503 buttonLayout.toggleNumberListVisible.triggered.connect(this, "toggleNumberListVisible(Boolean)");
\r
505 // Setup the font & font size combo boxes
\r
506 buttonLayout.addWidget(newSeparator());
\r
507 fontList = new QComboBox();
\r
508 fontSize = new QComboBox();
\r
509 fontList.setToolTip("Font");
\r
510 fontSize.setToolTip("Font Size");
\r
511 fontList.activated.connect(this, "fontChanged(String)");
\r
512 fontSize.activated.connect(this, "fontSizeChanged(String)");
\r
513 fontListAction = buttonLayout.addWidget(fontList);
\r
514 buttonLayout.toggleFontVisible.triggered.connect(this, "toggleFontListVisible(Boolean)");
\r
515 fontSizeAction = buttonLayout.addWidget(fontSize);
\r
516 buttonLayout.toggleFontSizeVisible.triggered.connect(this, "toggleFontSizeVisible(Boolean)");
\r
517 QFontDatabase fonts = new QFontDatabase();
\r
518 List<String> fontFamilies = fonts.families();
\r
519 for (int i = 0; i < fontFamilies.size(); i++) {
\r
520 fontList.addItem(fontFamilies.get(i));
\r
522 loadFontSize(fontFamilies.get(i));
\r
526 // buttonLayout.addWidget(newSeparator(), 0);
\r
527 fontColor = newToolButton("fontColor", tr("Font Color"));
\r
528 fontColorMenu = new ColorMenu(this);
\r
529 fontColor.setMenu(fontColorMenu.getMenu());
\r
530 fontColor.setPopupMode(ToolButtonPopupMode.MenuButtonPopup);
\r
531 fontColor.setAutoRaise(false);
\r
532 fontColorMenu.getMenu().triggered.connect(this, "fontColorClicked()");
\r
533 fontColorAction = buttonLayout.addWidget(fontColor);
\r
534 buttonLayout.toggleFontColorVisible.triggered.connect(this, "toggleFontColorVisible(Boolean)");
\r
535 fontHilight = newToolButton("fontHilight", tr("Font Hilight Color"));
\r
536 fontHilight.setPopupMode(ToolButtonPopupMode.MenuButtonPopup);
\r
537 fontHilight.setAutoRaise(false);
\r
538 fontHilightColorMenu = new ColorMenu(this);
\r
539 fontHilightColorMenu.setDefault(QColor.yellow);
\r
540 fontHilight.setMenu(fontHilightColorMenu.getMenu());
\r
541 fontHilightColorMenu.getMenu().triggered.connect(this, "fontHilightClicked()");
\r
542 fontHilightAction = buttonLayout.addWidget(fontHilight);
\r
543 fontHilightColorMenu.setDefault(QColor.yellow);
\r
544 buttonLayout.toggleFontHilight.triggered.connect(this, "toggleFontHilightVisible(Boolean)");
\r
546 spellCheckAction = buttonLayout.addWidget(spellCheckButton);
\r
547 buttonLayout.toggleNumberListVisible.triggered.connect(this, "spellCheckClicked()");
\r
548 buttonLayout.toggleSpellCheck.triggered.connect(this, "toggleSpellCheckVisible(Boolean)");
\r
550 todoAction = buttonLayout.addWidget(todoButton);
\r
551 buttonLayout.toggleNumberListVisible.triggered.connect(this, "todoClicked()");
\r
552 buttonLayout.toggleTodo.triggered.connect(this, "toggleTodoVisible(Boolean)");
\r
555 // buttonLayout.addWidget(new QLabel(), 1);
\r
556 v.addWidget(browser, 1);
\r
559 browser.downloadAttachmentRequested.connect(this,
\r
560 "downloadAttachment(QNetworkRequest)");
\r
561 browser.downloadImageRequested.connect(this,
\r
562 "downloadImage(QNetworkRequest)");
\r
563 setTabOrder(notebookBox, tagEdit);
\r
564 setTabOrder(tagEdit, browser);
\r
566 focusNoteShortcut = new QShortcut(this);
\r
567 setupShortcut(focusNoteShortcut, "Focus_Note");
\r
568 focusNoteShortcut.activated.connect(this, "focusNote()");
\r
569 focusTitleShortcut = new QShortcut(this);
\r
570 setupShortcut(focusTitleShortcut, "Focus_Title");
\r
571 focusTitleShortcut.activated.connect(this, "focusTitle()");
\r
572 focusTagShortcut = new QShortcut(this);
\r
573 setupShortcut(focusTagShortcut, "Focus_Tag");
\r
574 focusTagShortcut.activated.connect(this, "focusTag()");
\r
575 focusAuthorShortcut = new QShortcut(this);
\r
576 setupShortcut(focusAuthorShortcut, "Focus_Author");
\r
577 focusAuthorShortcut.activated.connect(this, "focusAuthor()");
\r
578 focusUrlShortcut = new QShortcut(this);
\r
579 setupShortcut(focusUrlShortcut, "Focus_Url");
\r
580 focusUrlShortcut.activated.connect(this, "focusUrl()");
\r
582 browser.page().mainFrame().setTextSizeMultiplier(Global.getTextSizeMultiplier());
\r
583 browser.page().mainFrame().setZoomFactor(Global.getZoomFactor());
\r
585 previewPageList = new HashMap<String,Integer>();
\r
587 browser.page().microFocusChanged.connect(this, "microFocusChanged()");
\r
591 QPalette pal = new QPalette();
\r
592 pal.setColor(ColorRole.Text, QColor.black);
\r
593 titleLabel.setPalette(pal);
\r
594 authorText.setPalette(pal);
\r
595 authorLabel.setPalette(pal);
\r
596 urlLabel.setPalette(pal);
\r
597 urlText.setPalette(pal);
\r
598 createdDate.setPalette(pal);
\r
599 createdTime.setPalette(pal);
\r
600 alteredDate.setPalette(pal);
\r
601 alteredTime.setPalette(pal);
\r
602 subjectDate.setPalette(pal);
\r
603 subjectTime.setPalette(pal);
\r
604 tagEdit.setPalette(pal);
\r
605 notebookBox.setPalette(pal);
\r
607 blockApplication = new Signal1<BrowserWindow>();
\r
608 unblockApplication = new Signal0();
\r
610 logger.log(logger.HIGH, "Browser setup complete");
\r
615 private void setupShortcut(QShortcut action, String text) {
\r
616 if (!Global.shortcutKeys.containsAction(text))
\r
618 action.setKey(new QKeySequence(Global.shortcutKeys.getShortcut(text)));
\r
624 // Getter for the QWebView
\r
625 public QWebView getBrowser() {
\r
629 // Block signals while loading data or things are flagged as dirty by
\r
631 public void loadingData(boolean val) {
\r
632 logger.log(logger.EXTREME, "Entering BrowserWindow.loadingData() " +val);
\r
633 notebookBox.blockSignals(val);
\r
634 browser.page().blockSignals(val);
\r
635 browser.page().mainFrame().blockSignals(val);
\r
636 titleLabel.blockSignals(val);
\r
637 alteredDate.blockSignals(val);
\r
638 alteredTime.blockSignals(val);
\r
639 createdTime.blockSignals(val);
\r
640 createdDate.blockSignals(val);
\r
641 subjectDate.blockSignals(val);
\r
642 subjectTime.blockSignals(val);
\r
643 urlText.blockSignals(val);
\r
644 authorText.blockSignals(val);
\r
646 exposeToJavascript();
\r
647 logger.log(logger.EXTREME, "Exiting BrowserWindow.loadingData() " +val);
\r
651 public void setReadOnly(boolean v) {
\r
653 titleLabel.setEnabled(!v);
\r
654 notebookBox.setEnabled(!v);
\r
655 tagEdit.setEnabled(!v);
\r
656 authorLabel.setEnabled(!v);
\r
657 geoBox.setEnabled(!v);
\r
658 urlText.setEnabled(!v);
\r
659 createdDate.setEnabled(!v);
\r
660 subjectDate.setEnabled(!v);
\r
661 alteredDate.setEnabled(!v);
\r
662 authorText.setEnabled(!v);
\r
663 createdTime.setEnabled(!v);
\r
664 alteredTime.setEnabled(!v);
\r
665 subjectTime.setEnabled(!v);
\r
666 getBrowser().setEnabled(true);
\r
667 // getBrowser().setEnabled(!v);
\r
670 // expose this class to Javascript on the web page
\r
671 private void exposeToJavascript() {
\r
672 browser.page().mainFrame().addToJavaScriptWindowObject("jambi", this);
\r
675 // Custom event queue
\r
677 public boolean event(QEvent e) {
\r
678 if (e.type().equals(QEvent.Type.FocusOut)) {
\r
679 logger.log(logger.EXTREME, "Focus lost");
\r
682 return super.event(e);
\r
685 // clear out browser
\r
686 public void clear() {
\r
687 logger.log(logger.EXTREME, "Entering BrowserWindow.clear()");
\r
689 browser.setContent(new QByteArray());
\r
690 tagEdit.setText("");
\r
691 tagEdit.tagCompleter.reset();
\r
692 urlLabel.setText(tr("Source URL:"));
\r
693 titleLabel.setText("");
\r
694 logger.log(logger.EXTREME, "Exiting BrowserWindow.clear()");
\r
697 // get/set current note
\r
698 public void setNote(Note n) {
\r
702 saveNoteTitle = n.getTitle();
\r
706 public Note getNote() {
\r
707 return currentNote;
\r
710 // New Editor Button
\r
711 private QPushButton newEditorButton(String name, String toolTip) {
\r
712 QPushButton button = new QPushButton();
\r
713 // QIcon icon = new QIcon(iconPath + name + ".gif");
\r
714 QIcon icon = new QIcon(iconPath + name + ".png");
\r
715 button.setIcon(icon);
\r
716 button.setToolTip(toolTip);
\r
717 button.clicked.connect(this, name + "Clicked()");
\r
720 // New Editor Button
\r
721 private QToolButton newToolButton(String name, String toolTip) {
\r
722 QToolButton button = new QToolButton();
\r
723 // QIcon icon = new QIcon(iconPath + name + ".gif");
\r
724 QIcon icon = new QIcon(iconPath + name + ".png");
\r
725 button.setIcon(icon);
\r
726 button.setToolTip(toolTip);
\r
727 button.clicked.connect(this, name + "Clicked()");
\r
732 private QLabel newSeparator() {
\r
733 return new QLabel(" ");
\r
736 // Set the title in the window
\r
737 public void setTitle(String t) {
\r
738 titleLabel.setText(t);
\r
743 // Return the current text title
\r
744 public String getTitle() {
\r
745 return titleLabel.text();
\r
748 // Set the tag name string
\r
749 public void setTag(String t) {
\r
751 tagEdit.setText(t);
\r
752 tagEdit.tagCompleter.reset();
\r
755 // Set the source URL
\r
756 public void setUrl(String t) {
\r
757 urlLabel.setText(tr("Source URL:\t"));
\r
758 urlText.setText(t);
\r
761 // The user want's to launch a web browser on the source of the URL
\r
762 public void sourceUrlClicked() {
\r
763 // Make sure we have a valid URL
\r
764 if (urlText.text().trim().equals(""))
\r
767 String url = urlText.text();
\r
768 if (!url.toLowerCase().startsWith(tr("http://")))
\r
769 url = tr("http://") +url;
\r
771 if (!QDesktopServices.openUrl(new QUrl(url))) {
\r
772 logger.log(logger.LOW, "Error opening file :" +url);
\r
776 public void setAuthor(String t) {
\r
777 authorLabel.setText(tr("Author:\t"));
\r
778 authorText.setText(t);
\r
781 // Set the creation date
\r
782 public void setCreation(long date) {
\r
783 QDateTime dt = new QDateTime();
\r
784 dt.setTime_t((int) (date / 1000));
\r
785 createdDate.setDateTime(dt);
\r
786 createdTime.setDateTime(dt);
\r
787 createdDate.setDisplayFormat(Global.getDateFormat());
\r
788 createdTime.setDisplayFormat(Global.getTimeFormat());
\r
791 // Set the creation date
\r
792 public void setAltered(long date) {
\r
793 QDateTime dt = new QDateTime();
\r
794 dt.setTime_t((int) (date / 1000));
\r
795 alteredDate.setDateTime(dt);
\r
796 alteredTime.setDateTime(dt);
\r
797 alteredDate.setDisplayFormat(Global.getDateFormat());
\r
798 alteredTime.setDisplayFormat(Global.getTimeFormat());
\r
801 // Set the subject date
\r
802 public void setSubjectDate(long date) {
\r
803 QDateTime dt = new QDateTime();
\r
804 dt.setTime_t((int) (date / 1000));
\r
805 subjectDate.setDateTime(dt);
\r
806 subjectTime.setDateTime(dt);
\r
807 subjectDate.setDisplayFormat(Global.getDateFormat());
\r
808 subjectTime.setDisplayFormat(Global.getTimeFormat());
\r
811 // Toggle the extended attribute information
\r
812 public void toggleInformation() {
\r
814 extendedOn = false;
\r
818 urlLabel.setVisible(extendedOn);
\r
819 urlText.setVisible(extendedOn);
\r
820 authorText.setVisible(extendedOn);
\r
821 geoBox.setVisible(extendedOn);
\r
822 authorLabel.setVisible(extendedOn);
\r
823 createdDate.setVisible(extendedOn);
\r
824 createdTime.setVisible(extendedOn);
\r
825 createdLabel.setVisible(extendedOn);
\r
826 alteredLabel.setVisible(extendedOn);
\r
827 alteredDate.setVisible(extendedOn);
\r
828 alteredTime.setVisible(extendedOn);
\r
829 //notebookBox.setVisible(extendedOn);
\r
830 notebookLabel.setVisible(extendedOn);
\r
831 subjectLabel.setVisible(extendedOn);
\r
832 subjectDate.setVisible(extendedOn);
\r
833 subjectTime.setVisible(extendedOn);
\r
836 public void hideButtons() {
\r
838 undoButton.parentWidget().setVisible(false);
\r
839 buttonsVisible = false;
\r
843 // Is the extended view on?
\r
844 public boolean isExtended() {
\r
848 // Listener for when a link is clicked
\r
849 @SuppressWarnings("unused")
\r
850 private void openFile() {
\r
851 logger.log(logger.EXTREME, "Starting openFile()");
\r
852 File fileHandle = new File(selectedFile);
\r
853 URI fileURL = fileHandle.toURI();
\r
854 String localURL = fileURL.toString();
\r
855 QUrl url = new QUrl(localURL);
\r
856 QFile file = new QFile(selectedFile);
\r
858 logger.log(logger.EXTREME, "Adding to fileWatcher:"+file.fileName());
\r
859 fileWatcher.addPath(file.fileName());
\r
861 if (!QDesktopServices.openUrl(url)) {
\r
862 logger.log(logger.LOW, "Error opening file :" +url);
\r
867 // Listener for when a link is clicked
\r
868 @SuppressWarnings("unused")
\r
869 private void linkClicked(QUrl url) {
\r
870 logger.log(logger.EXTREME, "URL Clicked: " +url.toString());
\r
871 if (url.toString().startsWith("latex:")) {
\r
872 int position = url.toString().lastIndexOf(".");
\r
873 String guid = url.toString().substring(0,position);
\r
874 position = guid.lastIndexOf("/");
\r
875 guid = guid.substring(position+1);
\r
879 if (url.toString().startsWith("nnres://")) {
\r
880 logger.log(logger.EXTREME, "URL is NN resource");
\r
881 if (url.toString().endsWith("/vnd.evernote.ink")) {
\r
882 logger.log(logger.EXTREME, "Unable to open ink note");
\r
883 QMessageBox.information(this, tr("Unable Open"), tr("This is an ink note.\n"+
\r
884 "Ink notes are not supported since Evernote has not\n published any specifications on them\n" +
\r
885 "and I'm too lazy to figure them out by myself."));
\r
888 String fullName = url.toString().substring(8);
\r
889 int index = fullName.indexOf(".");
\r
893 type = fullName.substring(index+1);
\r
894 guid = fullName.substring(0,index);
\r
896 index = guid.indexOf(Global.attachmentNameDelimeter);
\r
898 guid = guid.substring(0,index);
\r
900 List<Resource> resList = currentNote.getResources();
\r
901 Resource res = null;
\r
902 for (int i=0; i<resList.size(); i++) {
\r
903 if (resList.get(i).getGuid().equals(guid)) {
\r
904 res = resList.get(i);
\r
909 String resGuid = Global.resourceMap.get(guid);
\r
910 if (resGuid != null)
\r
911 res = conn.getNoteTable().noteResourceTable.getNoteResource(resGuid, true);
\r
915 if (res.getAttributes() != null &&
\r
916 res.getAttributes().getFileName() != null &&
\r
917 !res.getAttributes().getFileName().trim().equals(""))
\r
918 fileName = res.getGuid()+Global.attachmentNameDelimeter+res.getAttributes().getFileName();
\r
920 fileName = res.getGuid()+"."+type;
\r
921 QFile file = new QFile(Global.getFileManager().getResDirPath(fileName));
\r
922 QFile.OpenMode mode = new QFile.OpenMode();
\r
923 mode.set(QFile.OpenModeFlag.WriteOnly);
\r
924 boolean openResult = file.open(mode);
\r
925 logger.log(logger.EXTREME, "File opened:" +openResult);
\r
926 QDataStream out = new QDataStream(file);
\r
927 Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(res.getGuid(), true);
\r
928 QByteArray binData = new QByteArray(resBinary.getData().getBody());
\r
930 logger.log(logger.EXTREME, "Writing resource");
\r
931 out.writeBytes(binData.toByteArray());
\r
934 String whichOS = System.getProperty("os.name");
\r
935 if (whichOS.contains("Windows"))
\r
936 url.setUrl("file:///"+file.fileName());
\r
938 url.setUrl("file://"+file.fileName());
\r
939 // fileWatcher.removePath(file.fileName());
\r
940 logger.log(logger.EXTREME, "Adding file watcher " +file.fileName());
\r
941 fileWatcher.addPath(file.fileName());
\r
943 // If we can't open it, then prompt the user to save it.
\r
944 if (!QDesktopServices.openUrl(url)) {
\r
945 logger.log(logger.EXTREME, "We can't handle this. Where do we put it?");
\r
946 QFileDialog dialog = new QFileDialog();
\r
948 if (dialog.exec()!=0) {
\r
949 List<String> fileNames = dialog.selectedFiles(); //gets all selected filenames
\r
950 if (fileNames.size() == 0)
\r
952 String sf = fileNames.get(0);
\r
953 QFile saveFile = new QFile(sf);
\r
954 mode.set(QFile.OpenModeFlag.WriteOnly);
\r
955 saveFile.open(mode);
\r
956 QDataStream saveOut = new QDataStream(saveFile);
\r
957 saveOut.writeBytes(binData.toByteArray());
\r
965 logger.log(logger.EXTREME, "Launching URL");
\r
966 QDesktopServices.openUrl(url);
\r
969 // Listener for when BOLD is clicked
\r
970 @SuppressWarnings("unused")
\r
971 private void undoClicked() {
\r
972 browser.page().triggerAction(WebAction.Undo);
\r
973 browser.setFocus();
\r
976 // Listener for when BOLD is clicked
\r
977 @SuppressWarnings("unused")
\r
978 private void redoClicked() {
\r
979 browser.page().triggerAction(WebAction.Redo);
\r
980 browser.setFocus();
\r
983 // Listener for when BOLD is clicked
\r
984 @SuppressWarnings("unused")
\r
985 private void boldClicked() {
\r
986 browser.page().triggerAction(WebAction.ToggleBold);
\r
987 microFocusChanged();
\r
988 browser.setFocus();
\r
991 // Listener for when Italics is clicked
\r
992 @SuppressWarnings("unused")
\r
993 private void italicClicked() {
\r
994 browser.page().triggerAction(WebAction.ToggleItalic);
\r
995 microFocusChanged();
\r
996 browser.setFocus();
\r
999 // Listener for when UNDERLINE is clicked
\r
1000 @SuppressWarnings("unused")
\r
1001 private void underlineClicked() {
\r
1002 browser.page().triggerAction(WebAction.ToggleUnderline);
\r
1003 microFocusChanged();
\r
1004 browser.setFocus();
\r
1007 // Listener for when Strikethrough is clicked
\r
1008 @SuppressWarnings("unused")
\r
1009 private void strikethroughClicked() {
\r
1010 browser.page().mainFrame().evaluateJavaScript(
\r
1011 "document.execCommand('strikeThrough', false, '');");
\r
1012 browser.setFocus();
\r
1015 // Listener for when cut is clicked
\r
1016 @SuppressWarnings("unused")
\r
1017 private void cutClicked() {
\r
1018 browser.page().triggerAction(WebAction.Cut);
\r
1019 browser.setFocus();
\r
1022 // Listener when COPY is clicked
\r
1023 @SuppressWarnings("unused")
\r
1024 private void copyClicked() {
\r
1025 browser.page().triggerAction(WebAction.Copy);
\r
1026 browser.setFocus();
\r
1029 // Listener when PASTE is clicked
\r
1030 public void pasteClicked() {
\r
1031 logger.log(logger.EXTREME, "Paste Clicked");
\r
1032 if (forceTextPaste) {
\r
1033 pasteWithoutFormattingClicked();
\r
1036 QClipboard clipboard = QApplication.clipboard();
\r
1037 QMimeData mime = clipboard.mimeData();
\r
1039 // String x = mime.html();
\r
1041 if (mime.hasImage()) {
\r
1042 logger.log(logger.EXTREME, "Image paste found");
\r
1043 browser.setFocus();
\r
1044 insertImage(mime);
\r
1045 browser.setFocus();
\r
1049 if (mime.hasUrls()) {
\r
1050 logger.log(logger.EXTREME, "URL paste found");
\r
1052 browser.setFocus();
\r
1056 String text = mime.html();
\r
1057 if (text.contains("en-tag") && mime.hasHtml()) {
\r
1058 logger.log(logger.EXTREME, "Intra-note paste found");
\r
1059 text = fixInternotePaste(text);
\r
1060 mime.setHtml(text);
\r
1061 clipboard.setMimeData(mime);
\r
1064 logger.log(logger.EXTREME, "Final paste choice encountered");
\r
1065 browser.page().triggerAction(WebAction.Paste);
\r
1066 browser.setFocus();
\r
1070 // Paste text without formatting
\r
1071 private void pasteWithoutFormattingClicked() {
\r
1072 logger.log(logger.EXTREME, "Paste without format clipped");
\r
1073 QClipboard clipboard = QApplication.clipboard();
\r
1074 QMimeData mime = clipboard.mimeData();
\r
1075 if (!mime.hasText())
\r
1077 String text = mime.text();
\r
1078 clipboard.clear();
\r
1079 clipboard.setText(text, Mode.Clipboard);
\r
1080 browser.page().triggerAction(WebAction.Paste);
\r
1082 // This is done because pasting into an encryption block
\r
1083 // can cause multiple cells (which can't happen). It
\r
1084 // just goes through the table, extracts the data, &
\r
1085 // puts it back as one table cell.
\r
1086 if (insideEncryption) {
\r
1087 String js = new String( "function fixEncryption() { "
\r
1088 +" var selObj = window.getSelection();"
\r
1089 +" var selRange = selObj.getRangeAt(0);"
\r
1090 +" var workingNode = window.getSelection().anchorNode;"
\r
1091 +" while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { "
\r
1092 +" workingNode = workingNode.parentNode;"
\r
1094 +" workingNode.innerHTML = window.jambi.fixEncryptionPaste(workingNode.innerHTML);"
\r
1095 +"} fixEncryption();");
\r
1096 browser.page().mainFrame().evaluateJavaScript(js);
\r
1100 // This basically removes all the table tags and returns just the contents.
\r
1101 // This is called by JavaScript to fix encryption pastes.
\r
1102 public String fixEncryptionPaste(String data) {
\r
1103 data = data.replace("<tbody>", "");
\r
1104 data = data.replace("</tbody>", "");
\r
1105 data = data.replace("<tr>", "");
\r
1106 data = data.replace("</tr>", "");
\r
1107 data = data.replace("<td>", "");
\r
1108 data = data.replace("</td>", "<br>");
\r
1109 data = data.replace("<br><br>", "<br>");
\r
1111 return "<tbody><tr><td>"+data+"</td></tr></tbody>";
\r
1114 // insert date/time
\r
1115 @SuppressWarnings("unused")
\r
1116 private void insertDateTime() {
\r
1117 String fmt = Global.getDateFormat() + " " + Global.getTimeFormat();
\r
1118 String dateTimeFormat = new String(fmt);
\r
1119 SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);
\r
1120 Calendar cal = Calendar.getInstance();
\r
1122 browser.page().mainFrame().evaluateJavaScript(
\r
1123 "document.execCommand('insertHtml', false, '"+simple.format(cal.getTime())+"');");
\r
1125 browser.setFocus();
\r
1129 // Listener when Left is clicked
\r
1130 @SuppressWarnings("unused")
\r
1131 private void justifyLeftClicked() {
\r
1132 browser.page().mainFrame().evaluateJavaScript(
\r
1133 "document.execCommand('JustifyLeft', false, '');");
\r
1134 browser.setFocus();
\r
1137 // Listener when Center is clicked
\r
1138 @SuppressWarnings("unused")
\r
1139 private void justifyCenterClicked() {
\r
1140 browser.page().mainFrame().evaluateJavaScript(
\r
1141 "document.execCommand('JustifyCenter', false, '');");
\r
1142 browser.setFocus();
\r
1145 // Listener when Left is clicked
\r
1146 @SuppressWarnings("unused")
\r
1147 private void justifyRightClicked() {
\r
1148 browser.page().mainFrame().evaluateJavaScript(
\r
1149 "document.execCommand('JustifyRight', false, '');");
\r
1150 browser.setFocus();
\r
1153 // Listener when HLINE is clicked
\r
1154 @SuppressWarnings("unused")
\r
1155 private void hlineClicked() {
\r
1156 browser.page().mainFrame().evaluateJavaScript(
\r
1157 "document.execCommand('insertHorizontalRule', false, '');");
\r
1158 browser.setFocus();
\r
1161 // Listener when outdent is clicked
\r
1162 private void outdentClicked() {
\r
1163 browser.page().mainFrame().evaluateJavaScript(
\r
1164 "document.execCommand('outdent', false, '');");
\r
1165 browser.setFocus();
\r
1168 // Listener when a bullet list is clicked
\r
1169 @SuppressWarnings("unused")
\r
1170 private void bulletListClicked() {
\r
1171 browser.page().mainFrame().evaluateJavaScript(
\r
1172 "document.execCommand('InsertUnorderedList', false, '');");
\r
1173 browser.setFocus();
\r
1176 // Listener when a bullet list is clicked
\r
1177 @SuppressWarnings("unused")
\r
1178 private void numberListClicked() {
\r
1179 browser.page().mainFrame().evaluateJavaScript(
\r
1180 "document.execCommand('InsertOrderedList', false, '');");
\r
1181 browser.setFocus();
\r
1184 // Listener when indent is clicked
\r
1185 private void indentClicked() {
\r
1186 browser.page().mainFrame().evaluateJavaScript(
\r
1187 "document.execCommand('indent', false, '');");
\r
1188 browser.setFocus();
\r
1191 // Listener when the font name is changed
\r
1192 @SuppressWarnings("unused")
\r
1193 private void fontChanged(String font) {
\r
1194 browser.page().mainFrame().evaluateJavaScript(
\r
1195 "document.execCommand('fontName',false,'" + font + "');");
\r
1196 browser.setFocus();
\r
1199 // Listener when a font size is changed
\r
1200 @SuppressWarnings("unused")
\r
1201 private void fontSizeChanged(String font) {
\r
1202 String text = browser.selectedText();
\r
1203 if (text.trim().equalsIgnoreCase(""))
\r
1206 String selectedText = browser.selectedText();
\r
1207 String url = "<span style=\"font-size:" +font +"pt; \">"+selectedText +"</a>";
\r
1208 String script = "document.execCommand('insertHtml', false, '"+url+"');";
\r
1209 browser.page().mainFrame().evaluateJavaScript(script);
\r
1210 /* browser.page().mainFrame().evaluateJavaScript(
\r
1211 "document.execCommand('fontSize',false,'"
\r
1214 browser.setFocus();
\r
1217 // Load the font combo box based upon the font selected
\r
1218 private void loadFontSize(String name) {
\r
1219 QFontDatabase db = new QFontDatabase();
\r
1221 List<Integer> points = db.pointSizes(name);
\r
1222 for (int i=0; i<points.size(); i++) {
\r
1223 fontSize.addItem(points.get(i).toString());
\r
1226 fontSize.addItem("x-small");
\r
1227 fontSize.addItem("small");
\r
1228 fontSize.addItem("medium");
\r
1229 fontSize.addItem("large");
\r
1230 fontSize.addItem("x-large");
\r
1231 fontSize.addItem("xx-large");
\r
1232 fontSize.addItem("xxx-large");
\r
1236 // Listener when a font size is changed
\r
1237 @SuppressWarnings("unused")
\r
1238 private void fontColorClicked() {
\r
1239 // QColorDialog dialog = new QColorDialog();
\r
1240 // QColor color = QColorDialog.getColor();
\r
1241 QColor color = fontColorMenu.getColor();
\r
1242 if (color.isValid())
\r
1243 browser.page().mainFrame().evaluateJavaScript(
\r
1244 "document.execCommand('foreColor',false,'" + color.name()
\r
1246 browser.setFocus();
\r
1249 // Listener for when a background color change is requested
\r
1250 @SuppressWarnings("unused")
\r
1251 private void fontHilightClicked() {
\r
1252 // QColorDialog dialog = new QColorDialog();
\r
1253 // QColor color = QColorDialog.getColor();
\r
1254 QColor color = fontHilightColorMenu.getColor();
\r
1255 if (color.isValid())
\r
1256 browser.page().mainFrame().evaluateJavaScript(
\r
1257 "document.execCommand('backColor',false,'" + color.name()
\r
1259 browser.setFocus();
\r
1262 // Listener for when a background color change is requested
\r
1263 @SuppressWarnings("unused")
\r
1264 private void superscriptClicked() {
\r
1265 browser.page().mainFrame().evaluateJavaScript(
\r
1266 "document.execCommand('superscript');");
\r
1267 browser.setFocus();
\r
1270 // Listener for when a background color change is requested
\r
1271 @SuppressWarnings("unused")
\r
1272 private void subscriptClicked() {
\r
1273 browser.page().mainFrame().evaluateJavaScript(
\r
1274 "document.execCommand('subscript');");
\r
1275 browser.setFocus();
\r
1277 // Insert a to-do checkbox
\r
1278 @SuppressWarnings("unused")
\r
1279 private void todoClicked() {
\r
1280 FileNameMap fileNameMap = URLConnection.getFileNameMap();
\r
1281 String script_start = new String(
\r
1282 "document.execCommand('insertHtml', false, '");
\r
1283 String script_end = new String("');");
\r
1284 String todo = new String(
\r
1285 "<input TYPE=\"CHECKBOX\" value=\"false\" " +
\r
1286 "onMouseOver=\"style.cursor=\\'hand\\'\" " +
\r
1287 "onClick=\"value=checked; window.jambi.contentChanged(); \" />");
\r
1288 browser.page().mainFrame().evaluateJavaScript(
\r
1289 script_start + todo + script_end);
\r
1290 browser.setFocus();
\r
1293 // Encrypt the selected text
\r
1294 @SuppressWarnings("unused")
\r
1295 private void encryptText() {
\r
1296 String text = browser.selectedText();
\r
1297 if (text.trim().equalsIgnoreCase(""))
\r
1299 text = new String(text.replaceAll("\n", "<br/>"));
\r
1301 EnCryptDialog dialog = new EnCryptDialog();
\r
1303 if (!dialog.okPressed()) {
\r
1307 EnCrypt crypt = new EnCrypt();
\r
1308 String encrypted = crypt.encrypt(text, dialog.getPassword().trim(), 64);
\r
1309 String decrypted = crypt.decrypt(encrypted, dialog.getPassword().trim(), 64);
\r
1311 if (encrypted.trim().equals("")) {
\r
1312 QMessageBox.information(this, tr("Error"), tr("Error Encrypting String"));
\r
1315 StringBuffer buffer = new StringBuffer(encrypted.length() + 100);
\r
1316 buffer.append("<img en-tag=\"en-crypt\" cipher=\"RC2\" hint=\""
\r
1317 + dialog.getHint().replace("'","\\'") + "\" length=\"64\" ");
\r
1318 buffer.append("contentEditable=\"false\" alt=\"");
\r
1319 buffer.append(encrypted);
\r
1320 buffer.append("\" src=\"").append(FileUtils.toForwardSlashedPath(Global.getFileManager().getImageDirPath("encrypt.png") +"\""));
\r
1321 Global.cryptCounter++;
\r
1322 buffer.append(" id=\"crypt"+Global.cryptCounter.toString() +"\"");
\r
1323 buffer.append(" onMouseOver=\"style.cursor=\\'hand\\'\"");
\r
1324 buffer.append(" onClick=\"window.jambi.decryptText(\\'crypt"+Global.cryptCounter.toString()
\r
1325 +"\\', \\'"+encrypted+"\\', \\'"+dialog.getHint().replace("'", "\\&apos;")+"\\');\"");
\r
1326 buffer.append("style=\"display:block\" />");
\r
1328 String script_start = new String(
\r
1329 "document.execCommand('insertHtml', false, '");
\r
1330 String script_end = new String("');");
\r
1331 browser.page().mainFrame().evaluateJavaScript(
\r
1332 script_start + buffer.toString() + script_end);
\r
1336 // Insert a hyperlink
\r
1337 public void insertLink() {
\r
1338 logger.log(logger.EXTREME, "Inserting link");
\r
1339 String text = browser.selectedText();
\r
1340 if (text.trim().equalsIgnoreCase(""))
\r
1343 InsertLinkDialog dialog = new InsertLinkDialog(insertHyperlink);
\r
1344 if (currentHyperlink != null && currentHyperlink != "") {
\r
1345 dialog.setUrl(currentHyperlink);
\r
1348 if (!dialog.okPressed()) {
\r
1349 logger.log(logger.EXTREME, "Insert link canceled");
\r
1353 // Take care of inserting new links
\r
1354 if (insertHyperlink) {
\r
1355 String selectedText = browser.selectedText();
\r
1356 if (dialog.getUrl().trim().equals(""))
\r
1358 logger.log(logger.EXTREME, "Inserting link on text "+selectedText);
\r
1359 logger.log(logger.EXTREME, "URL Link " +dialog.getUrl().trim());
\r
1360 String dUrl = StringUtils.replace(dialog.getUrl().trim(), "'", "\\'");
\r
1361 String url = "<a href=\"" +dUrl
\r
1362 +"\" title=" +dUrl
\r
1363 +" >"+selectedText +"</a>";
\r
1364 String script = "document.execCommand('insertHtml', false, '"+url+"');";
\r
1365 browser.page().mainFrame().evaluateJavaScript(script);
\r
1369 // Edit existing links
\r
1370 String js = new String( "function getCursorPos() {"
\r
1372 +"if (window.getSelection) {"
\r
1373 +" var selObj = window.getSelection();"
\r
1374 +" var selRange = selObj.getRangeAt(0);"
\r
1375 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
1376 +" while(workingNode != null) { "
\r
1377 +" if (workingNode.nodeName.toLowerCase()=='a') workingNode.setAttribute('href','" +dialog.getUrl() +"');"
\r
1378 +" workingNode = workingNode.parentNode;"
\r
1381 +"} getCursorPos();");
\r
1382 browser.page().mainFrame().evaluateJavaScript(js);
\r
1384 if (!dialog.getUrl().trim().equals("")) {
\r
1390 js = new String( "function getCursorPos() {"
\r
1392 +"if (window.getSelection) {"
\r
1393 +" var selObj = window.getSelection();"
\r
1394 +" var selRange = selObj.getRangeAt(0);"
\r
1395 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
1396 +" while(workingNode != null) { "
\r
1397 +" if (workingNode.nodeName.toLowerCase()=='a') { "
\r
1398 +" workingNode.removeAttribute('href');"
\r
1399 +" workingNode.removeAttribute('title');"
\r
1400 +" var text = document.createTextNode(workingNode.innerText);"
\r
1401 +" workingNode.parentNode.insertBefore(text, workingNode);"
\r
1402 +" workingNode.parentNode.removeChild(workingNode);"
\r
1404 +" workingNode = workingNode.parentNode;"
\r
1407 +"} getCursorPos();");
\r
1408 browser.page().mainFrame().evaluateJavaScript(js);
\r
1416 // Insert a hyperlink
\r
1417 public void insertLatex() {
\r
1420 public void editLatex(String guid) {
\r
1421 logger.log(logger.EXTREME, "Inserting latex");
\r
1422 String text = browser.selectedText();
\r
1423 if (text.trim().equalsIgnoreCase("")) {
\r
1424 InsertLatexImage dialog = new InsertLatexImage();
\r
1425 if (guid != null) {
\r
1426 String formula = conn.getNoteTable().noteResourceTable.getNoteSourceUrl(guid).replace("http://latex.codecogs.com/gif.latex?", "");
\r
1427 dialog.setFormula(formula);
\r
1430 if (!dialog.okPressed()) {
\r
1431 logger.log(logger.EXTREME, "Edit LaTex canceled");
\r
1434 text = dialog.getFormula().trim();
\r
1436 blockApplication.emit(this);
\r
1437 logger.log(logger.EXTREME, "Inserting LaTeX formula:" +text);
\r
1439 text = StringUtils.replace(text, "'", "\\'");
\r
1440 String url = "http://latex.codecogs.com/gif.latex?" +text;
\r
1441 logger.log(logger.EXTREME, "Sending request to codecogs --> " + url);
\r
1442 QNetworkAccessManager manager = new QNetworkAccessManager(this);
\r
1443 manager.finished.connect(this, "insertLatexImageReady(QNetworkReply)");
\r
1444 unblockTime = new GregorianCalendar().getTimeInMillis()+5000;
\r
1445 awaitingHttpResponse = true;
\r
1446 manager.get(new QNetworkRequest(new QUrl(url)));
\r
1449 public void insertLatexImageReady(QNetworkReply reply) {
\r
1450 logger.log(logger.EXTREME, "Response received from CodeCogs");
\r
1451 if (reply.error() != NetworkError.NoError)
\r
1455 if (!awaitingHttpResponse)
\r
1458 awaitingHttpResponse = false;
\r
1459 QUrl replyUrl = reply.url();
\r
1460 QByteArray image = reply.readAll();
\r
1462 logger.log(logger.EXTREME, "New image size: " +image.size());
\r
1464 Resource newRes = null;
\r
1467 if (latexGuid == null) {
\r
1468 logger.log(logger.EXTREME, "Creating temporary gif");
\r
1469 path = Global.getFileManager().getResDirPath("latex-temp.gif");
\r
1470 tfile = new QFile(path);
\r
1471 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
\r
1472 logger.log(logger.EXTREME, "File Open: " +tfile.errorString());
\r
1473 tfile.write(image);
\r
1474 logger.log(logger.EXTREME, "Bytes writtes: "+tfile.size());
\r
1476 logger.log(logger.EXTREME, "Creating resource");
\r
1478 if (currentNote.getResources() != null || currentNote.getResources().size() > 0)
\r
1479 sequence = currentNote.getResources().size();
\r
1480 newRes = createResource(path,sequence ,"image/gif", false);
\r
1481 QImage pix = new QImage();
\r
1482 pix.loadFromData(image);
\r
1483 newRes.setHeight(new Integer(pix.height()).shortValue());
\r
1484 newRes.setWidth(new Integer(pix.width()).shortValue());
\r
1485 logger.log(logger.EXTREME, "Renaming temporary file to " +newRes.getGuid()+".gif");
\r
1486 path = Global.getFileManager().getResDirPath(newRes.getGuid()+".gif");
\r
1487 tfile.rename(path);
\r
1489 newRes = conn.getNoteTable().noteResourceTable.getNoteResource(latexGuid, false);
\r
1490 path = Global.getFileManager().getResDirPath(newRes.getGuid()+".gif");
\r
1491 tfile = new QFile(path);
\r
1492 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
\r
1493 tfile.write(image);
\r
1495 newRes.getData().setBody(image.toByteArray());
\r
1496 // Calculate the new hash value
\r
1499 logger.log(logger.EXTREME, "Generating MD5");
\r
1501 md = MessageDigest.getInstance("MD5");
\r
1502 md.update(image.toByteArray());
\r
1503 byte[] hash = md.digest();
\r
1504 newRes.getData().setBodyHash(hash);
\r
1505 } catch (NoSuchAlgorithmException e) {
\r
1506 e.printStackTrace();
\r
1508 QImage pix = new QImage();
\r
1509 pix.loadFromData(image);
\r
1510 newRes.setHeight(new Integer(pix.height()).shortValue());
\r
1511 newRes.setWidth(new Integer(pix.width()).shortValue());
\r
1512 conn.getNoteTable().noteResourceTable.updateNoteResource(newRes, true);
\r
1515 logger.log(logger.EXTREME, "Setting source: " +replyUrl.toString());
\r
1516 newRes.getAttributes().setSourceURL(replyUrl.toString());
\r
1517 conn.getNoteTable().noteResourceTable.updateNoteSourceUrl(newRes.getGuid(), replyUrl.toString(), true);
\r
1519 for(int i=0; i<currentNote.getResourcesSize(); i++) {
\r
1520 if (currentNote.getResources().get(i).getGuid().equals(newRes.getGuid())) {
\r
1521 currentNote.getResources().remove(i);
\r
1522 i=currentNote.getResourcesSize();
\r
1525 currentNote.getResources().add(newRes);
\r
1528 // do the actual insert into the note. We only do this on new formulas.
\r
1529 if (latexGuid == null) {
\r
1530 StringBuffer buffer = new StringBuffer(100);
\r
1531 String formula = replyUrl.toString().toLowerCase().replace("http://latex.codecogs.com/gif.latex?", "");
\r
1532 buffer.append("<a href=\"latex://"+path.replace("\\", "/")+"\" title=\""+formula+"\""
\r
1534 buffer.append(path.replace("\\", "/"));
\r
1535 buffer.append("\" en-tag=\"en-latex\" type=\"image/gif\""
\r
1536 +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""
\r
1537 +" guid=\"" +newRes.getGuid() +"\""
\r
1540 String script_start = new String("document.execCommand('insertHTML', false, '");
\r
1541 String script_end = new String("');");
\r
1542 browser.page().mainFrame().evaluateJavaScript(
\r
1543 script_start + buffer + script_end);
\r
1545 HtmlTagModifier modifier = new HtmlTagModifier(getContent());
\r
1546 modifier.modifyLatexTagHash(newRes);
\r
1547 String newContent = modifier.getHtml();
\r
1548 browser.setContent(new QByteArray(newContent));
\r
1551 logger.log(logger.EXTREME, "New HTML set\n" +browser.page().currentFrame().toHtml());
\r
1552 QWebSettings.setMaximumPagesInCache(0);
\r
1553 QWebSettings.setObjectCacheCapacities(0, 0, 0);
\r
1555 browser.page().mainFrame().setHtml(browser.page().mainFrame().toHtml());
\r
1558 // resourceSignal.contentChanged.emit(path);
\r
1560 unblockApplication.emit();
\r
1568 public void insertTable() {
\r
1569 TableDialog dialog = new TableDialog();
\r
1571 if (!dialog.okPressed()) {
\r
1575 int cols = dialog.getCols();
\r
1576 int rows = dialog.getRows();
\r
1577 int width = dialog.getWidth();
\r
1578 boolean percent = dialog.isPercent();
\r
1580 String newHTML = "<table border=\"1\" width=\"" +new Integer(width).toString();
\r
1582 newHTML = newHTML +"%";
\r
1583 newHTML = newHTML + "\"><tbody>";
\r
1585 for (int i=0; i<rows; i++) {
\r
1586 newHTML = newHTML +"<tr>";
\r
1587 for (int j=0; j<cols; j++) {
\r
1588 newHTML = newHTML +"<td> </td>";
\r
1590 newHTML = newHTML +"</tr>";
\r
1592 newHTML = newHTML+"</tbody></table>";
\r
1594 String script = "document.execCommand('insertHtml', false, '"+newHTML+"');";
\r
1595 browser.page().mainFrame().evaluateJavaScript(script);
\r
1599 // Text content changed
\r
1600 @SuppressWarnings("unused")
\r
1601 private void selectionChanged() {
\r
1602 browser.encryptAction.setEnabled(true);
\r
1603 browser.insertLinkAction.setEnabled(true);
\r
1604 String scriptStart = "var selection_text = (window.getSelection()).toString();"
\r
1605 + "var range = (window.getSelection()).getRangeAt(0);"
\r
1606 + "var parent_html = range.commonAncestorContainer.innerHTML;"
\r
1607 + "if (parent_html == undefined) {window.jambi.saveSelectedText(selection_text); return;}"
\r
1608 + "var first_text = range.startContainer.nodeValue.substr(range.startOffset);"
\r
1609 + "var last_text = (range.endContainer.nodeValue).substring(0,range.endOffset);"
\r
1610 + "var start = parent_html.indexOf(first_text);"
\r
1611 + "var end = parent_html.indexOf(last_text,start+1)+last_text.length;"
\r
1612 + "var value = parent_html.substring(start,end);"
\r
1613 + "window.jambi.saveSelectedText(value);" ;
\r
1614 browser.page().mainFrame().evaluateJavaScript(scriptStart);
\r
1618 public void saveSelectedText(String text) {
\r
1619 boolean enabled = true;
\r
1620 if (text.trim().length() == 0)
\r
1622 if (text.indexOf("en-tag=\"en-crypt\"") >= 0)
\r
1624 if (text.indexOf("<img en-tag=\"en-media\"") >= 0)
\r
1626 if (text.indexOf("<a en-tag=\"en-media\"") >= 0)
\r
1628 if (text.indexOf("<input ") >= 0)
\r
1631 browser.encryptAction.setEnabled(enabled);
\r
1632 browser.insertLinkAction.setEnabled(enabled);
\r
1633 // selectedText = text;
\r
1636 // Decrypt clicked text
\r
1637 public void decryptText(String id, String text, String hint) {
\r
1638 EnCrypt crypt = new EnCrypt();
\r
1639 String plainText = null;
\r
1640 Calendar currentTime = new GregorianCalendar();
\r
1641 Long l = new Long(currentTime.getTimeInMillis());
\r
1642 String slot = new String(Long.toString(l));
\r
1644 // First, try to decrypt with any keys we already have
\r
1645 for (int i=0; i<Global.passwordRemember.size(); i++) {
\r
1646 plainText = crypt.decrypt(text, Global.passwordRemember.get(i).getFirst(), 64);
\r
1647 if (plainText != null) {
\r
1648 slot = new String(Long.toString(l));
\r
1649 Global.passwordSafe.put(slot, Global.passwordRemember.get(i));
\r
1650 removeEncryption(id, plainText, false, slot);
\r
1656 EnDecryptDialog dialog = new EnDecryptDialog();
\r
1657 dialog.setHint(hint);
\r
1658 while (plainText == null || !dialog.okPressed()) {
\r
1660 if (!dialog.okPressed()) {
\r
1663 plainText = crypt.decrypt(text, dialog.getPassword().trim(), 64);
\r
1664 if (plainText == null) {
\r
1665 QMessageBox.warning(this, "Incorrect Password", "The password entered is not correct");
\r
1668 Pair<String,String> passwordPair = new Pair<String,String>();
\r
1669 passwordPair.setFirst(dialog.getPassword());
\r
1670 passwordPair.setSecond(dialog.getHint());
\r
1671 Global.passwordSafe.put(slot, passwordPair);
\r
1672 // removeEncryption(id, plainText.replaceAll("\n", "<br/>"), dialog.permanentlyDecrypt(), slot);
\r
1673 removeEncryption(id, plainText, dialog.permanentlyDecrypt(), slot);
\r
1674 if (dialog.rememberPassword()) {
\r
1675 Pair<String, String> pair = new Pair<String,String>();
\r
1676 pair.setFirst(dialog.getPassword());
\r
1677 pair.setSecond(dialog.getHint());
\r
1678 Global.passwordRemember.add(pair);
\r
1683 // Get the editor tag line
\r
1684 public TagLineEdit getTagLine() {
\r
1688 // Modify a note's tags
\r
1689 @SuppressWarnings("unused")
\r
1690 private void modifyTags() {
\r
1691 TagAssign tagWindow = new TagAssign(allTags, currentTags, !conn.getNotebookTable().isLinked(currentNote.getNotebookGuid()));
\r
1693 if (tagWindow.okClicked()) {
\r
1694 currentTags.clear();
\r
1695 StringBuffer tagDisplay = new StringBuffer();
\r
1697 List<QListWidgetItem> newTags = tagWindow.getTagList()
\r
1699 for (int i = 0; i < newTags.size(); i++) {
\r
1700 currentTags.add(newTags.get(i).text());
\r
1701 tagDisplay.append(newTags.get(i).text());
\r
1702 if (i < newTags.size() - 1) {
\r
1703 tagDisplay.append(Global.tagDelimeter + " ");
\r
1706 tagEdit.setText(tagDisplay.toString());
\r
1707 noteSignal.tagsChanged.emit(currentNote.getGuid(), currentTags);
\r
1711 // Tag line has been modified by typing text
\r
1712 @SuppressWarnings("unused")
\r
1713 private void modifyTagsTyping() {
\r
1714 String completionText = "";
\r
1715 if (tagEdit.currentCompleterSelection != null && !tagEdit.currentCompleterSelection.equals("")) {
\r
1716 completionText = tagEdit.currentCompleterSelection;
\r
1717 tagEdit.currentCompleterSelection = "";
\r
1720 if (tagEdit.text().equalsIgnoreCase(saveTagList))
\r
1723 // We know something has changed...
\r
1724 String oldTagArray[] = saveTagList.split(Global.tagDelimeter);
\r
1725 String newTagArray[];
\r
1726 if (!completionText.equals("")) {
\r
1727 String before = tagEdit.text().substring(0,tagEdit.cursorPosition());
\r
1728 int lastDelimiter = before.lastIndexOf(Global.tagDelimeter);
\r
1729 if (lastDelimiter > 0)
\r
1730 before = before.substring(0,before.lastIndexOf(Global.tagDelimeter));
\r
1733 String after = tagEdit.text().substring(tagEdit.cursorPosition());
\r
1734 newTagArray = (before+Global.tagDelimeter+completionText+Global.tagDelimeter+after).split(Global.tagDelimeter);
\r
1737 newTagArray = tagEdit.text().split(Global.tagDelimeter);
\r
1740 // Remove any traling or leading blanks
\r
1741 for (int i=0; i<newTagArray.length; i++)
\r
1742 newTagArray[i] = newTagArray[i].trim().replaceAll("^\\s+", "");;
\r
1744 // Remove any potential duplicates from the new list
\r
1745 for (int i=0; i<newTagArray.length; i++) {
\r
1746 boolean foundOnce = false;
\r
1747 for (int j=0; j<newTagArray.length; j++) {
\r
1748 if (newTagArray[j].equalsIgnoreCase(newTagArray[i])) {
\r
1752 newTagArray[j] = "";
\r
1757 List<String> newTagList = new ArrayList<String>();
\r
1758 List<String> oldTagList = new ArrayList<String>();
\r
1760 for (int i = 0; i < oldTagArray.length; i++)
\r
1761 if (!oldTagArray[i].trim().equals(""))
\r
1762 oldTagList.add(oldTagArray[i]);
\r
1763 for (int i = 0; i < newTagArray.length; i++)
\r
1764 if (!newTagArray[i].trim().equals(""))
\r
1765 newTagList.add(newTagArray[i]);
\r
1767 if (conn.getNotebookTable().isLinked(currentNote.getNotebookGuid())) {
\r
1768 for (int i=newTagList.size()-1; i>=0; i--) {
\r
1769 boolean found = false;
\r
1770 for (int j=0; j<allTags.size(); j++) {
\r
1771 if (allTags.get(j).getName().equalsIgnoreCase(newTagList.get(i))) {
\r
1777 newTagList.remove(i);
\r
1781 // Let's cleanup the appearance of the tag list
\r
1782 Collections.sort(newTagList);
\r
1783 String newDisplay = "";
\r
1784 for (int i=0; i<newTagList.size(); i++) {
\r
1785 newDisplay = newDisplay+newTagList.get(i);
\r
1786 if (i<newTagList.size()-1)
\r
1787 newDisplay = newDisplay+Global.tagDelimeter +" ";
\r
1789 tagEdit.blockSignals(true);
\r
1790 tagEdit.setText(newDisplay);
\r
1791 tagEdit.blockSignals(false);
\r
1793 // We now have lists of the new & old. Remove duplicates. If all
\r
1794 // are removed from both then nothing has really changed
\r
1795 for (int i = newTagList.size() - 1; i >= 0; i--) {
\r
1796 String nTag = newTagList.get(i);
\r
1797 for (int j = oldTagList.size() - 1; j >= 0; j--) {
\r
1798 String oTag = oldTagList.get(j);
\r
1799 if (oTag.equalsIgnoreCase(nTag)) {
\r
1800 oldTagList.remove(j);
\r
1801 newTagList.remove(i);
\r
1807 if (oldTagList.size() != 0 || newTagList.size() != 0) {
\r
1808 currentTags.clear();
\r
1809 newTagArray = tagEdit.text().split(Global.tagDelimeter);
\r
1810 for (int i = 0; i < newTagArray.length; i++)
\r
1811 if (!newTagArray[i].trim().equals(""))
\r
1812 currentTags.add(newTagArray[i].trim());
\r
1814 noteSignal.tagsChanged.emit(currentNote.getGuid(), currentTags);
\r
1819 // Tab button was pressed
\r
1820 public void tabPressed() {
\r
1821 if (insideEncryption)
\r
1823 if (!insideList && !insideTable) {
\r
1824 String script_start = new String(
\r
1825 "document.execCommand('insertHtml', false, ' ');");
\r
1826 browser.page().mainFrame().evaluateJavaScript(script_start);
\r
1832 if (insideTable) {
\r
1833 String js = new String( "function getCursorPosition() { "
\r
1834 +" var selObj = window.getSelection();"
\r
1835 +" var selRange = selObj.getRangeAt(0);"
\r
1836 +" var workingNode = window.getSelection().anchorNode;"
\r
1837 +" var rowCount = 0;"
\r
1838 +" var colCount = 0;"
\r
1839 +" while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { "
\r
1840 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
\r
1841 +" rowCount = rowCount+1;"
\r
1843 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
\r
1844 +" colCount = colCount+1;"
\r
1846 +" if (workingNode.previousSibling != null)"
\r
1847 +" workingNode = workingNode.previousSibling;"
\r
1849 +" workingNode = workingNode.parentNode;"
\r
1851 +" var nodes = workingNode.getElementsByTagName('tr');"
\r
1852 +" var tableRows = nodes.length;"
\r
1853 +" nodes = nodes[0].getElementsByTagName('td');"
\r
1854 +" var tableColumns = nodes.length;"
\r
1855 +" window.jambi.setTableCursorPositionTab(rowCount, colCount, tableRows, tableColumns);"
\r
1856 +"} getCursorPosition();");
\r
1857 browser.page().mainFrame().evaluateJavaScript(js);
\r
1861 // If a user presses tab from within a table
\r
1862 public void setTableCursorPositionTab(int currentRow, int currentCol, int tableRows, int tableColumns) {
\r
1863 if (tableRows == currentRow && currentCol == tableColumns) {
\r
1866 KeyboardModifiers modifiers = new KeyboardModifiers(KeyboardModifier.NoModifier);
\r
1867 QKeyEvent right = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Right.value(), modifiers);
\r
1868 QKeyEvent end = new QKeyEvent(Type.KeyPress, Qt.Key.Key_End.value(), modifiers);
\r
1869 QKeyEvent end2 = new QKeyEvent(Type.KeyPress, Qt.Key.Key_End.value(), modifiers);
\r
1870 getBrowser().focusWidget();
\r
1871 QCoreApplication.postEvent(getBrowser(), end);
\r
1872 QCoreApplication.postEvent(getBrowser(), right);
\r
1873 QCoreApplication.postEvent(getBrowser(), end2);
\r
1876 public void backtabPressed() {
\r
1877 if (insideEncryption)
\r
1881 if (insideTable) {
\r
1882 String js = new String( "function getCursorPosition() { "
\r
1883 +" var selObj = window.getSelection();"
\r
1884 +" var selRange = selObj.getRangeAt(0);"
\r
1885 +" var workingNode = window.getSelection().anchorNode;"
\r
1886 +" var rowCount = 0;"
\r
1887 +" var colCount = 0;"
\r
1888 +" while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { "
\r
1889 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
\r
1890 +" rowCount = rowCount+1;"
\r
1892 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
\r
1893 +" colCount = colCount+1;"
\r
1895 +" if (workingNode.previousSibling != null)"
\r
1896 +" workingNode = workingNode.previousSibling;"
\r
1898 +" workingNode = workingNode.parentNode;"
\r
1900 +" var nodes = workingNode.getElementsByTagName('tr');"
\r
1901 +" var tableRows = nodes.length;"
\r
1902 +" nodes = nodes[0].getElementsByTagName('td');"
\r
1903 +" var tableColumns = nodes.length;"
\r
1904 +" window.jambi.setTableCursorPositionBackTab(rowCount, colCount, tableRows, tableColumns);"
\r
1905 +"} getCursorPosition();");
\r
1906 browser.page().mainFrame().evaluateJavaScript(js);
\r
1911 // If a user presses backtab from within a table
\r
1912 public void setTableCursorPositionBackTab(int currentRow, int currentCol, int tableRows, int tableColumns) {
\r
1913 if (currentRow == 1 && currentCol == 1) {
\r
1916 KeyboardModifiers modifiers = new KeyboardModifiers(KeyboardModifier.NoModifier);
\r
1917 QKeyEvent left = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Left.value(), modifiers);
\r
1918 QKeyEvent home = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Home.value(), modifiers);
\r
1919 getBrowser().focusWidget();
\r
1920 QCoreApplication.postEvent(getBrowser(), home);
\r
1921 QCoreApplication.postEvent(getBrowser(), left);
\r
1925 public void setInsideList() {
\r
1926 insideList = true;
\r
1929 // The title has been edited
\r
1930 @SuppressWarnings("unused")
\r
1931 private void titleEdited() {
\r
1932 // If we don't have a good note, or if the current title
\r
1933 // matches the old title then we don't need to do anything
\r
1934 if (currentNote == null)
\r
1936 if (currentNote.getTitle().trim().equals(titleLabel.text().trim()))
\r
1939 // If we have a real change, we need to save it.
\r
1940 noteSignal.titleChanged.emit(currentNote.getGuid(), titleLabel.text());
\r
1941 currentNote.setTitle(titleLabel.text());
\r
1942 saveNoteTitle = titleLabel.text();
\r
1946 // Set the list of note tags
\r
1947 public void setAllTags(List<Tag> l) {
\r
1949 tagEdit.setTagList(l);
\r
1952 // Setter for the current tags
\r
1953 public void setCurrentTags(List<String> s) {
\r
1957 // Save the list of notebooks
\r
1958 public void setNotebookList(List<Notebook> n) {
\r
1960 loadNotebookList();
\r
1963 // Load the notebook list and select the current notebook
\r
1964 private void loadNotebookList() {
\r
1965 if (notebookBox.count() != 0)
\r
1966 notebookBox.clear();
\r
1967 if (notebookList == null)
\r
1970 for (int i = 0; i < notebookList.size(); i++) {
\r
1971 notebookBox.addItem(notebookList.get(i).getName());
\r
1972 if (currentNote != null) {
\r
1973 if (currentNote.getNotebookGuid().equals(
\r
1974 notebookList.get(i).getGuid())) {
\r
1975 notebookBox.setCurrentIndex(i);
\r
1982 // Set the notebook for a note
\r
1983 public void setNotebook(String notebook) {
\r
1984 currentNote.setNotebookGuid(notebook);
\r
1985 loadNotebookList();
\r
1988 // Get the contents of the editor
\r
1989 public String getContent() {
\r
1990 return browser.page().currentFrame().toHtml();
\r
1993 // The note contents have changed
\r
1994 public void contentChanged() {
\r
1995 String content = getContent();
\r
1997 noteSignal.noteChanged.emit(currentNote.getGuid(), content);
\r
2000 // The notebook selection has changed
\r
2001 @SuppressWarnings("unused")
\r
2002 private void notebookChanged() {
\r
2003 boolean changed = false;
\r
2004 String n = notebookBox.currentText();
\r
2005 for (int i = 0; i < notebookList.size(); i++) {
\r
2006 if (n.equals(notebookList.get(i).getName())) {
\r
2007 if (!notebookList.get(i).getGuid().equals(currentNote.getNotebookGuid())) {
\r
2008 String guid = conn.getNotebookTable().findNotebookByName(n);
\r
2009 if (conn.getNotebookTable().isLinked(guid)) {
\r
2010 tagEdit.setText("");
\r
2011 noteSignal.tagsChanged.emit(currentNote.getGuid(), new ArrayList<String>());
\r
2012 FilterEditorTags t = new FilterEditorTags(conn, logger);
\r
2013 setAllTags(t.getValidTags(currentNote));
\r
2015 currentNote.setNotebookGuid(notebookList.get(i).getGuid());
\r
2018 i = notebookList.size();
\r
2022 // If the notebook changed, signal the update
\r
2024 noteSignal.notebookChanged.emit(currentNote.getGuid(), currentNote
\r
2025 .getNotebookGuid());
\r
2028 // Check the note title
\r
2029 private void checkNoteTitle() {
\r
2030 String text = browser.page().currentFrame().toPlainText();
\r
2031 if (saveNoteTitle.trim().equals("") || saveNoteTitle.trim().equals("Untitled Note")) {
\r
2032 int newLine = text.indexOf("\n");
\r
2033 if (newLine > 0) {
\r
2034 text = text.substring(0, newLine);
\r
2035 if (text.trim().equals(""))
\r
2036 text = tr("Untitled Note");
\r
2037 titleLabel.setText(text);
\r
2039 if (text.length() > Constants.EDAM_NOTE_TITLE_LEN_MAX)
\r
2040 titleLabel.setText(text.substring(0, Constants.EDAM_NOTE_TITLE_LEN_MAX));
\r
2042 titleLabel.blockSignals(true);
\r
2043 if (text.trim().equals(""))
\r
2044 titleLabel.setText(tr("Untitled Note"));
\r
2046 titleLabel.setText(text);
\r
2047 titleLabel.blockSignals(false);
\r
2050 noteSignal.titleChanged.emit(currentNote.getGuid(), titleLabel
\r
2055 // Return the note contents so we can email them
\r
2056 public String getContentsToEmail() {
\r
2057 return browser.page().currentFrame().toPlainText().trim();
\r
2059 * int body = browser.page().currentFrame().toHtml().indexOf("<body>");
\r
2060 * String temp = browser.page().currentFrame().toHtml(); if (body == -1)
\r
2061 * temp = "<html><body><b>Test</b></body></html>"; else temp =
\r
2062 * "<html>"+temp.substring(body); return temp; // return
\r
2063 * urlEncode(browser.page().currentFrame().toHtml());
\r
2067 // Insert an image into the editor
\r
2068 private void insertImage(QMimeData mime) {
\r
2069 logger.log(logger.EXTREME, "Entering insertImage");
\r
2070 QImage img = (QImage) mime.imageData();
\r
2071 String script_start = new String(
\r
2072 "document.execCommand('insertHTML', false, '");
\r
2073 String script_end = new String("');");
\r
2075 long now = new Date().getTime();
\r
2076 String path = Global.getFileManager().getResDirPath(
\r
2077 (new Long(now).toString()) + ".jpg");
\r
2079 // This block is just a hack to make sure we wait at least 1ms so we
\r
2081 // have collisions on image names
\r
2082 long i = new Date().getTime();
\r
2084 i = new Date().getTime();
\r
2086 // Open the file & write the data
\r
2087 QFile tfile = new QFile(path);
\r
2088 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
\r
2089 if (!img.save(tfile)) {
\r
2095 Resource newRes = createResource(QUrl.fromLocalFile(path).toString(), 0, "image/jpeg", false);
\r
2096 if (newRes == null)
\r
2098 currentNote.getResources().add(newRes);
\r
2100 // do the actual insert into the note
\r
2101 StringBuffer buffer = new StringBuffer(100);
\r
2102 buffer.append("<img src=\"");
\r
2103 buffer.append(tfile.fileName());
\r
2104 buffer.append("\" en-tag=en-media type=\"image/jpeg\""
\r
2105 +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""
\r
2106 +" guid=\"" +newRes.getGuid() +"\""
\r
2107 +" onContextMenu=\"window.jambi.imageContextMenu(&." +tfile.fileName() +"&.);\""
\r
2110 browser.page().mainFrame().evaluateJavaScript(
\r
2111 script_start + buffer + script_end);
\r
2116 // Handle URLs that are trying to be pasted
\r
2117 public void handleUrls(QMimeData mime) {
\r
2118 logger.log(logger.EXTREME, "Starting handleUrls");
\r
2119 FileNameMap fileNameMap = URLConnection.getFileNameMap();
\r
2121 List<QUrl> urlList = mime.urls();
\r
2122 String url = new String();
\r
2123 String script_start = new String(
\r
2124 "document.execCommand('createLink', false, '");
\r
2125 String script_end = new String("');");
\r
2127 for (int i = 0; i < urlList.size(); i++) {
\r
2128 url = urlList.get(i).toString();
\r
2129 // Find out what type of file we have
\r
2130 String mimeType = fileNameMap.getContentTypeFor(url);
\r
2132 // If null returned, we need to guess at the file type
\r
2133 if (mimeType == null)
\r
2134 mimeType = "application/"
\r
2135 + url.substring(url.lastIndexOf(".") + 1);
\r
2137 // Check if we have an image or some other type of file
\r
2138 if (url.substring(0, 5).equalsIgnoreCase("file:")
\r
2139 && mimeType.substring(0, 5).equalsIgnoreCase("image")) {
\r
2140 handleLocalImageURLPaste(mime, mimeType);
\r
2143 String[] type = mimeType.split("/");
\r
2144 boolean valid = validAttachment(type[1]);
\r
2145 boolean smallEnough = checkFileAttachmentSize(url);
\r
2146 if (smallEnough && valid
\r
2147 && url.substring(0, 5).equalsIgnoreCase("file:")
\r
2148 && !mimeType.substring(0, 5).equalsIgnoreCase("image")) {
\r
2149 handleLocalAttachment(mime, mimeType);
\r
2152 browser.page().mainFrame().evaluateJavaScript(
\r
2153 script_start + url + script_end);
\r
2158 // If a URL being pasted is an image URL, then attach the image
\r
2159 private void handleLocalImageURLPaste(QMimeData mime, String mimeType) {
\r
2160 List<QUrl> urlList = mime.urls();
\r
2161 String url = new String();
\r
2162 String script_start_image = new String(
\r
2163 "document.execCommand('insertHtml', false, '");
\r
2164 String script_end = new String("');");
\r
2165 StringBuffer buffer;
\r
2167 // Copy the image over into the resource directory and create a new resource
\r
2168 // record for each url pasted
\r
2169 for (int i = 0; i < urlList.size(); i++) {
\r
2170 url = urlList.get(i).toString();
\r
2172 Resource newRes = createResource(url, i, mimeType, false);
\r
2173 if (newRes == null)
\r
2175 currentNote.getResources().add(newRes);
\r
2176 buffer = new StringBuffer(100);
\r
2178 // Open the file & write the data
\r
2179 String fileName = Global.getFileManager().getResDirPath(newRes.getGuid());
\r
2180 QFile tfile = new QFile(fileName);
\r
2181 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
\r
2182 tfile.write(newRes.getData().getBody());
\r
2184 buffer.append(script_start_image);
\r
2185 buffer.append("<img src=\"" + FileUtils.toForwardSlashedPath(fileName));
\r
2186 // if (mimeType.equalsIgnoreCase("image/jpg"))
\r
2187 // mimeType = "image/jpeg";
\r
2188 buffer.append("\" en-tag=\"en-media\" type=\"" + mimeType +"\""
\r
2189 +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""
\r
2190 +" guid=\"" +newRes.getGuid() +"\""
\r
2191 +" onContextMenu=\"window.jambi.imageContextMenu('" +tfile.fileName() +"');\""
\r
2193 buffer.append(script_end);
\r
2194 browser.page().mainFrame().evaluateJavaScript(buffer.toString());
\r
2200 // If a URL being pasted is a local file URL, then attach the file
\r
2201 private void handleLocalAttachment(QMimeData mime, String mimeType) {
\r
2202 logger.log(logger.EXTREME, "Attaching local file");
\r
2203 List<QUrl> urlList = mime.urls();
\r
2204 String script_start = new String(
\r
2205 "document.execCommand('insertHtml', false, '");
\r
2206 String script_end = new String("');");
\r
2207 StringBuffer buffer;
\r
2209 String[] type = mimeType.split("/");
\r
2210 String icon = findIcon(type[1]);
\r
2211 if (icon.equals("attachment.png"))
\r
2212 icon = findIcon(type[0]);
\r
2213 buffer = new StringBuffer(100);
\r
2215 for (int i = 0; i < urlList.size(); i++) {
\r
2216 String url = urlList.get(i).toString();
\r
2218 // Start building the HTML
\r
2219 if (icon.equals("attachment.png"))
\r
2220 icon = findIcon(url.substring(url.lastIndexOf(".")+1));
\r
2221 String imageURL = FileUtils.toFileURLString(Global.getFileManager().getImageDirFile(icon));
\r
2223 logger.log(logger.EXTREME, "Creating resource ");
\r
2224 Resource newRes = createResource(url, i, mimeType, true);
\r
2225 if (newRes == null)
\r
2227 logger.log(logger.EXTREME, "New resource size: " +newRes.getData().getSize());
\r
2228 currentNote.getResources().add(newRes);
\r
2230 String fileName = newRes.getGuid() + Global.attachmentNameDelimeter+newRes.getAttributes().getFileName();
\r
2231 // If we have a PDF, we need to setup the preview.
\r
2232 if (icon.equalsIgnoreCase("pdf.png") && Global.pdfPreview()) {
\r
2233 logger.log(logger.EXTREME, "Setting up PDF preview");
\r
2234 if (newRes.getAttributes() != null &&
\r
2235 newRes.getAttributes().getFileName() != null &&
\r
2236 !newRes.getAttributes().getFileName().trim().equals(""))
\r
2237 fileName = newRes.getGuid()+Global.attachmentNameDelimeter+
\r
2238 newRes.getAttributes().getFileName();
\r
2240 fileName = newRes.getGuid()+".pdf";
\r
2241 QFile file = new QFile(Global.getFileManager().getResDirPath(fileName));
\r
2242 QFile.OpenMode mode = new QFile.OpenMode();
\r
2243 mode.set(QFile.OpenModeFlag.WriteOnly);
\r
2245 QDataStream out = new QDataStream(file);
\r
2246 // Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(newRes.getGuid(), true);
\r
2247 QByteArray binData = new QByteArray(newRes.getData().getBody());
\r
2248 // resBinary = null;
\r
2249 out.writeBytes(binData.toByteArray());
\r
2252 PDFPreview pdfPreview = new PDFPreview();
\r
2253 if (pdfPreview.setupPreview(Global.getFileManager().getResDirPath(fileName), "pdf",0)) {
\r
2254 imageURL = file.fileName() + ".png";
\r
2258 logger.log(logger.EXTREME, "Generating link tags");
\r
2259 buffer.delete(0, buffer.length());
\r
2260 buffer.append("<a en-tag=\"en-media\" guid=\"" +newRes.getGuid()+"\" ");
\r
2261 buffer.append(" onContextMenu=\"window.jambi.imageContextMenu('")
\r
2262 .append(Global.getFileManager().getResDirPath(fileName))
\r
2263 .append("');\" "); buffer.append("type=\"" + mimeType + "\" href=\"nnres://" + fileName +"\" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\" >");
\r
2264 buffer.append("<img src=\"" + imageURL + "\" title=\"" +newRes.getAttributes().getFileName());
\r
2265 buffer.append("\"></img>");
\r
2266 buffer.append("</a>");
\r
2267 browser.page().mainFrame().evaluateJavaScript(
\r
2268 script_start + buffer.toString() + script_end);
\r
2273 private Resource createResource(String url, int sequence, String mime, boolean attachment) {
\r
2274 logger.log(logger.EXTREME, "Inside create resource");
\r
2275 QFile resourceFile;
\r
2276 String urlTest = new QUrl(url).toLocalFile();
\r
2277 if (!urlTest.equals(""))
\r
2279 url = url.replace("/", File.separator);
\r
2280 logger.log(logger.EXTREME, "Reading from file to create resource");
\r
2281 resourceFile = new QFile(url);
\r
2282 resourceFile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly));
\r
2283 // logger.log(logger.EXTREME, "Error opening file "+url.toString() +": "+resourceFile.errorString());
\r
2284 byte[] fileData = resourceFile.readAll().toByteArray();
\r
2285 resourceFile.close();
\r
2286 if (fileData.length == 0)
\r
2290 logger.log(logger.EXTREME, "Generating MD5");
\r
2291 md = MessageDigest.getInstance("MD5");
\r
2292 md.update(fileData);
\r
2293 byte[] hash = md.digest();
\r
2295 Resource r = new Resource();
\r
2296 Calendar time = new GregorianCalendar();
\r
2297 long prevTime = time.getTimeInMillis();
\r
2298 while (prevTime == time.getTimeInMillis()) {
\r
2299 time = new GregorianCalendar();
\r
2301 r.setGuid(time.getTimeInMillis()+new Integer(sequence).toString());
\r
2302 r.setNoteGuid(currentNote.getGuid());
\r
2304 r.setActive(true);
\r
2305 r.setUpdateSequenceNum(0);
\r
2306 r.setWidth((short) 0);
\r
2307 r.setHeight((short) 0);
\r
2308 r.setDuration((short) 0);
\r
2310 Data d = new Data();
\r
2311 d.setBody(fileData);
\r
2312 d.setBodyIsSet(true);
\r
2313 d.setBodyHash(hash);
\r
2314 d.setBodyHashIsSet(true);
\r
2316 d.setSize(fileData.length);
\r
2318 int fileNamePos = url.lastIndexOf(File.separator);
\r
2319 if (fileNamePos == -1)
\r
2320 fileNamePos = url.lastIndexOf("/");
\r
2321 String fileName = url.substring(fileNamePos+1);
\r
2322 ResourceAttributes a = new ResourceAttributes();
\r
2324 a.setAltitudeIsSet(false);
\r
2325 a.setLongitude(0);
\r
2326 a.setLongitudeIsSet(false);
\r
2328 a.setLatitudeIsSet(false);
\r
2329 a.setCameraMake("");
\r
2330 a.setCameraMakeIsSet(false);
\r
2331 a.setCameraModel("");
\r
2332 a.setCameraModelIsSet(false);
\r
2333 a.setAttachment(attachment);
\r
2334 a.setAttachmentIsSet(true);
\r
2335 a.setClientWillIndex(false);
\r
2336 a.setClientWillIndexIsSet(true);
\r
2337 a.setRecoType("");
\r
2338 a.setRecoTypeIsSet(false);
\r
2339 a.setSourceURL(url);
\r
2340 a.setSourceURLIsSet(true);
\r
2341 a.setTimestamp(0);
\r
2342 a.setTimestampIsSet(false);
\r
2343 a.setFileName(fileName);
\r
2344 a.setFileNameIsSet(true);
\r
2345 r.setAttributes(a);
\r
2347 conn.getNoteTable().noteResourceTable.saveNoteResource(r, true);
\r
2348 logger.log(logger.EXTREME, "Resource created");
\r
2350 } catch (NoSuchAlgorithmException e1) {
\r
2351 e1.printStackTrace();
\r
2357 // find the appropriate icon for an attachment
\r
2358 private String findIcon(String appl) {
\r
2359 appl = appl.toLowerCase();
\r
2360 File f = Global.getFileManager().getImageDirFile(appl + ".png");
\r
2362 return appl+".png";
\r
2363 return "attachment.png";
\r
2366 // Check if the account supports this type of attachment
\r
2367 private boolean validAttachment(String type) {
\r
2368 if (Global.isPremium())
\r
2370 if (type.equalsIgnoreCase("JPG"))
\r
2372 if (type.equalsIgnoreCase("PNG"))
\r
2374 if (type.equalsIgnoreCase("GIF"))
\r
2376 if (type.equalsIgnoreCase("MP3"))
\r
2378 if (type.equalsIgnoreCase("WAV"))
\r
2380 if (type.equalsIgnoreCase("AMR"))
\r
2382 if (type.equalsIgnoreCase("PDF"))
\r
2384 String error = tr("Non-premium accounts can only attach JPG, PNG, GIF, MP3, WAV, AMR, or PDF files.");
\r
2385 QMessageBox.information(this, tr("Non-Premium Account"), error);
\r
2390 // Check the file attachment to be sure it isn't over 25 mb
\r
2391 private boolean checkFileAttachmentSize(String url) {
\r
2392 String fileName = url.substring(8);
\r
2393 QFile resourceFile = new QFile(fileName);
\r
2394 resourceFile.open(new QIODevice.OpenMode(
\r
2395 QIODevice.OpenModeFlag.ReadOnly));
\r
2396 long size = resourceFile.size();
\r
2397 resourceFile.close();
\r
2398 size = size / 1024 / 1024;
\r
2399 if (size < 50 && Global.isPremium())
\r
2404 String error = tr("A file attachment may not exceed 25MB.");
\r
2405 QMessageBox.information(this, tr("Attachment Size"), error);
\r
2410 @SuppressWarnings("unused")
\r
2411 private void createdChanged() {
\r
2412 QDateTime dt = new QDateTime();
\r
2413 dt.setDate(createdDate.date());
\r
2414 dt.setTime(createdTime.time());
\r
2415 noteSignal.createdDateChanged.emit(currentNote.getGuid(), dt);
\r
2419 @SuppressWarnings("unused")
\r
2420 private void alteredChanged() {
\r
2421 QDateTime dt = new QDateTime();
\r
2422 dt.setDate(alteredDate.date());
\r
2423 dt.setTime(alteredTime.time());
\r
2424 noteSignal.alteredDateChanged.emit(currentNote.getGuid(), dt);
\r
2427 @SuppressWarnings("unused")
\r
2428 private void subjectDateTimeChanged() {
\r
2429 QDateTime dt = new QDateTime();
\r
2430 dt.setDate(subjectDate.date());
\r
2431 dt.setTime(subjectTime.time());
\r
2432 noteSignal.subjectDateChanged.emit(currentNote.getGuid(), dt);
\r
2436 @SuppressWarnings("unused")
\r
2437 private void sourceUrlChanged() {
\r
2438 noteSignal.sourceUrlChanged.emit(currentNote.getGuid(), urlText.text());
\r
2441 @SuppressWarnings("unused")
\r
2442 private void authorChanged() {
\r
2443 noteSignal.authorChanged.emit(currentNote.getGuid(), authorText.text());
\r
2446 @SuppressWarnings("unused")
\r
2447 private void geoBoxChanged() {
\r
2448 int index = geoBox.currentIndex();
\r
2449 geoBox.setCurrentIndex(0);
\r
2451 GeoDialog box = new GeoDialog();
\r
2452 box.setLongitude(currentNote.getAttributes().getLongitude());
\r
2453 box.setLatitude(currentNote.getAttributes().getLatitude());
\r
2454 box.setAltitude(currentNote.getAttributes().getAltitude());
\r
2456 if (!box.okPressed())
\r
2458 double alt = box.getAltitude();
\r
2459 double lat = box.getLatitude();
\r
2460 double lon = box.getLongitude();
\r
2461 if (alt != currentNote.getAttributes().getAltitude() ||
\r
2462 lon != currentNote.getAttributes().getLongitude() ||
\r
2463 lat != currentNote.getAttributes().getLatitude()) {
\r
2464 noteSignal.geoChanged.emit(currentNote.getGuid(), lon, lat, alt);
\r
2465 currentNote.getAttributes().setAltitude(alt);
\r
2466 currentNote.getAttributes().setLongitude(lon);
\r
2467 currentNote.getAttributes().setLatitude(lat);
\r
2472 noteSignal.geoChanged.emit(currentNote.getGuid(), 0.0, 0.0, 0.0);
\r
2473 currentNote.getAttributes().setAltitude(0.0);
\r
2474 currentNote.getAttributes().setLongitude(0.0);
\r
2475 currentNote.getAttributes().setLatitude(0.0);
\r
2478 if (index == 3 || index == 0) {
\r
2479 QDesktopServices.openUrl(new QUrl("http://maps.google.com/maps?z=6&q="+currentNote.getAttributes().getLatitude() +"," +currentNote.getAttributes().getLongitude()));
\r
2483 // ************************************************************
\r
2484 // * User chose to save an attachment. Pares out the request *
\r
2485 // * into a guid & file. Save the result. *
\r
2486 // ************************************************************
\r
2487 public void downloadAttachment(QNetworkRequest request) {
\r
2489 QFileDialog fd = new QFileDialog(this);
\r
2490 fd.setFileMode(FileMode.AnyFile);
\r
2491 fd.setConfirmOverwrite(true);
\r
2492 fd.setWindowTitle(tr("Save File"));
\r
2493 fd.setAcceptMode(AcceptMode.AcceptSave);
\r
2494 fd.setDirectory(System.getProperty("user.home"));
\r
2495 String name = request.url().toString();
\r
2497 int pos = name.lastIndexOf(Global.attachmentNameDelimeter);
\r
2499 guid = name.substring(0, pos).replace("nnres://", "");
\r
2500 name = name.substring(pos +Global.attachmentNameDelimeter.length());
\r
2501 fd.selectFile(name);
\r
2502 pos = name.lastIndexOf('.');
\r
2504 String mimeType = "(*." + name.substring(pos + 1)
\r
2505 + ");; All Files (*)";
\r
2506 fd.setFilter(tr(mimeType));
\r
2512 // Strip URL prefix and base dir
\r
2513 guid = guid.replace("nnres://", "")
\r
2514 .replace(FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath()), "");
\r
2515 guid = guid.replace("file://", "").replace("/", "")
\r
2516 .replace(FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath()), "");
\r
2518 pos = guid.lastIndexOf('.');
\r
2520 guid = guid.substring(0,pos);
\r
2521 if (fd.exec() != 0 && fd.selectedFiles().size() > 0) {
\r
2522 name = name.replace('\\', '/');
\r
2523 Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
\r
2524 QFile saveFile = new QFile(fd.selectedFiles().get(0));
\r
2525 QFile.OpenMode mode = new QFile.OpenMode();
\r
2526 mode.set(QFile.OpenModeFlag.WriteOnly);
\r
2527 saveFile.open(mode);
\r
2528 QDataStream saveOut = new QDataStream(saveFile);
\r
2529 QByteArray binData = new QByteArray(resBinary.getData().getBody());
\r
2530 saveOut.writeBytes(binData.toByteArray());
\r
2537 // ************************************************************
\r
2538 // * User chose to save an attachment. Pares out the request *
\r
2539 // * into a guid & file. Save the result. --- DONE FROM downloadAttachment now!!!!!
\r
2540 // ************************************************************
\r
2541 public void downloadImage(QNetworkRequest request) {
\r
2542 QFileDialog fd = new QFileDialog(this);
\r
2543 fd.setFileMode(FileMode.AnyFile);
\r
2544 fd.setConfirmOverwrite(true);
\r
2545 fd.setWindowTitle(tr("Save File"));
\r
2546 fd.setAcceptMode(AcceptMode.AcceptSave);
\r
2547 fd.setDirectory(System.getProperty("user.home"));
\r
2548 String name = request.url().toString();
\r
2549 name = name.replace("nnres://", "");
\r
2550 String dPath = FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath());
\r
2551 name = name.replace(dPath, "");
\r
2552 int pos = name.lastIndexOf('.');
\r
2553 String guid = name;
\r
2555 String mimeType = "(*." + name.substring(pos + 1)
\r
2556 + ");; All Files (*)";
\r
2557 fd.setFilter(tr(mimeType));
\r
2558 guid = guid.substring(0,pos);
\r
2560 pos = name.lastIndexOf(Global.attachmentNameDelimeter);
\r
2562 guid = name.substring(0, pos);
\r
2563 fd.selectFile(name.substring(pos+Global.attachmentNameDelimeter.length()));
\r
2565 if (fd.exec() != 0 && fd.selectedFiles().size() > 0) {
\r
2566 Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
\r
2567 String fileName = fd.selectedFiles().get(0);
\r
2568 QFile saveFile = new QFile(fileName);
\r
2569 QFile.OpenMode mode = new QFile.OpenMode();
\r
2570 mode.set(QFile.OpenModeFlag.WriteOnly);
\r
2571 saveFile.open(mode);
\r
2572 QDataStream saveOut = new QDataStream(saveFile);
\r
2573 QByteArray binData = new QByteArray(resBinary.getData().getBody());
\r
2574 saveOut.writeBytes(binData.toByteArray());
\r
2580 // *************************************************************
\r
2581 // * decrypt any hidden text. We could do an XML parse, but
\r
2582 // * it is quicker here just to scan for an <img tag & do the fix
\r
2583 // * the manual way
\r
2584 // *************************************************************
\r
2585 private void removeEncryption(String id, String plainText, boolean permanent, String slot) {
\r
2587 plainText = " <table class=\"en-crypt-temp\" slot=\""
\r
2590 +"border=1 width=100%><tbody><tr><td>"
\r
2591 +plainText+"</td></tr></tbody></table>";
\r
2594 String html = browser.page().mainFrame().toHtml();
\r
2595 String text = html;
\r
2596 int imagePos = html.indexOf("<img");
\r
2598 for ( ;imagePos>0; ) {
\r
2599 // Find the end tag
\r
2600 endPos = text.indexOf(">", imagePos);
\r
2601 String tag = text.substring(imagePos-1,endPos);
\r
2602 if (tag.indexOf("id=\""+id+"\"") > -1) {
\r
2603 text = text.substring(0,imagePos) +plainText+text.substring(endPos+1);
\r
2604 QTextCodec codec = QTextCodec.codecForName("UTF-8");
\r
2605 QByteArray unicode = codec.fromUnicode(text);
\r
2606 browser.setContent(unicode);
\r
2610 imagePos = text.indexOf("<img", imagePos+1);
\r
2615 //****************************************************************
\r
2616 //* Focus shortcuts
\r
2617 //****************************************************************
\r
2618 @SuppressWarnings("unused")
\r
2619 private void focusTitle() {
\r
2620 titleLabel.setFocus();
\r
2622 @SuppressWarnings("unused")
\r
2623 private void focusTag() {
\r
2624 tagEdit.setFocus();
\r
2626 @SuppressWarnings("unused")
\r
2627 private void focusNote() {
\r
2628 browser.setFocus();
\r
2630 @SuppressWarnings("unused")
\r
2631 private void focusAuthor() {
\r
2632 authorLabel.setFocus();
\r
2634 @SuppressWarnings("unused")
\r
2635 private void focusUrl() {
\r
2636 urlLabel.setFocus();
\r
2640 //*****************************************************************
\r
2641 //* Set the document background color
\r
2642 //*****************************************************************
\r
2643 public void setBackgroundColor(String color) {
\r
2644 String js = "function changeBackground(color) {"
\r
2645 +"document.body.style.background = color;"
\r
2647 +"changeBackground('" +color+"');";
\r
2648 browser.page().mainFrame().evaluateJavaScript(js);
\r
2653 //****************************************************************
\r
2654 //* MicroFocus changed
\r
2655 //****************************************************************
\r
2656 private void microFocusChanged() {
\r
2657 boldButton.setDown(false);
\r
2658 italicButton.setDown(false);
\r
2659 underlineButton.setDown(false);
\r
2660 browser.openAction.setEnabled(false);
\r
2661 browser.downloadAttachment.setEnabled(false);
\r
2662 browser.downloadImage.setEnabled(false);
\r
2663 browser.rotateImageLeft.setEnabled(false);
\r
2664 browser.rotateImageRight.setEnabled(false);
\r
2665 browser.insertTableAction.setEnabled(true);
\r
2666 browser.deleteTableColumnAction.setEnabled(false);
\r
2667 browser.insertTableRowAction.setEnabled(false);
\r
2668 browser.insertTableColumnAction.setEnabled(false);
\r
2669 browser.deleteTableRowAction.setEnabled(false);
\r
2670 browser.insertLinkAction.setText(tr("Insert Hyperlink"));
\r
2671 insertHyperlink = true;
\r
2672 currentHyperlink ="";
\r
2673 insideList = false;
\r
2674 insideTable = false;
\r
2675 insideEncryption = false;
\r
2676 forceTextPaste = false;
\r
2678 String js = new String( "function getCursorPos() {"
\r
2680 +"if (window.getSelection) {"
\r
2681 +" var selObj = window.getSelection();"
\r
2682 +" var selRange = selObj.getRangeAt(0);"
\r
2683 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
2684 +" while(workingNode != null) { "
\r
2685 // +" window.jambi.printNode(workingNode.nodeName);"
\r
2686 +" if (workingNode.nodeName=='TABLE') { if (workingNode.getAttribute('class').toLowerCase() == 'en-crypt-temp') window.jambi.insideEncryption(); }"
\r
2687 +" if (workingNode.nodeName=='B') window.jambi.boldActive();"
\r
2688 +" if (workingNode.nodeName=='I') window.jambi.italicActive();"
\r
2689 +" if (workingNode.nodeName=='U') window.jambi.underlineActive();"
\r
2690 +" if (workingNode.nodeName=='UL') window.jambi.setInsideList();"
\r
2691 +" if (workingNode.nodeName=='OL') window.jambi.setInsideList();"
\r
2692 +" if (workingNode.nodeName=='LI') window.jambi.setInsideList();"
\r
2693 +" if (workingNode.nodeName=='TBODY') window.jambi.setInsideTable();"
\r
2694 +" 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
2695 +" if (workingNode.nodeName=='SPAN') {"
\r
2696 +" if (workingNode.getAttribute('style') == 'text-decoration: underline;') window.jambi.underlineActive();"
\r
2698 +" workingNode = workingNode.parentNode;"
\r
2701 +"} getCursorPos();");
\r
2702 browser.page().mainFrame().evaluateJavaScript(js);
\r
2705 public void printNode(String n) {
\r
2706 System.out.println("Node Vaule: " +n);
\r
2709 public void insideEncryption() {
\r
2710 insideEncryption = true;
\r
2714 //****************************************************************
\r
2715 //* Insert a table row
\r
2716 //****************************************************************
\r
2717 public void insertTableRow() {
\r
2719 String js = new String( "function insertTableRow() {"
\r
2720 +" var selObj = window.getSelection();"
\r
2721 +" var selRange = selObj.getRangeAt(0);"
\r
2722 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
2723 +" var cellCount = 0;"
\r
2724 +" while(workingNode != null) { "
\r
2725 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
\r
2726 +" row = document.createElement('TR');"
\r
2727 +" var nodes = workingNode.getElementsByTagName('td');"
\r
2728 +" for (j=0; j<nodes.length; j=j+1) {"
\r
2729 +" cell = document.createElement('TD');"
\r
2730 +" cell.innerHTML=' ';"
\r
2731 +" row.appendChild(cell);"
\r
2733 +" workingNode.parentNode.insertBefore(row,workingNode.nextSibling);"
\r
2736 +" workingNode = workingNode.parentNode;"
\r
2738 +"} insertTableRow();");
\r
2739 browser.page().mainFrame().evaluateJavaScript(js);
\r
2743 public void insertTableColumn() {
\r
2744 String js = new String( "function insertTableColumn() {"
\r
2745 +" var selObj = window.getSelection();"
\r
2746 +" var selRange = selObj.getRangeAt(0);"
\r
2747 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
2748 +" var current = 0;"
\r
2749 +" while (workingNode.nodeName.toLowerCase() != 'table' && workingNode != null) {"
\r
2750 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
\r
2751 +" var td = workingNode;"
\r
2752 +" while (td.previousSibling != null) { "
\r
2753 +" current = current+1; td = td.previousSibling;"
\r
2756 +" workingNode = workingNode.parentNode; "
\r
2758 +" if (workingNode == null) return;"
\r
2759 +" for (var i=0; i<workingNode.rows.length; i++) { "
\r
2760 +" var cell = workingNode.rows[i].insertCell(current+1); "
\r
2761 +" cell.innerHTML = ' '; "
\r
2763 +"} insertTableColumn();");
\r
2764 browser.page().mainFrame().evaluateJavaScript(js);
\r
2768 //****************************************************************
\r
2769 //* Delete a table row
\r
2770 //****************************************************************
\r
2771 public void deleteTableRow() {
\r
2773 String js = new String( "function deleteTableRow() {"
\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 +" workingNode.parentNode.removeChild(workingNode);"
\r
2783 +" workingNode = workingNode.parentNode;"
\r
2785 +"} deleteTableRow();");
\r
2786 browser.page().mainFrame().evaluateJavaScript(js);
\r
2790 public void deleteTableColumn() {
\r
2791 String js = new String( "function deleteTableColumn() {"
\r
2792 +" var selObj = window.getSelection();"
\r
2793 +" var selRange = selObj.getRangeAt(0);"
\r
2794 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
2795 +" var current = 0;"
\r
2796 +" while (workingNode.nodeName.toLowerCase() != 'table' && workingNode != null) {"
\r
2797 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
\r
2798 +" var td = workingNode;"
\r
2799 +" while (td.previousSibling != null) { "
\r
2800 +" current = current+1; td = td.previousSibling;"
\r
2803 +" workingNode = workingNode.parentNode; "
\r
2805 +" if (workingNode == null) return;"
\r
2806 +" for (var i=0; i<workingNode.rows.length; i++) { "
\r
2807 +" workingNode.rows[i].deleteCell(current); "
\r
2809 +"} deleteTableColumn();");
\r
2810 browser.page().mainFrame().evaluateJavaScript(js);
\r
2815 public void setInsideTable() {
\r
2816 browser.insertTableRowAction.setEnabled(true);
\r
2817 browser.insertTableColumnAction.setEnabled(true);
\r
2818 browser.deleteTableRowAction.setEnabled(true);
\r
2819 browser.deleteTableColumnAction.setEnabled(true);
\r
2820 browser.insertTableAction.setEnabled(false);
\r
2821 browser.encryptAction.setEnabled(false);
\r
2822 insideTable = true;
\r
2825 public void setInsideLink(String link) {
\r
2826 browser.insertLinkAction.setText(tr("Edit Hyperlink"));
\r
2827 currentHyperlink = link;
\r
2828 insertHyperlink = false;
\r
2831 public void italicActive() {
\r
2832 italicButton.setDown(true);
\r
2834 public void boldActive() {
\r
2835 boldButton.setDown(true);
\r
2837 public void underlineActive() {
\r
2838 underlineButton.setDown(true);
\r
2840 public void forceTextPaste() {
\r
2841 forceTextPaste = true;
\r
2843 public void imageContextMenu(String f) {
\r
2844 browser.downloadImage.setEnabled(true);
\r
2845 browser.rotateImageRight.setEnabled(true);
\r
2846 browser.rotateImageLeft.setEnabled(true);
\r
2847 browser.openAction.setEnabled(true);
\r
2850 public void rotateImageRight() {
\r
2851 QWebSettings.setMaximumPagesInCache(0);
\r
2852 QWebSettings.setObjectCacheCapacities(0, 0, 0);
\r
2853 QImage image = new QImage(selectedFile);
\r
2854 QMatrix matrix = new QMatrix();
\r
2855 matrix.rotate( 90.0 );
\r
2856 image = image.transformed(matrix);
\r
2857 image.save(selectedFile);
\r
2858 QWebSettings.setMaximumPagesInCache(0);
\r
2859 QWebSettings.setObjectCacheCapacities(0, 0, 0);
\r
2860 browser.setHtml(browser.page().mainFrame().toHtml());
\r
2863 resourceSignal.contentChanged.emit(selectedFile);
\r
2866 public void rotateImageLeft() {
\r
2867 QImage image = new QImage(selectedFile);
\r
2868 QMatrix matrix = new QMatrix();
\r
2869 matrix.rotate( -90.0 );
\r
2870 image = image.transformed(matrix);
\r
2871 image.save(selectedFile);
\r
2872 browser.setHtml(browser.page().mainFrame().toHtml());
\r
2875 resourceSignal.contentChanged.emit(selectedFile);
\r
2877 public void resourceContextMenu(String f) {
\r
2878 browser.downloadAttachment.setEnabled(true);
\r
2879 browser.openAction.setEnabled(true);
\r
2882 public void latexContextMenu(String f) {
\r
2883 browser.downloadImage.setEnabled(true);
\r
2884 browser.rotateImageRight.setEnabled(true);
\r
2885 browser.rotateImageLeft.setEnabled(true);
\r
2886 browser.openAction.setEnabled(true);
\r
2890 //****************************************************************
\r
2891 //* Apply CSS style to specified word
\r
2892 //****************************************************************
\r
2893 /* public void applyStyleToWords(String word, String style) {
\r
2894 QFile script = new QFile("D:\\NeverNote\\js\\hilight1.js");
\r
2895 script.open(OpenModeFlag.ReadOnly);
\r
2896 String s = script.readAll().toString();
\r
2897 String js = new String(s +" findit('"+word+"', '"+style+"');");
\r
2898 browser.page().mainFrame().evaluateJavaScript(js);
\r
2899 System.out.println(getContent());
\r
2902 //****************************************************************
\r
2903 //* Someone tried to paste a resource between notes, so we need *
\r
2904 //* to do some special handling. *
\r
2905 //****************************************************************
\r
2906 private String fixInternotePaste(String text) {
\r
2907 logger.log(logger.EXTREME, "Fixing internote paste");
\r
2908 String returnValue = fixInternotePasteSearch(text, "<img", "src=\"");
\r
2909 return fixInternotePasteSearch(returnValue, "<a", "href=\"nnres://");
\r
2911 private String fixInternotePasteSearch(String text, String type, String locTag) {
\r
2913 // First, let's fix the images.
\r
2914 int startPos = text.indexOf(type);
\r
2916 for (; startPos>=0;) {
\r
2917 endPos = text.indexOf(">", startPos+1);
\r
2918 String segment = text.substring(startPos, endPos);
\r
2919 if (segment.indexOf("en-tag") > -1) {
\r
2920 String newSegment = segment;
\r
2922 int guidStartPos = segment.indexOf("guid=\"");
\r
2923 int guidEndPos = segment.indexOf("\"", guidStartPos+7);
\r
2924 String guid = segment.substring(guidStartPos+6,guidEndPos);
\r
2926 int mimeStartPos = segment.indexOf("type");
\r
2927 int mimeEndPos = segment.indexOf("\"", mimeStartPos+7);
\r
2928 String mime = segment.substring(mimeStartPos+6,mimeEndPos);
\r
2930 int srcStartPos = segment.indexOf("src");
\r
2931 int srcEndPos = segment.indexOf("\"", srcStartPos+6);
\r
2932 String src = segment.substring(srcStartPos+5,srcEndPos);
\r
2934 Calendar currentTime = new GregorianCalendar();
\r
2935 Long l = new Long(currentTime.getTimeInMillis());
\r
2936 long prevTime = l;
\r
2937 while (l==prevTime) {
\r
2938 currentTime = new GregorianCalendar();
\r
2939 l= new Long(currentTime.getTimeInMillis());
\r
2942 Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
\r
2943 // if r==null, then the image doesn't exist (it was probably cut out of another note, so
\r
2944 // we need to recereate it
\r
2946 r = createResource(src, 1, mime, false);
\r
2950 String randint = new String(Long.toString(l));
\r
2951 String extension = null;
\r
2952 if (r.getMime()!= null) {
\r
2953 extension = r.getMime().toLowerCase();
\r
2954 if (extension.indexOf("/")>-1)
\r
2955 extension = extension.substring(extension.indexOf("/")+1);
\r
2957 String newFile = randint;
\r
2958 if (r.getAttributes().getFileName() != null && r.getAttributes().getFileName() != "")
\r
2959 if (!locTag.startsWith("src"))
\r
2960 newFile = newFile+Global.attachmentNameDelimeter+r.getAttributes().getFileName();
\r
2961 r.setNoteGuid(currentNote.getGuid());
\r
2963 r.setGuid(randint);
\r
2964 conn.getNoteTable().noteResourceTable.saveNoteResource(r, true);
\r
2965 QFile f = new QFile(Global.getFileManager().getResDirPath(newFile));
\r
2966 QByteArray bin = new QByteArray(r.getData().getBody());
\r
2967 f.open(QFile.OpenModeFlag.WriteOnly);
\r
2970 newSegment = newSegment.replace("guid=\""+guid, "guid=\""+randint);
\r
2971 currentNote.getResources().add(r);
\r
2973 int startSrcPos = newSegment.indexOf(locTag);
\r
2974 int endSrcPos = newSegment.indexOf("\"",startSrcPos+locTag.length()+1);
\r
2976 if (locTag.startsWith("src")) {
\r
2977 source = newSegment.substring(startSrcPos+locTag.length(),endSrcPos);
\r
2978 newSegment = newSegment.replace(source,
\r
2979 FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath(newFile)));
\r
2981 source = newSegment.substring(startSrcPos+locTag.length(),endSrcPos);
\r
2982 newSegment = newSegment.replace(source, newFile);
\r
2985 text = text.substring(0,startPos) + newSegment + text.substring(endPos);
\r
2987 startPos = text.indexOf(type, startPos+1);
\r
2993 public void nextPage(String file) {
\r
2994 logger.log(logger.EXTREME, "Starting nextPage()");
\r
2996 Integer pageNumber;
\r
2997 if (previewPageList.containsKey(file))
\r
2998 pageNumber = previewPageList.get(file)+1;
\r
3001 previewPageList.remove(file);
\r
3002 previewPageList.put(file, pageNumber);
\r
3003 PDFPreview pdfPreview = new PDFPreview();
\r
3004 boolean goodPreview = pdfPreview.setupPreview(file, "pdf", pageNumber);
\r
3005 if (goodPreview) {
\r
3007 // String html = getContent();
\r
3008 QWebSettings.setMaximumPagesInCache(0);
\r
3009 QWebSettings.setObjectCacheCapacities(0, 0, 0);
\r
3010 // browser.setContent(new QByteArray());
\r
3011 browser.setHtml(browser.page().mainFrame().toHtml());
\r
3013 // browser.setContent(new QByteArray(html));
\r
3014 // browser.triggerPageAction(WebAction.Reload);
\r
3015 // pdfMouseOver(selectedFile);
\r
3019 public void previousPage(String file) {
\r
3020 logger.log(logger.EXTREME, "Starting previousPage()");
\r
3022 Integer pageNumber;
\r
3023 if (previewPageList.containsKey(file))
\r
3024 pageNumber = previewPageList.get(file)-1;
\r
3027 previewPageList.remove(file);
\r
3028 previewPageList.put(file, pageNumber);
\r
3029 PDFPreview pdfPreview = new PDFPreview();
\r
3030 boolean goodPreview = pdfPreview.setupPreview(file, "pdf", pageNumber);
\r
3031 if (goodPreview) {
\r
3033 // String html = getContent();
\r
3034 QWebSettings.setMaximumPagesInCache(0);
\r
3035 QWebSettings.setObjectCacheCapacities(0, 0, 0);
\r
3036 browser.setHtml(browser.page().mainFrame().toHtml());
\r
3038 // browser.setContent(new QByteArray(html));
\r
3039 // browser.triggerPageAction(WebAction.Reload);
\r
3043 /* public void pdfMouseOver(String name) {
\r
3045 if (previewPageList.containsKey(selectedFile))
\r
3046 pageNumber = previewPageList.get(selectedFile)+1;
\r
3050 if (pageNumber <= 1)
\r
3051 browser.previousPageAction.setEnabled(false);
\r
3053 browser.previousPageAction.setEnabled(true);
\r
3055 PDFPreview pdf = new PDFPreview();
\r
3056 int totalPages = pdf.getPageCount(name);
\r
3057 if (previewPageList.containsKey(selectedFile))
\r
3058 pageNumber = previewPageList.get(selectedFile)+1;
\r
3061 if (totalPages > pageNumber)
\r
3062 browser.nextPageAction.setEnabled(true);
\r
3064 browser.nextPageAction.setEnabled(false);
\r
3068 public void pdfMouseOut() {
\r
3069 // browser.nextPageAction.setVisible(false);
\r
3070 // browser.previousPageAction.setVisible(false);
\r
3074 @SuppressWarnings("unused")
\r
3075 private void toggleUndoVisible(Boolean toggle) {
\r
3076 undoAction.setVisible(toggle);
\r
3077 Global.saveEditorButtonsVisible("undo", toggle);
\r
3079 @SuppressWarnings("unused")
\r
3080 private void toggleRedoVisible(Boolean toggle) {
\r
3081 redoAction.setVisible(toggle);
\r
3082 Global.saveEditorButtonsVisible("redo", toggle);
\r
3084 @SuppressWarnings("unused")
\r
3085 private void toggleCutVisible(Boolean toggle) {
\r
3086 cutAction.setVisible(toggle);
\r
3087 Global.saveEditorButtonsVisible("cut", toggle);
\r
3089 @SuppressWarnings("unused")
\r
3090 private void toggleCopyVisible(Boolean toggle) {
\r
3091 copyAction.setVisible(toggle);
\r
3092 Global.saveEditorButtonsVisible("copy", toggle);
\r
3094 @SuppressWarnings("unused")
\r
3095 private void togglePasteVisible(Boolean toggle) {
\r
3096 pasteAction.setVisible(toggle);
\r
3097 Global.saveEditorButtonsVisible("paste", toggle);
\r
3099 @SuppressWarnings("unused")
\r
3100 private void toggleBoldVisible(Boolean toggle) {
\r
3101 boldAction.setVisible(toggle);
\r
3102 Global.saveEditorButtonsVisible("bold", toggle);
\r
3104 @SuppressWarnings("unused")
\r
3105 private void toggleItalicVisible(Boolean toggle) {
\r
3106 italicAction.setVisible(toggle);
\r
3107 Global.saveEditorButtonsVisible("italic", toggle);
\r
3109 @SuppressWarnings("unused")
\r
3110 private void toggleUnderlineVisible(Boolean toggle) {
\r
3111 underlineAction.setVisible(toggle);
\r
3112 Global.saveEditorButtonsVisible("underline", toggle);
\r
3114 @SuppressWarnings("unused")
\r
3115 private void toggleStrikethroughVisible(Boolean toggle) {
\r
3116 strikethroughAction.setVisible(toggle);
\r
3117 Global.saveEditorButtonsVisible("strikethrough", toggle);
\r
3119 @SuppressWarnings("unused")
\r
3120 private void toggleLeftAlignVisible(Boolean toggle) {
\r
3121 leftAlignAction.setVisible(toggle);
\r
3122 Global.saveEditorButtonsVisible("alignLeft", toggle);
\r
3124 @SuppressWarnings("unused")
\r
3125 private void toggleRightAlignVisible(Boolean toggle) {
\r
3126 rightAlignAction.setVisible(toggle);
\r
3127 Global.saveEditorButtonsVisible("alignRight", toggle);
\r
3129 @SuppressWarnings("unused")
\r
3130 private void toggleCenterAlignVisible(Boolean toggle) {
\r
3131 centerAlignAction.setVisible(toggle);
\r
3132 Global.saveEditorButtonsVisible("alignCenter", toggle);
\r
3134 @SuppressWarnings("unused")
\r
3135 private void toggleHLineVisible(Boolean toggle) {
\r
3136 hlineAction.setVisible(toggle);
\r
3137 Global.saveEditorButtonsVisible("hline", toggle);
\r
3139 @SuppressWarnings("unused")
\r
3140 private void toggleIndentVisible(Boolean toggle) {
\r
3141 indentAction.setVisible(toggle);
\r
3142 Global.saveEditorButtonsVisible("indent", toggle);
\r
3144 @SuppressWarnings("unused")
\r
3145 private void toggleTodoVisible(Boolean toggle) {
\r
3146 todoAction.setVisible(toggle);
\r
3147 Global.saveEditorButtonsVisible("todo", toggle);
\r
3149 @SuppressWarnings("unused")
\r
3150 private void toggleOutdentVisible(Boolean toggle) {
\r
3151 outdentAction.setVisible(toggle);
\r
3152 Global.saveEditorButtonsVisible("outdent", toggle);
\r
3154 @SuppressWarnings("unused")
\r
3155 private void toggleBulletListVisible(Boolean toggle) {
\r
3156 bulletListAction.setVisible(toggle);
\r
3157 Global.saveEditorButtonsVisible("bulletList", toggle);
\r
3159 @SuppressWarnings("unused")
\r
3160 private void toggleNumberListVisible(Boolean toggle) {
\r
3161 numberListAction.setVisible(toggle);
\r
3162 Global.saveEditorButtonsVisible("numberList", toggle);
\r
3164 @SuppressWarnings("unused")
\r
3165 private void toggleFontListVisible(Boolean toggle) {
\r
3166 fontListAction.setVisible(toggle);
\r
3167 Global.saveEditorButtonsVisible("font", toggle);
\r
3169 @SuppressWarnings("unused")
\r
3170 private void toggleFontColorVisible(Boolean toggle) {
\r
3171 fontColorAction.setVisible(toggle);
\r
3172 Global.saveEditorButtonsVisible("fontColor", toggle);
\r
3174 @SuppressWarnings("unused")
\r
3175 private void toggleFontSizeVisible(Boolean toggle) {
\r
3176 fontSizeAction.setVisible(toggle);
\r
3177 Global.saveEditorButtonsVisible("fontSize", toggle);
\r
3179 @SuppressWarnings("unused")
\r
3180 private void toggleFontHilightVisible(Boolean toggle) {
\r
3181 fontHilightAction.setVisible(toggle);
\r
3182 Global.saveEditorButtonsVisible("fontHilight", toggle);
\r
3184 @SuppressWarnings("unused")
\r
3185 private void toggleSpellCheckVisible(Boolean toggle) {
\r
3186 spellCheckAction.setVisible(toggle);
\r
3187 Global.saveEditorButtonsVisible("spellCheck", toggle);
\r
3191 private void setupDictionary() {
\r
3192 File wordList = new File(Global.getFileManager().getSpellDirPath()+Locale.getDefault()+".dic");
\r
3194 dictionary = new SpellDictionaryHashMap(wordList);
\r
3195 spellChecker = new SpellChecker(dictionary);
\r
3197 File userWordList;
\r
3198 userWordList = new File(Global.getFileManager().getSpellDirPathUser()+"user.dic");
\r
3200 // Get the local user spell dictionary
\r
3202 userDictionary = new SpellDictionaryHashMap(userWordList);
\r
3203 } catch (FileNotFoundException e) {
\r
3204 userWordList.createNewFile();
\r
3205 userDictionary = new SpellDictionaryHashMap(userWordList);
\r
3206 } catch (IOException e) {
\r
3207 userWordList.createNewFile();
\r
3208 userDictionary = new SpellDictionaryHashMap(userWordList);
\r
3211 spellListener = new SuggestionListener(this, spellChecker);
\r
3213 // Add the user dictionary
\r
3214 spellChecker.addSpellCheckListener(spellListener);
\r
3215 spellChecker.setUserDictionary(userDictionary);
\r
3217 } catch (FileNotFoundException e) {
\r
3218 QMessageBox.critical(this, tr("Spell Check Error"),
\r
3219 tr("Dictionary "+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+
\r
3220 ".dic was not found."));
\r
3221 } catch (IOException e) {
\r
3222 QMessageBox.critical(this, tr("Spell Check Error"),
\r
3223 tr("Dictionary "+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+
\r
3224 ".dic is invalid."));
\r
3229 // Invoke spell checker dialog
\r
3230 @SuppressWarnings("unused")
\r
3231 private void spellCheckClicked() {
\r
3233 if (spellChecker == null) {
\r
3234 setupDictionary();
\r
3237 // Read user settings
\r
3238 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREDIGITWORDS,
\r
3239 Global.getSpellSetting(Configuration.SPELL_IGNOREDIGITWORDS));
\r
3240 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREINTERNETADDRESSES,
\r
3241 Global.getSpellSetting(Configuration.SPELL_IGNOREINTERNETADDRESSES));
\r
3242 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREMIXEDCASE,
\r
3243 Global.getSpellSetting(Configuration.SPELL_IGNOREMIXEDCASE));
\r
3244 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREUPPERCASE,
\r
3245 Global.getSpellSetting(Configuration.SPELL_IGNOREUPPERCASE));
\r
3246 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNORESENTENCECAPITALIZATION,
\r
3247 Global.getSpellSetting(Configuration.SPELL_IGNORESENTENCECAPITALIZATION));
\r
3249 spellListener.abortSpellCheck = false;
\r
3250 spellListener.errorsFound = false;
\r
3251 String content = getBrowser().page().mainFrame().toPlainText();
\r
3252 StringWordTokenizer tokenizer = new StringWordTokenizer(content);
\r
3253 if (!tokenizer.hasMoreWords())
\r
3255 getBrowser().page().action(WebAction.MoveToStartOfDocument);
\r
3257 getBrowser().setFocus();
\r
3260 // Move to the start of page
\r
3261 KeyboardModifiers ctrl = new KeyboardModifiers(KeyboardModifier.ControlModifier.value());
\r
3262 QKeyEvent home = new QKeyEvent(Type.KeyPress, Key.Key_Home.value(), ctrl);
\r
3263 browser.keyPressEvent(home);
\r
3264 getBrowser().setFocus();
\r
3266 tokenizer = new StringWordTokenizer(content);
\r
3269 while(tokenizer.hasMoreWords()) {
\r
3270 word = tokenizer.nextWord();
\r
3271 found = getBrowser().page().findText(word);
\r
3272 if (found && !spellListener.abortSpellCheck) {
\r
3273 spellChecker.checkSpelling(new StringWordTokenizer(word));
\r
3274 getBrowser().setFocus();
\r
3278 // Go to the end of the document & finish up.
\r
3279 home = new QKeyEvent(Type.KeyPress, Key.Key_End.value(), ctrl);
\r
3280 browser.keyPressEvent(home);
\r
3281 if (!spellListener.errorsFound)
\r
3282 QMessageBox.information(this, tr("Spell Check Complete"),
\r
3283 tr("No Errors Found"));
\r