OSDN Git Service

GitHub最初のコミット(SourceForge.jp 128fa38 2013-02-28 15:28:57 と同じ内容)
[neighbornote/NeighborNote.git] / src / cx / fbn / nevernote / gui / BrowserWindow.java
1 /*
2  * This file is part of NixNote 
3  * Copyright 2009 Randy Baumgarte
4  * 
5  * This file may be licensed under the terms of of the
6  * GNU General Public License Version 2 (the ``GPL'').
7  *
8  * Software distributed under the License is distributed
9  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
10  * express or implied. See the GPL for the specific language
11  * governing rights and limitations.
12  *
13  * You should have received a copy of the GPL along with this
14  * program. If not, go to http://www.gnu.org/licenses/gpl.html
15  * or write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  */
19
20 package cx.fbn.nevernote.gui;
21
22 import java.io.File;
23 import java.io.FileNotFoundException;
24 import java.io.IOException;
25 import java.net.FileNameMap;
26 import java.net.URI;
27 import java.net.URLConnection;
28 import java.security.MessageDigest;
29 import java.security.NoSuchAlgorithmException;
30 import java.text.SimpleDateFormat;
31 import java.util.ArrayList;
32 import java.util.Calendar;
33 import java.util.Collections;
34 import java.util.Date;
35 import java.util.GregorianCalendar;
36 import java.util.HashMap;
37 import java.util.List;
38 import java.util.Locale;
39 import java.util.StringTokenizer;
40
41 import org.apache.commons.lang3.StringEscapeUtils;
42 import org.apache.commons.lang3.StringUtils;
43
44 import com.evernote.edam.limits.Constants;
45 import com.evernote.edam.type.Data;
46 import com.evernote.edam.type.Note;
47 import com.evernote.edam.type.Notebook;
48 import com.evernote.edam.type.Resource;
49 import com.evernote.edam.type.ResourceAttributes;
50 import com.evernote.edam.type.Tag;
51 import com.evernote.edam.type.User;
52 import com.swabunga.spell.engine.Configuration;
53 import com.swabunga.spell.engine.SpellDictionary;
54 import com.swabunga.spell.engine.SpellDictionaryHashMap;
55 import com.swabunga.spell.engine.Word;
56 import com.swabunga.spell.event.SpellCheckEvent;
57 import com.swabunga.spell.event.SpellCheckListener;
58 import com.swabunga.spell.event.SpellChecker;
59 import com.swabunga.spell.event.StringWordTokenizer;
60 import com.trolltech.qt.core.QByteArray;
61 import com.trolltech.qt.core.QCoreApplication;
62 import com.trolltech.qt.core.QDataStream;
63 import com.trolltech.qt.core.QDateTime;
64 import com.trolltech.qt.core.QEvent;
65 import com.trolltech.qt.core.QEvent.Type;
66 import com.trolltech.qt.core.QFile;
67 import com.trolltech.qt.core.QFileSystemWatcher;
68 import com.trolltech.qt.core.QIODevice;
69 import com.trolltech.qt.core.QMimeData;
70 import com.trolltech.qt.core.QSize;
71 import com.trolltech.qt.core.QTextCodec;
72 import com.trolltech.qt.core.QTimer;
73 import com.trolltech.qt.core.QUrl;
74 import com.trolltech.qt.core.Qt;
75 import com.trolltech.qt.core.Qt.Key;
76 import com.trolltech.qt.core.Qt.KeyboardModifier;
77 import com.trolltech.qt.core.Qt.KeyboardModifiers;
78 import com.trolltech.qt.gui.QAction;
79 import com.trolltech.qt.gui.QApplication;
80 import com.trolltech.qt.gui.QCalendarWidget;
81 import com.trolltech.qt.gui.QClipboard;
82 import com.trolltech.qt.gui.QClipboard.Mode;
83 import com.trolltech.qt.gui.QColor;
84 import com.trolltech.qt.gui.QComboBox;
85 import com.trolltech.qt.gui.QDateEdit;
86 import com.trolltech.qt.gui.QDesktopServices;
87 import com.trolltech.qt.gui.QFileDialog;
88 import com.trolltech.qt.gui.QFileDialog.AcceptMode;
89 import com.trolltech.qt.gui.QFileDialog.FileMode;
90 import com.trolltech.qt.gui.QFont;
91 import com.trolltech.qt.gui.QFontDatabase;
92 import com.trolltech.qt.gui.QFormLayout;
93 import com.trolltech.qt.gui.QGridLayout;
94 import com.trolltech.qt.gui.QHBoxLayout;
95 import com.trolltech.qt.gui.QIcon;
96 import com.trolltech.qt.gui.QImage;
97 import com.trolltech.qt.gui.QKeyEvent;
98 import com.trolltech.qt.gui.QKeySequence;
99 import com.trolltech.qt.gui.QLabel;
100 import com.trolltech.qt.gui.QLineEdit;
101 import com.trolltech.qt.gui.QListWidgetItem;
102 import com.trolltech.qt.gui.QMatrix;
103 import com.trolltech.qt.gui.QMessageBox;
104 import com.trolltech.qt.gui.QPalette;
105 import com.trolltech.qt.gui.QPalette.ColorRole;
106 import com.trolltech.qt.gui.QPushButton;
107 import com.trolltech.qt.gui.QShortcut;
108 import com.trolltech.qt.gui.QSplitter;
109 import com.trolltech.qt.gui.QTextEdit;
110 import com.trolltech.qt.gui.QTextEdit.LineWrapMode;
111 import com.trolltech.qt.gui.QTimeEdit;
112 import com.trolltech.qt.gui.QToolButton;
113 import com.trolltech.qt.gui.QToolButton.ToolButtonPopupMode;
114 import com.trolltech.qt.gui.QVBoxLayout;
115 import com.trolltech.qt.gui.QWidget;
116 import com.trolltech.qt.network.QNetworkAccessManager;
117 import com.trolltech.qt.network.QNetworkReply;
118 import com.trolltech.qt.network.QNetworkReply.NetworkError;
119 import com.trolltech.qt.network.QNetworkRequest;
120 import com.trolltech.qt.webkit.QWebPage;
121 import com.trolltech.qt.webkit.QWebPage.WebAction;
122 import com.trolltech.qt.webkit.QWebSettings;
123 import com.trolltech.qt.webkit.QWebView;
124
125 import cx.fbn.nevernote.Global;
126 import cx.fbn.nevernote.dialog.EnCryptDialog;
127 import cx.fbn.nevernote.dialog.EnDecryptDialog;
128 import cx.fbn.nevernote.dialog.GeoDialog;
129 import cx.fbn.nevernote.dialog.InsertLatexImage;
130 import cx.fbn.nevernote.dialog.InsertLinkDialog;
131 import cx.fbn.nevernote.dialog.NoteQuickLinkDialog;
132 import cx.fbn.nevernote.dialog.SpellCheck;
133 import cx.fbn.nevernote.dialog.TableDialog;
134 import cx.fbn.nevernote.dialog.TagAssign;
135 import cx.fbn.nevernote.evernote.EnCrypt;
136 import cx.fbn.nevernote.filters.FilterEditorTags;
137 import cx.fbn.nevernote.neighbornote.ClipBoardObserver;
138 import cx.fbn.nevernote.signals.NoteResourceSignal;
139 import cx.fbn.nevernote.signals.NoteSignal;
140 import cx.fbn.nevernote.sql.DatabaseConnection;
141 import cx.fbn.nevernote.utilities.ApplicationLogger;
142 import cx.fbn.nevernote.utilities.FileUtils;
143 import cx.fbn.nevernote.utilities.Pair;
144 import cx.fbn.nevernote.xml.HtmlTagModifier;
145
146 public class BrowserWindow extends QWidget {
147
148         public final QLineEdit titleLabel;
149         private final QLineEdit urlText;
150         private final QLabel authorLabel;
151         private final QLineEdit authorText;
152         private final QComboBox geoBox;
153         public final TagLineEdit tagEdit;
154         public final QLabel tagLabel;
155         private final QPushButton urlLabel;
156         private final QLabel alteredLabel;
157         private final QDateEdit alteredDate;
158         private final QTimeEdit alteredTime;
159         private final QDateEdit createdDate;
160         private final QTimeEdit createdTime;
161         private final QLabel subjectLabel;
162         private final QDateEdit subjectDate;
163         private final QTimeEdit subjectTime;
164         public final QComboBox notebookBox;
165         private final QLabel notebookLabel;
166         private final QLabel createdLabel;
167         public final QComboBox fontSize;
168         public final QAction    fontSizeAction;
169         private boolean extendedOn;
170         public boolean buttonsVisible;
171         private final String iconPath;
172         public final ContentView browser;
173         private final QTextEdit sourceEdit;
174         private String sourceEditHeader;
175         Highlighter syntaxHighlighter;
176         private List<Tag> allTags;
177         private List<String> currentTags;
178         public NoteSignal noteSignal;
179         public Signal2<String,String> evernoteLinkClicked;
180         private List<Notebook> notebookList;
181         private Note currentNote;
182         private String saveNoteTitle;
183         private String saveTagList;
184         private boolean insideList;
185         private final DatabaseConnection conn;
186         private final QCalendarWidget createdCalendarWidget;
187         private final QCalendarWidget alteredCalendarWidget;
188         private final QCalendarWidget subjectCalendarWidget;
189
190         public final QPushButton undoButton;
191         public final QAction    undoAction;
192         public final QPushButton redoButton;
193         public final QAction    redoAction;
194         public final QPushButton cutButton;
195         public final QAction    cutAction;
196         public final QPushButton copyButton;
197         public final QAction    copyAction;
198         public final QPushButton pasteButton;
199         public final QAction    pasteAction;
200         public final QPushButton boldButton;
201         public final QAction    boldAction;
202         public final QPushButton underlineButton;
203         public final QAction    underlineAction;
204         public final QPushButton italicButton;
205         public final QAction    italicAction;
206         public final Signal0 focusLost;
207         public final NoteResourceSignal resourceSignal;
208
209         public QPushButton rightAlignButton;
210         public final QAction    rightAlignAction;
211         public QPushButton leftAlignButton;
212         public final QAction    leftAlignAction;
213         public QPushButton centerAlignButton;
214         public final QAction    centerAlignAction;
215
216         public final QPushButton strikethroughButton;
217         public final QAction    strikethroughAction;
218         public final QPushButton hlineButton;
219         public final QAction    hlineAction;
220         public final QPushButton indentButton;
221         public final QAction    indentAction;
222         public final QPushButton outdentButton;
223         public final QAction    outdentAction;
224         public final QPushButton bulletListButton;
225         public final QAction    bulletListAction;
226         public final QPushButton numberListButton;
227         public final QAction    numberListAction;
228         public final QPushButton spellCheckButton;
229         public final QAction    spellCheckAction;
230         public final QPushButton todoButton;
231         public final QAction    todoAction;
232
233         public final QShortcut focusTitleShortcut;
234         public final QShortcut focusTagShortcut;
235         public final QShortcut focusNoteShortcut;
236         public final QShortcut focusUrlShortcut;
237         public final QShortcut focusAuthorShortcut;
238         
239         public EditorButtonBar buttonLayout;
240         public final QComboBox fontList;
241         public final QAction    fontListAction;
242         public final QToolButton fontColor;
243         public final QAction    fontColorAction;
244         private final ColorMenu fontColorMenu;
245         public final QToolButton fontHilight;
246         public final QAction    fontHilightAction;
247         private final ColorMenu fontHilightColorMenu;
248         public final QFileSystemWatcher fileWatcher;
249         public int cursorPosition;
250         private boolean forceTextPaste;
251         private String selectedFile;
252         private String currentHyperlink;
253         public boolean keepPDFNavigationHidden;
254         private final ApplicationLogger logger;
255         SpellDictionary dictionary;
256     SpellDictionary userDictionary;
257     SpellChecker spellChecker;
258     SuggestionListener spellListener;
259         private final HashMap<String,Integer> previewPageList;  
260         boolean insertHyperlink;
261         boolean insideTable;
262         boolean insideEncryption;
263         public Signal1<BrowserWindow> blockApplication;
264         public Signal0 unblockApplication;
265         public boolean awaitingHttpResponse;
266         public long     unblockTime;
267         private final QTimer setSourceTimer;
268         String latexGuid;  // This is set if we are editing an existing LaTeX formula.  Useful to track guid.
269
270         // ICHANGED
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         // ICHANGED 引数に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                 // ICHANGED
339                 this.cbObserver = cbObserver;
340                 
341                 focusLost = new Signal0();
342
343                 tagEdit = new TagLineEdit(allTags);
344                 tagLabel = new QLabel(tr("Tags:"));
345                 tagEdit.focusLost.connect(this, "modifyTagsTyping()");
346
347                 createdCalendarWidget = new QCalendarWidget();
348                 createdDate = new QDateEdit();
349                 createdDate.setDisplayFormat(Global.getDateFormat());
350                 createdDate.setCalendarPopup(true);
351                 createdDate.setCalendarWidget(createdCalendarWidget);
352                 createdTime = new QTimeEdit();
353                 createdDate.dateChanged.connect(this, "createdChanged()");
354                 createdTime.timeChanged.connect(this, "createdChanged()");
355
356                 alteredCalendarWidget = new QCalendarWidget();
357                 alteredDate = new QDateEdit();
358                 alteredDate.setDisplayFormat(Global.getDateFormat());
359                 alteredDate.setCalendarPopup(true);
360                 alteredDate.setCalendarWidget(alteredCalendarWidget);
361                 alteredTime = new QTimeEdit();
362                 alteredLabel = new QLabel(tr("Altered:"));
363                 alteredDate.dateChanged.connect(this, "alteredChanged()");
364                 alteredTime.timeChanged.connect(this, "alteredChanged()");
365
366                 subjectCalendarWidget = new QCalendarWidget();
367                 subjectDate = new QDateEdit();
368                 subjectDate.setDisplayFormat(Global.getDateFormat());
369                 subjectDate.setCalendarPopup(true);
370                 subjectDate.setCalendarWidget(subjectCalendarWidget);
371                 subjectTime = new QTimeEdit();
372                 subjectLabel = new QLabel(tr("Subject Date:"));
373                 subjectDate.dateChanged.connect(this, "subjectDateTimeChanged()");
374                 subjectTime.timeChanged.connect(this, "subjectDateTimeChanged()");
375                 authorText.textChanged.connect(this, "authorChanged()");
376                 urlText.textChanged.connect(this, "sourceUrlChanged()");
377
378                 notebookBox = new QComboBox();
379                 notebookLabel = new QLabel(tr("Notebook"));
380                 createdLabel = new QLabel(tr("Created:"));
381                 // selectedText = new String();
382
383                 urlLabel.setVisible(false);
384                 urlText.setVisible(false);
385                 authorLabel.setVisible(false);
386                 
387                 geoBox.setVisible(false);
388                 geoBox.addItem(new QIcon(iconPath+"globe.png"), "");
389                 geoBox.addItem(new String(tr("Set")));
390                 geoBox.addItem(new String(tr("Clear")));
391                 geoBox.addItem(new String(tr("View On Map")));
392                 geoBox.activated.connect(this, "geoBoxChanged()");
393                 
394                 authorText.setVisible(false);
395                 createdDate.setVisible(false);
396                 alteredLabel.setVisible(false);
397                 //notebookBox.setVisible(false);
398                 notebookLabel.setVisible(false);
399                 createdLabel.setVisible(false);
400                 createdTime.setVisible(false);
401                 alteredDate.setVisible(false);
402                 alteredTime.setVisible(false);
403                 subjectLabel.setVisible(false);
404                 subjectDate.setVisible(false);
405                 subjectTime.setVisible(false);
406                 extendedOn = false;
407                 buttonsVisible = true;
408                 setAcceptDrops(true);
409
410                 browser = new ContentView(this);
411                                 
412                 browser.page().setLinkDelegationPolicy(
413                                 QWebPage.LinkDelegationPolicy.DelegateAllLinks);
414                 browser.linkClicked.connect(this, "linkClicked(QUrl)");
415                 currentHyperlink = "";
416                 
417                 //Setup the source editor
418                 sourceEdit = new QTextEdit(this);
419                 sourceEdit.setVisible(false);
420                 sourceEdit.setTabChangesFocus(true);
421                 sourceEdit.setLineWrapMode(LineWrapMode.NoWrap);
422                 QFont font = new QFont();
423                 font.setFamily("Courier");
424                 font.setFixedPitch(true);
425                 font.setPointSize(10);
426                 sourceEdit.setFont(font);
427                 syntaxHighlighter = new Highlighter(sourceEdit.document());
428                 sourceEdit.textChanged.connect(this, "sourceEdited()");
429
430                 QVBoxLayout v = new QVBoxLayout();
431                 QFormLayout notebookLayout = new QFormLayout();
432                 QGridLayout dateLayout = new QGridLayout();
433                 titleLabel.setReadOnly(false);
434                 titleLabel.editingFinished.connect(this, "titleEdited()");
435                 browser.page().contentsChanged.connect(this, "contentChanged()");
436                 browser.page().selectionChanged.connect(this, "selectionChanged()");
437                 browser.page().mainFrame().javaScriptWindowObjectCleared.connect(this,
438                                 "exposeToJavascript()");
439
440                 notebookBox.activated.connect(this, "notebookChanged()");
441                 resourceSignal = new NoteResourceSignal();
442                 
443                 QHBoxLayout tagLayout = new QHBoxLayout();
444                 v.addWidget(titleLabel, 0);
445                 notebookLayout.addRow(notebookLabel, notebookBox);
446                 tagLayout.addLayout(notebookLayout, 0);
447                 tagLayout.stretch(4);
448                 tagLayout.addWidget(tagLabel, 0);
449                 tagLayout.addWidget(tagEdit, 1);
450                 v.addLayout(tagLayout);
451
452                 QHBoxLayout urlLayout = new QHBoxLayout();
453                 urlLayout.addWidget(urlLabel, 0);
454                 urlLayout.addWidget(urlText, 0);
455                 v.addLayout(urlLayout);
456
457                 QHBoxLayout authorLayout = new QHBoxLayout();
458                 authorLayout.addWidget(authorLabel, 0);
459                 authorLayout.addWidget(authorText, 0);
460                 authorLayout.addWidget(geoBox);
461                 v.addLayout(authorLayout);
462
463                 dateLayout.addWidget(createdLabel, 0, 0);
464                 dateLayout.addWidget(createdDate, 0, 1);
465                 dateLayout.addWidget(createdTime, 0, 2);
466                 dateLayout.setColumnStretch(9, 100);
467                 dateLayout.addWidget(alteredLabel, 0, 3);
468                 dateLayout.addWidget(alteredDate, 0, 4);
469                 dateLayout.addWidget(alteredTime, 0, 5);
470                 dateLayout.addWidget(subjectLabel, 0, 6);
471                 dateLayout.addWidget(subjectDate, 0, 7);
472                 dateLayout.addWidget(subjectTime, 0, 8);
473                 v.addLayout(dateLayout, 0);
474
475                 undoButton = newEditorButton("undo", tr("Undo Change"));
476                 redoButton = newEditorButton("redo", tr("Redo Change"));
477                 cutButton = newEditorButton("cut", tr("Cut"));
478                 copyButton = newEditorButton("copy", tr("Copy"));
479                 pasteButton = newEditorButton("paste", tr("Paste"));
480                 boldButton = newEditorButton("bold", tr("Bold"));
481                 underlineButton = newEditorButton("underline", tr("Underline"));
482                 italicButton = newEditorButton("italic", tr("Italic"));
483
484                 rightAlignButton = newEditorButton("justifyRight", tr("Right Align"));
485                 leftAlignButton = newEditorButton("justifyLeft", tr("Left Align"));
486                 centerAlignButton = newEditorButton("justifyCenter", tr("Center Align"));
487
488                 strikethroughButton = newEditorButton("strikethrough", tr("Strikethrough"));
489                 hlineButton = newEditorButton("hline", tr("Insert Horizontal Line"));
490                 indentButton = newEditorButton("indent", tr("Shift Right"));
491                 outdentButton = newEditorButton("outdent", tr("Shift Left"));
492                 bulletListButton = newEditorButton("bulletList", tr("Bullet List"));
493                 numberListButton = newEditorButton("numberList", tr("Number List"));
494                 spellCheckButton = newEditorButton("spellCheck", tr("Spell Check"));
495                 todoButton = newEditorButton("todo", tr("To-do"));
496
497                 
498                 buttonLayout = new EditorButtonBar();
499                 v.addWidget(buttonLayout);
500                 
501                 undoAction = buttonLayout.addWidget(undoButton);
502                 buttonLayout.toggleUndoVisible.triggered.connect(this, "toggleUndoVisible(Boolean)");
503                 redoAction = buttonLayout.addWidget(redoButton);
504                 buttonLayout.toggleRedoVisible.triggered.connect(this, "toggleRedoVisible(Boolean)");
505                 
506                 buttonLayout.addWidget(newSeparator());
507                 cutAction = buttonLayout.addWidget(cutButton);
508                 buttonLayout.toggleCutVisible.triggered.connect(this, "toggleCutVisible(Boolean)");
509                 copyAction = buttonLayout.addWidget(copyButton);
510                 buttonLayout.toggleCopyVisible.triggered.connect(this, "toggleCopyVisible(Boolean)");
511                 pasteAction = buttonLayout.addWidget(pasteButton);
512                 buttonLayout.togglePasteVisible.triggered.connect(this, "togglePasteVisible(Boolean)");
513
514                 buttonLayout.addWidget(newSeparator());
515                 boldAction = buttonLayout.addWidget(boldButton);
516                 buttonLayout.toggleBoldVisible.triggered.connect(this, "toggleBoldVisible(Boolean)");
517                 italicAction = buttonLayout.addWidget(italicButton);
518                 buttonLayout.toggleItalicVisible.triggered.connect(this, "toggleItalicVisible(Boolean)");
519                 underlineAction = buttonLayout.addWidget(underlineButton);
520                 buttonLayout.toggleUnderlineVisible.triggered.connect(this, "toggleUnderlineVisible(Boolean)");
521                 strikethroughAction = buttonLayout.addWidget(strikethroughButton);
522                 buttonLayout.toggleStrikethroughVisible.triggered.connect(this, "toggleStrikethroughVisible(Boolean)");
523
524                 
525                 buttonLayout.addWidget(newSeparator());
526                 leftAlignAction = buttonLayout.addWidget(leftAlignButton);
527                 buttonLayout.toggleLeftAlignVisible.triggered.connect(this, "toggleLeftAlignVisible(Boolean)");
528                 centerAlignAction = buttonLayout.addWidget(centerAlignButton);
529                 buttonLayout.toggleCenterAlignVisible.triggered.connect(this, "toggleCenterAlignVisible(Boolean)");
530                 rightAlignAction = buttonLayout.addWidget(rightAlignButton);
531                 buttonLayout.toggleRightAlignVisible.triggered.connect(this, "toggleRightAlignVisible(Boolean)");
532
533                 buttonLayout.addWidget(newSeparator());
534                 hlineAction = buttonLayout.addWidget(hlineButton);
535                 buttonLayout.toggleHLineVisible.triggered.connect(this, "toggleHLineVisible(Boolean)");
536
537                 indentAction = buttonLayout.addWidget(indentButton);
538                 buttonLayout.toggleIndentVisible.triggered.connect(this, "toggleIndentVisible(Boolean)");
539                 outdentAction = buttonLayout.addWidget(outdentButton);
540                 buttonLayout.toggleOutdentVisible.triggered.connect(this, "toggleOutdentVisible(Boolean)");
541                 bulletListAction = buttonLayout.addWidget(bulletListButton);
542                 buttonLayout.toggleBulletListVisible.triggered.connect(this, "toggleBulletListVisible(Boolean)");
543                 numberListAction = buttonLayout.addWidget(numberListButton);
544                 buttonLayout.toggleNumberListVisible.triggered.connect(this, "toggleNumberListVisible(Boolean)");
545
546                 // Setup the font & font size combo boxes
547                 buttonLayout.addWidget(newSeparator());
548                 fontList = new QComboBox();
549                 fontSize = new QComboBox();
550                 fontList.setToolTip("Font");
551                 fontSize.setToolTip("Font Size");
552                 fontList.activated.connect(this, "fontChanged(String)");
553                 fontSize.activated.connect(this, "fontSizeChanged(String)");
554                 fontListAction = buttonLayout.addWidget(fontList);
555                 buttonLayout.toggleFontVisible.triggered.connect(this, "toggleFontListVisible(Boolean)");
556                 fontSizeAction = buttonLayout.addWidget(fontSize);
557                 buttonLayout.toggleFontSizeVisible.triggered.connect(this, "toggleFontSizeVisible(Boolean)");
558                 QFontDatabase fonts = new QFontDatabase();
559                 List<String> fontFamilies = fonts.families();
560                 for (int i = 0; i < fontFamilies.size(); i++) {
561                         fontList.addItem(fontFamilies.get(i));
562                         if (i == 0) {
563                                 loadFontSize(fontFamilies.get(i));
564                         }
565                 }
566
567 //              buttonLayout.addWidget(newSeparator(), 0);
568                 fontColor = newToolButton("fontColor", tr("Font Color"));
569                 fontColorMenu = new ColorMenu(this);
570                 fontColor.setMenu(fontColorMenu.getMenu());
571                 fontColor.setPopupMode(ToolButtonPopupMode.MenuButtonPopup);
572                 fontColor.setAutoRaise(false);
573                 fontColorMenu.getMenu().triggered.connect(this, "fontColorClicked()");
574                 fontColorAction = buttonLayout.addWidget(fontColor);
575                 buttonLayout.toggleFontColorVisible.triggered.connect(this, "toggleFontColorVisible(Boolean)");
576                 fontHilight = newToolButton("fontHilight", tr("Font Hilight Color"));
577                 fontHilight.setPopupMode(ToolButtonPopupMode.MenuButtonPopup);
578                 fontHilight.setAutoRaise(false);
579                 fontHilightColorMenu = new ColorMenu(this);
580                 fontHilightColorMenu.setDefault(QColor.yellow);
581                 fontHilight.setMenu(fontHilightColorMenu.getMenu());
582                 fontHilightColorMenu.getMenu().triggered.connect(this, "fontHilightClicked()");
583                 fontHilightAction = buttonLayout.addWidget(fontHilight);
584                 fontHilightColorMenu.setDefault(QColor.yellow);
585                 buttonLayout.toggleFontHilight.triggered.connect(this, "toggleFontHilightVisible(Boolean)");
586                 
587                 spellCheckAction = buttonLayout.addWidget(spellCheckButton);
588                 buttonLayout.toggleNumberListVisible.triggered.connect(this, "spellCheckClicked()");
589                 buttonLayout.toggleSpellCheck.triggered.connect(this, "toggleSpellCheckVisible(Boolean)");
590                 
591                 todoAction = buttonLayout.addWidget(todoButton);
592                 buttonLayout.toggleNumberListVisible.triggered.connect(this, "todoClicked()");
593                 buttonLayout.toggleTodo.triggered.connect(this, "toggleTodoVisible(Boolean)");
594
595                 // Setup the source browser);
596
597 //              buttonLayout.addWidget(new QLabel(), 1);
598                 QSplitter editSplitter = new QSplitter(this);
599                 editSplitter.addWidget(browser);
600                 editSplitter.setOrientation(Qt.Orientation.Vertical);
601                 editSplitter.addWidget(sourceEdit);
602
603                 
604
605 //              v.addWidget(browser, 1);
606 //              v.addWidget(sourceEdit);
607                 v.addWidget(editSplitter);
608                 setLayout(v);
609
610                 browser.downloadAttachmentRequested.connect(this,
611                                 "downloadAttachment(QNetworkRequest)");
612                 browser.downloadImageRequested.connect(this,
613                                 "downloadImage(QNetworkRequest)");
614                 setTabOrder(notebookBox, tagEdit);
615                 setTabOrder(tagEdit, browser);
616                 
617                 focusNoteShortcut = new QShortcut(this);
618                 setupShortcut(focusNoteShortcut, "Focus_Note");
619                 focusNoteShortcut.activated.connect(this, "focusNote()");
620                 focusTitleShortcut = new QShortcut(this);
621                 setupShortcut(focusTitleShortcut, "Focus_Title");
622                 focusTitleShortcut.activated.connect(this, "focusTitle()");
623                 focusTagShortcut = new QShortcut(this);
624                 setupShortcut(focusTagShortcut, "Focus_Tag");
625                 focusTagShortcut.activated.connect(this, "focusTag()");
626                 focusAuthorShortcut = new QShortcut(this);
627                 setupShortcut(focusAuthorShortcut, "Focus_Author");
628                 focusAuthorShortcut.activated.connect(this, "focusAuthor()");
629                 focusUrlShortcut = new QShortcut(this);
630                 setupShortcut(focusUrlShortcut, "Focus_Url");
631                 focusUrlShortcut.activated.connect(this, "focusUrl()");
632                 
633                 browser.page().mainFrame().setTextSizeMultiplier(Global.getTextSizeMultiplier());
634                 browser.page().mainFrame().setZoomFactor(Global.getZoomFactor());
635                 
636                 previewPageList = new HashMap<String,Integer>();
637                 
638                 browser.page().microFocusChanged.connect(this, "microFocusChanged()");
639                 
640                 //Setup colors
641                 
642                 QPalette pal = new QPalette();
643                 pal.setColor(ColorRole.Text, QColor.black);
644                 titleLabel.setPalette(pal);
645                 authorText.setPalette(pal);
646                 authorLabel.setPalette(pal);
647                 urlLabel.setPalette(pal);
648                 urlText.setPalette(pal);
649                 createdDate.setPalette(pal);
650                 createdTime.setPalette(pal);
651                 alteredDate.setPalette(pal);
652                 alteredTime.setPalette(pal);
653                 subjectDate.setPalette(pal);
654                 subjectTime.setPalette(pal);
655                 tagEdit.setPalette(pal);
656                 notebookBox.setPalette(pal);
657                 
658                 blockApplication = new Signal1<BrowserWindow>();
659                 unblockApplication = new Signal0();
660                 
661                 setSourceTimer = new QTimer();
662                 setSourceTimer.timeout.connect(this, "setSource()");
663                 
664                 logger.log(logger.HIGH, "Browser setup complete");
665         }
666
667         
668         
669         private void setupShortcut(QShortcut action, String text) {
670                 if (!Global.shortcutKeys.containsAction(text))
671                         return;
672                 action.setKey(new QKeySequence(Global.shortcutKeys.getShortcut(text)));
673         }
674         
675         
676
677         
678         // Getter for the QWebView
679         public QWebView getBrowser() {
680                 return browser;
681         }
682
683         // Block signals while loading data or things are flagged as dirty by
684         // mistake
685         public void loadingData(boolean val) {
686                 logger.log(logger.EXTREME, "Entering BrowserWindow.loadingData() " +val);
687                 notebookBox.blockSignals(val);
688                 browser.page().blockSignals(val);
689                 browser.page().mainFrame().blockSignals(val);
690                 titleLabel.blockSignals(val);
691                 alteredDate.blockSignals(val);
692                 alteredTime.blockSignals(val);
693                 createdTime.blockSignals(val);
694                 createdDate.blockSignals(val);
695                 subjectDate.blockSignals(val);
696                 subjectTime.blockSignals(val);
697                 urlText.blockSignals(val);
698                 authorText.blockSignals(val);
699                 if (!val)
700                         exposeToJavascript();
701                 logger.log(logger.EXTREME, "Exiting BrowserWindow.loadingData() " +val);
702         }
703
704         // Enable/disable
705         public void setReadOnly(boolean v) {
706                 setEnabled(true);
707                 titleLabel.setEnabled(!v);
708                 notebookBox.setEnabled(!v);
709                 tagEdit.setEnabled(!v);
710                 authorLabel.setEnabled(!v);
711                 geoBox.setEnabled(!v);
712                 urlText.setEnabled(!v);
713                 createdDate.setEnabled(!v);
714                 subjectDate.setEnabled(!v);
715                 alteredDate.setEnabled(!v);
716                 authorText.setEnabled(!v);
717                 createdTime.setEnabled(!v);
718                 alteredTime.setEnabled(!v);
719                 subjectTime.setEnabled(!v);
720                 getBrowser().setEnabled(true);
721                 getBrowser().page().setContentEditable(!v);
722 //              getBrowser().setEnabled(!v);
723         }
724         
725         // expose this class to Javascript on the web page
726         private void exposeToJavascript() {
727                 browser.page().mainFrame().addToJavaScriptWindowObject("jambi", this);
728         }
729
730         // Custom event queue
731         @Override
732         public boolean event(QEvent e) {
733                 if (e.type().equals(QEvent.Type.FocusOut)) {
734                         logger.log(logger.EXTREME, "Focus lost");
735                         focusLost.emit();
736                 }
737                 return super.event(e);
738         }
739
740         // clear out browser
741         public void clear() {
742                 logger.log(logger.EXTREME, "Entering BrowserWindow.clear()");
743                 setNote(null);
744                 setContent(new QByteArray());
745                 tagEdit.setText("");
746                 tagEdit.tagCompleter.reset();
747                 urlLabel.setText(tr("Source URL:"));
748                 titleLabel.setText("");
749                 logger.log(logger.EXTREME, "Exiting BrowserWindow.clear()");
750         }
751
752         public void setContent(QByteArray data) {
753                 sourceEdit.blockSignals(true);
754                 browser.setContent(data);
755                 setSource();
756         }
757         // get/set current note
758         public void setNote(Note n) {
759                 currentNote = n;
760                 if (n == null)
761                         n = new Note();
762                 saveNoteTitle = n.getTitle();
763
764         }
765
766         public Note getNote() {
767                 return currentNote;
768         }
769
770         // New Editor Button
771         private QPushButton newEditorButton(String name, String toolTip) {
772                 QPushButton button = new QPushButton();
773 //              QIcon icon = new QIcon(iconPath + name + ".gif");
774                 QIcon icon = new QIcon(iconPath + name + ".png");
775                 button.setIcon(icon);
776                 // ICHANGED
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                 // ICHANGED
790                 button.setIconSize(new QSize(16, 16));
791                 
792                 button.setToolTip(toolTip);
793                 button.clicked.connect(this, name + "Clicked()");
794                 return button;
795         }
796
797         // New Separator
798         private QLabel newSeparator() {
799                 return new QLabel("   ");
800         }
801
802         // Set the title in the window
803         public void setTitle(String t) {
804                 titleLabel.setText(t);
805                 saveNoteTitle = t;
806                 checkNoteTitle();
807         }
808
809         // Return the current text title
810         public String getTitle() {
811                 return titleLabel.text();
812         }
813
814         // Set the tag name string
815         public void setTag(String t) {
816                 saveTagList = t;
817                 tagEdit.setText(t);
818                 tagEdit.tagCompleter.reset();
819         }
820
821         // Set the source URL
822         public void setUrl(String t) {
823                 urlLabel.setText(tr("Source URL:\t"));
824                 urlText.setText(t);
825         }
826
827         // The user want's to launch a web browser on the source of the URL
828         public void sourceUrlClicked() {
829                 // Make sure we have a valid URL
830                 if (urlText.text().trim().equals(""))
831                         return;
832                 
833                 String url = urlText.text();
834                 if (!url.toLowerCase().startsWith(tr("http://")))
835                         url = tr("http://") +url;
836                 
837         if (!QDesktopServices.openUrl(new QUrl(url))) {
838                 logger.log(logger.LOW, "Error opening file :" +url);
839         }
840         }
841         
842         public void setAuthor(String t) {
843                 authorLabel.setText(tr("Author:\t"));
844                 authorText.setText(t);
845         }
846
847         // Set the creation date
848         public void setCreation(long date) {
849                 QDateTime dt = new QDateTime();
850                 dt.setTime_t((int) (date / 1000));
851                 createdDate.setDateTime(dt);
852                 createdTime.setDateTime(dt);
853                 createdDate.setDisplayFormat(Global.getDateFormat());
854                 createdTime.setDisplayFormat(Global.getTimeFormat());
855         }
856
857         // Set the creation date
858         public void setAltered(long date) {
859                 QDateTime dt = new QDateTime();
860                 dt.setTime_t((int) (date / 1000));
861                 alteredDate.setDateTime(dt);
862                 alteredTime.setDateTime(dt);
863                 alteredDate.setDisplayFormat(Global.getDateFormat());
864                 alteredTime.setDisplayFormat(Global.getTimeFormat());
865         }
866
867         // Set the subject date
868         public void setSubjectDate(long date) {
869                 QDateTime dt = new QDateTime();
870                 dt.setTime_t((int) (date / 1000));
871                 subjectDate.setDateTime(dt);
872                 subjectTime.setDateTime(dt);
873                 subjectDate.setDisplayFormat(Global.getDateFormat());
874                 subjectTime.setDisplayFormat(Global.getTimeFormat());
875         }
876
877         // Toggle the extended attribute information
878         public void toggleInformation() {
879                 if (extendedOn) {
880                         extendedOn = false;
881                 } else {
882                         extendedOn = true;
883                 }
884                 urlLabel.setVisible(extendedOn);
885                 urlText.setVisible(extendedOn);
886                 authorText.setVisible(extendedOn);
887                 geoBox.setVisible(extendedOn);
888                 authorLabel.setVisible(extendedOn);
889                 createdDate.setVisible(extendedOn);
890                 createdTime.setVisible(extendedOn);
891                 createdLabel.setVisible(extendedOn);
892                 alteredLabel.setVisible(extendedOn);
893                 alteredDate.setVisible(extendedOn);
894                 alteredTime.setVisible(extendedOn);
895                 //notebookBox.setVisible(extendedOn);
896                 notebookLabel.setVisible(extendedOn);
897                 subjectLabel.setVisible(extendedOn);
898                 subjectDate.setVisible(extendedOn);
899                 subjectTime.setVisible(extendedOn);
900         }
901
902         public void hideButtons() {
903
904                 undoButton.parentWidget().setVisible(false);
905                 buttonsVisible = false;
906         }
907
908
909         // Is the extended view on?
910         public boolean isExtended() {
911                 return extendedOn;
912         }
913
914         // Listener for when a link is clicked
915         @SuppressWarnings("unused")
916         private void openFile() {
917                 logger.log(logger.EXTREME, "Starting openFile()");
918                 File fileHandle = new File(selectedFile);
919                 URI fileURL = fileHandle.toURI();
920                 String localURL = fileURL.toString();
921                 QUrl url = new QUrl(localURL);
922                 QFile file = new QFile(selectedFile);
923                 
924                 logger.log(logger.EXTREME, "Adding to fileWatcher:"+file.fileName());
925                 fileWatcher.addPath(file.fileName());
926         
927         if (!QDesktopServices.openUrl(url)) {
928                 logger.log(logger.LOW, "Error opening file :" +url);
929         }
930         }
931         
932         
933         // Listener for when a link is clicked
934         @SuppressWarnings("unused")
935         private void linkClicked(QUrl url) {
936                 logger.log(logger.EXTREME, "URL Clicked: " +url.toString());
937                 if (url.toString().startsWith("latex:")) {
938                         int position = url.toString().lastIndexOf(".");
939                         String guid = url.toString().substring(0,position);
940                         position = guid.lastIndexOf("/");
941                         guid = guid.substring(position+1);
942                         editLatex(guid);
943                         return;
944                 }
945                 if (url.toString().startsWith("evernote:/view/")) {
946                         StringTokenizer tokens = new StringTokenizer(url.toString().replace("evernote:/view/", ""), "/");
947                         tokens.nextToken();
948                         tokens.nextToken();
949                         String sid = tokens.nextToken();
950                         String lid = tokens.nextToken();
951                         
952                         // Emit that we want to switch to a new note
953                         evernoteLinkClicked.emit(sid, lid);
954
955                         return;
956                 }
957                 if (url.toString().startsWith("nnres://")) {
958                         logger.log(logger.EXTREME, "URL is NN resource");
959                         if (url.toString().endsWith("/vnd.evernote.ink")) {
960                                 logger.log(logger.EXTREME, "Unable to open ink note");
961                                 QMessageBox.information(this, tr("Unable Open"), tr("This is an ink note.\n"+
962                                         "Ink notes are not supported since Evernote has not\n published any specifications on them\n" +
963                                         "and I'm too lazy to figure them out by myself."));
964                                 return;
965                         }
966                         String fullName = url.toString().substring(8);
967                         int index = fullName.indexOf(".");
968                         String guid = "";
969                         String type = "";
970                         if (index >-1) {
971                                 type = fullName.substring(index+1);
972                                 guid = fullName.substring(0,index);
973                         }
974                         index = guid.indexOf(Global.attachmentNameDelimeter);
975                         if (index > -1) {
976                                 guid = guid.substring(0,index);
977                         }
978                         List<Resource> resList = currentNote.getResources();
979                         Resource res = null;
980                         for (int i=0; i<resList.size(); i++) {
981                                 if (resList.get(i).getGuid().equals(guid)) {
982                                         res = resList.get(i);
983                                         i=resList.size();
984                                 }
985                         }
986                         if (res == null) {
987                                 String resGuid = Global.resourceMap.get(guid);
988                                 if (resGuid != null) 
989                                         res = conn.getNoteTable().noteResourceTable.getNoteResource(resGuid, true);
990                         }
991                         if (res != null) {
992                                 String fileName;
993                                 if (res.getAttributes() != null && 
994                                                 res.getAttributes().getFileName() != null && 
995                                                 !res.getAttributes().getFileName().trim().equals(""))
996                                         fileName = res.getGuid()+Global.attachmentNameDelimeter+res.getAttributes().getFileName();
997                                 else
998                                         fileName = res.getGuid()+"."+type;
999                                 QFile file = new QFile(Global.getFileManager().getResDirPath(fileName));
1000                         QFile.OpenMode mode = new QFile.OpenMode();
1001                         mode.set(QFile.OpenModeFlag.WriteOnly);
1002                         boolean openResult = file.open(mode);
1003                                 logger.log(logger.EXTREME, "File opened:" +openResult);
1004                         QDataStream out = new QDataStream(file);
1005                         Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(res.getGuid(), true);
1006                                 QByteArray binData = new QByteArray(resBinary.getData().getBody());
1007                                 resBinary = null;
1008                                 logger.log(logger.EXTREME, "Writing resource");
1009                         out.writeBytes(binData.toByteArray());
1010                         file.close();
1011                                 
1012                         String whichOS = System.getProperty("os.name");
1013                                 if (whichOS.contains("Windows")) 
1014                                 url.setUrl("file:///"+file.fileName());
1015                         else
1016                                 url.setUrl("file://"+file.fileName());
1017                  //       fileWatcher.removePath(file.fileName());
1018                                 logger.log(logger.EXTREME, "Adding file watcher " +file.fileName());
1019                                 fileWatcher.addPath(file.fileName());
1020                         
1021                         // If we can't open it, then prompt the user to save it.
1022                         if (!QDesktopServices.openUrl(url)) {
1023                                         logger.log(logger.EXTREME, "We can't handle this.  Where do we put it?");
1024                                 QFileDialog dialog = new QFileDialog();
1025                                 dialog.show();
1026                                 if (dialog.exec()!=0) {
1027                                         List<String> fileNames = dialog.selectedFiles(); //gets all selected filenames
1028                                         if (fileNames.size() == 0) 
1029                                                 return;
1030                                         String sf = fileNames.get(0);
1031                                         QFile saveFile = new QFile(sf);
1032                                         mode.set(QFile.OpenModeFlag.WriteOnly);
1033                                         saveFile.open(mode);
1034                                         QDataStream saveOut = new QDataStream(saveFile);
1035                                         saveOut.writeBytes(binData.toByteArray());
1036                                         saveFile.close();
1037                                         return;
1038                                 }
1039                                 }
1040                         }
1041                         return;
1042                 }
1043                 logger.log(logger.EXTREME, "Launching URL");
1044                 QDesktopServices.openUrl(url);
1045         }
1046
1047         // Listener for when BOLD is clicked
1048         @SuppressWarnings("unused")
1049         private void undoClicked() {
1050                 browser.page().triggerAction(WebAction.Undo);
1051                 browser.setFocus();
1052         }
1053
1054         // Listener for when BOLD is clicked
1055         @SuppressWarnings("unused")
1056         private void redoClicked() {
1057                 browser.page().triggerAction(WebAction.Redo);
1058                 browser.setFocus();
1059         }
1060
1061         // Listener for when BOLD is clicked
1062         @SuppressWarnings("unused")
1063         private void boldClicked() {
1064                 browser.page().triggerAction(WebAction.ToggleBold);
1065                 microFocusChanged();
1066                 browser.setFocus();
1067         }
1068
1069         // Listener for when Italics is clicked
1070         @SuppressWarnings("unused")
1071         private void italicClicked() {
1072                 browser.page().triggerAction(WebAction.ToggleItalic);
1073                 microFocusChanged();
1074                 browser.setFocus();
1075         }
1076
1077         // Listener for when UNDERLINE is clicked
1078         @SuppressWarnings("unused")
1079         private void underlineClicked() {
1080                 browser.page().triggerAction(WebAction.ToggleUnderline);
1081                 microFocusChanged();
1082                 browser.setFocus();
1083         }
1084
1085         // Listener for when Strikethrough is clicked
1086         @SuppressWarnings("unused")
1087         private void strikethroughClicked() {
1088                 browser.page().mainFrame().evaluateJavaScript(
1089                                 "document.execCommand('strikeThrough', false, '');");
1090                 browser.setFocus();
1091         }
1092
1093         // Listener for when cut is clicked
1094         @SuppressWarnings("unused")
1095         private void cutClicked() {
1096                 // ICHANGED
1097                 cbObserver.setCopySourceGuid(currentNote.getGuid(), browser.page().selectedText());
1098                 
1099                 browser.page().triggerAction(WebAction.Cut);
1100                 browser.setFocus();
1101         }
1102
1103         // Listener when COPY is clicked
1104         @SuppressWarnings("unused")
1105         private void copyClicked() {
1106                 // ICHANGED
1107                 cbObserver.setCopySourceGuid(currentNote.getGuid(), browser.page().selectedText());
1108                 
1109                 browser.page().triggerAction(WebAction.Copy);
1110                 browser.setFocus();
1111         }
1112
1113         // Listener when PASTE is clicked
1114         public void pasteClicked() {
1115                 logger.log(logger.EXTREME, "Paste Clicked");
1116                 if (forceTextPaste) {
1117                         pasteWithoutFormattingClicked();
1118                         return;
1119                 }
1120                 
1121                 // ICHANGED コピー&ペーストの操作履歴をデータベースに登録
1122                 String srcGuid = cbObserver.getSourceGuid();
1123                 String dstGuid = currentNote.getGuid();
1124                 if(srcGuid != null && dstGuid != null){
1125                         if(!srcGuid.equals(dstGuid)){
1126                                 conn.getHistoryTable().addHistory("copy & paste", srcGuid, dstGuid);
1127                         }
1128                 }
1129                 
1130                 QClipboard clipboard = QApplication.clipboard();
1131                 QMimeData mime = clipboard.mimeData();
1132
1133                 if (mime.hasImage()) {
1134                         logger.log(logger.EXTREME, "Image paste found");
1135                         browser.setFocus();
1136                         insertImage(mime);
1137                         browser.setFocus();
1138                         return;
1139                 }
1140
1141                 if (mime.hasUrls()) {
1142                         logger.log(logger.EXTREME, "URL paste found");
1143                         if (mime.text().startsWith("evernote:")) {
1144                                 handleNoteLink(mime);
1145                         } else {
1146                                 handleUrls(mime);
1147                                 browser.setFocus();
1148                         }
1149                         return;
1150                 }
1151                 
1152                 String text = mime.html();
1153                 if (text.contains("en-tag") && mime.hasHtml()) {
1154                         logger.log(logger.EXTREME, "Intra-note paste found");
1155                         text = fixInternotePaste(text);
1156                         mime.setHtml(text);
1157                         clipboard.setMimeData(mime);
1158                 }
1159
1160                 logger.log(logger.EXTREME, "Final paste choice encountered");
1161                 browser.page().triggerAction(WebAction.Paste);
1162                 browser.setFocus();
1163
1164         }
1165
1166         // Paste text without formatting
1167         private void pasteWithoutFormattingClicked() {
1168                 logger.log(logger.EXTREME, "Paste without format clipped");
1169                 QClipboard clipboard = QApplication.clipboard();
1170                 QMimeData mime = clipboard.mimeData();
1171                 if (!mime.hasText())
1172                         return;
1173                 
1174                 // ICHANGED コピー&ペーストの操作履歴をデータベースに登録
1175                 String srcGuid = cbObserver.getSourceGuid();
1176                 String dstGuid = currentNote.getGuid();
1177                 if(srcGuid != null && dstGuid != null){
1178                         if(!srcGuid.equals(dstGuid)){
1179                                 conn.getHistoryTable().addHistory("copy & paste", srcGuid, dstGuid);
1180                         }
1181                 }
1182                 
1183                 String text = mime.text();
1184                 clipboard.clear();
1185                 clipboard.setText(text, Mode.Clipboard);
1186                 browser.page().triggerAction(WebAction.Paste);
1187
1188                 // This is done because pasting into an encryption block
1189                 // can cause multiple cells (which can't happen).  It 
1190                 // just goes through the table, extracts the data, & 
1191                 // puts it back as one table cell.
1192                 if (insideEncryption) {
1193                         String js = new String( "function fixEncryption() { "
1194                                         +"   var selObj = window.getSelection();"
1195                                         +"   var selRange = selObj.getRangeAt(0);"
1196                                         +"   var workingNode = window.getSelection().anchorNode;"
1197                                         +"   while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { " 
1198                                         +"           workingNode = workingNode.parentNode;"
1199                                         +"   } "
1200                                         +"   workingNode.innerHTML = window.jambi.fixEncryptionPaste(workingNode.innerHTML);"
1201                                         +"} fixEncryption();");
1202                         browser.page().mainFrame().evaluateJavaScript(js);
1203                 }
1204         }
1205         
1206         // This basically removes all the table tags and returns just the contents.
1207         // This is called by JavaScript to fix encryption pastes.
1208         public String fixEncryptionPaste(String data) {
1209                 data = data.replace("<tbody>", "");
1210                 data = data.replace("</tbody>", "");
1211                 data = data.replace("<tr>", "");
1212                 data = data.replace("</tr>", "");
1213                 data = data.replace("<td>", "");
1214                 data = data.replace("</td>", "<br>");
1215                 data = data.replace("<br><br>", "<br>");
1216
1217                 return "<tbody><tr><td>"+data+"</td></tr></tbody>";
1218         }
1219         
1220         // insert date/time
1221         @SuppressWarnings("unused")
1222         private void insertDateTime() {
1223                 String fmt = Global.getDateFormat() + " " + Global.getTimeFormat();
1224                 String dateTimeFormat = new String(fmt);
1225                 SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);
1226                 Calendar cal = Calendar.getInstance();
1227                 
1228                 browser.page().mainFrame().evaluateJavaScript(
1229                         "document.execCommand('insertHtml', false, '"+simple.format(cal.getTime())+"');");
1230                 
1231                 browser.setFocus();
1232
1233         }
1234
1235         // Listener when Left is clicked
1236         @SuppressWarnings("unused")
1237         private void justifyLeftClicked() {
1238                 browser.page().mainFrame().evaluateJavaScript(
1239                                 "document.execCommand('JustifyLeft', false, '');");
1240                 browser.setFocus();
1241         }
1242
1243         // Listener when Center is clicked
1244         @SuppressWarnings("unused")
1245         private void justifyCenterClicked() {
1246                 browser.page().mainFrame().evaluateJavaScript(
1247                                 "document.execCommand('JustifyCenter', false, '');");
1248                 browser.setFocus();
1249         }
1250
1251         // Listener when Left is clicked
1252         @SuppressWarnings("unused")
1253         private void justifyRightClicked() {
1254                 browser.page().mainFrame().evaluateJavaScript(
1255                                 "document.execCommand('JustifyRight', false, '');");
1256                 browser.setFocus();
1257         }
1258
1259         // Listener when HLINE is clicked
1260         @SuppressWarnings("unused")
1261         private void hlineClicked() {
1262                 browser.page().mainFrame().evaluateJavaScript(
1263                                 "document.execCommand('insertHorizontalRule', false, '');");
1264                 browser.setFocus();
1265         }
1266
1267         // Listener when outdent is clicked
1268         private void outdentClicked() {
1269                 browser.page().mainFrame().evaluateJavaScript(
1270                                 "document.execCommand('outdent', false, '');");
1271                 browser.setFocus();
1272         }
1273
1274         // Listener when a bullet list is clicked
1275         @SuppressWarnings("unused")
1276         private void bulletListClicked() {
1277                 browser.page().mainFrame().evaluateJavaScript(
1278                                 "document.execCommand('InsertUnorderedList', false, '');");
1279                 browser.setFocus();
1280         }
1281
1282         // Listener when a bullet list is clicked
1283         @SuppressWarnings("unused")
1284         private void numberListClicked() {
1285                 browser.page().mainFrame().evaluateJavaScript(
1286                                 "document.execCommand('InsertOrderedList', false, '');");
1287                 browser.setFocus();
1288         }
1289
1290         // Listener when indent is clicked
1291         private void indentClicked() {
1292                 browser.page().mainFrame().evaluateJavaScript(
1293                                 "document.execCommand('indent', false, '');");
1294                 browser.setFocus();
1295         }
1296
1297         // Listener when the font name is changed
1298         @SuppressWarnings("unused")
1299         private void fontChanged(String font) {
1300                 browser.page().mainFrame().evaluateJavaScript(
1301                                 "document.execCommand('fontName',false,'" + font + "');");
1302                 browser.setFocus();
1303         }
1304
1305         // Listener when a font size is changed
1306         @SuppressWarnings("unused")
1307         private void fontSizeChanged(String font) {
1308                 String text = browser.selectedText();
1309                 if (text.trim().equalsIgnoreCase(""))
1310                         return;
1311
1312                 String selectedText = browser.selectedText();
1313                 String url = "<span style=\"font-size:" +font +"pt; \">"+selectedText +"</a>";
1314                 String script = "document.execCommand('insertHtml', false, '"+url+"');";
1315                 browser.page().mainFrame().evaluateJavaScript(script);
1316 /*              browser.page().mainFrame().evaluateJavaScript(
1317                                 "document.execCommand('fontSize',false,'"
1318                                                 + font + "');");
1319 */
1320                 browser.setFocus();
1321         }
1322
1323         // Load the font combo box based upon the font selected
1324         private void loadFontSize(String name) {        
1325                 QFontDatabase db = new QFontDatabase(); 
1326                 fontSize.clear();
1327                 List<Integer> points = db.pointSizes(name); 
1328                 for (int i=0; i<points.size(); i++) { 
1329                         fontSize.addItem(points.get(i).toString()); 
1330                 }
1331                 /*
1332                 fontSize.addItem("x-small");
1333                 fontSize.addItem("small");
1334                 fontSize.addItem("medium");
1335                 fontSize.addItem("large");
1336                 fontSize.addItem("x-large");
1337                 fontSize.addItem("xx-large");
1338                 fontSize.addItem("xxx-large");
1339                 */
1340         }
1341
1342         // Listener when a font size is changed
1343         @SuppressWarnings("unused")
1344         private void fontColorClicked() {
1345 //              QColorDialog dialog = new QColorDialog();
1346 //              QColor color = QColorDialog.getColor();
1347                 QColor color = fontColorMenu.getColor();
1348                 if (color.isValid())
1349                         browser.page().mainFrame().evaluateJavaScript(
1350                                         "document.execCommand('foreColor',false,'" + color.name()
1351                                                         + "');");
1352                 browser.setFocus();
1353         }
1354
1355         // Listener for when a background color change is requested
1356         @SuppressWarnings("unused")
1357         private void fontHilightClicked() {
1358 //              QColorDialog dialog = new QColorDialog();
1359 //              QColor color = QColorDialog.getColor();
1360                 QColor color = fontHilightColorMenu.getColor();
1361                 if (color.isValid())
1362                         browser.page().mainFrame().evaluateJavaScript(
1363                                         "document.execCommand('backColor',false,'" + color.name()
1364                                                         + "');");
1365                 browser.setFocus();
1366         }
1367         
1368         // Listener for when a background color change is requested
1369         @SuppressWarnings("unused")
1370         private void superscriptClicked() {
1371                 browser.page().mainFrame().evaluateJavaScript(
1372                                         "document.execCommand('superscript');");
1373                 browser.setFocus();
1374         }
1375         
1376         // Listener for when a background color change is requested
1377         @SuppressWarnings("unused")
1378         private void subscriptClicked() {
1379                 browser.page().mainFrame().evaluateJavaScript(
1380                                         "document.execCommand('subscript');");
1381                 browser.setFocus();
1382         }
1383         // Insert a to-do checkbox
1384         @SuppressWarnings("unused")
1385         private void todoClicked() {
1386                 FileNameMap fileNameMap = URLConnection.getFileNameMap();
1387                 String script_start = new String(
1388                                 "document.execCommand('insertHtml', false, '");
1389                 String script_end = new String("');");
1390                 String todo = new String(
1391                                 "<input TYPE=\"CHECKBOX\" value=\"false\" " +
1392                                 "onMouseOver=\"style.cursor=\\'hand\\'\" " +
1393                                 "onClick=\"value=checked; window.jambi.contentChanged(); \" />");
1394                 browser.page().mainFrame().evaluateJavaScript(
1395                                 script_start + todo + script_end);
1396                 browser.setFocus();
1397         }
1398
1399         // Encrypt the selected text
1400         @SuppressWarnings("unused")
1401         private void encryptText() {
1402                 String text = browser.selectedText();
1403                 if (text.trim().equalsIgnoreCase(""))
1404                         return;
1405                 text = new String(text.replaceAll("\n", "<br/>"));
1406
1407                 EnCryptDialog dialog = new EnCryptDialog();
1408                 dialog.exec();
1409                 if (!dialog.okPressed()) {
1410                         return;
1411                 }
1412
1413                 EnCrypt crypt = new EnCrypt();
1414                 String encrypted = crypt.encrypt(text, dialog.getPassword().trim(), 64);
1415                 String decrypted = crypt.decrypt(encrypted, dialog.getPassword().trim(), 64);
1416
1417                 if (encrypted.trim().equals("")) {
1418                         QMessageBox.information(this, tr("Error"), tr("Error Encrypting String"));
1419                         return;
1420                 }
1421                 StringBuffer buffer = new StringBuffer(encrypted.length() + 100);
1422                 buffer.append("<img en-tag=\"en-crypt\" cipher=\"RC2\" hint=\""
1423                                 + dialog.getHint().replace("'","\\'") + "\" length=\"64\" ");
1424                 buffer.append("contentEditable=\"false\" alt=\"");
1425                 buffer.append(encrypted);
1426                 buffer.append("\" src=\"").append(FileUtils.toForwardSlashedPath(Global.getFileManager().getImageDirPath("encrypt.png") +"\""));
1427                 Global.cryptCounter++;
1428                 buffer.append(" id=\"crypt"+Global.cryptCounter.toString() +"\"");
1429                 buffer.append(" onMouseOver=\"style.cursor=\\'hand\\'\"");
1430                 buffer.append(" onClick=\"window.jambi.decryptText(\\'crypt"+Global.cryptCounter.toString() 
1431                                 +"\\', \\'"+encrypted+"\\', \\'"+dialog.getHint().replace("'", "\\&amp;apos;")+"\\');\"");
1432                 buffer.append("style=\"display:block\" />");
1433
1434                 String script_start = new String(
1435                                 "document.execCommand('insertHtml', false, '");
1436                 String script_end = new String("');");
1437                 browser.page().mainFrame().evaluateJavaScript(
1438                                 script_start + buffer.toString() + script_end);
1439         }
1440
1441
1442         // Insert a Quick hyperlink
1443         public void insertQuickLink() {
1444                 logger.log(logger.EXTREME, "Inserting link");
1445                 String text = browser.selectedText();
1446                 if (text.trim().equalsIgnoreCase(""))
1447                         return;
1448                 
1449                 // ICHANGED
1450                 NoteQuickLinkDialog dialog = new NoteQuickLinkDialog(logger, conn, text, cbObserver);
1451
1452                 if (dialog.getResults().size() == 0) {
1453                         QMessageBox.critical(null, tr("No Matches Found") ,tr("No matching notes found."));
1454                         return;
1455                 }
1456                 if (dialog.getResults().size() > 1) {
1457                         dialog.exec();
1458                         if (!dialog.okPressed) {
1459                                 logger.log(logger.EXTREME, "Insert link canceled");
1460                                 return;
1461                         }
1462                 }
1463
1464                 User user = Global.getUserInformation();
1465                 String dUrl = new String("evernote:///view/") + new String(user.getId() + "/" +user.getShardId() +"/"
1466                                 +dialog.getSelectedNote()+"/"+dialog.getSelectedNote() +"/ " +"style=\"color:#69aa35\"");
1467                 
1468                 String url = "<a title=\"" +dUrl
1469                                 +"\" href=" +dUrl 
1470                                 +" >"+text +"</a>";
1471                 String script = "document.execCommand('insertHtml', false, '"+url+"');";
1472                 browser.page().mainFrame().evaluateJavaScript(script);  
1473                 contentChanged();
1474         }
1475
1476         // Insert a hyperlink
1477         public void insertLink() {
1478                 logger.log(logger.EXTREME, "Inserting link");
1479                 String text = browser.selectedText();
1480                 if (text.trim().equalsIgnoreCase(""))
1481                         return;
1482
1483                 InsertLinkDialog dialog = new InsertLinkDialog(insertHyperlink);
1484                 if (currentHyperlink != null && currentHyperlink != "") {
1485                         dialog.setUrl(currentHyperlink);
1486                 }
1487                 dialog.exec();
1488                 if (!dialog.okPressed()) {
1489                         logger.log(logger.EXTREME, "Insert link canceled");
1490                         return;
1491                 }
1492                 
1493                 // Take care of inserting new links
1494                 if (insertHyperlink) {
1495                         String selectedText = browser.selectedText();
1496                         if (dialog.getUrl().trim().equals(""))
1497                                 return;
1498                         logger.log(logger.EXTREME, "Inserting link on text "+selectedText);
1499                         logger.log(logger.EXTREME, "URL Link " +dialog.getUrl().trim());
1500                         String dUrl = StringUtils.replace(dialog.getUrl().trim(), "'", "\\'");
1501                         String url = "<a href=\"" +dUrl
1502                                         +"\" title=" +dUrl 
1503                                         +" >"+selectedText +"</a>";
1504                         String script = "document.execCommand('insertHtml', false, '"+url+"');";
1505                         browser.page().mainFrame().evaluateJavaScript(script);
1506                         return;
1507                 }
1508                 
1509                 // Edit existing links
1510                 String js = new String( "function getCursorPos() {"
1511                                 +"var cursorPos;"
1512                                 +"if (window.getSelection) {"
1513                                 +"   var selObj = window.getSelection();"
1514                                 +"   var selRange = selObj.getRangeAt(0);"
1515                                 +"   var workingNode = window.getSelection().anchorNode.parentNode;"
1516                                 +"   while(workingNode != null) { " 
1517                                 +"      if (workingNode.nodeName.toLowerCase()=='a') workingNode.setAttribute('href','" +dialog.getUrl() +"');"
1518                                 +"      workingNode = workingNode.parentNode;"
1519                                 +"   }"
1520                                 +"}"
1521                                 +"} getCursorPos();");
1522                         browser.page().mainFrame().evaluateJavaScript(js);
1523                 
1524                 if (!dialog.getUrl().trim().equals("")) {
1525                         contentChanged();
1526                         return;
1527                 }
1528                 
1529                 // Remove URL
1530                 js = new String( "function getCursorPos() {"
1531                                 +"var cursorPos;"
1532                                 +"if (window.getSelection) {"
1533                                 +"   var selObj = window.getSelection();"
1534                                 +"   var selRange = selObj.getRangeAt(0);"
1535                                 +"   var workingNode = window.getSelection().anchorNode.parentNode;"
1536                                 +"   while(workingNode != null) { " 
1537                                 +"      if (workingNode.nodeName.toLowerCase()=='a') { "
1538                                 +"         workingNode.removeAttribute('href');"
1539                                 +"         workingNode.removeAttribute('title');"
1540                                 +"         var text = document.createTextNode(workingNode.innerText);"
1541                                 +"         workingNode.parentNode.insertBefore(text, workingNode);"
1542                                 +"         workingNode.parentNode.removeChild(workingNode);"
1543                                 +"      }"
1544                                 +"      workingNode = workingNode.parentNode;"
1545                                 +"   }"
1546                                 +"}"
1547                                 +"} getCursorPos();");
1548                         browser.page().mainFrame().evaluateJavaScript(js);
1549                         
1550                         contentChanged();
1551
1552                 
1553         }
1554         
1555         
1556         // Insert a hyperlink
1557         public void insertLatex() {
1558                 editLatex(null);
1559         }
1560         public void editLatex(String guid) {
1561                 logger.log(logger.EXTREME, "Inserting latex");
1562                 String text = browser.selectedText();
1563                 if (text.trim().equalsIgnoreCase("\n") || text.trim().equalsIgnoreCase("")) {
1564                         InsertLatexImage dialog = new InsertLatexImage();
1565                         if (guid != null) {
1566                                 String formula = conn.getNoteTable().noteResourceTable.getNoteSourceUrl(guid).replace("http://latex.codecogs.com/gif.latex?", "");
1567                                 dialog.setFormula(formula);
1568                         }
1569                         dialog.exec();
1570                         if (!dialog.okPressed()) {
1571                                 logger.log(logger.EXTREME, "Edit LaTex canceled");
1572                                 return;
1573                         }
1574                         text = dialog.getFormula().trim();
1575                 }
1576                 blockApplication.emit(this);
1577                 logger.log(logger.EXTREME, "Inserting LaTeX formula:" +text);
1578                 latexGuid = guid;
1579                 text = StringUtils.replace(text, "'", "\\'");
1580                 String url = "http://latex.codecogs.com/gif.latex?" +text;
1581                 logger.log(logger.EXTREME, "Sending request to codecogs --> " + url);
1582                 QNetworkAccessManager manager = new QNetworkAccessManager(this);
1583                 manager.finished.connect(this, "insertLatexImageReady(QNetworkReply)");
1584                 unblockTime = new GregorianCalendar().getTimeInMillis()+5000;
1585                 awaitingHttpResponse = true;
1586                 manager.get(new QNetworkRequest(new QUrl(url)));
1587         }
1588         
1589         public void insertLatexImageReady(QNetworkReply reply) {
1590                 logger.log(logger.EXTREME, "Response received from CodeCogs");
1591                 if (reply.error() != NetworkError.NoError) 
1592                         return;
1593
1594                 unblockTime = -1;
1595                 if (!awaitingHttpResponse)
1596                         return;
1597                 
1598                 awaitingHttpResponse = false;
1599                 QUrl replyUrl = reply.url();            
1600                 QByteArray image = reply.readAll();
1601                 reply.close();
1602                 logger.log(logger.EXTREME, "New image size: " +image.size());
1603
1604                 Resource newRes = null;
1605                 QFile tfile;
1606                 String path;
1607                 if (latexGuid == null) {
1608                         logger.log(logger.EXTREME, "Creating temporary gif");                   
1609                         path = Global.getFileManager().getResDirPath("latex-temp.gif");
1610                         tfile = new QFile(path);
1611                         tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
1612                         logger.log(logger.EXTREME, "File Open: " +tfile.errorString());
1613                         tfile.write(image);
1614                         logger.log(logger.EXTREME, "Bytes writtes: "+tfile.size());
1615                         tfile.close();
1616                         logger.log(logger.EXTREME, "Creating resource");
1617                         int sequence = 0;
1618                         if (currentNote.getResources() != null || currentNote.getResources().size() > 0)
1619                                 sequence = currentNote.getResources().size();
1620                         newRes = createResource(path,sequence ,"image/gif", false);
1621                         QImage pix = new QImage();
1622                         pix.loadFromData(image);
1623                         newRes.setHeight(new Integer(pix.height()).shortValue());
1624                         newRes.setWidth(new Integer(pix.width()).shortValue());
1625                         logger.log(logger.EXTREME, "Renaming temporary file to " +newRes.getGuid()+".gif");
1626                         path = Global.getFileManager().getResDirPath(newRes.getGuid()+".gif");
1627                         tfile.rename(path);
1628                 } else {
1629                         newRes = conn.getNoteTable().noteResourceTable.getNoteResource(latexGuid, false);
1630                         path = Global.getFileManager().getResDirPath(newRes.getGuid()+".gif");
1631                         tfile = new QFile(path);
1632                         tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
1633                         tfile.write(image);
1634                         tfile.close();
1635                         newRes.getData().setBody(image.toByteArray());
1636                         // Calculate the new hash value
1637                 MessageDigest md;
1638
1639                 logger.log(logger.EXTREME, "Generating MD5");
1640                 try {
1641                                 md = MessageDigest.getInstance("MD5");
1642                         md.update(image.toByteArray());
1643                         byte[] hash = md.digest();
1644                         newRes.getData().setBodyHash(hash);
1645                         } catch (NoSuchAlgorithmException e) {
1646                                 e.printStackTrace();
1647                         }
1648                         QImage pix = new QImage();
1649                         pix.loadFromData(image);
1650                         newRes.setHeight(new Integer(pix.height()).shortValue());
1651                         newRes.setWidth(new Integer(pix.width()).shortValue());
1652                         conn.getNoteTable().noteResourceTable.updateNoteResource(newRes, true);
1653                 }
1654
1655                 logger.log(logger.EXTREME, "Setting source: " +replyUrl.toString());
1656                 newRes.getAttributes().setSourceURL(replyUrl.toString());
1657                 conn.getNoteTable().noteResourceTable.updateNoteSourceUrl(newRes.getGuid(), replyUrl.toString(), true);
1658                 
1659                 for(int i=0; i<currentNote.getResourcesSize(); i++) {
1660                         if (currentNote.getResources().get(i).getGuid().equals(newRes.getGuid())) {
1661                                 currentNote.getResources().remove(i);
1662                                 i=currentNote.getResourcesSize();
1663                         }
1664                 }
1665                 currentNote.getResources().add(newRes);
1666                 
1667
1668                 // do the actual insert into the note.  We only do this on new formulas.  
1669                 if (latexGuid == null) {
1670                         StringBuffer buffer = new StringBuffer(100);
1671                         String formula = replyUrl.toString().toLowerCase().replace("http://latex.codecogs.com/gif.latex?", "");
1672                         buffer.append("<a href=\"latex://"+path.replace("\\", "/")+"\" title=\""+formula+"\""
1673                                         +"><img src=\"");
1674                         buffer.append(path.replace("\\", "/"));
1675                         buffer.append("\" en-tag=\"en-latex\" type=\"image/gif\""
1676                                 +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""
1677                                 +" guid=\"" +newRes.getGuid() +"\""
1678                                 + " /></a>");
1679                 
1680                         String script_start = new String("document.execCommand('insertHTML', false, '");
1681                         String script_end = new String("');");
1682                         browser.page().mainFrame().evaluateJavaScript(
1683                                         script_start + buffer + script_end);
1684                 } else {
1685                         HtmlTagModifier modifier = new HtmlTagModifier(getContent());
1686                         modifier.modifyLatexTagHash(newRes);
1687                         String newContent = modifier.getHtml();
1688                         setContent(new QByteArray(newContent));
1689                 }
1690
1691                 logger.log(logger.EXTREME, "New HTML set\n" +browser.page().currentFrame().toHtml());
1692                 QWebSettings.setMaximumPagesInCache(0);
1693                 QWebSettings.setObjectCacheCapacities(0, 0, 0);
1694                 
1695                 browser.page().mainFrame().setHtml(browser.page().mainFrame().toHtml());
1696                 browser.reload();
1697                 contentChanged();
1698 //              resourceSignal.contentChanged.emit(path);
1699                 unblockTime = -1;
1700         unblockApplication.emit();
1701                 return;
1702                 
1703         }
1704
1705         
1706         
1707         // Insert a table
1708         public void insertTable() {
1709                 TableDialog dialog = new TableDialog();
1710                 dialog.exec();
1711                 if (!dialog.okPressed()) {
1712                         return;
1713                 }
1714                 
1715                 int cols = dialog.getCols();
1716                 int rows = dialog.getRows();
1717                 int width = dialog.getWidth();
1718                 boolean percent = dialog.isPercent();
1719                 
1720                 String newHTML = "<table border=\"1\" width=\"" +new Integer(width).toString();
1721                 if (percent)
1722                         newHTML = newHTML +"%";
1723                 newHTML = newHTML + "\"><tbody>";
1724
1725                 for (int i=0; i<rows; i++) {
1726                         newHTML = newHTML +"<tr>";
1727                         for (int j=0; j<cols; j++) {
1728                                 newHTML = newHTML +"<td>&nbsp;</td>";
1729                         }
1730                         newHTML = newHTML +"</tr>";
1731                 }
1732                 newHTML = newHTML+"</tbody></table>";   
1733         
1734                 String script = "document.execCommand('insertHtml', false, '"+newHTML+"');";
1735                 browser.page().mainFrame().evaluateJavaScript(script);
1736         }
1737         
1738         
1739         // Text content changed
1740         @SuppressWarnings("unused")
1741         private void selectionChanged() {
1742                 browser.encryptAction.setEnabled(true);
1743                 browser.insertLinkAction.setEnabled(true);
1744                 browser.insertQuickLinkAction.setEnabled(true);
1745                 String scriptStart = "var selection_text = (window.getSelection()).toString();"
1746                                 + "var range = (window.getSelection()).getRangeAt(0);"
1747                                 + "var parent_html = range.commonAncestorContainer.innerHTML;"
1748                                 + "if (parent_html == undefined) {window.jambi.saveSelectedText(selection_text); return;}"
1749                                 + "var first_text = range.startContainer.nodeValue.substr(range.startOffset);"
1750                                 + "var last_text = (range.endContainer.nodeValue).substring(0,range.endOffset);"
1751                                 + "var start = parent_html.indexOf(first_text);"
1752                                 + "var end = parent_html.indexOf(last_text,start+1)+last_text.length;"
1753                                 + "var value = parent_html.substring(start,end);"
1754                                 + "window.jambi.saveSelectedText(value);" ;
1755                 browser.page().mainFrame().evaluateJavaScript(scriptStart);
1756
1757         }
1758
1759         public void saveSelectedText(String text) {
1760                 boolean enabled = true;
1761                 if (text.trim().length() == 0)
1762                         enabled=false;
1763                 if (text.indexOf("en-tag=\"en-crypt\"") >= 0)
1764                         enabled=false;
1765                 if (text.indexOf("<img en-tag=\"en-media\"") >= 0)
1766                         enabled=false;
1767                 if (text.indexOf("<a en-tag=\"en-media\"") >= 0)
1768                         enabled=false;
1769                 if (text.indexOf("<input ") >= 0)
1770                         enabled=false;
1771                 
1772                 browser.encryptAction.setEnabled(enabled);
1773                 browser.insertLinkAction.setEnabled(enabled);
1774                 browser.insertQuickLinkAction.setEnabled(enabled);
1775 //              selectedText = text;
1776         }
1777
1778         // Decrypt clicked text
1779         public void decryptText(String id, String text, String hint) {
1780                 EnCrypt crypt = new EnCrypt();
1781                 String plainText = null;
1782                 Calendar currentTime = new GregorianCalendar();
1783                 Long l = new Long(currentTime.getTimeInMillis());
1784                 String slot = new String(Long.toString(l));
1785                 
1786                 // First, try to decrypt with any keys we already have
1787                 for (int i=0; i<Global.passwordRemember.size(); i++) {
1788                         plainText = crypt.decrypt(text, Global.passwordRemember.get(i).getFirst(), 64);
1789                         if (plainText != null) {
1790                                 slot = new String(Long.toString(l));
1791                                 Global.passwordSafe.put(slot, Global.passwordRemember.get(i));
1792                                 removeEncryption(id, plainText, false, slot);   
1793                                 return;
1794                         }
1795                 }
1796                 
1797                 
1798                 EnDecryptDialog dialog = new EnDecryptDialog();
1799                 dialog.setHint(hint);
1800                 while (plainText == null || !dialog.okPressed()) {
1801                         dialog.exec();
1802                         if (!dialog.okPressed()) {
1803                                 return;
1804                         }
1805                         plainText = crypt.decrypt(text, dialog.getPassword().trim(), 64);
1806                         if (plainText == null) {
1807                                 QMessageBox.warning(this, tr("Incorrect Password"), tr("The password entered is not correct"));
1808                         }
1809                 }
1810                 Pair<String,String> passwordPair = new Pair<String,String>();
1811                 passwordPair.setFirst(dialog.getPassword());
1812                 passwordPair.setSecond(dialog.getHint());
1813                 Global.passwordSafe.put(slot, passwordPair);
1814 //              removeEncryption(id, plainText.replaceAll("\n", "<br/>"), dialog.permanentlyDecrypt(), slot);
1815                 removeEncryption(id, plainText, dialog.permanentlyDecrypt(), slot);
1816                 if (dialog.rememberPassword()) {
1817                         Pair<String, String> pair = new Pair<String,String>();
1818                         pair.setFirst(dialog.getPassword());
1819                         pair.setSecond(dialog.getHint());
1820                         Global.passwordRemember.add(pair);
1821                 }
1822
1823         }
1824
1825         // Get the editor tag line
1826         public TagLineEdit getTagLine() {
1827                 return tagEdit;
1828         }
1829
1830         // Modify a note's tags
1831         @SuppressWarnings("unused")
1832         private void modifyTags() {
1833                 TagAssign tagWindow = new TagAssign(allTags, currentTags, !conn.getNotebookTable().isLinked(currentNote.getNotebookGuid()));
1834                 tagWindow.exec();
1835                 if (tagWindow.okClicked()) {
1836                         currentTags.clear();
1837                         StringBuffer tagDisplay = new StringBuffer();
1838
1839                         List<QListWidgetItem> newTags = tagWindow.getTagList()
1840                                         .selectedItems();
1841                         for (int i = 0; i < newTags.size(); i++) {
1842                                 currentTags.add(newTags.get(i).text());
1843                                 tagDisplay.append(newTags.get(i).text());
1844                                 if (i < newTags.size() - 1) {
1845                                         tagDisplay.append(Global.tagDelimeter + " ");
1846                                 }
1847                         }
1848                         tagEdit.setText(tagDisplay.toString());
1849                         noteSignal.tagsChanged.emit(currentNote.getGuid(), currentTags);
1850                 }
1851         }
1852
1853         // Tag line has been modified by typing text
1854         @SuppressWarnings("unused")
1855         private void modifyTagsTyping() {
1856                 String completionText = "";
1857                 if (tagEdit.currentCompleterSelection != null && !tagEdit.currentCompleterSelection.equals("")) {
1858                         completionText = tagEdit.currentCompleterSelection;
1859                         tagEdit.currentCompleterSelection = "";
1860                 }
1861                 
1862                 if (tagEdit.text().equalsIgnoreCase(saveTagList))
1863                         return;
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();
2954         }
2955         
2956         //****************************************************************
2957         //* Delete a table row
2958         //****************************************************************
2959         public void deleteTableRow() {
2960                 
2961                 String js = new String( "function deleteTableRow() {"
2962                         +"   var selObj = window.getSelection();"
2963                         +"   var selRange = selObj.getRangeAt(0);"
2964                         +"   var workingNode = window.getSelection().anchorNode.parentNode;"
2965                         +"   var cellCount = 0;"
2966                         +"   while(workingNode != null) { " 
2967                         +"      if (workingNode.nodeName.toLowerCase()=='tr') {"
2968                         +"           workingNode.parentNode.removeChild(workingNode);"
2969                         +"           return;"
2970                         +"      }"
2971                         +"      workingNode = workingNode.parentNode;"
2972                         +"   }"
2973                         +"} deleteTableRow();");
2974                 browser.page().mainFrame().evaluateJavaScript(js);
2975                 contentChanged();
2976         }
2977
2978         public void deleteTableColumn() {
2979                 String js = new String( "function deleteTableColumn() {"
2980                                 +"   var selObj = window.getSelection();"
2981                                 +"   var selRange = selObj.getRangeAt(0);"
2982                                 +"   var workingNode = window.getSelection().anchorNode.parentNode;"
2983                                 +"   var current = 0;"
2984                                 +"   while (workingNode.nodeName.toLowerCase() != 'table' && workingNode != null) {"
2985                                 +"       if (workingNode.nodeName.toLowerCase() == 'td') {"
2986                                 +"          var td = workingNode;"
2987                                 +"          while (td.previousSibling != null) { " 
2988                                 +"             current = current+1; td = td.previousSibling;"
2989                                 +"          }"
2990                                 +"       }"
2991                                 +"       workingNode = workingNode.parentNode; "
2992                                 +"   }"
2993                                 +"   if (workingNode == null) return;"
2994                                 +"   for (var i=0; i<workingNode.rows.length; i++) { " 
2995                                 +"      workingNode.rows[i].deleteCell(current); "                      
2996                                 +"   }"
2997                                 +"} deleteTableColumn();");
2998                         browser.page().mainFrame().evaluateJavaScript(js);
2999                         contentChanged();
3000         }
3001         
3002         
3003         public void setInsideTable() {
3004                 browser.insertTableRowAction.setEnabled(true);
3005                 browser.insertTableColumnAction.setEnabled(true);
3006                 browser.deleteTableRowAction.setEnabled(true);
3007                 browser.deleteTableColumnAction.setEnabled(true);
3008                 browser.insertTableAction.setEnabled(false);
3009                 browser.encryptAction.setEnabled(false);
3010                 insideTable = true;
3011         }
3012         
3013         public void setInsideLink(String link) {
3014                 browser.insertLinkAction.setText(tr("Edit Hyperlink"));
3015                 currentHyperlink = link;
3016                 insertHyperlink = false;
3017         }
3018         
3019         public void italicActive() {
3020                 italicButton.setDown(true);
3021         }
3022         public void boldActive() {
3023                 boldButton.setDown(true);
3024         }
3025         public void underlineActive() {
3026                 underlineButton.setDown(true);
3027         }
3028         public void forceTextPaste() {
3029                 forceTextPaste = true;
3030         }
3031         public void imageContextMenu(String f) {
3032                 browser.downloadImage.setEnabled(true);
3033                 browser.rotateImageRight.setEnabled(true);
3034                 browser.rotateImageLeft.setEnabled(true);
3035                 browser.openAction.setEnabled(true);
3036                 selectedFile = f;
3037         }
3038         public void rotateImageRight() {
3039                 QWebSettings.setMaximumPagesInCache(0);
3040                 QWebSettings.setObjectCacheCapacities(0, 0, 0);
3041                 QImage image = new QImage(selectedFile);
3042                 QMatrix matrix = new QMatrix();
3043                 matrix.rotate( 90.0 );
3044                 image = image.transformed(matrix);
3045                 image.save(selectedFile);
3046                 QWebSettings.setMaximumPagesInCache(0);
3047                 QWebSettings.setObjectCacheCapacities(0, 0, 0);
3048                 browser.setHtml(browser.page().mainFrame().toHtml());
3049                 browser.reload();
3050                 contentChanged();
3051                 resourceSignal.contentChanged.emit(selectedFile);
3052
3053         }
3054         public void rotateImageLeft() {
3055                 QImage image = new QImage(selectedFile);
3056                 QMatrix matrix = new QMatrix();
3057                 matrix.rotate( -90.0 );
3058                 image = image.transformed(matrix);
3059                 image.save(selectedFile);
3060                 browser.setHtml(browser.page().mainFrame().toHtml());
3061                 browser.reload();
3062                 contentChanged();
3063                 resourceSignal.contentChanged.emit(selectedFile);
3064         }
3065         public void resourceContextMenu(String f) {
3066                 browser.downloadAttachment.setEnabled(true);
3067                 browser.openAction.setEnabled(true);
3068                 selectedFile = f;
3069         }
3070         public void latexContextMenu(String f) {
3071                 browser.downloadImage.setEnabled(true);
3072                 browser.rotateImageRight.setEnabled(true);
3073                 browser.rotateImageLeft.setEnabled(true);
3074                 browser.openAction.setEnabled(true);
3075                 selectedFile = f;
3076         }
3077
3078         //****************************************************************
3079         //* Apply CSS style to specified word
3080         //****************************************************************
3081 /*      public void applyStyleToWords(String word, String style) {
3082                 QFile script = new QFile("D:\\NeverNote\\js\\hilight1.js");
3083                 script.open(OpenModeFlag.ReadOnly);
3084                 String s = script.readAll().toString();
3085                 String js = new String(s +" findit('"+word+"', '"+style+"');");
3086                 browser.page().mainFrame().evaluateJavaScript(js);
3087                 System.out.println(getContent());
3088         }
3089 */      
3090         //****************************************************************
3091         //* Someone tried to paste a resource between notes, so we need  *
3092         //* to do some special handling.                                 *
3093         //****************************************************************
3094         private String fixInternotePaste(String text) {
3095                 logger.log(logger.EXTREME, "Fixing internote paste");
3096                 String returnValue = fixInternotePasteSearch(text, "<img", "src=\"");
3097                 return fixInternotePasteSearch(returnValue, "<a", "href=\"nnres://");
3098         }
3099         private String fixInternotePasteSearch(String text, String type, String locTag) {
3100                 
3101                 // First, let's fix the images.
3102                 int startPos = text.indexOf(type);
3103                 int endPos;
3104                 for (; startPos>=0;) {
3105                         endPos = text.indexOf(">", startPos+1);
3106                         String segment = text.substring(startPos, endPos);
3107                         if (segment.indexOf("en-tag") > -1) {
3108                                 String newSegment = segment;
3109                                 
3110                                 int guidStartPos = segment.indexOf("guid=\"");
3111                                 int guidEndPos = segment.indexOf("\"", guidStartPos+7);
3112                                 String guid = segment.substring(guidStartPos+6,guidEndPos);
3113                                 
3114                                 int mimeStartPos = segment.indexOf("type");
3115                                 int mimeEndPos = segment.indexOf("\"", mimeStartPos+7);
3116                                 String mime = segment.substring(mimeStartPos+6,mimeEndPos);
3117
3118                                 int srcStartPos = segment.indexOf("src");
3119                                 int srcEndPos = segment.indexOf("\"", srcStartPos+6);
3120                                 String src = segment.substring(srcStartPos+5,srcEndPos);
3121                                 
3122                                 Calendar currentTime = new GregorianCalendar();
3123                                 Long l = new Long(currentTime.getTimeInMillis());
3124                                 long prevTime = l;
3125                                 while (l==prevTime) {
3126                                         currentTime = new GregorianCalendar();
3127                                         l= new Long(currentTime.getTimeInMillis());
3128                                 }
3129                                 
3130                                 Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
3131                                 // if r==null, then the image doesn't exist (it was probably cut out of another note, so 
3132                                 // we need to recereate it
3133                                 if (r==null) {
3134                                         r = createResource(src, 1, mime, false);
3135                                         if (r==null)
3136                                                 return "";
3137                                 }
3138                         String randint = new String(Long.toString(l));
3139                         String extension = null;
3140                         if (r.getMime()!= null) {
3141                                 extension = r.getMime().toLowerCase();
3142                                 if (extension.indexOf("/")>-1)
3143                                         extension = extension.substring(extension.indexOf("/")+1);
3144                         }
3145                         String newFile = randint;
3146                         if (r.getAttributes().getFileName() != null && r.getAttributes().getFileName() != "")
3147                                 if (!locTag.startsWith("src"))
3148                                         newFile = newFile+Global.attachmentNameDelimeter+r.getAttributes().getFileName();
3149                         r.setNoteGuid(currentNote.getGuid());
3150                         
3151                         r.setGuid(randint);
3152                         conn.getNoteTable().noteResourceTable.saveNoteResource(r, true);
3153                                 QFile f = new QFile(Global.getFileManager().getResDirPath(newFile));
3154                                 QByteArray bin = new QByteArray(r.getData().getBody());
3155                                 f.open(QFile.OpenModeFlag.WriteOnly);
3156                                 f.write(bin);
3157                                 f.close();
3158                                 newSegment = newSegment.replace("guid=\""+guid, "guid=\""+randint);
3159                                 currentNote.getResources().add(r);
3160                                 
3161                                 int startSrcPos = newSegment.indexOf(locTag);
3162                                 int endSrcPos = newSegment.indexOf("\"",startSrcPos+locTag.length()+1);
3163                                 String source; 
3164                                 if (locTag.startsWith("src")) {
3165                                          source = newSegment.substring(startSrcPos+locTag.length(),endSrcPos);
3166                                                 newSegment = newSegment.replace(source,
3167                                                         FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath(newFile)));
3168                                 } else {
3169                                         source = newSegment.substring(startSrcPos+locTag.length(),endSrcPos);
3170                                         newSegment = newSegment.replace(source, newFile);
3171                                 }
3172                                 
3173                                 text = text.substring(0,startPos) + newSegment + text.substring(endPos);
3174                         }
3175                         startPos = text.indexOf(type, startPos+1);
3176                 }
3177                 return text;
3178         }
3179
3180
3181         public void nextPage(String file) {
3182                 logger.log(logger.EXTREME, "Starting nextPage()");
3183                 
3184                 Integer pageNumber;
3185                 if (previewPageList.containsKey(file))
3186                         pageNumber = previewPageList.get(file)+1;
3187                 else
3188                         pageNumber = 2;
3189                 previewPageList.remove(file);
3190                 previewPageList.put(file, pageNumber);
3191                 PDFPreview pdfPreview = new PDFPreview();
3192                 boolean goodPreview = pdfPreview.setupPreview(file, "pdf", pageNumber);
3193                 if (goodPreview) {
3194
3195 //                      String html = getContent();
3196                         QWebSettings.setMaximumPagesInCache(0);
3197                         QWebSettings.setObjectCacheCapacities(0, 0, 0);
3198 //                      browser.setContent(new QByteArray());
3199                         browser.setHtml(browser.page().mainFrame().toHtml());
3200                         browser.reload();
3201 //                      browser.setContent(new QByteArray(html));
3202 //                      browser.triggerPageAction(WebAction.Reload);
3203 //                      pdfMouseOver(selectedFile);
3204                 }
3205         }
3206
3207         public void previousPage(String file) {
3208                 logger.log(logger.EXTREME, "Starting previousPage()");
3209                 
3210                 Integer pageNumber;
3211                 if (previewPageList.containsKey(file))
3212                         pageNumber = previewPageList.get(file)-1;
3213                 else
3214                         pageNumber = 1;
3215                 previewPageList.remove(file);
3216                 previewPageList.put(file, pageNumber);
3217                 PDFPreview pdfPreview = new PDFPreview();
3218                 boolean goodPreview = pdfPreview.setupPreview(file, "pdf", pageNumber);
3219                 if (goodPreview) {
3220
3221 //                      String html = getContent();
3222                         QWebSettings.setMaximumPagesInCache(0);
3223                         QWebSettings.setObjectCacheCapacities(0, 0, 0);
3224                         browser.setHtml(browser.page().mainFrame().toHtml());
3225                         browser.reload();
3226 //                      browser.setContent(new QByteArray(html));
3227 //                      browser.triggerPageAction(WebAction.Reload);
3228                 }
3229         }
3230         
3231 /*      public void pdfMouseOver(String name) { 
3232                 int pageNumber;
3233                 if (previewPageList.containsKey(selectedFile))
3234                         pageNumber = previewPageList.get(selectedFile)+1;
3235                 else
3236                         pageNumber = 1;
3237                 
3238                 if (pageNumber <= 1)
3239                         browser.previousPageAction.setEnabled(false);
3240                 else
3241                         browser.previousPageAction.setEnabled(true);
3242                 
3243                 PDFPreview pdf = new PDFPreview();
3244                 int totalPages = pdf.getPageCount(name);
3245                 if (previewPageList.containsKey(selectedFile))
3246                         pageNumber = previewPageList.get(selectedFile)+1;
3247                 else
3248                         pageNumber = 1;
3249                 if (totalPages > pageNumber)
3250                         browser.nextPageAction.setEnabled(true);
3251                 else
3252                         browser.nextPageAction.setEnabled(false);
3253         }
3254         
3255
3256         public void pdfMouseOut() { 
3257 //              browser.nextPageAction.setVisible(false);
3258 //              browser.previousPageAction.setVisible(false);
3259         }
3260 */
3261         
3262         @SuppressWarnings("unused")
3263         private void toggleUndoVisible(Boolean toggle) {
3264                 undoAction.setVisible(toggle);
3265                 Global.saveEditorButtonsVisible("undo", toggle);
3266         }
3267         @SuppressWarnings("unused")
3268         private void toggleRedoVisible(Boolean toggle) {
3269                 redoAction.setVisible(toggle);
3270                 Global.saveEditorButtonsVisible("redo", toggle);
3271         }
3272         @SuppressWarnings("unused")
3273         private void toggleCutVisible(Boolean toggle) {
3274                 cutAction.setVisible(toggle);
3275                 Global.saveEditorButtonsVisible("cut", toggle);
3276         }
3277         @SuppressWarnings("unused")
3278         private void toggleCopyVisible(Boolean toggle) {
3279                 copyAction.setVisible(toggle);
3280                 Global.saveEditorButtonsVisible("copy", toggle);
3281         }
3282         @SuppressWarnings("unused")
3283         private void togglePasteVisible(Boolean toggle) {
3284                 pasteAction.setVisible(toggle);
3285                 Global.saveEditorButtonsVisible("paste", toggle);
3286         }
3287         @SuppressWarnings("unused")
3288         private void toggleBoldVisible(Boolean toggle) {
3289                 boldAction.setVisible(toggle);
3290                 Global.saveEditorButtonsVisible("bold", toggle);
3291         }
3292         @SuppressWarnings("unused")
3293         private void toggleItalicVisible(Boolean toggle) {
3294                 italicAction.setVisible(toggle);
3295                 Global.saveEditorButtonsVisible("italic", toggle);
3296         }
3297         @SuppressWarnings("unused")
3298         private void toggleUnderlineVisible(Boolean toggle) {
3299                 underlineAction.setVisible(toggle);
3300                 Global.saveEditorButtonsVisible("underline", toggle);
3301         }
3302         @SuppressWarnings("unused")
3303         private void toggleStrikethroughVisible(Boolean toggle) {
3304                 strikethroughAction.setVisible(toggle);
3305                 Global.saveEditorButtonsVisible("strikethrough", toggle);
3306         }
3307         @SuppressWarnings("unused")
3308         private void toggleLeftAlignVisible(Boolean toggle) {
3309                 leftAlignAction.setVisible(toggle);
3310                 Global.saveEditorButtonsVisible("alignLeft", toggle);
3311         }
3312         @SuppressWarnings("unused")
3313         private void toggleRightAlignVisible(Boolean toggle) {
3314                 rightAlignAction.setVisible(toggle);
3315                 Global.saveEditorButtonsVisible("alignRight", toggle);
3316         }       
3317         @SuppressWarnings("unused")
3318         private void toggleCenterAlignVisible(Boolean toggle) {
3319                 centerAlignAction.setVisible(toggle);
3320                 Global.saveEditorButtonsVisible("alignCenter", toggle);
3321         }
3322         @SuppressWarnings("unused")
3323         private void toggleHLineVisible(Boolean toggle) {
3324                 hlineAction.setVisible(toggle);
3325                 Global.saveEditorButtonsVisible("hline", toggle);
3326         }
3327         @SuppressWarnings("unused")
3328         private void toggleIndentVisible(Boolean toggle) {
3329                 indentAction.setVisible(toggle);
3330                 Global.saveEditorButtonsVisible("indent", toggle);
3331         }
3332         @SuppressWarnings("unused")
3333         private void toggleTodoVisible(Boolean toggle) {
3334                 todoAction.setVisible(toggle);
3335                 Global.saveEditorButtonsVisible("todo", toggle);
3336         }
3337         @SuppressWarnings("unused")
3338         private void toggleOutdentVisible(Boolean toggle) {
3339                 outdentAction.setVisible(toggle);
3340                 Global.saveEditorButtonsVisible("outdent", toggle);
3341         }
3342         @SuppressWarnings("unused")
3343         private void toggleBulletListVisible(Boolean toggle) {
3344                 bulletListAction.setVisible(toggle);
3345                 Global.saveEditorButtonsVisible("bulletList", toggle);
3346         }
3347         @SuppressWarnings("unused")
3348         private void toggleNumberListVisible(Boolean toggle) {
3349                 numberListAction.setVisible(toggle);
3350                 Global.saveEditorButtonsVisible("numberList", toggle);
3351         }
3352         @SuppressWarnings("unused")
3353         private void toggleFontListVisible(Boolean toggle) {
3354                 fontListAction.setVisible(toggle);
3355                 Global.saveEditorButtonsVisible("font", toggle);
3356         }
3357         @SuppressWarnings("unused")
3358         private void toggleFontColorVisible(Boolean toggle) {
3359                 fontColorAction.setVisible(toggle);
3360                 Global.saveEditorButtonsVisible("fontColor", toggle);
3361         }
3362         @SuppressWarnings("unused")
3363         private void toggleFontSizeVisible(Boolean toggle) {
3364                 fontSizeAction.setVisible(toggle);
3365                 Global.saveEditorButtonsVisible("fontSize", toggle);
3366         }
3367         @SuppressWarnings("unused")
3368         private void toggleFontHilightVisible(Boolean toggle) {
3369                 fontHilightAction.setVisible(toggle);
3370                 Global.saveEditorButtonsVisible("fontHilight", toggle);
3371         }
3372         @SuppressWarnings("unused")
3373         private void toggleSpellCheckVisible(Boolean toggle) {
3374                 spellCheckAction.setVisible(toggle);
3375                 Global.saveEditorButtonsVisible("spellCheck", toggle);
3376         }
3377
3378
3379         private void setupDictionary() {
3380                 File wordList = new File(Global.getFileManager().getSpellDirPath()+Locale.getDefault()+".dic");
3381                 try {
3382                         dictionary = new SpellDictionaryHashMap(wordList);
3383                         spellChecker = new SpellChecker(dictionary);
3384                         
3385                         File userWordList;
3386                         userWordList = new File(Global.getFileManager().getSpellDirPathUser()+"user.dic");
3387                         
3388                         // Get the local user spell dictionary
3389                         try {
3390                                 userDictionary = new SpellDictionaryHashMap(userWordList);
3391                         } catch (FileNotFoundException e) {
3392                                 userWordList.createNewFile();
3393                                 userDictionary = new SpellDictionaryHashMap(userWordList);
3394                         } catch (IOException e) {
3395                                 userWordList.createNewFile();
3396                                 userDictionary = new SpellDictionaryHashMap(userWordList);
3397                         }
3398                         
3399                         spellListener = new SuggestionListener(this, spellChecker);
3400                         
3401                         // Add the user dictionary
3402                         spellChecker.addSpellCheckListener(spellListener);
3403                         spellChecker.setUserDictionary(userDictionary);
3404
3405                 } catch (FileNotFoundException e) {
3406                         QMessageBox.critical(this, tr("Spell Check Error"), 
3407                                         tr("Dictionary ")+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+
3408                                                 tr(".dic was not found."));
3409                 } catch (IOException e) {
3410                         QMessageBox.critical(this, tr("Spell Check Error"), 
3411                                         tr("Dictionary ")+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+
3412                                                 tr(".dic is invalid."));
3413                 }
3414
3415         }
3416         
3417         // Invoke spell checker dialog
3418         @SuppressWarnings("unused")
3419         private void spellCheckClicked() {
3420
3421                 if (spellChecker == null) {
3422                         setupDictionary();      
3423                 }
3424                 
3425                 // Read user settings
3426                 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREDIGITWORDS, 
3427                                 Global.getSpellSetting(Configuration.SPELL_IGNOREDIGITWORDS));
3428                 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREINTERNETADDRESSES, 
3429                                 Global.getSpellSetting(Configuration.SPELL_IGNOREINTERNETADDRESSES));
3430                 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREMIXEDCASE, 
3431                                 Global.getSpellSetting(Configuration.SPELL_IGNOREMIXEDCASE));
3432                 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREUPPERCASE, 
3433                                 Global.getSpellSetting(Configuration.SPELL_IGNOREUPPERCASE));
3434                 spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNORESENTENCECAPITALIZATION, 
3435                                 Global.getSpellSetting(Configuration.SPELL_IGNORESENTENCECAPITALIZATION));
3436
3437                 spellListener.abortSpellCheck = false;
3438                 spellListener.errorsFound = false;
3439                 String content = getBrowser().page().mainFrame().toPlainText();
3440                 StringWordTokenizer tokenizer = new StringWordTokenizer(content);
3441                 if (!tokenizer.hasMoreWords())
3442                         return;
3443                 getBrowser().page().action(WebAction.MoveToStartOfDocument);
3444
3445                 getBrowser().setFocus();
3446                 boolean found;
3447                         
3448                 // Move to the start of page
3449                 KeyboardModifiers ctrl = new KeyboardModifiers(KeyboardModifier.ControlModifier.value());
3450                 QKeyEvent home = new QKeyEvent(Type.KeyPress, Key.Key_Home.value(), ctrl);  
3451                 browser.keyPressEvent(home);
3452                 getBrowser().setFocus();
3453                         
3454                 tokenizer = new StringWordTokenizer(content);
3455                 String word;
3456                         
3457                 while(tokenizer.hasMoreWords()) {
3458                         word = tokenizer.nextWord();
3459                         found = getBrowser().page().findText(word);
3460                         if (found && !spellListener.abortSpellCheck) {
3461                                 spellChecker.checkSpelling(new StringWordTokenizer(word));
3462                                 getBrowser().setFocus();
3463                         }
3464                 }
3465
3466                 // Go to the end of the document & finish up.
3467                 home = new QKeyEvent(Type.KeyPress, Key.Key_End.value(), ctrl);  
3468                 browser.keyPressEvent(home);
3469                 if (!spellListener.errorsFound)
3470                         QMessageBox.information(this, tr("Spell Check Complete"), 
3471                                         tr("No Errors Found"));
3472
3473     }
3474         
3475         // Source edited
3476         @SuppressWarnings("unused")
3477         private void sourceEdited() {
3478                 QTextCodec codec = QTextCodec.codecForLocale();
3479                 codec = QTextCodec.codecForName("UTF-8");
3480         String content =  codec.fromUnicode(sourceEdit.toHtml()).toString();
3481                 content = StringEscapeUtils.unescapeHtml4(removeTags(content));
3482                 QByteArray data = new QByteArray(sourceEditHeader+content+"</body></html>");
3483                 getBrowser().setContent(data);
3484                 checkNoteTitle();
3485                 if (currentNote != null && sourceEdit != null)
3486                         noteSignal.noteChanged.emit(currentNote.getGuid(), sourceEdit.toPlainText()); 
3487         }
3488         
3489         private void setSource() {
3490                 String text = getContent();
3491                 sourceEdit.blockSignals(true);
3492                 int body = text.indexOf("<body");
3493                 if (body > 0) {
3494                         body = text.indexOf(">",body);
3495                         if (body > 0) {
3496                                 sourceEditHeader =text.substring(0, body+1);
3497                                 text = text.substring(body+1);
3498                         }
3499                 }
3500                 text = text.replace("</body></html>", "");
3501                 sourceEdit.setPlainText(text);
3502                 sourceEdit.setReadOnly(!getBrowser().page().isContentEditable());
3503                 //syntaxHighlighter.rehighlight();
3504                 sourceEdit.blockSignals(false);
3505         }
3506
3507         // show/hide view source window
3508         public void showSource(boolean value) {
3509                 setSource();
3510                 sourceEdit.setVisible(value);
3511         }
3512
3513         // Remove HTML tags
3514         private String removeTags(String text) {
3515                 StringBuffer buffer = new StringBuffer(text);
3516                 boolean inTag = false;
3517                 int bodyPosition = text.indexOf("<body");
3518                 for (int i=buffer.length()-1; i>=0; i--) {
3519                         if (buffer.charAt(i) == '>')
3520                                 inTag = true;
3521                         if (buffer.charAt(i) == '<')
3522                                 inTag = false;
3523                         if (inTag || buffer.charAt(i) == '<' || i<bodyPosition)
3524                                 buffer.deleteCharAt(i);
3525                 }
3526                 
3527                 return buffer.toString();
3528         }
3529 }