2 * This file is part of NeverNote
\r
3 * Copyright 2009 Randy Baumgarte
\r
5 * This file may be licensed under the terms of of the
\r
6 * GNU General Public License Version 2 (the ``GPL'').
\r
8 * Software distributed under the License is distributed
\r
9 * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
\r
10 * express or implied. See the GPL for the specific language
\r
11 * governing rights and limitations.
\r
13 * You should have received a copy of the GPL along with this
\r
14 * program. If not, go to http://www.gnu.org/licenses/gpl.html
\r
15 * or write to the Free Software Foundation, Inc.,
\r
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
\r
20 package cx.fbn.nevernote.gui;
\r
22 import java.io.File;
\r
23 import java.io.FileNotFoundException;
\r
24 import java.io.IOException;
\r
25 import java.net.FileNameMap;
\r
26 import java.net.URI;
\r
27 import java.net.URLConnection;
\r
28 import java.security.MessageDigest;
\r
29 import java.security.NoSuchAlgorithmException;
\r
30 import java.text.SimpleDateFormat;
\r
31 import java.util.ArrayList;
\r
32 import java.util.Calendar;
\r
33 import java.util.Collections;
\r
34 import java.util.Date;
\r
35 import java.util.GregorianCalendar;
\r
36 import java.util.HashMap;
\r
37 import java.util.List;
\r
38 import java.util.Locale;
\r
40 import org.apache.commons.lang.StringUtils;
\r
42 import com.evernote.edam.limits.Constants;
\r
43 import com.evernote.edam.type.Data;
\r
44 import com.evernote.edam.type.Note;
\r
45 import com.evernote.edam.type.Notebook;
\r
46 import com.evernote.edam.type.Resource;
\r
47 import com.evernote.edam.type.ResourceAttributes;
\r
48 import com.evernote.edam.type.Tag;
\r
49 import com.swabunga.spell.engine.Configuration;
\r
50 import com.swabunga.spell.engine.SpellDictionary;
\r
51 import com.swabunga.spell.engine.SpellDictionaryHashMap;
\r
52 import com.swabunga.spell.engine.Word;
\r
53 import com.swabunga.spell.event.SpellCheckEvent;
\r
54 import com.swabunga.spell.event.SpellCheckListener;
\r
55 import com.swabunga.spell.event.SpellChecker;
\r
56 import com.swabunga.spell.event.StringWordTokenizer;
\r
57 import com.trolltech.qt.core.QByteArray;
\r
58 import com.trolltech.qt.core.QCoreApplication;
\r
59 import com.trolltech.qt.core.QDataStream;
\r
60 import com.trolltech.qt.core.QDateTime;
\r
61 import com.trolltech.qt.core.QEvent;
\r
62 import com.trolltech.qt.core.QEvent.Type;
\r
63 import com.trolltech.qt.core.QFile;
\r
64 import com.trolltech.qt.core.QFileSystemWatcher;
\r
65 import com.trolltech.qt.core.QIODevice;
\r
66 import com.trolltech.qt.core.QMimeData;
\r
67 import com.trolltech.qt.core.QTextCodec;
\r
68 import com.trolltech.qt.core.QUrl;
\r
69 import com.trolltech.qt.core.Qt;
\r
70 import com.trolltech.qt.core.Qt.Key;
\r
71 import com.trolltech.qt.core.Qt.KeyboardModifier;
\r
72 import com.trolltech.qt.core.Qt.KeyboardModifiers;
\r
73 import com.trolltech.qt.gui.QAction;
\r
74 import com.trolltech.qt.gui.QApplication;
\r
75 import com.trolltech.qt.gui.QCalendarWidget;
\r
76 import com.trolltech.qt.gui.QClipboard;
\r
77 import com.trolltech.qt.gui.QClipboard.Mode;
\r
78 import com.trolltech.qt.gui.QColor;
\r
79 import com.trolltech.qt.gui.QComboBox;
\r
80 import com.trolltech.qt.gui.QDateEdit;
\r
81 import com.trolltech.qt.gui.QDesktopServices;
\r
82 import com.trolltech.qt.gui.QFileDialog;
\r
83 import com.trolltech.qt.gui.QFileDialog.AcceptMode;
\r
84 import com.trolltech.qt.gui.QFileDialog.FileMode;
\r
85 import com.trolltech.qt.gui.QFontDatabase;
\r
86 import com.trolltech.qt.gui.QFormLayout;
\r
87 import com.trolltech.qt.gui.QGridLayout;
\r
88 import com.trolltech.qt.gui.QHBoxLayout;
\r
89 import com.trolltech.qt.gui.QIcon;
\r
90 import com.trolltech.qt.gui.QImage;
\r
91 import com.trolltech.qt.gui.QKeyEvent;
\r
92 import com.trolltech.qt.gui.QKeySequence;
\r
93 import com.trolltech.qt.gui.QLabel;
\r
94 import com.trolltech.qt.gui.QLineEdit;
\r
95 import com.trolltech.qt.gui.QListWidgetItem;
\r
96 import com.trolltech.qt.gui.QMatrix;
\r
97 import com.trolltech.qt.gui.QMessageBox;
\r
98 import com.trolltech.qt.gui.QPalette;
\r
99 import com.trolltech.qt.gui.QPalette.ColorRole;
\r
100 import com.trolltech.qt.gui.QPushButton;
\r
101 import com.trolltech.qt.gui.QShortcut;
\r
102 import com.trolltech.qt.gui.QTimeEdit;
\r
103 import com.trolltech.qt.gui.QToolButton;
\r
104 import com.trolltech.qt.gui.QToolButton.ToolButtonPopupMode;
\r
105 import com.trolltech.qt.gui.QVBoxLayout;
\r
106 import com.trolltech.qt.gui.QWidget;
\r
107 import com.trolltech.qt.network.QNetworkAccessManager;
\r
108 import com.trolltech.qt.network.QNetworkReply;
\r
109 import com.trolltech.qt.network.QNetworkReply.NetworkError;
\r
110 import com.trolltech.qt.network.QNetworkRequest;
\r
111 import com.trolltech.qt.webkit.QWebPage;
\r
112 import com.trolltech.qt.webkit.QWebPage.WebAction;
\r
113 import com.trolltech.qt.webkit.QWebSettings;
\r
114 import com.trolltech.qt.webkit.QWebView;
\r
116 import cx.fbn.nevernote.Global;
\r
117 import cx.fbn.nevernote.dialog.EnCryptDialog;
\r
118 import cx.fbn.nevernote.dialog.EnDecryptDialog;
\r
119 import cx.fbn.nevernote.dialog.GeoDialog;
\r
120 import cx.fbn.nevernote.dialog.InsertLatexImage;
\r
121 import cx.fbn.nevernote.dialog.InsertLinkDialog;
\r
122 import cx.fbn.nevernote.dialog.SpellCheck;
\r
123 import cx.fbn.nevernote.dialog.TableDialog;
\r
124 import cx.fbn.nevernote.dialog.TagAssign;
\r
125 import cx.fbn.nevernote.evernote.EnCrypt;
\r
126 import cx.fbn.nevernote.filters.FilterEditorTags;
\r
127 import cx.fbn.nevernote.signals.NoteResourceSignal;
\r
128 import cx.fbn.nevernote.signals.NoteSignal;
\r
129 import cx.fbn.nevernote.sql.DatabaseConnection;
\r
130 import cx.fbn.nevernote.utilities.ApplicationLogger;
\r
131 import cx.fbn.nevernote.utilities.FileUtils;
\r
132 import cx.fbn.nevernote.utilities.Pair;
\r
134 public class BrowserWindow extends QWidget {
\r
136 public final QLineEdit titleLabel;
\r
137 private final QLineEdit urlText;
\r
138 private final QLabel authorLabel;
\r
139 private final QLineEdit authorText;
\r
140 private final QComboBox geoBox;
\r
141 public final TagLineEdit tagEdit;
\r
142 public final QLabel tagLabel;
\r
143 private final QPushButton urlLabel;
\r
144 private final QLabel alteredLabel;
\r
145 private final QDateEdit alteredDate;
\r
146 private final QTimeEdit alteredTime;
\r
147 private final QDateEdit createdDate;
\r
148 private final QTimeEdit createdTime;
\r
149 private final QLabel subjectLabel;
\r
150 private final QDateEdit subjectDate;
\r
151 private final QTimeEdit subjectTime;
\r
152 public final QComboBox notebookBox;
\r
153 private final QLabel notebookLabel;
\r
154 private final QLabel createdLabel;
\r
155 public final QComboBox fontSize;
\r
156 public final QAction fontSizeAction;
\r
157 private boolean extendedOn;
\r
158 public boolean buttonsVisible;
\r
159 private final String iconPath = new String("classpath:cx/fbn/nevernote/icons/");
\r
160 private final ContentView browser;
\r
161 private List<Tag> allTags;
\r
162 private List<String> currentTags;
\r
163 public NoteSignal noteSignal;
\r
164 private List<Notebook> notebookList;
\r
165 private Note currentNote;
\r
166 private String saveNoteTitle;
\r
167 private String saveTagList;
\r
168 private boolean insideList;
\r
169 private final DatabaseConnection conn;
\r
170 private final QCalendarWidget createdCalendarWidget;
\r
171 private final QCalendarWidget alteredCalendarWidget;
\r
172 private final QCalendarWidget subjectCalendarWidget;
\r
174 public final QPushButton undoButton;
\r
175 public final QAction undoAction;
\r
176 public final QPushButton redoButton;
\r
177 public final QAction redoAction;
\r
178 public final QPushButton cutButton;
\r
179 public final QAction cutAction;
\r
180 public final QPushButton copyButton;
\r
181 public final QAction copyAction;
\r
182 public final QPushButton pasteButton;
\r
183 public final QAction pasteAction;
\r
184 public final QPushButton boldButton;
\r
185 public final QAction boldAction;
\r
186 public final QPushButton underlineButton;
\r
187 public final QAction underlineAction;
\r
188 public final QPushButton italicButton;
\r
189 public final QAction italicAction;
\r
190 public final Signal0 focusLost;
\r
191 public final NoteResourceSignal resourceSignal;
\r
193 public QPushButton rightAlignButton;
\r
194 public final QAction rightAlignAction;
\r
195 public QPushButton leftAlignButton;
\r
196 public final QAction leftAlignAction;
\r
197 public QPushButton centerAlignButton;
\r
198 public final QAction centerAlignAction;
\r
200 public final QPushButton strikethroughButton;
\r
201 public final QAction strikethroughAction;
\r
202 public final QPushButton hlineButton;
\r
203 public final QAction hlineAction;
\r
204 public final QPushButton indentButton;
\r
205 public final QAction indentAction;
\r
206 public final QPushButton outdentButton;
\r
207 public final QAction outdentAction;
\r
208 public final QPushButton bulletListButton;
\r
209 public final QAction bulletListAction;
\r
210 public final QPushButton numberListButton;
\r
211 public final QAction numberListAction;
\r
212 public final QPushButton spellCheckButton;
\r
213 public final QAction spellCheckAction;
\r
214 public final QPushButton todoButton;
\r
215 public final QAction todoAction;
\r
217 public final QShortcut focusTitleShortcut;
\r
218 public final QShortcut focusTagShortcut;
\r
219 public final QShortcut focusNoteShortcut;
\r
220 public final QShortcut focusUrlShortcut;
\r
221 public final QShortcut focusAuthorShortcut;
\r
223 public EditorButtonBar buttonLayout;
\r
224 public final QComboBox fontList;
\r
225 public final QAction fontListAction;
\r
226 public final QToolButton fontColor;
\r
227 public final QAction fontColorAction;
\r
228 private final ColorMenu fontColorMenu;
\r
229 public final QToolButton fontHilight;
\r
230 public final QAction fontHilightAction;
\r
231 private final ColorMenu fontHilightColorMenu;
\r
232 public final QFileSystemWatcher fileWatcher;
\r
233 public int cursorPosition;
\r
234 private boolean forceTextPaste = false;
\r
235 private String selectedFile;
\r
236 private String currentHyperlink;
\r
237 public boolean keepPDFNavigationHidden;
\r
238 private final ApplicationLogger logger;
\r
239 SpellDictionary dictionary;
\r
240 SpellDictionary userDictionary;
\r
241 SpellChecker spellChecker;
\r
242 SuggestionListener spellListener;
\r
243 private final HashMap<String,Integer> previewPageList;
\r
244 boolean insertHyperlink = true;
\r
245 boolean insideTable = false;
\r
246 boolean insideEncryption = false;
\r
247 public Signal1<BrowserWindow> blockApplication;
\r
248 public Signal0 unblockApplication;
\r
249 public boolean awaitingHttpResponse;
\r
250 public long unblockTime;
\r
251 String latexGuid; // This is set if we are editing an existing LaTeX formula. Useful to track guid.
\r
254 public static class SuggestionListener implements SpellCheckListener {
\r
255 public boolean abortSpellCheck = false;
\r
256 public boolean errorsFound = false;
\r
257 private final SpellCheck spellCheckDialog;
\r
260 private final BrowserWindow parent;
\r
261 public SuggestionListener(BrowserWindow parent, SpellChecker checker) {
\r
262 this.parent = parent;
\r
263 spellCheckDialog = new SpellCheck(checker);
\r
265 public void spellingError(SpellCheckEvent event) {
\r
266 errorsFound = true;
\r
267 spellCheckDialog.setWord(event.getInvalidWord());
\r
269 @SuppressWarnings("unchecked")
\r
270 List<Word> suggestions = event.getSuggestions();
\r
271 spellCheckDialog.clearSuggestions();
\r
272 if (!suggestions.isEmpty()) {
\r
273 // spellCheckDialog.setCurrentSuggestion(suggestions.get(0).getWord());
\r
274 for (int i=0; i<suggestions.size(); i++) {
\r
275 spellCheckDialog.addSuggestion(suggestions.get(i).getWord());
\r
277 spellCheckDialog.setSelectedSuggestion(0);
\r
279 spellCheckDialog.exec();
\r
280 if (spellCheckDialog.cancelPressed()) {
\r
281 abortSpellCheck = true;
\r
285 if (spellCheckDialog.replacePressed()) {
\r
286 QClipboard clipboard = QApplication.clipboard();
\r
287 clipboard.setText(spellCheckDialog.getReplacementWord());
\r
288 parent.pasteClicked();
\r
296 public BrowserWindow(DatabaseConnection c) {
\r
297 logger = new ApplicationLogger("browser.log");
\r
298 logger.log(logger.HIGH, "Setting up browser");
\r
300 fileWatcher = new QFileSystemWatcher();
\r
301 // fileWatcher.fileChanged.connect(this, "fileChanged(String)");
\r
302 noteSignal = new NoteSignal();
\r
303 titleLabel = new QLineEdit();
\r
304 titleLabel.setMaxLength(Constants.EDAM_NOTE_TITLE_LEN_MAX);
\r
305 urlText = new QLineEdit();
\r
306 authorText = new QLineEdit();
\r
307 geoBox = new QComboBox();
\r
308 urlLabel = new QPushButton();
\r
309 urlLabel.clicked.connect(this, "sourceUrlClicked()");
\r
310 authorLabel = new QLabel();
\r
313 focusLost = new Signal0();
\r
315 tagEdit = new TagLineEdit(allTags);
\r
316 tagLabel = new QLabel("Tags:");
\r
317 tagEdit.focusLost.connect(this, "modifyTagsTyping()");
\r
319 createdCalendarWidget = new QCalendarWidget();
\r
320 createdDate = new QDateEdit();
\r
321 createdDate.setDisplayFormat(Global.getDateFormat());
\r
322 createdDate.setCalendarPopup(true);
\r
323 createdDate.setCalendarWidget(createdCalendarWidget);
\r
324 createdTime = new QTimeEdit();
\r
325 createdDate.dateChanged.connect(this, "createdChanged()");
\r
326 createdTime.timeChanged.connect(this, "createdChanged()");
\r
328 alteredCalendarWidget = new QCalendarWidget();
\r
329 alteredDate = new QDateEdit();
\r
330 alteredDate.setDisplayFormat(Global.getDateFormat());
\r
331 alteredDate.setCalendarPopup(true);
\r
332 alteredDate.setCalendarWidget(alteredCalendarWidget);
\r
333 alteredTime = new QTimeEdit();
\r
334 alteredLabel = new QLabel("Altered:");
\r
335 alteredDate.dateChanged.connect(this, "alteredChanged()");
\r
336 alteredTime.timeChanged.connect(this, "alteredChanged()");
\r
338 subjectCalendarWidget = new QCalendarWidget();
\r
339 subjectDate = new QDateEdit();
\r
340 subjectDate.setDisplayFormat(Global.getDateFormat());
\r
341 subjectDate.setCalendarPopup(true);
\r
342 subjectDate.setCalendarWidget(subjectCalendarWidget);
\r
343 subjectTime = new QTimeEdit();
\r
344 subjectLabel = new QLabel(tr("Subject Date:"));
\r
345 subjectDate.dateChanged.connect(this, "subjectDateTimeChanged()");
\r
346 subjectTime.timeChanged.connect(this, "subjectDateTimeChanged()");
\r
347 authorText.textChanged.connect(this, "authorChanged()");
\r
348 urlText.textChanged.connect(this, "sourceUrlChanged()");
\r
350 notebookBox = new QComboBox();
\r
351 notebookLabel = new QLabel(tr("Notebook"));
\r
352 createdLabel = new QLabel(tr("Created:"));
\r
353 // selectedText = new String();
\r
355 urlLabel.setVisible(false);
\r
356 urlText.setVisible(false);
\r
357 authorLabel.setVisible(false);
\r
359 geoBox.setVisible(false);
\r
360 geoBox.addItem(new QIcon(iconPath+"globe.png"), "");
\r
361 geoBox.addItem(new String(tr("Set")));
\r
362 geoBox.addItem(new String(tr("Clear")));
\r
363 geoBox.addItem(new String(tr("View On Map")));
\r
364 geoBox.activated.connect(this, "geoBoxChanged()");
\r
366 authorText.setVisible(false);
\r
367 createdDate.setVisible(false);
\r
368 alteredLabel.setVisible(false);
\r
369 //notebookBox.setVisible(false);
\r
370 notebookLabel.setVisible(false);
\r
371 createdLabel.setVisible(false);
\r
372 createdTime.setVisible(false);
\r
373 alteredDate.setVisible(false);
\r
374 alteredTime.setVisible(false);
\r
375 subjectLabel.setVisible(false);
\r
376 subjectDate.setVisible(false);
\r
377 subjectTime.setVisible(false);
\r
378 extendedOn = false;
\r
379 buttonsVisible = true;
\r
380 setAcceptDrops(true);
\r
382 browser = new ContentView(this);
\r
383 browser.page().setLinkDelegationPolicy(
\r
384 QWebPage.LinkDelegationPolicy.DelegateAllLinks);
\r
385 browser.linkClicked.connect(this, "linkClicked(QUrl)");
\r
386 currentHyperlink = "";
\r
388 QVBoxLayout v = new QVBoxLayout();
\r
389 QFormLayout notebookLayout = new QFormLayout();
\r
390 QGridLayout dateLayout = new QGridLayout();
\r
391 titleLabel.setReadOnly(false);
\r
392 titleLabel.editingFinished.connect(this, "titleEdited()");
\r
393 browser.page().contentsChanged.connect(this, "contentChanged()");
\r
394 browser.page().selectionChanged.connect(this, "selectionChanged()");
\r
395 browser.page().mainFrame().javaScriptWindowObjectCleared.connect(this,
\r
396 "exposeToJavascript()");
\r
398 notebookBox.activated.connect(this, "notebookChanged()");
\r
399 resourceSignal = new NoteResourceSignal();
\r
401 QHBoxLayout tagLayout = new QHBoxLayout();
\r
402 v.addWidget(titleLabel, 0);
\r
403 notebookLayout.addRow(notebookLabel, notebookBox);
\r
404 tagLayout.addLayout(notebookLayout, 0);
\r
405 tagLayout.stretch(4);
\r
406 tagLayout.addWidget(tagLabel, 0);
\r
407 tagLayout.addWidget(tagEdit, 1);
\r
408 v.addLayout(tagLayout);
\r
410 QHBoxLayout urlLayout = new QHBoxLayout();
\r
411 urlLayout.addWidget(urlLabel, 0);
\r
412 urlLayout.addWidget(urlText, 0);
\r
413 v.addLayout(urlLayout);
\r
415 QHBoxLayout authorLayout = new QHBoxLayout();
\r
416 authorLayout.addWidget(authorLabel, 0);
\r
417 authorLayout.addWidget(authorText, 0);
\r
418 authorLayout.addWidget(geoBox);
\r
419 v.addLayout(authorLayout);
\r
421 dateLayout.addWidget(createdLabel, 0, 0);
\r
422 dateLayout.addWidget(createdDate, 0, 1);
\r
423 dateLayout.addWidget(createdTime, 0, 2);
\r
424 dateLayout.setColumnStretch(9, 100);
\r
425 dateLayout.addWidget(alteredLabel, 0, 3);
\r
426 dateLayout.addWidget(alteredDate, 0, 4);
\r
427 dateLayout.addWidget(alteredTime, 0, 5);
\r
428 dateLayout.addWidget(subjectLabel, 0, 6);
\r
429 dateLayout.addWidget(subjectDate, 0, 7);
\r
430 dateLayout.addWidget(subjectTime, 0, 8);
\r
431 v.addLayout(dateLayout, 0);
\r
433 undoButton = newEditorButton("undo", tr("Undo Change"));
\r
434 redoButton = newEditorButton("redo", tr("Redo Change"));
\r
435 cutButton = newEditorButton("cut", tr("Cut"));
\r
436 copyButton = newEditorButton("copy", tr("Copy"));
\r
437 pasteButton = newEditorButton("paste", tr("Paste"));
\r
438 boldButton = newEditorButton("bold", tr("Bold"));
\r
439 underlineButton = newEditorButton("underline", tr("Underline"));
\r
440 italicButton = newEditorButton("italic", tr("Italic"));
\r
442 rightAlignButton = newEditorButton("justifyRight", tr("Right Align"));
\r
443 leftAlignButton = newEditorButton("justifyLeft", tr("Left Align"));
\r
444 centerAlignButton = newEditorButton("justifyCenter", tr("Center Align"));
\r
446 strikethroughButton = newEditorButton("strikethrough", tr("Strikethrough"));
\r
447 hlineButton = newEditorButton("hline", tr("Insert Horizontal Line"));
\r
448 indentButton = newEditorButton("indent", tr("Shift Right"));
\r
449 outdentButton = newEditorButton("outdent", tr("Shift Left"));
\r
450 bulletListButton = newEditorButton("bulletList", tr("Bullet List"));
\r
451 numberListButton = newEditorButton("numberList", tr("Number List"));
\r
452 spellCheckButton = newEditorButton("spellCheck", tr("Spell Check"));
\r
453 todoButton = newEditorButton("todo", tr("To-do"));
\r
456 buttonLayout = new EditorButtonBar();
\r
457 v.addWidget(buttonLayout);
\r
459 undoAction = buttonLayout.addWidget(undoButton);
\r
460 buttonLayout.toggleUndoVisible.triggered.connect(this, "toggleUndoVisible(Boolean)");
\r
461 redoAction = buttonLayout.addWidget(redoButton);
\r
462 buttonLayout.toggleRedoVisible.triggered.connect(this, "toggleRedoVisible(Boolean)");
\r
464 buttonLayout.addWidget(newSeparator());
\r
465 cutAction = buttonLayout.addWidget(cutButton);
\r
466 buttonLayout.toggleCutVisible.triggered.connect(this, "toggleCutVisible(Boolean)");
\r
467 copyAction = buttonLayout.addWidget(copyButton);
\r
468 buttonLayout.toggleCopyVisible.triggered.connect(this, "toggleCopyVisible(Boolean)");
\r
469 pasteAction = buttonLayout.addWidget(pasteButton);
\r
470 buttonLayout.togglePasteVisible.triggered.connect(this, "togglePasteVisible(Boolean)");
\r
472 buttonLayout.addWidget(newSeparator());
\r
473 boldAction = buttonLayout.addWidget(boldButton);
\r
474 buttonLayout.toggleBoldVisible.triggered.connect(this, "toggleBoldVisible(Boolean)");
\r
475 italicAction = buttonLayout.addWidget(italicButton);
\r
476 buttonLayout.toggleItalicVisible.triggered.connect(this, "toggleItalicVisible(Boolean)");
\r
477 underlineAction = buttonLayout.addWidget(underlineButton);
\r
478 buttonLayout.toggleUnderlineVisible.triggered.connect(this, "toggleUnderlineVisible(Boolean)");
\r
479 strikethroughAction = buttonLayout.addWidget(strikethroughButton);
\r
480 buttonLayout.toggleStrikethroughVisible.triggered.connect(this, "toggleStrikethroughVisible(Boolean)");
\r
483 buttonLayout.addWidget(newSeparator());
\r
484 leftAlignAction = buttonLayout.addWidget(leftAlignButton);
\r
485 buttonLayout.toggleLeftAlignVisible.triggered.connect(this, "toggleLeftAlignVisible(Boolean)");
\r
486 centerAlignAction = buttonLayout.addWidget(centerAlignButton);
\r
487 buttonLayout.toggleCenterAlignVisible.triggered.connect(this, "toggleCenterAlignVisible(Boolean)");
\r
488 rightAlignAction = buttonLayout.addWidget(rightAlignButton);
\r
489 buttonLayout.toggleRightAlignVisible.triggered.connect(this, "toggleRightAlignVisible(Boolean)");
\r
491 buttonLayout.addWidget(newSeparator());
\r
492 hlineAction = buttonLayout.addWidget(hlineButton);
\r
493 buttonLayout.toggleHLineVisible.triggered.connect(this, "toggleHLineVisible(Boolean)");
\r
495 indentAction = buttonLayout.addWidget(indentButton);
\r
496 buttonLayout.toggleIndentVisible.triggered.connect(this, "toggleIndentVisible(Boolean)");
\r
497 outdentAction = buttonLayout.addWidget(outdentButton);
\r
498 buttonLayout.toggleOutdentVisible.triggered.connect(this, "toggleOutdentVisible(Boolean)");
\r
499 bulletListAction = buttonLayout.addWidget(bulletListButton);
\r
500 buttonLayout.toggleBulletListVisible.triggered.connect(this, "toggleBulletListVisible(Boolean)");
\r
501 numberListAction = buttonLayout.addWidget(numberListButton);
\r
502 buttonLayout.toggleNumberListVisible.triggered.connect(this, "toggleNumberListVisible(Boolean)");
\r
504 // Setup the font & font size combo boxes
\r
505 buttonLayout.addWidget(newSeparator());
\r
506 fontList = new QComboBox();
\r
507 fontSize = new QComboBox();
\r
508 fontList.setToolTip("Font");
\r
509 fontSize.setToolTip("Font Size");
\r
510 fontList.activated.connect(this, "fontChanged(String)");
\r
511 fontSize.activated.connect(this, "fontSizeChanged(String)");
\r
512 fontListAction = buttonLayout.addWidget(fontList);
\r
513 buttonLayout.toggleFontVisible.triggered.connect(this, "toggleFontListVisible(Boolean)");
\r
514 fontSizeAction = buttonLayout.addWidget(fontSize);
\r
515 buttonLayout.toggleFontSizeVisible.triggered.connect(this, "toggleFontSizeVisible(Boolean)");
\r
516 QFontDatabase fonts = new QFontDatabase();
\r
517 List<String> fontFamilies = fonts.families();
\r
518 for (int i = 0; i < fontFamilies.size(); i++) {
\r
519 fontList.addItem(fontFamilies.get(i));
\r
521 loadFontSize(fontFamilies.get(i));
\r
525 // buttonLayout.addWidget(newSeparator(), 0);
\r
526 fontColor = newToolButton("fontColor", tr("Font Color"));
\r
527 fontColorMenu = new ColorMenu(this);
\r
528 fontColor.setMenu(fontColorMenu.getMenu());
\r
529 fontColor.setPopupMode(ToolButtonPopupMode.MenuButtonPopup);
\r
530 fontColor.setAutoRaise(false);
\r
531 fontColorMenu.getMenu().triggered.connect(this, "fontColorClicked()");
\r
532 fontColorAction = buttonLayout.addWidget(fontColor);
\r
533 buttonLayout.toggleFontColorVisible.triggered.connect(this, "toggleFontColorVisible(Boolean)");
\r
534 fontHilight = newToolButton("fontHilight", tr("Font Hilight Color"));
\r
535 fontHilight.setPopupMode(ToolButtonPopupMode.MenuButtonPopup);
\r
536 fontHilight.setAutoRaise(false);
\r
537 fontHilightColorMenu = new ColorMenu(this);
\r
538 fontHilightColorMenu.setDefault(QColor.yellow);
\r
539 fontHilight.setMenu(fontHilightColorMenu.getMenu());
\r
540 fontHilightColorMenu.getMenu().triggered.connect(this, "fontHilightClicked()");
\r
541 fontHilightAction = buttonLayout.addWidget(fontHilight);
\r
542 fontHilightColorMenu.setDefault(QColor.yellow);
\r
543 buttonLayout.toggleFontHilight.triggered.connect(this, "toggleFontHilightVisible(Boolean)");
\r
545 spellCheckAction = buttonLayout.addWidget(spellCheckButton);
\r
546 buttonLayout.toggleNumberListVisible.triggered.connect(this, "spellCheckClicked()");
\r
547 buttonLayout.toggleSpellCheck.triggered.connect(this, "toggleSpellCheckVisible(Boolean)");
\r
549 todoAction = buttonLayout.addWidget(todoButton);
\r
550 buttonLayout.toggleNumberListVisible.triggered.connect(this, "todoClicked()");
\r
551 buttonLayout.toggleTodo.triggered.connect(this, "toggleTodoVisible(Boolean)");
\r
554 // buttonLayout.addWidget(new QLabel(), 1);
\r
555 v.addWidget(browser, 1);
\r
558 browser.downloadAttachmentRequested.connect(this,
\r
559 "downloadAttachment(QNetworkRequest)");
\r
560 browser.downloadImageRequested.connect(this,
\r
561 "downloadImage(QNetworkRequest)");
\r
562 setTabOrder(notebookBox, tagEdit);
\r
563 setTabOrder(tagEdit, browser);
\r
565 focusNoteShortcut = new QShortcut(this);
\r
566 setupShortcut(focusNoteShortcut, "Focus_Note");
\r
567 focusNoteShortcut.activated.connect(this, "focusNote()");
\r
568 focusTitleShortcut = new QShortcut(this);
\r
569 setupShortcut(focusTitleShortcut, "Focus_Title");
\r
570 focusTitleShortcut.activated.connect(this, "focusTitle()");
\r
571 focusTagShortcut = new QShortcut(this);
\r
572 setupShortcut(focusTagShortcut, "Focus_Tag");
\r
573 focusTagShortcut.activated.connect(this, "focusTag()");
\r
574 focusAuthorShortcut = new QShortcut(this);
\r
575 setupShortcut(focusAuthorShortcut, "Focus_Author");
\r
576 focusAuthorShortcut.activated.connect(this, "focusAuthor()");
\r
577 focusUrlShortcut = new QShortcut(this);
\r
578 setupShortcut(focusUrlShortcut, "Focus_Url");
\r
579 focusUrlShortcut.activated.connect(this, "focusUrl()");
\r
581 browser.page().mainFrame().setTextSizeMultiplier(Global.getTextSizeMultiplier());
\r
582 browser.page().mainFrame().setZoomFactor(Global.getZoomFactor());
\r
584 previewPageList = new HashMap<String,Integer>();
\r
586 browser.page().microFocusChanged.connect(this, "microFocusChanged()");
\r
590 QPalette pal = new QPalette();
\r
591 pal.setColor(ColorRole.Text, QColor.black);
\r
592 titleLabel.setPalette(pal);
\r
593 authorText.setPalette(pal);
\r
594 authorLabel.setPalette(pal);
\r
595 urlLabel.setPalette(pal);
\r
596 urlText.setPalette(pal);
\r
597 createdDate.setPalette(pal);
\r
598 createdTime.setPalette(pal);
\r
599 alteredDate.setPalette(pal);
\r
600 alteredTime.setPalette(pal);
\r
601 subjectDate.setPalette(pal);
\r
602 subjectTime.setPalette(pal);
\r
603 tagEdit.setPalette(pal);
\r
604 notebookBox.setPalette(pal);
\r
606 blockApplication = new Signal1<BrowserWindow>();
\r
607 unblockApplication = new Signal0();
\r
609 logger.log(logger.HIGH, "Browser setup complete");
\r
614 private void setupShortcut(QShortcut action, String text) {
\r
615 if (!Global.shortcutKeys.containsAction(text))
\r
617 action.setKey(new QKeySequence(Global.shortcutKeys.getShortcut(text)));
\r
623 // Getter for the QWebView
\r
624 public QWebView getBrowser() {
\r
628 // Block signals while loading data or things are flagged as dirty by
\r
630 public void loadingData(boolean val) {
\r
631 logger.log(logger.EXTREME, "Entering BrowserWindow.loadingData() " +val);
\r
632 notebookBox.blockSignals(val);
\r
633 browser.page().blockSignals(val);
\r
634 browser.page().mainFrame().blockSignals(val);
\r
635 titleLabel.blockSignals(val);
\r
636 alteredDate.blockSignals(val);
\r
637 alteredTime.blockSignals(val);
\r
638 createdTime.blockSignals(val);
\r
639 createdDate.blockSignals(val);
\r
640 subjectDate.blockSignals(val);
\r
641 subjectTime.blockSignals(val);
\r
642 urlText.blockSignals(val);
\r
643 authorText.blockSignals(val);
\r
645 exposeToJavascript();
\r
646 logger.log(logger.EXTREME, "Exiting BrowserWindow.loadingData() " +val);
\r
650 public void setReadOnly(boolean v) {
\r
652 titleLabel.setEnabled(!v);
\r
653 notebookBox.setEnabled(!v);
\r
654 tagEdit.setEnabled(!v);
\r
655 authorLabel.setEnabled(!v);
\r
656 geoBox.setEnabled(!v);
\r
657 urlText.setEnabled(!v);
\r
658 createdDate.setEnabled(!v);
\r
659 subjectDate.setEnabled(!v);
\r
660 alteredDate.setEnabled(!v);
\r
661 authorText.setEnabled(!v);
\r
662 createdTime.setEnabled(!v);
\r
663 alteredTime.setEnabled(!v);
\r
664 subjectTime.setEnabled(!v);
\r
665 getBrowser().setEnabled(true);
\r
666 // getBrowser().setEnabled(!v);
\r
669 // expose this class to Javascript on the web page
\r
670 private void exposeToJavascript() {
\r
671 browser.page().mainFrame().addToJavaScriptWindowObject("jambi", this);
\r
674 // Custom event queue
\r
676 public boolean event(QEvent e) {
\r
677 if (e.type().equals(QEvent.Type.FocusOut)) {
\r
678 logger.log(logger.EXTREME, "Focus lost");
\r
681 return super.event(e);
\r
684 // clear out browser
\r
685 public void clear() {
\r
686 logger.log(logger.EXTREME, "Entering BrowserWindow.clear()");
\r
688 browser.setContent(new QByteArray());
\r
689 tagEdit.setText("");
\r
690 tagEdit.tagCompleter.reset();
\r
691 urlLabel.setText(tr("Source URL:"));
\r
692 titleLabel.setText("");
\r
693 logger.log(logger.EXTREME, "Exiting BrowserWindow.clear()");
\r
696 // get/set current note
\r
697 public void setNote(Note n) {
\r
701 saveNoteTitle = n.getTitle();
\r
705 public Note getNote() {
\r
706 return currentNote;
\r
709 // New Editor Button
\r
710 private QPushButton newEditorButton(String name, String toolTip) {
\r
711 QPushButton button = new QPushButton();
\r
712 // QIcon icon = new QIcon(iconPath + name + ".gif");
\r
713 QIcon icon = new QIcon(iconPath + name + ".png");
\r
714 button.setIcon(icon);
\r
715 button.setToolTip(toolTip);
\r
716 button.clicked.connect(this, name + "Clicked()");
\r
719 // New Editor Button
\r
720 private QToolButton newToolButton(String name, String toolTip) {
\r
721 QToolButton button = new QToolButton();
\r
722 // QIcon icon = new QIcon(iconPath + name + ".gif");
\r
723 QIcon icon = new QIcon(iconPath + name + ".png");
\r
724 button.setIcon(icon);
\r
725 button.setToolTip(toolTip);
\r
726 button.clicked.connect(this, name + "Clicked()");
\r
731 private QLabel newSeparator() {
\r
732 return new QLabel(" ");
\r
735 // Set the title in the window
\r
736 public void setTitle(String t) {
\r
737 titleLabel.setText(t);
\r
742 // Return the current text title
\r
743 public String getTitle() {
\r
744 return titleLabel.text();
\r
747 // Set the tag name string
\r
748 public void setTag(String t) {
\r
750 tagEdit.setText(t);
\r
751 tagEdit.tagCompleter.reset();
\r
754 // Set the source URL
\r
755 public void setUrl(String t) {
\r
756 urlLabel.setText(tr("Source URL:\t"));
\r
757 urlText.setText(t);
\r
760 // The user want's to launch a web browser on the source of the URL
\r
761 public void sourceUrlClicked() {
\r
762 // Make sure we have a valid URL
\r
763 if (urlText.text().trim().equals(""))
\r
766 String url = urlText.text();
\r
767 if (!url.toLowerCase().startsWith(tr("http://")))
\r
768 url = tr("http://") +url;
\r
770 if (!QDesktopServices.openUrl(new QUrl(url))) {
\r
771 logger.log(logger.LOW, "Error opening file :" +url);
\r
775 public void setAuthor(String t) {
\r
776 authorLabel.setText(tr("Author:\t"));
\r
777 authorText.setText(t);
\r
780 // Set the creation date
\r
781 public void setCreation(long date) {
\r
782 QDateTime dt = new QDateTime();
\r
783 dt.setTime_t((int) (date / 1000));
\r
784 createdDate.setDateTime(dt);
\r
785 createdTime.setDateTime(dt);
\r
786 createdDate.setDisplayFormat(Global.getDateFormat());
\r
787 createdTime.setDisplayFormat(Global.getTimeFormat());
\r
790 // Set the creation date
\r
791 public void setAltered(long date) {
\r
792 QDateTime dt = new QDateTime();
\r
793 dt.setTime_t((int) (date / 1000));
\r
794 alteredDate.setDateTime(dt);
\r
795 alteredTime.setDateTime(dt);
\r
796 alteredDate.setDisplayFormat(Global.getDateFormat());
\r
797 alteredTime.setDisplayFormat(Global.getTimeFormat());
\r
800 // Set the subject date
\r
801 public void setSubjectDate(long date) {
\r
802 QDateTime dt = new QDateTime();
\r
803 dt.setTime_t((int) (date / 1000));
\r
804 subjectDate.setDateTime(dt);
\r
805 subjectTime.setDateTime(dt);
\r
806 subjectDate.setDisplayFormat(Global.getDateFormat());
\r
807 subjectTime.setDisplayFormat(Global.getTimeFormat());
\r
810 // Toggle the extended attribute information
\r
811 public void toggleInformation() {
\r
813 extendedOn = false;
\r
817 urlLabel.setVisible(extendedOn);
\r
818 urlText.setVisible(extendedOn);
\r
819 authorText.setVisible(extendedOn);
\r
820 geoBox.setVisible(extendedOn);
\r
821 authorLabel.setVisible(extendedOn);
\r
822 createdDate.setVisible(extendedOn);
\r
823 createdTime.setVisible(extendedOn);
\r
824 createdLabel.setVisible(extendedOn);
\r
825 alteredLabel.setVisible(extendedOn);
\r
826 alteredDate.setVisible(extendedOn);
\r
827 alteredTime.setVisible(extendedOn);
\r
828 //notebookBox.setVisible(extendedOn);
\r
829 notebookLabel.setVisible(extendedOn);
\r
830 subjectLabel.setVisible(extendedOn);
\r
831 subjectDate.setVisible(extendedOn);
\r
832 subjectTime.setVisible(extendedOn);
\r
835 public void hideButtons() {
\r
837 undoButton.parentWidget().setVisible(false);
\r
838 buttonsVisible = false;
\r
842 // Is the extended view on?
\r
843 public boolean isExtended() {
\r
847 // Listener for when a link is clicked
\r
848 @SuppressWarnings("unused")
\r
849 private void openFile() {
\r
850 logger.log(logger.EXTREME, "Starting openFile()");
\r
851 File fileHandle = new File(selectedFile);
\r
852 URI fileURL = fileHandle.toURI();
\r
853 String localURL = fileURL.toString();
\r
854 QUrl url = new QUrl(localURL);
\r
855 QFile file = new QFile(selectedFile);
\r
857 logger.log(logger.EXTREME, "Adding to fileWatcher:"+file.fileName());
\r
858 fileWatcher.addPath(file.fileName());
\r
860 if (!QDesktopServices.openUrl(url)) {
\r
861 logger.log(logger.LOW, "Error opening file :" +url);
\r
866 // Listener for when a link is clicked
\r
867 @SuppressWarnings("unused")
\r
868 private void linkClicked(QUrl url) {
\r
869 logger.log(logger.EXTREME, "URL Clicked: " +url.toString());
\r
870 if (url.toString().startsWith("latex:")) {
\r
871 int position = url.toString().lastIndexOf(".");
\r
872 String guid = url.toString().substring(0,position);
\r
873 position = guid.lastIndexOf("/");
\r
874 guid = guid.substring(position+1);
\r
878 if (url.toString().startsWith("nnres://")) {
\r
879 logger.log(logger.EXTREME, "URL is NN resource");
\r
880 if (url.toString().endsWith("/vnd.evernote.ink")) {
\r
881 logger.log(logger.EXTREME, "Unable to open ink note");
\r
882 QMessageBox.information(this, tr("Unable Open"), tr("This is an ink note.\n"+
\r
883 "Ink notes are not supported since Evernote has not\n published any specifications on them\n" +
\r
884 "and I'm too lazy to figure them out by myself."));
\r
887 String fullName = url.toString().substring(8);
\r
888 int index = fullName.indexOf(".");
\r
892 type = fullName.substring(index+1);
\r
893 guid = fullName.substring(0,index);
\r
895 index = guid.indexOf(Global.attachmentNameDelimeter);
\r
897 guid = guid.substring(0,index);
\r
899 List<Resource> resList = currentNote.getResources();
\r
900 Resource res = null;
\r
901 for (int i=0; i<resList.size(); i++) {
\r
902 if (resList.get(i).getGuid().equals(guid)) {
\r
903 res = resList.get(i);
\r
908 String resGuid = Global.resourceMap.get(guid);
\r
909 if (resGuid != null)
\r
910 res = conn.getNoteTable().noteResourceTable.getNoteResource(resGuid, true);
\r
914 if (res.getAttributes() != null &&
\r
915 res.getAttributes().getFileName() != null &&
\r
916 !res.getAttributes().getFileName().trim().equals(""))
\r
917 fileName = res.getGuid()+Global.attachmentNameDelimeter+res.getAttributes().getFileName();
\r
919 fileName = res.getGuid()+"."+type;
\r
920 QFile file = new QFile(Global.getFileManager().getResDirPath(fileName));
\r
921 QFile.OpenMode mode = new QFile.OpenMode();
\r
922 mode.set(QFile.OpenModeFlag.WriteOnly);
\r
923 boolean openResult = file.open(mode);
\r
924 logger.log(logger.EXTREME, "File opened:" +openResult);
\r
925 QDataStream out = new QDataStream(file);
\r
926 Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(res.getGuid(), true);
\r
927 QByteArray binData = new QByteArray(resBinary.getData().getBody());
\r
929 logger.log(logger.EXTREME, "Writing resource");
\r
930 out.writeBytes(binData.toByteArray());
\r
933 String whichOS = System.getProperty("os.name");
\r
934 if (whichOS.contains("Windows"))
\r
935 url.setUrl("file:///"+file.fileName());
\r
937 url.setUrl("file://"+file.fileName());
\r
938 // fileWatcher.removePath(file.fileName());
\r
939 logger.log(logger.EXTREME, "Adding file watcher " +file.fileName());
\r
940 fileWatcher.addPath(file.fileName());
\r
942 // If we can't open it, then prompt the user to save it.
\r
943 if (!QDesktopServices.openUrl(url)) {
\r
944 logger.log(logger.EXTREME, "We can't handle this. Where do we put it?");
\r
945 QFileDialog dialog = new QFileDialog();
\r
947 if (dialog.exec()!=0) {
\r
948 List<String> fileNames = dialog.selectedFiles(); //gets all selected filenames
\r
949 if (fileNames.size() == 0)
\r
951 String sf = fileNames.get(0);
\r
952 QFile saveFile = new QFile(sf);
\r
953 mode.set(QFile.OpenModeFlag.WriteOnly);
\r
954 saveFile.open(mode);
\r
955 QDataStream saveOut = new QDataStream(saveFile);
\r
956 saveOut.writeBytes(binData.toByteArray());
\r
964 logger.log(logger.EXTREME, "Launching URL");
\r
965 QDesktopServices.openUrl(url);
\r
968 // Listener for when BOLD is clicked
\r
969 @SuppressWarnings("unused")
\r
970 private void undoClicked() {
\r
971 browser.page().triggerAction(WebAction.Undo);
\r
972 browser.setFocus();
\r
975 // Listener for when BOLD is clicked
\r
976 @SuppressWarnings("unused")
\r
977 private void redoClicked() {
\r
978 browser.page().triggerAction(WebAction.Redo);
\r
979 browser.setFocus();
\r
982 // Listener for when BOLD is clicked
\r
983 @SuppressWarnings("unused")
\r
984 private void boldClicked() {
\r
985 browser.page().triggerAction(WebAction.ToggleBold);
\r
986 microFocusChanged();
\r
987 browser.setFocus();
\r
990 // Listener for when Italics is clicked
\r
991 @SuppressWarnings("unused")
\r
992 private void italicClicked() {
\r
993 browser.page().triggerAction(WebAction.ToggleItalic);
\r
994 microFocusChanged();
\r
995 browser.setFocus();
\r
998 // Listener for when UNDERLINE is clicked
\r
999 @SuppressWarnings("unused")
\r
1000 private void underlineClicked() {
\r
1001 browser.page().triggerAction(WebAction.ToggleUnderline);
\r
1002 microFocusChanged();
\r
1003 browser.setFocus();
\r
1006 // Listener for when Strikethrough is clicked
\r
1007 @SuppressWarnings("unused")
\r
1008 private void strikethroughClicked() {
\r
1009 browser.page().mainFrame().evaluateJavaScript(
\r
1010 "document.execCommand('strikeThrough', false, '');");
\r
1011 browser.setFocus();
\r
1014 // Listener for when cut is clicked
\r
1015 @SuppressWarnings("unused")
\r
1016 private void cutClicked() {
\r
1017 browser.page().triggerAction(WebAction.Cut);
\r
1018 browser.setFocus();
\r
1021 // Listener when COPY is clicked
\r
1022 @SuppressWarnings("unused")
\r
1023 private void copyClicked() {
\r
1024 browser.page().triggerAction(WebAction.Copy);
\r
1025 browser.setFocus();
\r
1028 // Listener when PASTE is clicked
\r
1029 public void pasteClicked() {
\r
1030 logger.log(logger.EXTREME, "Paste Clicked");
\r
1031 if (forceTextPaste) {
\r
1032 pasteWithoutFormattingClicked();
\r
1035 QClipboard clipboard = QApplication.clipboard();
\r
1036 QMimeData mime = clipboard.mimeData();
\r
1038 // String x = mime.html();
\r
1040 if (mime.hasImage()) {
\r
1041 logger.log(logger.EXTREME, "Image paste found");
\r
1042 browser.setFocus();
\r
1043 insertImage(mime);
\r
1044 browser.setFocus();
\r
1048 if (mime.hasUrls()) {
\r
1049 logger.log(logger.EXTREME, "URL paste found");
\r
1051 browser.setFocus();
\r
1055 String text = mime.html();
\r
1056 if (text.contains("en-tag") && mime.hasHtml()) {
\r
1057 logger.log(logger.EXTREME, "Intra-note paste found");
\r
1058 text = fixInternotePaste(text);
\r
1059 mime.setHtml(text);
\r
1060 clipboard.setMimeData(mime);
\r
1063 logger.log(logger.EXTREME, "Final paste choice encountered");
\r
1064 browser.page().triggerAction(WebAction.Paste);
\r
1065 browser.setFocus();
\r
1069 // Paste text without formatting
\r
1070 private void pasteWithoutFormattingClicked() {
\r
1071 logger.log(logger.EXTREME, "Paste without format clipped");
\r
1072 QClipboard clipboard = QApplication.clipboard();
\r
1073 QMimeData mime = clipboard.mimeData();
\r
1074 if (!mime.hasText())
\r
1076 String text = mime.text();
\r
1077 clipboard.clear();
\r
1078 clipboard.setText(text, Mode.Clipboard);
\r
1079 browser.page().triggerAction(WebAction.Paste);
\r
1081 // This is done because pasting into an encryption block
\r
1082 // can cause multiple cells (which can't happen). It
\r
1083 // just goes through the table, extracts the data, &
\r
1084 // puts it back as one table cell.
\r
1085 if (insideEncryption) {
\r
1086 String js = new String( "function fixEncryption() { "
\r
1087 +" var selObj = window.getSelection();"
\r
1088 +" var selRange = selObj.getRangeAt(0);"
\r
1089 +" var workingNode = window.getSelection().anchorNode;"
\r
1090 +" while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { "
\r
1091 +" workingNode = workingNode.parentNode;"
\r
1093 +" workingNode.innerHTML = window.jambi.fixEncryptionPaste(workingNode.innerHTML);"
\r
1094 +"} fixEncryption();");
\r
1095 browser.page().mainFrame().evaluateJavaScript(js);
\r
1099 // This basically removes all the table tags and returns just the contents.
\r
1100 // This is called by JavaScript to fix encryption pastes.
\r
1101 public String fixEncryptionPaste(String data) {
\r
1102 data = data.replace("<tbody>", "");
\r
1103 data = data.replace("</tbody>", "");
\r
1104 data = data.replace("<tr>", "");
\r
1105 data = data.replace("</tr>", "");
\r
1106 data = data.replace("<td>", "");
\r
1107 data = data.replace("</td>", "<br>");
\r
1108 data = data.replace("<br><br>", "<br>");
\r
1110 return "<tbody><tr><td>"+data+"</td></tr></tbody>";
\r
1113 // insert date/time
\r
1114 @SuppressWarnings("unused")
\r
1115 private void insertDateTime() {
\r
1116 String fmt = Global.getDateFormat() + " " + Global.getTimeFormat();
\r
1117 String dateTimeFormat = new String(fmt);
\r
1118 SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);
\r
1119 Calendar cal = Calendar.getInstance();
\r
1121 browser.page().mainFrame().evaluateJavaScript(
\r
1122 "document.execCommand('insertHtml', false, '"+simple.format(cal.getTime())+"');");
\r
1124 browser.setFocus();
\r
1128 // Listener when Left is clicked
\r
1129 @SuppressWarnings("unused")
\r
1130 private void justifyLeftClicked() {
\r
1131 browser.page().mainFrame().evaluateJavaScript(
\r
1132 "document.execCommand('JustifyLeft', false, '');");
\r
1133 browser.setFocus();
\r
1136 // Listener when Center is clicked
\r
1137 @SuppressWarnings("unused")
\r
1138 private void justifyCenterClicked() {
\r
1139 browser.page().mainFrame().evaluateJavaScript(
\r
1140 "document.execCommand('JustifyCenter', false, '');");
\r
1141 browser.setFocus();
\r
1144 // Listener when Left is clicked
\r
1145 @SuppressWarnings("unused")
\r
1146 private void justifyRightClicked() {
\r
1147 browser.page().mainFrame().evaluateJavaScript(
\r
1148 "document.execCommand('JustifyRight', false, '');");
\r
1149 browser.setFocus();
\r
1152 // Listener when HLINE is clicked
\r
1153 @SuppressWarnings("unused")
\r
1154 private void hlineClicked() {
\r
1155 browser.page().mainFrame().evaluateJavaScript(
\r
1156 "document.execCommand('insertHorizontalRule', false, '');");
\r
1157 browser.setFocus();
\r
1160 // Listener when outdent is clicked
\r
1161 private void outdentClicked() {
\r
1162 browser.page().mainFrame().evaluateJavaScript(
\r
1163 "document.execCommand('outdent', false, '');");
\r
1164 browser.setFocus();
\r
1167 // Listener when a bullet list is clicked
\r
1168 @SuppressWarnings("unused")
\r
1169 private void bulletListClicked() {
\r
1170 browser.page().mainFrame().evaluateJavaScript(
\r
1171 "document.execCommand('InsertUnorderedList', false, '');");
\r
1172 browser.setFocus();
\r
1175 // Listener when a bullet list is clicked
\r
1176 @SuppressWarnings("unused")
\r
1177 private void numberListClicked() {
\r
1178 browser.page().mainFrame().evaluateJavaScript(
\r
1179 "document.execCommand('InsertOrderedList', false, '');");
\r
1180 browser.setFocus();
\r
1183 // Listener when indent is clicked
\r
1184 private void indentClicked() {
\r
1185 browser.page().mainFrame().evaluateJavaScript(
\r
1186 "document.execCommand('indent', false, '');");
\r
1187 browser.setFocus();
\r
1190 // Listener when the font name is changed
\r
1191 @SuppressWarnings("unused")
\r
1192 private void fontChanged(String font) {
\r
1193 browser.page().mainFrame().evaluateJavaScript(
\r
1194 "document.execCommand('fontName',false,'" + font + "');");
\r
1195 browser.setFocus();
\r
1198 // Listener when a font size is changed
\r
1199 @SuppressWarnings("unused")
\r
1200 private void fontSizeChanged(String font) {
\r
1201 String text = browser.selectedText();
\r
1202 if (text.trim().equalsIgnoreCase(""))
\r
1205 String selectedText = browser.selectedText();
\r
1206 String url = "<span style=\"font-size:" +font +"pt; \">"+selectedText +"</a>";
\r
1207 String script = "document.execCommand('insertHtml', false, '"+url+"');";
\r
1208 browser.page().mainFrame().evaluateJavaScript(script);
\r
1209 /* browser.page().mainFrame().evaluateJavaScript(
\r
1210 "document.execCommand('fontSize',false,'"
\r
1213 browser.setFocus();
\r
1216 // Load the font combo box based upon the font selected
\r
1217 private void loadFontSize(String name) {
\r
1218 QFontDatabase db = new QFontDatabase();
\r
1220 List<Integer> points = db.pointSizes(name);
\r
1221 for (int i=0; i<points.size(); i++) {
\r
1222 fontSize.addItem(points.get(i).toString());
\r
1225 fontSize.addItem("x-small");
\r
1226 fontSize.addItem("small");
\r
1227 fontSize.addItem("medium");
\r
1228 fontSize.addItem("large");
\r
1229 fontSize.addItem("x-large");
\r
1230 fontSize.addItem("xx-large");
\r
1231 fontSize.addItem("xxx-large");
\r
1235 // Listener when a font size is changed
\r
1236 @SuppressWarnings("unused")
\r
1237 private void fontColorClicked() {
\r
1238 // QColorDialog dialog = new QColorDialog();
\r
1239 // QColor color = QColorDialog.getColor();
\r
1240 QColor color = fontColorMenu.getColor();
\r
1241 if (color.isValid())
\r
1242 browser.page().mainFrame().evaluateJavaScript(
\r
1243 "document.execCommand('foreColor',false,'" + color.name()
\r
1245 browser.setFocus();
\r
1248 // Listener for when a background color change is requested
\r
1249 @SuppressWarnings("unused")
\r
1250 private void fontHilightClicked() {
\r
1251 // QColorDialog dialog = new QColorDialog();
\r
1252 // QColor color = QColorDialog.getColor();
\r
1253 QColor color = fontHilightColorMenu.getColor();
\r
1254 if (color.isValid())
\r
1255 browser.page().mainFrame().evaluateJavaScript(
\r
1256 "document.execCommand('backColor',false,'" + color.name()
\r
1258 browser.setFocus();
\r
1261 // Listener for when a background color change is requested
\r
1262 @SuppressWarnings("unused")
\r
1263 private void superscriptClicked() {
\r
1264 browser.page().mainFrame().evaluateJavaScript(
\r
1265 "document.execCommand('superscript');");
\r
1266 browser.setFocus();
\r
1269 // Listener for when a background color change is requested
\r
1270 @SuppressWarnings("unused")
\r
1271 private void subscriptClicked() {
\r
1272 browser.page().mainFrame().evaluateJavaScript(
\r
1273 "document.execCommand('subscript');");
\r
1274 browser.setFocus();
\r
1276 // Insert a to-do checkbox
\r
1277 @SuppressWarnings("unused")
\r
1278 private void todoClicked() {
\r
1279 FileNameMap fileNameMap = URLConnection.getFileNameMap();
\r
1280 String script_start = new String(
\r
1281 "document.execCommand('insertHtml', false, '");
\r
1282 String script_end = new String("');");
\r
1283 String todo = new String(
\r
1284 "<input TYPE=\"CHECKBOX\" value=\"false\" " +
\r
1285 "onMouseOver=\"style.cursor=\\'hand\\'\" " +
\r
1286 "onClick=\"value=checked; window.jambi.contentChanged(); \" />");
\r
1287 browser.page().mainFrame().evaluateJavaScript(
\r
1288 script_start + todo + script_end);
\r
1289 browser.setFocus();
\r
1292 // Encrypt the selected text
\r
1293 @SuppressWarnings("unused")
\r
1294 private void encryptText() {
\r
1295 String text = browser.selectedText();
\r
1296 if (text.trim().equalsIgnoreCase(""))
\r
1298 text = new String(text.replaceAll("\n", "<br/>"));
\r
1300 EnCryptDialog dialog = new EnCryptDialog();
\r
1302 if (!dialog.okPressed()) {
\r
1306 EnCrypt crypt = new EnCrypt();
\r
1307 String encrypted = crypt.encrypt(text, dialog.getPassword().trim(), 64);
\r
1308 String decrypted = crypt.decrypt(encrypted, dialog.getPassword().trim(), 64);
\r
1310 if (encrypted.trim().equals("")) {
\r
1311 QMessageBox.information(this, tr("Error"), tr("Error Encrypting String"));
\r
1314 StringBuffer buffer = new StringBuffer(encrypted.length() + 100);
\r
1315 buffer.append("<img en-tag=\"en-crypt\" cipher=\"RC2\" hint=\""
\r
1316 + dialog.getHint().replace("'","\\'") + "\" length=\"64\" ");
\r
1317 buffer.append("contentEditable=\"false\" alt=\"");
\r
1318 buffer.append(encrypted);
\r
1319 buffer.append("\" src=\"").append(FileUtils.toForwardSlashedPath(Global.getFileManager().getImageDirPath("encrypt.png") +"\""));
\r
1320 Global.cryptCounter++;
\r
1321 buffer.append(" id=\"crypt"+Global.cryptCounter.toString() +"\"");
\r
1322 buffer.append(" onMouseOver=\"style.cursor=\\'hand\\'\"");
\r
1323 buffer.append(" onClick=\"window.jambi.decryptText(\\'crypt"+Global.cryptCounter.toString()
\r
1324 +"\\', \\'"+encrypted+"\\', \\'"+dialog.getHint().replace("'", "\\&apos;")+"\\');\"");
\r
1325 buffer.append("style=\"display:block\" />");
\r
1327 String script_start = new String(
\r
1328 "document.execCommand('insertHtml', false, '");
\r
1329 String script_end = new String("');");
\r
1330 browser.page().mainFrame().evaluateJavaScript(
\r
1331 script_start + buffer.toString() + script_end);
\r
1335 // Insert a hyperlink
\r
1336 public void insertLink() {
\r
1337 logger.log(logger.EXTREME, "Inserting link");
\r
1338 String text = browser.selectedText();
\r
1339 if (text.trim().equalsIgnoreCase(""))
\r
1342 InsertLinkDialog dialog = new InsertLinkDialog(insertHyperlink);
\r
1343 if (currentHyperlink != null && currentHyperlink != "") {
\r
1344 dialog.setUrl(currentHyperlink);
\r
1347 if (!dialog.okPressed()) {
\r
1348 logger.log(logger.EXTREME, "Insert link canceled");
\r
1352 // Take care of inserting new links
\r
1353 if (insertHyperlink) {
\r
1354 String selectedText = browser.selectedText();
\r
1355 if (dialog.getUrl().trim().equals(""))
\r
1357 logger.log(logger.EXTREME, "Inserting link on text "+selectedText);
\r
1358 logger.log(logger.EXTREME, "URL Link " +dialog.getUrl().trim());
\r
1359 String dUrl = StringUtils.replace(dialog.getUrl().trim(), "'", "\\'");
\r
1360 String url = "<a href=\"" +dUrl
\r
1361 +"\" title=" +dUrl
\r
1362 +" >"+selectedText +"</a>";
\r
1363 String script = "document.execCommand('insertHtml', false, '"+url+"');";
\r
1364 browser.page().mainFrame().evaluateJavaScript(script);
\r
1368 // Edit existing links
\r
1369 String js = new String( "function getCursorPos() {"
\r
1371 +"if (window.getSelection) {"
\r
1372 +" var selObj = window.getSelection();"
\r
1373 +" var selRange = selObj.getRangeAt(0);"
\r
1374 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
1375 +" while(workingNode != null) { "
\r
1376 +" if (workingNode.nodeName.toLowerCase()=='a') workingNode.setAttribute('href','" +dialog.getUrl() +"');"
\r
1377 +" workingNode = workingNode.parentNode;"
\r
1380 +"} getCursorPos();");
\r
1381 browser.page().mainFrame().evaluateJavaScript(js);
\r
1383 if (!dialog.getUrl().trim().equals("")) {
\r
1389 js = new String( "function getCursorPos() {"
\r
1391 +"if (window.getSelection) {"
\r
1392 +" var selObj = window.getSelection();"
\r
1393 +" var selRange = selObj.getRangeAt(0);"
\r
1394 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
1395 +" while(workingNode != null) { "
\r
1396 +" if (workingNode.nodeName.toLowerCase()=='a') { "
\r
1397 +" workingNode.removeAttribute('href');"
\r
1398 +" workingNode.removeAttribute('title');"
\r
1399 +" var text = document.createTextNode(workingNode.innerText);"
\r
1400 +" workingNode.parentNode.insertBefore(text, workingNode);"
\r
1401 +" workingNode.parentNode.removeChild(workingNode);"
\r
1403 +" workingNode = workingNode.parentNode;"
\r
1406 +"} getCursorPos();");
\r
1407 browser.page().mainFrame().evaluateJavaScript(js);
\r
1415 // Insert a hyperlink
\r
1416 public void insertLatex() {
\r
1419 public void editLatex(String guid) {
\r
1420 logger.log(logger.EXTREME, "Inserting latex");
\r
1421 String text = browser.selectedText();
\r
1422 if (text.trim().equalsIgnoreCase("")) {
\r
1423 InsertLatexImage dialog = new InsertLatexImage();
\r
1424 if (guid != null) {
\r
1425 String formula = conn.getNoteTable().noteResourceTable.getNoteSourceUrl(guid).replace("http://latex.codecogs.com/gif.latex?", "");
\r
1426 dialog.setFormula(formula);
\r
1429 if (!dialog.okPressed()) {
\r
1430 logger.log(logger.EXTREME, "Edit LaTex canceled");
\r
1433 text = dialog.getFormula().trim();
\r
1435 blockApplication.emit(this);
\r
1436 logger.log(logger.EXTREME, "Inserting LaTeX formula:" +text);
\r
1438 text = StringUtils.replace(text, "'", "\\'");
\r
1439 String url = "http://latex.codecogs.com/gif.latex?" +text;
\r
1440 logger.log(logger.EXTREME, "Sending request to codecogs --> " + url);
\r
1441 QNetworkAccessManager manager = new QNetworkAccessManager(this);
\r
1442 manager.finished.connect(this, "insertLatexImageReady(QNetworkReply)");
\r
1443 unblockTime = new GregorianCalendar().getTimeInMillis()+5000;
\r
1444 awaitingHttpResponse = true;
\r
1445 manager.get(new QNetworkRequest(new QUrl(url)));
\r
1448 public void insertLatexImageReady(QNetworkReply reply) {
\r
1449 logger.log(logger.EXTREME, "Response received from CodeCogs");
\r
1450 if (reply.error() != NetworkError.NoError)
\r
1454 if (!awaitingHttpResponse)
\r
1457 awaitingHttpResponse = false;
\r
1458 QUrl replyUrl = reply.url();
\r
1459 QByteArray image = reply.readAll();
\r
1461 logger.log(logger.EXTREME, "New image size: " +image.size());
\r
1463 Resource newRes = null;
\r
1466 if (latexGuid == null) {
\r
1467 logger.log(logger.EXTREME, "Creating temporary gif");
\r
1468 path = Global.getFileManager().getResDirPath("latex-temp.gif");
\r
1469 tfile = new QFile(path);
\r
1470 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
\r
1471 logger.log(logger.EXTREME, "File Open: " +tfile.errorString());
\r
1472 tfile.write(image);
\r
1473 logger.log(logger.EXTREME, "Bytes writtes: "+tfile.size());
\r
1475 logger.log(logger.EXTREME, "Creating resource");
\r
1476 newRes = createResource(path,0,"image/gif", false);
\r
1477 logger.log(logger.EXTREME, "Renaming temporary file to " +newRes.getGuid()+".gif");
\r
1478 path = Global.getFileManager().getResDirPath(newRes.getGuid()+".gif");
\r
1479 tfile.rename(path);
\r
1481 newRes = conn.getNoteTable().noteResourceTable.getNoteResource(latexGuid, false);
\r
1482 path = Global.getFileManager().getResDirPath(newRes.getGuid()+".gif");
\r
1483 tfile = new QFile(path);
\r
1484 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
\r
1485 tfile.write(image);
\r
1487 newRes.getData().setBody(image.toByteArray());
\r
1488 conn.getNoteTable().noteResourceTable.updateNoteResource(newRes, true);
\r
1491 logger.log(logger.EXTREME, "Setting source: " +replyUrl.toString());
\r
1492 newRes.getAttributes().setSourceURL(replyUrl.toString());
\r
1493 conn.getNoteTable().noteResourceTable.updateNoteSourceUrl(newRes.getGuid(), replyUrl.toString(), true);
\r
1495 for(int i=0; i<currentNote.getResourcesSize(); i++) {
\r
1496 if (currentNote.getResources().get(i).getGuid().equals(newRes.getGuid())) {
\r
1497 currentNote.getResources().remove(i);
\r
1498 i=currentNote.getResourcesSize();
\r
1501 currentNote.getResources().add(newRes);
\r
1504 // do the actual insert into the note. We only do this on new formulas. Existing ones we
\r
1505 // just write out the file (which is aleady done) and reload.
\r
1506 if (latexGuid == null) {
\r
1507 StringBuffer buffer = new StringBuffer(100);
\r
1508 String formula = replyUrl.toString().toLowerCase().replace("http://latex.codecogs.com/gif.latex?", "");
\r
1509 buffer.append("<a href=\"latex://"+path.replace("\\", "/")+"\" title=\""+formula+"\""
\r
1511 buffer.append(path.replace("\\", "/"));
\r
1512 buffer.append("\" en-tag=\"en-latex\" type=\"image/gif\""
\r
1513 +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""
\r
1514 +" guid=\"" +newRes.getGuid() +"\""
\r
1517 String script_start = new String("document.execCommand('insertHTML', false, '");
\r
1518 String script_end = new String("');");
\r
1519 browser.page().mainFrame().evaluateJavaScript(
\r
1520 script_start + buffer + script_end);
\r
1523 logger.log(logger.EXTREME, "New HTML set\n" +browser.page().currentFrame().toHtml());
\r
1524 QWebSettings.setMaximumPagesInCache(0);
\r
1525 QWebSettings.setObjectCacheCapacities(0, 0, 0);
\r
1527 browser.page().mainFrame().setHtml(browser.page().mainFrame().toHtml());
\r
1530 // resourceSignal.contentChanged.emit(path);
\r
1532 unblockApplication.emit();
\r
1541 public void insertTable() {
\r
1542 TableDialog dialog = new TableDialog();
\r
1544 if (!dialog.okPressed()) {
\r
1548 int cols = dialog.getCols();
\r
1549 int rows = dialog.getRows();
\r
1550 int width = dialog.getWidth();
\r
1551 boolean percent = dialog.isPercent();
\r
1553 String newHTML = "<table border=\"1\" width=\"" +new Integer(width).toString();
\r
1555 newHTML = newHTML +"%";
\r
1556 newHTML = newHTML + "\"><tbody>";
\r
1558 for (int i=0; i<rows; i++) {
\r
1559 newHTML = newHTML +"<tr>";
\r
1560 for (int j=0; j<cols; j++) {
\r
1561 newHTML = newHTML +"<td> </td>";
\r
1563 newHTML = newHTML +"</tr>";
\r
1565 newHTML = newHTML+"</tbody></table>";
\r
1567 String script = "document.execCommand('insertHtml', false, '"+newHTML+"');";
\r
1568 browser.page().mainFrame().evaluateJavaScript(script);
\r
1572 // Text content changed
\r
1573 @SuppressWarnings("unused")
\r
1574 private void selectionChanged() {
\r
1575 browser.encryptAction.setEnabled(true);
\r
1576 browser.insertLinkAction.setEnabled(true);
\r
1577 String scriptStart = "var selection_text = (window.getSelection()).toString();"
\r
1578 + "var range = (window.getSelection()).getRangeAt(0);"
\r
1579 + "var parent_html = range.commonAncestorContainer.innerHTML;"
\r
1580 + "if (parent_html == undefined) {window.jambi.saveSelectedText(selection_text); return;}"
\r
1581 + "var first_text = range.startContainer.nodeValue.substr(range.startOffset);"
\r
1582 + "var last_text = (range.endContainer.nodeValue).substring(0,range.endOffset);"
\r
1583 + "var start = parent_html.indexOf(first_text);"
\r
1584 + "var end = parent_html.indexOf(last_text,start+1)+last_text.length;"
\r
1585 + "var value = parent_html.substring(start,end);"
\r
1586 + "window.jambi.saveSelectedText(value);" ;
\r
1587 browser.page().mainFrame().evaluateJavaScript(scriptStart);
\r
1591 public void saveSelectedText(String text) {
\r
1592 boolean enabled = true;
\r
1593 if (text.trim().length() == 0)
\r
1595 if (text.indexOf("en-tag=\"en-crypt\"") >= 0)
\r
1597 if (text.indexOf("<img en-tag=\"en-media\"") >= 0)
\r
1599 if (text.indexOf("<a en-tag=\"en-media\"") >= 0)
\r
1601 if (text.indexOf("<input ") >= 0)
\r
1604 browser.encryptAction.setEnabled(enabled);
\r
1605 browser.insertLinkAction.setEnabled(enabled);
\r
1606 // selectedText = text;
\r
1609 // Decrypt clicked text
\r
1610 public void decryptText(String id, String text, String hint) {
\r
1611 EnCrypt crypt = new EnCrypt();
\r
1612 String plainText = null;
\r
1613 Calendar currentTime = new GregorianCalendar();
\r
1614 Long l = new Long(currentTime.getTimeInMillis());
\r
1615 String slot = new String(Long.toString(l));
\r
1617 // First, try to decrypt with any keys we already have
\r
1618 for (int i=0; i<Global.passwordRemember.size(); i++) {
\r
1619 plainText = crypt.decrypt(text, Global.passwordRemember.get(i).getFirst(), 64);
\r
1620 if (plainText != null) {
\r
1621 slot = new String(Long.toString(l));
\r
1622 Global.passwordSafe.put(slot, Global.passwordRemember.get(i));
\r
1623 removeEncryption(id, plainText, false, slot);
\r
1629 EnDecryptDialog dialog = new EnDecryptDialog();
\r
1630 dialog.setHint(hint);
\r
1631 while (plainText == null || !dialog.okPressed()) {
\r
1633 if (!dialog.okPressed()) {
\r
1636 plainText = crypt.decrypt(text, dialog.getPassword().trim(), 64);
\r
1637 if (plainText == null) {
\r
1638 QMessageBox.warning(this, "Incorrect Password", "The password entered is not correct");
\r
1641 Pair<String,String> passwordPair = new Pair<String,String>();
\r
1642 passwordPair.setFirst(dialog.getPassword());
\r
1643 passwordPair.setSecond(dialog.getHint());
\r
1644 Global.passwordSafe.put(slot, passwordPair);
\r
1645 // removeEncryption(id, plainText.replaceAll("\n", "<br/>"), dialog.permanentlyDecrypt(), slot);
\r
1646 removeEncryption(id, plainText, dialog.permanentlyDecrypt(), slot);
\r
1647 if (dialog.rememberPassword()) {
\r
1648 Pair<String, String> pair = new Pair<String,String>();
\r
1649 pair.setFirst(dialog.getPassword());
\r
1650 pair.setSecond(dialog.getHint());
\r
1651 Global.passwordRemember.add(pair);
\r
1656 // Get the editor tag line
\r
1657 public TagLineEdit getTagLine() {
\r
1661 // Modify a note's tags
\r
1662 @SuppressWarnings("unused")
\r
1663 private void modifyTags() {
\r
1664 TagAssign tagWindow = new TagAssign(allTags, currentTags, !conn.getNotebookTable().isLinked(currentNote.getNotebookGuid()));
\r
1666 if (tagWindow.okClicked()) {
\r
1667 currentTags.clear();
\r
1668 StringBuffer tagDisplay = new StringBuffer();
\r
1670 List<QListWidgetItem> newTags = tagWindow.getTagList()
\r
1672 for (int i = 0; i < newTags.size(); i++) {
\r
1673 currentTags.add(newTags.get(i).text());
\r
1674 tagDisplay.append(newTags.get(i).text());
\r
1675 if (i < newTags.size() - 1) {
\r
1676 tagDisplay.append(Global.tagDelimeter + " ");
\r
1679 tagEdit.setText(tagDisplay.toString());
\r
1680 noteSignal.tagsChanged.emit(currentNote.getGuid(), currentTags);
\r
1684 // Tag line has been modified by typing text
\r
1685 @SuppressWarnings("unused")
\r
1686 private void modifyTagsTyping() {
\r
1687 String completionText = "";
\r
1688 if (tagEdit.currentCompleterSelection != null && !tagEdit.currentCompleterSelection.equals("")) {
\r
1689 completionText = tagEdit.currentCompleterSelection;
\r
1690 tagEdit.currentCompleterSelection = "";
\r
1693 if (tagEdit.text().equalsIgnoreCase(saveTagList))
\r
1696 // We know something has changed...
\r
1697 String oldTagArray[] = saveTagList.split(Global.tagDelimeter);
\r
1698 String newTagArray[];
\r
1699 if (!completionText.equals("")) {
\r
1700 String before = tagEdit.text().substring(0,tagEdit.cursorPosition());
\r
1701 int lastDelimiter = before.lastIndexOf(Global.tagDelimeter);
\r
1702 if (lastDelimiter > 0)
\r
1703 before = before.substring(0,before.lastIndexOf(Global.tagDelimeter));
\r
1706 String after = tagEdit.text().substring(tagEdit.cursorPosition());
\r
1707 newTagArray = (before+Global.tagDelimeter+completionText+Global.tagDelimeter+after).split(Global.tagDelimeter);
\r
1710 newTagArray = tagEdit.text().split(Global.tagDelimeter);
\r
1713 // Remove any traling or leading blanks
\r
1714 for (int i=0; i<newTagArray.length; i++)
\r
1715 newTagArray[i] = newTagArray[i].trim().replaceAll("^\\s+", "");;
\r
1717 // Remove any potential duplicates from the new list
\r
1718 for (int i=0; i<newTagArray.length; i++) {
\r
1719 boolean foundOnce = false;
\r
1720 for (int j=0; j<newTagArray.length; j++) {
\r
1721 if (newTagArray[j].equalsIgnoreCase(newTagArray[i])) {
\r
1725 newTagArray[j] = "";
\r
1730 List<String> newTagList = new ArrayList<String>();
\r
1731 List<String> oldTagList = new ArrayList<String>();
\r
1733 for (int i = 0; i < oldTagArray.length; i++)
\r
1734 if (!oldTagArray[i].trim().equals(""))
\r
1735 oldTagList.add(oldTagArray[i]);
\r
1736 for (int i = 0; i < newTagArray.length; i++)
\r
1737 if (!newTagArray[i].trim().equals(""))
\r
1738 newTagList.add(newTagArray[i]);
\r
1740 if (conn.getNotebookTable().isLinked(currentNote.getNotebookGuid())) {
\r
1741 for (int i=newTagList.size()-1; i>=0; i--) {
\r
1742 boolean found = false;
\r
1743 for (int j=0; j<allTags.size(); j++) {
\r
1744 if (allTags.get(j).getName().equalsIgnoreCase(newTagList.get(i))) {
\r
1750 newTagList.remove(i);
\r
1754 // Let's cleanup the appearance of the tag list
\r
1755 Collections.sort(newTagList);
\r
1756 String newDisplay = "";
\r
1757 for (int i=0; i<newTagList.size(); i++) {
\r
1758 newDisplay = newDisplay+newTagList.get(i);
\r
1759 if (i<newTagList.size()-1)
\r
1760 newDisplay = newDisplay+Global.tagDelimeter +" ";
\r
1762 tagEdit.blockSignals(true);
\r
1763 tagEdit.setText(newDisplay);
\r
1764 tagEdit.blockSignals(false);
\r
1766 // We now have lists of the new & old. Remove duplicates. If all
\r
1767 // are removed from both then nothing has really changed
\r
1768 for (int i = newTagList.size() - 1; i >= 0; i--) {
\r
1769 String nTag = newTagList.get(i);
\r
1770 for (int j = oldTagList.size() - 1; j >= 0; j--) {
\r
1771 String oTag = oldTagList.get(j);
\r
1772 if (oTag.equalsIgnoreCase(nTag)) {
\r
1773 oldTagList.remove(j);
\r
1774 newTagList.remove(i);
\r
1780 if (oldTagList.size() != 0 || newTagList.size() != 0) {
\r
1781 currentTags.clear();
\r
1782 newTagArray = tagEdit.text().split(Global.tagDelimeter);
\r
1783 for (int i = 0; i < newTagArray.length; i++)
\r
1784 if (!newTagArray[i].trim().equals(""))
\r
1785 currentTags.add(newTagArray[i].trim());
\r
1787 noteSignal.tagsChanged.emit(currentNote.getGuid(), currentTags);
\r
1792 // Tab button was pressed
\r
1793 public void tabPressed() {
\r
1794 if (insideEncryption)
\r
1796 if (!insideList && !insideTable) {
\r
1797 String script_start = new String(
\r
1798 "document.execCommand('insertHtml', false, ' ');");
\r
1799 browser.page().mainFrame().evaluateJavaScript(script_start);
\r
1805 if (insideTable) {
\r
1806 String js = new String( "function getCursorPosition() { "
\r
1807 +" var selObj = window.getSelection();"
\r
1808 +" var selRange = selObj.getRangeAt(0);"
\r
1809 +" var workingNode = window.getSelection().anchorNode;"
\r
1810 +" var rowCount = 0;"
\r
1811 +" var colCount = 0;"
\r
1812 +" while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { "
\r
1813 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
\r
1814 +" rowCount = rowCount+1;"
\r
1816 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
\r
1817 +" colCount = colCount+1;"
\r
1819 +" if (workingNode.previousSibling != null)"
\r
1820 +" workingNode = workingNode.previousSibling;"
\r
1822 +" workingNode = workingNode.parentNode;"
\r
1824 +" var nodes = workingNode.getElementsByTagName('tr');"
\r
1825 +" var tableRows = nodes.length;"
\r
1826 +" nodes = nodes[0].getElementsByTagName('td');"
\r
1827 +" var tableColumns = nodes.length;"
\r
1828 +" window.jambi.setTableCursorPositionTab(rowCount, colCount, tableRows, tableColumns);"
\r
1829 +"} getCursorPosition();");
\r
1830 browser.page().mainFrame().evaluateJavaScript(js);
\r
1834 // If a user presses tab from within a table
\r
1835 public void setTableCursorPositionTab(int currentRow, int currentCol, int tableRows, int tableColumns) {
\r
1836 if (tableRows == currentRow && currentCol == tableColumns) {
\r
1839 KeyboardModifiers modifiers = new KeyboardModifiers(KeyboardModifier.NoModifier);
\r
1840 QKeyEvent right = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Right.value(), modifiers);
\r
1841 QKeyEvent end = new QKeyEvent(Type.KeyPress, Qt.Key.Key_End.value(), modifiers);
\r
1842 QKeyEvent end2 = new QKeyEvent(Type.KeyPress, Qt.Key.Key_End.value(), modifiers);
\r
1843 getBrowser().focusWidget();
\r
1844 QCoreApplication.postEvent(getBrowser(), end);
\r
1845 QCoreApplication.postEvent(getBrowser(), right);
\r
1846 QCoreApplication.postEvent(getBrowser(), end2);
\r
1849 public void backtabPressed() {
\r
1850 if (insideEncryption)
\r
1854 if (insideTable) {
\r
1855 String js = new String( "function getCursorPosition() { "
\r
1856 +" var selObj = window.getSelection();"
\r
1857 +" var selRange = selObj.getRangeAt(0);"
\r
1858 +" var workingNode = window.getSelection().anchorNode;"
\r
1859 +" var rowCount = 0;"
\r
1860 +" var colCount = 0;"
\r
1861 +" while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { "
\r
1862 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
\r
1863 +" rowCount = rowCount+1;"
\r
1865 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
\r
1866 +" colCount = colCount+1;"
\r
1868 +" if (workingNode.previousSibling != null)"
\r
1869 +" workingNode = workingNode.previousSibling;"
\r
1871 +" workingNode = workingNode.parentNode;"
\r
1873 +" var nodes = workingNode.getElementsByTagName('tr');"
\r
1874 +" var tableRows = nodes.length;"
\r
1875 +" nodes = nodes[0].getElementsByTagName('td');"
\r
1876 +" var tableColumns = nodes.length;"
\r
1877 +" window.jambi.setTableCursorPositionBackTab(rowCount, colCount, tableRows, tableColumns);"
\r
1878 +"} getCursorPosition();");
\r
1879 browser.page().mainFrame().evaluateJavaScript(js);
\r
1884 // If a user presses backtab from within a table
\r
1885 public void setTableCursorPositionBackTab(int currentRow, int currentCol, int tableRows, int tableColumns) {
\r
1886 if (currentRow == 1 && currentCol == 1) {
\r
1889 KeyboardModifiers modifiers = new KeyboardModifiers(KeyboardModifier.NoModifier);
\r
1890 QKeyEvent left = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Left.value(), modifiers);
\r
1891 QKeyEvent home = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Home.value(), modifiers);
\r
1892 getBrowser().focusWidget();
\r
1893 QCoreApplication.postEvent(getBrowser(), home);
\r
1894 QCoreApplication.postEvent(getBrowser(), left);
\r
1898 public void setInsideList() {
\r
1899 insideList = true;
\r
1902 // The title has been edited
\r
1903 @SuppressWarnings("unused")
\r
1904 private void titleEdited() {
\r
1905 // If we don't have a good note, or if the current title
\r
1906 // matches the old title then we don't need to do anything
\r
1907 if (currentNote == null)
\r
1909 if (currentNote.getTitle().trim().equals(titleLabel.text().trim()))
\r
1912 // If we have a real change, we need to save it.
\r
1913 noteSignal.titleChanged.emit(currentNote.getGuid(), titleLabel.text());
\r
1914 currentNote.setTitle(titleLabel.text());
\r
1915 saveNoteTitle = titleLabel.text();
\r
1919 // Set the list of note tags
\r
1920 public void setAllTags(List<Tag> l) {
\r
1922 tagEdit.setTagList(l);
\r
1925 // Setter for the current tags
\r
1926 public void setCurrentTags(List<String> s) {
\r
1930 // Save the list of notebooks
\r
1931 public void setNotebookList(List<Notebook> n) {
\r
1933 loadNotebookList();
\r
1936 // Load the notebook list and select the current notebook
\r
1937 private void loadNotebookList() {
\r
1938 if (notebookBox.count() != 0)
\r
1939 notebookBox.clear();
\r
1940 if (notebookList == null)
\r
1943 for (int i = 0; i < notebookList.size(); i++) {
\r
1944 notebookBox.addItem(notebookList.get(i).getName());
\r
1945 if (currentNote != null) {
\r
1946 if (currentNote.getNotebookGuid().equals(
\r
1947 notebookList.get(i).getGuid())) {
\r
1948 notebookBox.setCurrentIndex(i);
\r
1955 // Set the notebook for a note
\r
1956 public void setNotebook(String notebook) {
\r
1957 currentNote.setNotebookGuid(notebook);
\r
1958 loadNotebookList();
\r
1961 // Get the contents of the editor
\r
1962 public String getContent() {
\r
1963 return browser.page().currentFrame().toHtml();
\r
1966 // The note contents have changed
\r
1967 public void contentChanged() {
\r
1968 String content = getContent();
\r
1970 noteSignal.noteChanged.emit(currentNote.getGuid(), content);
\r
1973 // The notebook selection has changed
\r
1974 @SuppressWarnings("unused")
\r
1975 private void notebookChanged() {
\r
1976 boolean changed = false;
\r
1977 String n = notebookBox.currentText();
\r
1978 for (int i = 0; i < notebookList.size(); i++) {
\r
1979 if (n.equals(notebookList.get(i).getName())) {
\r
1980 if (!notebookList.get(i).getGuid().equals(currentNote.getNotebookGuid())) {
\r
1981 String guid = conn.getNotebookTable().findNotebookByName(n);
\r
1982 if (conn.getNotebookTable().isLinked(guid)) {
\r
1983 tagEdit.setText("");
\r
1984 noteSignal.tagsChanged.emit(currentNote.getGuid(), new ArrayList<String>());
\r
1985 FilterEditorTags t = new FilterEditorTags(conn, logger);
\r
1986 setAllTags(t.getValidTags(currentNote));
\r
1988 currentNote.setNotebookGuid(notebookList.get(i).getGuid());
\r
1991 i = notebookList.size();
\r
1995 // If the notebook changed, signal the update
\r
1997 noteSignal.notebookChanged.emit(currentNote.getGuid(), currentNote
\r
1998 .getNotebookGuid());
\r
2001 // Check the note title
\r
2002 private void checkNoteTitle() {
\r
2003 String text = browser.page().currentFrame().toPlainText();
\r
2004 if (saveNoteTitle.trim().equals("") || saveNoteTitle.trim().equals("Untitled Note")) {
\r
2005 int newLine = text.indexOf("\n");
\r
2006 if (newLine > 0) {
\r
2007 text = text.substring(0, newLine);
\r
2008 if (text.trim().equals(""))
\r
2009 text = tr("Untitled Note");
\r
2010 titleLabel.setText(text);
\r
2012 if (text.length() > Constants.EDAM_NOTE_TITLE_LEN_MAX)
\r
2013 titleLabel.setText(text.substring(0, Constants.EDAM_NOTE_TITLE_LEN_MAX));
\r
2015 titleLabel.blockSignals(true);
\r
2016 if (text.trim().equals(""))
\r
2017 titleLabel.setText(tr("Untitled Note"));
\r
2019 titleLabel.setText(text);
\r
2020 titleLabel.blockSignals(false);
\r
2023 noteSignal.titleChanged.emit(currentNote.getGuid(), titleLabel
\r
2028 // Return the note contents so we can email them
\r
2029 public String getContentsToEmail() {
\r
2030 return browser.page().currentFrame().toPlainText().trim();
\r
2032 * int body = browser.page().currentFrame().toHtml().indexOf("<body>");
\r
2033 * String temp = browser.page().currentFrame().toHtml(); if (body == -1)
\r
2034 * temp = "<html><body><b>Test</b></body></html>"; else temp =
\r
2035 * "<html>"+temp.substring(body); return temp; // return
\r
2036 * urlEncode(browser.page().currentFrame().toHtml());
\r
2040 // Insert an image into the editor
\r
2041 private void insertImage(QMimeData mime) {
\r
2042 logger.log(logger.EXTREME, "Entering insertImage");
\r
2043 QImage img = (QImage) mime.imageData();
\r
2044 String script_start = new String(
\r
2045 "document.execCommand('insertHTML', false, '");
\r
2046 String script_end = new String("');");
\r
2048 long now = new Date().getTime();
\r
2049 String path = Global.getFileManager().getResDirPath(
\r
2050 (new Long(now).toString()) + ".jpg");
\r
2052 // This block is just a hack to make sure we wait at least 1ms so we
\r
2054 // have collisions on image names
\r
2055 long i = new Date().getTime();
\r
2057 i = new Date().getTime();
\r
2059 // Open the file & write the data
\r
2060 QFile tfile = new QFile(path);
\r
2061 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
\r
2062 if (!img.save(tfile)) {
\r
2068 Resource newRes = createResource(QUrl.fromLocalFile(path).toString(), 0, "image/jpeg", false);
\r
2069 if (newRes == null)
\r
2071 currentNote.getResources().add(newRes);
\r
2073 // do the actual insert into the note
\r
2074 StringBuffer buffer = new StringBuffer(100);
\r
2075 buffer.append("<img src=\"");
\r
2076 buffer.append(tfile.fileName());
\r
2077 buffer.append("\" en-tag=en-media type=\"image/jpeg\""
\r
2078 +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""
\r
2079 +" guid=\"" +newRes.getGuid() +"\""
\r
2080 +" onContextMenu=\"window.jambi.imageContextMenu(&." +tfile.fileName() +"&.);\""
\r
2083 browser.page().mainFrame().evaluateJavaScript(
\r
2084 script_start + buffer + script_end);
\r
2089 // Handle URLs that are trying to be pasted
\r
2090 public void handleUrls(QMimeData mime) {
\r
2091 logger.log(logger.EXTREME, "Starting handleUrls");
\r
2092 FileNameMap fileNameMap = URLConnection.getFileNameMap();
\r
2094 List<QUrl> urlList = mime.urls();
\r
2095 String url = new String();
\r
2096 String script_start = new String(
\r
2097 "document.execCommand('createLink', false, '");
\r
2098 String script_end = new String("');");
\r
2100 for (int i = 0; i < urlList.size(); i++) {
\r
2101 url = urlList.get(i).toString();
\r
2102 // Find out what type of file we have
\r
2103 String mimeType = fileNameMap.getContentTypeFor(url);
\r
2105 // If null returned, we need to guess at the file type
\r
2106 if (mimeType == null)
\r
2107 mimeType = "application/"
\r
2108 + url.substring(url.lastIndexOf(".") + 1);
\r
2110 // Check if we have an image or some other type of file
\r
2111 if (url.substring(0, 5).equalsIgnoreCase("file:")
\r
2112 && mimeType.substring(0, 5).equalsIgnoreCase("image")) {
\r
2113 handleLocalImageURLPaste(mime, mimeType);
\r
2116 String[] type = mimeType.split("/");
\r
2117 boolean valid = validAttachment(type[1]);
\r
2118 boolean smallEnough = checkFileAttachmentSize(url);
\r
2119 if (smallEnough && valid
\r
2120 && url.substring(0, 5).equalsIgnoreCase("file:")
\r
2121 && !mimeType.substring(0, 5).equalsIgnoreCase("image")) {
\r
2122 handleLocalAttachment(mime, mimeType);
\r
2125 browser.page().mainFrame().evaluateJavaScript(
\r
2126 script_start + url + script_end);
\r
2131 // If a URL being pasted is an image URL, then attach the image
\r
2132 private void handleLocalImageURLPaste(QMimeData mime, String mimeType) {
\r
2133 List<QUrl> urlList = mime.urls();
\r
2134 String url = new String();
\r
2135 String script_start_image = new String(
\r
2136 "document.execCommand('insertHtml', false, '");
\r
2137 String script_end = new String("');");
\r
2138 StringBuffer buffer;
\r
2140 // Copy the image over into the resource directory and create a new resource
\r
2141 // record for each url pasted
\r
2142 for (int i = 0; i < urlList.size(); i++) {
\r
2143 url = urlList.get(i).toString();
\r
2145 Resource newRes = createResource(url, i, mimeType, false);
\r
2146 if (newRes == null)
\r
2148 currentNote.getResources().add(newRes);
\r
2149 buffer = new StringBuffer(100);
\r
2151 // Open the file & write the data
\r
2152 String fileName = Global.getFileManager().getResDirPath(newRes.getGuid());
\r
2153 QFile tfile = new QFile(fileName);
\r
2154 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
\r
2155 tfile.write(newRes.getData().getBody());
\r
2157 buffer.append(script_start_image);
\r
2158 buffer.append("<img src=\"" + FileUtils.toForwardSlashedPath(fileName));
\r
2159 // if (mimeType.equalsIgnoreCase("image/jpg"))
\r
2160 // mimeType = "image/jpeg";
\r
2161 buffer.append("\" en-tag=\"en-media\" type=\"" + mimeType +"\""
\r
2162 +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""
\r
2163 +" guid=\"" +newRes.getGuid() +"\""
\r
2164 +" onContextMenu=\"window.jambi.imageContextMenu('" +tfile.fileName() +"');\""
\r
2166 buffer.append(script_end);
\r
2167 browser.page().mainFrame().evaluateJavaScript(buffer.toString());
\r
2173 // If a URL being pasted is a local file URL, then attach the file
\r
2174 private void handleLocalAttachment(QMimeData mime, String mimeType) {
\r
2175 logger.log(logger.EXTREME, "Attaching local file");
\r
2176 List<QUrl> urlList = mime.urls();
\r
2177 String script_start = new String(
\r
2178 "document.execCommand('insertHtml', false, '");
\r
2179 String script_end = new String("');");
\r
2180 StringBuffer buffer;
\r
2182 String[] type = mimeType.split("/");
\r
2183 String icon = findIcon(type[1]);
\r
2184 if (icon.equals("attachment.png"))
\r
2185 icon = findIcon(type[0]);
\r
2186 buffer = new StringBuffer(100);
\r
2188 for (int i = 0; i < urlList.size(); i++) {
\r
2189 String url = urlList.get(i).toString();
\r
2191 // Start building the HTML
\r
2192 if (icon.equals("attachment.png"))
\r
2193 icon = findIcon(url.substring(url.lastIndexOf(".")+1));
\r
2194 String imageURL = FileUtils.toFileURLString(Global.getFileManager().getImageDirFile(icon));
\r
2196 logger.log(logger.EXTREME, "Creating resource ");
\r
2197 Resource newRes = createResource(url, i, mimeType, true);
\r
2198 if (newRes == null)
\r
2200 logger.log(logger.EXTREME, "New resource size: " +newRes.getData().getSize());
\r
2201 currentNote.getResources().add(newRes);
\r
2203 String fileName = newRes.getGuid() + Global.attachmentNameDelimeter+newRes.getAttributes().getFileName();
\r
2204 // If we have a PDF, we need to setup the preview.
\r
2205 if (icon.equalsIgnoreCase("pdf.png") && Global.pdfPreview()) {
\r
2206 logger.log(logger.EXTREME, "Setting up PDF preview");
\r
2207 if (newRes.getAttributes() != null &&
\r
2208 newRes.getAttributes().getFileName() != null &&
\r
2209 !newRes.getAttributes().getFileName().trim().equals(""))
\r
2210 fileName = newRes.getGuid()+Global.attachmentNameDelimeter+
\r
2211 newRes.getAttributes().getFileName();
\r
2213 fileName = newRes.getGuid()+".pdf";
\r
2214 QFile file = new QFile(Global.getFileManager().getResDirPath(fileName));
\r
2215 QFile.OpenMode mode = new QFile.OpenMode();
\r
2216 mode.set(QFile.OpenModeFlag.WriteOnly);
\r
2218 QDataStream out = new QDataStream(file);
\r
2219 // Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(newRes.getGuid(), true);
\r
2220 QByteArray binData = new QByteArray(newRes.getData().getBody());
\r
2221 // resBinary = null;
\r
2222 out.writeBytes(binData.toByteArray());
\r
2225 PDFPreview pdfPreview = new PDFPreview();
\r
2226 if (pdfPreview.setupPreview(Global.getFileManager().getResDirPath(fileName), "pdf",0)) {
\r
2227 imageURL = file.fileName() + ".png";
\r
2231 logger.log(logger.EXTREME, "Generating link tags");
\r
2232 buffer.delete(0, buffer.length());
\r
2233 buffer.append("<a en-tag=\"en-media\" guid=\"" +newRes.getGuid()+"\" ");
\r
2234 buffer.append(" onContextMenu=\"window.jambi.imageContextMenu('")
\r
2235 .append(Global.getFileManager().getResDirPath(fileName))
\r
2236 .append("');\" "); buffer.append("type=\"" + mimeType + "\" href=\"nnres://" + fileName +"\" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\" >");
\r
2237 buffer.append("<img src=\"" + imageURL + "\" title=\"" +newRes.getAttributes().getFileName());
\r
2238 buffer.append("\"></img>");
\r
2239 buffer.append("</a>");
\r
2240 browser.page().mainFrame().evaluateJavaScript(
\r
2241 script_start + buffer.toString() + script_end);
\r
2246 private Resource createResource(String url, int sequence, String mime, boolean attachment) {
\r
2247 logger.log(logger.EXTREME, "Inside create resource");
\r
2248 QFile resourceFile;
\r
2249 String urlTest = new QUrl(url).toLocalFile();
\r
2250 if (!urlTest.equals(""))
\r
2252 url = url.replace("/", File.separator);
\r
2253 logger.log(logger.EXTREME, "Reading from file to create resource");
\r
2254 resourceFile = new QFile(url);
\r
2255 resourceFile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly));
\r
2256 // logger.log(logger.EXTREME, "Error opening file "+url.toString() +": "+resourceFile.errorString());
\r
2257 byte[] fileData = resourceFile.readAll().toByteArray();
\r
2258 resourceFile.close();
\r
2259 if (fileData.length == 0)
\r
2263 logger.log(logger.EXTREME, "Generating MD5");
\r
2264 md = MessageDigest.getInstance("MD5");
\r
2265 md.update(fileData);
\r
2266 byte[] hash = md.digest();
\r
2268 Resource r = new Resource();
\r
2269 Calendar time = new GregorianCalendar();
\r
2270 long prevTime = time.getTimeInMillis();
\r
2271 while (prevTime == time.getTimeInMillis()) {
\r
2272 time = new GregorianCalendar();
\r
2274 r.setGuid(time.getTimeInMillis()+new Integer(sequence).toString());
\r
2275 r.setNoteGuid(currentNote.getGuid());
\r
2277 r.setActive(true);
\r
2278 r.setUpdateSequenceNum(0);
\r
2279 r.setWidth((short) 0);
\r
2280 r.setHeight((short) 0);
\r
2281 r.setDuration((short) 0);
\r
2283 Data d = new Data();
\r
2284 d.setBody(fileData);
\r
2285 d.setBodyIsSet(true);
\r
2286 d.setBodyHash(hash);
\r
2287 d.setBodyHashIsSet(true);
\r
2289 d.setSize(fileData.length);
\r
2291 int fileNamePos = url.lastIndexOf(File.separator);
\r
2292 if (fileNamePos == -1)
\r
2293 fileNamePos = url.lastIndexOf("/");
\r
2294 String fileName = url.substring(fileNamePos+1);
\r
2295 ResourceAttributes a = new ResourceAttributes();
\r
2297 a.setAltitudeIsSet(false);
\r
2298 a.setLongitude(0);
\r
2299 a.setLongitudeIsSet(false);
\r
2301 a.setLatitudeIsSet(false);
\r
2302 a.setCameraMake("");
\r
2303 a.setCameraMakeIsSet(false);
\r
2304 a.setCameraModel("");
\r
2305 a.setCameraModelIsSet(false);
\r
2306 a.setAttachment(attachment);
\r
2307 a.setAttachmentIsSet(true);
\r
2308 a.setClientWillIndex(false);
\r
2309 a.setClientWillIndexIsSet(true);
\r
2310 a.setRecoType("");
\r
2311 a.setRecoTypeIsSet(false);
\r
2312 a.setSourceURL(url);
\r
2313 a.setSourceURLIsSet(true);
\r
2314 a.setTimestamp(0);
\r
2315 a.setTimestampIsSet(false);
\r
2316 a.setFileName(fileName);
\r
2317 a.setFileNameIsSet(true);
\r
2318 r.setAttributes(a);
\r
2320 conn.getNoteTable().noteResourceTable.saveNoteResource(r, true);
\r
2321 logger.log(logger.EXTREME, "Resource created");
\r
2323 } catch (NoSuchAlgorithmException e1) {
\r
2324 e1.printStackTrace();
\r
2330 // find the appropriate icon for an attachment
\r
2331 private String findIcon(String appl) {
\r
2332 appl = appl.toLowerCase();
\r
2333 File f = Global.getFileManager().getImageDirFile(appl + ".png");
\r
2335 return appl+".png";
\r
2336 return "attachment.png";
\r
2339 // Check if the account supports this type of attachment
\r
2340 private boolean validAttachment(String type) {
\r
2341 if (Global.isPremium())
\r
2343 if (type.equalsIgnoreCase("JPG"))
\r
2345 if (type.equalsIgnoreCase("PNG"))
\r
2347 if (type.equalsIgnoreCase("GIF"))
\r
2349 if (type.equalsIgnoreCase("MP3"))
\r
2351 if (type.equalsIgnoreCase("WAV"))
\r
2353 if (type.equalsIgnoreCase("AMR"))
\r
2355 if (type.equalsIgnoreCase("PDF"))
\r
2357 String error = tr("Non-premium accounts can only attach JPG, PNG, GIF, MP3, WAV, AMR, or PDF files.");
\r
2358 QMessageBox.information(this, tr("Non-Premium Account"), error);
\r
2363 // Check the file attachment to be sure it isn't over 25 mb
\r
2364 private boolean checkFileAttachmentSize(String url) {
\r
2365 String fileName = url.substring(8);
\r
2366 QFile resourceFile = new QFile(fileName);
\r
2367 resourceFile.open(new QIODevice.OpenMode(
\r
2368 QIODevice.OpenModeFlag.ReadOnly));
\r
2369 long size = resourceFile.size();
\r
2370 resourceFile.close();
\r
2371 size = size / 1024 / 1024;
\r
2372 if (size < 50 && Global.isPremium())
\r
2377 String error = tr("A file attachment may not exceed 25MB.");
\r
2378 QMessageBox.information(this, tr("Attachment Size"), error);
\r
2383 @SuppressWarnings("unused")
\r
2384 private void createdChanged() {
\r
2385 QDateTime dt = new QDateTime();
\r
2386 dt.setDate(createdDate.date());
\r
2387 dt.setTime(createdTime.time());
\r
2388 noteSignal.createdDateChanged.emit(currentNote.getGuid(), dt);
\r
2392 @SuppressWarnings("unused")
\r
2393 private void alteredChanged() {
\r
2394 QDateTime dt = new QDateTime();
\r
2395 dt.setDate(alteredDate.date());
\r
2396 dt.setTime(alteredTime.time());
\r
2397 noteSignal.alteredDateChanged.emit(currentNote.getGuid(), dt);
\r
2400 @SuppressWarnings("unused")
\r
2401 private void subjectDateTimeChanged() {
\r
2402 QDateTime dt = new QDateTime();
\r
2403 dt.setDate(subjectDate.date());
\r
2404 dt.setTime(subjectTime.time());
\r
2405 noteSignal.subjectDateChanged.emit(currentNote.getGuid(), dt);
\r
2409 @SuppressWarnings("unused")
\r
2410 private void sourceUrlChanged() {
\r
2411 noteSignal.sourceUrlChanged.emit(currentNote.getGuid(), urlText.text());
\r
2414 @SuppressWarnings("unused")
\r
2415 private void authorChanged() {
\r
2416 noteSignal.authorChanged.emit(currentNote.getGuid(), authorText.text());
\r
2419 @SuppressWarnings("unused")
\r
2420 private void geoBoxChanged() {
\r
2421 int index = geoBox.currentIndex();
\r
2422 geoBox.setCurrentIndex(0);
\r
2424 GeoDialog box = new GeoDialog();
\r
2425 box.setLongitude(currentNote.getAttributes().getLongitude());
\r
2426 box.setLatitude(currentNote.getAttributes().getLatitude());
\r
2427 box.setAltitude(currentNote.getAttributes().getAltitude());
\r
2429 if (!box.okPressed())
\r
2431 double alt = box.getAltitude();
\r
2432 double lat = box.getLatitude();
\r
2433 double lon = box.getLongitude();
\r
2434 if (alt != currentNote.getAttributes().getAltitude() ||
\r
2435 lon != currentNote.getAttributes().getLongitude() ||
\r
2436 lat != currentNote.getAttributes().getLatitude()) {
\r
2437 noteSignal.geoChanged.emit(currentNote.getGuid(), lon, lat, alt);
\r
2438 currentNote.getAttributes().setAltitude(alt);
\r
2439 currentNote.getAttributes().setLongitude(lon);
\r
2440 currentNote.getAttributes().setLatitude(lat);
\r
2445 noteSignal.geoChanged.emit(currentNote.getGuid(), 0.0, 0.0, 0.0);
\r
2446 currentNote.getAttributes().setAltitude(0.0);
\r
2447 currentNote.getAttributes().setLongitude(0.0);
\r
2448 currentNote.getAttributes().setLatitude(0.0);
\r
2451 if (index == 3 || index == 0) {
\r
2452 QDesktopServices.openUrl(new QUrl("http://maps.google.com/maps?z=6&q="+currentNote.getAttributes().getLatitude() +"," +currentNote.getAttributes().getLongitude()));
\r
2456 // ************************************************************
\r
2457 // * User chose to save an attachment. Pares out the request *
\r
2458 // * into a guid & file. Save the result. *
\r
2459 // ************************************************************
\r
2460 public void downloadAttachment(QNetworkRequest request) {
\r
2462 QFileDialog fd = new QFileDialog(this);
\r
2463 fd.setFileMode(FileMode.AnyFile);
\r
2464 fd.setConfirmOverwrite(true);
\r
2465 fd.setWindowTitle(tr("Save File"));
\r
2466 fd.setAcceptMode(AcceptMode.AcceptSave);
\r
2467 fd.setDirectory(System.getProperty("user.home"));
\r
2468 String name = request.url().toString();
\r
2470 int pos = name.lastIndexOf(Global.attachmentNameDelimeter);
\r
2472 guid = name.substring(0, pos).replace("nnres://", "");
\r
2473 name = name.substring(pos +Global.attachmentNameDelimeter.length());
\r
2474 fd.selectFile(name);
\r
2475 pos = name.lastIndexOf('.');
\r
2477 String mimeType = "(*." + name.substring(pos + 1)
\r
2478 + ");; All Files (*)";
\r
2479 fd.setFilter(tr(mimeType));
\r
2485 // Strip URL prefix and base dir
\r
2486 guid = guid.replace("nnres://", "")
\r
2487 .replace(FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath()), "");
\r
2488 guid = guid.replace("file://", "").replace("/", "")
\r
2489 .replace(FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath()), "");
\r
2491 pos = guid.lastIndexOf('.');
\r
2493 guid = guid.substring(0,pos);
\r
2494 if (fd.exec() != 0 && fd.selectedFiles().size() > 0) {
\r
2495 name = name.replace('\\', '/');
\r
2496 Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
\r
2497 QFile saveFile = new QFile(fd.selectedFiles().get(0));
\r
2498 QFile.OpenMode mode = new QFile.OpenMode();
\r
2499 mode.set(QFile.OpenModeFlag.WriteOnly);
\r
2500 saveFile.open(mode);
\r
2501 QDataStream saveOut = new QDataStream(saveFile);
\r
2502 QByteArray binData = new QByteArray(resBinary.getData().getBody());
\r
2503 saveOut.writeBytes(binData.toByteArray());
\r
2510 // ************************************************************
\r
2511 // * User chose to save an attachment. Pares out the request *
\r
2512 // * into a guid & file. Save the result. --- DONE FROM downloadAttachment now!!!!!
\r
2513 // ************************************************************
\r
2514 public void downloadImage(QNetworkRequest request) {
\r
2515 QFileDialog fd = new QFileDialog(this);
\r
2516 fd.setFileMode(FileMode.AnyFile);
\r
2517 fd.setConfirmOverwrite(true);
\r
2518 fd.setWindowTitle(tr("Save File"));
\r
2519 fd.setAcceptMode(AcceptMode.AcceptSave);
\r
2520 fd.setDirectory(System.getProperty("user.home"));
\r
2521 String name = request.url().toString();
\r
2522 name = name.replace("nnres://", "");
\r
2523 String dPath = FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath());
\r
2524 name = name.replace(dPath, "");
\r
2525 int pos = name.lastIndexOf('.');
\r
2526 String guid = name;
\r
2528 String mimeType = "(*." + name.substring(pos + 1)
\r
2529 + ");; All Files (*)";
\r
2530 fd.setFilter(tr(mimeType));
\r
2531 guid = guid.substring(0,pos);
\r
2533 pos = name.lastIndexOf(Global.attachmentNameDelimeter);
\r
2535 guid = name.substring(0, pos);
\r
2536 fd.selectFile(name.substring(pos+Global.attachmentNameDelimeter.length()));
\r
2538 if (fd.exec() != 0 && fd.selectedFiles().size() > 0) {
\r
2539 Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
\r
2540 String fileName = fd.selectedFiles().get(0);
\r
2541 QFile saveFile = new QFile(fileName);
\r
2542 QFile.OpenMode mode = new QFile.OpenMode();
\r
2543 mode.set(QFile.OpenModeFlag.WriteOnly);
\r
2544 saveFile.open(mode);
\r
2545 QDataStream saveOut = new QDataStream(saveFile);
\r
2546 QByteArray binData = new QByteArray(resBinary.getData().getBody());
\r
2547 saveOut.writeBytes(binData.toByteArray());
\r
2553 // *************************************************************
\r
2554 // * decrypt any hidden text. We could do an XML parse, but
\r
2555 // * it is quicker here just to scan for an <img tag & do the fix
\r
2556 // * the manual way
\r
2557 // *************************************************************
\r
2558 private void removeEncryption(String id, String plainText, boolean permanent, String slot) {
\r
2560 plainText = " <table class=\"en-crypt-temp\" slot=\""
\r
2563 +"border=1 width=100%><tbody><tr><td>"
\r
2564 +plainText+"</td></tr></tbody></table>";
\r
2567 String html = browser.page().mainFrame().toHtml();
\r
2568 String text = html;
\r
2569 int imagePos = html.indexOf("<img");
\r
2571 for ( ;imagePos>0; ) {
\r
2572 // Find the end tag
\r
2573 endPos = text.indexOf(">", imagePos);
\r
2574 String tag = text.substring(imagePos-1,endPos);
\r
2575 if (tag.indexOf("id=\""+id+"\"") > -1) {
\r
2576 text = text.substring(0,imagePos) +plainText+text.substring(endPos+1);
\r
2577 QTextCodec codec = QTextCodec.codecForName("UTF-8");
\r
2578 QByteArray unicode = codec.fromUnicode(text);
\r
2579 browser.setContent(unicode);
\r
2583 imagePos = text.indexOf("<img", imagePos+1);
\r
2588 //****************************************************************
\r
2589 //* Focus shortcuts
\r
2590 //****************************************************************
\r
2591 @SuppressWarnings("unused")
\r
2592 private void focusTitle() {
\r
2593 titleLabel.setFocus();
\r
2595 @SuppressWarnings("unused")
\r
2596 private void focusTag() {
\r
2597 tagEdit.setFocus();
\r
2599 @SuppressWarnings("unused")
\r
2600 private void focusNote() {
\r
2601 browser.setFocus();
\r
2603 @SuppressWarnings("unused")
\r
2604 private void focusAuthor() {
\r
2605 authorLabel.setFocus();
\r
2607 @SuppressWarnings("unused")
\r
2608 private void focusUrl() {
\r
2609 urlLabel.setFocus();
\r
2613 //*****************************************************************
\r
2614 //* Set the document background color
\r
2615 //*****************************************************************
\r
2616 public void setBackgroundColor(String color) {
\r
2617 String js = "function changeBackground(color) {"
\r
2618 +"document.body.style.background = color;"
\r
2620 +"changeBackground('" +color+"');";
\r
2621 browser.page().mainFrame().evaluateJavaScript(js);
\r
2626 //****************************************************************
\r
2627 //* MicroFocus changed
\r
2628 //****************************************************************
\r
2629 private void microFocusChanged() {
\r
2630 boldButton.setDown(false);
\r
2631 italicButton.setDown(false);
\r
2632 underlineButton.setDown(false);
\r
2633 browser.openAction.setEnabled(false);
\r
2634 browser.downloadAttachment.setEnabled(false);
\r
2635 browser.downloadImage.setEnabled(false);
\r
2636 browser.rotateImageLeft.setEnabled(false);
\r
2637 browser.rotateImageRight.setEnabled(false);
\r
2638 browser.insertTableAction.setEnabled(true);
\r
2639 browser.deleteTableColumnAction.setEnabled(false);
\r
2640 browser.insertTableRowAction.setEnabled(false);
\r
2641 browser.insertTableColumnAction.setEnabled(false);
\r
2642 browser.deleteTableRowAction.setEnabled(false);
\r
2643 browser.insertLinkAction.setText(tr("Insert Hyperlink"));
\r
2644 insertHyperlink = true;
\r
2645 currentHyperlink ="";
\r
2646 insideList = false;
\r
2647 insideTable = false;
\r
2648 insideEncryption = false;
\r
2649 forceTextPaste = false;
\r
2651 String js = new String( "function getCursorPos() {"
\r
2653 +"if (window.getSelection) {"
\r
2654 +" var selObj = window.getSelection();"
\r
2655 +" var selRange = selObj.getRangeAt(0);"
\r
2656 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
2657 +" while(workingNode != null) { "
\r
2658 // +" window.jambi.printNode(workingNode.nodeName);"
\r
2659 +" if (workingNode.nodeName=='TABLE') { if (workingNode.getAttribute('class').toLowerCase() == 'en-crypt-temp') window.jambi.insideEncryption(); }"
\r
2660 +" if (workingNode.nodeName=='B') window.jambi.boldActive();"
\r
2661 +" if (workingNode.nodeName=='I') window.jambi.italicActive();"
\r
2662 +" if (workingNode.nodeName=='U') window.jambi.underlineActive();"
\r
2663 +" if (workingNode.nodeName=='UL') window.jambi.setInsideList();"
\r
2664 +" if (workingNode.nodeName=='OL') window.jambi.setInsideList();"
\r
2665 +" if (workingNode.nodeName=='LI') window.jambi.setInsideList();"
\r
2666 +" if (workingNode.nodeName=='TBODY') window.jambi.setInsideTable();"
\r
2667 +" 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
2668 +" if (workingNode.nodeName=='SPAN') {"
\r
2669 +" if (workingNode.getAttribute('style') == 'text-decoration: underline;') window.jambi.underlineActive();"
\r
2671 +" workingNode = workingNode.parentNode;"
\r
2674 +"} getCursorPos();");
\r
2675 browser.page().mainFrame().evaluateJavaScript(js);
\r
2678 public void printNode(String n) {
\r
2679 System.out.println("Node Vaule: " +n);
\r
2682 public void insideEncryption() {
\r
2683 insideEncryption = true;
\r
2687 //****************************************************************
\r
2688 //* Insert a table row
\r
2689 //****************************************************************
\r
2690 public void insertTableRow() {
\r
2692 String js = new String( "function insertTableRow() {"
\r
2693 +" var selObj = window.getSelection();"
\r
2694 +" var selRange = selObj.getRangeAt(0);"
\r
2695 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
2696 +" var cellCount = 0;"
\r
2697 +" while(workingNode != null) { "
\r
2698 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
\r
2699 +" row = document.createElement('TR');"
\r
2700 +" var nodes = workingNode.getElementsByTagName('td');"
\r
2701 +" for (j=0; j<nodes.length; j=j+1) {"
\r
2702 +" cell = document.createElement('TD');"
\r
2703 +" cell.innerHTML=' ';"
\r
2704 +" row.appendChild(cell);"
\r
2706 +" workingNode.parentNode.insertBefore(row,workingNode.nextSibling);"
\r
2709 +" workingNode = workingNode.parentNode;"
\r
2711 +"} insertTableRow();");
\r
2712 browser.page().mainFrame().evaluateJavaScript(js);
\r
2716 public void insertTableColumn() {
\r
2717 String js = new String( "function insertTableColumn() {"
\r
2718 +" var selObj = window.getSelection();"
\r
2719 +" var selRange = selObj.getRangeAt(0);"
\r
2720 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
2721 +" var current = 0;"
\r
2722 +" while (workingNode.nodeName.toLowerCase() != 'table' && workingNode != null) {"
\r
2723 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
\r
2724 +" var td = workingNode;"
\r
2725 +" while (td.previousSibling != null) { "
\r
2726 +" current = current+1; td = td.previousSibling;"
\r
2729 +" workingNode = workingNode.parentNode; "
\r
2731 +" if (workingNode == null) return;"
\r
2732 +" for (var i=0; i<workingNode.rows.length; i++) { "
\r
2733 +" var cell = workingNode.rows[i].insertCell(current+1); "
\r
2734 +" cell.innerHTML = ' '; "
\r
2736 +"} insertTableColumn();");
\r
2737 browser.page().mainFrame().evaluateJavaScript(js);
\r
2741 //****************************************************************
\r
2742 //* Delete a table row
\r
2743 //****************************************************************
\r
2744 public void deleteTableRow() {
\r
2746 String js = new String( "function deleteTableRow() {"
\r
2747 +" var selObj = window.getSelection();"
\r
2748 +" var selRange = selObj.getRangeAt(0);"
\r
2749 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
2750 +" var cellCount = 0;"
\r
2751 +" while(workingNode != null) { "
\r
2752 +" if (workingNode.nodeName.toLowerCase()=='tr') {"
\r
2753 +" workingNode.parentNode.removeChild(workingNode);"
\r
2756 +" workingNode = workingNode.parentNode;"
\r
2758 +"} deleteTableRow();");
\r
2759 browser.page().mainFrame().evaluateJavaScript(js);
\r
2763 public void deleteTableColumn() {
\r
2764 String js = new String( "function deleteTableColumn() {"
\r
2765 +" var selObj = window.getSelection();"
\r
2766 +" var selRange = selObj.getRangeAt(0);"
\r
2767 +" var workingNode = window.getSelection().anchorNode.parentNode;"
\r
2768 +" var current = 0;"
\r
2769 +" while (workingNode.nodeName.toLowerCase() != 'table' && workingNode != null) {"
\r
2770 +" if (workingNode.nodeName.toLowerCase() == 'td') {"
\r
2771 +" var td = workingNode;"
\r
2772 +" while (td.previousSibling != null) { "
\r
2773 +" current = current+1; td = td.previousSibling;"
\r
2776 +" workingNode = workingNode.parentNode; "
\r
2778 +" if (workingNode == null) return;"
\r
2779 +" for (var i=0; i<workingNode.rows.length; i++) { "
\r
2780 +" workingNode.rows[i].deleteCell(current); "
\r
2782 +"} deleteTableColumn();");
\r
2783 browser.page().mainFrame().evaluateJavaScript(js);
\r
2788 public void setInsideTable() {
\r
2789 browser.insertTableRowAction.setEnabled(true);
\r
2790 browser.insertTableColumnAction.setEnabled(true);
\r
2791 browser.deleteTableRowAction.setEnabled(true);
\r
2792 browser.deleteTableColumnAction.setEnabled(true);
\r
2793 browser.insertTableAction.setEnabled(false);
\r
2794 browser.encryptAction.setEnabled(false);
\r
2795 insideTable = true;
\r
2798 public void setInsideLink(String link) {
\r
2799 browser.insertLinkAction.setText(tr("Edit Hyperlink"));
\r
2800 currentHyperlink = link;
\r
2801 insertHyperlink = false;
\r
2804 public void italicActive() {
\r
2805 italicButton.setDown(true);
\r
2807 public void boldActive() {
\r
2808 boldButton.setDown(true);
\r
2810 public void underlineActive() {
\r
2811 underlineButton.setDown(true);
\r
2813 public void forceTextPaste() {
\r
2814 forceTextPaste = true;
\r
2816 public void imageContextMenu(String f) {
\r
2817 browser.downloadImage.setEnabled(true);
\r
2818 browser.rotateImageRight.setEnabled(true);
\r
2819 browser.rotateImageLeft.setEnabled(true);
\r
2820 browser.openAction.setEnabled(true);
\r
2823 public void rotateImageRight() {
\r
2824 QWebSettings.setMaximumPagesInCache(0);
\r
2825 QWebSettings.setObjectCacheCapacities(0, 0, 0);
\r
2826 QImage image = new QImage(selectedFile);
\r
2827 QMatrix matrix = new QMatrix();
\r
2828 matrix.rotate( 90.0 );
\r
2829 image = image.transformed(matrix);
\r
2830 image.save(selectedFile);
\r
2831 QWebSettings.setMaximumPagesInCache(0);
\r
2832 QWebSettings.setObjectCacheCapacities(0, 0, 0);
\r
2833 browser.setHtml(browser.page().mainFrame().toHtml());
\r
2836 resourceSignal.contentChanged.emit(selectedFile);
\r
2839 public void rotateImageLeft() {
\r
2840 QImage image = new QImage(selectedFile);
\r
2841 QMatrix matrix = new QMatrix();
\r
2842 matrix.rotate( -90.0 );
\r
2843 image = image.transformed(matrix);
\r
2844 image.save(selectedFile);
\r
2845 browser.setHtml(browser.page().mainFrame().toHtml());
\r
2848 resourceSignal.contentChanged.emit(selectedFile);
\r
2850 public void resourceContextMenu(String f) {
\r
2851 browser.downloadAttachment.setEnabled(true);
\r
2852 browser.openAction.setEnabled(true);
\r
2855 public void latexContextMenu(String f) {
\r
2856 browser.downloadImage.setEnabled(true);
\r
2857 browser.rotateImageRight.setEnabled(true);
\r
2858 browser.rotateImageLeft.setEnabled(true);
\r
2859 browser.openAction.setEnabled(true);
\r
2863 //****************************************************************
\r
2864 //* Apply CSS style to specified word
\r
2865 //****************************************************************
\r
2866 /* public void applyStyleToWords(String word, String style) {
\r
2867 QFile script = new QFile("D:\\NeverNote\\js\\hilight1.js");
\r
2868 script.open(OpenModeFlag.ReadOnly);
\r
2869 String s = script.readAll().toString();
\r
2870 String js = new String(s +" findit('"+word+"', '"+style+"');");
\r
2871 browser.page().mainFrame().evaluateJavaScript(js);
\r
2872 System.out.println(getContent());
\r
2875 //****************************************************************
\r
2876 //* Someone tried to paste a resource between notes, so we need *
\r
2877 //* to do some special handling. *
\r
2878 //****************************************************************
\r
2879 private String fixInternotePaste(String text) {
\r
2880 logger.log(logger.EXTREME, "Fixing internote paste");
\r
2881 String returnValue = fixInternotePasteSearch(text, "<img", "src=\"");
\r
2882 return fixInternotePasteSearch(returnValue, "<a", "href=\"nnres://");
\r
2884 private String fixInternotePasteSearch(String text, String type, String locTag) {
\r
2886 // First, let's fix the images.
\r
2887 int startPos = text.indexOf(type);
\r
2889 for (; startPos>=0;) {
\r
2890 endPos = text.indexOf(">", startPos+1);
\r
2891 String segment = text.substring(startPos, endPos);
\r
2892 if (segment.indexOf("en-tag") > -1) {
\r
2893 String newSegment = segment;
\r
2895 int guidStartPos = segment.indexOf("guid=\"");
\r
2896 int guidEndPos = segment.indexOf("\"", guidStartPos+7);
\r
2897 String guid = segment.substring(guidStartPos+6,guidEndPos);
\r
2899 int mimeStartPos = segment.indexOf("type");
\r
2900 int mimeEndPos = segment.indexOf("\"", mimeStartPos+7);
\r
2901 String mime = segment.substring(mimeStartPos+6,mimeEndPos);
\r
2903 int srcStartPos = segment.indexOf("src");
\r
2904 int srcEndPos = segment.indexOf("\"", srcStartPos+6);
\r
2905 String src = segment.substring(srcStartPos+5,srcEndPos);
\r
2907 Calendar currentTime = new GregorianCalendar();
\r
2908 Long l = new Long(currentTime.getTimeInMillis());
\r
2909 long prevTime = l;
\r
2910 while (l==prevTime) {
\r
2911 currentTime = new GregorianCalendar();
\r
2912 l= new Long(currentTime.getTimeInMillis());
\r
2915 Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
\r
2916 // if r==null, then the image doesn't exist (it was probably cut out of another note, so
\r
2917 // we need to recereate it
\r
2919 r = createResource(src, 1, mime, false);
\r
2923 String randint = new String(Long.toString(l));
\r
2924 String extension = null;
\r
2925 if (r.getMime()!= null) {
\r
2926 extension = r.getMime().toLowerCase();
\r
2927 if (extension.indexOf("/")>-1)
\r
2928 extension = extension.substring(extension.indexOf("/")+1);
\r
2930 String newFile = randint;
\r
2931 if (r.getAttributes().getFileName() != null && r.getAttributes().getFileName() != "")
\r
2932 if (!locTag.startsWith("src"))
\r
2933 newFile = newFile+Global.attachmentNameDelimeter+r.getAttributes().getFileName();
\r
2934 r.setNoteGuid(currentNote.getGuid());
\r
2936 r.setGuid(randint);
\r
2937 conn.getNoteTable().noteResourceTable.saveNoteResource(r, true);
\r
2938 QFile f = new QFile(Global.getFileManager().getResDirPath(newFile));
\r
2939 QByteArray bin = new QByteArray(r.getData().getBody());
\r
2940 f.open(QFile.OpenModeFlag.WriteOnly);
\r
2943 newSegment = newSegment.replace("guid=\""+guid, "guid=\""+randint);
\r
2944 currentNote.getResources().add(r);
\r
2946 int startSrcPos = newSegment.indexOf(locTag);
\r
2947 int endSrcPos = newSegment.indexOf("\"",startSrcPos+locTag.length()+1);
\r
2949 if (locTag.startsWith("src")) {
\r
2950 source = newSegment.substring(startSrcPos+locTag.length(),endSrcPos);
\r
2951 newSegment = newSegment.replace(source,
\r
2952 FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath(newFile)));
\r
2954 source = newSegment.substring(startSrcPos+locTag.length(),endSrcPos);
\r
2955 newSegment = newSegment.replace(source, newFile);
\r
2958 text = text.substring(0,startPos) + newSegment + text.substring(endPos);
\r
2960 startPos = text.indexOf(type, startPos+1);
\r
2966 public void nextPage(String file) {
\r
2967 logger.log(logger.EXTREME, "Starting nextPage()");
\r
2969 Integer pageNumber;
\r
2970 if (previewPageList.containsKey(file))
\r
2971 pageNumber = previewPageList.get(file)+1;
\r
2974 previewPageList.remove(file);
\r
2975 previewPageList.put(file, pageNumber);
\r
2976 PDFPreview pdfPreview = new PDFPreview();
\r
2977 boolean goodPreview = pdfPreview.setupPreview(file, "pdf", pageNumber);
\r
2978 if (goodPreview) {
\r
2980 // String html = getContent();
\r
2981 QWebSettings.setMaximumPagesInCache(0);
\r
2982 QWebSettings.setObjectCacheCapacities(0, 0, 0);
\r
2983 // browser.setContent(new QByteArray());
\r
2984 browser.setHtml(browser.page().mainFrame().toHtml());
\r
2986 // browser.setContent(new QByteArray(html));
\r
2987 // browser.triggerPageAction(WebAction.Reload);
\r
2988 // pdfMouseOver(selectedFile);
\r
2992 public void previousPage(String file) {
\r
2993 logger.log(logger.EXTREME, "Starting previousPage()");
\r
2995 Integer pageNumber;
\r
2996 if (previewPageList.containsKey(file))
\r
2997 pageNumber = previewPageList.get(file)-1;
\r
3000 previewPageList.remove(file);
\r
3001 previewPageList.put(file, pageNumber);
\r
3002 PDFPreview pdfPreview = new PDFPreview();
\r
3003 boolean goodPreview = pdfPreview.setupPreview(file, "pdf", pageNumber);
\r
3004 if (goodPreview) {
\r
3006 // String html = getContent();
\r
3007 QWebSettings.setMaximumPagesInCache(0);
\r
3008 QWebSettings.setObjectCacheCapacities(0, 0, 0);
\r
3009 browser.setHtml(browser.page().mainFrame().toHtml());
\r
3011 // browser.setContent(new QByteArray(html));
\r
3012 // browser.triggerPageAction(WebAction.Reload);
\r
3016 /* public void pdfMouseOver(String name) {
\r
3018 if (previewPageList.containsKey(selectedFile))
\r
3019 pageNumber = previewPageList.get(selectedFile)+1;
\r
3023 if (pageNumber <= 1)
\r
3024 browser.previousPageAction.setEnabled(false);
\r
3026 browser.previousPageAction.setEnabled(true);
\r
3028 PDFPreview pdf = new PDFPreview();
\r
3029 int totalPages = pdf.getPageCount(name);
\r
3030 if (previewPageList.containsKey(selectedFile))
\r
3031 pageNumber = previewPageList.get(selectedFile)+1;
\r
3034 if (totalPages > pageNumber)
\r
3035 browser.nextPageAction.setEnabled(true);
\r
3037 browser.nextPageAction.setEnabled(false);
\r
3041 public void pdfMouseOut() {
\r
3042 // browser.nextPageAction.setVisible(false);
\r
3043 // browser.previousPageAction.setVisible(false);
\r
3047 @SuppressWarnings("unused")
\r
3048 private void toggleUndoVisible(Boolean toggle) {
\r
3049 undoAction.setVisible(toggle);
\r
3050 Global.saveEditorButtonsVisible("undo", toggle);
\r
3052 @SuppressWarnings("unused")
\r
3053 private void toggleRedoVisible(Boolean toggle) {
\r
3054 redoAction.setVisible(toggle);
\r
3055 Global.saveEditorButtonsVisible("redo", toggle);
\r
3057 @SuppressWarnings("unused")
\r
3058 private void toggleCutVisible(Boolean toggle) {
\r
3059 cutAction.setVisible(toggle);
\r
3060 Global.saveEditorButtonsVisible("cut", toggle);
\r
3062 @SuppressWarnings("unused")
\r
3063 private void toggleCopyVisible(Boolean toggle) {
\r
3064 copyAction.setVisible(toggle);
\r
3065 Global.saveEditorButtonsVisible("copy", toggle);
\r
3067 @SuppressWarnings("unused")
\r
3068 private void togglePasteVisible(Boolean toggle) {
\r
3069 pasteAction.setVisible(toggle);
\r
3070 Global.saveEditorButtonsVisible("paste", toggle);
\r
3072 @SuppressWarnings("unused")
\r
3073 private void toggleBoldVisible(Boolean toggle) {
\r
3074 boldAction.setVisible(toggle);
\r
3075 Global.saveEditorButtonsVisible("bold", toggle);
\r
3077 @SuppressWarnings("unused")
\r
3078 private void toggleItalicVisible(Boolean toggle) {
\r
3079 italicAction.setVisible(toggle);
\r
3080 Global.saveEditorButtonsVisible("italic", toggle);
\r
3082 @SuppressWarnings("unused")
\r
3083 private void toggleUnderlineVisible(Boolean toggle) {
\r
3084 underlineAction.setVisible(toggle);
\r
3085 Global.saveEditorButtonsVisible("underline", toggle);
\r
3087 @SuppressWarnings("unused")
\r
3088 private void toggleStrikethroughVisible(Boolean toggle) {
\r
3089 strikethroughAction.setVisible(toggle);
\r
3090 Global.saveEditorButtonsVisible("strikethrough", toggle);
\r
3092 @SuppressWarnings("unused")
\r
3093 private void toggleLeftAlignVisible(Boolean toggle) {
\r
3094 leftAlignAction.setVisible(toggle);
\r
3095 Global.saveEditorButtonsVisible("alignLeft", toggle);
\r
3097 @SuppressWarnings("unused")
\r
3098 private void toggleRightAlignVisible(Boolean toggle) {
\r
3099 rightAlignAction.setVisible(toggle);
\r
3100 Global.saveEditorButtonsVisible("alignRight", toggle);
\r
3102 @SuppressWarnings("unused")
\r
3103 private void toggleCenterAlignVisible(Boolean toggle) {
\r
3104 centerAlignAction.setVisible(toggle);
\r
3105 Global.saveEditorButtonsVisible("alignCenter", toggle);
\r
3107 @SuppressWarnings("unused")
\r
3108 private void toggleHLineVisible(Boolean toggle) {
\r
3109 hlineAction.setVisible(toggle);
\r
3110 Global.saveEditorButtonsVisible("hline", toggle);
\r
3112 @SuppressWarnings("unused")
\r
3113 private void toggleIndentVisible(Boolean toggle) {
\r
3114 indentAction.setVisible(toggle);
\r
3115 Global.saveEditorButtonsVisible("indent", toggle);
\r
3117 @SuppressWarnings("unused")
\r
3118 private void toggleTodoVisible(Boolean toggle) {
\r
3119 todoAction.setVisible(toggle);
\r
3120 Global.saveEditorButtonsVisible("todo", toggle);
\r
3122 @SuppressWarnings("unused")
\r
3123 private void toggleOutdentVisible(Boolean toggle) {
\r
3124 outdentAction.setVisible(toggle);
\r
3125 Global.saveEditorButtonsVisible("outdent", toggle);
\r
3127 @SuppressWarnings("unused")
\r
3128 private void toggleBulletListVisible(Boolean toggle) {
\r
3129 bulletListAction.setVisible(toggle);
\r
3130 Global.saveEditorButtonsVisible("bulletList", toggle);
\r
3132 @SuppressWarnings("unused")
\r
3133 private void toggleNumberListVisible(Boolean toggle) {
\r
3134 numberListAction.setVisible(toggle);
\r
3135 Global.saveEditorButtonsVisible("numberList", toggle);
\r
3137 @SuppressWarnings("unused")
\r
3138 private void toggleFontListVisible(Boolean toggle) {
\r
3139 fontListAction.setVisible(toggle);
\r
3140 Global.saveEditorButtonsVisible("font", toggle);
\r
3142 @SuppressWarnings("unused")
\r
3143 private void toggleFontColorVisible(Boolean toggle) {
\r
3144 fontColorAction.setVisible(toggle);
\r
3145 Global.saveEditorButtonsVisible("fontColor", toggle);
\r
3147 @SuppressWarnings("unused")
\r
3148 private void toggleFontSizeVisible(Boolean toggle) {
\r
3149 fontSizeAction.setVisible(toggle);
\r
3150 Global.saveEditorButtonsVisible("fontSize", toggle);
\r
3152 @SuppressWarnings("unused")
\r
3153 private void toggleFontHilightVisible(Boolean toggle) {
\r
3154 fontHilightAction.setVisible(toggle);
\r
3155 Global.saveEditorButtonsVisible("fontHilight", toggle);
\r
3157 @SuppressWarnings("unused")
\r
3158 private void toggleSpellCheckVisible(Boolean toggle) {
\r
3159 spellCheckAction.setVisible(toggle);
\r
3160 Global.saveEditorButtonsVisible("spellCheck", toggle);
\r
3164 private void setupDictionary() {
\r
3165 File wordList = new File(Global.getFileManager().getSpellDirPath()+Locale.getDefault()+".dic");
\r
3167 dictionary = new SpellDictionaryHashMap(wordList);
\r
3168 spellChecker = new SpellChecker(dictionary);
\r
3170 File userWordList;
\r
3171 userWordList = new File(Global.getFileManager().getSpellDirPathUser()+"user.dic");
\r
3173 // Get the local user spell dictionary
\r
3175 userDictionary = new SpellDictionaryHashMap(userWordList);
\r
3176 } catch (FileNotFoundException e) {
\r
3177 userWordList.createNewFile();
\r
3178 userDictionary = new SpellDictionaryHashMap(userWordList);
\r
3179 } catch (IOException e) {
\r
3180 userWordList.createNewFile();
\r
3181 userDictionary = new SpellDictionaryHashMap(userWordList);
\r
3184 spellListener = new SuggestionListener(this, spellChecker);
\r
3186 // Add the user dictionary
\r
3187 spellChecker.addSpellCheckListener(spellListener);
\r
3188 spellChecker.setUserDictionary(userDictionary);
\r
3190 } catch (FileNotFoundException e) {
\r
3191 QMessageBox.critical(this, tr("Spell Check Error"),
\r
3192 tr("Dictionary "+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+
\r
3193 ".dic was not found."));
\r
3194 } catch (IOException e) {
\r
3195 QMessageBox.critical(this, tr("Spell Check Error"),
\r
3196 tr("Dictionary "+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+
\r
3197 ".dic is invalid."));
\r
3202 // Invoke spell checker dialog
\r
3203 @SuppressWarnings("unused")
\r
3204 private void spellCheckClicked() {
\r
3206 if (spellChecker == null) {
\r
3207 setupDictionary();
\r
3210 // Read user settings
\r
3211 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREDIGITWORDS,
\r
3212 Global.getSpellSetting(Configuration.SPELL_IGNOREDIGITWORDS));
\r
3213 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREINTERNETADDRESSES,
\r
3214 Global.getSpellSetting(Configuration.SPELL_IGNOREINTERNETADDRESSES));
\r
3215 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREMIXEDCASE,
\r
3216 Global.getSpellSetting(Configuration.SPELL_IGNOREMIXEDCASE));
\r
3217 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREUPPERCASE,
\r
3218 Global.getSpellSetting(Configuration.SPELL_IGNOREUPPERCASE));
\r
3219 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNORESENTENCECAPITALIZATION,
\r
3220 Global.getSpellSetting(Configuration.SPELL_IGNORESENTENCECAPITALIZATION));
\r
3222 spellListener.abortSpellCheck = false;
\r
3223 spellListener.errorsFound = false;
\r
3224 String content = getBrowser().page().mainFrame().toPlainText();
\r
3225 StringWordTokenizer tokenizer = new StringWordTokenizer(content);
\r
3226 if (!tokenizer.hasMoreWords())
\r
3228 getBrowser().page().action(WebAction.MoveToStartOfDocument);
\r
3230 getBrowser().setFocus();
\r
3233 // Move to the start of page
\r
3234 KeyboardModifiers ctrl = new KeyboardModifiers(KeyboardModifier.ControlModifier.value());
\r
3235 QKeyEvent home = new QKeyEvent(Type.KeyPress, Key.Key_Home.value(), ctrl);
\r
3236 browser.keyPressEvent(home);
\r
3237 getBrowser().setFocus();
\r
3239 tokenizer = new StringWordTokenizer(content);
\r
3242 while(tokenizer.hasMoreWords()) {
\r
3243 word = tokenizer.nextWord();
\r
3244 found = getBrowser().page().findText(word);
\r
3245 if (found && !spellListener.abortSpellCheck) {
\r
3246 spellChecker.checkSpelling(new StringWordTokenizer(word));
\r
3247 getBrowser().setFocus();
\r
3251 // Go to the end of the document & finish up.
\r
3252 home = new QKeyEvent(Type.KeyPress, Key.Key_End.value(), ctrl);
\r
3253 browser.keyPressEvent(home);
\r
3254 if (!spellListener.errorsFound)
\r
3255 QMessageBox.information(this, tr("Spell Check Complete"),
\r
3256 tr("No Errors Found"));
\r