OSDN Git Service

- Gui cleanup - Rework count threads to reduce SQL overhead & improve performance.
[neighbornote/NeighborNote.git] / src / cx / fbn / nevernote / gui / BrowserWindow.java
1 /*\r
2  * This file is part of NeverNote \r
3  * Copyright 2009 Randy Baumgarte\r
4  * \r
5  * This file may be licensed under the terms of of the\r
6  * GNU General Public License Version 2 (the ``GPL'').\r
7  *\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
12  *\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
17  *\r
18  */\r
19 \r
20 package cx.fbn.nevernote.gui;\r
21 \r
22 import java.io.File;\r
23 import java.io.FileNotFoundException;\r
24 import java.io.IOException;\r
25 import java.net.FileNameMap;\r
26 import java.net.URI;\r
27 import java.net.URLConnection;\r
28 import java.security.MessageDigest;\r
29 import java.security.NoSuchAlgorithmException;\r
30 import java.text.SimpleDateFormat;\r
31 import java.util.ArrayList;\r
32 import java.util.Calendar;\r
33 import java.util.Collections;\r
34 import java.util.Date;\r
35 import java.util.GregorianCalendar;\r
36 import java.util.HashMap;\r
37 import java.util.List;\r
38 import java.util.Locale;\r
39 \r
40 import org.apache.commons.lang.StringUtils;\r
41 \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.QNetworkRequest;\r
108 import com.trolltech.qt.webkit.QWebPage;\r
109 import com.trolltech.qt.webkit.QWebPage.WebAction;\r
110 import com.trolltech.qt.webkit.QWebSettings;\r
111 import com.trolltech.qt.webkit.QWebView;\r
112 \r
113 import cx.fbn.nevernote.Global;\r
114 import cx.fbn.nevernote.dialog.EnCryptDialog;\r
115 import cx.fbn.nevernote.dialog.EnDecryptDialog;\r
116 import cx.fbn.nevernote.dialog.GeoDialog;\r
117 import cx.fbn.nevernote.dialog.InsertLinkDialog;\r
118 import cx.fbn.nevernote.dialog.SpellCheck;\r
119 import cx.fbn.nevernote.dialog.TableDialog;\r
120 import cx.fbn.nevernote.dialog.TagAssign;\r
121 import cx.fbn.nevernote.evernote.EnCrypt;\r
122 import cx.fbn.nevernote.filters.FilterEditorTags;\r
123 import cx.fbn.nevernote.signals.NoteResourceSignal;\r
124 import cx.fbn.nevernote.signals.NoteSignal;\r
125 import cx.fbn.nevernote.sql.DatabaseConnection;\r
126 import cx.fbn.nevernote.utilities.ApplicationLogger;\r
127 import cx.fbn.nevernote.utilities.FileUtils;\r
128 import cx.fbn.nevernote.utilities.Pair;\r
129 \r
130 public class BrowserWindow extends QWidget {\r
131 \r
132         public final QLineEdit titleLabel;\r
133         private final QLineEdit urlText;\r
134         private final QLabel authorLabel;\r
135         private final QLineEdit authorText;\r
136         private final QComboBox geoBox;\r
137         public final TagLineEdit tagEdit;\r
138         public final QLabel tagLabel;\r
139         private final QPushButton urlLabel;\r
140         private final QLabel alteredLabel;\r
141         private final QDateEdit alteredDate;\r
142         private final QTimeEdit alteredTime;\r
143         private final QDateEdit createdDate;\r
144         private final QTimeEdit createdTime;\r
145         private final QLabel subjectLabel;\r
146         private final QDateEdit subjectDate;\r
147         private final QTimeEdit subjectTime;\r
148         public final QComboBox notebookBox;\r
149         private final QLabel notebookLabel;\r
150         private final QLabel createdLabel;\r
151         public final QComboBox fontSize;\r
152         public final QAction    fontSizeAction;\r
153         private boolean extendedOn;\r
154         public boolean buttonsVisible;\r
155         private final String iconPath = new String("classpath:cx/fbn/nevernote/icons/");\r
156         private final ContentView browser;\r
157         private List<Tag> allTags;\r
158         private List<String> currentTags;\r
159         public NoteSignal noteSignal;\r
160         private List<Notebook> notebookList;\r
161         private Note currentNote;\r
162         private String saveNoteTitle;\r
163         private String saveTagList;\r
164         private boolean insideList;\r
165 //      private String selectedText;\r
166         private final DatabaseConnection conn;\r
167         private final QCalendarWidget createdCalendarWidget;\r
168         private final QCalendarWidget alteredCalendarWidget;\r
169         private final QCalendarWidget subjectCalendarWidget;\r
170 \r
171         public final QPushButton undoButton;\r
172         public final QAction    undoAction;\r
173         public final QPushButton redoButton;\r
174         public final QAction    redoAction;\r
175         public final QPushButton cutButton;\r
176         public final QAction    cutAction;\r
177         public final QPushButton copyButton;\r
178         public final QAction    copyAction;\r
179         public final QPushButton pasteButton;\r
180         public final QAction    pasteAction;\r
181         public final QPushButton boldButton;\r
182         public final QAction    boldAction;\r
183         public final QPushButton underlineButton;\r
184         public final QAction    underlineAction;\r
185         public final QPushButton italicButton;\r
186         public final QAction    italicAction;\r
187         public final Signal0 focusLost;\r
188         public final NoteResourceSignal resourceSignal;\r
189 \r
190         public QPushButton rightAlignButton;\r
191         public final QAction    rightAlignAction;\r
192         public QPushButton leftAlignButton;\r
193         public final QAction    leftAlignAction;\r
194         public QPushButton centerAlignButton;\r
195         public final QAction    centerAlignAction;\r
196 \r
197         public final QPushButton strikethroughButton;\r
198         public final QAction    strikethroughAction;\r
199         public final QPushButton hlineButton;\r
200         public final QAction    hlineAction;\r
201         public final QPushButton indentButton;\r
202         public final QAction    indentAction;\r
203         public final QPushButton outdentButton;\r
204         public final QAction    outdentAction;\r
205         public final QPushButton bulletListButton;\r
206         public final QAction    bulletListAction;\r
207         public final QPushButton numberListButton;\r
208         public final QAction    numberListAction;\r
209         public final QPushButton spellCheckButton;\r
210         public final QAction    spellCheckAction;\r
211         public final QPushButton todoButton;\r
212         public final QAction    todoAction;\r
213 \r
214         public final QShortcut focusTitleShortcut;\r
215         public final QShortcut focusTagShortcut;\r
216         public final QShortcut focusNoteShortcut;\r
217         public final QShortcut focusUrlShortcut;\r
218         public final QShortcut focusAuthorShortcut;\r
219         \r
220         public EditorButtonBar buttonLayout;\r
221         public final QComboBox fontList;\r
222         public final QAction    fontListAction;\r
223         public final QToolButton fontColor;\r
224         public final QAction    fontColorAction;\r
225         private final ColorMenu fontColorMenu;\r
226         public final QToolButton fontHilight;\r
227         public final QAction    fontHilightAction;\r
228         private final ColorMenu fontHilightColorMenu;\r
229         public final QFileSystemWatcher fileWatcher;\r
230         public int cursorPosition;\r
231         private boolean forceTextPaste = false;\r
232         private String selectedFile;\r
233         private String currentHyperlink;\r
234         public boolean keepPDFNavigationHidden;\r
235         private final ApplicationLogger logger;\r
236         SpellDictionary dictionary;\r
237     SpellDictionary userDictionary;\r
238     SpellChecker spellChecker;\r
239     SuggestionListener spellListener;\r
240         private final HashMap<String,Integer> previewPageList;  \r
241         boolean insertHyperlink = true;\r
242         boolean insideTable = false;\r
243         boolean insideEncryption = false;\r
244 \r
245         \r
246         public static class SuggestionListener implements SpellCheckListener {\r
247                 public boolean abortSpellCheck = false;\r
248                 public boolean errorsFound = false;\r
249                 private final SpellCheck                spellCheckDialog;\r
250                 \r
251                 \r
252                 private final BrowserWindow parent;\r
253                 public SuggestionListener(BrowserWindow parent, SpellChecker checker) {\r
254                         this.parent = parent;\r
255                         spellCheckDialog = new SpellCheck(checker);\r
256                 }\r
257                 public void spellingError(SpellCheckEvent event) {\r
258                         errorsFound = true;\r
259                         spellCheckDialog.setWord(event.getInvalidWord());\r
260 \r
261                     @SuppressWarnings("unchecked")\r
262                         List<Word> suggestions = event.getSuggestions();\r
263                     spellCheckDialog.clearSuggestions();\r
264                     if (!suggestions.isEmpty()) {\r
265 //                     spellCheckDialog.setCurrentSuggestion(suggestions.get(0).getWord());\r
266                        for (int i=0; i<suggestions.size(); i++) {\r
267                           spellCheckDialog.addSuggestion(suggestions.get(i).getWord());\r
268                        }\r
269                        spellCheckDialog.setSelectedSuggestion(0);\r
270                     }\r
271                     spellCheckDialog.exec();\r
272                     if (spellCheckDialog.cancelPressed()) {\r
273                         abortSpellCheck = true;\r
274                         event.cancel();\r
275                         return;\r
276                     }\r
277                     if (spellCheckDialog.replacePressed()) {\r
278                         QClipboard clipboard = QApplication.clipboard();\r
279                         clipboard.setText(spellCheckDialog.getReplacementWord()); \r
280                         parent.pasteClicked();\r
281                     }\r
282                     event.cancel();\r
283                  }\r
284         }\r
285 \r
286         \r
287         \r
288         public BrowserWindow(DatabaseConnection c) {\r
289                 logger = new ApplicationLogger("browser.log");\r
290                 logger.log(logger.HIGH, "Setting up browser");\r
291                 \r
292                 fileWatcher = new QFileSystemWatcher();\r
293 //              fileWatcher.fileChanged.connect(this, "fileChanged(String)");\r
294                 noteSignal = new NoteSignal();\r
295                 titleLabel = new QLineEdit();\r
296                 titleLabel.setMaxLength(Constants.EDAM_NOTE_TITLE_LEN_MAX);\r
297                 urlText = new QLineEdit();\r
298                 authorText = new QLineEdit();\r
299                 geoBox = new QComboBox();\r
300                 urlLabel = new QPushButton();\r
301                 urlLabel.clicked.connect(this, "sourceUrlClicked()");\r
302                 authorLabel = new QLabel();\r
303                 conn = c;\r
304                 \r
305                 focusLost = new Signal0();\r
306 \r
307                 tagEdit = new TagLineEdit(allTags);\r
308                 tagLabel = new QLabel("Tags:");\r
309                 tagEdit.focusLost.connect(this, "modifyTagsTyping()");\r
310 \r
311                 createdCalendarWidget = new QCalendarWidget();\r
312                 createdDate = new QDateEdit();\r
313                 createdDate.setDisplayFormat(Global.getDateFormat());\r
314                 createdDate.setCalendarPopup(true);\r
315                 createdDate.setCalendarWidget(createdCalendarWidget);\r
316                 createdTime = new QTimeEdit();\r
317                 createdDate.dateChanged.connect(this, "createdChanged()");\r
318                 createdTime.timeChanged.connect(this, "createdChanged()");\r
319 \r
320                 alteredCalendarWidget = new QCalendarWidget();\r
321                 alteredDate = new QDateEdit();\r
322                 alteredDate.setDisplayFormat(Global.getDateFormat());\r
323                 alteredDate.setCalendarPopup(true);\r
324                 alteredDate.setCalendarWidget(alteredCalendarWidget);\r
325                 alteredTime = new QTimeEdit();\r
326                 alteredLabel = new QLabel("Altered:");\r
327                 alteredDate.dateChanged.connect(this, "alteredChanged()");\r
328                 alteredTime.timeChanged.connect(this, "alteredChanged()");\r
329 \r
330                 subjectCalendarWidget = new QCalendarWidget();\r
331                 subjectDate = new QDateEdit();\r
332                 subjectDate.setDisplayFormat(Global.getDateFormat());\r
333                 subjectDate.setCalendarPopup(true);\r
334                 subjectDate.setCalendarWidget(subjectCalendarWidget);\r
335                 subjectTime = new QTimeEdit();\r
336                 subjectLabel = new QLabel(tr("Subject Date:"));\r
337                 subjectDate.dateChanged.connect(this, "subjectDateTimeChanged()");\r
338                 subjectTime.timeChanged.connect(this, "subjectDateTimeChanged()");\r
339                 authorText.textChanged.connect(this, "authorChanged()");\r
340                 urlText.textChanged.connect(this, "sourceUrlChanged()");\r
341 \r
342                 notebookBox = new QComboBox();\r
343                 notebookLabel = new QLabel(tr("Notebook"));\r
344                 createdLabel = new QLabel(tr("Created:"));\r
345                 // selectedText = new String();\r
346 \r
347                 urlLabel.setVisible(false);\r
348                 urlText.setVisible(false);\r
349                 authorLabel.setVisible(false);\r
350                 \r
351                 geoBox.setVisible(false);\r
352                 geoBox.addItem(new QIcon(iconPath+"globe.png"), "");\r
353                 geoBox.addItem(new String(tr("Set")));\r
354                 geoBox.addItem(new String(tr("Clear")));\r
355                 geoBox.addItem(new String(tr("View On Map")));\r
356                 geoBox.activated.connect(this, "geoBoxChanged()");\r
357                 \r
358                 authorText.setVisible(false);\r
359                 createdDate.setVisible(false);\r
360                 alteredLabel.setVisible(false);\r
361                 //notebookBox.setVisible(false);\r
362                 notebookLabel.setVisible(false);\r
363                 createdLabel.setVisible(false);\r
364                 createdTime.setVisible(false);\r
365                 alteredDate.setVisible(false);\r
366                 alteredTime.setVisible(false);\r
367                 subjectLabel.setVisible(false);\r
368                 subjectDate.setVisible(false);\r
369                 subjectTime.setVisible(false);\r
370                 extendedOn = false;\r
371                 buttonsVisible = true;\r
372                 setAcceptDrops(true);\r
373 \r
374                 browser = new ContentView(this);\r
375                 browser.page().setLinkDelegationPolicy(\r
376                                 QWebPage.LinkDelegationPolicy.DelegateAllLinks);\r
377                 browser.linkClicked.connect(this, "linkClicked(QUrl)");\r
378                 currentHyperlink = "";\r
379                 \r
380                 QVBoxLayout v = new QVBoxLayout();\r
381                 QFormLayout notebookLayout = new QFormLayout();\r
382                 QGridLayout dateLayout = new QGridLayout();\r
383                 titleLabel.setReadOnly(false);\r
384                 titleLabel.editingFinished.connect(this, "titleEdited()");\r
385                 browser.page().contentsChanged.connect(this, "contentChanged()");\r
386                 browser.page().selectionChanged.connect(this, "selectionChanged()");\r
387                 browser.page().mainFrame().javaScriptWindowObjectCleared.connect(this,\r
388                                 "exposeToJavascript()");\r
389 \r
390                 notebookBox.activated.connect(this, "notebookChanged()");\r
391                 resourceSignal = new NoteResourceSignal();\r
392                 \r
393                 QHBoxLayout tagLayout = new QHBoxLayout();\r
394                 v.addWidget(titleLabel, 0);\r
395                 notebookLayout.addRow(notebookLabel, notebookBox);\r
396                 tagLayout.addLayout(notebookLayout, 0);\r
397                 tagLayout.stretch(4);\r
398                 tagLayout.addWidget(tagLabel, 0);\r
399                 tagLayout.addWidget(tagEdit, 1);\r
400                 v.addLayout(tagLayout);\r
401 \r
402                 QHBoxLayout urlLayout = new QHBoxLayout();\r
403                 urlLayout.addWidget(urlLabel, 0);\r
404                 urlLayout.addWidget(urlText, 0);\r
405                 v.addLayout(urlLayout);\r
406 \r
407                 QHBoxLayout authorLayout = new QHBoxLayout();\r
408                 authorLayout.addWidget(authorLabel, 0);\r
409                 authorLayout.addWidget(authorText, 0);\r
410                 authorLayout.addWidget(geoBox);\r
411                 v.addLayout(authorLayout);\r
412 \r
413                 dateLayout.addWidget(createdLabel, 0, 0);\r
414                 dateLayout.addWidget(createdDate, 0, 1);\r
415                 dateLayout.addWidget(createdTime, 0, 2);\r
416                 dateLayout.setColumnStretch(9, 100);\r
417                 dateLayout.addWidget(alteredLabel, 0, 3);\r
418                 dateLayout.addWidget(alteredDate, 0, 4);\r
419                 dateLayout.addWidget(alteredTime, 0, 5);\r
420                 dateLayout.addWidget(subjectLabel, 0, 6);\r
421                 dateLayout.addWidget(subjectDate, 0, 7);\r
422                 dateLayout.addWidget(subjectTime, 0, 8);\r
423                 v.addLayout(dateLayout, 0);\r
424 \r
425                 undoButton = newEditorButton("undo", tr("Undo Change"));\r
426                 redoButton = newEditorButton("redo", tr("Redo Change"));\r
427                 cutButton = newEditorButton("cut", tr("Cut"));\r
428                 copyButton = newEditorButton("copy", tr("Copy"));\r
429                 pasteButton = newEditorButton("paste", tr("Paste"));\r
430                 boldButton = newEditorButton("bold", tr("Bold"));\r
431                 underlineButton = newEditorButton("underline", tr("Underline"));\r
432                 italicButton = newEditorButton("italic", tr("Italic"));\r
433 \r
434                 rightAlignButton = newEditorButton("justifyRight", tr("Right Align"));\r
435                 leftAlignButton = newEditorButton("justifyLeft", tr("Left Align"));\r
436                 centerAlignButton = newEditorButton("justifyCenter", tr("Center Align"));\r
437 \r
438                 strikethroughButton = newEditorButton("strikethrough", tr("Strikethrough"));\r
439                 hlineButton = newEditorButton("hline", tr("Insert Horizontal Line"));\r
440                 indentButton = newEditorButton("indent", tr("Shift Right"));\r
441                 outdentButton = newEditorButton("outdent", tr("Shift Left"));\r
442                 bulletListButton = newEditorButton("bulletList", tr("Bullet List"));\r
443                 numberListButton = newEditorButton("numberList", tr("Number List"));\r
444                 spellCheckButton = newEditorButton("spellCheck", tr("Spell Check"));\r
445                 todoButton = newEditorButton("todo", tr("To-do"));\r
446 \r
447                 \r
448                 buttonLayout = new EditorButtonBar();\r
449                 v.addWidget(buttonLayout);\r
450                 \r
451                 undoAction = buttonLayout.addWidget(undoButton);\r
452                 buttonLayout.toggleUndoVisible.triggered.connect(this, "toggleUndoVisible(Boolean)");\r
453                 redoAction = buttonLayout.addWidget(redoButton);\r
454                 buttonLayout.toggleRedoVisible.triggered.connect(this, "toggleRedoVisible(Boolean)");\r
455                 \r
456                 buttonLayout.addWidget(newSeparator());\r
457                 cutAction = buttonLayout.addWidget(cutButton);\r
458                 buttonLayout.toggleCutVisible.triggered.connect(this, "toggleCutVisible(Boolean)");\r
459                 copyAction = buttonLayout.addWidget(copyButton);\r
460                 buttonLayout.toggleCopyVisible.triggered.connect(this, "toggleCopyVisible(Boolean)");\r
461                 pasteAction = buttonLayout.addWidget(pasteButton);\r
462                 buttonLayout.togglePasteVisible.triggered.connect(this, "togglePasteVisible(Boolean)");\r
463 \r
464                 buttonLayout.addWidget(newSeparator());\r
465                 boldAction = buttonLayout.addWidget(boldButton);\r
466                 buttonLayout.toggleBoldVisible.triggered.connect(this, "toggleBoldVisible(Boolean)");\r
467                 italicAction = buttonLayout.addWidget(italicButton);\r
468                 buttonLayout.toggleItalicVisible.triggered.connect(this, "toggleItalicVisible(Boolean)");\r
469                 underlineAction = buttonLayout.addWidget(underlineButton);\r
470                 buttonLayout.toggleUnderlineVisible.triggered.connect(this, "toggleUnderlineVisible(Boolean)");\r
471                 strikethroughAction = buttonLayout.addWidget(strikethroughButton);\r
472                 buttonLayout.toggleStrikethroughVisible.triggered.connect(this, "toggleStrikethroughVisible(Boolean)");\r
473 \r
474                 \r
475                 buttonLayout.addWidget(newSeparator());\r
476                 leftAlignAction = buttonLayout.addWidget(leftAlignButton);\r
477                 buttonLayout.toggleLeftAlignVisible.triggered.connect(this, "toggleLeftAlignVisible(Boolean)");\r
478                 centerAlignAction = buttonLayout.addWidget(centerAlignButton);\r
479                 buttonLayout.toggleCenterAlignVisible.triggered.connect(this, "toggleCenterAlignVisible(Boolean)");\r
480                 rightAlignAction = buttonLayout.addWidget(rightAlignButton);\r
481                 buttonLayout.toggleRightAlignVisible.triggered.connect(this, "toggleRightAlignVisible(Boolean)");\r
482 \r
483                 buttonLayout.addWidget(newSeparator());\r
484                 hlineAction = buttonLayout.addWidget(hlineButton);\r
485                 buttonLayout.toggleHLineVisible.triggered.connect(this, "toggleHLineVisible(Boolean)");\r
486 \r
487                 indentAction = buttonLayout.addWidget(indentButton);\r
488                 buttonLayout.toggleIndentVisible.triggered.connect(this, "toggleIndentVisible(Boolean)");\r
489                 outdentAction = buttonLayout.addWidget(outdentButton);\r
490                 buttonLayout.toggleOutdentVisible.triggered.connect(this, "toggleOutdentVisible(Boolean)");\r
491                 bulletListAction = buttonLayout.addWidget(bulletListButton);\r
492                 buttonLayout.toggleBulletListVisible.triggered.connect(this, "toggleBulletListVisible(Boolean)");\r
493                 numberListAction = buttonLayout.addWidget(numberListButton);\r
494                 buttonLayout.toggleNumberListVisible.triggered.connect(this, "toggleNumberListVisible(Boolean)");\r
495 \r
496                 // Setup the font & font size combo boxes\r
497                 buttonLayout.addWidget(newSeparator());\r
498                 fontList = new QComboBox();\r
499                 fontSize = new QComboBox();\r
500                 fontList.setToolTip("Font");\r
501                 fontSize.setToolTip("Font Size");\r
502                 fontList.activated.connect(this, "fontChanged(String)");\r
503                 fontSize.activated.connect(this, "fontSizeChanged(String)");\r
504                 fontListAction = buttonLayout.addWidget(fontList);\r
505                 buttonLayout.toggleFontVisible.triggered.connect(this, "toggleFontListVisible(Boolean)");\r
506                 fontSizeAction = buttonLayout.addWidget(fontSize);\r
507                 buttonLayout.toggleFontSizeVisible.triggered.connect(this, "toggleFontSizeVisible(Boolean)");\r
508                 QFontDatabase fonts = new QFontDatabase();\r
509                 List<String> fontFamilies = fonts.families();\r
510                 for (int i = 0; i < fontFamilies.size(); i++) {\r
511                         fontList.addItem(fontFamilies.get(i));\r
512                         if (i == 0) {\r
513                                 loadFontSize(fontFamilies.get(i));\r
514                         }\r
515                 }\r
516 \r
517 //              buttonLayout.addWidget(newSeparator(), 0);\r
518                 fontColor = newToolButton("fontColor", tr("Font Color"));\r
519                 fontColorMenu = new ColorMenu(this);\r
520                 fontColor.setMenu(fontColorMenu.getMenu());\r
521                 fontColor.setPopupMode(ToolButtonPopupMode.MenuButtonPopup);\r
522                 fontColor.setAutoRaise(false);\r
523                 fontColorMenu.getMenu().triggered.connect(this, "fontColorClicked()");\r
524                 fontColorAction = buttonLayout.addWidget(fontColor);\r
525                 buttonLayout.toggleFontColorVisible.triggered.connect(this, "toggleFontColorVisible(Boolean)");\r
526                 fontHilight = newToolButton("fontHilight", tr("Font Hilight Color"));\r
527                 fontHilight.setPopupMode(ToolButtonPopupMode.MenuButtonPopup);\r
528                 fontHilight.setAutoRaise(false);\r
529                 fontHilightColorMenu = new ColorMenu(this);\r
530                 fontHilightColorMenu.setDefault(QColor.yellow);\r
531                 fontHilight.setMenu(fontHilightColorMenu.getMenu());\r
532                 fontHilightColorMenu.getMenu().triggered.connect(this, "fontHilightClicked()");\r
533                 fontHilightAction = buttonLayout.addWidget(fontHilight);\r
534                 fontHilightColorMenu.setDefault(QColor.yellow);\r
535                 buttonLayout.toggleFontHilight.triggered.connect(this, "toggleFontHilightVisible(Boolean)");\r
536                 \r
537                 spellCheckAction = buttonLayout.addWidget(spellCheckButton);\r
538                 buttonLayout.toggleNumberListVisible.triggered.connect(this, "spellCheckClicked()");\r
539                 buttonLayout.toggleSpellCheck.triggered.connect(this, "toggleSpellCheckVisible(Boolean)");\r
540                 \r
541                 todoAction = buttonLayout.addWidget(todoButton);\r
542                 buttonLayout.toggleNumberListVisible.triggered.connect(this, "todoClicked()");\r
543                 buttonLayout.toggleTodo.triggered.connect(this, "toggleTodoVisible(Boolean)");\r
544 \r
545 \r
546 //              buttonLayout.addWidget(new QLabel(), 1);\r
547                 v.addWidget(browser, 1);\r
548                 setLayout(v);\r
549 \r
550                 browser.downloadAttachmentRequested.connect(this,\r
551                                 "downloadAttachment(QNetworkRequest)");\r
552                 browser.downloadImageRequested.connect(this,\r
553                                 "downloadImage(QNetworkRequest)");\r
554                 setTabOrder(notebookBox, tagEdit);\r
555                 setTabOrder(tagEdit, browser);\r
556                 \r
557                 focusNoteShortcut = new QShortcut(this);\r
558                 setupShortcut(focusNoteShortcut, "Focus_Note");\r
559                 focusNoteShortcut.activated.connect(this, "focusNote()");\r
560                 focusTitleShortcut = new QShortcut(this);\r
561                 setupShortcut(focusTitleShortcut, "Focus_Title");\r
562                 focusTitleShortcut.activated.connect(this, "focusTitle()");\r
563                 focusTagShortcut = new QShortcut(this);\r
564                 setupShortcut(focusTagShortcut, "Focus_Tag");\r
565                 focusTagShortcut.activated.connect(this, "focusTag()");\r
566                 focusAuthorShortcut = new QShortcut(this);\r
567                 setupShortcut(focusAuthorShortcut, "Focus_Author");\r
568                 focusAuthorShortcut.activated.connect(this, "focusAuthor()");\r
569                 focusUrlShortcut = new QShortcut(this);\r
570                 setupShortcut(focusUrlShortcut, "Focus_Url");\r
571                 focusUrlShortcut.activated.connect(this, "focusUrl()");\r
572                 \r
573                 browser.page().mainFrame().setTextSizeMultiplier(Global.getTextSizeMultiplier());\r
574                 browser.page().mainFrame().setZoomFactor(Global.getZoomFactor());\r
575                 \r
576                 previewPageList = new HashMap<String,Integer>();\r
577                 \r
578                 browser.page().microFocusChanged.connect(this, "microFocusChanged()");\r
579                 \r
580                 //Setup colors\r
581                 \r
582                 QPalette pal = new QPalette();\r
583                 pal.setColor(ColorRole.Text, QColor.black);\r
584                 titleLabel.setPalette(pal);\r
585                 authorText.setPalette(pal);\r
586                 authorLabel.setPalette(pal);\r
587                 urlLabel.setPalette(pal);\r
588                 urlText.setPalette(pal);\r
589                 createdDate.setPalette(pal);\r
590                 createdTime.setPalette(pal);\r
591                 alteredDate.setPalette(pal);\r
592                 alteredTime.setPalette(pal);\r
593                 subjectDate.setPalette(pal);\r
594                 subjectTime.setPalette(pal);\r
595                 tagEdit.setPalette(pal);\r
596                 notebookBox.setPalette(pal);\r
597                 \r
598                 logger.log(logger.HIGH, "Browser setup complete");\r
599         }\r
600 \r
601         \r
602         \r
603         private void setupShortcut(QShortcut action, String text) {\r
604                 if (!Global.shortcutKeys.containsAction(text))\r
605                         return;\r
606                 action.setKey(new QKeySequence(Global.shortcutKeys.getShortcut(text)));\r
607         }\r
608         \r
609         \r
610 \r
611         \r
612         // Getter for the QWebView\r
613         public QWebView getBrowser() {\r
614                 return browser;\r
615         }\r
616 \r
617         // Block signals while loading data or things are flagged as dirty by\r
618         // mistake\r
619         public void loadingData(boolean val) {\r
620                 logger.log(logger.EXTREME, "Entering BrowserWindow.loadingData() " +val);\r
621                 notebookBox.blockSignals(val);\r
622                 browser.page().blockSignals(val);\r
623                 browser.page().mainFrame().blockSignals(val);\r
624                 titleLabel.blockSignals(val);\r
625                 alteredDate.blockSignals(val);\r
626                 alteredTime.blockSignals(val);\r
627                 createdTime.blockSignals(val);\r
628                 createdDate.blockSignals(val);\r
629                 subjectDate.blockSignals(val);\r
630                 subjectTime.blockSignals(val);\r
631                 urlText.blockSignals(val);\r
632                 authorText.blockSignals(val);\r
633                 if (!val)\r
634                         exposeToJavascript();\r
635                 logger.log(logger.EXTREME, "Exiting BrowserWindow.loadingData() " +val);\r
636         }\r
637 \r
638         // Enable/disable\r
639         public void setReadOnly(boolean v) {\r
640                 setEnabled(true);\r
641                 titleLabel.setEnabled(!v);\r
642                 notebookBox.setEnabled(!v);\r
643                 tagEdit.setEnabled(!v);\r
644                 authorLabel.setEnabled(!v);\r
645                 geoBox.setEnabled(!v);\r
646                 urlText.setEnabled(!v);\r
647                 createdDate.setEnabled(!v);\r
648                 subjectDate.setEnabled(!v);\r
649                 alteredDate.setEnabled(!v);\r
650                 authorText.setEnabled(!v);\r
651                 createdTime.setEnabled(!v);\r
652                 alteredTime.setEnabled(!v);\r
653                 subjectTime.setEnabled(!v);\r
654                 getBrowser().setEnabled(true);\r
655         }\r
656         \r
657         // expose this class to Javascript on the web page\r
658         private void exposeToJavascript() {\r
659                 browser.page().mainFrame().addToJavaScriptWindowObject("jambi", this);\r
660         }\r
661 \r
662         // Custom event queue\r
663         @Override\r
664         public boolean event(QEvent e) {\r
665                 if (e.type().equals(QEvent.Type.FocusOut)) {\r
666                         logger.log(logger.EXTREME, "Focus lost");\r
667                         focusLost.emit();\r
668                 }\r
669                 return super.event(e);\r
670         }\r
671 \r
672         // clear out browser\r
673         public void clear() {\r
674                 logger.log(logger.EXTREME, "Entering BrowserWindow.clear()");\r
675                 setNote(null);\r
676                 browser.setContent(new QByteArray());\r
677                 tagEdit.setText("");\r
678                 tagEdit.tagCompleter.reset();\r
679                 urlLabel.setText(tr("Source URL:"));\r
680                 titleLabel.setText("");\r
681                 logger.log(logger.EXTREME, "Exiting BrowserWindow.clear()");\r
682         }\r
683 \r
684         // get/set current note\r
685         public void setNote(Note n) {\r
686                 currentNote = n;\r
687                 if (n == null)\r
688                         n = new Note();\r
689                 saveNoteTitle = n.getTitle();\r
690 \r
691         }\r
692 \r
693         public Note getNote() {\r
694                 return currentNote;\r
695         }\r
696 \r
697         // New Editor Button\r
698         private QPushButton newEditorButton(String name, String toolTip) {\r
699                 QPushButton button = new QPushButton();\r
700 //              QIcon icon = new QIcon(iconPath + name + ".gif");\r
701                 QIcon icon = new QIcon(iconPath + name + ".png");\r
702                 button.setIcon(icon);\r
703                 button.setToolTip(toolTip);\r
704                 button.clicked.connect(this, name + "Clicked()");\r
705                 return button;\r
706         }\r
707         // New Editor Button\r
708         private QToolButton newToolButton(String name, String toolTip) {\r
709                 QToolButton button = new QToolButton();\r
710 //              QIcon icon = new QIcon(iconPath + name + ".gif");\r
711                 QIcon icon = new QIcon(iconPath + name + ".png");\r
712                 button.setIcon(icon);\r
713                 button.setToolTip(toolTip);\r
714                 button.clicked.connect(this, name + "Clicked()");\r
715                 return button;\r
716         }\r
717 \r
718         // New Separator\r
719         private QLabel newSeparator() {\r
720                 return new QLabel("   ");\r
721         }\r
722 \r
723         // Set the title in the window\r
724         public void setTitle(String t) {\r
725                 titleLabel.setText(t);\r
726                 saveNoteTitle = t;\r
727                 checkNoteTitle();\r
728         }\r
729 \r
730         // Return the current text title\r
731         public String getTitle() {\r
732                 return titleLabel.text();\r
733         }\r
734 \r
735         // Set the tag name string\r
736         public void setTag(String t) {\r
737                 saveTagList = t;\r
738                 tagEdit.setText(t);\r
739                 tagEdit.tagCompleter.reset();\r
740         }\r
741 \r
742         // Set the source URL\r
743         public void setUrl(String t) {\r
744                 urlLabel.setText(tr("Source URL:\t"));\r
745                 urlText.setText(t);\r
746         }\r
747 \r
748         // The user want's to launch a web browser on the source of the URL\r
749         public void sourceUrlClicked() {\r
750                 // Make sure we have a valid URL\r
751                 if (urlText.text().trim().equals(""))\r
752                         return;\r
753                 \r
754                 String url = urlText.text();\r
755                 if (!url.toLowerCase().startsWith(tr("http://")))\r
756                         url = tr("http://") +url;\r
757                 \r
758         if (!QDesktopServices.openUrl(new QUrl(url))) {\r
759                 logger.log(logger.LOW, "Error opening file :" +url);\r
760         }\r
761         }\r
762         \r
763         public void setAuthor(String t) {\r
764                 authorLabel.setText(tr("Author:\t"));\r
765                 authorText.setText(t);\r
766         }\r
767 \r
768         // Set the creation date\r
769         public void setCreation(long date) {\r
770                 QDateTime dt = new QDateTime();\r
771                 dt.setTime_t((int) (date / 1000));\r
772                 createdDate.setDateTime(dt);\r
773                 createdTime.setDateTime(dt);\r
774                 createdDate.setDisplayFormat(Global.getDateFormat());\r
775                 createdTime.setDisplayFormat(Global.getTimeFormat());\r
776         }\r
777 \r
778         // Set the creation date\r
779         public void setAltered(long date) {\r
780                 QDateTime dt = new QDateTime();\r
781                 dt.setTime_t((int) (date / 1000));\r
782                 alteredDate.setDateTime(dt);\r
783                 alteredTime.setDateTime(dt);\r
784                 alteredDate.setDisplayFormat(Global.getDateFormat());\r
785                 alteredTime.setDisplayFormat(Global.getTimeFormat());\r
786         }\r
787 \r
788         // Set the subject date\r
789         public void setSubjectDate(long date) {\r
790                 QDateTime dt = new QDateTime();\r
791                 dt.setTime_t((int) (date / 1000));\r
792                 subjectDate.setDateTime(dt);\r
793                 subjectTime.setDateTime(dt);\r
794                 subjectDate.setDisplayFormat(Global.getDateFormat());\r
795                 subjectTime.setDisplayFormat(Global.getTimeFormat());\r
796         }\r
797 \r
798         // Toggle the extended attribute information\r
799         public void toggleInformation() {\r
800                 if (extendedOn) {\r
801                         extendedOn = false;\r
802                 } else {\r
803                         extendedOn = true;\r
804                 }\r
805                 urlLabel.setVisible(extendedOn);\r
806                 urlText.setVisible(extendedOn);\r
807                 authorText.setVisible(extendedOn);\r
808                 geoBox.setVisible(extendedOn);\r
809                 authorLabel.setVisible(extendedOn);\r
810                 createdDate.setVisible(extendedOn);\r
811                 createdTime.setVisible(extendedOn);\r
812                 createdLabel.setVisible(extendedOn);\r
813                 alteredLabel.setVisible(extendedOn);\r
814                 alteredDate.setVisible(extendedOn);\r
815                 alteredTime.setVisible(extendedOn);\r
816                 //notebookBox.setVisible(extendedOn);\r
817                 notebookLabel.setVisible(extendedOn);\r
818                 subjectLabel.setVisible(extendedOn);\r
819                 subjectDate.setVisible(extendedOn);\r
820                 subjectTime.setVisible(extendedOn);\r
821         }\r
822 \r
823         public void hideButtons() {\r
824 \r
825                 undoButton.parentWidget().setVisible(false);\r
826                 buttonsVisible = false;\r
827         }\r
828 \r
829 \r
830         // Is the extended view on?\r
831         public boolean isExtended() {\r
832                 return extendedOn;\r
833         }\r
834 \r
835         // Listener for when a link is clicked\r
836         @SuppressWarnings("unused")\r
837         private void openFile() {\r
838                 logger.log(logger.EXTREME, "Starting openFile()");\r
839                 File fileHandle = new File(selectedFile);\r
840                 URI fileURL = fileHandle.toURI();\r
841                 String localURL = fileURL.toString();\r
842                 QUrl url = new QUrl(localURL);\r
843                 QFile file = new QFile(selectedFile);\r
844                 \r
845                 logger.log(logger.EXTREME, "Adding to fileWatcher:"+file.fileName());\r
846                 fileWatcher.addPath(file.fileName());\r
847         \r
848         if (!QDesktopServices.openUrl(url)) {\r
849                 logger.log(logger.LOW, "Error opening file :" +url);\r
850         }\r
851         }\r
852         \r
853         \r
854         // Listener for when a link is clicked\r
855         @SuppressWarnings("unused")\r
856         private void linkClicked(QUrl url) {\r
857                 logger.log(logger.EXTREME, "URL Clicked: " +url.toString());\r
858                 if (url.toString().substring(0,8).equals("nnres://")) {\r
859                         logger.log(logger.EXTREME, "URL is NN resource");\r
860                         if (url.toString().endsWith("/vnd.evernote.ink")) {\r
861                                 logger.log(logger.EXTREME, "Unable to open ink note");\r
862                                 QMessageBox.information(this, tr("Unable Open"), tr("This is an ink note.\n"+\r
863                                         "Ink notes are not supported since Evernote has not\n published any specifications on them\n" +\r
864                                         "and I'm too lazy to figure them out by myself."));\r
865                                 return;\r
866                         }\r
867                         String fullName = url.toString().substring(8);\r
868                         int index = fullName.indexOf(".");\r
869                         String guid = "";\r
870                         String type = "";\r
871                         if (index >-1) {\r
872                                 type = fullName.substring(index+1);\r
873                                 guid = fullName.substring(0,index);\r
874                         }\r
875                         index = guid.indexOf(Global.attachmentNameDelimeter);\r
876                         if (index > -1) {\r
877                                 guid = guid.substring(0,index);\r
878                         }\r
879                         List<Resource> resList = currentNote.getResources();\r
880                         Resource res = null;\r
881                         for (int i=0; i<resList.size(); i++) {\r
882                                 if (resList.get(i).getGuid().equals(guid)) {\r
883                                         res = resList.get(i);\r
884                                         i=resList.size();\r
885                                 }\r
886                         }\r
887                         if (res == null) {\r
888                                 String resGuid = Global.resourceMap.get(guid);\r
889                                 if (resGuid != null) \r
890                                         res = conn.getNoteTable().noteResourceTable.getNoteResource(resGuid, true);\r
891                         }\r
892                         if (res != null) {\r
893                                 String fileName;\r
894                                 if (res.getAttributes() != null && \r
895                                                 res.getAttributes().getFileName() != null && \r
896                                                 !res.getAttributes().getFileName().trim().equals(""))\r
897                                         fileName = res.getGuid()+Global.attachmentNameDelimeter+res.getAttributes().getFileName();\r
898                                 else\r
899                                         fileName = res.getGuid()+"."+type;\r
900                                 QFile file = new QFile(Global.getFileManager().getResDirPath(fileName));\r
901                         QFile.OpenMode mode = new QFile.OpenMode();\r
902                         mode.set(QFile.OpenModeFlag.WriteOnly);\r
903                         boolean openResult = file.open(mode);\r
904                                 logger.log(logger.EXTREME, "File opened:" +openResult);\r
905                         QDataStream out = new QDataStream(file);\r
906                         Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(res.getGuid(), true);\r
907                                 QByteArray binData = new QByteArray(resBinary.getData().getBody());\r
908                                 resBinary = null;\r
909                                 logger.log(logger.EXTREME, "Writing resource");\r
910                         out.writeBytes(binData.toByteArray());\r
911                         file.close();\r
912                                 \r
913                         String whichOS = System.getProperty("os.name");\r
914                                 if (whichOS.contains("Windows")) \r
915                                 url.setUrl("file:///"+file.fileName());\r
916                         else\r
917                                 url.setUrl("file://"+file.fileName());\r
918                  //       fileWatcher.removePath(file.fileName());\r
919                                 logger.log(logger.EXTREME, "Adding file watcher " +file.fileName());\r
920                                 fileWatcher.addPath(file.fileName());\r
921                         \r
922                         // If we can't open it, then prompt the user to save it.\r
923                         if (!QDesktopServices.openUrl(url)) {\r
924                                         logger.log(logger.EXTREME, "We can't handle this.  Where do we put it?");\r
925                                 QFileDialog dialog = new QFileDialog();\r
926                                 dialog.show();\r
927                                 if (dialog.exec()!=0) {\r
928                                         List<String> fileNames = dialog.selectedFiles(); //gets all selected filenames\r
929                                         if (fileNames.size() == 0) \r
930                                                 return;\r
931                                         String sf = fileNames.get(0);\r
932                                         QFile saveFile = new QFile(sf);\r
933                                         mode.set(QFile.OpenModeFlag.WriteOnly);\r
934                                         saveFile.open(mode);\r
935                                         QDataStream saveOut = new QDataStream(saveFile);\r
936                                         saveOut.writeBytes(binData.toByteArray());\r
937                                         saveFile.close();\r
938                                         return;\r
939                                 }\r
940                                 }\r
941                         }\r
942                         return;\r
943                 }\r
944                 logger.log(logger.EXTREME, "Launching URL");\r
945                 QDesktopServices.openUrl(url);\r
946         }\r
947 \r
948         // Listener for when BOLD is clicked\r
949         @SuppressWarnings("unused")\r
950         private void undoClicked() {\r
951                 browser.page().triggerAction(WebAction.Undo);\r
952                 browser.setFocus();\r
953         }\r
954 \r
955         // Listener for when BOLD is clicked\r
956         @SuppressWarnings("unused")\r
957         private void redoClicked() {\r
958                 browser.page().triggerAction(WebAction.Redo);\r
959                 browser.setFocus();\r
960         }\r
961 \r
962         // Listener for when BOLD is clicked\r
963         @SuppressWarnings("unused")\r
964         private void boldClicked() {\r
965                 browser.page().triggerAction(WebAction.ToggleBold);\r
966                 microFocusChanged();\r
967                 browser.setFocus();\r
968         }\r
969 \r
970         // Listener for when Italics is clicked\r
971         @SuppressWarnings("unused")\r
972         private void italicClicked() {\r
973                 browser.page().triggerAction(WebAction.ToggleItalic);\r
974                 microFocusChanged();\r
975                 browser.setFocus();\r
976         }\r
977 \r
978         // Listener for when UNDERLINE is clicked\r
979         @SuppressWarnings("unused")\r
980         private void underlineClicked() {\r
981                 browser.page().triggerAction(WebAction.ToggleUnderline);\r
982                 microFocusChanged();\r
983                 browser.setFocus();\r
984         }\r
985 \r
986         // Listener for when Strikethrough is clicked\r
987         @SuppressWarnings("unused")\r
988         private void strikethroughClicked() {\r
989                 browser.page().mainFrame().evaluateJavaScript(\r
990                                 "document.execCommand('strikeThrough', false, '');");\r
991                 browser.setFocus();\r
992         }\r
993 \r
994         // Listener for when cut is clicked\r
995         @SuppressWarnings("unused")\r
996         private void cutClicked() {\r
997                 browser.page().triggerAction(WebAction.Cut);\r
998                 browser.setFocus();\r
999         }\r
1000 \r
1001         // Listener when COPY is clicked\r
1002         @SuppressWarnings("unused")\r
1003         private void copyClicked() {\r
1004                 browser.page().triggerAction(WebAction.Copy);\r
1005                 browser.setFocus();\r
1006         }\r
1007 \r
1008         // Listener when PASTE is clicked\r
1009         public void pasteClicked() {\r
1010                 logger.log(logger.EXTREME, "Paste Clicked");\r
1011                 if (forceTextPaste) {\r
1012                         pasteWithoutFormattingClicked();\r
1013                         return;\r
1014                 }\r
1015                 QClipboard clipboard = QApplication.clipboard();\r
1016                 QMimeData mime = clipboard.mimeData();\r
1017                 \r
1018 //               String x = mime.html();\r
1019 \r
1020                 if (mime.hasImage()) {\r
1021                         logger.log(logger.EXTREME, "Image paste found");\r
1022                         browser.setFocus();\r
1023                         insertImage(mime);\r
1024                         browser.setFocus();\r
1025                         return;\r
1026                 }\r
1027 \r
1028                 if (mime.hasUrls()) {\r
1029                         logger.log(logger.EXTREME, "URL paste found");\r
1030                         handleUrls(mime);\r
1031                         browser.setFocus();\r
1032                         return;\r
1033                 }\r
1034                 \r
1035                 String text = mime.html();\r
1036                 if (text.contains("en-tag") && mime.hasHtml()) {\r
1037                         logger.log(logger.EXTREME, "Intra-note paste found");\r
1038                         text = fixInternotePaste(text);\r
1039                         mime.setHtml(text);\r
1040                         clipboard.setMimeData(mime);\r
1041                 }\r
1042 \r
1043                 logger.log(logger.EXTREME, "Final paste choice encountered");\r
1044                 browser.page().triggerAction(WebAction.Paste);\r
1045                 browser.setFocus();\r
1046 \r
1047         }\r
1048 \r
1049         // Paste text without formatting\r
1050         private void pasteWithoutFormattingClicked() {\r
1051                 logger.log(logger.EXTREME, "Paste without format clipped");\r
1052                 QClipboard clipboard = QApplication.clipboard();\r
1053                 QMimeData mime = clipboard.mimeData();\r
1054                 if (!mime.hasText())\r
1055                         return;\r
1056                 String text = mime.text();\r
1057                 clipboard.clear();\r
1058                 clipboard.setText(text, Mode.Clipboard);\r
1059                 browser.page().triggerAction(WebAction.Paste);\r
1060 \r
1061                 // This is done because pasting into an encryption block\r
1062                 // can cause multiple cells (which can't happen).  It \r
1063                 // just goes through the table, extracts the data, & \r
1064                 // puts it back as one table cell.\r
1065                 if (insideEncryption) {\r
1066                         String js = new String( "function fixEncryption() { "\r
1067                                         +"   var selObj = window.getSelection();"\r
1068                                         +"   var selRange = selObj.getRangeAt(0);"\r
1069                                         +"   var workingNode = window.getSelection().anchorNode;"\r
1070                                         +"   while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { " \r
1071                                         +"           workingNode = workingNode.parentNode;"\r
1072                                         +"   } "\r
1073                                         +"   workingNode.innerHTML = window.jambi.fixEncryptionPaste(workingNode.innerHTML);"\r
1074                                         +"} fixEncryption();");\r
1075                         browser.page().mainFrame().evaluateJavaScript(js);\r
1076                 }\r
1077         }\r
1078         \r
1079         // This basically removes all the table tags and returns just the contents.\r
1080         // This is called by JavaScript to fix encryption pastes.\r
1081         public String fixEncryptionPaste(String data) {\r
1082                 data = data.replace("<tbody>", "");\r
1083                 data = data.replace("</tbody>", "");\r
1084                 data = data.replace("<tr>", "");\r
1085                 data = data.replace("</tr>", "");\r
1086                 data = data.replace("<td>", "");\r
1087                 data = data.replace("</td>", "<br>");\r
1088                 data = data.replace("<br><br>", "<br>");\r
1089 \r
1090                 return "<tbody><tr><td>"+data+"</td></tr></tbody>";\r
1091         }\r
1092         \r
1093         // insert date/time\r
1094         @SuppressWarnings("unused")\r
1095         private void insertDateTime() {\r
1096                 String fmt = Global.getDateFormat() + " " + Global.getTimeFormat();\r
1097                 String dateTimeFormat = new String(fmt);\r
1098                 SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);\r
1099                 Calendar cal = Calendar.getInstance();\r
1100                 \r
1101                 browser.page().mainFrame().evaluateJavaScript(\r
1102                         "document.execCommand('insertHtml', false, '"+simple.format(cal.getTime())+"');");\r
1103                 \r
1104                 browser.setFocus();\r
1105 \r
1106         }\r
1107 \r
1108         // Listener when Left is clicked\r
1109         @SuppressWarnings("unused")\r
1110         private void justifyLeftClicked() {\r
1111                 browser.page().mainFrame().evaluateJavaScript(\r
1112                                 "document.execCommand('JustifyLeft', false, '');");\r
1113                 browser.setFocus();\r
1114         }\r
1115 \r
1116         // Listener when Center is clicked\r
1117         @SuppressWarnings("unused")\r
1118         private void justifyCenterClicked() {\r
1119                 browser.page().mainFrame().evaluateJavaScript(\r
1120                                 "document.execCommand('JustifyCenter', false, '');");\r
1121                 browser.setFocus();\r
1122         }\r
1123 \r
1124         // Listener when Left is clicked\r
1125         @SuppressWarnings("unused")\r
1126         private void justifyRightClicked() {\r
1127                 browser.page().mainFrame().evaluateJavaScript(\r
1128                                 "document.execCommand('JustifyRight', false, '');");\r
1129                 browser.setFocus();\r
1130         }\r
1131 \r
1132         // Listener when HLINE is clicked\r
1133         @SuppressWarnings("unused")\r
1134         private void hlineClicked() {\r
1135                 browser.page().mainFrame().evaluateJavaScript(\r
1136                                 "document.execCommand('insertHorizontalRule', false, '');");\r
1137                 browser.setFocus();\r
1138         }\r
1139 \r
1140         // Listener when outdent is clicked\r
1141         private void outdentClicked() {\r
1142                 browser.page().mainFrame().evaluateJavaScript(\r
1143                                 "document.execCommand('outdent', false, '');");\r
1144                 browser.setFocus();\r
1145         }\r
1146 \r
1147         // Listener when a bullet list is clicked\r
1148         @SuppressWarnings("unused")\r
1149         private void bulletListClicked() {\r
1150                 browser.page().mainFrame().evaluateJavaScript(\r
1151                                 "document.execCommand('InsertUnorderedList', false, '');");\r
1152                 browser.setFocus();\r
1153         }\r
1154 \r
1155         // Listener when a bullet list is clicked\r
1156         @SuppressWarnings("unused")\r
1157         private void numberListClicked() {\r
1158                 browser.page().mainFrame().evaluateJavaScript(\r
1159                                 "document.execCommand('InsertOrderedList', false, '');");\r
1160                 browser.setFocus();\r
1161         }\r
1162 \r
1163         // Listener when indent is clicked\r
1164         private void indentClicked() {\r
1165                 browser.page().mainFrame().evaluateJavaScript(\r
1166                                 "document.execCommand('indent', false, '');");\r
1167                 browser.setFocus();\r
1168         }\r
1169 \r
1170         // Listener when the font name is changed\r
1171         @SuppressWarnings("unused")\r
1172         private void fontChanged(String font) {\r
1173                 browser.page().mainFrame().evaluateJavaScript(\r
1174                                 "document.execCommand('fontName',false,'" + font + "');");\r
1175                 browser.setFocus();\r
1176         }\r
1177 \r
1178         // Listener when a font size is changed\r
1179         @SuppressWarnings("unused")\r
1180         private void fontSizeChanged(String font) {\r
1181                 String text = browser.selectedText();\r
1182                 if (text.trim().equalsIgnoreCase(""))\r
1183                         return;\r
1184 \r
1185                 String selectedText = browser.selectedText();\r
1186                 String url = "<span style=\"font-size:" +font +"pt; \">"+selectedText +"</a>";\r
1187                 String script = "document.execCommand('insertHtml', false, '"+url+"');";\r
1188                 browser.page().mainFrame().evaluateJavaScript(script);\r
1189 /*              browser.page().mainFrame().evaluateJavaScript(\r
1190                                 "document.execCommand('fontSize',false,'"\r
1191                                                 + font + "');");\r
1192 */\r
1193                 browser.setFocus();\r
1194         }\r
1195 \r
1196         // Load the font combo box based upon the font selected\r
1197         private void loadFontSize(String name) {        \r
1198                 QFontDatabase db = new QFontDatabase(); \r
1199                 fontSize.clear();\r
1200                 List<Integer> points = db.pointSizes(name); \r
1201                 for (int i=0; i<points.size(); i++) { \r
1202                         fontSize.addItem(points.get(i).toString()); \r
1203                 }\r
1204                 /*\r
1205                 fontSize.addItem("x-small");\r
1206                 fontSize.addItem("small");\r
1207                 fontSize.addItem("medium");\r
1208                 fontSize.addItem("large");\r
1209                 fontSize.addItem("x-large");\r
1210                 fontSize.addItem("xx-large");\r
1211                 fontSize.addItem("xxx-large");\r
1212                 */\r
1213         }\r
1214 \r
1215         // Listener when a font size is changed\r
1216         @SuppressWarnings("unused")\r
1217         private void fontColorClicked() {\r
1218 //              QColorDialog dialog = new QColorDialog();\r
1219 //              QColor color = QColorDialog.getColor();\r
1220                 QColor color = fontColorMenu.getColor();\r
1221                 if (color.isValid())\r
1222                         browser.page().mainFrame().evaluateJavaScript(\r
1223                                         "document.execCommand('foreColor',false,'" + color.name()\r
1224                                                         + "');");\r
1225                 browser.setFocus();\r
1226         }\r
1227 \r
1228         // Listener for when a background color change is requested\r
1229         @SuppressWarnings("unused")\r
1230         private void fontHilightClicked() {\r
1231 //              QColorDialog dialog = new QColorDialog();\r
1232 //              QColor color = QColorDialog.getColor();\r
1233                 QColor color = fontHilightColorMenu.getColor();\r
1234                 if (color.isValid())\r
1235                         browser.page().mainFrame().evaluateJavaScript(\r
1236                                         "document.execCommand('backColor',false,'" + color.name()\r
1237                                                         + "');");\r
1238                 browser.setFocus();\r
1239         }\r
1240         \r
1241         // Listener for when a background color change is requested\r
1242         @SuppressWarnings("unused")\r
1243         private void superscriptClicked() {\r
1244                 browser.page().mainFrame().evaluateJavaScript(\r
1245                                         "document.execCommand('superscript');");\r
1246                 browser.setFocus();\r
1247         }\r
1248         \r
1249         // Listener for when a background color change is requested\r
1250         @SuppressWarnings("unused")\r
1251         private void subscriptClicked() {\r
1252                 browser.page().mainFrame().evaluateJavaScript(\r
1253                                         "document.execCommand('subscript');");\r
1254                 browser.setFocus();\r
1255         }\r
1256         // Insert a to-do checkbox\r
1257         @SuppressWarnings("unused")\r
1258         private void todoClicked() {\r
1259                 FileNameMap fileNameMap = URLConnection.getFileNameMap();\r
1260                 String script_start = new String(\r
1261                                 "document.execCommand('insertHtml', false, '");\r
1262                 String script_end = new String("');");\r
1263                 String todo = new String(\r
1264                                 "<input TYPE=\"CHECKBOX\" value=\"false\" " +\r
1265                                 "onMouseOver=\"style.cursor=\\'hand\\'\" " +\r
1266                                 "onClick=\"value=checked; window.jambi.contentChanged(); \" />");\r
1267                 browser.page().mainFrame().evaluateJavaScript(\r
1268                                 script_start + todo + script_end);\r
1269                 browser.setFocus();\r
1270         }\r
1271 \r
1272         // Encrypt the selected text\r
1273         @SuppressWarnings("unused")\r
1274         private void encryptText() {\r
1275                 String text = browser.selectedText();\r
1276                 if (text.trim().equalsIgnoreCase(""))\r
1277                         return;\r
1278                 text = new String(text.replaceAll("\n", "<br/>"));\r
1279 \r
1280                 EnCryptDialog dialog = new EnCryptDialog();\r
1281                 dialog.exec();\r
1282                 if (!dialog.okPressed()) {\r
1283                         return;\r
1284                 }\r
1285 \r
1286                 EnCrypt crypt = new EnCrypt();\r
1287                 String encrypted = crypt.encrypt(text, dialog.getPassword().trim(), 64);\r
1288                 String decrypted = crypt.decrypt(encrypted, dialog.getPassword().trim(), 64);\r
1289 \r
1290                 if (encrypted.trim().equals("")) {\r
1291                         QMessageBox.information(this, tr("Error"), tr("Error Encrypting String"));\r
1292                         return;\r
1293                 }\r
1294                 StringBuffer buffer = new StringBuffer(encrypted.length() + 100);\r
1295                 buffer.append("<img en-tag=\"en-crypt\" cipher=\"RC2\" hint=\""\r
1296                                 + dialog.getHint().replace("'","\\'") + "\" length=\"64\" ");\r
1297                 buffer.append("contentEditable=\"false\" alt=\"");\r
1298                 buffer.append(encrypted);\r
1299                 buffer.append("\" src=\"").append(FileUtils.toForwardSlashedPath(Global.getFileManager().getImageDirPath("encrypt.png") +"\""));\r
1300                 Global.cryptCounter++;\r
1301                 buffer.append(" id=\"crypt"+Global.cryptCounter.toString() +"\"");\r
1302                 buffer.append(" onMouseOver=\"style.cursor=\\'hand\\'\"");\r
1303                 buffer.append(" onClick=\"window.jambi.decryptText(\\'crypt"+Global.cryptCounter.toString() \r
1304                                 +"\\', \\'"+encrypted+"\\', \\'"+dialog.getHint().replace("'", "\\&amp;apos;")+"\\');\"");\r
1305                 buffer.append("style=\"display:block\" />");\r
1306 \r
1307                 String script_start = new String(\r
1308                                 "document.execCommand('insertHtml', false, '");\r
1309                 String script_end = new String("');");\r
1310                 browser.page().mainFrame().evaluateJavaScript(\r
1311                                 script_start + buffer.toString() + script_end);\r
1312         }\r
1313 \r
1314         \r
1315         // Insert a hyperlink\r
1316         public void insertLink() {\r
1317                 logger.log(logger.EXTREME, "Inserting link");\r
1318                 String text = browser.selectedText();\r
1319                 if (text.trim().equalsIgnoreCase(""))\r
1320                         return;\r
1321 \r
1322                 InsertLinkDialog dialog = new InsertLinkDialog(insertHyperlink);\r
1323                 if (currentHyperlink != null && currentHyperlink != "") {\r
1324                         dialog.setUrl(currentHyperlink);\r
1325                 }\r
1326                 dialog.exec();\r
1327                 if (!dialog.okPressed()) {\r
1328                         logger.log(logger.EXTREME, "Insert link canceled");\r
1329                         return;\r
1330                 }\r
1331                 \r
1332                 // Take care of inserting new links\r
1333                 if (insertHyperlink) {\r
1334                         String selectedText = browser.selectedText();\r
1335                         if (dialog.getUrl().trim().equals(""))\r
1336                                 return;\r
1337                         logger.log(logger.EXTREME, "Inserting link on text "+selectedText);\r
1338                         logger.log(logger.EXTREME, "URL Link " +dialog.getUrl().trim());\r
1339                         String dUrl = StringUtils.replace(dialog.getUrl().trim(), "'", "\\'");\r
1340                         String url = "<a href=\"" +dUrl\r
1341                                         +"\" title=" +dUrl \r
1342                                         +" >"+selectedText +"</a>";\r
1343                         String script = "document.execCommand('insertHtml', false, '"+url+"');";\r
1344                         browser.page().mainFrame().evaluateJavaScript(script);\r
1345                         return;\r
1346                 }\r
1347                 \r
1348                 // Edit existing links\r
1349                 String js = new String( "function getCursorPos() {"\r
1350                                 +"var cursorPos;"\r
1351                                 +"if (window.getSelection) {"\r
1352                                 +"   var selObj = window.getSelection();"\r
1353                                 +"   var selRange = selObj.getRangeAt(0);"\r
1354                                 +"   var workingNode = window.getSelection().anchorNode.parentNode;"\r
1355                                 +"   while(workingNode != null) { " \r
1356                                 +"      if (workingNode.nodeName.toLowerCase()=='a') workingNode.setAttribute('href','" +dialog.getUrl() +"');"\r
1357                                 +"      workingNode = workingNode.parentNode;"\r
1358                                 +"   }"\r
1359                                 +"}"\r
1360                                 +"} getCursorPos();");\r
1361                         browser.page().mainFrame().evaluateJavaScript(js);\r
1362                 \r
1363                 if (!dialog.getUrl().trim().equals("")) {\r
1364                         contentChanged();\r
1365                         return;\r
1366                 }\r
1367                 \r
1368                 // Remove URL\r
1369                 js = new String( "function getCursorPos() {"\r
1370                                 +"var cursorPos;"\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') { "\r
1377                                 +"         workingNode.removeAttribute('href');"\r
1378                                 +"         workingNode.removeAttribute('title');"\r
1379                                 +"         var text = document.createTextNode(workingNode.innerText);"\r
1380                                 +"         workingNode.parentNode.insertBefore(text, workingNode);"\r
1381                                 +"         workingNode.parentNode.removeChild(workingNode);"\r
1382                                 +"      }"\r
1383                                 +"      workingNode = workingNode.parentNode;"\r
1384                                 +"   }"\r
1385                                 +"}"\r
1386                                 +"} getCursorPos();");\r
1387                         browser.page().mainFrame().evaluateJavaScript(js);\r
1388                         \r
1389                         contentChanged();\r
1390 \r
1391                 \r
1392         }\r
1393         \r
1394         \r
1395         // Insert a table\r
1396         public void insertTable() {\r
1397                 TableDialog dialog = new TableDialog();\r
1398                 dialog.exec();\r
1399                 if (!dialog.okPressed()) {\r
1400                         return;\r
1401                 }\r
1402                 \r
1403                 int cols = dialog.getCols();\r
1404                 int rows = dialog.getRows();\r
1405                 int width = dialog.getWidth();\r
1406                 boolean percent = dialog.isPercent();\r
1407                 \r
1408                 String newHTML = "<table border=\"1\" width=\"" +new Integer(width).toString();\r
1409                 if (percent)\r
1410                         newHTML = newHTML +"%";\r
1411                 newHTML = newHTML + "\"><tbody>";\r
1412 \r
1413                 for (int i=0; i<rows; i++) {\r
1414                         newHTML = newHTML +"<tr>";\r
1415                         for (int j=0; j<cols; j++) {\r
1416                                 newHTML = newHTML +"<td>&nbsp;</td>";\r
1417                         }\r
1418                         newHTML = newHTML +"</tr>";\r
1419                 }\r
1420                 newHTML = newHTML+"</tbody></table>";   \r
1421         \r
1422                 String script = "document.execCommand('insertHtml', false, '"+newHTML+"');";\r
1423                 browser.page().mainFrame().evaluateJavaScript(script);\r
1424         }\r
1425         \r
1426         \r
1427         // Text content changed\r
1428         @SuppressWarnings("unused")\r
1429         private void selectionChanged() {\r
1430                 browser.encryptAction.setEnabled(true);\r
1431                 browser.insertLinkAction.setEnabled(true);\r
1432                 String scriptStart = "var selection_text = (window.getSelection()).toString();"\r
1433                                 + "var range = (window.getSelection()).getRangeAt(0);"\r
1434                                 + "var parent_html = range.commonAncestorContainer.innerHTML;"\r
1435                                 + "if (parent_html == undefined) {window.jambi.saveSelectedText(selection_text); return;}"\r
1436                                 + "var first_text = range.startContainer.nodeValue.substr(range.startOffset);"\r
1437                                 + "var last_text = (range.endContainer.nodeValue).substring(0,range.endOffset);"\r
1438                                 + "var start = parent_html.indexOf(first_text);"\r
1439                                 + "var end = parent_html.indexOf(last_text,start+1)+last_text.length;"\r
1440                                 + "var value = parent_html.substring(start,end);"\r
1441                                 + "window.jambi.saveSelectedText(value);" ;\r
1442                 browser.page().mainFrame().evaluateJavaScript(scriptStart);\r
1443 \r
1444         }\r
1445 \r
1446         public void saveSelectedText(String text) {\r
1447                 boolean enabled = true;\r
1448                 if (text.trim().length() == 0)\r
1449                         enabled=false;\r
1450                 if (text.indexOf("en-tag=\"en-crypt\"") >= 0)\r
1451                         enabled=false;\r
1452                 if (text.indexOf("<img en-tag=\"en-media\"") >= 0)\r
1453                         enabled=false;\r
1454                 if (text.indexOf("<a en-tag=\"en-media\"") >= 0)\r
1455                         enabled=false;\r
1456                 if (text.indexOf("<input ") >= 0)\r
1457                         enabled=false;\r
1458                 \r
1459                 browser.encryptAction.setEnabled(enabled);\r
1460                 browser.insertLinkAction.setEnabled(enabled);\r
1461 //              selectedText = text;\r
1462         }\r
1463 \r
1464         // Decrypt clicked text\r
1465         public void decryptText(String id, String text, String hint) {\r
1466                 EnCrypt crypt = new EnCrypt();\r
1467                 String plainText = null;\r
1468                 Calendar currentTime = new GregorianCalendar();\r
1469                 Long l = new Long(currentTime.getTimeInMillis());\r
1470                 String slot = new String(Long.toString(l));\r
1471                 \r
1472                 // First, try to decrypt with any keys we already have\r
1473                 for (int i=0; i<Global.passwordRemember.size(); i++) {\r
1474                         plainText = crypt.decrypt(text, Global.passwordRemember.get(i).getFirst(), 64);\r
1475                         if (plainText != null) {\r
1476                                 slot = new String(Long.toString(l));\r
1477                                 Global.passwordSafe.put(slot, Global.passwordRemember.get(i));\r
1478                                 removeEncryption(id, plainText, false, slot);   \r
1479                                 return;\r
1480                         }\r
1481                 }\r
1482                 \r
1483                 \r
1484                 EnDecryptDialog dialog = new EnDecryptDialog();\r
1485                 dialog.setHint(hint);\r
1486                 while (plainText == null || !dialog.okPressed()) {\r
1487                         dialog.exec();\r
1488                         if (!dialog.okPressed()) {\r
1489                                 return;\r
1490                         }\r
1491                         plainText = crypt.decrypt(text, dialog.getPassword().trim(), 64);\r
1492                         if (plainText == null) {\r
1493                                 QMessageBox.warning(this, "Incorrect Password", "The password entered is not correct");\r
1494                         }\r
1495                 }\r
1496                 Pair<String,String> passwordPair = new Pair<String,String>();\r
1497                 passwordPair.setFirst(dialog.getPassword());\r
1498                 passwordPair.setSecond(dialog.getHint());\r
1499                 Global.passwordSafe.put(slot, passwordPair);\r
1500 //              removeEncryption(id, plainText.replaceAll("\n", "<br/>"), dialog.permanentlyDecrypt(), slot);\r
1501                 removeEncryption(id, plainText, dialog.permanentlyDecrypt(), slot);\r
1502                 if (dialog.rememberPassword()) {\r
1503                         Pair<String, String> pair = new Pair<String,String>();\r
1504                         pair.setFirst(dialog.getPassword());\r
1505                         pair.setSecond(dialog.getHint());\r
1506                         Global.passwordRemember.add(pair);\r
1507                 }\r
1508 \r
1509         }\r
1510 \r
1511         // Get the editor tag line\r
1512         public TagLineEdit getTagLine() {\r
1513                 return tagEdit;\r
1514         }\r
1515 \r
1516         // Modify a note's tags\r
1517         @SuppressWarnings("unused")\r
1518         private void modifyTags() {\r
1519                 TagAssign tagWindow = new TagAssign(allTags, currentTags, !conn.getNotebookTable().isLinked(currentNote.getNotebookGuid()));\r
1520                 tagWindow.exec();\r
1521                 if (tagWindow.okClicked()) {\r
1522                         currentTags.clear();\r
1523                         StringBuffer tagDisplay = new StringBuffer();\r
1524 \r
1525                         List<QListWidgetItem> newTags = tagWindow.getTagList()\r
1526                                         .selectedItems();\r
1527                         for (int i = 0; i < newTags.size(); i++) {\r
1528                                 currentTags.add(newTags.get(i).text());\r
1529                                 tagDisplay.append(newTags.get(i).text());\r
1530                                 if (i < newTags.size() - 1) {\r
1531                                         tagDisplay.append(Global.tagDelimeter + " ");\r
1532                                 }\r
1533                         }\r
1534                         tagEdit.setText(tagDisplay.toString());\r
1535                         noteSignal.tagsChanged.emit(currentNote.getGuid(), currentTags);\r
1536                 }\r
1537         }\r
1538 \r
1539         // Tag line has been modified by typing text\r
1540         @SuppressWarnings("unused")\r
1541         private void modifyTagsTyping() {\r
1542                 String completionText = "";\r
1543                 if (tagEdit.currentCompleterSelection != null && !tagEdit.currentCompleterSelection.equals("")) {\r
1544                         completionText = tagEdit.currentCompleterSelection;\r
1545                         tagEdit.currentCompleterSelection = "";\r
1546                 }\r
1547                 \r
1548                 if (tagEdit.text().equalsIgnoreCase(saveTagList))\r
1549                         return;\r
1550 \r
1551                 // We know something has changed...\r
1552                 String oldTagArray[] = saveTagList.split(Global.tagDelimeter);\r
1553                 String newTagArray[];\r
1554                 if (!completionText.equals("")) {\r
1555                         String before = tagEdit.text().substring(0,tagEdit.cursorPosition());\r
1556                         int lastDelimiter = before.lastIndexOf(Global.tagDelimeter);\r
1557                         if (lastDelimiter > 0)\r
1558                                 before = before.substring(0,before.lastIndexOf(Global.tagDelimeter));\r
1559                         else \r
1560                                 before = "";\r
1561                         String after = tagEdit.text().substring(tagEdit.cursorPosition());\r
1562                         newTagArray = (before+Global.tagDelimeter+completionText+Global.tagDelimeter+after).split(Global.tagDelimeter);\r
1563                 }\r
1564                 else {\r
1565                         newTagArray = tagEdit.text().split(Global.tagDelimeter);\r
1566                 }\r
1567                 \r
1568                 // Remove any traling or leading blanks\r
1569                 for (int i=0; i<newTagArray.length; i++)\r
1570                         newTagArray[i] = newTagArray[i].trim().replaceAll("^\\s+", "");;\r
1571                 \r
1572                 // Remove any potential duplicates from the new list\r
1573                 for (int i=0; i<newTagArray.length; i++) {\r
1574                         boolean foundOnce = false;\r
1575                         for (int j=0; j<newTagArray.length; j++) {\r
1576                                 if (newTagArray[j].equalsIgnoreCase(newTagArray[i])) {\r
1577                                         if (!foundOnce) {\r
1578                                                 foundOnce = true;\r
1579                                         } else\r
1580                                                 newTagArray[j] = "";\r
1581                                 }\r
1582                         }\r
1583                 }\r
1584 \r
1585                 List<String> newTagList = new ArrayList<String>();\r
1586                 List<String> oldTagList = new ArrayList<String>();\r
1587 \r
1588                 for (int i = 0; i < oldTagArray.length; i++)\r
1589                         if (!oldTagArray[i].trim().equals(""))\r
1590                                 oldTagList.add(oldTagArray[i]);\r
1591                 for (int i = 0; i < newTagArray.length; i++)\r
1592                         if (!newTagArray[i].trim().equals(""))\r
1593                                 newTagList.add(newTagArray[i]);\r
1594 \r
1595                 if (conn.getNotebookTable().isLinked(currentNote.getNotebookGuid())) {\r
1596                         for (int i=newTagList.size()-1; i>=0; i--) {\r
1597                                 boolean found = false;\r
1598                                 for (int j=0; j<allTags.size(); j++) {\r
1599                                         if (allTags.get(j).getName().equalsIgnoreCase(newTagList.get(i))) {\r
1600                                                 found = true;\r
1601                                                 j=allTags.size();\r
1602                                         }\r
1603                                 }\r
1604                                 if (!found)\r
1605                                         newTagList.remove(i);\r
1606                         }\r
1607                 }\r
1608 \r
1609                 // Let's cleanup the appearance of the tag list\r
1610                 Collections.sort(newTagList);\r
1611                 String newDisplay = "";\r
1612                 for (int i=0; i<newTagList.size(); i++) {\r
1613                         newDisplay = newDisplay+newTagList.get(i);\r
1614                         if (i<newTagList.size()-1)\r
1615                                 newDisplay = newDisplay+Global.tagDelimeter +" ";\r
1616                 }\r
1617                 tagEdit.blockSignals(true);\r
1618                 tagEdit.setText(newDisplay);\r
1619                 tagEdit.blockSignals(false);\r
1620                 \r
1621                 // We now have lists of the new & old. Remove duplicates. If all\r
1622                 // are removed from both then nothing has really changed\r
1623                 for (int i = newTagList.size() - 1; i >= 0; i--) {\r
1624                         String nTag = newTagList.get(i);\r
1625                         for (int j = oldTagList.size() - 1; j >= 0; j--) {\r
1626                                 String oTag = oldTagList.get(j);\r
1627                                 if (oTag.equalsIgnoreCase(nTag)) {\r
1628                                         oldTagList.remove(j);\r
1629                                         newTagList.remove(i);\r
1630                                         j = -1;\r
1631                                 }\r
1632                         }\r
1633                 }\r
1634 \r
1635                 if (oldTagList.size() != 0 || newTagList.size() != 0) {\r
1636                         currentTags.clear();\r
1637                         newTagArray = tagEdit.text().split(Global.tagDelimeter);\r
1638                         for (int i = 0; i < newTagArray.length; i++)\r
1639                                 if (!newTagArray[i].trim().equals(""))\r
1640                                         currentTags.add(newTagArray[i].trim());\r
1641 \r
1642                         noteSignal.tagsChanged.emit(currentNote.getGuid(), currentTags);\r
1643                 }\r
1644                 \r
1645         }\r
1646 \r
1647         // Tab button was pressed\r
1648         public void tabPressed() {\r
1649                 if (insideEncryption)\r
1650                         return;\r
1651                 if (!insideList && !insideTable) {\r
1652                         String script_start = new String(\r
1653                         "document.execCommand('insertHtml', false, '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;');");\r
1654                         browser.page().mainFrame().evaluateJavaScript(script_start);\r
1655                         return;\r
1656                 }\r
1657                 if (insideList) {\r
1658                         indentClicked();\r
1659                 }\r
1660                 if (insideTable) {\r
1661                         String js = new String( "function getCursorPosition() { "\r
1662                                         +"   var selObj = window.getSelection();"\r
1663                                         +"   var selRange = selObj.getRangeAt(0);"\r
1664                                         +"   var workingNode = window.getSelection().anchorNode;"\r
1665                                         +"   var rowCount = 0;"\r
1666                                         +"   var colCount = 0;"\r
1667                                         +"   while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { " \r
1668                                         +"      if (workingNode.nodeName.toLowerCase()=='tr') {"\r
1669                                         +"         rowCount = rowCount+1;"\r
1670                                         +"      }"\r
1671                                         +"      if (workingNode.nodeName.toLowerCase() == 'td') {"\r
1672                                         +"         colCount = colCount+1;"\r
1673                                         +"      }"\r
1674                                         +"      if (workingNode.previousSibling != null)"\r
1675                                         +"          workingNode = workingNode.previousSibling;"\r
1676                                         +"      else "\r
1677                                         +"           workingNode = workingNode.parentNode;"\r
1678                                         +"   }"\r
1679                                         +"   var nodes = workingNode.getElementsByTagName('tr');"\r
1680                                         +"   var tableRows = nodes.length;"\r
1681                                         +"   nodes = nodes[0].getElementsByTagName('td');"\r
1682                                         +"   var tableColumns = nodes.length;"\r
1683                                         +"   window.jambi.setTableCursorPositionTab(rowCount, colCount, tableRows, tableColumns);"\r
1684                                         +"} getCursorPosition();");\r
1685                         browser.page().mainFrame().evaluateJavaScript(js);\r
1686                 }\r
1687         }\r
1688         \r
1689         // If a user presses tab from within a table\r
1690         public void setTableCursorPositionTab(int currentRow, int currentCol, int tableRows, int tableColumns) {\r
1691                 if (tableRows == currentRow && currentCol == tableColumns) {\r
1692                         insertTableRow();\r
1693                 }\r
1694                 KeyboardModifiers modifiers = new KeyboardModifiers(KeyboardModifier.NoModifier);\r
1695                 QKeyEvent right = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Right.value(), modifiers);\r
1696                 QKeyEvent end = new QKeyEvent(Type.KeyPress, Qt.Key.Key_End.value(), modifiers);\r
1697                 QKeyEvent end2 = new QKeyEvent(Type.KeyPress, Qt.Key.Key_End.value(), modifiers);\r
1698                 getBrowser().focusWidget();\r
1699                 QCoreApplication.postEvent(getBrowser(), end);\r
1700                 QCoreApplication.postEvent(getBrowser(), right);\r
1701                 QCoreApplication.postEvent(getBrowser(), end2);\r
1702         }\r
1703                 \r
1704         public void backtabPressed() {\r
1705                 if (insideEncryption) \r
1706                         return;\r
1707                 if (insideList)\r
1708                         outdentClicked();\r
1709                 if (insideTable) {\r
1710                         String js = new String( "function getCursorPosition() { "\r
1711                                         +"   var selObj = window.getSelection();"\r
1712                                         +"   var selRange = selObj.getRangeAt(0);"\r
1713                                         +"   var workingNode = window.getSelection().anchorNode;"\r
1714                                         +"   var rowCount = 0;"\r
1715                                         +"   var colCount = 0;"\r
1716                                         +"   while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { " \r
1717                                         +"      if (workingNode.nodeName.toLowerCase()=='tr') {"\r
1718                                         +"         rowCount = rowCount+1;"\r
1719                                         +"      }"\r
1720                                         +"      if (workingNode.nodeName.toLowerCase() == 'td') {"\r
1721                                         +"         colCount = colCount+1;"\r
1722                                         +"      }"\r
1723                                         +"      if (workingNode.previousSibling != null)"\r
1724                                         +"          workingNode = workingNode.previousSibling;"\r
1725                                         +"      else "\r
1726                                         +"           workingNode = workingNode.parentNode;"\r
1727                                         +"   }"\r
1728                                         +"   var nodes = workingNode.getElementsByTagName('tr');"\r
1729                                         +"   var tableRows = nodes.length;"\r
1730                                         +"   nodes = nodes[0].getElementsByTagName('td');"\r
1731                                         +"   var tableColumns = nodes.length;"\r
1732                                         +"   window.jambi.setTableCursorPositionBackTab(rowCount, colCount, tableRows, tableColumns);"\r
1733                                         +"} getCursorPosition();");\r
1734                         browser.page().mainFrame().evaluateJavaScript(js);\r
1735                         \r
1736                 }\r
1737         }\r
1738         \r
1739         // If a user presses backtab from within a table\r
1740         public void setTableCursorPositionBackTab(int currentRow, int currentCol, int tableRows, int tableColumns) {\r
1741                 if (currentRow  == 1 && currentCol == 1) {\r
1742                         return;\r
1743                 }\r
1744                 KeyboardModifiers modifiers = new KeyboardModifiers(KeyboardModifier.NoModifier);\r
1745                 QKeyEvent left = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Left.value(), modifiers);\r
1746                 QKeyEvent home = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Home.value(), modifiers);\r
1747                 getBrowser().focusWidget();\r
1748                 QCoreApplication.postEvent(getBrowser(), home);\r
1749                 QCoreApplication.postEvent(getBrowser(), left);\r
1750         }\r
1751         \r
1752         \r
1753         public void setInsideList() {\r
1754                 insideList = true;\r
1755         }\r
1756         \r
1757         // The title has been edited\r
1758         @SuppressWarnings("unused")\r
1759         private void titleEdited() {\r
1760                 // If we don't have a good note, or if the current title\r
1761                 // matches the old title then we don't need to do anything\r
1762                 if (currentNote == null)\r
1763                         return;\r
1764                 if (currentNote.getTitle().trim().equals(titleLabel.text().trim()))\r
1765                         return;\r
1766                 \r
1767                 // If we have a real change, we need to save it.\r
1768                 noteSignal.titleChanged.emit(currentNote.getGuid(), titleLabel.text());\r
1769                 currentNote.setTitle(titleLabel.text());\r
1770                 saveNoteTitle = titleLabel.text();\r
1771                 checkNoteTitle();\r
1772         }\r
1773 \r
1774         // Set the list of note tags\r
1775         public void setAllTags(List<Tag> l) {\r
1776                 allTags = l;\r
1777                 tagEdit.setTagList(l);\r
1778         }\r
1779 \r
1780         // Setter for the current tags\r
1781         public void setCurrentTags(List<String> s) {\r
1782                 currentTags = s;\r
1783         }\r
1784 \r
1785         // Save the list of notebooks\r
1786         public void setNotebookList(List<Notebook> n) {\r
1787                 notebookList = n;\r
1788                 loadNotebookList();\r
1789         }\r
1790 \r
1791         // Load the notebook list and select the current notebook\r
1792         private void loadNotebookList() {\r
1793                 if (notebookBox.count() != 0)\r
1794                         notebookBox.clear();\r
1795                 if (notebookList == null)\r
1796                         return;\r
1797 \r
1798                 for (int i = 0; i < notebookList.size(); i++) {\r
1799                         notebookBox.addItem(notebookList.get(i).getName());\r
1800                         if (currentNote != null) {\r
1801                                 if (currentNote.getNotebookGuid().equals(\r
1802                                                 notebookList.get(i).getGuid())) {\r
1803                                         notebookBox.setCurrentIndex(i);\r
1804                                 }\r
1805                         }\r
1806                 }\r
1807         }\r
1808         \r
1809         \r
1810         // Set the notebook for a note\r
1811         public void setNotebook(String notebook) {\r
1812                 currentNote.setNotebookGuid(notebook);\r
1813                 loadNotebookList();\r
1814         }\r
1815 \r
1816         // Get the contents of the editor\r
1817         public String getContent() {\r
1818                 return browser.page().currentFrame().toHtml();\r
1819         }\r
1820 \r
1821         // The note contents have changed\r
1822         public void contentChanged() {\r
1823                 String content = getContent();\r
1824                 checkNoteTitle();\r
1825                 noteSignal.noteChanged.emit(currentNote.getGuid(), content); \r
1826         }\r
1827 \r
1828         // The notebook selection has changed\r
1829         @SuppressWarnings("unused")\r
1830         private void notebookChanged() {\r
1831                 boolean changed = false;\r
1832                 String n = notebookBox.currentText();\r
1833                 for (int i = 0; i < notebookList.size(); i++) {\r
1834                         if (n.equals(notebookList.get(i).getName())) {\r
1835                                 if (!notebookList.get(i).getGuid().equals(currentNote.getNotebookGuid())) {\r
1836                                         String guid = conn.getNotebookTable().findNotebookByName(n);\r
1837                                         if (conn.getNotebookTable().isLinked(guid)) {\r
1838                                                 tagEdit.setText("");\r
1839                                                 noteSignal.tagsChanged.emit(currentNote.getGuid(), new ArrayList<String>());\r
1840                                                 FilterEditorTags t = new FilterEditorTags(conn, logger);\r
1841                                                 setAllTags(t.getValidTags(currentNote));\r
1842                                         }\r
1843                                         currentNote.setNotebookGuid(notebookList.get(i).getGuid());\r
1844                                         changed = true;\r
1845                                 }\r
1846                                 i = notebookList.size();\r
1847                         }\r
1848                 }\r
1849                 \r
1850                 // If the notebook changed, signal the update\r
1851                 if (changed)\r
1852                         noteSignal.notebookChanged.emit(currentNote.getGuid(), currentNote\r
1853                                         .getNotebookGuid());\r
1854         }\r
1855 \r
1856         // Check the note title\r
1857         private void checkNoteTitle() {\r
1858                 String text = browser.page().currentFrame().toPlainText();\r
1859                 if (saveNoteTitle.trim().equals("") || saveNoteTitle.trim().equals("Untitled Note")) {\r
1860                         int newLine = text.indexOf("\n");\r
1861                         if (newLine > 0) {\r
1862                                 text = text.substring(0, newLine);\r
1863                                 if (text.trim().equals(""))\r
1864                                         text = tr("Untitled Note");\r
1865                                 titleLabel.setText(text);\r
1866                         } else {\r
1867                                 if (text.length() > Constants.EDAM_NOTE_TITLE_LEN_MAX)\r
1868                                         titleLabel.setText(text.substring(0, Constants.EDAM_NOTE_TITLE_LEN_MAX));\r
1869                                 else {\r
1870                                         titleLabel.blockSignals(true);\r
1871                                         if (text.trim().equals(""))\r
1872                                                 titleLabel.setText(tr("Untitled Note"));\r
1873                                         else\r
1874                                                 titleLabel.setText(text);\r
1875                                         titleLabel.blockSignals(false);\r
1876                                 }\r
1877                         }\r
1878                         noteSignal.titleChanged.emit(currentNote.getGuid(), titleLabel\r
1879                                         .text());\r
1880                 }\r
1881         }\r
1882 \r
1883         // Return the note contents so we can email them\r
1884         public String getContentsToEmail() {\r
1885                 return browser.page().currentFrame().toPlainText().trim();\r
1886                 /*\r
1887                  * int body = browser.page().currentFrame().toHtml().indexOf("<body>");\r
1888                  * String temp = browser.page().currentFrame().toHtml(); if (body == -1)\r
1889                  * temp = "<html><body><b>Test</b></body></html>"; else temp =\r
1890                  * "<html>"+temp.substring(body); return temp; // return\r
1891                  * urlEncode(browser.page().currentFrame().toHtml());\r
1892                  */\r
1893         }\r
1894 \r
1895         // Insert an image into the editor\r
1896         private void insertImage(QMimeData mime) {\r
1897                 logger.log(logger.EXTREME, "Entering insertImage");\r
1898                 QImage img = (QImage) mime.imageData();\r
1899                 String script_start = new String(\r
1900                                 "document.execCommand('insertHTML', false, '");\r
1901                 String script_end = new String("');");\r
1902 \r
1903                 long now = new Date().getTime();\r
1904                 String path = Global.getFileManager().getResDirPath(\r
1905                                 (new Long(now).toString()) + ".jpg");\r
1906 \r
1907                 // This block is just a hack to make sure we wait at least 1ms so we\r
1908                 // don't\r
1909                 // have collisions on image names\r
1910                 long i = new Date().getTime();\r
1911                 while (now == i)\r
1912                         i = new Date().getTime();\r
1913 \r
1914                 // Open the file & write the data\r
1915                 QFile tfile = new QFile(path);\r
1916                 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));\r
1917                 if (!img.save(tfile)) {\r
1918                         tfile.close();\r
1919                         return;\r
1920                 }\r
1921                 tfile.close();\r
1922                 \r
1923                 Resource newRes = createResource(QUrl.fromLocalFile(path).toString(), 0, "image/jpeg", false);\r
1924                 if (newRes == null)\r
1925                         return;\r
1926                 currentNote.getResources().add(newRes);\r
1927 \r
1928                 // do the actual insert into the note\r
1929                 StringBuffer buffer = new StringBuffer(100);\r
1930                 buffer.append("<img src=\"");\r
1931                 buffer.append(tfile.fileName());\r
1932                 buffer.append("\" en-tag=en-media type=\"image/jpeg\""\r
1933                                 +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""\r
1934                                 +" guid=\"" +newRes.getGuid() +"\""\r
1935 //                              +" onContextMenu=\"window.jambi.imageContextMenu('" +tfile.fileName() +"');\""\r
1936                                 +" onContextMenu=\"window.jambi.imageContextMenu(&amp." +tfile.fileName() +"&amp.);\""\r
1937                                 + " />");\r
1938                 \r
1939                 browser.page().mainFrame().evaluateJavaScript(\r
1940                                 script_start + buffer + script_end);\r
1941 \r
1942                 return;\r
1943         }\r
1944 \r
1945         // Handle URLs that are trying to be pasted\r
1946         public void handleUrls(QMimeData mime) {\r
1947                 logger.log(logger.EXTREME, "Starting handleUrls");\r
1948                 FileNameMap fileNameMap = URLConnection.getFileNameMap();\r
1949 \r
1950                 List<QUrl> urlList = mime.urls();\r
1951                 String url = new String();\r
1952                 String script_start = new String(\r
1953                                 "document.execCommand('createLink', false, '");\r
1954                 String script_end = new String("');");\r
1955 \r
1956                 for (int i = 0; i < urlList.size(); i++) {\r
1957                         url = urlList.get(i).toString();\r
1958                         // Find out what type of file we have\r
1959                         String mimeType = fileNameMap.getContentTypeFor(url);\r
1960 \r
1961                         // If null returned, we need to guess at the file type\r
1962                         if (mimeType == null)\r
1963                                 mimeType = "application/"\r
1964                                                 + url.substring(url.lastIndexOf(".") + 1);\r
1965 \r
1966                         // Check if we have an image or some other type of file\r
1967                         if (url.substring(0, 5).equalsIgnoreCase("file:")\r
1968                                         && mimeType.substring(0, 5).equalsIgnoreCase("image")) {\r
1969                                 handleLocalImageURLPaste(mime, mimeType);\r
1970                                 return;\r
1971                         }\r
1972                         String[] type = mimeType.split("/");\r
1973                         boolean valid = validAttachment(type[1]);\r
1974                         boolean smallEnough = checkFileAttachmentSize(url);\r
1975                         if (smallEnough && valid\r
1976                                         && url.substring(0, 5).equalsIgnoreCase("file:")\r
1977                                         && !mimeType.substring(0, 5).equalsIgnoreCase("image")) {\r
1978                                 handleLocalAttachment(mime, mimeType);\r
1979                                 return;\r
1980                         }\r
1981                         browser.page().mainFrame().evaluateJavaScript(\r
1982                                         script_start + url + script_end);\r
1983                 }\r
1984                 return;\r
1985         }\r
1986 \r
1987         // If a URL being pasted is an image URL, then attach the image\r
1988         private void handleLocalImageURLPaste(QMimeData mime, String mimeType) {\r
1989                 List<QUrl> urlList = mime.urls();\r
1990                 String url = new String();\r
1991                 String script_start_image = new String(\r
1992                                 "document.execCommand('insertHtml', false, '");\r
1993                 String script_end = new String("');");\r
1994                 StringBuffer buffer;\r
1995 \r
1996                 // Copy the image over into the resource directory and create a new resource \r
1997                 // record for each url pasted\r
1998                 for (int i = 0; i < urlList.size(); i++) {\r
1999                         url = urlList.get(i).toString();\r
2000 \r
2001                         Resource newRes = createResource(url, i, mimeType, false);\r
2002                         if (newRes == null)\r
2003                                 return;\r
2004                         currentNote.getResources().add(newRes);\r
2005                         buffer = new StringBuffer(100);\r
2006                         \r
2007                         // Open the file & write the data\r
2008                         String fileName = Global.getFileManager().getResDirPath(newRes.getGuid());\r
2009                         QFile tfile = new QFile(fileName);\r
2010                         tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));\r
2011                         tfile.write(newRes.getData().getBody());\r
2012                         tfile.close();\r
2013                         buffer.append(script_start_image);\r
2014                         buffer.append("<img src=\"" + FileUtils.toForwardSlashedPath(fileName));\r
2015 //                      if (mimeType.equalsIgnoreCase("image/jpg"))\r
2016 //                              mimeType = "image/jpeg";\r
2017                         buffer.append("\" en-tag=\"en-media\" type=\"" + mimeType +"\""\r
2018                                         +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""\r
2019                                         +" guid=\"" +newRes.getGuid() +"\""\r
2020                                         +" onContextMenu=\"window.jambi.imageContextMenu(&apos;" +tfile.fileName() +"&apos;);\""\r
2021                                         + " />");\r
2022                         buffer.append(script_end);\r
2023                         browser.page().mainFrame().evaluateJavaScript(buffer.toString());\r
2024                 }\r
2025                 return;\r
2026         }\r
2027         \r
2028 \r
2029         // If a URL being pasted is a local file URL, then attach the file\r
2030         private void handleLocalAttachment(QMimeData mime, String mimeType) {\r
2031                 logger.log(logger.EXTREME, "Attaching local file");\r
2032                 List<QUrl> urlList = mime.urls();\r
2033                 String script_start = new String(\r
2034                                 "document.execCommand('insertHtml', false, '");\r
2035                 String script_end = new String("');");\r
2036                 StringBuffer buffer;\r
2037 \r
2038                         String[] type = mimeType.split("/");\r
2039                         String icon = findIcon(type[1]);\r
2040                         if (icon.equals("attachment.png"))\r
2041                                 icon = findIcon(type[0]);\r
2042                         buffer = new StringBuffer(100);\r
2043 \r
2044                 for (int i = 0; i < urlList.size(); i++) {\r
2045                         String url = urlList.get(i).toString();\r
2046 \r
2047                         // Start building the HTML\r
2048                         if (icon.equals("attachment.png"))\r
2049                                 icon = findIcon(url.substring(url.lastIndexOf(".")+1));\r
2050                         String imageURL = FileUtils.toFileURLString(Global.getFileManager().getImageDirFile(icon));\r
2051 \r
2052                         logger.log(logger.EXTREME, "Creating resource ");\r
2053                         Resource newRes = createResource(url, i, mimeType, true);\r
2054                         if (newRes == null)\r
2055                                 return;\r
2056                         logger.log(logger.EXTREME, "New resource size: " +newRes.getData().getSize());\r
2057                         currentNote.getResources().add(newRes);\r
2058                         \r
2059                         String fileName = newRes.getGuid() + Global.attachmentNameDelimeter+newRes.getAttributes().getFileName();\r
2060                         // If we have a PDF, we need to setup the preview.\r
2061                         if (icon.equalsIgnoreCase("pdf.png") && Global.pdfPreview()) {\r
2062                                 logger.log(logger.EXTREME, "Setting up PDF preview");\r
2063                                 if (newRes.getAttributes() != null && \r
2064                                                 newRes.getAttributes().getFileName() != null && \r
2065                                                 !newRes.getAttributes().getFileName().trim().equals(""))\r
2066                                         fileName = newRes.getGuid()+Global.attachmentNameDelimeter+\r
2067                                                 newRes.getAttributes().getFileName();\r
2068                                 else\r
2069                                         fileName = newRes.getGuid()+".pdf";\r
2070                                 QFile file = new QFile(Global.getFileManager().getResDirPath(fileName));\r
2071                         QFile.OpenMode mode = new QFile.OpenMode();\r
2072                         mode.set(QFile.OpenModeFlag.WriteOnly);\r
2073                         file.open(mode);\r
2074                         QDataStream out = new QDataStream(file);\r
2075 //                      Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(newRes.getGuid(), true);\r
2076                                 QByteArray binData = new QByteArray(newRes.getData().getBody());\r
2077 //                              resBinary = null;\r
2078                         out.writeBytes(binData.toByteArray());\r
2079                         file.close();\r
2080 \r
2081                                 PDFPreview pdfPreview = new PDFPreview();\r
2082                                 if (pdfPreview.setupPreview(Global.getFileManager().getResDirPath(fileName), "pdf",0)) {\r
2083                                 imageURL = file.fileName() + ".png";\r
2084                                 }\r
2085                         }\r
2086                                                 \r
2087                         logger.log(logger.EXTREME, "Generating link tags");\r
2088                         buffer.delete(0, buffer.length());\r
2089                         buffer.append("<a en-tag=\"en-media\" guid=\"" +newRes.getGuid()+"\" ");\r
2090                         buffer.append(" onContextMenu=\"window.jambi.imageContextMenu(&apos;")\r
2091                       .append(Global.getFileManager().getResDirPath(fileName))\r
2092                       .append("&apos;);\" ");                   buffer.append("type=\"" + mimeType + "\" href=\"nnres://" + fileName +"\" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\" >");\r
2093                         buffer.append("<img src=\"" + imageURL + "\" title=\"" +newRes.getAttributes().getFileName());\r
2094                         buffer.append("\"></img>");\r
2095                         buffer.append("</a>");\r
2096                         browser.page().mainFrame().evaluateJavaScript(\r
2097                                         script_start + buffer.toString() + script_end);\r
2098                 }\r
2099                 return;\r
2100         }\r
2101 \r
2102         private Resource createResource(String url, int sequence, String mime, boolean attachment) {\r
2103                 logger.log(logger.EXTREME, "Inside create resource");\r
2104                 QFile resourceFile;\r
2105                 String urlTest = new QUrl(url).toLocalFile();\r
2106                 if (!urlTest.equals(""))\r
2107                         url = urlTest;\r
2108                 url = url.replace("/", File.separator);\r
2109         resourceFile = new QFile(url); \r
2110         resourceFile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly));\r
2111         byte[] fileData = resourceFile.readAll().toByteArray();\r
2112         resourceFile.close();\r
2113         if (fileData.length == 0)\r
2114                 return null;\r
2115         MessageDigest md;\r
2116         try {\r
2117                 md = MessageDigest.getInstance("MD5");\r
2118                 md.update(fileData);\r
2119                 byte[] hash = md.digest();\r
2120   \r
2121                 Resource r = new Resource();\r
2122                 Calendar time = new GregorianCalendar();\r
2123                 long prevTime = time.getTimeInMillis();\r
2124                 while (prevTime == time.getTimeInMillis()) {\r
2125                         time = new GregorianCalendar();\r
2126                 }\r
2127                 r.setGuid(time.getTimeInMillis()+new Integer(sequence).toString());\r
2128                 r.setNoteGuid(currentNote.getGuid());\r
2129                 r.setMime(mime);\r
2130                 r.setActive(true);\r
2131                 r.setUpdateSequenceNum(0);\r
2132                 r.setWidth((short) 0);\r
2133                 r.setHeight((short) 0);\r
2134                 r.setDuration((short) 0);\r
2135                                 \r
2136                 Data d = new Data();\r
2137                 d.setBody(fileData);\r
2138                 d.setBodyIsSet(true);\r
2139                 d.setBodyHash(hash);\r
2140                 d.setBodyHashIsSet(true);\r
2141                 r.setData(d);\r
2142                 d.setSize(fileData.length);\r
2143                 \r
2144                 int fileNamePos = url.lastIndexOf(File.separator);\r
2145                 if (fileNamePos == -1)\r
2146                         fileNamePos = url.lastIndexOf("/");\r
2147                         String fileName = url.substring(fileNamePos+1);\r
2148                 ResourceAttributes a = new ResourceAttributes();\r
2149                 a.setAltitude(0);\r
2150                 a.setAltitudeIsSet(false);\r
2151                 a.setLongitude(0);\r
2152                 a.setLongitudeIsSet(false);\r
2153                 a.setLatitude(0);\r
2154                 a.setLatitudeIsSet(false);\r
2155                 a.setCameraMake("");\r
2156                 a.setCameraMakeIsSet(false);\r
2157                 a.setCameraModel("");\r
2158                 a.setCameraModelIsSet(false);\r
2159                 a.setAttachment(attachment);\r
2160                 a.setAttachmentIsSet(true);\r
2161                 a.setClientWillIndex(false);\r
2162                 a.setClientWillIndexIsSet(true);\r
2163                 a.setRecoType("");\r
2164                 a.setRecoTypeIsSet(false);\r
2165                 a.setSourceURL(url);\r
2166                 a.setSourceURLIsSet(true);\r
2167                 a.setTimestamp(0);\r
2168                 a.setTimestampIsSet(false);\r
2169                 a.setFileName(fileName);\r
2170                 a.setFileNameIsSet(true);\r
2171                 r.setAttributes(a);\r
2172                 \r
2173                 conn.getNoteTable().noteResourceTable.saveNoteResource(r, true);\r
2174                 return r;\r
2175         } catch (NoSuchAlgorithmException e1) {\r
2176                 e1.printStackTrace();\r
2177                 }\r
2178         return null;\r
2179         }\r
2180         \r
2181 \r
2182     // find the appropriate icon for an attachment\r
2183     private String findIcon(String appl) {\r
2184         appl = appl.toLowerCase();\r
2185         File f = Global.getFileManager().getImageDirFile(appl + ".png");\r
2186         if (f.exists())\r
2187                 return appl+".png";\r
2188         return "attachment.png";\r
2189     }\r
2190 \r
2191         // Check if the account supports this type of attachment\r
2192         private boolean validAttachment(String type) {\r
2193                 if (Global.isPremium())\r
2194                         return true;\r
2195                 if (type.equalsIgnoreCase("JPG"))\r
2196                         return true;\r
2197                 if (type.equalsIgnoreCase("PNG"))\r
2198                         return true;\r
2199                 if (type.equalsIgnoreCase("GIF"))\r
2200                         return true;\r
2201                 if (type.equalsIgnoreCase("MP3"))\r
2202                         return true;\r
2203                 if (type.equalsIgnoreCase("WAV"))\r
2204                         return true;\r
2205                 if (type.equalsIgnoreCase("AMR"))\r
2206                         return true;\r
2207                 if (type.equalsIgnoreCase("PDF"))\r
2208                         return true;\r
2209                 String error = tr("Non-premium accounts can only attach JPG, PNG, GIF, MP3, WAV, AMR, or PDF files.");\r
2210                 QMessageBox.information(this, tr("Non-Premium Account"), error);\r
2211 \r
2212                 return false;\r
2213         }\r
2214 \r
2215         // Check the file attachment to be sure it isn't over 25 mb\r
2216         private boolean checkFileAttachmentSize(String url) {\r
2217                 String fileName = url.substring(8);\r
2218                 QFile resourceFile = new QFile(fileName);\r
2219                 resourceFile.open(new QIODevice.OpenMode(\r
2220                                 QIODevice.OpenModeFlag.ReadOnly));\r
2221                 long size = resourceFile.size();\r
2222                 resourceFile.close();\r
2223                 size = size / 1024 / 1024;\r
2224                 if (size < 50 && Global.isPremium())\r
2225                         return true;\r
2226                 if (size < 25)\r
2227                         return true;\r
2228 \r
2229                 String error = tr("A file attachment may not exceed 25MB.");\r
2230                 QMessageBox.information(this, tr("Attachment Size"), error);\r
2231                 return false;\r
2232         }\r
2233 \r
2234 \r
2235         @SuppressWarnings("unused")\r
2236         private void createdChanged() {\r
2237                 QDateTime dt = new QDateTime();\r
2238                 dt.setDate(createdDate.date());\r
2239                 dt.setTime(createdTime.time());\r
2240                 noteSignal.createdDateChanged.emit(currentNote.getGuid(), dt);\r
2241 \r
2242         }\r
2243 \r
2244         @SuppressWarnings("unused")\r
2245         private void alteredChanged() {\r
2246                 QDateTime dt = new QDateTime();\r
2247                 dt.setDate(alteredDate.date());\r
2248                 dt.setTime(alteredTime.time());\r
2249                 noteSignal.alteredDateChanged.emit(currentNote.getGuid(), dt);\r
2250         }\r
2251 \r
2252         @SuppressWarnings("unused")\r
2253         private void subjectDateTimeChanged() {\r
2254                 QDateTime dt = new QDateTime();\r
2255                 dt.setDate(subjectDate.date());\r
2256                 dt.setTime(subjectTime.time());\r
2257                 noteSignal.subjectDateChanged.emit(currentNote.getGuid(), dt);\r
2258 \r
2259         }\r
2260 \r
2261         @SuppressWarnings("unused")\r
2262         private void sourceUrlChanged() {\r
2263                 noteSignal.sourceUrlChanged.emit(currentNote.getGuid(), urlText.text());\r
2264         }\r
2265 \r
2266         @SuppressWarnings("unused")\r
2267         private void authorChanged() {\r
2268                 noteSignal.authorChanged.emit(currentNote.getGuid(), authorText.text());\r
2269         }\r
2270         \r
2271         @SuppressWarnings("unused")\r
2272         private void geoBoxChanged() {\r
2273                 int index = geoBox.currentIndex();\r
2274                 geoBox.setCurrentIndex(0);\r
2275                 if (index == 1) {\r
2276                         GeoDialog box = new GeoDialog();\r
2277                         box.setLongitude(currentNote.getAttributes().getLongitude());\r
2278                         box.setLatitude(currentNote.getAttributes().getLatitude());\r
2279                         box.setAltitude(currentNote.getAttributes().getAltitude());\r
2280                         box.exec();\r
2281                         if (!box.okPressed())\r
2282                                 return;\r
2283                         double alt = box.getAltitude();\r
2284                         double lat = box.getLatitude();\r
2285                         double lon = box.getLongitude();\r
2286                         if (alt != currentNote.getAttributes().getAltitude() ||\r
2287                                 lon != currentNote.getAttributes().getLongitude() ||\r
2288                                 lat != currentNote.getAttributes().getLatitude()) {\r
2289                                         noteSignal.geoChanged.emit(currentNote.getGuid(), lon, lat, alt);\r
2290                                         currentNote.getAttributes().setAltitude(alt);\r
2291                                         currentNote.getAttributes().setLongitude(lon);\r
2292                                         currentNote.getAttributes().setLatitude(lat);\r
2293                         }\r
2294                 }\r
2295                 \r
2296                 if (index == 2) {\r
2297                         noteSignal.geoChanged.emit(currentNote.getGuid(), 0.0, 0.0, 0.0);\r
2298                         currentNote.getAttributes().setAltitude(0.0);\r
2299                         currentNote.getAttributes().setLongitude(0.0);\r
2300                         currentNote.getAttributes().setLatitude(0.0);\r
2301                 }\r
2302                 \r
2303                 if (index == 3 || index == 0) {\r
2304                         QDesktopServices.openUrl(new QUrl("http://maps.google.com/maps?z=6&q="+currentNote.getAttributes().getLatitude() +"," +currentNote.getAttributes().getLongitude()));\r
2305                 }\r
2306         }\r
2307 \r
2308         // ************************************************************\r
2309         // * User chose to save an attachment. Pares out the request *\r
2310         // * into a guid & file. Save the result. *\r
2311         // ************************************************************\r
2312         public void downloadAttachment(QNetworkRequest request) {\r
2313                 String guid;\r
2314                 QFileDialog fd = new QFileDialog(this);\r
2315                 fd.setFileMode(FileMode.AnyFile);\r
2316                 fd.setConfirmOverwrite(true);\r
2317                 fd.setWindowTitle(tr("Save File"));\r
2318                 fd.setAcceptMode(AcceptMode.AcceptSave);\r
2319                 fd.setDirectory(System.getProperty("user.home"));\r
2320                 String name = request.url().toString();\r
2321 \r
2322                 int pos = name.lastIndexOf(Global.attachmentNameDelimeter);\r
2323                 if (pos > -1) {\r
2324                         guid = name.substring(0, pos).replace("nnres://", "");\r
2325                         name = name.substring(pos +Global.attachmentNameDelimeter.length());\r
2326                         fd.selectFile(name);\r
2327                         pos = name.lastIndexOf('.');\r
2328                         if (pos > -1) {\r
2329                                 String mimeType = "(*." + name.substring(pos + 1)\r
2330                                                 + ");; All Files (*)";\r
2331                                 fd.setFilter(tr(mimeType));\r
2332                         }\r
2333                 } else {\r
2334                         guid = name;\r
2335                 }\r
2336 \r
2337                 // Strip URL prefix and base dir\r
2338                 guid = guid.replace("nnres://", "")\r
2339                         .replace(FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath()), "");\r
2340                 guid = guid.replace("file://", "").replace("/", "")\r
2341                 .replace(FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath()), "");\r
2342 \r
2343                 pos = guid.lastIndexOf('.');\r
2344                 if (pos > 0)\r
2345                         guid = guid.substring(0,pos);\r
2346                 if (fd.exec() != 0 && fd.selectedFiles().size() > 0) {\r
2347                         name = name.replace('\\', '/');\r
2348                         Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);\r
2349                         QFile saveFile = new QFile(fd.selectedFiles().get(0));\r
2350                         QFile.OpenMode mode = new QFile.OpenMode();\r
2351                         mode.set(QFile.OpenModeFlag.WriteOnly);\r
2352                         saveFile.open(mode);\r
2353                         QDataStream saveOut = new QDataStream(saveFile);\r
2354                         QByteArray binData = new QByteArray(resBinary.getData().getBody());\r
2355                         saveOut.writeBytes(binData.toByteArray());\r
2356                         saveFile.close();\r
2357 \r
2358                 }\r
2359         }\r
2360 \r
2361         \r
2362         // ************************************************************\r
2363         // * User chose to save an attachment. Pares out the request *\r
2364         // * into a guid & file. Save the result. --- DONE FROM downloadAttachment now!!!!!   \r
2365         // ************************************************************\r
2366         public void downloadImage(QNetworkRequest request) {\r
2367                 QFileDialog fd = new QFileDialog(this);\r
2368                 fd.setFileMode(FileMode.AnyFile);\r
2369                 fd.setConfirmOverwrite(true);\r
2370                 fd.setWindowTitle(tr("Save File"));\r
2371                 fd.setAcceptMode(AcceptMode.AcceptSave);\r
2372                 fd.setDirectory(System.getProperty("user.home"));\r
2373                 String name = request.url().toString();\r
2374                 name = name.replace("nnres://", "");\r
2375                 String dPath = FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath());\r
2376                 name = name.replace(dPath, "");\r
2377                 int pos = name.lastIndexOf('.');\r
2378                 String guid = name;\r
2379                 if (pos > -1) {\r
2380                         String mimeType = "(*." + name.substring(pos + 1)\r
2381                         + ");; All Files (*)";\r
2382                                 fd.setFilter(tr(mimeType));\r
2383                         guid = guid.substring(0,pos);\r
2384                 }\r
2385                 pos = name.lastIndexOf(Global.attachmentNameDelimeter);\r
2386                 if (pos > -1) {\r
2387                         guid = name.substring(0, pos);\r
2388                         fd.selectFile(name.substring(pos+Global.attachmentNameDelimeter.length()));             \r
2389                 }\r
2390                 if (fd.exec() != 0 && fd.selectedFiles().size() > 0) {\r
2391                         Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);\r
2392                         String fileName = fd.selectedFiles().get(0);\r
2393                         QFile saveFile = new QFile(fileName);\r
2394                         QFile.OpenMode mode = new QFile.OpenMode();\r
2395                         mode.set(QFile.OpenModeFlag.WriteOnly);\r
2396                         saveFile.open(mode);\r
2397                         QDataStream saveOut = new QDataStream(saveFile);\r
2398                         QByteArray binData = new QByteArray(resBinary.getData().getBody());\r
2399                         saveOut.writeBytes(binData.toByteArray());\r
2400                         saveFile.close();\r
2401                 }\r
2402         }\r
2403 \r
2404         \r
2405         // *************************************************************\r
2406         // * decrypt any hidden text.  We could do an XML parse, but \r
2407         // * it is quicker here just to scan for an <img tag & do the fix\r
2408         // * the manual way\r
2409         // *************************************************************\r
2410         private void removeEncryption(String id, String plainText, boolean permanent, String slot) {\r
2411                 if (!permanent) {\r
2412                         plainText = " <table class=\"en-crypt-temp\" slot=\""\r
2413                                         +slot \r
2414                                         +"\""\r
2415                                         +"border=1 width=100%><tbody><tr><td>"\r
2416                                         +plainText+"</td></tr></tbody></table>";\r
2417                 }\r
2418                 \r
2419                 String html = browser.page().mainFrame().toHtml();\r
2420                 String text = html;\r
2421                 int imagePos = html.indexOf("<img");\r
2422                 int endPos;\r
2423                 for ( ;imagePos>0; ) {\r
2424                         // Find the end tag\r
2425                         endPos = text.indexOf(">", imagePos);\r
2426                         String tag = text.substring(imagePos-1,endPos);\r
2427                         if (tag.indexOf("id=\""+id+"\"") > -1) {\r
2428                                         text = text.substring(0,imagePos) +plainText+text.substring(endPos+1);  \r
2429                                         QTextCodec codec = QTextCodec.codecForName("UTF-8");\r
2430                                 QByteArray unicode =  codec.fromUnicode(text);\r
2431                                         browser.setContent(unicode);\r
2432                                         if (permanent)\r
2433                                                 contentChanged();\r
2434                         }\r
2435                         imagePos = text.indexOf("<img", imagePos+1);\r
2436                 }\r
2437         }\r
2438         \r
2439         \r
2440         //****************************************************************\r
2441         //* Focus shortcuts\r
2442         //****************************************************************\r
2443         @SuppressWarnings("unused")\r
2444         private void focusTitle() {\r
2445                 titleLabel.setFocus();\r
2446         }\r
2447         @SuppressWarnings("unused")\r
2448         private void focusTag() {\r
2449                 tagEdit.setFocus();\r
2450         }\r
2451         @SuppressWarnings("unused")\r
2452         private void focusNote() {\r
2453                 browser.setFocus();\r
2454         }\r
2455         @SuppressWarnings("unused")\r
2456         private void focusAuthor() {\r
2457                 authorLabel.setFocus();\r
2458         }\r
2459         @SuppressWarnings("unused")\r
2460         private void focusUrl() {\r
2461                 urlLabel.setFocus();\r
2462         }\r
2463         \r