OSDN Git Service

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