OSDN Git Service

Merge branch 'development' of ssh://nevernote.git.sourceforge.net/gitroot/nevernote...
[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.lang3.StringEscapeUtils;\r
42 import org.apache.commons.lang3.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.evernote.edam.type.User;\r
52 import com.swabunga.spell.engine.Configuration;\r
53 import com.swabunga.spell.engine.SpellDictionary;\r
54 import com.swabunga.spell.engine.SpellDictionaryHashMap;\r
55 import com.swabunga.spell.engine.Word;\r
56 import com.swabunga.spell.event.SpellCheckEvent;\r
57 import com.swabunga.spell.event.SpellCheckListener;\r
58 import com.swabunga.spell.event.SpellChecker;\r
59 import com.swabunga.spell.event.StringWordTokenizer;\r
60 import com.trolltech.qt.core.QByteArray;\r
61 import com.trolltech.qt.core.QCoreApplication;\r
62 import com.trolltech.qt.core.QDataStream;\r
63 import com.trolltech.qt.core.QDateTime;\r
64 import com.trolltech.qt.core.QEvent;\r
65 import com.trolltech.qt.core.QEvent.Type;\r
66 import com.trolltech.qt.core.QFile;\r
67 import com.trolltech.qt.core.QFileSystemWatcher;\r
68 import com.trolltech.qt.core.QIODevice;\r
69 import com.trolltech.qt.core.QMimeData;\r
70 import com.trolltech.qt.core.QTextCodec;\r
71 import com.trolltech.qt.core.QTimer;\r
72 import com.trolltech.qt.core.QUrl;\r
73 import com.trolltech.qt.core.Qt;\r
74 import com.trolltech.qt.core.Qt.Key;\r
75 import com.trolltech.qt.core.Qt.KeyboardModifier;\r
76 import com.trolltech.qt.core.Qt.KeyboardModifiers;\r
77 import com.trolltech.qt.gui.QAction;\r
78 import com.trolltech.qt.gui.QApplication;\r
79 import com.trolltech.qt.gui.QCalendarWidget;\r
80 import com.trolltech.qt.gui.QClipboard;\r
81 import com.trolltech.qt.gui.QClipboard.Mode;\r
82 import com.trolltech.qt.gui.QColor;\r
83 import com.trolltech.qt.gui.QComboBox;\r
84 import com.trolltech.qt.gui.QDateEdit;\r
85 import com.trolltech.qt.gui.QDesktopServices;\r
86 import com.trolltech.qt.gui.QFileDialog;\r
87 import com.trolltech.qt.gui.QFileDialog.AcceptMode;\r
88 import com.trolltech.qt.gui.QFileDialog.FileMode;\r
89 import com.trolltech.qt.gui.QFont;\r
90 import com.trolltech.qt.gui.QFontDatabase;\r
91 import com.trolltech.qt.gui.QFormLayout;\r
92 import com.trolltech.qt.gui.QGridLayout;\r
93 import com.trolltech.qt.gui.QHBoxLayout;\r
94 import com.trolltech.qt.gui.QIcon;\r
95 import com.trolltech.qt.gui.QImage;\r
96 import com.trolltech.qt.gui.QKeyEvent;\r
97 import com.trolltech.qt.gui.QKeySequence;\r
98 import com.trolltech.qt.gui.QLabel;\r
99 import com.trolltech.qt.gui.QLineEdit;\r
100 import com.trolltech.qt.gui.QListWidgetItem;\r
101 import com.trolltech.qt.gui.QMatrix;\r
102 import com.trolltech.qt.gui.QMessageBox;\r
103 import com.trolltech.qt.gui.QPalette;\r
104 import com.trolltech.qt.gui.QPalette.ColorRole;\r
105 import com.trolltech.qt.gui.QPushButton;\r
106 import com.trolltech.qt.gui.QShortcut;\r
107 import com.trolltech.qt.gui.QSplitter;\r
108 import com.trolltech.qt.gui.QTextEdit;\r
109 import com.trolltech.qt.gui.QTextEdit.LineWrapMode;\r
110 import com.trolltech.qt.gui.QTimeEdit;\r
111 import com.trolltech.qt.gui.QToolButton;\r
112 import com.trolltech.qt.gui.QToolButton.ToolButtonPopupMode;\r
113 import com.trolltech.qt.gui.QVBoxLayout;\r
114 import com.trolltech.qt.gui.QWidget;\r
115 import com.trolltech.qt.network.QNetworkAccessManager;\r
116 import com.trolltech.qt.network.QNetworkReply;\r
117 import com.trolltech.qt.network.QNetworkReply.NetworkError;\r
118 import com.trolltech.qt.network.QNetworkRequest;\r
119 import com.trolltech.qt.webkit.QWebPage;\r
120 import com.trolltech.qt.webkit.QWebPage.WebAction;\r
121 import com.trolltech.qt.webkit.QWebSettings;\r
122 import com.trolltech.qt.webkit.QWebView;\r
123 \r
124 import cx.fbn.nevernote.Global;\r
125 import cx.fbn.nevernote.dialog.EnCryptDialog;\r
126 import cx.fbn.nevernote.dialog.EnDecryptDialog;\r
127 import cx.fbn.nevernote.dialog.GeoDialog;\r
128 import cx.fbn.nevernote.dialog.InsertLatexImage;\r
129 import cx.fbn.nevernote.dialog.InsertLinkDialog;\r
130 import cx.fbn.nevernote.dialog.NoteQuickLinkDialog;\r
131 import cx.fbn.nevernote.dialog.SpellCheck;\r
132 import cx.fbn.nevernote.dialog.TableDialog;\r
133 import cx.fbn.nevernote.dialog.TagAssign;\r
134 import cx.fbn.nevernote.evernote.EnCrypt;\r
135 import cx.fbn.nevernote.filters.FilterEditorTags;\r
136 import cx.fbn.nevernote.signals.NoteResourceSignal;\r
137 import cx.fbn.nevernote.signals.NoteSignal;\r
138 import cx.fbn.nevernote.sql.DatabaseConnection;\r
139 import cx.fbn.nevernote.utilities.ApplicationLogger;\r
140 import cx.fbn.nevernote.utilities.FileUtils;\r
141 import cx.fbn.nevernote.utilities.Pair;\r
142 import cx.fbn.nevernote.xml.HtmlTagModifier;\r
143 \r
144 public class BrowserWindow extends QWidget {\r
145 \r
146         public final QLineEdit titleLabel;\r
147         private final QLineEdit urlText;\r
148         private final QLabel authorLabel;\r
149         private final QLineEdit authorText;\r
150         private final QComboBox geoBox;\r
151         public final TagLineEdit tagEdit;\r
152         public final QLabel tagLabel;\r
153         private final QPushButton urlLabel;\r
154         private final QLabel alteredLabel;\r
155         private final QDateEdit alteredDate;\r
156         private final QTimeEdit alteredTime;\r
157         private final QDateEdit createdDate;\r
158         private final QTimeEdit createdTime;\r
159         private final QLabel subjectLabel;\r
160         private final QDateEdit subjectDate;\r
161         private final QTimeEdit subjectTime;\r
162         public final QComboBox notebookBox;\r
163         private final QLabel notebookLabel;\r
164         private final QLabel createdLabel;\r
165         public final QComboBox fontSize;\r
166         public final QAction    fontSizeAction;\r
167         private boolean extendedOn;\r
168         public boolean buttonsVisible;\r
169         private final String iconPath;\r
170         public final ContentView browser;\r
171         private final QTextEdit sourceEdit;\r
172         private String sourceEditHeader;\r
173         Highlighter syntaxHighlighter;\r
174         private List<Tag> allTags;\r
175         private List<String> currentTags;\r
176         public NoteSignal noteSignal;\r
177         public Signal2<String,String> evernoteLinkClicked;\r
178         private List<Notebook> notebookList;\r
179         private Note currentNote;\r
180         private String saveNoteTitle;\r
181         private String saveTagList;\r
182         private boolean insideList;\r
183         private final DatabaseConnection conn;\r
184         private final QCalendarWidget createdCalendarWidget;\r
185         private final QCalendarWidget alteredCalendarWidget;\r
186         private final QCalendarWidget subjectCalendarWidget;\r
187 \r
188         public final QPushButton undoButton;\r
189         public final QAction    undoAction;\r
190         public final QPushButton redoButton;\r
191         public final QAction    redoAction;\r
192         public final QPushButton cutButton;\r
193         public final QAction    cutAction;\r
194         public final QPushButton copyButton;\r
195         public final QAction    copyAction;\r
196         public final QPushButton pasteButton;\r
197         public final QAction    pasteAction;\r
198         public final QPushButton boldButton;\r
199         public final QAction    boldAction;\r
200         public final QPushButton underlineButton;\r
201         public final QAction    underlineAction;\r
202         public final QPushButton italicButton;\r
203         public final QAction    italicAction;\r
204         public final Signal0 focusLost;\r
205         public final NoteResourceSignal resourceSignal;\r
206 \r
207         public QPushButton rightAlignButton;\r
208         public final QAction    rightAlignAction;\r
209         public QPushButton leftAlignButton;\r
210         public final QAction    leftAlignAction;\r
211         public QPushButton centerAlignButton;\r
212         public final QAction    centerAlignAction;\r
213 \r
214         public final QPushButton strikethroughButton;\r
215         public final QAction    strikethroughAction;\r
216         public final QPushButton hlineButton;\r
217         public final QAction    hlineAction;\r
218         public final QPushButton indentButton;\r
219         public final QAction    indentAction;\r
220         public final QPushButton outdentButton;\r
221         public final QAction    outdentAction;\r
222         public final QPushButton bulletListButton;\r
223         public final QAction    bulletListAction;\r
224         public final QPushButton numberListButton;\r
225         public final QAction    numberListAction;\r
226         public final QPushButton spellCheckButton;\r
227         public final QAction    spellCheckAction;\r
228         public final QPushButton todoButton;\r
229         public final QAction    todoAction;\r
230 \r
231         public final QShortcut focusTitleShortcut;\r
232         public final QShortcut focusTagShortcut;\r
233         public final QShortcut focusNoteShortcut;\r
234         public final QShortcut focusUrlShortcut;\r
235         public final QShortcut focusAuthorShortcut;\r
236         \r
237         public EditorButtonBar buttonLayout;\r
238         public final QComboBox fontList;\r
239         public final QAction    fontListAction;\r
240         public final QToolButton fontColor;\r
241         public final QAction    fontColorAction;\r
242         private final ColorMenu fontColorMenu;\r
243         public final QToolButton fontHilight;\r
244         public final QAction    fontHilightAction;\r
245         private final ColorMenu fontHilightColorMenu;\r
246         public final QFileSystemWatcher fileWatcher;\r
247         public int cursorPosition;\r
248         private boolean forceTextPaste;\r
249         private String selectedFile;\r
250         private String currentHyperlink;\r
251         public boolean keepPDFNavigationHidden;\r
252         private final ApplicationLogger logger;\r
253         SpellDictionary dictionary;\r
254     SpellDictionary userDictionary;\r
255     SpellChecker spellChecker;\r
256     SuggestionListener spellListener;\r
257         private final HashMap<String,Integer> previewPageList;  \r
258         boolean insertHyperlink;\r
259         boolean insideTable;\r
260         boolean insideEncryption;\r
261         public Signal1<BrowserWindow> blockApplication;\r
262         public Signal0 unblockApplication;\r
263         public boolean awaitingHttpResponse;\r
264         public long     unblockTime;\r
265         private final QTimer setSourceTimer;\r
266         String latexGuid;  // This is set if we are editing an existing LaTeX formula.  Useful to track guid.\r
267 \r
268         \r
269         public static class SuggestionListener implements SpellCheckListener {\r
270                 public boolean abortSpellCheck = false;\r
271                 public boolean errorsFound = false;\r
272                 private final SpellCheck                spellCheckDialog;\r
273                 \r
274                 \r
275                 private final BrowserWindow parent;\r
276                 public SuggestionListener(BrowserWindow parent, SpellChecker checker) {\r
277                         this.parent = parent;\r
278                         spellCheckDialog = new SpellCheck(checker);\r
279                 }\r
280                 public void spellingError(SpellCheckEvent event) {\r
281                         errorsFound = true;\r
282                         spellCheckDialog.setWord(event.getInvalidWord());\r
283 \r
284                     @SuppressWarnings("unchecked")\r
285                         List<Word> suggestions = event.getSuggestions();\r
286                     spellCheckDialog.clearSuggestions();\r
287                     if (!suggestions.isEmpty()) {\r
288 //                     spellCheckDialog.setCurrentSuggestion(suggestions.get(0).getWord());\r
289                        for (int i=0; i<suggestions.size(); i++) {\r
290                           spellCheckDialog.addSuggestion(suggestions.get(i).getWord());\r
291                        }\r
292                        spellCheckDialog.setSelectedSuggestion(0);\r
293                     }\r
294                     spellCheckDialog.exec();\r
295                     if (spellCheckDialog.cancelPressed()) {\r
296                         abortSpellCheck = true;\r
297                         event.cancel();\r
298                         return;\r
299                     }\r
300                     if (spellCheckDialog.replacePressed()) {\r
301                         QClipboard clipboard = QApplication.clipboard();\r
302                         clipboard.setText(spellCheckDialog.getReplacementWord()); \r
303                         parent.pasteClicked();\r
304                     }\r
305                     event.cancel();\r
306                  }\r
307         }\r
308 \r
309         \r
310         \r
311         public BrowserWindow(DatabaseConnection c) {\r
312                 logger = new ApplicationLogger("browser.log");\r
313                 logger.log(logger.HIGH, "Setting up browser");\r
314                 iconPath = new String("classpath:cx/fbn/nevernote/icons/");\r
315                 forceTextPaste = false;\r
316                 insertHyperlink = true;\r
317                 insideTable = false;\r
318                 insideEncryption = false;\r
319                 \r
320                 fileWatcher = new QFileSystemWatcher();\r
321 //              fileWatcher.fileChanged.connect(this, "fileChanged(String)");\r
322                 noteSignal = new NoteSignal();\r
323                 titleLabel = new QLineEdit();\r
324                 evernoteLinkClicked = new Signal2<String,String>();\r
325                 titleLabel.setMaxLength(Constants.EDAM_NOTE_TITLE_LEN_MAX);\r
326                 urlText = new QLineEdit();\r
327                 authorText = new QLineEdit();\r
328                 geoBox = new QComboBox();\r
329                 urlLabel = new QPushButton();\r
330                 urlLabel.clicked.connect(this, "sourceUrlClicked()");\r
331                 authorLabel = new QLabel();\r
332                 conn = c;\r
333                 \r
334                 focusLost = new Signal0();\r
335 \r
336                 tagEdit = new TagLineEdit(allTags);\r
337                 tagLabel = new QLabel(tr("Tags:"));\r
338                 tagEdit.focusLost.connect(this, "modifyTagsTyping()");\r
339 \r
340                 createdCalendarWidget = new QCalendarWidget();\r
341                 createdDate = new QDateEdit();\r
342                 createdDate.setDisplayFormat(Global.getDateFormat());\r
343                 createdDate.setCalendarPopup(true);\r
344                 createdDate.setCalendarWidget(createdCalendarWidget);\r
345                 createdTime = new QTimeEdit();\r
346                 createdDate.dateChanged.connect(this, "createdChanged()");\r
347                 createdTime.timeChanged.connect(this, "createdChanged()");\r
348 \r
349                 alteredCalendarWidget = new QCalendarWidget();\r
350                 alteredDate = new QDateEdit();\r
351                 alteredDate.setDisplayFormat(Global.getDateFormat());\r
352                 alteredDate.setCalendarPopup(true);\r
353                 alteredDate.setCalendarWidget(alteredCalendarWidget);\r
354                 alteredTime = new QTimeEdit();\r
355                 alteredLabel = new QLabel(tr("Altered:"));\r
356                 alteredDate.dateChanged.connect(this, "alteredChanged()");\r
357                 alteredTime.timeChanged.connect(this, "alteredChanged()");\r
358 \r
359                 subjectCalendarWidget = new QCalendarWidget();\r
360                 subjectDate = new QDateEdit();\r
361                 subjectDate.setDisplayFormat(Global.getDateFormat());\r
362                 subjectDate.setCalendarPopup(true);\r
363                 subjectDate.setCalendarWidget(subjectCalendarWidget);\r
364                 subjectTime = new QTimeEdit();\r
365                 subjectLabel = new QLabel(tr("Subject Date:"));\r
366                 subjectDate.dateChanged.connect(this, "subjectDateTimeChanged()");\r
367                 subjectTime.timeChanged.connect(this, "subjectDateTimeChanged()");\r
368                 authorText.textChanged.connect(this, "authorChanged()");\r
369                 urlText.textChanged.connect(this, "sourceUrlChanged()");\r
370 \r
371                 notebookBox = new QComboBox();\r
372                 notebookLabel = new QLabel(tr("Notebook"));\r
373                 createdLabel = new QLabel(tr("Created:"));\r
374                 // selectedText = new String();\r
375 \r
376                 urlLabel.setVisible(false);\r
377                 urlText.setVisible(false);\r
378                 authorLabel.setVisible(false);\r
379                 \r
380                 geoBox.setVisible(false);\r
381                 geoBox.addItem(new QIcon(iconPath+"globe.png"), "");\r
382                 geoBox.addItem(new String(tr("Set")));\r
383                 geoBox.addItem(new String(tr("Clear")));\r
384                 geoBox.addItem(new String(tr("View On Map")));\r
385                 geoBox.activated.connect(this, "geoBoxChanged()");\r
386                 \r
387                 authorText.setVisible(false);\r
388                 createdDate.setVisible(false);\r
389                 alteredLabel.setVisible(false);\r
390                 //notebookBox.setVisible(false);\r
391                 notebookLabel.setVisible(false);\r
392                 createdLabel.setVisible(false);\r
393                 createdTime.setVisible(false);\r
394                 alteredDate.setVisible(false);\r
395                 alteredTime.setVisible(false);\r
396                 subjectLabel.setVisible(false);\r
397                 subjectDate.setVisible(false);\r
398                 subjectTime.setVisible(false);\r
399                 extendedOn = false;\r
400                 buttonsVisible = true;\r
401                 setAcceptDrops(true);\r
402 \r
403                 browser = new ContentView(this);\r
404                                 \r
405                 browser.page().setLinkDelegationPolicy(\r
406                                 QWebPage.LinkDelegationPolicy.DelegateAllLinks);\r
407                 browser.linkClicked.connect(this, "linkClicked(QUrl)");\r
408                 currentHyperlink = "";\r
409                 \r
410                 //Setup the source editor\r
411                 sourceEdit = new QTextEdit(this);\r
412                 sourceEdit.setVisible(false);\r
413                 sourceEdit.setTabChangesFocus(true);\r
414                 sourceEdit.setLineWrapMode(LineWrapMode.NoWrap);\r
415                 QFont font = new QFont();\r
416                 font.setFamily("Courier");\r
417                 font.setFixedPitch(true);\r
418                 font.setPointSize(10);\r
419                 sourceEdit.setFont(font);\r
420                 syntaxHighlighter = new Highlighter(sourceEdit.document());\r
421                 sourceEdit.textChanged.connect(this, "sourceEdited()");\r
422 \r
423                 QVBoxLayout v = new QVBoxLayout();\r
424                 QFormLayout notebookLayout = new QFormLayout();\r
425                 QGridLayout dateLayout = new QGridLayout();\r
426                 titleLabel.setReadOnly(false);\r
427                 titleLabel.editingFinished.connect(this, "titleEdited()");\r
428                 browser.page().contentsChanged.connect(this, "contentChanged()");\r
429                 browser.page().selectionChanged.connect(this, "selectionChanged()");\r
430                 browser.page().mainFrame().javaScriptWindowObjectCleared.connect(this,\r
431                                 "exposeToJavascript()");\r
432 \r
433                 notebookBox.activated.connect(this, "notebookChanged()");\r
434                 resourceSignal = new NoteResourceSignal();\r
435                 \r
436                 QHBoxLayout tagLayout = new QHBoxLayout();\r
437                 v.addWidget(titleLabel, 0);\r
438                 notebookLayout.addRow(notebookLabel, notebookBox);\r
439                 tagLayout.addLayout(notebookLayout, 0);\r
440                 tagLayout.stretch(4);\r
441                 tagLayout.addWidget(tagLabel, 0);\r
442                 tagLayout.addWidget(tagEdit, 1);\r
443                 v.addLayout(tagLayout);\r
444 \r
445                 QHBoxLayout urlLayout = new QHBoxLayout();\r
446                 urlLayout.addWidget(urlLabel, 0);\r
447                 urlLayout.addWidget(urlText, 0);\r
448                 v.addLayout(urlLayout);\r
449 \r
450                 QHBoxLayout authorLayout = new QHBoxLayout();\r
451                 authorLayout.addWidget(authorLabel, 0);\r
452                 authorLayout.addWidget(authorText, 0);\r
453                 authorLayout.addWidget(geoBox);\r
454                 v.addLayout(authorLayout);\r
455 \r
456                 dateLayout.addWidget(createdLabel, 0, 0);\r
457                 dateLayout.addWidget(createdDate, 0, 1);\r
458                 dateLayout.addWidget(createdTime, 0, 2);\r
459                 dateLayout.setColumnStretch(9, 100);\r
460                 dateLayout.addWidget(alteredLabel, 0, 3);\r
461                 dateLayout.addWidget(alteredDate, 0, 4);\r
462                 dateLayout.addWidget(alteredTime, 0, 5);\r
463                 dateLayout.addWidget(subjectLabel, 0, 6);\r
464                 dateLayout.addWidget(subjectDate, 0, 7);\r
465                 dateLayout.addWidget(subjectTime, 0, 8);\r
466                 v.addLayout(dateLayout, 0);\r
467 \r
468                 undoButton = newEditorButton("undo", tr("Undo Change"));\r
469                 redoButton = newEditorButton("redo", tr("Redo Change"));\r
470                 cutButton = newEditorButton("cut", tr("Cut"));\r
471                 copyButton = newEditorButton("copy", tr("Copy"));\r
472                 pasteButton = newEditorButton("paste", tr("Paste"));\r
473                 boldButton = newEditorButton("bold", tr("Bold"));\r
474                 underlineButton = newEditorButton("underline", tr("Underline"));\r
475                 italicButton = newEditorButton("italic", tr("Italic"));\r
476 \r
477                 rightAlignButton = newEditorButton("justifyRight", tr("Right Align"));\r
478                 leftAlignButton = newEditorButton("justifyLeft", tr("Left Align"));\r
479                 centerAlignButton = newEditorButton("justifyCenter", tr("Center Align"));\r
480 \r
481                 strikethroughButton = newEditorButton("strikethrough", tr("Strikethrough"));\r
482                 hlineButton = newEditorButton("hline", tr("Insert Horizontal Line"));\r
483                 indentButton = newEditorButton("indent", tr("Shift Right"));\r
484                 outdentButton = newEditorButton("outdent", tr("Shift Left"));\r
485                 bulletListButton = newEditorButton("bulletList", tr("Bullet List"));\r
486                 numberListButton = newEditorButton("numberList", tr("Number List"));\r
487                 spellCheckButton = newEditorButton("spellCheck", tr("Spell Check"));\r
488                 todoButton = newEditorButton("todo", tr("To-do"));\r
489 \r
490                 \r
491                 buttonLayout = new EditorButtonBar();\r
492                 v.addWidget(buttonLayout);\r
493                 \r
494                 undoAction = buttonLayout.addWidget(undoButton);\r
495                 buttonLayout.toggleUndoVisible.triggered.connect(this, "toggleUndoVisible(Boolean)");\r
496                 redoAction = buttonLayout.addWidget(redoButton);\r
497                 buttonLayout.toggleRedoVisible.triggered.connect(this, "toggleRedoVisible(Boolean)");\r
498                 \r
499                 buttonLayout.addWidget(newSeparator());\r
500                 cutAction = buttonLayout.addWidget(cutButton);\r
501                 buttonLayout.toggleCutVisible.triggered.connect(this, "toggleCutVisible(Boolean)");\r
502                 copyAction = buttonLayout.addWidget(copyButton);\r
503                 buttonLayout.toggleCopyVisible.triggered.connect(this, "toggleCopyVisible(Boolean)");\r
504                 pasteAction = buttonLayout.addWidget(pasteButton);\r
505                 buttonLayout.togglePasteVisible.triggered.connect(this, "togglePasteVisible(Boolean)");\r
506 \r
507                 buttonLayout.addWidget(newSeparator());\r
508                 boldAction = buttonLayout.addWidget(boldButton);\r
509                 buttonLayout.toggleBoldVisible.triggered.connect(this, "toggleBoldVisible(Boolean)");\r
510                 italicAction = buttonLayout.addWidget(italicButton);\r
511                 buttonLayout.toggleItalicVisible.triggered.connect(this, "toggleItalicVisible(Boolean)");\r
512                 underlineAction = buttonLayout.addWidget(underlineButton);\r
513                 buttonLayout.toggleUnderlineVisible.triggered.connect(this, "toggleUnderlineVisible(Boolean)");\r
514                 strikethroughAction = buttonLayout.addWidget(strikethroughButton);\r
515                 buttonLayout.toggleStrikethroughVisible.triggered.connect(this, "toggleStrikethroughVisible(Boolean)");\r
516 \r
517                 \r
518                 buttonLayout.addWidget(newSeparator());\r
519                 leftAlignAction = buttonLayout.addWidget(leftAlignButton);\r
520                 buttonLayout.toggleLeftAlignVisible.triggered.connect(this, "toggleLeftAlignVisible(Boolean)");\r
521                 centerAlignAction = buttonLayout.addWidget(centerAlignButton);\r
522                 buttonLayout.toggleCenterAlignVisible.triggered.connect(this, "toggleCenterAlignVisible(Boolean)");\r
523                 rightAlignAction = buttonLayout.addWidget(rightAlignButton);\r
524                 buttonLayout.toggleRightAlignVisible.triggered.connect(this, "toggleRightAlignVisible(Boolean)");\r
525 \r
526                 buttonLayout.addWidget(newSeparator());\r
527                 hlineAction = buttonLayout.addWidget(hlineButton);\r
528                 buttonLayout.toggleHLineVisible.triggered.connect(this, "toggleHLineVisible(Boolean)");\r
529 \r
530                 indentAction = buttonLayout.addWidget(indentButton);\r
531                 buttonLayout.toggleIndentVisible.triggered.connect(this, "toggleIndentVisible(Boolean)");\r
532                 outdentAction = buttonLayout.addWidget(outdentButton);\r
533                 buttonLayout.toggleOutdentVisible.triggered.connect(this, "toggleOutdentVisible(Boolean)");\r
534                 bulletListAction = buttonLayout.addWidget(bulletListButton);\r
535                 buttonLayout.toggleBulletListVisible.triggered.connect(this, "toggleBulletListVisible(Boolean)");\r
536                 numberListAction = buttonLayout.addWidget(numberListButton);\r
537                 buttonLayout.toggleNumberListVisible.triggered.connect(this, "toggleNumberListVisible(Boolean)");\r
538 \r
539                 // Setup the font & font size combo boxes\r
540                 buttonLayout.addWidget(newSeparator());\r
541                 fontList = new QComboBox();\r
542                 fontSize = new QComboBox();\r
543                 fontList.setToolTip("Font");\r
544                 fontSize.setToolTip("Font Size");\r
545                 fontList.activated.connect(this, "fontChanged(String)");\r
546                 fontSize.activated.connect(this, "fontSizeChanged(String)");\r
547                 fontListAction = buttonLayout.addWidget(fontList);\r
548                 buttonLayout.toggleFontVisible.triggered.connect(this, "toggleFontListVisible(Boolean)");\r
549                 fontSizeAction = buttonLayout.addWidget(fontSize);\r
550                 buttonLayout.toggleFontSizeVisible.triggered.connect(this, "toggleFontSizeVisible(Boolean)");\r
551                 QFontDatabase fonts = new QFontDatabase();\r
552                 List<String> fontFamilies = fonts.families();\r
553                 for (int i = 0; i < fontFamilies.size(); i++) {\r
554                         fontList.addItem(fontFamilies.get(i));\r
555                         if (i == 0) {\r
556                                 loadFontSize(fontFamilies.get(i));\r
557                         }\r
558                 }\r
559 \r
560 //              buttonLayout.addWidget(newSeparator(), 0);\r
561                 fontColor = newToolButton("fontColor", tr("Font Color"));\r
562                 fontColorMenu = new ColorMenu(this);\r
563                 fontColor.setMenu(fontColorMenu.getMenu());\r
564                 fontColor.setPopupMode(ToolButtonPopupMode.MenuButtonPopup);\r
565                 fontColor.setAutoRaise(false);\r
566                 fontColorMenu.getMenu().triggered.connect(this, "fontColorClicked()");\r
567                 fontColorAction = buttonLayout.addWidget(fontColor);\r
568                 buttonLayout.toggleFontColorVisible.triggered.connect(this, "toggleFontColorVisible(Boolean)");\r
569                 fontHilight = newToolButton("fontHilight", tr("Font Hilight Color"));\r
570                 fontHilight.setPopupMode(ToolButtonPopupMode.MenuButtonPopup);\r
571                 fontHilight.setAutoRaise(false);\r
572                 fontHilightColorMenu = new ColorMenu(this);\r
573                 fontHilightColorMenu.setDefault(QColor.yellow);\r
574                 fontHilight.setMenu(fontHilightColorMenu.getMenu());\r
575                 fontHilightColorMenu.getMenu().triggered.connect(this, "fontHilightClicked()");\r
576                 fontHilightAction = buttonLayout.addWidget(fontHilight);\r
577                 fontHilightColorMenu.setDefault(QColor.yellow);\r
578                 buttonLayout.toggleFontHilight.triggered.connect(this, "toggleFontHilightVisible(Boolean)");\r
579                 \r
580                 spellCheckAction = buttonLayout.addWidget(spellCheckButton);\r
581                 buttonLayout.toggleNumberListVisible.triggered.connect(this, "spellCheckClicked()");\r
582                 buttonLayout.toggleSpellCheck.triggered.connect(this, "toggleSpellCheckVisible(Boolean)");\r
583                 \r
584                 todoAction = buttonLayout.addWidget(todoButton);\r
585                 buttonLayout.toggleNumberListVisible.triggered.connect(this, "todoClicked()");\r
586                 buttonLayout.toggleTodo.triggered.connect(this, "toggleTodoVisible(Boolean)");\r
587 \r
588                 // Setup the source browser);\r
589 \r
590 //              buttonLayout.addWidget(new QLabel(), 1);\r
591                 QSplitter editSplitter = new QSplitter(this);\r
592                 editSplitter.addWidget(browser);\r
593                 editSplitter.setOrientation(Qt.Orientation.Vertical);\r
594                 editSplitter.addWidget(sourceEdit);\r
595 \r
596                 \r
597 \r
598 //              v.addWidget(browser, 1);\r
599 //              v.addWidget(sourceEdit);\r
600                 v.addWidget(editSplitter);\r
601                 setLayout(v);\r
602 \r
603                 browser.downloadAttachmentRequested.connect(this,\r
604                                 "downloadAttachment(QNetworkRequest)");\r
605                 browser.downloadImageRequested.connect(this,\r
606                                 "downloadImage(QNetworkRequest)");\r
607                 setTabOrder(notebookBox, tagEdit);\r
608                 setTabOrder(tagEdit, browser);\r
609                 \r
610                 focusNoteShortcut = new QShortcut(this);\r
611                 setupShortcut(focusNoteShortcut, "Focus_Note");\r
612                 focusNoteShortcut.activated.connect(this, "focusNote()");\r
613                 focusTitleShortcut = new QShortcut(this);\r
614                 setupShortcut(focusTitleShortcut, "Focus_Title");\r
615                 focusTitleShortcut.activated.connect(this, "focusTitle()");\r
616                 focusTagShortcut = new QShortcut(this);\r
617                 setupShortcut(focusTagShortcut, "Focus_Tag");\r
618                 focusTagShortcut.activated.connect(this, "focusTag()");\r
619                 focusAuthorShortcut = new QShortcut(this);\r
620                 setupShortcut(focusAuthorShortcut, "Focus_Author");\r
621                 focusAuthorShortcut.activated.connect(this, "focusAuthor()");\r
622                 focusUrlShortcut = new QShortcut(this);\r
623                 setupShortcut(focusUrlShortcut, "Focus_Url");\r
624                 focusUrlShortcut.activated.connect(this, "focusUrl()");\r
625                 \r
626                 browser.page().mainFrame().setTextSizeMultiplier(Global.getTextSizeMultiplier());\r
627                 browser.page().mainFrame().setZoomFactor(Global.getZoomFactor());\r
628                 \r
629                 previewPageList = new HashMap<String,Integer>();\r
630                 \r
631                 browser.page().microFocusChanged.connect(this, "microFocusChanged()");\r
632                 \r
633                 //Setup colors\r
634                 \r
635                 QPalette pal = new QPalette();\r
636                 pal.setColor(ColorRole.Text, QColor.black);\r
637                 titleLabel.setPalette(pal);\r
638                 authorText.setPalette(pal);\r
639                 authorLabel.setPalette(pal);\r
640                 urlLabel.setPalette(pal);\r
641                 urlText.setPalette(pal);\r
642                 createdDate.setPalette(pal);\r
643                 createdTime.setPalette(pal);\r
644                 alteredDate.setPalette(pal);\r
645                 alteredTime.setPalette(pal);\r
646                 subjectDate.setPalette(pal);\r
647                 subjectTime.setPalette(pal);\r
648                 tagEdit.setPalette(pal);\r
649                 notebookBox.setPalette(pal);\r
650                 \r
651                 blockApplication = new Signal1<BrowserWindow>();\r
652                 unblockApplication = new Signal0();\r
653                 \r
654                 setSourceTimer = new QTimer();\r
655                 setSourceTimer.timeout.connect(this, "setSource()");\r
656                 \r
657                 logger.log(logger.HIGH, "Browser setup complete");\r
658         }\r
659 \r
660         \r
661         \r
662         private void setupShortcut(QShortcut action, String text) {\r
663                 if (!Global.shortcutKeys.containsAction(text))\r
664                         return;\r
665                 action.setKey(new QKeySequence(Global.shortcutKeys.getShortcut(text)));\r
666         }\r
667         \r
668         \r
669 \r
670         \r
671         // Getter for the QWebView\r
672         public QWebView getBrowser() {\r
673                 return browser;\r
674         }\r
675 \r
676         // Block signals while loading data or things are flagged as dirty by\r
677         // mistake\r
678         public void loadingData(boolean val) {\r
679                 logger.log(logger.EXTREME, "Entering BrowserWindow.loadingData() " +val);\r
680                 notebookBox.blockSignals(val);\r
681                 browser.page().blockSignals(val);\r
682                 browser.page().mainFrame().blockSignals(val);\r
683                 titleLabel.blockSignals(val);\r
684                 alteredDate.blockSignals(val);\r
685                 alteredTime.blockSignals(val);\r
686                 createdTime.blockSignals(val);\r
687                 createdDate.blockSignals(val);\r
688                 subjectDate.blockSignals(val);\r
689                 subjectTime.blockSignals(val);\r
690                 urlText.blockSignals(val);\r
691                 authorText.blockSignals(val);\r
692                 if (!val)\r
693                         exposeToJavascript();\r
694                 logger.log(logger.EXTREME, "Exiting BrowserWindow.loadingData() " +val);\r
695         }\r
696 \r
697         // Enable/disable\r
698         public void setReadOnly(boolean v) {\r
699                 setEnabled(true);\r
700                 titleLabel.setEnabled(!v);\r
701                 notebookBox.setEnabled(!v);\r
702                 tagEdit.setEnabled(!v);\r
703                 authorLabel.setEnabled(!v);\r
704                 geoBox.setEnabled(!v);\r
705                 urlText.setEnabled(!v);\r
706                 createdDate.setEnabled(!v);\r
707                 subjectDate.setEnabled(!v);\r
708                 alteredDate.setEnabled(!v);\r
709                 authorText.setEnabled(!v);\r
710                 createdTime.setEnabled(!v);\r
711                 alteredTime.setEnabled(!v);\r
712                 subjectTime.setEnabled(!v);\r
713                 getBrowser().setEnabled(true);\r
714                 getBrowser().page().setContentEditable(!v);\r
715 //              getBrowser().setEnabled(!v);\r
716         }\r
717         \r
718         // expose this class to Javascript on the web page\r
719         private void exposeToJavascript() {\r
720                 browser.page().mainFrame().addToJavaScriptWindowObject("jambi", this);\r
721         }\r
722 \r
723         // Custom event queue\r
724         @Override\r
725         public boolean event(QEvent e) {\r
726                 if (e.type().equals(QEvent.Type.FocusOut)) {\r
727                         logger.log(logger.EXTREME, "Focus lost");\r
728                         focusLost.emit();\r
729                 }\r
730                 return super.event(e);\r
731         }\r
732 \r
733         // clear out browser\r
734         public void clear() {\r
735                 logger.log(logger.EXTREME, "Entering BrowserWindow.clear()");\r
736                 setNote(null);\r
737                 setContent(new QByteArray());\r
738                 tagEdit.setText("");\r
739                 tagEdit.tagCompleter.reset();\r
740                 urlLabel.setText(tr("Source URL:"));\r
741                 titleLabel.setText("");\r
742                 logger.log(logger.EXTREME, "Exiting BrowserWindow.clear()");\r
743         }\r
744 \r
745         public void setContent(QByteArray data) {\r
746                 sourceEdit.blockSignals(true);\r
747                 browser.setContent(data);\r
748                 setSource();\r
749         }\r
750         // get/set current note\r
751         public void setNote(Note n) {\r
752                 currentNote = n;\r
753                 if (n == null)\r
754                         n = new Note();\r
755                 saveNoteTitle = n.getTitle();\r
756 \r
757         }\r
758 \r
759         public Note getNote() {\r
760                 return currentNote;\r
761         }\r
762 \r
763         // New Editor Button\r
764         private QPushButton newEditorButton(String name, String toolTip) {\r
765                 QPushButton button = new QPushButton();\r
766 //              QIcon icon = new QIcon(iconPath + name + ".gif");\r
767                 QIcon icon = new QIcon(iconPath + name + ".png");\r
768                 button.setIcon(icon);\r
769                 button.setToolTip(toolTip);\r
770                 button.clicked.connect(this, name + "Clicked()");\r
771                 return button;\r
772         }\r
773         // New Editor Button\r
774         private QToolButton newToolButton(String name, String toolTip) {\r
775                 QToolButton button = new QToolButton();\r
776 //              QIcon icon = new QIcon(iconPath + name + ".gif");\r
777                 QIcon icon = new QIcon(iconPath + name + ".png");\r
778                 button.setIcon(icon);\r
779                 button.setToolTip(toolTip);\r
780                 button.clicked.connect(this, name + "Clicked()");\r
781                 return button;\r
782         }\r
783 \r
784         // New Separator\r
785         private QLabel newSeparator() {\r
786                 return new QLabel("   ");\r
787         }\r
788 \r
789         // Set the title in the window\r
790         public void setTitle(String t) {\r
791                 titleLabel.setText(t);\r
792                 saveNoteTitle = t;\r
793                 checkNoteTitle();\r
794         }\r
795 \r
796         // Return the current text title\r
797         public String getTitle() {\r
798                 return titleLabel.text();\r
799         }\r
800 \r
801         // Set the tag name string\r
802         public void setTag(String t) {\r
803                 saveTagList = t;\r
804                 tagEdit.setText(t);\r
805                 tagEdit.tagCompleter.reset();\r
806         }\r
807 \r
808         // Set the source URL\r
809         public void setUrl(String t) {\r
810                 urlLabel.setText(tr("Source URL:\t"));\r
811                 urlText.setText(t);\r
812         }\r
813 \r
814         // The user want's to launch a web browser on the source of the URL\r
815         public void sourceUrlClicked() {\r
816                 // Make sure we have a valid URL\r
817                 if (urlText.text().trim().equals(""))\r
818                         return;\r
819                 \r
820                 String url = urlText.text();\r
821                 if (!url.toLowerCase().startsWith(tr("http://")))\r
822                         url = tr("http://") +url;\r
823                 \r
824         if (!QDesktopServices.openUrl(new QUrl(url))) {\r
825                 logger.log(logger.LOW, "Error opening file :" +url);\r
826         }\r
827         }\r
828         \r
829         public void setAuthor(String t) {\r
830                 authorLabel.setText(tr("Author:\t"));\r
831                 authorText.setText(t);\r
832         }\r
833 \r
834         // Set the creation date\r
835         public void setCreation(long date) {\r
836                 QDateTime dt = new QDateTime();\r
837                 dt.setTime_t((int) (date / 1000));\r
838                 createdDate.setDateTime(dt);\r
839                 createdTime.setDateTime(dt);\r
840                 createdDate.setDisplayFormat(Global.getDateFormat());\r
841                 createdTime.setDisplayFormat(Global.getTimeFormat());\r
842         }\r
843 \r
844         // Set the creation date\r
845         public void setAltered(long date) {\r
846                 QDateTime dt = new QDateTime();\r
847                 dt.setTime_t((int) (date / 1000));\r
848                 alteredDate.setDateTime(dt);\r
849                 alteredTime.setDateTime(dt);\r
850                 alteredDate.setDisplayFormat(Global.getDateFormat());\r
851                 alteredTime.setDisplayFormat(Global.getTimeFormat());\r
852         }\r
853 \r
854         // Set the subject date\r
855         public void setSubjectDate(long date) {\r
856                 QDateTime dt = new QDateTime();\r
857                 dt.setTime_t((int) (date / 1000));\r
858                 subjectDate.setDateTime(dt);\r
859                 subjectTime.setDateTime(dt);\r
860                 subjectDate.setDisplayFormat(Global.getDateFormat());\r
861                 subjectTime.setDisplayFormat(Global.getTimeFormat());\r
862         }\r
863 \r
864         // Toggle the extended attribute information\r
865         public void toggleInformation() {\r
866                 if (extendedOn) {\r
867                         extendedOn = false;\r
868                 } else {\r
869                         extendedOn = true;\r
870                 }\r
871                 urlLabel.setVisible(extendedOn);\r
872                 urlText.setVisible(extendedOn);\r
873                 authorText.setVisible(extendedOn);\r
874                 geoBox.setVisible(extendedOn);\r
875                 authorLabel.setVisible(extendedOn);\r
876                 createdDate.setVisible(extendedOn);\r
877                 createdTime.setVisible(extendedOn);\r
878                 createdLabel.setVisible(extendedOn);\r
879                 alteredLabel.setVisible(extendedOn);\r
880                 alteredDate.setVisible(extendedOn);\r
881                 alteredTime.setVisible(extendedOn);\r
882                 //notebookBox.setVisible(extendedOn);\r
883                 notebookLabel.setVisible(extendedOn);\r
884                 subjectLabel.setVisible(extendedOn);\r
885                 subjectDate.setVisible(extendedOn);\r
886                 subjectTime.setVisible(extendedOn);\r
887         }\r
888 \r
889         public void hideButtons() {\r
890 \r
891                 undoButton.parentWidget().setVisible(false);\r
892                 buttonsVisible = false;\r
893         }\r
894 \r
895 \r
896         // Is the extended view on?\r
897         public boolean isExtended() {\r
898                 return extendedOn;\r
899         }\r
900 \r
901         // Listener for when a link is clicked\r
902         @SuppressWarnings("unused")\r
903         private void openFile() {\r
904                 logger.log(logger.EXTREME, "Starting openFile()");\r
905                 File fileHandle = new File(selectedFile);\r
906                 URI fileURL = fileHandle.toURI();\r
907                 String localURL = fileURL.toString();\r
908                 QUrl url = new QUrl(localURL);\r
909                 QFile file = new QFile(selectedFile);\r
910                 \r
911                 logger.log(logger.EXTREME, "Adding to fileWatcher:"+file.fileName());\r
912                 fileWatcher.addPath(file.fileName());\r
913         \r
914         if (!QDesktopServices.openUrl(url)) {\r
915                 logger.log(logger.LOW, "Error opening file :" +url);\r
916         }\r
917         }\r
918         \r
919         \r
920         // Listener for when a link is clicked\r
921         @SuppressWarnings("unused")\r
922         private void linkClicked(QUrl url) {\r
923                 logger.log(logger.EXTREME, "URL Clicked: " +url.toString());\r
924                 if (url.toString().startsWith("latex:")) {\r
925                         int position = url.toString().lastIndexOf(".");\r
926                         String guid = url.toString().substring(0,position);\r
927                         position = guid.lastIndexOf("/");\r
928                         guid = guid.substring(position+1);\r
929                         editLatex(guid);\r
930                         return;\r
931                 }\r
932                 if (url.toString().startsWith("evernote:/view/")) {\r
933                         StringTokenizer tokens = new StringTokenizer(url.toString().replace("evernote:/view/", ""), "/");\r
934                         tokens.nextToken();\r
935                         tokens.nextToken();\r
936                         String sid = tokens.nextToken();\r
937                         String lid = tokens.nextToken();\r
938                         \r
939                         // Emit that we want to switch to a new note\r
940                         evernoteLinkClicked.emit(sid, lid);\r
941 \r
942                         return;\r
943                 }\r
944                 if (url.toString().startsWith("nnres://")) {\r
945                         logger.log(logger.EXTREME, "URL is NN resource");\r
946                         if (url.toString().endsWith("/vnd.evernote.ink")) {\r
947                                 logger.log(logger.EXTREME, "Unable to open ink note");\r
948                                 QMessageBox.information(this, tr("Unable Open"), tr("This is an ink note.\n"+\r
949                                         "Ink notes are not supported since Evernote has not\n published any specifications on them\n" +\r
950                                         "and I'm too lazy to figure them out by myself."));\r
951                                 return;\r
952                         }\r
953                         String fullName = url.toString().substring(8);\r
954                         int index = fullName.indexOf(".");\r
955                         String guid = "";\r
956                         String type = "";\r
957                         if (index >-1) {\r
958                                 type = fullName.substring(index+1);\r
959                                 guid = fullName.substring(0,index);\r
960                         }\r
961                         index = guid.indexOf(Global.attachmentNameDelimeter);\r
962                         if (index > -1) {\r
963                                 guid = guid.substring(0,index);\r
964                         }\r
965                         List<Resource> resList = currentNote.getResources();\r
966                         Resource res = null;\r
967                         for (int i=0; i<resList.size(); i++) {\r
968                                 if (resList.get(i).getGuid().equals(guid)) {\r
969                                         res = resList.get(i);\r
970                                         i=resList.size();\r
971                                 }\r
972                         }\r
973                         if (res == null) {\r
974                                 String resGuid = Global.resourceMap.get(guid);\r
975                                 if (resGuid != null) \r
976                                         res = conn.getNoteTable().noteResourceTable.getNoteResource(resGuid, true);\r
977                         }\r
978                         if (res != null) {\r
979                                 String fileName;\r
980                                 if (res.getAttributes() != null && \r
981                                                 res.getAttributes().getFileName() != null && \r
982                                                 !res.getAttributes().getFileName().trim().equals(""))\r
983                                         fileName = res.getGuid()+Global.attachmentNameDelimeter+res.getAttributes().getFileName();\r
984                                 else\r
985                                         fileName = res.getGuid()+"."+type;\r
986                                 QFile file = new QFile(Global.getFileManager().getResDirPath(fileName));\r
987                         QFile.OpenMode mode = new QFile.OpenMode();\r
988                         mode.set(QFile.OpenModeFlag.WriteOnly);\r
989                         boolean openResult = file.open(mode);\r
990                                 logger.log(logger.EXTREME, "File opened:" +openResult);\r
991                         QDataStream out = new QDataStream(file);\r
992                         Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(res.getGuid(), true);\r
993                                 QByteArray binData = new QByteArray(resBinary.getData().getBody());\r
994                                 resBinary = null;\r
995                                 logger.log(logger.EXTREME, "Writing resource");\r
996                         out.writeBytes(binData.toByteArray());\r
997                         file.close();\r
998                                 \r
999                         String whichOS = System.getProperty("os.name");\r
1000                                 if (whichOS.contains("Windows")) \r
1001                                 url.setUrl("file:///"+file.fileName());\r
1002                         else\r
1003                                 url.setUrl("file://"+file.fileName());\r
1004                  //       fileWatcher.removePath(file.fileName());\r
1005                                 logger.log(logger.EXTREME, "Adding file watcher " +file.fileName());\r
1006                                 fileWatcher.addPath(file.fileName());\r
1007                         \r
1008                         // If we can't open it, then prompt the user to save it.\r
1009                         if (!QDesktopServices.openUrl(url)) {\r
1010                                         logger.log(logger.EXTREME, "We can't handle this.  Where do we put it?");\r
1011                                 QFileDialog dialog = new QFileDialog();\r
1012                                 dialog.show();\r
1013                                 if (dialog.exec()!=0) {\r
1014                                         List<String> fileNames = dialog.selectedFiles(); //gets all selected filenames\r
1015                                         if (fileNames.size() == 0) \r
1016                                                 return;\r
1017                                         String sf = fileNames.get(0);\r
1018                                         QFile saveFile = new QFile(sf);\r
1019                                         mode.set(QFile.OpenModeFlag.WriteOnly);\r
1020                                         saveFile.open(mode);\r
1021                                         QDataStream saveOut = new QDataStream(saveFile);\r
1022                                         saveOut.writeBytes(binData.toByteArray());\r
1023                                         saveFile.close();\r
1024                                         return;\r
1025                                 }\r
1026                                 }\r
1027                         }\r
1028                         return;\r
1029                 }\r
1030                 logger.log(logger.EXTREME, "Launching URL");\r
1031                 QDesktopServices.openUrl(url);\r
1032         }\r
1033 \r
1034         // Listener for when BOLD is clicked\r
1035         @SuppressWarnings("unused")\r
1036         private void undoClicked() {\r
1037                 browser.page().triggerAction(WebAction.Undo);\r
1038                 browser.setFocus();\r
1039         }\r
1040 \r
1041         // Listener for when BOLD is clicked\r
1042         @SuppressWarnings("unused")\r
1043         private void redoClicked() {\r
1044                 browser.page().triggerAction(WebAction.Redo);\r
1045                 browser.setFocus();\r
1046         }\r
1047 \r
1048         // Listener for when BOLD is clicked\r
1049         @SuppressWarnings("unused")\r
1050         private void boldClicked() {\r
1051                 browser.page().triggerAction(WebAction.ToggleBold);\r
1052                 microFocusChanged();\r
1053                 browser.setFocus();\r
1054         }\r
1055 \r
1056         // Listener for when Italics is clicked\r
1057         @SuppressWarnings("unused")\r
1058         private void italicClicked() {\r
1059                 browser.page().triggerAction(WebAction.ToggleItalic);\r
1060                 microFocusChanged();\r
1061                 browser.setFocus();\r
1062         }\r
1063 \r
1064         // Listener for when UNDERLINE is clicked\r
1065         @SuppressWarnings("unused")\r
1066         private void underlineClicked() {\r
1067                 browser.page().triggerAction(WebAction.ToggleUnderline);\r
1068                 microFocusChanged();\r
1069                 browser.setFocus();\r
1070         }\r
1071 \r
1072         // Listener for when Strikethrough is clicked\r
1073         @SuppressWarnings("unused")\r
1074         private void strikethroughClicked() {\r
1075                 browser.page().mainFrame().evaluateJavaScript(\r
1076                                 "document.execCommand('strikeThrough', false, '');");\r
1077                 browser.setFocus();\r
1078         }\r
1079 \r
1080         // Listener for when cut is clicked\r
1081         @SuppressWarnings("unused")\r
1082         private void cutClicked() {\r
1083                 browser.page().triggerAction(WebAction.Cut);\r
1084                 browser.setFocus();\r
1085         }\r
1086 \r
1087         // Listener when COPY is clicked\r
1088         @SuppressWarnings("unused")\r
1089         private void copyClicked() {\r
1090                 browser.page().triggerAction(WebAction.Copy);\r
1091                 browser.setFocus();\r
1092         }\r
1093 \r
1094         // Listener when PASTE is clicked\r
1095         public void pasteClicked() {\r
1096                 logger.log(logger.EXTREME, "Paste Clicked");\r
1097                 if (forceTextPaste) {\r
1098                         pasteWithoutFormattingClicked();\r
1099                         return;\r
1100                 }\r
1101                 QClipboard clipboard = QApplication.clipboard();\r
1102                 QMimeData mime = clipboard.mimeData();\r
1103 \r
1104                 if (mime.hasImage()) {\r
1105                         logger.log(logger.EXTREME, "Image paste found");\r
1106                         browser.setFocus();\r
1107                         insertImage(mime);\r
1108                         browser.setFocus();\r
1109                         return;\r
1110                 }\r
1111 \r
1112                 if (mime.hasUrls()) {\r
1113                         logger.log(logger.EXTREME, "URL paste found");\r
1114                         if (mime.text().startsWith("evernote:")) {\r
1115                                 handleNoteLink(mime);\r
1116                         } else {\r
1117                                 handleUrls(mime);\r
1118                                 browser.setFocus();\r
1119                         }\r
1120                         return;\r
1121                 }\r
1122                 \r
1123                 String text = mime.html();\r
1124                 if (text.contains("en-tag") && mime.hasHtml()) {\r
1125                         logger.log(logger.EXTREME, "Intra-note paste found");\r
1126                         text = fixInternotePaste(text);\r
1127                         mime.setHtml(text);\r
1128                         clipboard.setMimeData(mime);\r
1129                 }\r
1130 \r
1131                 logger.log(logger.EXTREME, "Final paste choice encountered");\r
1132                 browser.page().triggerAction(WebAction.Paste);\r
1133                 browser.setFocus();\r
1134 \r
1135         }\r
1136 \r
1137         // Paste text without formatting\r
1138         private void pasteWithoutFormattingClicked() {\r
1139                 logger.log(logger.EXTREME, "Paste without format clipped");\r
1140                 QClipboard clipboard = QApplication.clipboard();\r
1141                 QMimeData mime = clipboard.mimeData();\r
1142                 if (!mime.hasText())\r
1143                         return;\r
1144                 String text = mime.text();\r
1145                 clipboard.clear();\r
1146                 clipboard.setText(text, Mode.Clipboard);\r
1147                 browser.page().triggerAction(WebAction.Paste);\r
1148 \r
1149                 // This is done because pasting into an encryption block\r
1150                 // can cause multiple cells (which can't happen).  It \r
1151                 // just goes through the table, extracts the data, & \r
1152                 // puts it back as one table cell.\r
1153                 if (insideEncryption) {\r
1154                         String js = new String( "function fixEncryption() { "\r
1155                                         +"   var selObj = window.getSelection();"\r
1156                                         +"   var selRange = selObj.getRangeAt(0);"\r
1157                                         +"   var workingNode = window.getSelection().anchorNode;"\r
1158                                         +"   while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { " \r
1159                                         +"           workingNode = workingNode.parentNode;"\r
1160                                         +"   } "\r
1161                                         +"   workingNode.innerHTML = window.jambi.fixEncryptionPaste(workingNode.innerHTML);"\r
1162                                         +"} fixEncryption();");\r
1163                         browser.page().mainFrame().evaluateJavaScript(js);\r
1164                 }\r
1165         }\r
1166         \r
1167         // This basically removes all the table tags and returns just the contents.\r
1168         // This is called by JavaScript to fix encryption pastes.\r
1169         public String fixEncryptionPaste(String data) {\r
1170                 data = data.replace("<tbody>", "");\r
1171                 data = data.replace("</tbody>", "");\r
1172                 data = data.replace("<tr>", "");\r
1173                 data = data.replace("</tr>", "");\r
1174                 data = data.replace("<td>", "");\r
1175                 data = data.replace("</td>", "<br>");\r
1176                 data = data.replace("<br><br>", "<br>");\r
1177 \r
1178                 return "<tbody><tr><td>"+data+"</td></tr></tbody>";\r
1179         }\r
1180         \r
1181         // insert date/time\r
1182         @SuppressWarnings("unused")\r
1183         private void insertDateTime() {\r
1184                 String fmt = Global.getDateFormat() + " " + Global.getTimeFormat();\r
1185                 String dateTimeFormat = new String(fmt);\r
1186                 SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);\r
1187                 Calendar cal = Calendar.getInstance();\r
1188                 \r
1189                 browser.page().mainFrame().evaluateJavaScript(\r
1190                         "document.execCommand('insertHtml', false, '"+simple.format(cal.getTime())+"');");\r
1191                 \r
1192                 browser.setFocus();\r
1193 \r
1194         }\r
1195 \r
1196         // Listener when Left is clicked\r
1197         @SuppressWarnings("unused")\r
1198         private void justifyLeftClicked() {\r
1199                 browser.page().mainFrame().evaluateJavaScript(\r
1200                                 "document.execCommand('JustifyLeft', false, '');");\r
1201                 browser.setFocus();\r
1202         }\r
1203 \r
1204         // Listener when Center is clicked\r
1205         @SuppressWarnings("unused")\r
1206         private void justifyCenterClicked() {\r
1207                 browser.page().mainFrame().evaluateJavaScript(\r
1208                                 "document.execCommand('JustifyCenter', false, '');");\r
1209                 browser.setFocus();\r
1210         }\r
1211 \r
1212         // Listener when Left is clicked\r
1213         @SuppressWarnings("unused")\r
1214         private void justifyRightClicked() {\r
1215                 browser.page().mainFrame().evaluateJavaScript(\r
1216                                 "document.execCommand('JustifyRight', false, '');");\r
1217                 browser.setFocus();\r
1218         }\r
1219 \r
1220         // Listener when HLINE is clicked\r
1221         @SuppressWarnings("unused")\r
1222         private void hlineClicked() {\r
1223                 browser.page().mainFrame().evaluateJavaScript(\r
1224                                 "document.execCommand('insertHorizontalRule', false, '');");\r
1225                 browser.setFocus();\r
1226         }\r
1227 \r
1228         // Listener when outdent is clicked\r
1229         private void outdentClicked() {\r
1230                 browser.page().mainFrame().evaluateJavaScript(\r
1231                                 "document.execCommand('outdent', false, '');");\r
1232                 browser.setFocus();\r
1233         }\r
1234 \r
1235         // Listener when a bullet list is clicked\r
1236         @SuppressWarnings("unused")\r
1237         private void bulletListClicked() {\r
1238                 browser.page().mainFrame().evaluateJavaScript(\r
1239                                 "document.execCommand('InsertUnorderedList', false, '');");\r
1240                 browser.setFocus();\r
1241         }\r
1242 \r
1243         // Listener when a bullet list is clicked\r
1244         @SuppressWarnings("unused")\r
1245         private void numberListClicked() {\r
1246                 browser.page().mainFrame().evaluateJavaScript(\r
1247                                 "document.execCommand('InsertOrderedList', false, '');");\r
1248                 browser.setFocus();\r
1249         }\r
1250 \r
1251         // Listener when indent is clicked\r
1252         private void indentClicked() {\r
1253                 browser.page().mainFrame().evaluateJavaScript(\r
1254                                 "document.execCommand('indent', false, '');");\r
1255                 browser.setFocus();\r
1256         }\r
1257 \r
1258         // Listener when the font name is changed\r
1259         @SuppressWarnings("unused")\r
1260         private void fontChanged(String font) {\r
1261                 browser.page().mainFrame().evaluateJavaScript(\r
1262                                 "document.execCommand('fontName',false,'" + font + "');");\r
1263                 browser.setFocus();\r
1264         }\r
1265 \r
1266         // Listener when a font size is changed\r
1267         @SuppressWarnings("unused")\r
1268         private void fontSizeChanged(String font) {\r
1269                 String text = browser.selectedText();\r
1270                 if (text.trim().equalsIgnoreCase(""))\r
1271                         return;\r
1272 \r
1273                 String selectedText = browser.selectedText();\r
1274                 String url = "<span style=\"font-size:" +font +"pt; \">"+selectedText +"</a>";\r
1275                 String script = "document.execCommand('insertHtml', false, '"+url+"');";\r
1276                 browser.page().mainFrame().evaluateJavaScript(script);\r
1277 /*              browser.page().mainFrame().evaluateJavaScript(\r
1278                                 "document.execCommand('fontSize',false,'"\r
1279                                                 + font + "');");\r
1280 */\r
1281                 browser.setFocus();\r
1282         }\r
1283 \r
1284         // Load the font combo box based upon the font selected\r
1285         private void loadFontSize(String name) {        \r
1286                 QFontDatabase db = new QFontDatabase(); \r
1287                 fontSize.clear();\r
1288                 List<Integer> points = db.pointSizes(name); \r
1289                 for (int i=0; i<points.size(); i++) { \r
1290                         fontSize.addItem(points.get(i).toString()); \r
1291                 }\r
1292                 /*\r
1293                 fontSize.addItem("x-small");\r
1294                 fontSize.addItem("small");\r
1295                 fontSize.addItem("medium");\r
1296                 fontSize.addItem("large");\r
1297                 fontSize.addItem("x-large");\r
1298                 fontSize.addItem("xx-large");\r
1299                 fontSize.addItem("xxx-large");\r
1300                 */\r
1301         }\r
1302 \r
1303         // Listener when a font size is changed\r
1304         @SuppressWarnings("unused")\r
1305         private void fontColorClicked() {\r
1306 //              QColorDialog dialog = new QColorDialog();\r
1307 //              QColor color = QColorDialog.getColor();\r
1308                 QColor color = fontColorMenu.getColor();\r
1309                 if (color.isValid())\r
1310                         browser.page().mainFrame().evaluateJavaScript(\r
1311                                         "document.execCommand('foreColor',false,'" + color.name()\r
1312                                                         + "');");\r
1313                 browser.setFocus();\r
1314         }\r
1315 \r
1316         // Listener for when a background color change is requested\r
1317         @SuppressWarnings("unused")\r
1318         private void fontHilightClicked() {\r
1319 //              QColorDialog dialog = new QColorDialog();\r
1320 //              QColor color = QColorDialog.getColor();\r
1321                 QColor color = fontHilightColorMenu.getColor();\r
1322                 if (color.isValid())\r
1323                         browser.page().mainFrame().evaluateJavaScript(\r
1324                                         "document.execCommand('backColor',false,'" + color.name()\r
1325                                                         + "');");\r
1326                 browser.setFocus();\r
1327         }\r
1328         \r
1329         // Listener for when a background color change is requested\r
1330         @SuppressWarnings("unused")\r
1331         private void superscriptClicked() {\r
1332                 browser.page().mainFrame().evaluateJavaScript(\r
1333                                         "document.execCommand('superscript');");\r
1334                 browser.setFocus();\r
1335         }\r
1336         \r
1337         // Listener for when a background color change is requested\r
1338         @SuppressWarnings("unused")\r
1339         private void subscriptClicked() {\r
1340                 browser.page().mainFrame().evaluateJavaScript(\r
1341                                         "document.execCommand('subscript');");\r
1342                 browser.setFocus();\r
1343         }\r
1344         // Insert a to-do checkbox\r
1345         @SuppressWarnings("unused")\r
1346         private void todoClicked() {\r
1347                 FileNameMap fileNameMap = URLConnection.getFileNameMap();\r
1348                 String script_start = new String(\r
1349                                 "document.execCommand('insertHtml', false, '");\r
1350                 String script_end = new String("');");\r
1351                 String todo = new String(\r
1352                                 "<input TYPE=\"CHECKBOX\" value=\"false\" " +\r
1353                                 "onMouseOver=\"style.cursor=\\'hand\\'\" " +\r
1354                                 "onClick=\"value=checked; window.jambi.contentChanged(); \" />");\r
1355                 browser.page().mainFrame().evaluateJavaScript(\r
1356                                 script_start + todo + script_end);\r
1357                 browser.setFocus();\r
1358         }\r
1359 \r
1360         // Encrypt the selected text\r
1361         @SuppressWarnings("unused")\r
1362         private void encryptText() {\r
1363                 String text = browser.selectedText();\r
1364                 if (text.trim().equalsIgnoreCase(""))\r
1365                         return;\r
1366                 text = new String(text.replaceAll("\n", "<br/>"));\r
1367 \r
1368                 EnCryptDialog dialog = new EnCryptDialog();\r
1369                 dialog.exec();\r
1370                 if (!dialog.okPressed()) {\r
1371                         return;\r
1372                 }\r
1373 \r
1374                 EnCrypt crypt = new EnCrypt();\r
1375                 String encrypted = crypt.encrypt(text, dialog.getPassword().trim(), 64);\r
1376                 String decrypted = crypt.decrypt(encrypted, dialog.getPassword().trim(), 64);\r
1377 \r
1378                 if (encrypted.trim().equals("")) {\r
1379                         QMessageBox.information(this, tr("Error"), tr("Error Encrypting String"));\r
1380                         return;\r
1381                 }\r
1382                 StringBuffer buffer = new StringBuffer(encrypted.length() + 100);\r
1383                 buffer.append("<img en-tag=\"en-crypt\" cipher=\"RC2\" hint=\""\r
1384                                 + dialog.getHint().replace("'","\\'") + "\" length=\"64\" ");\r
1385                 buffer.append("contentEditable=\"false\" alt=\"");\r
1386                 buffer.append(encrypted);\r
1387                 buffer.append("\" src=\"").append(FileUtils.toForwardSlashedPath(Global.getFileManager().getImageDirPath("encrypt.png") +"\""));\r
1388                 Global.cryptCounter++;\r
1389                 buffer.append(" id=\"crypt"+Global.cryptCounter.toString() +"\"");\r
1390                 buffer.append(" onMouseOver=\"style.cursor=\\'hand\\'\"");\r
1391                 buffer.append(" onClick=\"window.jambi.decryptText(\\'crypt"+Global.cryptCounter.toString() \r
1392                                 +"\\', \\'"+encrypted+"\\', \\'"+dialog.getHint().replace("'", "\\&amp;apos;")+"\\');\"");\r
1393                 buffer.append("style=\"display:block\" />");\r
1394 \r
1395                 String script_start = new String(\r
1396                                 "document.execCommand('insertHtml', false, '");\r
1397                 String script_end = new String("');");\r
1398                 browser.page().mainFrame().evaluateJavaScript(\r
1399                                 script_start + buffer.toString() + script_end);\r
1400         }\r
1401 \r
1402 \r
1403         // Insert a Quick hyperlink\r
1404         public void insertQuickLink() {\r
1405                 logger.log(logger.EXTREME, "Inserting link");\r
1406                 String text = browser.selectedText();\r
1407                 if (text.trim().equalsIgnoreCase(""))\r
1408                         return;\r
1409 \r
1410                 NoteQuickLinkDialog dialog = new NoteQuickLinkDialog(logger, conn, text);\r
1411                 if (dialog.getResults().size() == 0) {\r
1412                         QMessageBox.critical(null, tr("No Matches Found") ,tr("No matching notes found."));\r
1413                         return;\r
1414                 }\r
1415                 if (dialog.getResults().size() > 1) {\r
1416                         dialog.exec();\r
1417                         if (!dialog.okPressed) {\r
1418                                 logger.log(logger.EXTREME, "Insert link canceled");\r
1419                                 return;\r
1420                         }\r
1421                 }\r
1422 \r
1423                 User user = Global.getUserInformation();\r
1424                 String dUrl = new String("evernote:///view/") + new String(user.getId() + "/" +user.getShardId() +"/"\r
1425                                 +dialog.getSelectedNote()+"/"+dialog.getSelectedNote() +"/ " +"style=\"color:#69aa35\"");\r
1426                 \r
1427                 String url = "<a title=\"" +dUrl\r
1428                                 +"\" href=" +dUrl \r
1429                                 +" >"+text +"</a>";\r
1430                 String script = "document.execCommand('insertHtml', false, '"+url+"');";\r
1431                 browser.page().mainFrame().evaluateJavaScript(script);  \r
1432                 contentChanged();\r
1433         }\r
1434 \r
1435         // Insert a hyperlink\r
1436         public void insertLink() {\r
1437                 logger.log(logger.EXTREME, "Inserting link");\r
1438                 String text = browser.selectedText();\r
1439                 if (text.trim().equalsIgnoreCase(""))\r
1440                         return;\r
1441 \r
1442                 InsertLinkDialog dialog = new InsertLinkDialog(insertHyperlink);\r
1443                 if (currentHyperlink != null && currentHyperlink != "") {\r
1444                         dialog.setUrl(currentHyperlink);\r
1445                 }\r
1446                 dialog.exec();\r
1447                 if (!dialog.okPressed()) {\r
1448                         logger.log(logger.EXTREME, "Insert link canceled");\r
1449                         return;\r
1450                 }\r
1451                 \r
1452                 // Take care of inserting new links\r
1453                 if (insertHyperlink) {\r
1454                         String selectedText = browser.selectedText();\r
1455                         if (dialog.getUrl().trim().equals(""))\r
1456                                 return;\r
1457                         logger.log(logger.EXTREME, "Inserting link on text "+selectedText);\r
1458                         logger.log(logger.EXTREME, "URL Link " +dialog.getUrl().trim());\r
1459                         String dUrl = StringUtils.replace(dialog.getUrl().trim(), "'", "\\'");\r
1460                         String url = "<a href=\"" +dUrl\r
1461                                         +"\" title=" +dUrl \r
1462                                         +" >"+selectedText +"</a>";\r
1463                         String script = "document.execCommand('insertHtml', false, '"+url+"');";\r
1464                         browser.page().mainFrame().evaluateJavaScript(script);\r
1465                         return;\r
1466                 }\r
1467                 \r
1468                 // Edit existing links\r
1469                 String js = new String( "function getCursorPos() {"\r
1470                                 +"var cursorPos;"\r
1471                                 +"if (window.getSelection) {"\r
1472                                 +"   var selObj = window.getSelection();"\r
1473                                 +"   var selRange = selObj.getRangeAt(0);"\r
1474                                 +"   var workingNode = window.getSelection().anchorNode.parentNode;"\r
1475                                 +"   while(workingNode != null) { " \r
1476                                 +"      if (workingNode.nodeName.toLowerCase()=='a') workingNode.setAttribute('href','" +dialog.getUrl() +"');"\r
1477                                 +"      workingNode = workingNode.parentNode;"\r
1478                                 +"   }"\r
1479                                 +"}"\r
1480                                 +"} getCursorPos();");\r
1481                         browser.page().mainFrame().evaluateJavaScript(js);\r
1482                 \r
1483                 if (!dialog.getUrl().trim().equals("")) {\r
1484                         contentChanged();\r
1485                         return;\r
1486                 }\r
1487                 \r
1488                 // Remove URL\r
1489                 js = new String( "function getCursorPos() {"\r
1490                                 +"var cursorPos;"\r
1491                                 +"if (window.getSelection) {"\r
1492                                 +"   var selObj = window.getSelection();"\r
1493                                 +"   var selRange = selObj.getRangeAt(0);"\r
1494                                 +"   var workingNode = window.getSelection().anchorNode.parentNode;"\r
1495                                 +"   while(workingNode != null) { " \r
1496                                 +"      if (workingNode.nodeName.toLowerCase()=='a') { "\r
1497                                 +"         workingNode.removeAttribute('href');"\r
1498                                 +"         workingNode.removeAttribute('title');"\r
1499                                 +"         var text = document.createTextNode(workingNode.innerText);"\r
1500                                 +"         workingNode.parentNode.insertBefore(text, workingNode);"\r
1501                                 +"         workingNode.parentNode.removeChild(workingNode);"\r
1502                                 +"      }"\r
1503                                 +"      workingNode = workingNode.parentNode;"\r
1504                                 +"   }"\r
1505                                 +"}"\r
1506                                 +"} getCursorPos();");\r
1507                         browser.page().mainFrame().evaluateJavaScript(js);\r
1508                         \r
1509                         contentChanged();\r
1510 \r
1511                 \r
1512         }\r
1513         \r
1514         \r
1515         // Insert a hyperlink\r
1516         public void insertLatex() {\r
1517                 editLatex(null);\r
1518         }\r
1519         public void editLatex(String guid) {\r
1520                 logger.log(logger.EXTREME, "Inserting latex");\r
1521                 String text = browser.selectedText();\r
1522                 if (text.trim().equalsIgnoreCase("\n") || text.trim().equalsIgnoreCase("")) {\r
1523                         InsertLatexImage dialog = new InsertLatexImage();\r
1524                         if (guid != null) {\r
1525                                 String formula = conn.getNoteTable().noteResourceTable.getNoteSourceUrl(guid).replace("http://latex.codecogs.com/gif.latex?", "");\r
1526                                 dialog.setFormula(formula);\r
1527                         }\r
1528                         dialog.exec();\r
1529                         if (!dialog.okPressed()) {\r
1530                                 logger.log(logger.EXTREME, "Edit LaTex canceled");\r
1531                                 return;\r
1532                         }\r
1533                         text = dialog.getFormula().trim();\r
1534                 }\r
1535                 blockApplication.emit(this);\r
1536                 logger.log(logger.EXTREME, "Inserting LaTeX formula:" +text);\r
1537                 latexGuid = guid;\r
1538                 text = StringUtils.replace(text, "'", "\\'");\r
1539                 String url = "http://latex.codecogs.com/gif.latex?" +text;\r
1540                 logger.log(logger.EXTREME, "Sending request to codecogs --> " + url);\r
1541                 QNetworkAccessManager manager = new QNetworkAccessManager(this);\r
1542                 manager.finished.connect(this, "insertLatexImageReady(QNetworkReply)");\r
1543                 unblockTime = new GregorianCalendar().getTimeInMillis()+5000;\r
1544                 awaitingHttpResponse = true;\r
1545                 manager.get(new QNetworkRequest(new QUrl(url)));\r
1546         }\r
1547         \r
1548         public void insertLatexImageReady(QNetworkReply reply) {\r
1549                 logger.log(logger.EXTREME, "Response received from CodeCogs");\r
1550                 if (reply.error() != NetworkError.NoError) \r
1551                         return;\r
1552 \r
1553                 unblockTime = -1;\r
1554                 if (!awaitingHttpResponse)\r
1555                         return;\r
1556                 \r
1557                 awaitingHttpResponse = false;\r
1558                 QUrl replyUrl = reply.url();            \r
1559                 QByteArray image = reply.readAll();\r
1560                 reply.close();\r
1561                 logger.log(logger.EXTREME, "New image size: " +image.size());\r
1562 \r
1563                 Resource newRes = null;\r
1564                 QFile tfile;\r
1565                 String path;\r
1566                 if (latexGuid == null) {\r
1567                         logger.log(logger.EXTREME, "Creating temporary gif");                   \r
1568                         path = Global.getFileManager().getResDirPath("latex-temp.gif");\r
1569                         tfile = new QFile(path);\r
1570                         tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));\r
1571                         logger.log(logger.EXTREME, "File Open: " +tfile.errorString());\r
1572                         tfile.write(image);\r
1573                         logger.log(logger.EXTREME, "Bytes writtes: "+tfile.size());\r
1574                         tfile.close();\r
1575                         logger.log(logger.EXTREME, "Creating resource");\r
1576                         int sequence = 0;\r
1577                         if (currentNote.getResources() != null || currentNote.getResources().size() > 0)\r
1578                                 sequence = currentNote.getResources().size();\r
1579                         newRes = createResource(path,sequence ,"image/gif", false);\r
1580                         QImage pix = new QImage();\r
1581                         pix.loadFromData(image);\r
1582                         newRes.setHeight(new Integer(pix.height()).shortValue());\r
1583                         newRes.setWidth(new Integer(pix.width()).shortValue());\r
1584                         logger.log(logger.EXTREME, "Renaming temporary file to " +newRes.getGuid()+".gif");\r
1585                         path = Global.getFileManager().getResDirPath(newRes.getGuid()+".gif");\r
1586                         tfile.rename(path);\r
1587                 } else {\r
1588                         newRes = conn.getNoteTable().noteResourceTable.getNoteResource(latexGuid, false);\r
1589                         path = Global.getFileManager().getResDirPath(newRes.getGuid()+".gif");\r
1590                         tfile = new QFile(path);\r
1591                         tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));\r
1592                         tfile.write(image);\r
1593                         tfile.close();\r
1594                         newRes.getData().setBody(image.toByteArray());\r
1595                         // Calculate the new hash value\r
1596                 MessageDigest md;\r
1597 \r
1598                 logger.log(logger.EXTREME, "Generating MD5");\r
1599                 try {\r
1600                                 md = MessageDigest.getInstance("MD5");\r
1601                         md.update(image.toByteArray());\r
1602                         byte[] hash = md.digest();\r
1603                         newRes.getData().setBodyHash(hash);\r
1604                         } catch (NoSuchAlgorithmException e) {\r
1605                                 e.printStackTrace();\r
1606                         }\r
1607                         QImage pix = new QImage();\r
1608                         pix.loadFromData(image);\r
1609                         newRes.setHeight(new Integer(pix.height()).shortValue());\r
1610                         newRes.setWidth(new Integer(pix.width()).shortValue());\r
1611                         conn.getNoteTable().noteResourceTable.updateNoteResource(newRes, true);\r
1612                 }\r
1613 \r
1614                 logger.log(logger.EXTREME, "Setting source: " +replyUrl.toString());\r
1615                 newRes.getAttributes().setSourceURL(replyUrl.toString());\r
1616                 conn.getNoteTable().noteResourceTable.updateNoteSourceUrl(newRes.getGuid(), replyUrl.toString(), true);\r
1617                 \r
1618                 for(int i=0; i<currentNote.getResourcesSize(); i++) {\r
1619                         if (currentNote.getResources().get(i).getGuid().equals(newRes.getGuid())) {\r
1620                                 currentNote.getResources().remove(i);\r
1621                                 i=currentNote.getResourcesSize();\r
1622                         }\r
1623                 }\r
1624                 currentNote.getResources().add(newRes);\r
1625                 \r
1626 \r
1627                 // do the actual insert into the note.  We only do this on new formulas.  \r
1628                 if (latexGuid == null) {\r
1629                         StringBuffer buffer = new StringBuffer(100);\r
1630                         String formula = replyUrl.toString().toLowerCase().replace("http://latex.codecogs.com/gif.latex?", "");\r
1631                         buffer.append("<a href=\"latex://"+path.replace("\\", "/")+"\" title=\""+formula+"\""\r
1632                                         +"><img src=\"");\r
1633                         buffer.append(path.replace("\\", "/"));\r
1634                         buffer.append("\" en-tag=\"en-latex\" type=\"image/gif\""\r
1635                                 +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""\r
1636                                 +" guid=\"" +newRes.getGuid() +"\""\r
1637                                 + " /></a>");\r
1638                 \r
1639                         String script_start = new String("document.execCommand('insertHTML', false, '");\r
1640                         String script_end = new String("');");\r
1641                         browser.page().mainFrame().evaluateJavaScript(\r
1642                                         script_start + buffer + script_end);\r
1643                 } else {\r
1644                         HtmlTagModifier modifier = new HtmlTagModifier(getContent());\r
1645                         modifier.modifyLatexTagHash(newRes);\r
1646                         String newContent = modifier.getHtml();\r
1647                         setContent(new QByteArray(newContent));\r
1648                 }\r
1649 \r
1650                 logger.log(logger.EXTREME, "New HTML set\n" +browser.page().currentFrame().toHtml());\r
1651                 QWebSettings.setMaximumPagesInCache(0);\r
1652                 QWebSettings.setObjectCacheCapacities(0, 0, 0);\r
1653                 \r
1654                 browser.page().mainFrame().setHtml(browser.page().mainFrame().toHtml());\r
1655                 browser.reload();\r
1656                 contentChanged();\r
1657 //              resourceSignal.contentChanged.emit(path);\r
1658                 unblockTime = -1;\r
1659         unblockApplication.emit();\r
1660                 return;\r
1661                 \r
1662         }\r
1663 \r
1664         \r
1665         \r
1666         // Insert a table\r
1667         public void insertTable() {\r
1668                 TableDialog dialog = new TableDialog();\r
1669                 dialog.exec();\r
1670                 if (!dialog.okPressed()) {\r
1671                         return;\r
1672                 }\r
1673                 \r
1674                 int cols = dialog.getCols();\r
1675                 int rows = dialog.getRows();\r
1676                 int width = dialog.getWidth();\r
1677                 boolean percent = dialog.isPercent();\r
1678                 \r
1679                 String newHTML = "<table border=\"1\" width=\"" +new Integer(width).toString();\r
1680                 if (percent)\r
1681                         newHTML = newHTML +"%";\r
1682                 newHTML = newHTML + "\"><tbody>";\r
1683 \r
1684                 for (int i=0; i<rows; i++) {\r
1685                         newHTML = newHTML +"<tr>";\r
1686                         for (int j=0; j<cols; j++) {\r
1687                                 newHTML = newHTML +"<td>&nbsp;</td>";\r
1688                         }\r
1689                         newHTML = newHTML +"</tr>";\r
1690                 }\r
1691                 newHTML = newHTML+"</tbody></table>";   \r
1692         \r
1693                 String script = "document.execCommand('insertHtml', false, '"+newHTML+"');";\r
1694                 browser.page().mainFrame().evaluateJavaScript(script);\r
1695         }\r
1696         \r
1697         \r
1698         // Text content changed\r
1699         @SuppressWarnings("unused")\r
1700         private void selectionChanged() {\r
1701                 browser.encryptAction.setEnabled(true);\r
1702                 browser.insertLinkAction.setEnabled(true);\r
1703                 browser.insertQuickLinkAction.setEnabled(true);\r
1704                 String scriptStart = "var selection_text = (window.getSelection()).toString();"\r
1705                                 + "var range = (window.getSelection()).getRangeAt(0);"\r
1706                                 + "var parent_html = range.commonAncestorContainer.innerHTML;"\r
1707                                 + "if (parent_html == undefined) {window.jambi.saveSelectedText(selection_text); return;}"\r
1708                                 + "var first_text = range.startContainer.nodeValue.substr(range.startOffset);"\r
1709                                 + "var last_text = (range.endContainer.nodeValue).substring(0,range.endOffset);"\r
1710                                 + "var start = parent_html.indexOf(first_text);"\r
1711                                 + "var end = parent_html.indexOf(last_text,start+1)+last_text.length;"\r
1712                                 + "var value = parent_html.substring(start,end);"\r
1713                                 + "window.jambi.saveSelectedText(value);" ;\r
1714                 browser.page().mainFrame().evaluateJavaScript(scriptStart);\r
1715 \r
1716         }\r
1717 \r
1718         public void saveSelectedText(String text) {\r
1719                 boolean enabled = true;\r
1720                 if (text.trim().length() == 0)\r
1721                         enabled=false;\r
1722                 if (text.indexOf("en-tag=\"en-crypt\"") >= 0)\r
1723                         enabled=false;\r
1724                 if (text.indexOf("<img en-tag=\"en-media\"") >= 0)\r
1725                         enabled=false;\r
1726                 if (text.indexOf("<a en-tag=\"en-media\"") >= 0)\r
1727                         enabled=false;\r
1728                 if (text.indexOf("<input ") >= 0)\r
1729                         enabled=false;\r
1730                 \r
1731                 browser.encryptAction.setEnabled(enabled);\r
1732                 browser.insertLinkAction.setEnabled(enabled);\r
1733                 browser.insertQuickLinkAction.setEnabled(enabled);\r
1734 //              selectedText = text;\r
1735         }\r
1736 \r
1737         // Decrypt clicked text\r
1738         public void decryptText(String id, String text, String hint) {\r
1739                 EnCrypt crypt = new EnCrypt();\r
1740                 String plainText = null;\r
1741                 Calendar currentTime = new GregorianCalendar();\r
1742                 Long l = new Long(currentTime.getTimeInMillis());\r
1743                 String slot = new String(Long.toString(l));\r
1744                 \r
1745                 // First, try to decrypt with any keys we already have\r
1746                 for (int i=0; i<Global.passwordRemember.size(); i++) {\r
1747                         plainText = crypt.decrypt(text, Global.passwordRemember.get(i).getFirst(), 64);\r
1748                         if (plainText != null) {\r
1749                                 slot = new String(Long.toString(l));\r
1750                                 Global.passwordSafe.put(slot, Global.passwordRemember.get(i));\r
1751                                 removeEncryption(id, plainText, false, slot);   \r
1752                                 return;\r
1753                         }\r
1754                 }\r
1755                 \r
1756                 \r
1757                 EnDecryptDialog dialog = new EnDecryptDialog();\r
1758                 dialog.setHint(hint);\r
1759                 while (plainText == null || !dialog.okPressed()) {\r
1760                         dialog.exec();\r
1761                         if (!dialog.okPressed()) {\r
1762                                 return;\r
1763                         }\r
1764                         plainText = crypt.decrypt(text, dialog.getPassword().trim(), 64);\r
1765                         if (plainText == null) {\r
1766                                 QMessageBox.warning(this, tr("Incorrect Password"), tr("The password entered is not correct"));\r
1767                         }\r
1768                 }\r
1769                 Pair<String,String> passwordPair = new Pair<String,String>();\r
1770                 passwordPair.setFirst(dialog.getPassword());\r
1771                 passwordPair.setSecond(dialog.getHint());\r
1772                 Global.passwordSafe.put(slot, passwordPair);\r
1773 //              removeEncryption(id, plainText.replaceAll("\n", "<br/>"), dialog.permanentlyDecrypt(), slot);\r
1774                 removeEncryption(id, plainText, dialog.permanentlyDecrypt(), slot);\r
1775                 if (dialog.rememberPassword()) {\r
1776                         Pair<String, String> pair = new Pair<String,String>();\r
1777                         pair.setFirst(dialog.getPassword());\r
1778                         pair.setSecond(dialog.getHint());\r
1779                         Global.passwordRemember.add(pair);\r
1780                 }\r
1781 \r
1782         }\r
1783 \r
1784         // Get the editor tag line\r
1785         public TagLineEdit getTagLine() {\r
1786                 return tagEdit;\r
1787         }\r
1788 \r
1789         // Modify a note's tags\r
1790         @SuppressWarnings("unused")\r
1791         private void modifyTags() {\r
1792                 TagAssign tagWindow = new TagAssign(allTags, currentTags, !conn.getNotebookTable().isLinked(currentNote.getNotebookGuid()));\r
1793                 tagWindow.exec();\r
1794                 if (tagWindow.okClicked()) {\r
1795                         currentTags.clear();\r
1796                         StringBuffer tagDisplay = new StringBuffer();\r
1797 \r
1798                         List<QListWidgetItem> newTags = tagWindow.getTagList()\r
1799                                         .selectedItems();\r
1800                         for (int i = 0; i < newTags.size(); i++) {\r
1801                                 currentTags.add(newTags.get(i).text());\r
1802                                 tagDisplay.append(newTags.get(i).text());\r
1803                                 if (i < newTags.size() - 1) {\r
1804                                         tagDisplay.append(Global.tagDelimeter + " ");\r
1805                                 }\r
1806                         }\r
1807                         tagEdit.setText(tagDisplay.toString());\r
1808                         noteSignal.tagsChanged.emit(currentNote.getGuid(), currentTags);\r
1809                 }\r
1810         }\r
1811 \r
1812         // Tag line has been modified by typing text\r
1813         @SuppressWarnings("unused")\r
1814         private void modifyTagsTyping() {\r
1815                 String completionText = "";\r
1816                 if (tagEdit.currentCompleterSelection != null && !tagEdit.currentCompleterSelection.equals("")) {\r
1817                         completionText = tagEdit.currentCompleterSelection;\r
1818                         tagEdit.currentCompleterSelection = "";\r
1819                 }\r
1820                 \r
1821                 if (tagEdit.text().equalsIgnoreCase(saveTagList))\r
1822                         return;\r
1823 \r
1824                 // We know something has changed...\r
1825                 String oldTagArray[] = saveTagList.split(Global.tagDelimeter);\r
1826                 String newTagArray[];\r
1827                 if (!completionText.equals("")) {\r
1828                         String before = tagEdit.text().substring(0,tagEdit.cursorPosition());\r
1829                         int lastDelimiter = before.lastIndexOf(Global.tagDelimeter);\r
1830                         if (lastDelimiter > 0)\r
1831                                 before = before.substring(0,before.lastIndexOf(Global.tagDelimeter));\r
1832                         else \r
1833                                 before = "";\r
1834                         String after = tagEdit.text().substring(tagEdit.cursorPosition());\r
1835                         newTagArray = (before+Global.tagDelimeter+completionText+Global.tagDelimeter+after).split(Global.tagDelimeter);\r
1836                 }\r
1837                 else {\r
1838                         newTagArray = tagEdit.text().split(Global.tagDelimeter);\r
1839                 }\r
1840                 \r
1841                 // Remove any traling or leading blanks\r
1842                 for (int i=0; i<newTagArray.length; i++)\r
1843                         newTagArray[i] = newTagArray[i].trim().replaceAll("^\\s+", "");;\r
1844                 \r
1845                 // Remove any potential duplicates from the new list\r
1846                 for (int i=0; i<newTagArray.length; i++) {\r
1847                         boolean foundOnce = false;\r
1848                         for (int j=0; j<newTagArray.length; j++) {\r
1849                                 if (newTagArray[j].equalsIgnoreCase(newTagArray[i])) {\r
1850                                         if (!foundOnce) {\r
1851                                                 foundOnce = true;\r
1852                                         } else\r
1853                                                 newTagArray[j] = "";\r
1854                                 }\r
1855                         }\r
1856                 }\r
1857 \r
1858                 List<String> newTagList = new ArrayList<String>();\r
1859                 List<String> oldTagList = new ArrayList<String>();\r
1860 \r
1861                 for (int i = 0; i < oldTagArray.length; i++)\r
1862                         if (!oldTagArray[i].trim().equals(""))\r
1863                                 oldTagList.add(oldTagArray[i]);\r
1864                 for (int i = 0; i < newTagArray.length; i++)\r
1865                         if (!newTagArray[i].trim().equals(""))\r
1866                                 newTagList.add(newTagArray[i]);\r
1867 \r
1868                 if (conn.getNotebookTable().isLinked(currentNote.getNotebookGuid())) {\r
1869                         for (int i=newTagList.size()-1; i>=0; i--) {\r
1870                                 boolean found = false;\r
1871                                 for (int j=0; j<allTags.size(); j++) {\r
1872                                         if (allTags.get(j).getName().equalsIgnoreCase(newTagList.get(i))) {\r
1873                                                 found = true;\r
1874                                                 j=allTags.size();\r
1875                                         }\r
1876                                 }\r
1877                                 if (!found)\r
1878                                         newTagList.remove(i);\r
1879                         }\r
1880                 }\r
1881 \r
1882                 // Let's cleanup the appearance of the tag list\r
1883                 Collections.sort(newTagList);\r
1884                 String newDisplay = "";\r
1885                 for (int i=0; i<newTagList.size(); i++) {\r
1886                         newDisplay = newDisplay+newTagList.get(i);\r
1887                         if (i<newTagList.size()-1)\r
1888                                 newDisplay = newDisplay+Global.tagDelimeter +" ";\r
1889                 }\r
1890                 tagEdit.blockSignals(true);\r
1891                 tagEdit.setText(newDisplay);\r
1892                 tagEdit.blockSignals(false);\r
1893                 \r
1894                 // We now have lists of the new & old. Remove duplicates. If all\r
1895                 // are removed from both then nothing has really changed\r
1896                 for (int i = newTagList.size() - 1; i >= 0; i--) {\r
1897                         String nTag = newTagList.get(i);\r
1898                         for (int j = oldTagList.size() - 1; j >= 0; j--) {\r
1899                                 String oTag = oldTagList.get(j);\r
1900                                 if (oTag.equalsIgnoreCase(nTag)) {\r
1901                                         oldTagList.remove(j);\r
1902                                         newTagList.remove(i);\r
1903                                         j = -1;\r
1904                                 }\r
1905                         }\r
1906                 }\r
1907 \r
1908                 if (oldTagList.size() != 0 || newTagList.size() != 0) {\r
1909                         currentTags.clear();\r
1910                         newTagArray = tagEdit.text().split(Global.tagDelimeter);\r
1911                         for (int i = 0; i < newTagArray.length; i++)\r
1912                                 if (!newTagArray[i].trim().equals(""))\r
1913                                         currentTags.add(newTagArray[i].trim());\r
1914 \r
1915                         noteSignal.tagsChanged.emit(currentNote.getGuid(), currentTags);\r
1916                 }\r
1917                 \r
1918         }\r
1919 \r
1920         // Tab button was pressed\r
1921         public void tabPressed() {\r
1922                 if (insideEncryption)\r
1923                         return;\r
1924                 if (!insideList && !insideTable) {\r
1925                         String script_start = new String(\r
1926                         "document.execCommand('insertHtml', false, '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;');");\r
1927                         browser.page().mainFrame().evaluateJavaScript(script_start);\r
1928                         return;\r
1929                 }\r
1930                 if (insideList) {\r
1931                         indentClicked();\r
1932                 }\r
1933                 if (insideTable) {\r
1934                         String js = new String( "function getCursorPosition() { "\r
1935                                         +"   var selObj = window.getSelection();"\r
1936                                         +"   var selRange = selObj.getRangeAt(0);"\r
1937                                         +"   var workingNode = window.getSelection().anchorNode;"\r
1938                                         +"   var rowCount = 0;"\r
1939                                         +"   var colCount = 0;"\r
1940                                         +"   while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { " \r
1941                                         +"      if (workingNode.nodeName.toLowerCase()=='tr') {"\r
1942                                         +"         rowCount = rowCount+1;"\r
1943                                         +"      }"\r
1944                                         +"      if (workingNode.nodeName.toLowerCase() == 'td') {"\r
1945                                         +"         colCount = colCount+1;"\r
1946                                         +"      }"\r
1947                                         +"      if (workingNode.previousSibling != null)"\r
1948                                         +"          workingNode = workingNode.previousSibling;"\r
1949                                         +"      else "\r
1950                                         +"           workingNode = workingNode.parentNode;"\r
1951                                         +"   }"\r
1952                                         +"   var nodes = workingNode.getElementsByTagName('tr');"\r
1953                                         +"   var tableRows = nodes.length;"\r
1954                                         +"   nodes = nodes[0].getElementsByTagName('td');"\r
1955                                         +"   var tableColumns = nodes.length;"\r
1956                                         +"   window.jambi.setTableCursorPositionTab(rowCount, colCount, tableRows, tableColumns);"\r
1957                                         +"} getCursorPosition();");\r
1958                         browser.page().mainFrame().evaluateJavaScript(js);\r
1959                 }\r
1960         }\r
1961         \r
1962         // If a user presses tab from within a table\r
1963         public void setTableCursorPositionTab(int currentRow, int currentCol, int tableRows, int tableColumns) {\r
1964                 if (tableRows == currentRow && currentCol == tableColumns) {\r
1965                         insertTableRow();\r
1966                 }\r
1967                 KeyboardModifiers modifiers = new KeyboardModifiers(KeyboardModifier.NoModifier);\r
1968                 QKeyEvent right = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Right.value(), modifiers);\r
1969                 QKeyEvent end = new QKeyEvent(Type.KeyPress, Qt.Key.Key_End.value(), modifiers);\r
1970                 QKeyEvent end2 = new QKeyEvent(Type.KeyPress, Qt.Key.Key_End.value(), modifiers);\r
1971                 getBrowser().focusWidget();\r
1972                 QCoreApplication.postEvent(getBrowser(), end);\r
1973                 QCoreApplication.postEvent(getBrowser(), right);\r
1974                 QCoreApplication.postEvent(getBrowser(), end2);\r
1975         }\r
1976                 \r
1977         public void backtabPressed() {\r
1978                 if (insideEncryption) \r
1979                         return;\r
1980                 if (insideList)\r
1981                         outdentClicked();\r
1982                 if (insideTable) {\r
1983                         String js = new String( "function getCursorPosition() { "\r
1984                                         +"   var selObj = window.getSelection();"\r
1985                                         +"   var selRange = selObj.getRangeAt(0);"\r
1986                                         +"   var workingNode = window.getSelection().anchorNode;"\r
1987                                         +"   var rowCount = 0;"\r
1988                                         +"   var colCount = 0;"\r
1989                                         +"   while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { " \r
1990                                         +"      if (workingNode.nodeName.toLowerCase()=='tr') {"\r
1991                                         +"         rowCount = rowCount+1;"\r
1992                                         +"      }"\r
1993                                         +"      if (workingNode.nodeName.toLowerCase() == 'td') {"\r
1994                                         +"         colCount = colCount+1;"\r
1995                                         +"      }"\r
1996                                         +"      if (workingNode.previousSibling != null)"\r
1997                                         +"          workingNode = workingNode.previousSibling;"\r
1998                                         +"      else "\r
1999                                         +"           workingNode = workingNode.parentNode;"\r
2000                                         +"   }"\r
2001                                         +"   var nodes = workingNode.getElementsByTagName('tr');"\r
2002                                         +"   var tableRows = nodes.length;"\r
2003                                         +"   nodes = nodes[0].getElementsByTagName('td');"\r
2004                                         +"   var tableColumns = nodes.length;"\r
2005                                         +"   window.jambi.setTableCursorPositionBackTab(rowCount, colCount, tableRows, tableColumns);"\r
2006                                         +"} getCursorPosition();");\r
2007                         browser.page().mainFrame().evaluateJavaScript(js);\r
2008                         \r
2009                 }\r
2010         }\r
2011         \r
2012         // If a user presses backtab from within a table\r
2013         public void setTableCursorPositionBackTab(int currentRow, int currentCol, int tableRows, int tableColumns) {\r
2014                 if (currentRow  == 1 && currentCol == 1) {\r
2015                         return;\r
2016                 }\r
2017                 KeyboardModifiers modifiers = new KeyboardModifiers(KeyboardModifier.NoModifier);\r
2018                 QKeyEvent left = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Left.value(), modifiers);\r
2019                 QKeyEvent home = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Home.value(), modifiers);\r
2020                 getBrowser().focusWidget();\r
2021                 QCoreApplication.postEvent(getBrowser(), home);\r
2022                 QCoreApplication.postEvent(getBrowser(), left);\r
2023         }\r
2024         \r
2025         \r
2026         public void setInsideList() {\r
2027                 insideList = true;\r
2028         }\r
2029         \r
2030         // The title has been edited\r
2031         @SuppressWarnings("unused")\r
2032         private void titleEdited() {\r
2033                 // If we don't have a good note, or if the current title\r
2034                 // matches the old title then we don't need to do anything\r
2035                 if (currentNote == null)\r
2036                         return;\r
2037                 if (currentNote.getTitle().trim().equals(titleLabel.text().trim()))\r
2038                         return;\r
2039                 \r
2040                 // If we have a real change, we need to save it.\r
2041                 String text = titleLabel.text().trim();\r
2042                 if (text.equals("")) \r
2043                         text = tr("Untitled Note");\r
2044                 noteSignal.titleChanged.emit(currentNote.getGuid(), text);\r
2045                 currentNote.setTitle(text);\r
2046                 saveNoteTitle = text;\r
2047                 checkNoteTitle();\r
2048         }\r
2049 \r
2050         // Set the list of note tags\r
2051         public void setAllTags(List<Tag> l) {\r
2052                 allTags = l;\r
2053                 tagEdit.setTagList(l);\r
2054         }\r
2055 \r
2056         // Setter for the current tags\r
2057         public void setCurrentTags(List<String> s) {\r
2058                 currentTags = s;\r
2059         }\r
2060 \r
2061         // Save the list of notebooks\r
2062         public void setNotebookList(List<Notebook> n) {\r
2063                 notebookList = n;\r
2064                 loadNotebookList();\r
2065         }\r
2066 \r
2067         // Load the notebook list and select the current notebook\r
2068         private void loadNotebookList() {\r
2069                 if (notebookBox.count() != 0)\r
2070                         notebookBox.clear();\r
2071                 if (notebookList == null)\r
2072                         return;\r
2073 \r
2074                 for (int i = 0; i < notebookList.size(); i++) {\r
2075                         notebookBox.addItem(notebookList.get(i).getName());\r
2076                         if (currentNote != null) {\r
2077                                 if (currentNote.getNotebookGuid().equals(\r
2078                                                 notebookList.get(i).getGuid())) {\r
2079                                         notebookBox.setCurrentIndex(i);\r
2080                                 }\r
2081                         }\r
2082                 }\r
2083         }\r
2084         \r
2085         \r
2086         // Set the notebook for a note\r
2087         public void setNotebook(String notebook) {\r
2088                 currentNote.setNotebookGuid(notebook);\r
2089                 loadNotebookList();\r
2090         }\r
2091 \r
2092         // Get the contents of the editor\r
2093         public String getContent() {\r
2094                 return browser.page().currentFrame().toHtml();\r
2095         }\r
2096 \r
2097         // The note contents have changed\r
2098         public void contentChanged() {\r
2099                 String content = getContent();\r
2100                 \r
2101                 // This puts in a 1/2 second delay\r
2102                 // before updating the source editor.\r
2103                 // It improves response when someone is doing\r
2104                 // frequent updates on a large note.\r
2105                 // If the source editor isn't visible, then there\r
2106                 // is no point to doing any of this.\r
2107                 if (sourceEdit.isVisible()) {\r
2108                         setSourceTimer.stop();\r
2109                         setSourceTimer.setInterval(500);\r
2110                         setSourceTimer.setSingleShot(true);\r
2111                         setSourceTimer.start();\r
2112                 }\r
2113                 \r
2114                 checkNoteTitle();\r
2115                 noteSignal.noteChanged.emit(currentNote.getGuid(), content); \r
2116         }\r
2117 \r
2118         // The notebook selection has changed\r
2119         @SuppressWarnings("unused")\r
2120         private void notebookChanged() {\r
2121                 boolean changed = false;\r
2122                 String n = notebookBox.currentText();\r
2123                 for (int i = 0; i < notebookList.size(); i++) {\r
2124                         if (n.equals(notebookList.get(i).getName())) {\r
2125                                 if (!notebookList.get(i).getGuid().equals(currentNote.getNotebookGuid())) {\r
2126                                         String guid = conn.getNotebookTable().findNotebookByName(n);\r
2127                                         if (conn.getNotebookTable().isLinked(guid)) {\r
2128                                                 tagEdit.setText("");\r
2129                                                 noteSignal.tagsChanged.emit(currentNote.getGuid(), new ArrayList<String>());\r
2130                                                 FilterEditorTags t = new FilterEditorTags(conn, logger);\r
2131                                                 setAllTags(t.getValidTags(currentNote));\r
2132                                         }\r
2133                                         currentNote.setNotebookGuid(notebookList.get(i).getGuid());\r
2134                                         changed = true;\r
2135                                 }\r
2136                                 i = notebookList.size();\r
2137                         }\r
2138                 }\r
2139                 \r
2140                 // If the notebook changed, signal the update\r
2141                 if (changed)\r
2142                         noteSignal.notebookChanged.emit(currentNote.getGuid(), currentNote\r
2143                                         .getNotebookGuid());\r
2144         }\r
2145 \r
2146         // Check the note title\r
2147         private void checkNoteTitle() {\r
2148                 String text = browser.page().currentFrame().toPlainText();\r
2149                 if (saveNoteTitle == null)\r
2150                         saveNoteTitle = new String();\r
2151                 text = text.trim();\r
2152                 if (!saveNoteTitle.trim().equals("") && !saveNoteTitle.trim().equals("Untitled Note"))\r
2153                         text = saveNoteTitle.trim();\r
2154                 int newLine = text.indexOf("\n");\r
2155                 if (newLine > 0)\r
2156                         text = text.substring(0,newLine);\r
2157                 if (saveNoteTitle.trim().equals("") || saveNoteTitle.trim().equals("Untitled Note")) {\r
2158                         if (text.trim().equals(""))\r
2159                                 text = tr("Untitled Note");\r
2160                                 titleLabel.setText(text);\r
2161                 } else {\r
2162                         if (text.length() > Constants.EDAM_NOTE_TITLE_LEN_MAX)\r
2163                                 titleLabel.setText(text.substring(0, Constants.EDAM_NOTE_TITLE_LEN_MAX));\r
2164                         else {\r
2165                                 titleLabel.blockSignals(true);\r
2166                                 if (text.trim().equals(""))\r
2167                                         titleLabel.setText(tr("Untitled Note"));\r
2168                                 else\r
2169                                         titleLabel.setText(text);\r
2170                                 titleLabel.blockSignals(false);\r
2171                         }\r
2172                 }\r
2173                 if (currentNote != null && titleLabel != null && !currentNote.getTitle().equals(text))\r
2174                         noteSignal.titleChanged.emit(currentNote.getGuid(), text);\r
2175         }\r
2176 \r
2177         // Return the note contents so we can email them\r
2178         public String getContentsToEmail() {\r
2179                 return browser.page().currentFrame().toPlainText().trim();\r
2180                 /*\r
2181                  * int body = browser.page().currentFrame().toHtml().indexOf("<body>");\r
2182                  * String temp = browser.page().currentFrame().toHtml(); if (body == -1)\r
2183                  * temp = "<html><body><b>Test</b></body></html>"; else temp =\r
2184                  * "<html>"+temp.substring(body); return temp; // return\r
2185                  * urlEncode(browser.page().currentFrame().toHtml());\r
2186                  */\r
2187         }\r
2188 \r
2189         // Insert an image into the editor\r
2190         private void insertImage(QMimeData mime) {\r
2191                 logger.log(logger.EXTREME, "Entering insertImage");\r
2192                 QImage img = (QImage) mime.imageData();\r
2193                 String script_start = new String(\r
2194                                 "document.execCommand('insertHTML', false, '");\r
2195                 String script_end = new String("');");\r
2196 \r
2197                 long now = new Date().getTime();\r
2198                 String path = Global.getFileManager().getResDirPath(\r
2199                                 (new Long(now).toString()) + ".jpg");\r
2200 \r
2201                 // This block is just a hack to make sure we wait at least 1ms so we\r
2202                 // don't\r
2203                 // have collisions on image names\r
2204                 long i = new Date().getTime();\r
2205                 while (now == i)\r
2206                         i = new Date().getTime();\r
2207 \r
2208                 // Open the file & write the data\r
2209                 QFile tfile = new QFile(path);\r
2210                 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));\r
2211                 if (!img.save(tfile)) {\r
2212                         tfile.close();\r
2213                         return;\r
2214                 }\r
2215                 tfile.close();\r
2216                 \r
2217                 Resource newRes = createResource(QUrl.fromLocalFile(path).toString(), 0, "image/jpeg", false);\r
2218                 if (newRes == null)\r
2219                         return;\r
2220                 currentNote.getResources().add(newRes);\r
2221 \r
2222                 // do the actual insert into the note\r
2223                 StringBuffer buffer = new StringBuffer(100);\r
2224                 buffer.append("<img src=\"");\r
2225                 buffer.append(tfile.fileName());\r
2226                 buffer.append("\" en-tag=en-media type=\"image/jpeg\""\r
2227                                 +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""\r
2228                                 +" guid=\"" +newRes.getGuid() +"\""\r
2229                                 +" onContextMenu=\"window.jambi.imageContextMenu(&amp." +tfile.fileName() +"&amp.);\""\r
2230                                 + " />");\r
2231                 \r
2232                 browser.page().mainFrame().evaluateJavaScript(\r
2233                                 script_start + buffer + script_end);\r
2234 \r
2235                 return;\r
2236         }\r
2237 \r
2238         // Handle pasting of a note-to-note link\r
2239         private void handleNoteLink(QMimeData mime) {\r
2240                 for (int i=0; i<mime.urls().size(); i++) {\r
2241                         StringTokenizer tokens = new StringTokenizer(mime.urls().get(i).toString().replace("evernote:///view/", ""), "/");\r
2242                         tokens.nextToken();\r
2243                         tokens.nextToken();\r
2244                         String sid = tokens.nextToken();\r
2245                         String lid = tokens.nextToken();\r
2246                         \r
2247                         if (!sid.equals(currentNote.getGuid()) && !lid.equals(currentNote.getGuid())) {\r
2248                                 \r
2249                                 Note note = conn.getNoteTable().getNote(sid, false, false, false, false, false);\r
2250                                 if (note == null)\r
2251                                         note = conn.getNoteTable().getNote(lid, false, false, false, false, false);\r
2252                 \r
2253                                 if (note == null)\r
2254                                         return;\r
2255 \r
2256                                 // If we've gotten this far, we have a bunch of values.  We need to build the link.\r
2257                                 StringBuffer url = new StringBuffer(100);\r
2258                                 String script_start = new String(\r
2259                                         "document.execCommand('insertHtml', false, '");\r
2260                                 String script_end = new String("');");\r
2261         \r
2262                                 url.append("<a href=\""+mime.urls().get(i).toString() +"\" style=\"color:#69aa35\">");\r
2263                                 url.append(note.getTitle());\r
2264                                 url.append("</a>");\r
2265                                 if (mime.urls().size() > 1)\r
2266                                         url.append("&nbsp;");\r
2267                                 browser.page().mainFrame().evaluateJavaScript(\r
2268                                                 script_start + url + script_end);\r
2269                         }\r
2270                 }\r
2271         }\r
2272         \r
2273         // Handle URLs that are trying to be pasted\r
2274         public void handleUrls(QMimeData mime) {\r
2275                 logger.log(logger.EXTREME, "Starting handleUrls");\r
2276                 FileNameMap fileNameMap = URLConnection.getFileNameMap();\r
2277 \r
2278                 List<QUrl> urlList = mime.urls();\r
2279                 String url = new String();\r
2280                 String script_start = new String(\r
2281                                 "document.execCommand('createLink', false, '");\r
2282                 String script_end = new String("');");\r
2283 \r
2284                 for (int i = 0; i < urlList.size(); i++) {\r
2285                         url = urlList.get(i).toString();\r
2286                         // Find out what type of file we have\r
2287                         String mimeType = fileNameMap.getContentTypeFor(url);\r
2288 \r
2289                         // If null returned, we need to guess at the file type\r
2290                         if (mimeType == null)\r
2291                                 mimeType = "application/"\r
2292                                                 + url.substring(url.lastIndexOf(".") + 1);\r
2293 \r
2294                         // Check if we have an image or some other type of file\r
2295                         if (url.substring(0, 5).equalsIgnoreCase("file:")\r
2296                                         && mimeType.substring(0, 5).equalsIgnoreCase("image")) {\r
2297                                 handleLocalImageURLPaste(mime, mimeType);\r
2298                                 return;\r
2299                         }\r
2300 \r
2301                         boolean smallEnough = checkFileAttachmentSize(url);\r
2302                         if (smallEnough \r
2303                                         && url.substring(0, 5).equalsIgnoreCase("file:")\r
2304                                         && !mimeType.substring(0, 5).equalsIgnoreCase("image")) {\r
2305                                 handleLocalAttachment(mime, mimeType);\r
2306                                 return;\r
2307                         }\r
2308                         browser.page().mainFrame().evaluateJavaScript(\r
2309                                         script_start + url + script_end);\r
2310                 }\r
2311                 return;\r
2312         }\r
2313 \r
2314         // If a URL being pasted is an image URL, then attach the image\r
2315         private void handleLocalImageURLPaste(QMimeData mime, String mimeType) {\r
2316                 List<QUrl> urlList = mime.urls();\r
2317                 String url = new String();\r
2318                 String script_start_image = new String(\r
2319                                 "document.execCommand('insertHtml', false, '");\r
2320                 String script_end = new String("');");\r
2321                 StringBuffer buffer;\r
2322 \r
2323                 // Copy the image over into the resource directory and create a new resource \r
2324                 // record for each url pasted\r
2325                 for (int i = 0; i < urlList.size(); i++) {\r
2326                         url = urlList.get(i).toString();\r
2327 \r
2328                         Resource newRes = createResource(url, i, mimeType, false);\r
2329                         if (newRes == null)\r
2330                                 return;\r
2331                         currentNote.getResources().add(newRes);\r
2332                         buffer = new StringBuffer(100);\r
2333                         \r
2334                         // Open the file & write the data\r
2335                         String fileName = Global.getFileManager().getResDirPath(newRes.getGuid());\r
2336                         QFile tfile = new QFile(fileName);\r
2337                         tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));\r
2338                         tfile.write(newRes.getData().getBody());\r
2339                         tfile.close();\r
2340                         buffer.append(script_start_image);\r
2341                         buffer.append("<img src=\"" + FileUtils.toForwardSlashedPath(fileName));\r
2342 //                      if (mimeType.equalsIgnoreCase("image/jpg"))\r
2343 //                              mimeType = "image/jpeg";\r
2344                         buffer.append("\" en-tag=\"en-media\" type=\"" + mimeType +"\""\r
2345                                         +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""\r
2346                                         +" guid=\"" +newRes.getGuid() +"\""\r
2347                                         +" onContextMenu=\"window.jambi.imageContextMenu(&apos;" +tfile.fileName() +"&apos;);\""\r
2348                                         + " />");\r
2349                         buffer.append(script_end);\r
2350                         browser.page().mainFrame().evaluateJavaScript(buffer.toString());\r
2351                 }\r
2352                 return;\r
2353         }\r
2354         \r
2355 \r
2356         // If a URL being pasted is a local file URL, then attach the file\r
2357         private void handleLocalAttachment(QMimeData mime, String mimeType) {\r
2358                 logger.log(logger.EXTREME, "Attaching local file");\r
2359                 List<QUrl> urlList = mime.urls();\r
2360                 String script_start = new String(\r
2361                                 "document.execCommand('insertHtml', false, '");\r
2362                 String script_end = new String("');");\r
2363                 StringBuffer buffer;\r
2364 \r
2365                         String[] type = mimeType.split("/");\r
2366                         String icon = findIcon(type[1]);\r
2367                         if (icon.equals("attachment.png"))\r
2368                                 icon = findIcon(type[0]);\r
2369                         buffer = new StringBuffer(100);\r
2370 \r
2371                 for (int i = 0; i < urlList.size(); i++) {\r
2372                         String url = urlList.get(i).toString();\r
2373 \r
2374                         // Start building the HTML\r
2375                         if (icon.equals("attachment.png"))\r
2376                                 icon = findIcon(url.substring(url.lastIndexOf(".")+1));\r
2377                         String imageURL = FileUtils.toFileURLString(Global.getFileManager().getImageDirFile(icon));\r
2378 \r
2379                         logger.log(logger.EXTREME, "Creating resource ");\r
2380                         Resource newRes = createResource(url, i, mimeType, true);\r
2381                         if (newRes == null)\r
2382                                 return;\r
2383                         logger.log(logger.EXTREME, "New resource size: " +newRes.getData().getSize());\r
2384                         currentNote.getResources().add(newRes);\r
2385                         \r
2386                         String fileName = newRes.getGuid() + Global.attachmentNameDelimeter+newRes.getAttributes().getFileName();\r
2387                         // If we have a PDF, we need to setup the preview.\r
2388                         if (icon.equalsIgnoreCase("pdf.png") && Global.pdfPreview()) {\r
2389                                 logger.log(logger.EXTREME, "Setting up PDF preview");\r
2390                                 if (newRes.getAttributes() != null && \r
2391                                                 newRes.getAttributes().getFileName() != null && \r
2392                                                 !newRes.getAttributes().getFileName().trim().equals(""))\r
2393                                         fileName = newRes.getGuid()+Global.attachmentNameDelimeter+\r
2394                                                 newRes.getAttributes().getFileName();\r
2395                                 else\r
2396                                         fileName = newRes.getGuid()+".pdf";\r
2397                                 QFile file = new QFile(Global.getFileManager().getResDirPath(fileName));\r
2398                         QFile.OpenMode mode = new QFile.OpenMode();\r
2399                         mode.set(QFile.OpenModeFlag.WriteOnly);\r
2400                         file.open(mode);\r
2401                         QDataStream out = new QDataStream(file);\r
2402 //                      Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(newRes.getGuid(), true);\r
2403                                 QByteArray binData = new QByteArray(newRes.getData().getBody());\r
2404 //                              resBinary = null;\r
2405                         out.writeBytes(binData.toByteArray());\r
2406                         file.close();\r
2407 \r
2408                                 PDFPreview pdfPreview = new PDFPreview();\r
2409                                 if (pdfPreview.setupPreview(Global.getFileManager().getResDirPath(fileName), "pdf",0)) {\r
2410                                 imageURL = file.fileName() + ".png";\r
2411                                 }\r
2412                         }\r
2413                         \r
2414                         logger.log(logger.EXTREME, "Generating link tags");\r
2415                         buffer.delete(0, buffer.length());\r
2416                         buffer.append("<a en-tag=\"en-media\" guid=\"" +newRes.getGuid()+"\" ");\r
2417                         buffer.append(" onContextMenu=\"window.jambi.imageContextMenu(&apos;")\r
2418                       .append(Global.getFileManager().getResDirPath(fileName))\r
2419                       .append("&apos;);\" ");                   \r
2420                         buffer.append("type=\"" + mimeType + "\" href=\"nnres://" + fileName +"\" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\" >");\r
2421                         buffer.append("<img src=\"" + imageURL + "\" title=\"" +newRes.getAttributes().getFileName());\r
2422                         buffer.append("\"></img>");\r
2423                         buffer.append("</a>");\r
2424                         browser.page().mainFrame().evaluateJavaScript(\r
2425                                         script_start + buffer.toString() + script_end);\r
2426                 }\r
2427                 return;\r
2428         }\r
2429 \r
2430         private Resource createResource(String url, int sequence, String mime, boolean attachment) {\r
2431                 logger.log(logger.EXTREME, "Inside create resource");\r
2432                 QFile resourceFile; \r
2433                 //These two lines are added to handle odd characters in the name like #.  Without it\r
2434                 // toLocalFile() chokes and returns the wrong name.\r
2435                 logger.log(logger.EXTREME, "File URL:" +url);\r
2436                 String whichOS = System.getProperty("os.name");\r
2437                 if (whichOS.contains("Windows")) \r
2438                         url = url.replace("file:///", "");\r
2439                 else\r
2440                         url = url.replace("file://", "");\r
2441                 String urlTest = new QUrl(url).toLocalFile();\r
2442                 logger.log(logger.EXTREME, "File URL toLocalFile():" +urlTest);\r
2443                 urlTest = url;\r
2444                 if (!urlTest.equals(""))\r
2445                         url = urlTest;\r
2446 //              url = url.replace("/", File.separator);\r
2447                 logger.log(logger.EXTREME, "Reading from file to create resource:" +url);\r
2448                 resourceFile = new QFile(url); \r
2449         resourceFile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly));\r
2450         logger.log(logger.EXTREME, "Error opening file "+url.toString()  +": "+resourceFile.errorString());\r
2451         byte[] fileData = resourceFile.readAll().toByteArray();\r
2452         resourceFile.close();\r
2453         logger.log(logger.EXTREME, "File Length: " +fileData.length);\r
2454         if (fileData.length == 0)\r
2455                 return null;\r
2456         MessageDigest md;\r
2457         try {\r
2458                 logger.log(logger.EXTREME, "Generating MD5");\r
2459                 md = MessageDigest.getInstance("MD5");\r
2460                 md.update(fileData);\r
2461                 byte[] hash = md.digest();\r
2462   \r
2463                 Resource r = new Resource();\r
2464                 Calendar time = new GregorianCalendar();\r
2465                 long prevTime = time.getTimeInMillis();\r
2466                 while (prevTime == time.getTimeInMillis()) {\r
2467                         time = new GregorianCalendar();\r
2468                 }\r
2469                 r.setGuid(time.getTimeInMillis()+new Integer(sequence).toString());\r
2470                 r.setNoteGuid(currentNote.getGuid());\r
2471                 r.setMime(mime);\r
2472                 r.setActive(true);\r
2473                 r.setUpdateSequenceNum(0);\r
2474                 r.setWidth((short) 0);\r
2475                 r.setHeight((short) 0);\r
2476                 r.setDuration((short) 0);\r
2477                                 \r
2478                 Data d = new Data();\r
2479                 d.setBody(fileData);\r
2480                 d.setBodyIsSet(true);\r
2481                 d.setBodyHash(hash);\r
2482                 d.setBodyHashIsSet(true);\r
2483                 r.setData(d);\r
2484                 d.setSize(fileData.length);\r
2485                 \r
2486                 int fileNamePos = url.lastIndexOf(File.separator);\r
2487                 if (fileNamePos == -1)\r
2488                         fileNamePos = url.lastIndexOf("/");\r
2489                         String fileName = url.substring(fileNamePos+1);\r
2490                 ResourceAttributes a = new ResourceAttributes();\r
2491                 a.setAltitude(0);\r
2492                 a.setAltitudeIsSet(false);\r
2493                 a.setLongitude(0);\r
2494                 a.setLongitudeIsSet(false);\r
2495                 a.setLatitude(0);\r
2496                 a.setLatitudeIsSet(false);\r
2497                 a.setCameraMake("");\r
2498                 a.setCameraMakeIsSet(false);\r
2499                 a.setCameraModel("");\r
2500                 a.setCameraModelIsSet(false);\r
2501                 a.setAttachment(attachment);\r
2502                 a.setAttachmentIsSet(true);\r
2503                 a.setClientWillIndex(false);\r
2504                 a.setClientWillIndexIsSet(true);\r
2505                 a.setRecoType("");\r
2506                 a.setRecoTypeIsSet(false);\r
2507                 a.setSourceURL(url);\r
2508                 a.setSourceURLIsSet(true);\r
2509                 a.setTimestamp(0);\r
2510                 a.setTimestampIsSet(false);\r
2511                 a.setFileName(fileName);\r
2512                 a.setFileNameIsSet(true);\r
2513                 r.setAttributes(a);\r
2514                 \r
2515                 conn.getNoteTable().noteResourceTable.saveNoteResource(r, true);\r
2516                 logger.log(logger.EXTREME, "Resource created");\r
2517                 return r;\r
2518         } catch (NoSuchAlgorithmException e1) {\r
2519                 e1.printStackTrace();\r
2520                 }\r
2521         return null;\r
2522         }\r
2523         \r
2524 \r
2525     // find the appropriate icon for an attachment\r
2526     private String findIcon(String appl) {\r
2527         appl = appl.toLowerCase();\r
2528         File f = Global.getFileManager().getImageDirFile(appl + ".png");\r
2529         if (f.exists())\r
2530                 return appl+".png";\r
2531         return "attachment.png";\r
2532     }\r
2533 \r
2534 \r
2535 \r
2536         // Check the file attachment to be sure it isn't over 25 mb\r
2537         private boolean checkFileAttachmentSize(String url) {\r
2538                 String fileName = url.substring(8);\r
2539                 QFile resourceFile = new QFile(fileName);\r
2540                 resourceFile.open(new QIODevice.OpenMode(\r
2541                                 QIODevice.OpenModeFlag.ReadOnly));\r
2542                 long size = resourceFile.size();\r
2543                 resourceFile.close();\r
2544                 size = size / 1024 / 1024;\r
2545                 if (size < 50 && Global.isPremium())\r
2546                         return true;\r
2547                 if (size < 25)\r
2548                         return true;\r
2549 \r
2550                 String error = tr("A file attachment may not exceed 25MB.");\r
2551                 QMessageBox.information(this, tr("Attachment Size"), error);\r
2552                 return false;\r
2553         }\r
2554 \r
2555 \r
2556         @SuppressWarnings("unused")\r
2557         private void createdChanged() {\r
2558                 QDateTime dt = new QDateTime();\r
2559                 dt.setDate(createdDate.date());\r
2560                 dt.setTime(createdTime.time());\r
2561                 noteSignal.createdDateChanged.emit(currentNote.getGuid(), dt);\r
2562 \r
2563         }\r
2564 \r
2565         @SuppressWarnings("unused")\r
2566         private void alteredChanged() {\r
2567                 QDateTime dt = new QDateTime();\r
2568                 dt.setDate(alteredDate.date());\r
2569                 dt.setTime(alteredTime.time());\r
2570                 noteSignal.alteredDateChanged.emit(currentNote.getGuid(), dt);\r
2571         }\r
2572 \r
2573         @SuppressWarnings("unused")\r
2574         private void subjectDateTimeChanged() {\r
2575                 QDateTime dt = new QDateTime();\r
2576                 dt.setDate(subjectDate.date());\r
2577                 dt.setTime(subjectTime.time());\r
2578                 noteSignal.subjectDateChanged.emit(currentNote.getGuid(), dt);\r
2579 \r
2580         }\r
2581 \r
2582         @SuppressWarnings("unused")\r
2583         private void sourceUrlChanged() {\r
2584                 noteSignal.sourceUrlChanged.emit(currentNote.getGuid(), urlText.text());\r
2585         }\r
2586 \r
2587         @SuppressWarnings("unused")\r
2588         private void authorChanged() {\r
2589                 noteSignal.authorChanged.emit(currentNote.getGuid(), authorText.text());\r
2590         }\r
2591         \r
2592         @SuppressWarnings("unused")\r
2593         private void geoBoxChanged() {\r
2594                 int index = geoBox.currentIndex();\r
2595                 geoBox.setCurrentIndex(0);\r
2596                 if (index == 1) {\r
2597                         GeoDialog box = new GeoDialog();\r
2598                         box.setLongitude(currentNote.getAttributes().getLongitude());\r
2599                         box.setLatitude(currentNote.getAttributes().getLatitude());\r
2600                         box.setAltitude(currentNote.getAttributes().getAltitude());\r
2601                         box.exec();\r
2602                         if (!box.okPressed())\r
2603                                 return;\r
2604                         double alt = box.getAltitude();\r
2605                         double lat = box.getLatitude();\r
2606                         double lon = box.getLongitude();\r
2607                         if (alt != currentNote.getAttributes().getAltitude() ||\r
2608                                 lon != currentNote.getAttributes().getLongitude() ||\r
2609                                 lat != currentNote.getAttributes().getLatitude()) {\r
2610                                         noteSignal.geoChanged.emit(currentNote.getGuid(), lon, lat, alt);\r
2611                                         currentNote.getAttributes().setAltitude(alt);\r
2612                                         currentNote.getAttributes().setLongitude(lon);\r
2613                                         currentNote.getAttributes().setLatitude(lat);\r
2614                         }\r
2615                 }\r
2616                 \r
2617                 if (index == 2) {\r
2618                         noteSignal.geoChanged.emit(currentNote.getGuid(), 0.0, 0.0, 0.0);\r
2619                         currentNote.getAttributes().setAltitude(0.0);\r
2620                         currentNote.getAttributes().setLongitude(0.0);\r
2621                         currentNote.getAttributes().setLatitude(0.0);\r
2622                 }\r
2623                 \r
2624                 if (index == 3 || index == 0) {\r
2625                         QDesktopServices.openUrl(new QUrl("http://maps.google.com/maps?z=6&q="+currentNote.getAttributes().getLatitude() +"," +currentNote.getAttributes().getLongitude()));\r
2626                 }\r
2627         }\r
2628 \r
2629         // ************************************************************\r
2630         // * User chose to save an attachment. Pares out the request *\r
2631         // * into a guid & file. Save the result. *\r
2632         // ************************************************************\r
2633         public void downloadAttachment(QNetworkRequest request) {\r
2634                 String guid;\r
2635                 QFileDialog fd = new QFileDialog(this);\r
2636                 fd.setFileMode(FileMode.AnyFile);\r
2637                 fd.setConfirmOverwrite(true);\r
2638                 fd.setWindowTitle(tr("Save File"));\r
2639                 fd.setAcceptMode(AcceptMode.AcceptSave);\r
2640                 fd.setDirectory(System.getProperty("user.home"));\r
2641                 String name = request.url().toString();\r
2642 \r
2643                 int pos = name.lastIndexOf(Global.attachmentNameDelimeter);\r
2644                 if (pos > -1) {\r
2645                         guid = name.substring(0, pos).replace("nnres://", "");\r
2646                         name = name.substring(pos +Global.attachmentNameDelimeter.length());\r
2647                         fd.selectFile(name);\r
2648                         pos = name.lastIndexOf('.');\r
2649                         if (pos > -1) {\r
2650                                 String mimeType = "(*." + name.substring(pos + 1)\r
2651                                                 + ");; All Files (*)";\r
2652                                 fd.setFilter(tr(mimeType));\r
2653                         }\r
2654                 } else {\r
2655                         guid = name;\r
2656                 }\r
2657 \r
2658                 // Strip URL prefix and base dir\r
2659                 guid = guid.replace("nnres://", "")\r
2660                         .replace(FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath()), "");\r
2661                 guid = guid.replace("file://", "").replace("/", "")\r
2662                 .replace(FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath()), "");\r
2663 \r
2664                 pos = guid.lastIndexOf('.');\r
2665                 if (pos > 0)\r
2666                         guid = guid.substring(0,pos);\r
2667                 if (fd.exec() != 0 && fd.selectedFiles().size() > 0) {\r
2668                         name = name.replace('\\', '/');\r
2669                         Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);\r
2670                         QFile saveFile = new QFile(fd.selectedFiles().get(0));\r
2671                         QFile.OpenMode mode = new QFile.OpenMode();\r
2672                         mode.set(QFile.OpenModeFlag.WriteOnly);\r
2673                         saveFile.open(mode);\r
2674                         QDataStream saveOut = new QDataStream(saveFile);\r
2675                         QByteArray binData = new QByteArray(resBinary.getData().getBody());\r
2676                         saveOut.writeBytes(binData.toByteArray());\r
2677                         saveFile.close();\r
2678 \r
2679                 }\r
2680         }\r
2681 \r
2682         \r
2683         // ************************************************************\r
2684         // * User chose to save an attachment. Pares out the request *\r
2685         // * into a guid & file. Save the result. --- DONE FROM downloadAttachment now!!!!!   \r
2686         // ************************************************************\r
2687         public void downloadImage(QNetworkRequest request) {\r
2688                 QFileDialog fd = new QFileDialog(this);\r
2689                 fd.setFileMode(FileMode.AnyFile);\r
2690                 fd.setConfirmOverwrite(true);\r
2691                 fd.setWindowTitle(tr("Save File"));\r
2692                 fd.setAcceptMode(AcceptMode.AcceptSave);\r
2693                 fd.setDirectory(System.getProperty("user.home"));\r
2694                 String name = request.url().toString();\r
2695                 name = name.replace("nnres://", "");\r
2696                 String dPath = FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath());\r
2697                 name = name.replace(dPath, "");\r
2698                 int pos = name.lastIndexOf('.');\r
2699                 String guid = name;\r
2700                 if (pos > -1) {\r
2701                         String mimeType = "(*." + name.substring(pos + 1)\r
2702                         + ");; All Files (*)";\r
2703                                 fd.setFilter(tr(mimeType));\r
2704                         guid = guid.substring(0,pos);\r
2705                 }\r
2706                 pos = name.lastIndexOf(Global.attachmentNameDelimeter);\r
2707                 if (pos > -1) {\r
2708                         guid = name.substring(0, pos);\r
2709                         fd.selectFile(name.substring(pos+Global.attachmentNameDelimeter.length()));             \r
2710                 }\r
2711                 if (fd.exec() != 0 && fd.selectedFiles().size() > 0) {\r
2712                         Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);\r
2713                         String fileName = fd.selectedFiles().get(0);\r
2714                         QFile saveFile = new QFile(fileName);\r
2715                         QFile.OpenMode mode = new QFile.OpenMode();\r
2716                         mode.set(QFile.OpenModeFlag.WriteOnly);\r
2717                         saveFile.open(mode);\r
2718                         QDataStream saveOut = new QDataStream(saveFile);\r
2719                         QByteArray binData = new QByteArray(resBinary.getData().getBody());\r
2720                         saveOut.writeBytes(binData.toByteArray());\r
2721                         saveFile.close();\r
2722                 }\r
2723         }\r
2724 \r
2725         \r
2726         // *************************************************************\r
2727         // * decrypt any hidden text.  We could do an XML parse, but \r
2728         // * it is quicker here just to scan for an <img tag & do the fix\r
2729         // * the manual way\r
2730         // *************************************************************\r
2731         private void removeEncryption(String id, String plainText, boolean permanent, String slot) {\r
2732                 if (!permanent) {\r
2733                         plainText = " <table class=\"en-crypt-temp\" slot=\""\r
2734                                         +slot \r
2735                                         +"\""\r
2736                                         +"border=1 width=100%><tbody><tr><td>"\r
2737                                         +plainText+"</td></tr></tbody></table>";\r
2738                 }\r
2739                 \r
2740                 String html = browser.page().mainFrame().toHtml();\r
2741                 String text = html;\r
2742                 int imagePos = html.indexOf("<img");\r
2743                 int endPos;\r
2744                 for ( ;imagePos>0; ) {\r
2745                         // Find the end tag\r
2746                         endPos = text.indexOf(">", imagePos);\r
2747                         String tag = text.substring(imagePos-1,endPos);\r
2748                         if (tag.indexOf("id=\""+id+"\"") > -1) {\r
2749                                         text = text.substring(0,imagePos) +plainText+text.substring(endPos+1);  \r
2750                                         QTextCodec codec = QTextCodec.codecForName("UTF-8");\r
2751                                 QByteArray unicode =  codec.fromUnicode(text);\r
2752                                         setContent(unicode);\r
2753                                         if (permanent)\r
2754                                                 contentChanged();\r
2755                         }\r
2756                         imagePos = text.indexOf("<img", imagePos+1);\r
2757                 }\r
2758         }\r
2759         \r
2760         \r
2761         //****************************************************************\r
2762         //* Focus shortcuts\r
2763         //****************************************************************\r
2764         @SuppressWarnings("unused")\r
2765         private void focusTitle() {\r
2766                 titleLabel.setFocus();\r
2767         }\r
2768         @SuppressWarnings("unused")\r
2769         private void focusTag() {\r
2770                 tagEdit.setFocus();\r
2771         }\r
2772         @SuppressWarnings("unused")\r
2773         private void focusNote() {\r
2774                 browser.setFocus();\r
2775         }\r
2776         @SuppressWarnings("unused")\r
2777         private void focusAuthor() {\r
2778                 authorLabel.setFocus();\r
2779         }\r
2780         @SuppressWarnings("unused")\r
2781         private void focusUrl() {\r
2782                 urlLabel.setFocus();\r
2783         }\r
2784         \r
2785 \r
2786         //*****************************************************************\r
2787         //* Set the document background color\r
2788         //*****************************************************************\r
2789         public void setBackgroundColor(String color) {\r
2790                 String js = "function changeBackground(color) {"\r
2791                         +"document.body.style.background = color;"\r
2792                         +"}" \r
2793                         +"changeBackground('" +color+"');";\r
2794                 browser.page().mainFrame().evaluateJavaScript(js);\r
2795                 contentChanged();\r
2796         }\r
2797         \r
2798         \r
2799         //****************************************************************\r
2800         //* MicroFocus changed\r
2801         //****************************************************************\r
2802         private void microFocusChanged() {\r
2803                 boldButton.setDown(false);\r
2804                 italicButton.setDown(false);\r
2805                 underlineButton.setDown(false);\r
2806                 browser.openAction.setEnabled(false);\r
2807                 browser.downloadAttachment.setEnabled(false);\r
2808                 browser.downloadImage.setEnabled(false);\r
2809                 browser.rotateImageLeft.setEnabled(false);\r
2810                 browser.rotateImageRight.setEnabled(false);\r
2811                 browser.insertTableAction.setEnabled(true);\r
2812                 browser.deleteTableColumnAction.setEnabled(false);\r
2813                 browser.insertTableRowAction.setEnabled(false);\r
2814                 browser.insertTableColumnAction.setEnabled(false);\r
2815                 browser.deleteTableRowAction.setEnabled(false);\r
2816                 browser.insertLinkAction.setText(tr("Insert Hyperlink"));\r
2817                 insertHyperlink = true;\r
2818                 browser.insertQuickLinkAction.setEnabled(true);\r
2819                 currentHyperlink ="";\r
2820                 insideList = false;\r
2821                 insideTable = false;\r
2822                 insideEncryption = false;\r
2823                 forceTextPaste = false;\r
2824                 \r
2825                 String js = new String( "function getCursorPos() {"\r
2826                         +"var cursorPos;"\r
2827                         +"if (window.getSelection) {"\r
2828                         +"   var selObj = window.getSelection();"\r
2829                         +"   var selRange = selObj.getRangeAt(0);"\r
2830                         +"   var workingNode = window.getSelection().anchorNode.parentNode;"\r
2831                         +"   while(workingNode != null) { " \r
2832 //                      +"      window.jambi.printNode(workingNode.nodeName);"\r
2833                         +"      if (workingNode.nodeName=='TABLE') { if (workingNode.getAttribute('class').toLowerCase() == 'en-crypt-temp') window.jambi.insideEncryption(); }"\r
2834                         +"      if (workingNode.nodeName=='B') window.jambi.boldActive();"\r
2835                         +"      if (workingNode.nodeName=='I') window.jambi.italicActive();"\r
2836                         +"      if (workingNode.nodeName=='U') window.jambi.underlineActive();"\r
2837                         +"      if (workingNode.nodeName=='UL') window.jambi.setInsideList();"\r
2838                         +"      if (workingNode.nodeName=='OL') window.jambi.setInsideList();"\r
2839                         +"      if (workingNode.nodeName=='LI') window.jambi.setInsideList();"\r
2840                         +"      if (workingNode.nodeName=='TBODY') window.jambi.setInsideTable();"\r
2841                         +"      if (workingNode.nodeName=='A') {for(var x = 0; x < workingNode.attributes.length; x++ ) {if (workingNode.attributes[x].nodeName.toLowerCase() == 'href') window.jambi.setInsideLink(workingNode.attributes[x].nodeValue);}}"\r
2842                         +"      if (workingNode.nodeName=='SPAN') {"\r
2843                         +"         if (workingNode.getAttribute('style') == 'text-decoration: underline;') window.jambi.underlineActive();"\r
2844                         +"      }"\r
2845                         +"      workingNode = workingNode.parentNode;"\r
2846                         +"   }"\r
2847                         +"}"\r
2848                         +"} getCursorPos();");\r
2849                 browser.page().mainFrame().evaluateJavaScript(js);\r
2850         }\r
2851         \r
2852         public void printNode(String n) {\r
2853                 System.out.println("Node Vaule: " +n);\r
2854         }\r
2855         \r
2856         public void insideEncryption() {\r
2857                 insideEncryption = true;\r
2858                 forceTextPaste();\r
2859         }\r
2860         \r
2861         //****************************************************************\r
2862         //* Insert a table row\r
2863         //****************************************************************\r
2864         public void insertTableRow() {\r
2865                 \r
2866                 String js = new String( "function insertTableRow() {"\r
2867                         +"   var selObj = window.getSelection();"\r
2868                         +"   var selRange = selObj.getRangeAt(0);"\r
2869                         +"   var workingNode = window.getSelection().anchorNode.parentNode;"\r
2870                         +"   var cellCount = 0;"\r
2871                         +"   while(workingNode != null) { " \r
2872                         +"      if (workingNode.nodeName.toLowerCase()=='tr') {"\r
2873                         +"           row = document.createElement('TR');"\r
2874                         +"           var nodes = workingNode.getElementsByTagName('td');"\r
2875                         +"           for (j=0; j<nodes.length; j=j+1) {"\r
2876                         +"              cell = document.createElement('TD');"\r
2877                         +"              cell.innerHTML='&nbsp;';"\r
2878                         +"              row.appendChild(cell);"\r
2879                         +"           }"                 \r
2880                         +"           workingNode.parentNode.insertBefore(row,workingNode.nextSibling);"\r
2881                         +"           return;"\r
2882                         +"      }"\r
2883                         +"      workingNode = workingNode.parentNode;"\r
2884                         +"   }"\r
2885                         +"} insertTableRow();");\r
2886                 browser.page().mainFrame().evaluateJavaScript(js);\r
2887                 contentChanged();\r
2888         }\r
2889         \r
2890         public void insertTableColumn() {\r
2891                 String js = new String( "function insertTableColumn() {"\r
2892                                 +"   var selObj = window.getSelection();"\r
2893                                 +"   var selRange = selObj.getRangeAt(0);"\r
2894                                 +"   var workingNode = window.getSelection().anchorNode.parentNode;"\r
2895                                 +"   var current = 0;"\r
2896                                 +"   while (workingNode.nodeName.toLowerCase() != 'table' && workingNode != null) {"\r
2897                                 +"       if (workingNode.nodeName.toLowerCase() == 'td') {"\r
2898                                 +"          var td = workingNode;"\r
2899                                 +"          while (td.previousSibling != null) { " \r
2900                                 +"             current = current+1; td = td.previousSibling;"\r
2901                                 +"          }"\r
2902                                 +"       }"\r
2903                                 +"       workingNode = workingNode.parentNode; "\r
2904                                 +"   }"\r
2905                                 +"   if (workingNode == null) return;"\r
2906                                 +"   for (var i=0; i<workingNode.rows.length; i++) { " \r
2907                                 +"      var cell = workingNode.rows[i].insertCell(current+1); "                 \r
2908                                 +"      cell.innerHTML = '&nbsp'; "\r
2909                                 +"   }"\r
2910                                 +"} insertTableColumn();");\r
2911                         browser.page().mainFrame().evaluateJavaScript(js);\r
2912                         contentChanged();\r
2913         }\r
2914         \r
2915         //****************************************************************\r
2916         //* Delete a table row\r
2917         //****************************************************************\r
2918         public void deleteTableRow() {\r
2919                 \r
2920                 String js = new String( "function deleteTableRow() {"\r
2921                         +"   var selObj = window.getSelection();"\r
2922                         +"   var selRange = selObj.getRangeAt(0);"\r
2923                         +"   var workingNode = window.getSelection().anchorNode.parentNode;"\r
2924                         +"   var cellCount = 0;"\r
2925                         +"   while(workingNode != null) { " \r
2926                         +"      if (workingNode.nodeName.toLowerCase()=='tr') {"\r
2927                         +"           workingNode.parentNode.removeChild(workingNode);"\r
2928                         +"           return;"\r
2929                         +"      }"\r
2930                         +"      workingNode = workingNode.parentNode;"\r
2931                         +"   }"\r
2932                         +"} deleteTableRow();");\r
2933                 browser.page().mainFrame().evaluateJavaScript(js);\r
2934                 contentChanged();\r
2935         }\r
2936 \r
2937         public void deleteTableColumn() {\r
2938                 String js = new String( "function deleteTableColumn() {"\r
2939                                 +"   var selObj = window.getSelection();"\r
2940                                 +"   var selRange = selObj.getRangeAt(0);"\r
2941                                 +"   var workingNode = window.getSelection().anchorNode.parentNode;"\r
2942                                 +"   var current = 0;"\r
2943                                 +"   while (workingNode.nodeName.toLowerCase() != 'table' && workingNode != null) {"\r
2944                                 +"       if (workingNode.nodeName.toLowerCase() == 'td') {"\r
2945                                 +"          var td = workingNode;"\r
2946                                 +"          while (td.previousSibling != null) { " \r
2947                                 +"             current = current+1; td = td.previousSibling;"\r
2948                                 +"          }"\r
2949                                 +"       }"\r
2950                                 +"       workingNode = workingNode.parentNode; "\r
2951                                 +"   }"\r
2952                                 +"   if (workingNode == null) return;"\r
2953                                 +"   for (var i=0; i<workingNode.rows.length; i++) { " \r
2954                                 +"      workingNode.rows[i].deleteCell(current); "                      \r
2955                                 +"   }"\r
2956                                 +"} deleteTableColumn();");\r
2957                         browser.page().mainFrame().evaluateJavaScript(js);\r
2958                         contentChanged();\r
2959         }\r
2960         \r
2961         \r
2962         public void setInsideTable() {\r
2963                 browser.insertTableRowAction.setEnabled(true);\r
2964                 browser.insertTableColumnAction.setEnabled(true);\r
2965                 browser.deleteTableRowAction.setEnabled(true);\r
2966                 browser.deleteTableColumnAction.setEnabled(true);\r
2967                 browser.insertTableAction.setEnabled(false);\r
2968                 browser.encryptAction.setEnabled(false);\r
2969                 insideTable = true;\r
2970         }\r
2971         \r
2972         public void setInsideLink(String link) {\r
2973                 browser.insertLinkAction.setText(tr("Edit Hyperlink"));\r
2974                 currentHyperlink = link;\r
2975                 insertHyperlink = false;\r
2976         }\r
2977         \r
2978         public void italicActive() {\r
2979                 italicButton.setDown(true);\r
2980         }\r
2981         public void boldActive() {\r
2982                 boldButton.setDown(true);\r
2983         }\r
2984         public void underlineActive() {\r
2985                 underlineButton.setDown(true);\r
2986         }\r
2987         public void forceTextPaste() {\r
2988                 forceTextPaste = true;\r
2989         }\r
2990         public void imageContextMenu(String f) {\r
2991                 browser.downloadImage.setEnabled(true);\r
2992                 browser.rotateImageRight.setEnabled(true);\r
2993                 browser.rotateImageLeft.setEnabled(true);\r
2994                 browser.openAction.setEnabled(true);\r
2995                 selectedFile = f;\r
2996         }\r
2997         public void rotateImageRight() {\r
2998                 QWebSettings.setMaximumPagesInCache(0);\r
2999                 QWebSettings.setObjectCacheCapacities(0, 0, 0);\r
3000                 QImage image = new QImage(selectedFile);\r
3001                 QMatrix matrix = new QMatrix();\r
3002                 matrix.rotate( 90.0 );\r
3003                 image = image.transformed(matrix);\r
3004                 image.save(selectedFile);\r
3005                 QWebSettings.setMaximumPagesInCache(0);\r
3006                 QWebSettings.setObjectCacheCapacities(0, 0, 0);\r
3007                 browser.setHtml(browser.page().mainFrame().toHtml());\r
3008                 browser.reload();\r
3009                 contentChanged();\r
3010                 resourceSignal.contentChanged.emit(selectedFile);\r
3011 \r
3012         }\r
3013         public void rotateImageLeft() {\r
3014                 QImage image = new QImage(selectedFile);\r
3015                 QMatrix matrix = new QMatrix();\r
3016                 matrix.rotate( -90.0 );\r
3017                 image = image.transformed(matrix);\r
3018                 image.save(selectedFile);\r
3019                 browser.setHtml(browser.page().mainFrame().toHtml());\r
3020                 browser.reload();\r
3021                 contentChanged();\r
3022                 resourceSignal.contentChanged.emit(selectedFile);\r
3023         }\r
3024         public void resourceContextMenu(String f) {\r
3025                 browser.downloadAttachment.setEnabled(true);\r
3026                 browser.openAction.setEnabled(true);\r
3027                 selectedFile = f;\r
3028         }\r
3029         public void latexContextMenu(String f) {\r
3030                 browser.downloadImage.setEnabled(true);\r
3031                 browser.rotateImageRight.setEnabled(true);\r
3032                 browser.rotateImageLeft.setEnabled(true);\r
3033                 browser.openAction.setEnabled(true);\r
3034                 selectedFile = f;\r
3035         }\r
3036 \r
3037         //****************************************************************\r
3038         //* Apply CSS style to specified word\r
3039         //****************************************************************\r
3040 /*      public void applyStyleToWords(String word, String style) {\r
3041                 QFile script = new QFile("D:\\NeverNote\\js\\hilight1.js");\r
3042                 script.open(OpenModeFlag.ReadOnly);\r
3043                 String s = script.readAll().toString();\r
3044                 String js = new String(s +" findit('"+word+"', '"+style+"');");\r
3045                 browser.page().mainFrame().evaluateJavaScript(js);\r
3046                 System.out.println(getContent());\r
3047         }\r
3048 */      \r
3049         //****************************************************************\r
3050         //* Someone tried to paste a resource between notes, so we need  *\r
3051         //* to do some special handling.                                 *\r
3052         //****************************************************************\r
3053         private String fixInternotePaste(String text) {\r
3054                 logger.log(logger.EXTREME, "Fixing internote paste");\r
3055                 String returnValue = fixInternotePasteSearch(text, "<img", "src=\"");\r
3056                 return fixInternotePasteSearch(returnValue, "<a", "href=\"nnres://");\r
3057         }\r
3058         private String fixInternotePasteSearch(String text, String type, String locTag) {\r
3059                 \r
3060                 // First, let's fix the images.\r
3061                 int startPos = text.indexOf(type);\r
3062                 int endPos;\r
3063                 for (; startPos>=0;) {\r
3064                         endPos = text.indexOf(">", startPos+1);\r
3065                         String segment = text.substring(startPos, endPos);\r
3066                         if (segment.indexOf("en-tag") > -1) {\r
3067                                 String newSegment = segment;\r
3068                                 \r
3069                                 int guidStartPos = segment.indexOf("guid=\"");\r
3070                                 int guidEndPos = segment.indexOf("\"", guidStartPos+7);\r
3071                                 String guid = segment.substring(guidStartPos+6,guidEndPos);\r
3072                                 \r
3073                                 int mimeStartPos = segment.indexOf("type");\r
3074                                 int mimeEndPos = segment.indexOf("\"", mimeStartPos+7);\r
3075                                 String mime = segment.substring(mimeStartPos+6,mimeEndPos);\r
3076 \r
3077                                 int srcStartPos = segment.indexOf("src");\r
3078                                 int srcEndPos = segment.indexOf("\"", srcStartPos+6);\r
3079                                 String src = segment.substring(srcStartPos+5,srcEndPos);\r
3080                                 \r
3081                                 Calendar currentTime = new GregorianCalendar();\r
3082                                 Long l = new Long(currentTime.getTimeInMillis());\r
3083                                 long prevTime = l;\r
3084                                 while (l==prevTime) {\r
3085                                         currentTime = new GregorianCalendar();\r
3086                                         l= new Long(currentTime.getTimeInMillis());\r
3087                                 }\r
3088                                 \r
3089                                 Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);\r
3090                                 // if r==null, then the image doesn't exist (it was probably cut out of another note, so \r
3091                                 // we need to recereate it\r
3092                                 if (r==null) {\r
3093                                         r = createResource(src, 1, mime, false);\r
3094                                         if (r==null)\r
3095                                                 return "";\r
3096                                 }\r
3097                         String randint = new String(Long.toString(l));\r
3098                         String extension = null;\r
3099                         if (r.getMime()!= null) {\r
3100                                 extension = r.getMime().toLowerCase();\r
3101                                 if (extension.indexOf("/")>-1)\r
3102                                         extension = extension.substring(extension.indexOf("/")+1);\r
3103                         }\r
3104                         String newFile = randint;\r
3105                         if (r.getAttributes().getFileName() != null && r.getAttributes().getFileName() != "")\r
3106                                 if (!locTag.startsWith("src"))\r
3107                                         newFile = newFile+Global.attachmentNameDelimeter+r.getAttributes().getFileName();\r
3108                         r.setNoteGuid(currentNote.getGuid());\r
3109                         \r
3110                         r.setGuid(randint);\r
3111                         conn.getNoteTable().noteResourceTable.saveNoteResource(r, true);\r
3112                                 QFile f = new QFile(Global.getFileManager().getResDirPath(newFile));\r
3113                                 QByteArray bin = new QByteArray(r.getData().getBody());\r
3114                                 f.open(QFile.OpenModeFlag.WriteOnly);\r
3115                                 f.write(bin);\r
3116                                 f.close();\r
3117                                 newSegment = newSegment.replace("guid=\""+guid, "guid=\""+randint);\r
3118                                 currentNote.getResources().add(r);\r
3119                                 \r
3120                                 int startSrcPos = newSegment.indexOf(locTag);\r
3121                                 int endSrcPos = newSegment.indexOf("\"",startSrcPos+locTag.length()+1);\r
3122                                 String source; \r
3123                                 if (locTag.startsWith("src")) {\r
3124                                          source = newSegment.substring(startSrcPos+locTag.length(),endSrcPos);\r
3125                                                 newSegment = newSegment.replace(source,\r
3126                                                         FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath(newFile)));\r
3127                                 } else {\r
3128                                         source = newSegment.substring(startSrcPos+locTag.length(),endSrcPos);\r
3129                                         newSegment = newSegment.replace(source, newFile);\r
3130                                 }\r
3131                                 \r
3132                                 text = text.substring(0,startPos) + newSegment + text.substring(endPos);\r
3133                         }\r
3134                         startPos = text.indexOf(type, startPos+1);\r
3135                 }\r
3136                 return text;\r
3137         }\r
3138 \r
3139 \r
3140         public void nextPage(String file) {\r
3141                 logger.log(logger.EXTREME, "Starting nextPage()");\r
3142                 \r
3143                 Integer pageNumber;\r
3144                 if (previewPageList.containsKey(file))\r
3145                         pageNumber = previewPageList.get(file)+1;\r
3146                 else\r
3147                         pageNumber = 2;\r
3148                 previewPageList.remove(file);\r
3149                 previewPageList.put(file, pageNumber);\r
3150                 PDFPreview pdfPreview = new PDFPreview();\r
3151                 boolean goodPreview = pdfPreview.setupPreview(file, "pdf", pageNumber);\r
3152                 if (goodPreview) {\r
3153 \r
3154 //                      String html = getContent();\r
3155                         QWebSettings.setMaximumPagesInCache(0);\r
3156                         QWebSettings.setObjectCacheCapacities(0, 0, 0);\r
3157 //                      browser.setContent(new QByteArray());\r
3158                         browser.setHtml(browser.page().mainFrame().toHtml());\r
3159                         browser.reload();\r
3160 //                      browser.setContent(new QByteArray(html));\r
3161 //                      browser.triggerPageAction(WebAction.Reload);\r
3162 //                      pdfMouseOver(selectedFile);\r
3163                 }\r
3164         }\r
3165 \r
3166         public void previousPage(String file) {\r
3167                 logger.log(logger.EXTREME, "Starting previousPage()");\r
3168                 \r
3169                 Integer pageNumber;\r
3170                 if (previewPageList.containsKey(file))\r
3171                         pageNumber = previewPageList.get(file)-1;\r
3172                 else\r
3173                         pageNumber = 1;\r
3174                 previewPageList.remove(file);\r
3175                 previewPageList.put(file, pageNumber);\r
3176                 PDFPreview pdfPreview = new PDFPreview();\r
3177                 boolean goodPreview = pdfPreview.setupPreview(file, "pdf", pageNumber);\r
3178                 if (goodPreview) {\r
3179 \r
3180 //                      String html = getContent();\r
3181                         QWebSettings.setMaximumPagesInCache(0);\r
3182                         QWebSettings.setObjectCacheCapacities(0, 0, 0);\r
3183                         browser.setHtml(browser.page().mainFrame().toHtml());\r
3184                         browser.reload();\r
3185 //                      browser.setContent(new QByteArray(html));\r
3186 //                      browser.triggerPageAction(WebAction.Reload);\r
3187                 }\r
3188         }\r
3189         \r
3190 /*      public void pdfMouseOver(String name) { \r
3191                 int pageNumber;\r
3192                 if (previewPageList.containsKey(selectedFile))\r
3193                         pageNumber = previewPageList.get(selectedFile)+1;\r
3194                 else\r
3195                         pageNumber = 1;\r
3196                 \r
3197                 if (pageNumber <= 1)\r
3198                         browser.previousPageAction.setEnabled(false);\r
3199                 else\r
3200                         browser.previousPageAction.setEnabled(true);\r
3201                 \r
3202                 PDFPreview pdf = new PDFPreview();\r
3203                 int totalPages = pdf.getPageCount(name);\r
3204                 if (previewPageList.containsKey(selectedFile))\r
3205                         pageNumber = previewPageList.get(selectedFile)+1;\r
3206                 else\r
3207                         pageNumber = 1;\r
3208                 if (totalPages > pageNumber)\r
3209                         browser.nextPageAction.setEnabled(true);\r
3210                 else\r
3211                         browser.nextPageAction.setEnabled(false);\r
3212         }\r
3213         \r
3214 \r
3215         public void pdfMouseOut() { \r
3216 //              browser.nextPageAction.setVisible(false);\r
3217 //              browser.previousPageAction.setVisible(false);\r
3218         }\r
3219 */\r
3220         \r
3221         @SuppressWarnings("unused")\r
3222         private void toggleUndoVisible(Boolean toggle) {\r
3223                 undoAction.setVisible(toggle);\r
3224                 Global.saveEditorButtonsVisible("undo", toggle);\r
3225         }\r
3226         @SuppressWarnings("unused")\r
3227         private void toggleRedoVisible(Boolean toggle) {\r
3228                 redoAction.setVisible(toggle);\r
3229                 Global.saveEditorButtonsVisible("redo", toggle);\r
3230         }\r
3231         @SuppressWarnings("unused")\r
3232         private void toggleCutVisible(Boolean toggle) {\r
3233                 cutAction.setVisible(toggle);\r
3234                 Global.saveEditorButtonsVisible("cut", toggle);\r
3235         }\r
3236         @SuppressWarnings("unused")\r
3237         private void toggleCopyVisible(Boolean toggle) {\r
3238                 copyAction.setVisible(toggle);\r
3239                 Global.saveEditorButtonsVisible("copy", toggle);\r
3240         }\r
3241         @SuppressWarnings("unused")\r
3242         private void togglePasteVisible(Boolean toggle) {\r
3243                 pasteAction.setVisible(toggle);\r
3244                 Global.saveEditorButtonsVisible("paste", toggle);\r
3245         }\r
3246         @SuppressWarnings("unused")\r
3247         private void toggleBoldVisible(Boolean toggle) {\r
3248                 boldAction.setVisible(toggle);\r
3249                 Global.saveEditorButtonsVisible("bold", toggle);\r
3250         }\r
3251         @SuppressWarnings("unused")\r
3252         private void toggleItalicVisible(Boolean toggle) {\r
3253                 italicAction.setVisible(toggle);\r
3254                 Global.saveEditorButtonsVisible("italic", toggle);\r
3255         }\r
3256         @SuppressWarnings("unused")\r
3257         private void toggleUnderlineVisible(Boolean toggle) {\r
3258                 underlineAction.setVisible(toggle);\r
3259                 Global.saveEditorButtonsVisible("underline", toggle);\r
3260         }\r
3261         @SuppressWarnings("unused")\r
3262         private void toggleStrikethroughVisible(Boolean toggle) {\r
3263                 strikethroughAction.setVisible(toggle);\r
3264                 Global.saveEditorButtonsVisible("strikethrough", toggle);\r
3265         }\r
3266         @SuppressWarnings("unused")\r
3267         private void toggleLeftAlignVisible(Boolean toggle) {\r
3268                 leftAlignAction.setVisible(toggle);\r
3269                 Global.saveEditorButtonsVisible("alignLeft", toggle);\r
3270         }\r
3271         @SuppressWarnings("unused")\r
3272         private void toggleRightAlignVisible(Boolean toggle) {\r
3273                 rightAlignAction.setVisible(toggle);\r
3274                 Global.saveEditorButtonsVisible("alignRight", toggle);\r
3275         }       \r
3276         @SuppressWarnings("unused")\r
3277         private void toggleCenterAlignVisible(Boolean toggle) {\r
3278                 centerAlignAction.setVisible(toggle);\r
3279                 Global.saveEditorButtonsVisible("alignCenter", toggle);\r
3280         }\r
3281         @SuppressWarnings("unused")\r
3282         private void toggleHLineVisible(Boolean toggle) {\r
3283                 hlineAction.setVisible(toggle);\r
3284                 Global.saveEditorButtonsVisible("hline", toggle);\r
3285         }\r
3286         @SuppressWarnings("unused")\r
3287         private void toggleIndentVisible(Boolean toggle) {\r
3288                 indentAction.setVisible(toggle);\r
3289                 Global.saveEditorButtonsVisible("indent", toggle);\r
3290         }\r
3291         @SuppressWarnings("unused")\r
3292         private void toggleTodoVisible(Boolean toggle) {\r
3293                 todoAction.setVisible(toggle);\r
3294                 Global.saveEditorButtonsVisible("todo", toggle);\r
3295         }\r
3296         @SuppressWarnings("unused")\r
3297         private void toggleOutdentVisible(Boolean toggle) {\r
3298                 outdentAction.setVisible(toggle);\r
3299                 Global.saveEditorButtonsVisible("outdent", toggle);\r
3300         }\r
3301         @SuppressWarnings("unused")\r
3302         private void toggleBulletListVisible(Boolean toggle) {\r
3303                 bulletListAction.setVisible(toggle);\r
3304                 Global.saveEditorButtonsVisible("bulletList", toggle);\r
3305         }\r
3306         @SuppressWarnings("unused")\r
3307         private void toggleNumberListVisible(Boolean toggle) {\r
3308                 numberListAction.setVisible(toggle);\r
3309                 Global.saveEditorButtonsVisible("numberList", toggle);\r
3310         }\r
3311         @SuppressWarnings("unused")\r
3312         private void toggleFontListVisible(Boolean toggle) {\r
3313                 fontListAction.setVisible(toggle);\r
3314                 Global.saveEditorButtonsVisible("font", toggle);\r
3315         }\r
3316         @SuppressWarnings("unused")\r
3317         private void toggleFontColorVisible(Boolean toggle) {\r
3318                 fontColorAction.setVisible(toggle);\r
3319                 Global.saveEditorButtonsVisible("fontColor", toggle);\r
3320         }\r
3321         @SuppressWarnings("unused")\r
3322         private void toggleFontSizeVisible(Boolean toggle) {\r
3323                 fontSizeAction.setVisible(toggle);\r
3324                 Global.saveEditorButtonsVisible("fontSize", toggle);\r
3325         }\r
3326         @SuppressWarnings("unused")\r
3327         private void toggleFontHilightVisible(Boolean toggle) {\r
3328                 fontHilightAction.setVisible(toggle);\r
3329                 Global.saveEditorButtonsVisible("fontHilight", toggle);\r
3330         }\r
3331         @SuppressWarnings("unused")\r
3332         private void toggleSpellCheckVisible(Boolean toggle) {\r
3333                 spellCheckAction.setVisible(toggle);\r
3334                 Global.saveEditorButtonsVisible("spellCheck", toggle);\r
3335         }\r
3336 \r
3337 \r
3338         private void setupDictionary() {\r
3339                 File wordList = new File(Global.getFileManager().getSpellDirPath()+Locale.getDefault()+".dic");\r
3340                 try {\r
3341                         dictionary = new SpellDictionaryHashMap(wordList);\r
3342                         spellChecker = new SpellChecker(dictionary);\r
3343                         \r
3344                         File userWordList;\r
3345                         userWordList = new File(Global.getFileManager().getSpellDirPathUser()+"user.dic");\r
3346                         \r
3347                         // Get the local user spell dictionary\r
3348                         try {\r
3349                                 userDictionary = new SpellDictionaryHashMap(userWordList);\r
3350                         } catch (FileNotFoundException e) {\r
3351                                 userWordList.createNewFile();\r
3352                                 userDictionary = new SpellDictionaryHashMap(userWordList);\r
3353                         } catch (IOException e) {\r
3354                                 userWordList.createNewFile();\r
3355                                 userDictionary = new SpellDictionaryHashMap(userWordList);\r
3356                         }\r
3357                         \r
3358                         spellListener = new SuggestionListener(this, spellChecker);\r
3359                         \r
3360                         // Add the user dictionary\r
3361                         spellChecker.addSpellCheckListener(spellListener);\r
3362                         spellChecker.setUserDictionary(userDictionary);\r
3363 \r
3364                 } catch (FileNotFoundException e) {\r
3365                         QMessageBox.critical(this, tr("Spell Check Error"), \r
3366                                         tr("Dictionary ")+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+\r
3367                                                 tr(".dic was not found."));\r
3368                 } catch (IOException e) {\r
3369                         QMessageBox.critical(this, tr("Spell Check Error"), \r
3370                                         tr("Dictionary ")+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+\r
3371                                                 tr(".dic is invalid."));\r
3372                 }\r
3373 \r
3374         }\r
3375         \r
3376         // Invoke spell checker dialog\r
3377         @SuppressWarnings("unused")\r
3378         private void spellCheckClicked() {\r
3379 \r
3380                 if (spellChecker == null) {\r
3381                         setupDictionary();      \r
3382                 }\r
3383                 \r
3384                 // Read user settings\r
3385                 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREDIGITWORDS, \r
3386                                 Global.getSpellSetting(Configuration.SPELL_IGNOREDIGITWORDS));\r
3387                 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREINTERNETADDRESSES, \r
3388                                 Global.getSpellSetting(Configuration.SPELL_IGNOREINTERNETADDRESSES));\r
3389                 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREMIXEDCASE, \r
3390                                 Global.getSpellSetting(Configuration.SPELL_IGNOREMIXEDCASE));\r
3391                 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREUPPERCASE, \r
3392                                 Global.getSpellSetting(Configuration.SPELL_IGNOREUPPERCASE));\r
3393                 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNORESENTENCECAPITALIZATION, \r
3394                                 Global.getSpellSetting(Configuration.SPELL_IGNORESENTENCECAPITALIZATION));\r
3395 \r
3396                 spellListener.abortSpellCheck = false;\r
3397                 spellListener.errorsFound = false;\r
3398                 String content = getBrowser().page().mainFrame().toPlainText();\r
3399                 StringWordTokenizer tokenizer = new StringWordTokenizer(content);\r
3400                 if (!tokenizer.hasMoreWords())\r
3401                         return;\r
3402                 getBrowser().page().action(WebAction.MoveToStartOfDocument);\r
3403 \r
3404                 getBrowser().setFocus();\r
3405                 boolean found;\r
3406                         \r
3407                 // Move to the start of page\r
3408                 KeyboardModifiers ctrl = new KeyboardModifiers(KeyboardModifier.ControlModifier.value());\r
3409                 QKeyEvent home = new QKeyEvent(Type.KeyPress, Key.Key_Home.value(), ctrl);  \r
3410                 browser.keyPressEvent(home);\r
3411                 getBrowser().setFocus();\r
3412                         \r
3413                 tokenizer = new StringWordTokenizer(content);\r
3414                 String word;\r
3415                         \r
3416                 while(tokenizer.hasMoreWords()) {\r
3417                         word = tokenizer.nextWord();\r
3418                         found = getBrowser().page().findText(word);\r
3419                         if (found && !spellListener.abortSpellCheck) {\r
3420                                 spellChecker.checkSpelling(new StringWordTokenizer(word));\r
3421                                 getBrowser().setFocus();\r
3422                         }\r
3423                 }\r
3424 \r
3425                 // Go to the end of the document & finish up.\r
3426                 home = new QKeyEvent(Type.KeyPress, Key.Key_End.value(), ctrl);  \r
3427                 browser.keyPressEvent(home);\r
3428                 if (!spellListener.errorsFound)\r
3429                         QMessageBox.information(this, tr("Spell Check Complete"), \r
3430                                         tr("No Errors Found"));\r
3431 \r
3432     }\r
3433         \r
3434         // Source edited\r
3435         @SuppressWarnings("unused")\r
3436         private void sourceEdited() {\r
3437                 QTextCodec codec = QTextCodec.codecForLocale();\r
3438                 codec = QTextCodec.codecForName("UTF-8");\r
3439         String content =  codec.fromUnicode(sourceEdit.toHtml()).toString();\r
3440                 content = StringEscapeUtils.unescapeHtml4(removeTags(content));\r
3441                 QByteArray data = new QByteArray(sourceEditHeader+content+"</body></html>");\r
3442                 getBrowser().setContent(data);\r
3443                 checkNoteTitle();\r
3444                 if (currentNote != null && sourceEdit != null)\r
3445                         noteSignal.noteChanged.emit(currentNote.getGuid(), sourceEdit.toPlainText()); \r
3446         }\r
3447         \r
3448         private void setSource() {\r
3449                 String text = getContent();\r
3450                 sourceEdit.blockSignals(true);\r
3451                 int body = text.indexOf("<body");\r
3452                 if (body > 0) {\r
3453                         body = text.indexOf(">",body);\r
3454                         if (body > 0) {\r
3455                                 sourceEditHeader =text.substring(0, body+1);\r
3456                                 text = text.substring(body+1);\r
3457                         }\r
3458                 }\r
3459                 text = text.replace("</body></html>", "");\r
3460                 sourceEdit.setPlainText(text);\r
3461                 sourceEdit.setReadOnly(!getBrowser().page().isContentEditable());\r
3462                 //syntaxHighlighter.rehighlight();\r
3463                 sourceEdit.blockSignals(false);\r
3464         }\r
3465 \r
3466         // show/hide view source window\r
3467         public void showSource(boolean value) {\r
3468                 setSource();\r
3469                 sourceEdit.setVisible(value);\r
3470         }\r
3471 \r
3472         // Remove HTML tags\r
3473         private String removeTags(String text) {\r
3474                 StringBuffer buffer = new StringBuffer(text);\r
3475                 boolean inTag = false;\r
3476                 int bodyPosition = text.indexOf("<body");\r
3477                 for (int i=buffer.length()-1; i>=0; i--) {\r
3478                         if (buffer.charAt(i) == '>')\r
3479                                 inTag = true;\r
3480                         if (buffer.charAt(i) == '<')\r
3481                                 inTag = false;\r
3482                         if (inTag || buffer.charAt(i) == '<' || i<bodyPosition)\r
3483                                 buffer.deleteCharAt(i);\r
3484                 }\r
3485                 \r
3486                 return buffer.toString();\r
3487         }\r
3488 }\r