OSDN Git Service

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