From 46a06a0483a75c377a327bab869f6e424a0b6865 Mon Sep 17 00:00:00 2001 From: yuki Date: Tue, 12 Mar 2013 18:12:08 +0900 Subject: [PATCH] =?utf8?q?GitHub=E6=9C=80=E5=88=9D=E3=81=AE=E3=82=B3?= =?utf8?q?=E3=83=9F=E3=83=83=E3=83=88(SourceForge.jp=20128fa38=202013-02-2?= =?utf8?q?8=2015:28:57=20=E3=81=A8=E5=90=8C=E3=81=98=E5=86=85=E5=AE=B9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- .classpath | 64 +- .gitignore | 3 + .project | 2 +- README.txt | 29 - build.xml | 12 +- install.sh | 6 +- install.txt | 6 +- license.html | 6 +- nixnote-osx => neighbornote-osx | 68 +- nixnote.bat => neighbornote.bat | 66 +- nixnote.desktop => neighbornote.desktop.desktop | 8 +- neighbornote.ico | Bin 0 -> 16452 bytes neighbornote.png | Bin 0 -> 4183 bytes nixnote.pro => neighbornote.pro | 0 nixnote.sh => neighbornote.sh | 70 +- neighbornote_path.sh | 2 + nixnote.ico | Bin 370070 -> 0 bytes nixnote.png | Bin 2725 -> 0 bytes nixnote_path.sh | 2 - release.txt | 2 +- shortcuts_howto.txt | 8 +- src/cx/fbn/nevernote/Global.java | 4331 ++++++------ src/cx/fbn/nevernote/NeverNote.java | 1360 +++- src/cx/fbn/nevernote/dialog/ConfigDialog.java | 38 +- .../nevernote/dialog/ConfigRensoNoteListPage.java | 285 + src/cx/fbn/nevernote/dialog/LogFileDialog.java | 2 +- .../fbn/nevernote/dialog/NoteQuickLinkDialog.java | 370 +- src/cx/fbn/nevernote/dialog/OnlineNoteHistory.java | 337 +- src/cx/fbn/nevernote/gui/BrowserWindow.java | 7017 ++++++++++---------- src/cx/fbn/nevernote/gui/ExternalBrowse.java | 340 +- src/cx/fbn/nevernote/gui/MainMenuBar.java | 1843 ++--- src/cx/fbn/nevernote/gui/NoteTableContextMenu.java | 55 + src/cx/fbn/nevernote/gui/RensoNoteList.java | 289 + src/cx/fbn/nevernote/gui/RensoNoteListItem.java | 168 + src/cx/fbn/nevernote/gui/ShortcutKeys.java | 11 + src/cx/fbn/nevernote/gui/TabBrowse.java | 149 + src/cx/fbn/nevernote/gui/TabBrowserBar.java | 27 + src/cx/fbn/nevernote/gui/TabBrowserWidget.java | 28 + src/cx/fbn/nevernote/gui/TableView.java | 1187 ++-- src/cx/fbn/nevernote/gui/TrashTreeWidget.java | 5 + src/cx/fbn/nevernote/icons/appearance.jpg | Bin 3696 -> 0 bytes src/cx/fbn/nevernote/icons/appearance.png | Bin 0 -> 3298 bytes src/cx/fbn/nevernote/icons/debug.jpg | Bin 1384 -> 2885 bytes src/cx/fbn/nevernote/icons/rensoNoteList.png | Bin 0 -> 9557 bytes src/cx/fbn/nevernote/icons/splash_logo.png | Bin 17907 -> 29727 bytes src/cx/fbn/nevernote/icons/star.png | Bin 0 -> 4105 bytes .../nevernote/neighbornote/ClipBoardObserver.java | 37 + src/cx/fbn/nevernote/oauth/OAuthWindow.java | 8 +- src/cx/fbn/nevernote/sql/DatabaseConnection.java | 72 +- src/cx/fbn/nevernote/sql/ExcludedTable.java | 157 + src/cx/fbn/nevernote/sql/HistoryTable.java | 284 + src/cx/fbn/nevernote/sql/NoteTable.java | 3461 +++++----- src/cx/fbn/nevernote/sql/StaredTable.java | 172 + src/cx/fbn/nevernote/threads/CounterRunner.java | 643 +- src/cx/fbn/nevernote/threads/IndexRunner.java | 1479 ++--- src/cx/fbn/nevernote/threads/SaveRunner.java | 374 +- src/cx/fbn/nevernote/threads/SyncRunner.java | 4189 ++++++------ src/cx/fbn/nevernote/threads/ThumbnailRunner.java | 469 +- src/cx/fbn/nevernote/utilities/ListManager.java | 2570 +++---- uninstall.sh | 4 +- 60 files changed, 17781 insertions(+), 14334 deletions(-) delete mode 100644 README.txt mode change 100755 => 100644 build.xml mode change 100755 => 100644 install.sh rename nixnote-osx => neighbornote-osx (56%) rename nixnote.bat => neighbornote.bat (54%) rename nixnote.desktop => neighbornote.desktop.desktop (53%) mode change 100755 => 100644 create mode 100644 neighbornote.ico create mode 100644 neighbornote.png rename nixnote.pro => neighbornote.pro (100%) rename nixnote.sh => neighbornote.sh (54%) mode change 100755 => 100644 create mode 100644 neighbornote_path.sh delete mode 100644 nixnote.ico delete mode 100644 nixnote.png delete mode 100755 nixnote_path.sh create mode 100644 src/cx/fbn/nevernote/dialog/ConfigRensoNoteListPage.java create mode 100644 src/cx/fbn/nevernote/gui/NoteTableContextMenu.java create mode 100644 src/cx/fbn/nevernote/gui/RensoNoteList.java create mode 100644 src/cx/fbn/nevernote/gui/RensoNoteListItem.java create mode 100644 src/cx/fbn/nevernote/gui/TabBrowse.java create mode 100644 src/cx/fbn/nevernote/gui/TabBrowserBar.java create mode 100644 src/cx/fbn/nevernote/gui/TabBrowserWidget.java delete mode 100644 src/cx/fbn/nevernote/icons/appearance.jpg create mode 100644 src/cx/fbn/nevernote/icons/appearance.png create mode 100644 src/cx/fbn/nevernote/icons/rensoNoteList.png create mode 100644 src/cx/fbn/nevernote/icons/star.png create mode 100644 src/cx/fbn/nevernote/neighbornote/ClipBoardObserver.java create mode 100644 src/cx/fbn/nevernote/sql/ExcludedTable.java create mode 100644 src/cx/fbn/nevernote/sql/HistoryTable.java create mode 100644 src/cx/fbn/nevernote/sql/StaredTable.java mode change 100755 => 100644 uninstall.sh diff --git a/.classpath b/.classpath index 4472bf0..77ad830 100644 --- a/.classpath +++ b/.classpath @@ -1,32 +1,32 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.gitignore b/.gitignore index 6c3ab6e..01b5b21 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,6 @@ #Local platform binaries /lib/*.dll + +#ini file +NeighborNote.ini diff --git a/.project b/.project index 3a0dc3c..a71896b 100644 --- a/.project +++ b/.project @@ -1,6 +1,6 @@ - NixNote + NeighborNote diff --git a/README.txt b/README.txt deleted file mode 100644 index d6fdbf8..0000000 --- a/README.txt +++ /dev/null @@ -1,29 +0,0 @@ -NixNote:: Evernote client clone for Linux, Mac OS X and Windows - - Copyright 2009-2012, Randy Baumgarte - Licensed under GNU General Public Lisence version 2 - -This is an incomplete clone of Evernote designed to run on Linux. -It is written in Java so it will also run on other platforms as well but the primary focus has been to try -and get a usable environment for Linux. While this is designed to work with Evernote, it is in no way -connected with or supported by Evernote. Any problems you encounter will not be corrected by them -and, since this is GPL software, you are using this software at your own risk. - -See release.txt for details of what works and what doesn't work. - -People have used this with both 64 & 32 bit versions of Linux as well as OpenJDK & Sun's Java -and (so far) have not encountered any problems with these different environments. - -Documents: - -release.txt: Includes new features, known bugs and limitations. - -changelog.txt: ChangeLog and development history -install.txt: Build and install instructions -credit.txt: Credit of nevernote developers -gpl.txt: License description of GPL v2. -license.txt: Legal notices for licenses and trademarks - -shortcut_howto.txt: How-to document to setup shortcut keys. -shurtcut_sample.txt: Its configuration sample - diff --git a/build.xml b/build.xml old mode 100755 new mode 100644 index 2dca043..d9e0187 --- a/build.xml +++ b/build.xml @@ -1,7 +1,7 @@ - + @@ -29,18 +29,18 @@ - + - - + + - + @@ -236,7 +236,7 @@ - + diff --git a/install.sh b/install.sh old mode 100755 new mode 100644 index 8eb41d0..77024a3 --- a/install.sh +++ b/install.sh @@ -7,8 +7,8 @@ if [ "$(id -u)" != "0" ]; then exit 1 fi -cp $package_dir/usr/share/applications/nixnote.desktop /usr/share/applications/nixnote.desktop -mkdir /usr/share/nixnote -cp -r $package_dir/usr/share/nixnote/* /usr/share/nixnote/ +cp $package_dir/usr/share/applications/neighbornote.desktop /usr/share/applications/neighbornote.desktop +mkdir /usr/share/neighbornote +cp -r $package_dir/usr/share/neighbornote/* /usr/share/neighbornote/ echo "Install complete" diff --git a/install.txt b/install.txt index 9c8c788..b7b7efe 100644 --- a/install.txt +++ b/install.txt @@ -1,4 +1,4 @@ -Welcome to NixNote. +Welcome to Neighbornote. This is a very basic clone of Evernote designed to run on Linux. It is written in Java so it will also run on other platforms as well but the primary focus has been to try @@ -73,7 +73,7 @@ Only i386 & amd64 are currently supported. This is due to the fact that Qt Jamb -- NOTE: I don't have OS-X so I can't verify the stability or usability of this under OS-X 1.) Download the Mac install version. 2.) Run the install program. -3.) Run nixnote.sh from the installation directory. +3.) Run neighbornote.sh from the installation directory. @@ -83,7 +83,7 @@ Only i386 & amd64 are currently supported. This is due to the fact that Qt Jamb ===================== There are additional options if you wish to run multiple copies under the same userid and options which impact how Java works. These settings are optional and, depending upon your needs, you probably don't need to touch them. -To run under multiple IDs, you need to pass a parameter NN_NAME="" to the nixnote.sh shell script where is whatever name you want to identify this instance as. For example, ./nixnote.sh NN_NAME="test" will create a separate database called "test". Anything you put in there will be separate from the default NeverNote database, so the username can also be different. +To run under multiple IDs, you need to pass a parameter NN_NAME="" to the neighbornote.sh shell script where is whatever name you want to identify this instance as. For example, ./nixnote.sh NN_NAME="test" will create a separate database called "test". Anything you put in there will be separate from the default NeverNote database, so the username can also be different. diff --git a/license.html b/license.html index a6321b0..594fe15 100644 --- a/license.html +++ b/license.html @@ -1,11 +1,11 @@ -NixNote 1.0 +NeighborNote 1.0

-NixNote is licensed under the Gnu Public License (GPL) version 2. +NeighborNote is licensed under the Gnu Public License (GPL) version 2.

-Evernote is Copyright © 2000-2010 Evernote Corporation.All rights reserved. +Evernote is Copyright © 2000-2010 Evernote Corporation.All rights reserved.

Qt and Jambi the licensed property of Nokia Corporation and/or its subsidiaries. Nokia, Qt and their respective logos are trademarks of Nokia Corporation in Finland and/or other countries worldwide.

diff --git a/nixnote-osx b/neighbornote-osx similarity index 56% rename from nixnote-osx rename to neighbornote-osx index 18a1cd9..78fcadf 100644 --- a/nixnote-osx +++ b/neighbornote-osx @@ -1,7 +1,7 @@ #! /bin/sh ########################################### -# NixNote Startup script for OS-X +# NeighborNote Startup script for OS-X ########################################### @@ -13,8 +13,8 @@ eval $1 # The ones below are examples only. # ########################################### -NIXNOTE=$(cd `dirname $0` && pwd) -# NIXNOTE=/usr/share/nixnote +NEIGHBORNOTE=$(cd `dirname $0` && pwd) +# NEIGHBORNOTE=/usr/share/neighbornote ######################################## # Memory settings. These can be tuned # @@ -54,7 +54,7 @@ NN_GC_OPT=-Xincgc ######################################## # This next variable is optional. It # # is only needed if you want to run # -# multiple copies of NixNote under # +# multiple copies of NeighborNote under # # the same Linux user id. Each # # additional copy (after the first) # # should have a unique name. This # @@ -84,40 +84,40 @@ done ##################### # Setup environment # ##################### -NN_CLASSPATH=$NIXNOTE/nixnote.jar - -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/apache-mime4j-0.6.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/commons-codec-1.5.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/commons-compress-1.2.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/commons-lang3-3.0.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/commons-logging-1.1.1.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/evernote-api-1.20.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/h2-1.3.158.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/httpclient-4.1.1.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/httpcore-4.1.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/httpmime-4.1.1.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/jaxen-1.1.3.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/jazzy.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/jtidy-r938.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/libthrift.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/log4j-1.2.14.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/pdfbox-app-1.6.0.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/poi-3.7-20101029.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/poi-ooxml-3.7.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/poi-ooxml-schemas-3.7-20101029.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/poi-scratchpad-3.7-20101029.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/scribe-1.3.0.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/tika.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/xmlbeans-2.3.0.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/xsdlib-20060615.jar - -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/qtjambi-macosx-4.5.2_01.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/qtjambi-macosx-gcc-4.5.2_01.jar +NN_CLASSPATH=$NEIGHBORNOTE/neighbornote.jar + +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/apache-mime4j-0.6.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/commons-codec-1.5.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/commons-compress-1.2.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/commons-lang3-3.0.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/commons-logging-1.1.1.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/evernote-api-1.20.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/h2-1.3.158.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/httpclient-4.1.1.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/httpcore-4.1.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/httpmime-4.1.1.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/jaxen-1.1.3.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/jazzy.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/jtidy-r938.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/libthrift.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/log4j-1.2.14.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/pdfbox-app-1.6.0.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/poi-3.7-20101029.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/poi-ooxml-3.7.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/poi-ooxml-schemas-3.7-20101029.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/poi-scratchpad-3.7-20101029.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/scribe-1.3.0.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/tika.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/xmlbeans-2.3.0.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/xsdlib-20060615.jar + +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/qtjambi-macosx-4.5.2_01.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/qtjambi-macosx-gcc-4.5.2_01.jar ################### # Run the program # ################### -cd $NIXNOTE +cd $NEIGHBORNOTE java -Xmx$NN_XMX -Xms$NN_XMS -XX:NewRatio=$NN_NEW_RATIO $NN_GC_OPT $NN_DEBUG -classpath $NN_CLASSPATH cx.fbn.nevernote.NeverNote --sync-only=$NN_SYNCONLY --home=$NN_HOME --name=$NN_NAME -XstartOnFirstThread -d32 -client diff --git a/nixnote.bat b/neighbornote.bat similarity index 54% rename from nixnote.bat rename to neighbornote.bat index c2a79f0..6893c6e 100755 --- a/nixnote.bat +++ b/neighbornote.bat @@ -2,7 +2,7 @@ rem ##################### rem # Install variables # rem ##################### -set NIXNOTE=%~dp0 +set NEIGHBORNOTE=%~dp0 rem ######################################## rem # Memory settings. These can be tuned # @@ -42,7 +42,7 @@ rem set NN_DEBUG=-verbose:gc rem ######################################## rem # This next variable is optional. It # rem # is only needed if you want to run # -rem # multiple copies of NixNote under # +rem # multiple copies of NeighborNote under# rem # the same user id. Each # rem # additional copy (after the first) # rem # should have a unique name. This # @@ -77,37 +77,37 @@ GOTO Loop rem ##################### rem # Setup environment # rem ##################### -set NN_CLASSPATH=%NIXNOTE%nixnote.jar - -set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\apache-mime4j-0.6.jar -set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\commons-codec-1.5.jar -set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\commons-compress-1.2.jar -set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\commons-lang3-3.0.jar -set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\commons-logging-1.1.1.jar -set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\evernote-api-1.20.jar -set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\h2-1.3.158.jar -set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\httpclient-4.1.1.jar -set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\httpcore-4.1.jar -set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\httpmime-4.1.1.jar -set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\jaxen-1.1.3.jar -set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\jazzy.jar -set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\jtidy-r938.jar -set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\libthrift.jar -set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\log4j-1.2.14.jar -set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\pdfbox-app-1.6.0.jar -set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\poi-3.7-20101029.jar -set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\poi-ooxml-3.7.jar -set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\poi-ooxml-schemas-3.7-20101029.jar -set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\poi-scratchpad-3.7-20101029.jar -set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\scribe-1.3.0.jar -set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\tika.jar -set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\xmlbeans-2.3.0.jar -set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\xsdlib-20060615.jar - -if exist "%NIXNOTE%lib\qtjambi-win32-4.5.2_01.jar" set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\qtjambi-win32-4.5.2_01.jar -if exist "%NIXNOTE%lib\qtjambi-win32-msvc2005-4.5.2_01.jar" set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\qtjambi-win32-msvc2005-4.5.2_01.jar -if exist "%NIXNOTE%lib\qtjambi-win64-4.5.2_01.jar" set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\qtjambi-win64-4.5.2_01.jar -if exist "%NIXNOTE%lib\qtjambi-win64-msvc2005x64-4.5.2_01.jar" set NN_CLASSPATH=%NN_CLASSPATH%;%NIXNOTE%lib\qtjambi-win64-msvc2005x64-4.5.2_01.jar +set NN_CLASSPATH=%NEIGHBORNOTE%neighbornote.jar + +set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\apache-mime4j-0.6.jar +set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\commons-codec-1.5.jar +set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\commons-compress-1.2.jar +set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\commons-lang3-3.0.jar +set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\commons-logging-1.1.1.jar +set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\evernote-api-1.20.jar +set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\h2-1.3.158.jar +set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\httpclient-4.1.1.jar +set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\httpcore-4.1.jar +set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\httpmime-4.1.1.jar +set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\jaxen-1.1.3.jar +set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\jazzy.jar +set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\jtidy-r938.jar +set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\libthrift.jar +set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\log4j-1.2.14.jar +set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\pdfbox-app-1.6.0.jar +set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\poi-3.7-20101029.jar +set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\poi-ooxml-3.7.jar +set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\poi-ooxml-schemas-3.7-20101029.jar +set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\poi-scratchpad-3.7-20101029.jar +set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\scribe-1.3.0.jar +set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\tika.jar +set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\xmlbeans-2.3.0.jar +set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\xsdlib-20060615.jar + +if exist "%NEIGHBORNOTE%lib\qtjambi-win32-4.5.2_01.jar" set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\qtjambi-win32-4.5.2_01.jar +if exist "%NEIGHBORNOTE%lib\qtjambi-win32-msvc2005-4.5.2_01.jar" set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\qtjambi-win32-msvc2005-4.5.2_01.jar +if exist "%NEIGHBORNOTE%lib\qtjambi-win64-4.5.2_01.jar" set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\qtjambi-win64-4.5.2_01.jar +if exist "%NEIGHBORNOTE%lib\qtjambi-win64-msvc2005x64-4.5.2_01.jar" set NN_CLASSPATH=%NN_CLASSPATH%;%NEIGHBORNOTE%lib\qtjambi-win64-msvc2005x64-4.5.2_01.jar rem set NN_CLASSPATH="%NN_CLASSPATH%" diff --git a/nixnote.desktop b/neighbornote.desktop.desktop old mode 100755 new mode 100644 similarity index 53% rename from nixnote.desktop rename to neighbornote.desktop.desktop index 496cafe..4a00ef5 --- a/nixnote.desktop +++ b/neighbornote.desktop.desktop @@ -1,10 +1,12 @@ + [Desktop Entry] -Name=NixNote +Name=NeighborNote Comment=Use with Evernote to remember everything GenericName=Evernote-clone -Exec=/usr/share/nixnote/nixnote.sh -Icon=/usr/share/nixnote/nixnote.png +Exec=/usr/share/neighbornote/neighbornote.sh +Icon=/usr/share/neighbornote/neighbornote.png StartupNotify=true Terminal=false Type=Application Categories=Network; +Name[ja_JP]=neighbornote.desktop diff --git a/neighbornote.ico b/neighbornote.ico new file mode 100644 index 0000000000000000000000000000000000000000..17fc15b4aff176078bfbf55bbeb39bb3745e50d3 GIT binary patch literal 16452 zcmW+;1z1yG8^0SH3`V!)K$J$1?jb3Sv@}T9=n!F}6(mIIMhR)@5GGPehrnM_=?T0W!5HS$piX@NKl%D+S#T}zC zeB60My7L;q5kFQ^FbK@v%?Ze+`SD+0=LoGeChEhhC)2dg-Nu{>_4MpOwr{4psY$fF z6u22)-J=ZF`^esFGRAe{AtK~&TU~37XS3P%_5)we<&BWf{&0@;YBqNpe9%*Fz3%zG z?4N8$?eig@pFSM#)RU3S57ilfT{j!6f!kUAyZW6%%Pja;WHZju%vgVGeqCoc&Dx?p zma#0kjHKbzfbhhKda?n0Oz}`1A_0>iJQG3*ijuT{7}*`*zct1Sa^R{DSp?54D)x%q zx#tOtfJZ*46nBgTqalRUY%ig}L-kBNPTh$mo$k(pwgMi}hlaM_-QgAS$R1Dh`rtvZ z%QF`<$U`cQnM)W_+V>y*hd4VgkX6EL*xQ2VZzLYx!{pGIE z!pQhHckSPr^A@e}$9DvhnZ3Q=y?8dUnZ%IslhEz8P|jUU7H0q1TVg>1E-DV)UJqFq zSJ8Vm6vHUV2B~kOGIzrZOB1*YMgedgx-G{<3zamnqTqt&D&LYO`zP&$O46*!zIdnt zLD9}(ETa}nZuw=ZfBC>kFc`A->*UN)m}qZln0x-+gVOjn->?nE&^HJSuRk2z&&pqk ziBmh27Q){(XcI8icL&42CIoUNP>a=eSCeLNv`+poTWv*$vGpe=Si4v z?Q2P)!g`Y!o{dKx*dUjN|7IRaZn`m#ws^l$r$P#vq&zh7qCE&*;5uKeN-ooRbU)9U zO!+edgpWQa%~()sKR$dcC;-GOSlrfHfHe5cbi$465b6t9sBtYqe$X)Q-lbeeKX-ak zly0!>-AQ4t)GVLkjYVK@*IvJg15>Mpe+G`bz+6l@#=w>3l2p85fLnauSUCITmt z+KzXkt$@Ijzm?456t6L1D~ZEqZGWOI9`Gz=T0c<8c?yuItka0m=S-_wcVIt*2~_{C z)phyZN4%;xe`Ke@@I&sx`7T;62uwyDKfFz;a71{5n0yHxMfqCd<)>jqSG4DquN{W( zz=*jQD8zEIOm0SMfkFhx;(h#wp+vg)VdiiBvX8h|0;+y3kRfY`ZcHOG?a zcLAqQ@6!MN#0Oxah>Rk{+>SoA0zyw2S}&OIq8yiEG;8__rufh*c1KxwVRX%cmud8i zF<|bP3}89$t*ncPU^h=9X!6SrcAqhR_|kipq^&nvQ|b!~`e`ljs&|Ez^Pm75<@Nd3 z9D>vWQ1sVK8{k9Fj)rzmCAj1!c;GyL%ig~LX_K_&MEBYq5fEJ&Ti=owyQW+3gZU_D zXoNSLiNU>r&Vmt=c#c_39JiG&2Ck2S`Ea*5M?GB=q^Xb#VpzR#aqTLcE>#psdV*M%QH(Fc>Kl3xt4SsALr0_5Yzv05 zi?W5gJPavT3BNKnTxS=fvTi>KYv&OV+A6(=jQYBLamG$ah=rnDx(+*!pIEcPsE@T2 zK*!~5fDmE+Nd@!W`J~g?q!E%47=U;Y@hm zt6$xpxOg%wbv+Sa$#T%O7&J;{3SoVb_w|sIJ-JA7_|Fkpe4D+*1SF!doaj(# z!MQhM&)h-@DAYAYf7-hJ-byv9_?CWkP7m?AEbiPf|CnbGEYmYp(o&2y^$LIH>^`v zysBJUa_rFXt0zfe@Q0n7GvRDneYBIQeeWS+ko)L2UQr*y+d0$*<{l+{_|!tAi%0}h zNEP=~bcXf`P|!xPv9LbV!kb#g-y!Ppt+>9u3*HE-!5Uyb^w`1o_*l$PA&`%pqeukU zNvNs@xuk%Z8itk|lN7ee=<_tlMhA-{^L!uT6|fsje`;7R_GV&>14Jh4ieMWg?Zz^V zOFw?sLLFn0-XZZ6_|aqZCF{+FsXY0lhtDX`2)G?bPWu}#sIr6HGgII@io!gx)uaub z2+DlT-;YNcSIQK2|G>7c7P>FWXm(JJ^FaM4ehf=JVg71!moOx{??>#{F2%-y;`|x4 zz8!ouKmVPlwf^C&Wh|S6R$$ODZ%_gO3!a>(SYy6Xaq6jx69uyTFsf3y zStn8^2Rx-<-px*`j}c1Irb7EoyD##{WhJuTXNgI#O-gXQm3PB`x;27f=NL$`3*Qr2 zvY?OAby7%!6o&6k);*aWF|GPyi+&-bJA4j3c5BFc@`^UcT^Kk?*JEq2o%fS|0^D0B zBEtNcwrE=Z*5AFqs@n)WP4q-XA?ClP7q+tTxuvQNdoM{`jM1KXz+MUO+YU@*lKbN$ zg<|d3i|g@&3ZI$(s>cO!YI%wZ5=jZFzq7cchGDcIQrjNqxlnumtV^!4kIrG?dwKP| zC3g**%J{dRWaQgRInlo@>Iz~oML-8Gq zMY8JPD0P|0LM-pzLBs=4J@eucalY$?kCG?(E;(&+_LJFwOkvQ|G(UNyAL`rjLmk(_ zuwUdtv`>4K#RmAC8yYsp!09A>|M;}x_@vN8WggrED0=%G8eJv_V|hO30JPm|Qn`+J z-AYnV-%>nMU%CkcOvFhWyvj7(mFamO1>qu?^7Qos&0-RoUyp&^`yyvi*q1`0f#c_~kYz@t|D0c6DhrYJ1ELIG)cf1 z<>lWTCo@vMMd@wkmkm_G8YpVURpw*Tv=13Kw{lbrA~XeYvX3IChEolvJkkkiNdsDY3>%$d_)d4(t0K^$Wcsjp5R0>Phr(wGinb1H zB^;%E!CLvf$O;=AwMh;p*V)igc!jbc+z@!)v|-!x2|Nlt`NOy~fxeM)oUVi`HHYO9 zk{r#i?6~){p-HJ2Svc96{G+4%GlL=eneS5VAJ@2qzj{x#2`V^TEjzJi1MKh-M8CaW zzGFlCQ!!A(-YOx*I%%5A=Ogj;o^5+1GJ(lge%HJc41e^hF8S?GIY)P*C#1g_-=>1g z@0;kfnhc~`)%iuO)>TuH2mGg==7*o(fS^on@F6^CiiEgDpqV+vc!1FLsqEiF{6Bt4 z1aNJoO+ZK0*a=uJOxu90Id!wqU-Kx zeq|@RzL|ucpJS#FY7X<3#mHzX_WtpCT2opyjIMm4bk((klu7h^VLv%?{qgHe zJXr%zV%_utiZ0)VLc5ZeuaD>wXFg5DH^IJkT5P1easL){hKCwXI%D+rh?aOZ=3*@% z==d$Ra)0f{4e8zY^5^IM{^f9UM1O~direR|@pW%mp+kI1M3+rD;3$CQ^hUEZ|=!LrE>)MQ00gi&MeVe#T&4Df=rIY7GpZ`I4} z=g3lgm$JBHT0w$9r^8r&*Lilo%$W_}c!fGuob;pSbHB3a=vRvlHg@N+{ERNYGE3Q)V>uBasT?EJGTX40>Z!T84s#nw^ zTQX&O3x&VT{3)!tQOI$B%GC%sQOKB0VFhSd7)Ozid+mO!A7iSgJLBwfqK8#EIMiL;v=PGKO7{*$Hw z6#y7!3QZRJ->TS;w`}Ch)6o^d$rW=n13(qSN(^8hX)U)&8=Q0W@9NaD6adJ0(fQXt zp(MIk(88cT9r5fH{y#k+COSOR5gvihk`rFsx5l(m^NX;7!7!)Y9l#Rn^j9ZLK4ieC z>9SSRrJih5Bmcod(Iw;HSrGV6Scs52WS|ykXW#BB^!dQu)J?05=FYhzasXZ#}u&lBLIZnz4hzQ9Jn zV?4`HaRx5!yCYx$D!UWTfq^Ow{|fQj#y(r-Zjr_mzsTkp2M~Kji8d{oCIWMk!ztPt zm`w0;uSzWu^z7o+Pf*v9)$f}6FARYmZYc+eMsXQo?=K0%=t&OW;@tvkeDodX8r88M zQeK@vgCqVzTbp})z9o?Kdj5V0&~MIY_kuSbmg#{S@fmDnMf(7ALSX4pzD3&O*P(~k zsM9aw^Ayf-!~uYa6gc4nlb>;9OWfP>!I{;&NHUx4kv@Q~q<q!lE&G8#X~zCc&0c*-_PevQh3oih|?+wIFhGn{_~~ucpEd zD(ta)V~O~bNV)zx7_y4gXbjC?T4H1rSLX7+(3>6f<|DM?zGRYV z@hY#5G0gHPUI{Da7-3X=LrOo7)?~vy@H-&+rvL4fgUlcz7RI0y3_%BTV^E86Hy$V5 zD&D&7-`x?sqr1Vpp7kL{=6FfGN_e6XXt@EjtnzdDt48Qo@sdggc{t+rHJa`;&%pO6 z{8!ch&3;)ER}$cO-SP2@Xi@f{!iW)kmWkPf=_nX2-mHmLAD z&ny3#HEv5U(roid!ey;RMi(QgOlMWh4mT1S$&pJu_Oe$S%M>Ud^4e2Ts28C2+XLF0 zZ&wQQ1n3)sw5;d1Kt$d2W5>#a<<}1(*5A*l4Z$#NsTN_7RR812!*8-;5a-p+8v-ql z_I>fMAL|zW70rRNKSB#9>*QZT@yV{mOm2*MvdFvZPG)Vg#LZT?s=<>L@OJ2;oUEusr4x=$UY5|u1xW;YFAE^8 zFqVj?wC1o|qHPdq=3KMFd!r(f;?NTk$?uT-jFL@m?Ak>W81)O25-0G_dR6e8*@JvH z5Co%Q?~_RspXJMBjHj}L=6EB3emN0_vRlsKZYKW42kzL#TP;iG-t0IEMf`MjebeGj zp?e{N?x%Bo-v)fV4&xmB2P)o0(pmFO)`pt`q|(X6H{;XN0(0kCe&9m}Aj)rUBW_2B z^Dm)2Sa-CIn5#U(kHOj1G2%RI@0Fe?g%rvXTFR}=rbFWZgnXz6-M6hMoZC$z*oi^A zpcch=FACONd}dy2J#@%LEE0ZtJTa0LRPD_r_qVtA4&ARmF-Fz2G0R0E-{29y0q`GAOB^NU8Z0`LePkQb+JydS|SepBm^It5=Lq@FglA4qs> zN_NmQs?|m=r_VcxeXm&cT+oz0($|~y9+j;Rym%HZ>gx}820JlDEacg_iF=&>7~RTy zAzFWtCno!VvY9tJID-XGu$_c}jssRl+EMHEKBA@p(=G`8hzAXl#KY8zB<-l}#Y7S5 zC28Z52)}2Q&Yf+Y$Sv9IK+X1*JbVv3shW{X{ngP%i-$i(UHU@*8Y`Ahhl$p=CSuRQ zuIv@%n?h(!I)u^<6Yr>wwD1;vki;(7K&hLC&yfjPCm69|>=IY~LM=8iRMY|}cxs3w zw%}XT_~kr4f!6Z_SyD*Y+>CCOtdaT2OaFLvu2`PeH^cdRs}D;eAoa`)`1Q3}k#GL{ zJSd3LGjF&WWAaOaYAF)t$KCMF?;gNxvR6k6_V{=#^MgF!dY7ISt+otPbHpIzZ@rxw zPS`VX{5okR9use~xpmn4gQNL>E;v6L z3NobNY)QBIoS~gu66(@*KUBzf!vA&OKv$Y#Ij{0c6Ze{epg$^-Os#?yOrbp+U@}3_lpCyNmm~88*yL+*3f=$93p3^un zBl$(#e#i{@g4jnN{O!tkaMQktx8$inU29-w$BPQ4MPv%3!X94MFlO!0u9G?R0$YWJ zk_L@C9_WL|S}W$`FVTTg%%UHhL$$pBs{<%Zq#J(Uk%$aUKqWK&5LxOPxovm0fVi+9 zXv1V1UmUJ$WxPgWjwY|8S=mJicBUM=AL8fZ&3=|Ni?H)RM45;Uhg__`<ImUqnc< zjq;(@{L%$dwL5x~9Sa3XN@M$(Two#8zk@1-NjuCic>Sy|&a|{nNUoEFijdZvja1=V zSbh_R0wW0ioV4z%9_42GW#CIdp8eecu}BNK6-P_jc9!GKe#C` zXq!uiMp&IG;wv9gub=xHt?K+_eM{IBH=9m8IfrKjBwv)I6cd-wT=sYxt78oBr%EQ- zgRVb)kd0UH5dN(J=y;dTNZR7bQE7pZJAx&oljFsx27M!^{{J|KI z9;_zIjSFtl;f(1G=pN+e{f$FWVHw;O` zqVp%lu2>|ef{iBvca=3<@?_g~xezIRqV+i<+5;!!0$xc_30--a-_9Z(t?5OCnTw2> zl-4JdYj*kSkGW@)_ch!%??1nL*8Hok^y6iR1YF}1kH+r=?@Siw4r}j9IH*s^+b{*K zN!G0WG5Eo1_1P=xPPNF#5JPNyQHcmi`?&z=3Z|XasayWp0WuYOuwckI_43dtp-%7Z z(+O&eTQq4+zX$l>iy>p9dVQ+$sJhd%&OOK;coH&gRrN2Vb9N=PW+j?FsGZ5*Dt+4g z9a>6zV_C0!E5b64XbLp={cEM*=GANu{Z|MFHRzItX&OHUQ)>@U71K1;@o;yQ2vO+_ z7w5wmKTLTq)x_$0+Jj?}O^ZbBK68_{eLi;*vYyTh#E@xe8%N$7TA!7?dk+hD7q zubKq8HI%&UOsDc^+-fp~Xrq-~FjK@wVAcg`IBl)|RZoFgmBuuahwi!Xmk8fnR2>xPWiJ5=&}rxCjS;L?0B zc^-{m{%o<=L<%-KFQH5Kbt`}Jq2c?4^BZmTK~sQ2U3A+~Sw;AlOMFhf!XIjkYnVtw zbF%GNcX&Lboq`I{(MykCWm%Ojf_6<3LBVwupC>7QX`m2C8oHXT= z{o}^VhCYDWItK)sgx1W-KS}zS^q`-DQ`439=Z|3BXUxwI)|NhwK((pQ3Q2j*7`|JE zd%Y|73mS$**7#TOc8Z;EYf`^28Xr312L?ur;MN-P$5?HF?=j&QYtC9QDQN5rY$=Cr zn-|*K{4DQd=x(>fNu_p@&zo;q5#_Y8zx>am=ouP#nf4N2+{Z>gnRQ(Jf!_O6SA~p; zh~!{?@wrEMQWKA8mi=yyd4r-a=xsz1G#|#PdSBe`tP)lricb!Kv%l;xys8@pvM0{%9)cxWI~1>Ogkz;8?-%0g-n-Vn0gg ziJ$d?zV}xA+OGTJx(5mAVRX%BeyN;?ML`|+YNMpcid;aDAbq9ul9L)W>qewF#^?{e zagMwv>PMx=>&3Tq{G`{KCVha+;H~cTdaqAE2;_PI<<#-?$3*NYqAi*?cdQ7^;!u_~ zZgA2M6Pi|x^&Z?P+Jl6!9ksZ@M$u*m9pq&9U0p8P?cc8z3|+h3ziT9#yBL8#4uiSm zGyw`}=mI%C8)^lIfYx@&=8w0yLhf@P)DMTAke_R;yfvXy_xdoGw=5=to+!hg{O5^( z{|>i$oPYbf)-(0|Mmq4iFMN)=aL8PDBBR89|-$+ zysO!xcQI+!>xI)HRPWxbvYXR_<$V+Pw$&L?i^T7*Q;AQWR(8+G-!dKi-j4WKe|41i z@N*FND2d5g@6ty{A%1ka^(OdPfTW-KkLMewn0v$D7}$56$l?jA>R*J(9+<_;k~|gk zle^`d$f6t4=UC>-Z=gN@p|Jf?TU>3)0_(M1OeAu3I_n7Tz;6V+Dsy?DmJJ~%Y{0$o zZ<$b7g( zBo7k+C7PbO4_I(X1eV~_+s(ggr=60`Ja#lAjOGo$OD3{(fL`ciHDND)X&-o@nq+qf zR!#iW*zaQS4Tj$H9g@@%piolNgzobLhjW8!7;Tf zA~9Ov2R0&S>q7!r4@1R@-rqrqjanrAK`|X@xr^(IJ{P|P0M^ZadjW>o(dd}k=7L@@ zd7gr!^32~$tic-BCw}3+eiZ}b6;Kn-spnpv#8p3SUdq!n6JNhpalU$Up$P!h#O9~J z?+9z;LbCA{C-aT&W;=l8*bpEta-A~%P$#gO!i}@AIzxw))4Wm0T)6XZX_tkg>Wrgz zUO(gCTw^@AH%PCDm(xYa`WtsT*En;Ou5Iq%k*5G5mCQOgHAb(7|GSzFOD{r~V;*ll zSfDp=SbckEC<2s@k}Sd@ccj(2mKQj zroggJRW#`F`sFl!rJ3E_1G&Bc-q*YDg^nig46z2i&^2_xj4?)hWRb$%GBBm_!Ygu` z>-vr&o~IZ2A89&HRnS<-K_14nQ{KlR?lCw09TiYimkd)4C3?!sM*E-?{h@ILemCgr zolDSEY$*jgE>u3)eo3m*QGQ-0(1SkX%2RJSE#{hkFTth7Asp3s|=6a(^C zfF(n-e;w9P&;C996F%4qS8JfZJTBrxx^iii9OHaaesB4K&|8B)ZovF!;0_`8m;YWo zpU${uH88~0hrxU8I`*@+_kAOGFQxaLV*uF*aKIrjQiG`}!L*!tp~z%!VZ zoElTXRwi_hyhB zX-!C4vyoOuW1<(irO1GXw*5PBmtnTHkVFu=VgE8kI<_+U$t~9yf+z1;7<8C;4B4KP z^3ryPP=bz~r{C@E&rmD1vnZX63Cy^alUUMsVaG-Za=U}7HY~T2v429D)W-DGm6l&m z{{1I+z#CF^@0GwZd8)Yrp*RfJ=f$NUs57P!#%d$Dhz$ne+KhqjbPt2Ekp$9`5x#HF zaj;oEW>lc?CkD`A7A^j{SYEw!Bhvdub#YAsUke$mup7x=PrLn#jBTJLM7i zdGIW5oR3!x)xnU84j83pzb@D)!2tO)&A0!#q&&&84A*c^Tx+I9>ibin!>n5T)0)p1 z28rHKaf~j2%tkqwpF6=1#<2};kPf0T)-xpG)n1dY&>Au>^;P*6xxAY`_x8osh(7c`Se4)!Q=`YxCb*(?taZK9s6AH z?z?P1pSVZ*$>&mCG>`k#0rxJsM3M(tVaz4Bw*4c&z;r|_Z9hby+&S64uNjgl05r@F z+-_<>BpmmD0i>S@w&MTZC47>}FC6b$qgfO9Jb7zwi~Kb=Lm?)x%iGHJ&!4p9jbsbs zPideSYLDbL?Z`yU7EWbD&KE}wR$ud%=12Xv=aHMqm$v*FN@#$t>c2x>!`cdiR zk3q46BtP%dy8xBlu9Z?!bqi!^g^7c?i!*%_za6!jxy#O{mpScESGGf~L^CErx;tQ= z!)X<*F?KjzQHdRsVU2aZ$$Q}wcY=N)C|MlhSCx|azV6Zw1mt$w4o!erm9sHD>x<*# zxon_z2ye`jEWQRW;FLAXB+~FX;h2RQmGX_t5<*zMBUM*5N7|BPxTVFugU#xvlGARx z?N*3)x8K80A$~1kryKyFpt6}&)lvE`0}y`ubKGcwW`lji1?2Y1U>X+bL_SOiJTPx@ zC|44caQUic{Z&%DDTGl%pH0W`Q54oOnpm<-tj#1cjr!OUrrP}o7_qFq;1-5{`8)S)*#Lk-#W|~PAu79$gTANo3y7#h7G)5Q5?+XZCPwY?^E0wDY1AJJeGeJJdh7g>6n8w566;n0Mu<(W z-(q8aX8aCS+{*=ir64($t@^8I(WHDw?6OQ8wyu3zjwJ|iU)CY}J#_5fx|p<~=Lu9! z?P(<}tK2JiJxO)Hr!A_+J$=Kg?+M$LG2 z?zU-*j3+<1e#uGn8860u#Hx19RljkW6e~43Bu{@EdAOJ#X+pTP2`bN{W#vWQ6``5! zFEzof<6k+`y!v%6`eMYJu<1s&37*f5pwv+P`^N7J;o9Q)%{jyVYSH-s?J?85ThCAQ z@zLZfcdR^S08-yB2UUod{!R=#GG5xu^sJxb|IbT;wrQUJ9g49yh)(E)fEG_i*4l52 zuI?#6IMn)eer=n^HzB7<)TGYcBJ;vr;9!TQeA+MXhYNI6Af5eJQJefLwAXivc@O6w zkCJ@;il9_AOK9A?aj$rQ5!rwqhE=Ncuk3pQfDUPCNHkx7X2AlD=`x^0V)A+3Kfb)(mmnoKN{+3_@x8sZ{q`R~&7-3ao`$=T z8AP~N{jg=?7*|XZ8?mTe6aRPmvR-9U*D=dq$>87i!SK|hss17(+66=21_cmZT%Rfc zt;wYF2~8|#;KkmEQ^A22t#<saQjkhYk^5dl*(Zt+@T?r zlfa-DX)A{iF`yfu5zEoRq5_UN1V!FE=|FZ!W#FTBM&(q{gm~Q?3;JQtKnLuWW7~+! zvBZJ&17*RBLmeOyZ(m;6+HWnnb>yS-U-k?Y&z?K;jt$?R<49+iA|{DI>1VtL@#;#6 z_}&}U9`5{!r`4LKzf~Rq0##os)J;d;O-EVBy+p7_3pvwIi`f5BA4u+MlzTxxxzI$9AIb_{t7Z&OVZCqwWZ8%R64yp91qb^ z*hQ9#f&<&bR_i)D8jdg1|MY{#ARFPU?tH}o`Sd(bCrcoAAl8hKzcu~_9SNkQcQ%qs z`YZ&?{T5R2cmi;RV|`@jQ+5_cCef>lZ=mwU>z)cDElgavn%`IuL8`O6kXlV;Vrc*< zRH)qW?zm_0*Y*dEs(<^p>td4uTUJQ@BkQ+&`6+mx{PE?cI=yLX9!7tu^2h1YfXjsb z@wO(BXvI%d*hd6y(T~}oD@`I50i{6pE$+vD66%7BH%HP6nJN;yfs6WhMq#dxTVle8 zH&+kBdNu^EK{37i7aS@Q6WpN&rH0_ZdYp}j{S5=-&I};lB(HRkl)wpLF@7t96U(2< zUoPs*8xwCgYQj*1&(8j)NXzsA+yFZM-#zdCvD+{pcGNf~Frw_ z1)^_wzaEyiVb!u^+|($iz66<;@oOF{8J@phL4VhzJ4nN|>PCJI*)u)BHQ*L8350rU zJ?XPG%g9P9>|J}B2kXQU%k^A;hyL+&ICubNZhSfP?KOSXf7iY@Xc`f%Te+mo!@R_7U5MlTVU*CnQ$ z2cy-V?(=F(i8kIn(X*`kR;C`8RsTYf5^J$|!(cPQj*c1NS)d4%vUU)mb@OzvQ~v2+ za>iz(!x?V{R0;uxxCdM5o8kLO>k1w<&feuN+K{%8dsfFLx8Fs3vv z#n2b7+qh+@;V7pT(D!kQf{dxWpo4bnI~W3x$ujo?b|%eAQ<+$Gy4R z5mRR0p`+L|i0kJd;152Nf5#V8A7&qwT%zCrcyox+Ng##W-s(C+0EFP93b~_6c%RLE zq#O-Jdw4nWG@P%)$$!>J^y2#|8$+p|>e8A7!((a=TlgwiKB&3kcPh^BA!N`OxFWN4 zYxH*>srTLVv9laCPpxyYm9}navP;RIUcqrHmO=vGSJ>8JZNS&v5?y?nxeG@)b=9}& z=!QKekdZ#rTkA0nS5xf1vHd?^eqhwi(!lr}EUlJ*4+}G!t)00rB|^piD#Vg#fv5v&q3zdQyQ_rgd4Mif^+fm+iHuI|C}~h zm0A6MLV>fs)$+!dV||lCT5;WC$W!cUxe=`5)z6CFRMIsGB;X@OnFoACy(@5tJ|P=F zt4udDstxfl?J@QnJFEPs!8OhSVKg&V)|nDa!!C+6f<2E@&jxSJ!cU0Nk23nkjkdD^ z;Ku9xV;EefI75h3Bm74t@Y=V~n}VfZ7zM+$-Iv^d;si*p1dQ#7slt7q^miI=dZYwafJQMviF@wqrGEsF4D1gf65{rE_{uRw z^T84=+A4DIHpF$9uKH$wvP6z0x^dT3zwvJ=rE0RymkqAz6Ak5EORcci{F#9oUR}AaAYg9V(_Ru4A#5jQsVxl3 zI~#&H4Uy8n%!@t{?J|RnfIfSV8^Zm5(`qVq`l4h;?RCCJq*Vvsei<;%5$G+<7Qy|~rUqH^uPu*BLvbKKDePbv@xsUAwLLkw zf71ca#=oanv|s`NJ{Ogmgy!sPH=(Rd!QU27YPWBp(aX3ETXNo`;yzRK=r-asUbH)Rd?(SKz z?1J<#){IjTN(qC*+@=c166SLZ04OzUN3Mq$ZLd|qsMl#QLSk;y))Ctx))pIUPyRbm z|FZ~ZA2(ED;PJ1O6Y-RyOa`Y3q<#h#dJiO?&26!q2!NX}KfRMi3P3Uls$}grPpvzi zgT3(**xXz{DZi|QFBL`OQr9|s03)Phs^6H56-Zc?GGssc5bI`KS~9R4*b%G&00CBw zwsp8P>urlcV2J>_+9%0eqHnVG3SMJVJv+OK7pvC5co^w^$VSLf3%I3Ec&>&_G7qQA z0q-tv_ZOx;R|O7F?Q0J^LV3k|4nvMJ0bsAytw#!z7uNzFiDvyP#`x~ujdw_~=I`K3 zo_hT(9dy$BA{7~_DQ#Pj1k$?d(H&39KY}_!`~bAw{>E?4);)PwLiP@HOBRP(XOXQc zEJ35@NCqMHOwM}|u(A2>>~_OyMu)X>T%TEcX9AFt2dWhagm~lP(022;=>-wG2w4`t zAhvuy1n#!I`RefqXQO4KZ2|pyyH4s3cNcOVn2%=GD~j*oH&K#$&~o{S<{NcB-ri=D zH`{^sMV-dYhs)cT*e;v*4$Pr_?R|-WQQxs!8wpMwum4`{2ADV6Hp3iW)(j3Zmt>%I z3|&9Z0`8gxa&6G8lER4vB8nhgdwgW19ZjEqM@PxxchP86S{iT$OQ17W#U0PD;8qK5nhhM=-KR3aF(`8H?kR=dCwfoC_26T-GDcM^F zVXA6!eKz2q=amx)?3`VG7%;xQ9$%${%{kv{Ex|F&!><)GXw4&T-nFz9!*!p($8(lk z&|8SFK%F4x{Qi4okKI1mA8McF>3!&{^a6j0KaRLl0Qm^;XvT55^*Zz5J!nYC4qU`$ z3@}07x>)=s^#AXDGu5EV%l-6YS^VE}j0gW&q*cx=te^O^qw1}kGXrPYe^z5SA^Gr^ z`!(bxT?Wd-^hkb+L^^)p=mckFt^Tdoi9qbH`rdD!G(7<+0GfvZGeYI+LQdx4~l;UNZW0ue~A~MFYdO#>+gJ#vlungNr*WR0zClr1mK}kd876>&VEO*1 zbMR+sdanwA0-AfFL)0jptG~{+mbkwoH1_8<#*mt0-xb=XVsG z5CrL|=onz3dU-mk&Ur@jzPpC4pI{ap=egVFrU^+*Lk4ya22K#h{-Lyvso^tzYXjnd zkW+bV*6mnQ2&l}I{mk?=-fF?mhL67ly1JIVriij%xGvhCswQdTrih{-X{el-e7QDg zjS{W9B;1%14~py=dXXxNIC$=5!Oo=Le^a$LBs{TR)$ISacS%Zp=q0 zxzMJYGCc-$#Q!4AnLkcDKVA>G-k+&vZlo%z=L4n%kZY7eY00XuW&N4aj1DKJ7c{6I ztn{oE{E9*1js(SWesW03^X#nWh)2Vj(1TZ{FHmY?xHONSPoBLMmuo7LvFXIZh!nAf zhhEYIa(74h4jt%KOI2TeP5{Q!|8v|7Uh)tY+!#L55+XVZTvEl3U}z~g%R`W*(w_q< zbwqp3oWBpsX{0nIiUE{J0x!y|SXWO*l75YrN{=&cH zyBC`^Vfg|=m8aw9U{19mq8bDjy|?it{@SgL11OhV!Z&#T!*a=~Wh?)g{=HZjoO)UE z__n2GCNqF zIvAfWhleUy(7t`&XI~*=&u#I(%RCi$w0m+vV~Q}lNN?k0DNqb4;Jr6TdUWahIc`17%@~-kD03`U~^v&vhLW5RuYhwv1=wX?J86;G);q*<+ zqmQ`={AZT*15e;<{74!Tn@!y*}^zR>suEY zRL$(d_)A|weJzCKXS!G76*&)As!lGI%K{$(Y$*Ned;2hR4kB%4{x8!H@}aKiD)D2> zqo?jNI^ovj&uS6U)V*N>?ORnRyE)G^w?F$*2`+M$$;3BsC$q7klbUO%-#9{oO&IIR zLaxD?-W_yj|7m?rZKr!#NND>NXTLuY-x1{EcGe1(b60#SaT+cC*eDawH^u z&h;A{VWBX!WQCS=#GBz6CKVc%m$~Y-)R6n5DWUM9tMBB2IbZugRY$pEatiQG_G*fo ziCd7J=K~cu7MAk-T_=C96o&4&4ajiKMf7RzH9R|8vD7HE;#2$3~PS@t85b%F% zqYdR*iZ0*ZI{3=>bGD5Vmd2kobFcZ?A7Ff zloDjff-(>2aPDOJm0!FE1F6=SS=?5=YwUjKcxbAJvU^h>3PHKYr(gms(NgrH^p8C$I-n)(jC^=%u z9Xc)6sd*^qc@9n*PJLy%AFoB`t};T0Y0eD1{PTqm{^F>8&Aps(LyM47DfUoyz!-M) zas2GXi63!4!Suq!rZ-)StHLn&yw$-Un_{9(p6;_N%Pf1&{(n`XQD#Q21|6?^!FAPb zB@_D7^Alwa*QbZFbk&sfo8m)GEjKzzhnCLwAxQ{@Zu--bogz(bS{zD|`u# ze|Ec26s`H*P@q_am`}=H;%>7z$^m-W5+4ddT6%QXk~KBTd3EI8KOLEE2D1frh0H@v zp$vBx*Bbli%{H$71-{fSzNLB~lwJwNeTThXf~>rU?-B|+j1s7TWdt(U8;{QqgWd*`P=P>eD+LnH{IHWf)ULDB!h_{9T#cPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L00yA|00yA}=wuMj00007bV*G`2iyk} z2@@%GD6r%J01wwmL_t(|+U;C>cvR(?|NY+goJleRBtamoVkN1!c9t&1?xK};tyL@4 zwOenINZ!1C-`Y2XiMSZ+f>sH-rt*G>3p`>E1VuA$*A`wDD zCbyaM?jJKr&di*X3pd@G_j$etk~uT;UVq>B{=OH0AsLb(8ImCxk|7zA9N|9uq=hI& zJ0=4-7C;<81%R;tR%ZV^2S7`9y$#@5xOfKFqT#RCQ3m2B`~y6k4qz^TrvZFDGz3ca3kArrhyj&m|}S@7PBgY)RPvHe25w?Db{C9TmXxC11nND05 z$qayZW)q-4@ea^_(yyf!;ymJE^Y}bzlK{Tf=B0mz8YDl`j4GSw z+~C2kAH)t=C0m;Y%PTS(F9Ws{1$*qVyZiE6MyV6wX|&xHXU$` zDxc>}A#k07$X^n&NLDu0ph?N5eEbp;B8&-;l)*MO)jPR|!lCcx;Dw_!m#`O8~GzB8>s)NTtRV zInKrqOnqGpH+i&*ra9@K?Dvcs{h@P(0`bBqXR{z6o4T_t*&eBMfclWkiy4{hc~8L3 zDS@kJ*Gv>kWTX;KNY*7xd6VCthu?vdF!@TPT3j3D#H??#nsPz_{ zeMKf{$DlKb*^lR1Dkd--z!GLQCad5ic=-9K`R-lCC0$o+z8r1)G@}&h%an-rhZVjk zXIC~O)TsikJ}mp-(HjWf6=Z8Bv(~!6-{xmpuP&BQa&%rL%;;=)pBZ0+;(h8UfqXrv zqy}o78Y&$~UC;A*4tK?6u%r6~@=hV16vaanKP2RqER6}0WAX!};8)utkss}|();v+ zqQld~5q-mUe}_a=IYfQhg7<~_(= zz1dTz;0*>G5wXZO#4yZ}&exUpOBySbs0_p{@3KgS&Aid90+NFKrfKPGVt*@5bY#WIen>hwUxE6IP42)YU*j#R!40J`$+ z5CCErUz(229^9@6*7x6c5dy?jbY0l93RD#{U7uHunRFM6saUcvb~7kAO13B&Eqsa&$J1WdJ<3p0wDNZ?ZCj2R zKCBZ!#DDNKAV#w!$blSQ{n7%kBp>Gum}nznj~=zC`r@KW21kaRfUfhn+Pb_TZIE zo8L93XtI!N!@yigh^6BWxh|~la_Ci(QeT*HjKODc2#|Y9{94KDTu&#h{*RVJV7MQK zR9M!zux1A`DkS6H)NC7+4ZxwLr6XpKbXsorS5PL9deMLx&evu&CcFr~s>IGPPKv_p z5h1wm5=x~I^#w*5qOSF}Fg_)lgnUE=)10(byn0#laTM6xZ73o zrjTA><{7G7v--lmi!q8N^Bn&_(zI)IMboZnj&U1Zz5XkAl-8-~dIF1-oFar$==uOU zM;{kO&5D4An0yD&qYLaHBSu;NYSXUAMfh8v?yeN4P8`%tacX$^okDC1WHy2L3s*L@ zD)C-m`3WlFSX}`fL&Vf1w<$J`k+QN!c9fSjf_y=MSs6^pHx3Mg125f{7P6$E)PdL3 z>^KR82TnP$yz~ME+H-7xeRfcedilJK?Fw8U!fsZbuws0%7(&WVt6sdgcy@o=smrAmy*qihZtw4-Wj-~oC~a4W;OL#@@2j^B-RRtgFLJ*K9~;4BRx1G_=l z>=+gPIiS=d6q_61gbxiUS3>#2O8XJ<7&t>9|)QMlQLGOn6l7uNAR4l0GL z%QGzIST2}{T^1A=Bbcn@pZcR?dT*}f^$6|ckPWFJCqNlp-W1_Hf!(;rV?QFC?Z<$O zk`jMvM$<+mn*%8fuu8S}(3v&N6(`*}pergrb(7iczCh1@)ejxhvs~JX1f~UK=Vk|X za?kOBSn7B@Ng*o*I72DVOkF&3#2z{7$(fD665{zBgM{%+yUSV)qGP~HdU?DQ0l@JF zcuj@8;0#m8URScCUxtJ1BC$)!itfzoxmz@uZ_wj=GSBoSDt{rwJOw|eptyp`d*mnp za4EBuFkiD;dDd;?N*rNrkg^V0CGZNU8waqk6MsQFlbdN4R`2)6MjG#N1!rV~)6#o$%%j*-_!l`6V;7d0US91br*bd$?)Y7DY^#0OaO_74;t?q zTXE1oiLodc9hR+o zR_`{bl@cEOev z=WpA-FXx*S_*3?~+Js)2Pmf=dOl9$n-!i z3rJ*#UW2pGhjVKpo!*jt?WpC|iAD!}T4-xUdNQhc{MLr`JvN9I?H5NauTK0$iSrb& z{@N1@E6`}yMOiL;T6jv{O-X}|4d8?yini3)nBgMI4-^W<|&rzaLYb~e)cb5?wL zbt35ypXt#}m~|97v;F17{pzT0x$}|@9gC-LeXbZ?CyB|boYI2Dlx+1K2Ra?G?<}64 z_}bD7w!DJ_Bud%o8#LRNIXcL?%;X@Cp1ET5*!}LPZu#N&8e2-!-l-1oV$al_h#$;b zMR59U=Wl%w2Ux_cPJ3C+g8+cyz0nN^5p%zCz#IhtHPwk^Ox)86S*BoGVKJd36?|Sq z{_fWE690>jKqAIBe23j>vmP8d!Xe-2y;|dfOMg73qVT+Z0Ob2C#!Vo3hI;Ay=bxY0 zgpXLRym#E&0FKIf;If;~+kD5B_a1T!fGe_({H{IHcG8{a?r1)sj{3OC>=omd7|?w? zT-Vj%W34j_4n+UNP>}h2PzB zu>(GrB?pi1aP{Gun(lwy@d=bwPc?5i;hUwCNgTlps1FnJ+%MObjTA!ziSEnOqpWO1 z`72K~Klh0&Jpib==g@=U@CD2K9}WIqGX=}*focEtiFFhJ)I50j2&6jiAn|SVObG@y z>gzwzj_PsPit%Gra3N?H`sr(*{AS2eeuq68kGO3uXM-{gutN+ON#Y3+n=|B{AsLb( h8ImCxk|D{H{{!ZHo)?P1XqNy0002ovPDHLkV1hw?;_Cna literal 0 HcmV?d00001 diff --git a/nixnote.pro b/neighbornote.pro similarity index 100% rename from nixnote.pro rename to neighbornote.pro diff --git a/nixnote.sh b/neighbornote.sh old mode 100755 new mode 100644 similarity index 54% rename from nixnote.sh rename to neighbornote.sh index eefa460..9dc77b6 --- a/nixnote.sh +++ b/neighbornote.sh @@ -8,8 +8,8 @@ eval $1 # The ones below are examples only. # ########################################### -NIXNOTE=$(cd `dirname $0` && pwd) -# NIXNOTE=/usr/share/nixnote +NEIGHBORNOTE=$(cd `dirname $0` && pwd) +# NEIGHBORNOTE=/usr/share/neighbornote ######################################## # Memory settings. These can be tuned # @@ -49,7 +49,7 @@ NN_GC_OPT=-Xincgc ######################################## # This next variable is optional. It # # is only needed if you want to run # -# multiple copies of NixNote under # +# multiple copies of NeighborNote under # # the same Linux user id. Each # # additional copy (after the first) # # should have a unique name. This # @@ -79,41 +79,41 @@ done ##################### # Setup environment # ##################### -NN_CLASSPATH=$NIXNOTE/nixnote.jar - -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/apache-mime4j-0.6.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/commons-codec-1.5.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/commons-compress-1.2.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/commons-lang3-3.0.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/commons-logging-1.1.1.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/evernote-api-1.20.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/h2-1.3.158.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/httpclient-4.1.1.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/httpcore-4.1.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/httpmime-4.1.1.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/jaxen-1.1.3.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/jazzy.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/jtidy-r938.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/libthrift.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/log4j-1.2.14.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/scribe-1.3.0.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/pdfbox-app-1.6.0.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/poi-3.7-20101029.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/poi-ooxml-3.7.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/poi-ooxml-schemas-3.7-20101029.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/poi-scratchpad-3.7-20101029.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/tika.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/xmlbeans-2.3.0.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/xsdlib-20060615.jar - -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/qtjambi-linux32-4.5.2_01.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/qtjambi-linux32-gcc-4.5.2_01.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/qtjambi-linux64-4.5.2_01.jar -NN_CLASSPATH=$NN_CLASSPATH:$NIXNOTE/lib/qtjambi-linux64-gcc-4.5.2_01.jar +NN_CLASSPATH=$NEIGHBORNOTE/neighbornote.jar + +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/apache-mime4j-0.6.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/commons-codec-1.5.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/commons-compress-1.2.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/commons-lang3-3.0.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/commons-logging-1.1.1.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/evernote-api-1.20.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/h2-1.3.158.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/httpclient-4.1.1.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/httpcore-4.1.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/httpmime-4.1.1.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/jaxen-1.1.3.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/jazzy.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/jtidy-r938.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/libthrift.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/log4j-1.2.14.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/scribe-1.3.0.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/pdfbox-app-1.6.0.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/poi-3.7-20101029.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/poi-ooxml-3.7.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/poi-ooxml-schemas-3.7-20101029.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/poi-scratchpad-3.7-20101029.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/tika.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/xmlbeans-2.3.0.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/xsdlib-20060615.jar + +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/qtjambi-linux32-4.5.2_01.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/qtjambi-linux32-gcc-4.5.2_01.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/qtjambi-linux64-4.5.2_01.jar +NN_CLASSPATH=$NN_CLASSPATH:$NEIGHBORNOTE/lib/qtjambi-linux64-gcc-4.5.2_01.jar ################### # Run the program # ################### -cd $NIXNOTE +cd $NEIGHBORNOTE java -Xmx$NN_XMX -Xms$NN_XMS -XX:NewRatio=$NN_NEW_RATIO $NN_GC_OPT $NN_DEBUG -classpath $NN_CLASSPATH cx.fbn.nevernote.NeverNote --name=$NN_NAME --home=$NN_HOME --sync-only=$NN_SYNCONLY cd - diff --git a/neighbornote_path.sh b/neighbornote_path.sh new file mode 100644 index 0000000..7e12c04 --- /dev/null +++ b/neighbornote_path.sh @@ -0,0 +1,2 @@ +#! /bin/sh +/usr/share/neighbornote/neighbornote.sh $* diff --git a/nixnote.ico b/nixnote.ico deleted file mode 100644 index e3b79fb9f054db8f7bd01f2b54a3d124b164076e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 370070 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¥$*TKMTcVBkWxf$-`72K#j< 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%0D~%fPL&O$xlsA+av3f)}mL8b$P=%QO~FR&B#Ia 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 O2>223BXEk3!2bu4c3ztR diff --git a/nixnote.png b/nixnote.png deleted file mode 100644 index 5c89ec9b0db583ab50468a50e9f756c8d373c6f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2725 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 diff --git a/nixnote_path.sh b/nixnote_path.sh deleted file mode 100755 index 3ee3d60..0000000 --- a/nixnote_path.sh +++ /dev/null @@ -1,2 +0,0 @@ -#! /bin/sh -/usr/share/nixnote/nixnote.sh $* diff --git a/release.txt b/release.txt index e32370a..8892e2f 100644 --- a/release.txt +++ b/release.txt @@ -1,4 +1,4 @@ -Welcome to NixNote +Welcome to NeighborNote This is an open source clone of Evernote designed to run on Linux. It is written in Java so it will also run on Windows & OS-X, but the primary focus has been to try and get a usable environment for Linux. While this is designed to work with Evernote, it is in no way connectedwith or supported by Evernote. Any problems you encounter will not be corrected by them and,since this is GPL software, you are using this software at your own risk. diff --git a/shortcuts_howto.txt b/shortcuts_howto.txt index 6147761..347147c 100644 --- a/shortcuts_howto.txt +++ b/shortcuts_howto.txt @@ -1,18 +1,18 @@ -I've tried to add the ability to customize your NixNote menu shortcuts, +I've tried to add the ability to customize your NeighborNote menu shortcuts, but I don't want to take the time to setup a new dialog box and all the junk that entails. So, I chose a text file config instead. Eventually I may change it so the text file can be edited within the running program, but I have other things to spend my time on at the moment. -First, you don't need to do this. Nixnote comes with a default set of +First, you don't need to do this. Neighbornote comes with a default set of shortcuts. If you are happy with those then you don't need to do a thing. If you want to customize your shortcuts then you need to do a little work. You should have a shortcuts_sample.txt file. Copy this to shortcuts.txt -in your Nixnote home directory (~/.nevernote on Linux & OS-X and your user +in your Neighbornote home directory (~/.nevernote on Linux & OS-X and your user home directory on Windows). This is the file that is read -when Nixnote starts. Any changes to this file only happen at startup +when Neighbornote starts. Any changes to this file only happen at startup so if you change it you need to restart the program to see those changes. This file has three main columns. diff --git a/src/cx/fbn/nevernote/Global.java b/src/cx/fbn/nevernote/Global.java index 89b5966..e9e757d 100644 --- a/src/cx/fbn/nevernote/Global.java +++ b/src/cx/fbn/nevernote/Global.java @@ -1,2033 +1,2306 @@ -/* - * This file is part of NixNote - * Copyright 2009 Randy Baumgarte - * - * This file may be licensed under the terms of of the - * GNU General Public License Version 2 (the ``GPL''). - * - * Software distributed under the License is distributed - * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either - * express or implied. See the GPL for the specific language - * governing rights and limitations. - * - * You should have received a copy of the GPL along with this - * program. If not, go to http://www.gnu.org/licenses/gpl.html - * or write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * -*/ - -package cx.fbn.nevernote; - - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.HashMap; -import java.util.List; - -import org.apache.commons.lang3.StringEscapeUtils; - -import com.evernote.edam.type.Accounting; -import com.evernote.edam.type.PrivilegeLevel; -import com.evernote.edam.type.User; -import com.evernote.edam.type.UserAttributes; -import com.swabunga.spell.engine.Configuration; -import com.trolltech.qt.core.QByteArray; -import com.trolltech.qt.core.QSettings; -import com.trolltech.qt.core.QSize; -import com.trolltech.qt.gui.QPalette; -import com.trolltech.qt.gui.QSystemTrayIcon; - -import cx.fbn.nevernote.config.FileManager; -import cx.fbn.nevernote.config.InitializationException; -import cx.fbn.nevernote.config.StartupConfig; -import cx.fbn.nevernote.gui.ContainsAttributeFilterTable; -import cx.fbn.nevernote.gui.DateAttributeFilterTable; -import cx.fbn.nevernote.gui.ShortcutKeys; -import cx.fbn.nevernote.utilities.ApplicationLogger; -import cx.fbn.nevernote.utilities.Pair; - - -//***************************************************** -//***************************************************** -//* Global constants & static functions used by -//* multiple threads. -//***************************************************** -//***************************************************** - -public class Global { - // Set current version and the known versions. - public static String version = "1.5"; - public static String[] validVersions = {"1.5", "1.4", "1.3", "1.2", "1.1", "1.0", "0.99", "0.98", "0.97", "0.96"}; - public static String username = ""; - //public static String password = ""; - - - // Each thread has an ID. This is used primarily to check the status - // of running threads. - public static final int mainThreadId=0; - public static final int syncThreadId=1; - public static final int tagCounterThreadId=2; - public static final int trashCounterThreadId=3; // This should always be the highest thread ID - public static final int indexThreadId=4; // Thread for indexing words - public static final int saveThreadId=5; // Thread used for processing data to saving content - public static final int notebookCounterThreadId=6; // Notebook Thread - public static final int indexThread03Id=7; // unused - public static final int indexThread04Id=8; // unused - public static final int dbThreadId=9; // This should always be the highest thread ID - public static final int threadCount = 10; - - - // These variables deal with where the list of notes appears - // They will either be vertical (View_List_Narrow) or will be - // on top of the note (View_List_Wide). It also has the size of - // thumbnails displayed in each view - public static int View_List_Wide = 1; - public static int View_List_Narrow = 2; - public static QSize smallThumbnailSize = new QSize(100,75); - public static QSize largeThumbnailSize = new QSize(300,225); - - // This is used to keep a running list of passwords that the user - // wants us to remember. - public static HashMap> passwordSafe = new HashMap>(); - public static List> passwordRemember = new ArrayList>(); - - - //public static String currentNotebookGuid; - - // These deal with Evernote user settings - public static User user; - public static long authTimeRemaining; - public static long authRefreshTime; - public static long failedRefreshes = 0; - public static String userStoreUrl; - public static String noteStoreUrl; - public static String noteStoreUrlBase; - - // When we want to shut down we set this to true to short - // circut other threads - public static boolean keepRunning; - - // In the note list, these are the column numbers - // so I don't need to hard code numbers. - public static int noteTableCreationPosition = 0; - public static int noteTableTitlePosition = 1; - public static int noteTableTagPosition = 2; - public static int noteTableNotebookPosition = 3; - public static int noteTableChangedPosition = 4; - public static int noteTableGuidPosition = 5; - public static int noteTableAuthorPosition = 6; - public static int noteTableSourceUrlPosition = 7; - public static int noteTableSubjectDatePosition = 8; - public static int noteTableSynchronizedPosition = 9; - public static int noteTableThumbnailPosition = 10; - public static int noteTablePinnedPosition = 11; - public static int noteTableColumnCount = 12; - public static Integer cryptCounter = 0; - - //public static int minimumWordCount = 2; - - // Regular expression to parse text with when indexing - private static String wordRegex; - - // Experimental fixes. Set via Edit/Preferences/Debugging - public static boolean enableCarriageReturnFix = false; - public static boolean enableHTMLEntitiesFix = false; - - // Used to set & retrieve ini & Windows registry settings - public static QSettings settings; // Set & get ini settings - public static boolean isConnected; // Are we connected to Evernote - public static boolean showDeleted = false; // Show deleted notes? - public static boolean disableUploads = false; // Should we disable uploads (used in testing features) - public static int messageLevel; // The level of messages to write to the log files - public static String tagDelimeter = ","; // This is used to separate out tag names when entering above note - public static String attachmentNameDelimeter = "------"; // Used to separate out attachment names in the res directory - - - //* Database fields - public static String databaseName = new String("NeverNote"); // database name. used for multiple databases to separate settings. - public static String indexDatabaseName = new String("Index"); // searchable words database - public static String resourceDatabaseName = new String("Resources"); // attachments database - public static DateAttributeFilterTable createdSinceFilter; - public static DateAttributeFilterTable createdBeforeFilter; - public static DateAttributeFilterTable changedSinceFilter; - public static DateAttributeFilterTable changedBeforeFilter; - public static ContainsAttributeFilterTable containsFilter; - - // Log file used for debugging - public static ApplicationLogger logger; - //PrintStream stdoutStream; - - // Application key shortcuts & appearance - public static QPalette originalPalette; - public static ShortcutKeys shortcutKeys; - - public static boolean disableViewing; // used to disable the editor - - // When saving a note, this is a list of things we strip out because Evernote hates them - public static List invalidElements = new ArrayList(); - public static HashMap> invalidAttributes = new HashMap>(); - - public static boolean mimicEvernoteInterface; // Try to mimic Evernote or allow multiple notebook selection - public static HashMap resourceMap; // List of attachments for a note. - public static String cipherPassword = ""; // If the database is encrypted, this stores the password - public static String databaseCache = "16384"; // Default DB cache size - - // These are used for performance testing - static Calendar startTraceTime; - static Calendar intervalTraceTime; - - static boolean syncOnly; - - private static FileManager fileManager; // Used to access files & directories - - // Do initial setup - public static void setup(StartupConfig startupConfig) throws InitializationException { - settings = new QSettings("fbn.cx", startupConfig.getName()); - disableViewing = startupConfig.getDisableViewing(); - syncOnly = startupConfig.isSyncOnly(); - - fileManager = new FileManager(startupConfig.getHomeDirPath(), startupConfig.getProgramDirPath()); - - - getServer(); // Setup URL to connect to - - // Get regular expressions used to parse out words - settings.beginGroup("General"); - String regex = (String) settings.value("regex", "[,\\s]+"); - setWordRegex(regex); - settings.endGroup(); - - //Setup debugging information - settings.beginGroup("Debug"); - String msglevel = (String) settings.value("messageLevel", "Low"); - settings.endGroup(); - - - //messageLevel = 1; - setMessageLevel(msglevel); - keepRunning = true; // Make sure child threads stay running +/* + * This file is part of NixNote + * Copyright 2009 Randy Baumgarte + * + * This file may be licensed under the terms of of the + * GNU General Public License Version 2 (the ``GPL''). + * + * Software distributed under the License is distributed + * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the GPL for the specific language + * governing rights and limitations. + * + * You should have received a copy of the GPL along with this + * program. If not, go to http://www.gnu.org/licenses/gpl.html + * or write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * +*/ + +package cx.fbn.nevernote; + + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.HashMap; +import java.util.List; + +import org.apache.commons.lang3.StringEscapeUtils; + +import com.evernote.edam.type.Accounting; +import com.evernote.edam.type.PrivilegeLevel; +import com.evernote.edam.type.User; +import com.evernote.edam.type.UserAttributes; +import com.swabunga.spell.engine.Configuration; +import com.trolltech.qt.core.QByteArray; +import com.trolltech.qt.core.QSettings; +import com.trolltech.qt.core.QSize; +import com.trolltech.qt.gui.QPalette; +import com.trolltech.qt.gui.QSystemTrayIcon; + +import cx.fbn.nevernote.config.FileManager; +import cx.fbn.nevernote.config.InitializationException; +import cx.fbn.nevernote.config.StartupConfig; +import cx.fbn.nevernote.gui.ContainsAttributeFilterTable; +import cx.fbn.nevernote.gui.DateAttributeFilterTable; +import cx.fbn.nevernote.gui.ShortcutKeys; +import cx.fbn.nevernote.utilities.ApplicationLogger; +import cx.fbn.nevernote.utilities.Pair; + + +//***************************************************** +//***************************************************** +//* Global constants & static functions used by +//* multiple threads. +//***************************************************** +//***************************************************** + +public class Global { + // Set current version and the known versions. + // ICHANGED 自分用に変更 + public static String version = "0.1"; + public static String[] validVersions = {"0.1"}; + + public static String username = ""; + //public static String password = ""; + + + // Each thread has an ID. This is used primarily to check the status + // of running threads. + public static final int mainThreadId=0; + public static final int syncThreadId=1; + public static final int tagCounterThreadId=2; + public static final int trashCounterThreadId=3; // This should always be the highest thread ID + public static final int indexThreadId=4; // Thread for indexing words + public static final int saveThreadId=5; // Thread used for processing data to saving content + public static final int notebookCounterThreadId=6; // Notebook Thread + public static final int indexThread03Id=7; // unused + public static final int indexThread04Id=8; // unused + public static final int dbThreadId=9; // This should always be the highest thread ID + public static final int threadCount = 10; + + + // These variables deal with where the list of notes appears + // They will either be vertical (View_List_Narrow) or will be + // on top of the note (View_List_Wide). It also has the size of + // thumbnails displayed in each view + public static int View_List_Wide = 1; + public static int View_List_Narrow = 2; + public static QSize smallThumbnailSize = new QSize(100,75); + public static QSize largeThumbnailSize = new QSize(300,225); + + // This is used to keep a running list of passwords that the user + // wants us to remember. + public static HashMap> passwordSafe = new HashMap>(); + public static List> passwordRemember = new ArrayList>(); + + + //public static String currentNotebookGuid; + + // These deal with Evernote user settings + public static User user; + public static long authTimeRemaining; + public static long authRefreshTime; + public static long failedRefreshes = 0; + public static String userStoreUrl; + public static String noteStoreUrl; + public static String noteStoreUrlBase; + + // When we want to shut down we set this to true to short + // circut other threads + public static boolean keepRunning; + + // In the note list, these are the column numbers + // so I don't need to hard code numbers. + public static int noteTableCreationPosition = 0; + public static int noteTableTitlePosition = 1; + public static int noteTableTagPosition = 2; + public static int noteTableNotebookPosition = 3; + public static int noteTableChangedPosition = 4; + public static int noteTableGuidPosition = 5; + public static int noteTableAuthorPosition = 6; + public static int noteTableSourceUrlPosition = 7; + public static int noteTableSubjectDatePosition = 8; + public static int noteTableSynchronizedPosition = 9; + public static int noteTableThumbnailPosition = 10; + public static int noteTablePinnedPosition = 11; + public static int noteTableColumnCount = 12; + public static Integer cryptCounter = 0; + + //public static int minimumWordCount = 2; + + // Regular expression to parse text with when indexing + private static String wordRegex; + + // Experimental fixes. Set via Edit/Preferences/Debugging + public static boolean enableCarriageReturnFix = false; + public static boolean enableHTMLEntitiesFix = false; + + // Used to set & retrieve ini & Windows registry settings + public static QSettings settings; // Set & get ini settings + public static boolean isConnected; // Are we connected to Evernote + public static boolean showDeleted = false; // Show deleted notes? + public static boolean disableUploads = false; // Should we disable uploads (used in testing features) + public static int messageLevel; // The level of messages to write to the log files + public static String tagDelimeter = ","; // This is used to separate out tag names when entering above note + public static String attachmentNameDelimeter = "------"; // Used to separate out attachment names in the res directory + + + //* Database fields + public static String databaseName = new String("NeverNote"); // database name. used for multiple databases to separate settings. + public static String indexDatabaseName = new String("Index"); // searchable words database + public static String resourceDatabaseName = new String("Resources"); // attachments database + + // ICHANGED + public static String behaviorDatabaseName = new String("Behavior"); // 操作履歴データベース + + public static DateAttributeFilterTable createdSinceFilter; + public static DateAttributeFilterTable createdBeforeFilter; + public static DateAttributeFilterTable changedSinceFilter; + public static DateAttributeFilterTable changedBeforeFilter; + public static ContainsAttributeFilterTable containsFilter; + + // Log file used for debugging + public static ApplicationLogger logger; + //PrintStream stdoutStream; + + // Application key shortcuts & appearance + public static QPalette originalPalette; + public static ShortcutKeys shortcutKeys; + + public static boolean disableViewing; // used to disable the editor + + // When saving a note, this is a list of things we strip out because Evernote hates them + public static List invalidElements = new ArrayList(); + public static HashMap> invalidAttributes = new HashMap>(); + + public static boolean mimicEvernoteInterface; // Try to mimic Evernote or allow multiple notebook selection + public static HashMap resourceMap; // List of attachments for a note. + public static String cipherPassword = ""; // If the database is encrypted, this stores the password + public static String databaseCache = "16384"; // Default DB cache size + + // These are used for performance testing + static Calendar startTraceTime; + static Calendar intervalTraceTime; + + static boolean syncOnly; + + private static FileManager fileManager; // Used to access files & directories + + // Do initial setup + public static void setup(StartupConfig startupConfig) throws InitializationException { + // ICHANGED 設定値の保存先を変更 + settings = new QSettings("NeighborNote.ini", QSettings.Format.IniFormat); + + disableViewing = startupConfig.getDisableViewing(); + syncOnly = startupConfig.isSyncOnly(); + + fileManager = new FileManager(startupConfig.getHomeDirPath(), startupConfig.getProgramDirPath()); + + + getServer(); // Setup URL to connect to + + // Get regular expressions used to parse out words + settings.beginGroup("General"); + String regex = (String) settings.value("regex", "[,\\s]+"); + setWordRegex(regex); + settings.endGroup(); + + //Setup debugging information + settings.beginGroup("Debug"); + String msglevel = (String) settings.value("messageLevel", "Low"); + settings.endGroup(); + + + //messageLevel = 1; + setMessageLevel(msglevel); + keepRunning = true; // Make sure child threads stay running disableUploads = disableUploads(); // Should we upload anything? Normally false. //disableUploads = true; //***** DELETE THIS LINE ******* - enableCarriageReturnFix = enableCarriageReturnFix(); // Enable test fix? - enableHTMLEntitiesFix = enableHtmlEntitiesFix(); // Enable test fix? - - logger = new ApplicationLogger("global.log"); // Setup log for this class - shortcutKeys = new ShortcutKeys(); // Setup keyboard shortcuts. - mimicEvernoteInterface = getMimicEvernoteInterface(); // Should we mimic Evernote's notebook behavior - resourceMap = new HashMap(); // Setup resource map used to store attachments when editing - - databaseCache = getDatabaseCacheSize(); // Set database cache size - - Global.username = getUserInformation().getUsername(); - } - - // Get/Set word parsing regular expression - public static String getWordRegex() { - return wordRegex; - } - public static void setWordRegex(String r) { - wordRegex = r; - } - - // Set the debug message level - public static void setMessageLevel(String msglevel) { - if (msglevel.equalsIgnoreCase("low")) - messageLevel = 1; - if (msglevel.equalsIgnoreCase("medium")) - messageLevel = 2; - if (msglevel.equalsIgnoreCase("high")) - messageLevel = 3; - if (msglevel.equalsIgnoreCase("extreme")) - messageLevel = 4; - settings.beginGroup("Debug"); - settings.setValue("messageLevel", msglevel); - settings.endGroup(); - } - - //**************************************************** - //**************************************************** - //** Save user account information from Evernote - //**************************************************** - //**************************************************** - public static void saveUserInformation(User user) { - settings.beginGroup("User"); - settings.setValue("id", user.getId()); - settings.setValue("username", user.getUsername()); - settings.setValue("email", user.getEmail()); - settings.setValue("name", user.getName()); - settings.setValue("timezone", user.getTimezone()); - settings.setValue("privilege", user.getPrivilege().getValue()); - settings.setValue("created", user.getCreated()); - settings.setValue("updated", user.getUpdated()); - settings.setValue("deleted", user.getDeleted()); - settings.setValue("shard", user.getShardId()); - settings.endGroup(); - isPremium(); - if (user.getAttributes()!=null) - saveUserAttributes(user.getAttributes()); - if (user.getAccounting()!=null) - saveUserAccounting(user.getAccounting()); - - } - public static User getUserInformation() { - User user = new User(); - settings.beginGroup("User"); - try { - user.setId((Integer)settings.value("id", 0)); - } catch (java.lang.ClassCastException e) { - user.setId(new Integer((String)settings.value("id", "0"))); - } - String username = (String)settings.value("username", ""); - String email = (String)settings.value("email", ""); - String name = (String)settings.value("name", ""); - String timezone = (String)settings.value("timezone", ""); - Integer privilege = 0; - try { - privilege = new Integer((String)settings.value("privilege", "0")); - } catch (java.lang.ClassCastException e) { - privilege = (Integer)settings.value("privilege", 0); - } - - try { - String date = (String)settings.value("created", "0"); - user.setCreated(new Long(date)); - date = (String)settings.value("updated", "0"); - user.setUpdated(new Long(date)); - date = (String)settings.value("deleted", "0"); - user.setDeleted(new Long(date)); - } catch (java.lang.ClassCastException e) { - Long date = (Long)settings.value("created", 0); - user.setCreated(date); - date = (Long)settings.value("updated", 0); - user.setUpdated(date); - date = (Long)settings.value("deleted", 0); - user.setDeleted(date); - } - - String shard = (String)settings.value("shard", ""); - settings.endGroup(); - - user.setUsername(username); - user.setEmail(email); - user.setName(name); - user.setTimezone(timezone); - PrivilegeLevel userLevel = PrivilegeLevel.findByValue(privilege); - user.setPrivilege(userLevel); - user.setShardId(shard); - return user; - } - - public static void saveUserAttributes(UserAttributes attrib) { - settings.beginGroup("UserAttributes"); - settings.setValue("defaultLocationName", attrib.getDefaultLocationName()); - settings.setValue("defaultLatitude", attrib.getDefaultLocationName()); - settings.setValue("defaultLongitude", attrib.getDefaultLocationName()); - settings.setValue("incomingEmailAddress", attrib.getIncomingEmailAddress()); - settings.endGroup(); - } - public static UserAttributes getUserAttributes() { - settings.beginGroup("UserAttributes"); - UserAttributes attrib = new UserAttributes(); - attrib.setDefaultLocationName((String)settings.value("defaultLocationName","")); - attrib.setDefaultLatitudeIsSet(false); - attrib.setDefaultLongitudeIsSet(false); - attrib.setIncomingEmailAddress((String)settings.value("incomingEmailAddress", "")); - settings.endGroup(); - return attrib; - } - public static void saveUserAccounting(Accounting acc) { - settings.beginGroup("UserAccounting"); - settings.setValue("uploadLimit", acc.getUploadLimit()); - settings.setValue("uploadLimitEnd", acc.getUploadLimitEnd()); - settings.setValue("uploadLimitNextMonth", acc.getUploadLimitNextMonth()); - settings.setValue("premiumServiceStart", acc.getPremiumServiceStart()); - settings.setValue("nextPaymentDue", acc.getNextPaymentDue()); - settings.setValue("uploadAmount", acc.getUpdated()); - settings.endGroup(); - } - public static long getUploadLimitEnd() { - Long limit; - settings.beginGroup("UserAccounting"); - - // Upload limit - try { - String val = (String)settings.value("uploadLimitEnd", "0"); - limit = new Long(val.trim()); - } catch (Exception e) { - try { - limit = (Long)settings.value("uploadLimitEnd", 0); - } catch (Exception e1) { - limit = new Long(0); - } - } - - // return value - settings.endGroup(); - return limit; - } - public static void saveUploadAmount(long amount) { - settings.beginGroup("UserAccounting"); - settings.setValue("uploadAmount", amount); - settings.endGroup(); - } - public static long getUploadAmount() { - long amt=0; - settings.beginGroup("UserAccounting"); - try { - String num = (String)settings.value("uploadAmount", "0"); - amt = new Long(num.trim()); - } catch (Exception e) { - try { - amt = (Integer)settings.value("uploadAmount", 0); - } catch (Exception e1) { - amt = 0; - } - } - settings.endGroup(); - return amt; - } - public static void saveEvernoteUpdateCount(long amount) { - settings.beginGroup("UserAccounting"); - settings.setValue("updateCount", amount); - settings.endGroup(); - } - public static long getEvernoteUpdateCount() { - long amt; - settings.beginGroup("UserAccounting"); - try { - String num = (String)settings.value("updateCount", new Long(0).toString()); - amt = new Long(num.trim()); - } catch (java.lang.ClassCastException e) { - amt = 0; - } - settings.endGroup(); - return amt; - } - public static boolean isPremium() { - int level; - settings.beginGroup("User"); - try { - String num = (String)settings.value("privilege", "1"); - level = new Integer(num.trim()); - } catch (java.lang.ClassCastException e) { - try { - level = (Integer)settings.value("privilege", 1); - } catch (Exception e1) { - level = 1; - } - } - settings.endGroup(); - PrivilegeLevel userLevel = PrivilegeLevel.findByValue(level); - if (userLevel == PrivilegeLevel.NORMAL) - return false; - return true; - - } - public static long getUploadLimit() { - settings.beginGroup("UserAccounting"); - long limit; - try { - String num = (String)settings.value("uploadLimit", new Long(0).toString()); - limit = new Long(num.trim()); - } catch (java.lang.ClassCastException e) { - limit = 0; - } - settings.endGroup(); - return limit; - } - - - - //**************************************************** - //**************************************************** - //** View settings. Used to restore settings - //** when starting and to control how the program - //** behaves. - //**************************************************** - //**************************************************** - - //* Get/Set if we should show a tray icon - public static boolean showTrayIcon() { - settings.beginGroup("General"); - try { - String max = (String) settings.value("showTrayIcon", "false"); - settings.endGroup(); - if (!max.equalsIgnoreCase("true") || !QSystemTrayIcon.isSystemTrayAvailable()) - return false; - else - return true; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value("showTrayIcon", false); - settings.endGroup(); - return value; - } - } - public static void setShowTrayIcon(boolean val) { - settings.beginGroup("General"); - if (val) - settings.setValue("showTrayIcon", "true"); - else - settings.setValue("showTrayIcon", "false"); - settings.endGroup(); - } - - // Get/Set window maximized when closed last - public static boolean wasWindowMaximized() { - try { - settings.beginGroup("General"); - String max = (String) settings.value("isMaximized", "true"); - settings.endGroup(); - if (!max.equalsIgnoreCase("true")) - return false; - return true; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value("isMaximized", true); - settings.endGroup(); - return value; - } - } - public static void saveWindowMaximized(boolean isMax) { - settings.beginGroup("General"); - if (isMax) - settings.setValue("isMaximized", "true"); - else - settings.setValue("isMaximized", "false"); - settings.endGroup(); - } - - // Get/set currently viewed note Guid - public static String getLastViewedNoteGuid() { - settings.beginGroup("General"); - String guid = (String) settings.value("lastViewedNote", ""); - settings.endGroup(); - return guid; - } - public static void saveCurrentNoteGuid(String guid) { - settings.beginGroup("General"); - if (guid != null) - settings.setValue("lastViewedNote", guid); - else - settings.setValue("lastViewedNote", ""); - settings.endGroup(); - } - - // Get/Set the note column we are sorted on and the order - public static void setSortColumn(int i) { - int view = Global.getListView(); - settings.beginGroup("General"); - if (view == Global.View_List_Wide) - settings.setValue("sortColumn", i); - else - settings.setValue("sortColumn-Narrow", i); - settings.endGroup(); - } - public static int getSortColumn() {; - String key; - if (Global.getListView() == Global.View_List_Wide) - key = "sortColumn"; - else - key = "sortColumn-Narrow"; - - settings.beginGroup("General"); - int order; - try { - String val = settings.value(key, new Integer(0)).toString(); - order = new Integer(val.trim()); - } catch (Exception e) { - try { - order = (Integer)settings.value(key, 0); - } catch (Exception e1) { - order = 0; - } - } - - settings.endGroup(); - return order; - } - public static void setSortOrder(int i) { - int view = Global.getListView(); - settings.beginGroup("General"); - if (view == Global.View_List_Wide) - settings.setValue("sortOrder", i); - else - settings.setValue("sortOrder-Narrow", i); - settings.endGroup(); - } - public static int getSortOrder() { - int view = Global.getListView(); - settings.beginGroup("General"); - String key; - if (view == Global.View_List_Wide) - key = "sortOrder"; - else - key = "sortOrder-Narrow"; - - int order; - try { - String val = settings.value(key, new Integer(0)).toString(); - order = new Integer(val.trim()); - } catch (Exception e) { - try { - order = (Integer)settings.value(key, 0); - } catch (Exception e1) { - order = 0; - } - } - - settings.endGroup(); - return order; - } - - // Should we automatically log in to Evernote when starting? - public static boolean automaticLogin() { - try { - settings.beginGroup("General"); - String text = (String)settings.value("automaticLogin", "false"); - settings.endGroup(); - if (text.equalsIgnoreCase("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value("automaticLogin", false); - settings.endGroup(); - return value; - } - } - public static void setAutomaticLogin(boolean val) { - settings.beginGroup("General"); - if (val) - settings.setValue("automaticLogin", "true"); - else - settings.setValue("automaticLogin", "false"); - settings.endGroup(); - } - - // Get/set the Evernote server Url. - public static void setServer(String server) { - settings.beginGroup("General"); - settings.setValue("server", server); - settings.endGroup(); - } - public static String getServer() { - settings.beginGroup("General"); - String text = (String)settings.value("server", "www.evernote.com"); - if (text.equals("www.evernote.com")) { - userStoreUrl = "https://www.evernote.com/edam/user"; - noteStoreUrlBase = "www.evernote.com/edam/note/"; - } else { - userStoreUrl = "https://sandbox.evernote.com/edam/user"; - noteStoreUrlBase = "sandbox.evernote.com/edam/note/"; - } - settings.endGroup(); -// if (isPremium()) - noteStoreUrlBase = "https://" + noteStoreUrlBase; -// else -// noteStoreUrlBase = "http://" + noteStoreUrlBase; - return text; - } - - // Get/Set if we should disable uploads to Evernote - public static boolean disableUploads() { - settings.beginGroup("General"); - try { - String text = (String)settings.value("disableUploads", "false"); - settings.endGroup(); - if (text.equalsIgnoreCase("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value("disableUploads", false); - settings.endGroup(); - return value; - } - } - public static void setDisableUploads(boolean val) { - settings.beginGroup("General"); - if (val) - settings.setValue("disableUploads", "true"); - else - settings.setValue("disableUploads", "false"); - settings.endGroup(); - disableUploads = val; - } - - // Should we view PDF documents inline? - public static boolean pdfPreview() { - settings.beginGroup("General"); - try { - String text = (String)settings.value("pdfPreview", "true"); - settings.endGroup(); - if (text.equalsIgnoreCase("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value("pdfPreview", true); - settings.endGroup(); - return value; - } - } - public static void setPdfPreview(boolean val) { - settings.beginGroup("General"); - if (val) - settings.setValue("pdfPreview", "true"); - else - settings.setValue("pdfPreview", "false"); - settings.endGroup(); - } - - // When creating a new note, should it inherit tags that are currently selected? - public static boolean newNoteWithSelectedTags() { - settings.beginGroup("General"); - try { - String text = (String)settings.value("newNoteWithSelectedTags", "false"); - settings.endGroup(); - if (text.equalsIgnoreCase("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value("newNoteWithSelectedTags", false); - settings.endGroup(); - return value; - } - } - public static void setNewNoteWithSelectedTags(boolean val) { - settings.beginGroup("General"); - if (val) - settings.setValue("newNoteWithSelectedTags", "true"); - else - settings.setValue("newNoteWithSelectedTags", "false"); - settings.endGroup(); - } - - // Minimum weight for text OCRed from Evernote. Anything below this - // Won't be shown to the user when they search - public static void setRecognitionWeight(int len) { - settings.beginGroup("General"); - settings.setValue("recognitionWeight", len); - settings.endGroup(); - } - public static int getRecognitionWeight() { - settings.beginGroup("General"); - Integer len; - try { + enableCarriageReturnFix = enableCarriageReturnFix(); // Enable test fix? + enableHTMLEntitiesFix = enableHtmlEntitiesFix(); // Enable test fix? + + logger = new ApplicationLogger("global.log"); // Setup log for this class + shortcutKeys = new ShortcutKeys(); // Setup keyboard shortcuts. + mimicEvernoteInterface = getMimicEvernoteInterface(); // Should we mimic Evernote's notebook behavior + resourceMap = new HashMap(); // Setup resource map used to store attachments when editing + + databaseCache = getDatabaseCacheSize(); // Set database cache size + + Global.username = getUserInformation().getUsername(); + } + + // Get/Set word parsing regular expression + public static String getWordRegex() { + return wordRegex; + } + public static void setWordRegex(String r) { + wordRegex = r; + } + + // Set the debug message level + public static void setMessageLevel(String msglevel) { + if (msglevel.equalsIgnoreCase("low")) + messageLevel = 1; + if (msglevel.equalsIgnoreCase("medium")) + messageLevel = 2; + if (msglevel.equalsIgnoreCase("high")) + messageLevel = 3; + if (msglevel.equalsIgnoreCase("extreme")) + messageLevel = 4; + settings.beginGroup("Debug"); + settings.setValue("messageLevel", msglevel); + settings.endGroup(); + } + + //**************************************************** + //**************************************************** + //** Save user account information from Evernote + //**************************************************** + //**************************************************** + public static void saveUserInformation(User user) { + settings.beginGroup("User"); + settings.setValue("id", user.getId()); + settings.setValue("username", user.getUsername()); + settings.setValue("email", user.getEmail()); + settings.setValue("name", user.getName()); + settings.setValue("timezone", user.getTimezone()); + settings.setValue("privilege", user.getPrivilege().getValue()); + settings.setValue("created", user.getCreated()); + settings.setValue("updated", user.getUpdated()); + settings.setValue("deleted", user.getDeleted()); + settings.setValue("shard", user.getShardId()); + settings.endGroup(); + isPremium(); + if (user.getAttributes()!=null) + saveUserAttributes(user.getAttributes()); + if (user.getAccounting()!=null) + saveUserAccounting(user.getAccounting()); + + } + public static User getUserInformation() { + User user = new User(); + settings.beginGroup("User"); + try { + user.setId((Integer)settings.value("id", 0)); + } catch (java.lang.ClassCastException e) { + user.setId(new Integer((String)settings.value("id", "0"))); + } + String username = (String)settings.value("username", ""); + String email = (String)settings.value("email", ""); + String name = (String)settings.value("name", ""); + String timezone = (String)settings.value("timezone", ""); + Integer privilege = 0; + try { + privilege = new Integer((String)settings.value("privilege", "0")); + } catch (java.lang.ClassCastException e) { + privilege = (Integer)settings.value("privilege", 0); + } + + try { + String date = (String)settings.value("created", "0"); + user.setCreated(new Long(date)); + date = (String)settings.value("updated", "0"); + user.setUpdated(new Long(date)); + date = (String)settings.value("deleted", "0"); + user.setDeleted(new Long(date)); + } catch (java.lang.ClassCastException e) { + Long date = (Long)settings.value("created", 0); + user.setCreated(date); + date = (Long)settings.value("updated", 0); + user.setUpdated(date); + date = (Long)settings.value("deleted", 0); + user.setDeleted(date); + } + + String shard = (String)settings.value("shard", ""); + settings.endGroup(); + + user.setUsername(username); + user.setEmail(email); + user.setName(name); + user.setTimezone(timezone); + PrivilegeLevel userLevel = PrivilegeLevel.findByValue(privilege); + user.setPrivilege(userLevel); + user.setShardId(shard); + return user; + } + + public static void saveUserAttributes(UserAttributes attrib) { + settings.beginGroup("UserAttributes"); + settings.setValue("defaultLocationName", attrib.getDefaultLocationName()); + settings.setValue("defaultLatitude", attrib.getDefaultLocationName()); + settings.setValue("defaultLongitude", attrib.getDefaultLocationName()); + settings.setValue("incomingEmailAddress", attrib.getIncomingEmailAddress()); + settings.endGroup(); + } + public static UserAttributes getUserAttributes() { + settings.beginGroup("UserAttributes"); + UserAttributes attrib = new UserAttributes(); + attrib.setDefaultLocationName((String)settings.value("defaultLocationName","")); + attrib.setDefaultLatitudeIsSet(false); + attrib.setDefaultLongitudeIsSet(false); + attrib.setIncomingEmailAddress((String)settings.value("incomingEmailAddress", "")); + settings.endGroup(); + return attrib; + } + public static void saveUserAccounting(Accounting acc) { + settings.beginGroup("UserAccounting"); + settings.setValue("uploadLimit", acc.getUploadLimit()); + settings.setValue("uploadLimitEnd", acc.getUploadLimitEnd()); + settings.setValue("uploadLimitNextMonth", acc.getUploadLimitNextMonth()); + settings.setValue("premiumServiceStart", acc.getPremiumServiceStart()); + settings.setValue("nextPaymentDue", acc.getNextPaymentDue()); + settings.setValue("uploadAmount", acc.getUpdated()); + settings.endGroup(); + } + public static long getUploadLimitEnd() { + Long limit; + settings.beginGroup("UserAccounting"); + + // Upload limit + try { + String val = (String)settings.value("uploadLimitEnd", "0"); + limit = new Long(val.trim()); + } catch (Exception e) { + try { + limit = (Long)settings.value("uploadLimitEnd", 0); + } catch (Exception e1) { + limit = new Long(0); + } + } + + // return value + settings.endGroup(); + return limit; + } + public static void saveUploadAmount(long amount) { + settings.beginGroup("UserAccounting"); + settings.setValue("uploadAmount", amount); + settings.endGroup(); + } + public static long getUploadAmount() { + long amt=0; + settings.beginGroup("UserAccounting"); + try { + String num = (String)settings.value("uploadAmount", "0"); + amt = new Long(num.trim()); + } catch (Exception e) { + try { + amt = (Integer)settings.value("uploadAmount", 0); + } catch (Exception e1) { + amt = 0; + } + } + settings.endGroup(); + return amt; + } + public static void saveEvernoteUpdateCount(long amount) { + settings.beginGroup("UserAccounting"); + settings.setValue("updateCount", amount); + settings.endGroup(); + } + public static long getEvernoteUpdateCount() { + long amt; + settings.beginGroup("UserAccounting"); + try { + String num = (String)settings.value("updateCount", new Long(0).toString()); + amt = new Long(num.trim()); + } catch (java.lang.ClassCastException e) { + amt = 0; + } + settings.endGroup(); + return amt; + } + public static boolean isPremium() { + int level; + settings.beginGroup("User"); + try { + String num = (String)settings.value("privilege", "1"); + level = new Integer(num.trim()); + } catch (java.lang.ClassCastException e) { + try { + level = (Integer)settings.value("privilege", 1); + } catch (Exception e1) { + level = 1; + } + } + settings.endGroup(); + PrivilegeLevel userLevel = PrivilegeLevel.findByValue(level); + if (userLevel == PrivilegeLevel.NORMAL) + return false; + return true; + + } + public static long getUploadLimit() { + settings.beginGroup("UserAccounting"); + long limit; + try { + String num = (String)settings.value("uploadLimit", new Long(0).toString()); + limit = new Long(num.trim()); + } catch (java.lang.ClassCastException e) { + limit = 0; + } + settings.endGroup(); + return limit; + } + + + + //**************************************************** + //**************************************************** + //** View settings. Used to restore settings + //** when starting and to control how the program + //** behaves. + //**************************************************** + //**************************************************** + + //* Get/Set if we should show a tray icon + public static boolean showTrayIcon() { + settings.beginGroup("General"); + try { + String max = (String) settings.value("showTrayIcon", "false"); + settings.endGroup(); + if (!max.equalsIgnoreCase("true") || !QSystemTrayIcon.isSystemTrayAvailable()) + return false; + else + return true; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("showTrayIcon", false); + settings.endGroup(); + return value; + } + } + public static void setShowTrayIcon(boolean val) { + settings.beginGroup("General"); + if (val) + settings.setValue("showTrayIcon", "true"); + else + settings.setValue("showTrayIcon", "false"); + settings.endGroup(); + } + + // Get/Set window maximized when closed last + public static boolean wasWindowMaximized() { + try { + settings.beginGroup("General"); + String max = (String) settings.value("isMaximized", "true"); + settings.endGroup(); + if (!max.equalsIgnoreCase("true")) + return false; + return true; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("isMaximized", true); + settings.endGroup(); + return value; + } + } + public static void saveWindowMaximized(boolean isMax) { + settings.beginGroup("General"); + if (isMax) + settings.setValue("isMaximized", "true"); + else + settings.setValue("isMaximized", "false"); + settings.endGroup(); + } + + // Get/set currently viewed note Guid + public static String getLastViewedNoteGuid() { + settings.beginGroup("General"); + String guid = (String) settings.value("lastViewedNote", ""); + settings.endGroup(); + return guid; + } + public static void saveCurrentNoteGuid(String guid) { + settings.beginGroup("General"); + if (guid != null) + settings.setValue("lastViewedNote", guid); + else + settings.setValue("lastViewedNote", ""); + settings.endGroup(); + } + + // Get/Set the note column we are sorted on and the order + public static void setSortColumn(int i) { + int view = Global.getListView(); + settings.beginGroup("General"); + if (view == Global.View_List_Wide) + settings.setValue("sortColumn", i); + else + settings.setValue("sortColumn-Narrow", i); + settings.endGroup(); + } + public static int getSortColumn() {; + String key; + if (Global.getListView() == Global.View_List_Wide) + key = "sortColumn"; + else + key = "sortColumn-Narrow"; + + settings.beginGroup("General"); + int order; + try { + String val = settings.value(key, new Integer(0)).toString(); + order = new Integer(val.trim()); + } catch (Exception e) { + try { + order = (Integer)settings.value(key, 0); + } catch (Exception e1) { + order = 0; + } + } + + settings.endGroup(); + return order; + } + public static void setSortOrder(int i) { + int view = Global.getListView(); + settings.beginGroup("General"); + if (view == Global.View_List_Wide) + settings.setValue("sortOrder", i); + else + settings.setValue("sortOrder-Narrow", i); + settings.endGroup(); + } + public static int getSortOrder() { + int view = Global.getListView(); + settings.beginGroup("General"); + String key; + if (view == Global.View_List_Wide) + key = "sortOrder"; + else + key = "sortOrder-Narrow"; + + int order; + try { + String val = settings.value(key, new Integer(0)).toString(); + order = new Integer(val.trim()); + } catch (Exception e) { + try { + order = (Integer)settings.value(key, 0); + } catch (Exception e1) { + order = 0; + } + } + + settings.endGroup(); + return order; + } + + // Should we automatically log in to Evernote when starting? + public static boolean automaticLogin() { + try { + settings.beginGroup("General"); + String text = (String)settings.value("automaticLogin", "false"); + settings.endGroup(); + if (text.equalsIgnoreCase("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("automaticLogin", false); + settings.endGroup(); + return value; + } + } + public static void setAutomaticLogin(boolean val) { + settings.beginGroup("General"); + if (val) + settings.setValue("automaticLogin", "true"); + else + settings.setValue("automaticLogin", "false"); + settings.endGroup(); + } + + // Get/set the Evernote server Url. + public static void setServer(String server) { + settings.beginGroup("General"); + settings.setValue("server", server); + settings.endGroup(); + } + public static String getServer() { + settings.beginGroup("General"); + String text = (String)settings.value("server", "www.evernote.com"); + if (text.equals("www.evernote.com")) { + userStoreUrl = "https://www.evernote.com/edam/user"; + noteStoreUrlBase = "www.evernote.com/edam/note/"; + } else { + userStoreUrl = "https://sandbox.evernote.com/edam/user"; + noteStoreUrlBase = "sandbox.evernote.com/edam/note/"; + } + settings.endGroup(); +// if (isPremium()) + noteStoreUrlBase = "https://" + noteStoreUrlBase; +// else +// noteStoreUrlBase = "http://" + noteStoreUrlBase; + return text; + } + + // Get/Set if we should disable uploads to Evernote + public static boolean disableUploads() { + settings.beginGroup("General"); + try { + String text = (String)settings.value("disableUploads", "false"); + settings.endGroup(); + if (text.equalsIgnoreCase("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("disableUploads", false); + settings.endGroup(); + return value; + } + } + public static void setDisableUploads(boolean val) { + settings.beginGroup("General"); + if (val) + settings.setValue("disableUploads", "true"); + else + settings.setValue("disableUploads", "false"); + settings.endGroup(); + disableUploads = val; + } + + // Should we view PDF documents inline? + public static boolean pdfPreview() { + settings.beginGroup("General"); + try { + String text = (String)settings.value("pdfPreview", "true"); + settings.endGroup(); + if (text.equalsIgnoreCase("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("pdfPreview", true); + settings.endGroup(); + return value; + } + } + public static void setPdfPreview(boolean val) { + settings.beginGroup("General"); + if (val) + settings.setValue("pdfPreview", "true"); + else + settings.setValue("pdfPreview", "false"); + settings.endGroup(); + } + + // When creating a new note, should it inherit tags that are currently selected? + public static boolean newNoteWithSelectedTags() { + settings.beginGroup("General"); + try { + String text = (String)settings.value("newNoteWithSelectedTags", "false"); + settings.endGroup(); + if (text.equalsIgnoreCase("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("newNoteWithSelectedTags", false); + settings.endGroup(); + return value; + } + } + public static void setNewNoteWithSelectedTags(boolean val) { + settings.beginGroup("General"); + if (val) + settings.setValue("newNoteWithSelectedTags", "true"); + else + settings.setValue("newNoteWithSelectedTags", "false"); + settings.endGroup(); + } + + // Minimum weight for text OCRed from Evernote. Anything below this + // Won't be shown to the user when they search + public static void setRecognitionWeight(int len) { + settings.beginGroup("General"); + settings.setValue("recognitionWeight", len); + settings.endGroup(); + } + public static int getRecognitionWeight() { + settings.beginGroup("General"); + Integer len; + try { len = (Integer)settings.value("recognitionWeight", 30); - } catch (Exception e) { + } catch (Exception e) { len = 80; - } - settings.endGroup(); - return len; - } - - // get/set current debug message level - public static String getMessageLevel() { - settings.beginGroup("Debug"); - String text = (String)settings.value("messageLevel", "Low"); - settings.endGroup(); - setMessageLevel(text); - return text; - } - public static void setDateFormat(String format) { - settings.beginGroup("General"); - settings.setValue("dateFormat", format); - settings.endGroup(); - } - - // Get/Set user date/time formats - public static String getDateFormat() { - settings.beginGroup("General"); - String text = (String)settings.value("dateFormat", "MM/dd/yyyy"); - settings.endGroup(); - return text; - } - public static void setTimeFormat(String format) { - settings.beginGroup("General"); - settings.setValue("timeFormat", format); - settings.endGroup(); - } - public static String getTimeFormat() { - settings.beginGroup("General"); - String text = (String)settings.value("timeFormat", "HH:mm:ss"); - settings.endGroup(); - return text; - } - - // How often should we sync with Evernote? - public static String getSyncInterval() { - settings.beginGroup("General"); - String text = (String)settings.value("syncInterval", "15 minutes"); - settings.endGroup(); - return text; - } - public static void setSyncInterval(String format) { - settings.beginGroup("General"); - settings.setValue("syncInterval", format); - settings.endGroup(); - } - - // Get/Set the width of columns and their position for the - // next start. - public static void setColumnWidth(String col, int width) { - if (Global.getListView() == Global.View_List_Wide) - settings.beginGroup("ColumnWidths"); - else - settings.beginGroup("ColumnWidths-Narrow"); - settings.setValue(col, width); - settings.endGroup(); - } - public static int getColumnWidth(String col) { - int view = Global.getListView(); - if (view == Global.View_List_Wide) - settings.beginGroup("ColumnWidths"); - else - settings.beginGroup("ColumnWidths-Narrow"); - Integer width; - try { - String val = (String)settings.value(col, "0"); - width = new Integer(val.trim()); - } catch (Exception e) { - try { - width = (Integer)settings.value(col, 0); - } catch (Exception e1) { - width = 0; - } - } - settings.endGroup(); - return width; - } - public static void setColumnPosition(String col, int width) { - if (Global.getListView() == Global.View_List_Wide) - settings.beginGroup("ColumnPosition"); - else - settings.beginGroup("ColumnPosition-Narrow"); - settings.setValue(col, width); - settings.endGroup(); - } - public static int getColumnPosition(String col) { - if (Global.getListView() == Global.View_List_Wide) - settings.beginGroup("ColumnPosition"); - else - settings.beginGroup("ColumnPosition-Narrow"); - Integer width; - try { - String val = (String)settings.value(col, "-1"); - width = new Integer(val.trim()); - } catch (Exception e) { - try { - width = (Integer)settings.value(col, 0); - } catch (Exception e1) { - width = 0; - } - } - settings.endGroup(); - return width; - } - - // Ping the user when they try to delete or just do it. - public static boolean verifyDelete() { - settings.beginGroup("General"); - try { - String text = (String)settings.value("verifyDelete", "true"); - settings.endGroup(); - if (text.equalsIgnoreCase("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value("verifyDelete", true); - settings.endGroup(); - return value; - } - } - public static void setVerifyDelete(boolean val) { - settings.beginGroup("General"); - if (val) - settings.setValue("verifyDelete", "true"); - else - settings.setValue("verifyDelete", "false"); - settings.endGroup(); - } - - // Should it start minimized? - public static boolean startMinimized() { - settings.beginGroup("General"); - try { - String text = (String)settings.value("startMinimized", "false"); - settings.endGroup(); - if (text.equalsIgnoreCase("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value("startMinimized", false); - settings.endGroup(); - return value; - } - } - public static void setStartMinimized(boolean val) { - settings.beginGroup("General"); - if (val) - settings.setValue("startMinimized", "true"); - else - settings.setValue("startMinimized", "false"); - settings.endGroup(); - } - - // Should we upload the content of any deleted notes - public static boolean synchronizeDeletedContent() { - settings.beginGroup("General"); - try { - String text = (String)settings.value("syncDeletedContent", "false"); - settings.endGroup(); - if (text.equalsIgnoreCase("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value("syncDeletedContent", false); - settings.endGroup(); - return value; - } - } - public static void setSynchronizeDeletedContent(boolean val) { - settings.beginGroup("General"); - if (val) - settings.setValue("syncDeletedContent", "true"); - else - settings.setValue("syncDeletedContent", "false"); - settings.endGroup(); - } - - // Is a section of the window visible? Used to hide things people don't - // want to see. - public static boolean isWindowVisible(String window) { - settings.beginGroup("WindowsVisible"); - try { - String defaultValue = "true"; - if (window.equalsIgnoreCase("noteInformation")) - defaultValue = "false"; - String text = (String)settings.value(window, defaultValue); - settings.endGroup(); - if (text.equalsIgnoreCase("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - boolean defaultValue = true; - if (window.equalsIgnoreCase("noteInformation")) - defaultValue = false; - Boolean value = (Boolean) settings.value("showTrayIcon", defaultValue); - settings.endGroup(); - return value; - } - } - public static void saveWindowVisible(String window, boolean val) { - settings.beginGroup("WindowsVisible"); - if (val) - settings.setValue(window, "true"); - else - settings.setValue(window, "false"); - settings.endGroup(); - } - - // Is a list in the column in the note list visible? - public static boolean isColumnVisible(String window) { - String defaultValue = "true"; - int view = Global.getListView(); - if (Global.getListView() == Global.View_List_Wide) - settings.beginGroup("ColumnsVisible"); - else - settings.beginGroup("ColumnsVisible-Narrow"); - if (window.equalsIgnoreCase("thumbnail") && view == Global.View_List_Wide) - defaultValue = "false"; - if (window.equalsIgnoreCase("thumbnail")) - defaultValue = "false"; - if (window.equalsIgnoreCase("Guid")) - defaultValue = "false"; - try { - String text = (String)settings.value(window, defaultValue); - settings.endGroup(); - if (text.equalsIgnoreCase("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - boolean defBool = false; - if (window.equalsIgnoreCase("true")) - defBool = true; - else - defBool = false; - Boolean value = (Boolean) settings.value(window, defBool); - settings.endGroup(); - return value; - } - } - public static void saveColumnVisible(String column, boolean val) { - if (Global.getListView() == Global.View_List_Wide) - settings.beginGroup("ColumnsVisible"); - else - settings.beginGroup("ColumnsVisible-Narrow"); - if (val) - settings.setValue(column, "true"); - else - settings.setValue(column, "false"); - settings.endGroup(); - } - - // Is a particular editor button visible? - public static boolean isEditorButtonVisible(String window) { - settings.beginGroup("EditorButtonsVisible"); - try { - String text = (String)settings.value(window, "true"); - settings.endGroup(); - if (text.equalsIgnoreCase("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value(window, true); - settings.endGroup(); - return value; - } - } - public static void saveEditorButtonsVisible(String column, boolean val) { - settings.beginGroup("EditorButtonsVisible"); - if (val) - settings.setValue(column, "true"); - else - settings.setValue(column, "false"); - settings.endGroup(); - } - - // Should the test fixes be enabled - public static boolean enableCarriageReturnFix() { - try { - settings.beginGroup("Debug"); - String text = (String)settings.value("enableCarriageReturnFix", "false"); - settings.endGroup(); - if (text.equalsIgnoreCase("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value("enableCarriageReturnFix", false); - settings.endGroup(); - return value; - } - } - public static void saveCarriageReturnFix(boolean val) { - settings.beginGroup("Debug"); - if (val) - settings.setValue("enableCarriageReturnFix", "true"); - else - settings.setValue("enableCarriageReturnFix", "false"); - settings.endGroup(); - } - public static boolean enableHtmlEntitiesFix() { - try { - settings.beginGroup("Debug"); - String text = (String)settings.value("enableHtmlEntitiesFix", "false"); - settings.endGroup(); - if (text.equalsIgnoreCase("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value("enableHtmlEntitiesFix", false); - settings.endGroup(); - return value; - } - } - public static void saveHtmlEntitiesFix(boolean val) { - settings.beginGroup("Debug"); - if (val) - settings.setValue("enableHtmlEntitiesFix", "true"); - else - settings.setValue("enableHtmlEntitiesFix", "false"); - settings.endGroup(); - } - -// public static void setIndexThreads(int val) { -// settings.beginGroup("General"); -// settings.setValue("indexThreads", val); -// settings.endGroup(); -// } -// public static int getIndexThreads() { -// settings.beginGroup("General"); -// Integer threads; -// try { -// String val = (String)settings.value("indexThreads", "1"); -// threads = new Integer(val.trim()); -// } catch (Exception e) { -// try { -// threads = (Integer)settings.value("indexThreads", 1); -// } catch (Exception e1) { -// threads = 1; -// } -// } -// settings.endGroup(); -// threads = 1; -// return threads; - - // Get/Set text zoom factor -// } - public static void setZoomFactor(double val) { - settings.beginGroup("General"); - settings.setValue("zoomFactor", val); - settings.endGroup(); - } - public static double getZoomFactor() { - settings.beginGroup("General"); - Double threads; - try { - String val = (String)settings.value("zoomFactor", "1.0"); - threads = new Double(val.trim()); - } catch (Exception e) { - try { - threads = (Double)settings.value("zoomFactor", 1.0); - } catch (Exception e1) { - threads = new Double(1); - } - } - settings.endGroup(); - return threads; - } - public static void setTextSizeMultiplier(double val) { - settings.beginGroup("General"); - settings.setValue("textMultiplier", val); - settings.endGroup(); - } - public static double getTextSizeMultiplier() { - settings.beginGroup("General"); - Double threads; - try { - String val = (String)settings.value("textMultiplier", "1"); - threads = new Double(val.trim()); - } catch (Exception e) { - try { - threads = (Double)settings.value("textMultiplier", 1); - } catch (Exception e1) { - threads = new Double(1); - } - } - settings.endGroup(); - return threads; - } - - - // Should we mimic Evernote and restrict the notebooks selected? - public static boolean getMimicEvernoteInterface() { - settings.beginGroup("General"); - try { - String text = (String)settings.value("mimicEvernoteInterface", "true"); - settings.endGroup(); - if (text.equalsIgnoreCase("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value("mimicEvernoteInterface", true); - settings.endGroup(); - return value; - } - } - public static void setMimicEvernoteInterface(boolean value) { - settings.beginGroup("General"); - if (value) - settings.setValue("mimicEvernoteInterface", "true"); - else - settings.setValue("mimicEvernoteInterface", "false"); - settings.endGroup(); - } - - - // Synchronize with Evernote when closing? - public static boolean synchronizeOnClose() { - settings.beginGroup("General"); - try { - String text = (String)settings.value("synchronizeOnClose", "false"); - settings.endGroup(); - if (text.equalsIgnoreCase("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value("synchronizeOnClose", false); - settings.endGroup(); - return value; - } - } - public static void setSynchronizeOnClose(boolean val) { - settings.beginGroup("General"); - if (val) - settings.setValue("synchronizeOnClose", "true"); - else - settings.setValue("synchronizeOnClose", "false"); - settings.endGroup(); - } - - // Get/set the database version. Not really used any more, but kept - // for compatibility. - public static void setDatabaseVersion(String version) { - settings.beginGroup("General"); - settings.setValue("databaseVersion", version); - settings.endGroup(); - } - public static String getDatabaseVersion() { - settings.beginGroup("General"); - String val = (String)settings.value("databaseVersion", "0.70"); - settings.endGroup(); - return val; - } - - // Get the URL (full path) of the main database - public static String getDatabaseUrl() { - settings.beginGroup("General"); - String val = (String)settings.value("DatabaseURL", ""); - settings.endGroup(); - if (val.equals("")) - val = "jdbc:h2:"+Global.getFileManager().getDbDirPath(Global.databaseName); - return val; - } - - // get the url (full path) of the searchable word database - public static String getIndexDatabaseUrl() { - settings.beginGroup("General"); - String val = (String)settings.value("IndexDatabaseURL", ""); - settings.endGroup(); - if (val.equals("")) - val = "jdbc:h2:"+Global.getFileManager().getDbDirPath(Global.indexDatabaseName); - return val; - } - - // Get the url (full path) of the attachment database - public static String getResourceDatabaseUrl() { - settings.beginGroup("General"); - String val = (String)settings.value("ResourceDatabaseURL", ""); - settings.endGroup(); - if (val.equals("")) - val = "jdbc:h2:"+Global.getFileManager().getDbDirPath(Global.resourceDatabaseName); - return val; - } - public static void setDatabaseUrl(String value) { - settings.beginGroup("General"); - settings.setValue("DatabaseURL", value); - settings.endGroup(); - } - public static void setIndexDatabaseUrl(String value) { - settings.beginGroup("General"); - settings.setValue("IndexDatabaseURL", value); - settings.endGroup(); - } - public static void setResourceDatabaseUrl(String value) { - settings.beginGroup("General"); - settings.setValue("ResourceDatabaseURL", value); - settings.endGroup(); - } - public static String getDatabaseUserid() { - settings.beginGroup("General"); - String val = (String)settings.value("databaseUserid", ""); - settings.endGroup(); - return val; - } - public static String getDatabaseUserPassword() { - settings.beginGroup("General"); - String val = (String)settings.value("databaseUserPassword", ""); - settings.endGroup(); - return val; - } - - // get/Set the style sheet and the palette to control the look & feel - public static void setStyle(String style) { - settings.beginGroup("General"); - settings.setValue("style", style); - settings.endGroup(); - } - public static String getStyle() { - settings.beginGroup("General"); - String val = (String)settings.value("style", "Cleanlooks"); - settings.endGroup(); - return val; - } - public static boolean useStandardPalette() { - settings.beginGroup("General"); - try { - String text = (String)settings.value("standardPalette", "true"); - settings.endGroup(); - if (text.equalsIgnoreCase("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value("standardPalette", true); - settings.endGroup(); - return value; - } - } - public static void setStandardPalette(boolean val) { - settings.beginGroup("General"); - if (val) - settings.setValue("standardPalette", "true"); - else - settings.setValue("standardPalette", "false"); - settings.endGroup(); - } - - // Set the amount of time to wait between indexing - // Get/Set interval when the index thread wakes up. - public static void setIndexThreadSleepInterval(int sleep) { - settings.beginGroup("General"); - settings.setValue("IndexThreadSleepInterval", sleep); - settings.endGroup(); - } - public static int getIndexThreadSleepInterval() { - settings.beginGroup("General"); - Integer sleep; - try { - String val = (String)settings.value("IndexThreadSleepInterval", "300"); - sleep = new Integer(val.trim()); - } catch (Exception e) { - try { - sleep = (Integer)settings.value("IndexThreadSleepInterval", 0); - } catch (Exception e1) { - sleep = 300; - } - } - settings.endGroup(); - return sleep; - } - - - // Get/Set a window state for later restoring - public static void saveState(String name, QByteArray state) { - int view = Global.getListView(); - if (view == Global.View_List_Narrow) - name = name +"Narrow"; - settings.beginGroup("SaveState"); - settings.setValue(name, state); - settings.endGroup(); - } - - public static QByteArray restoreState(String name) { - int view = Global.getListView(); - if (view == Global.View_List_Narrow) - name = name +"Narrow"; - settings.beginGroup("SaveState"); - QByteArray state = (QByteArray)settings.value(name); - settings.endGroup(); - return state; - } - public static void saveGeometry(String name, QByteArray state) { - int view = Global.getListView(); - if (view == Global.View_List_Narrow) - settings.beginGroup("SaveGeometryNarrow"); - else - settings.beginGroup("SaveGeometry"); - settings.setValue(name, state); - settings.endGroup(); - } - - public static QByteArray restoreGeometry(String name) { - int view = Global.getListView(); - if (view == Global.View_List_Narrow) - settings.beginGroup("SaveGeometryNarrow"); - else - settings.beginGroup("SaveGeometry"); - QByteArray state = (QByteArray)settings.value(name); - settings.endGroup(); - return state; - } - - - // Set how often to do an automatic save - public static void setAutoSaveInterval(int interval) { - settings.beginGroup("General"); - settings.setValue("autoSaveInterval", interval); - settings.endGroup(); - } - public static int getAutoSaveInterval() { - settings.beginGroup("General"); - Integer value; - try { - String val = (String)settings.value("autoSaveInterval", "5"); - value = new Integer(val.trim()); - } catch (Exception e) { - try { - value = (Integer)settings.value("autoSaveInterval", 5); - } catch (Exception e1) { - value = 5; - } - } - settings.endGroup(); - return value; - } - - // Add an invalid attribute & element to the database so we don't bother parsing it in the future - // These values we automatically remove from any note. - // Add invalid attributes - public static void addInvalidAttribute(String element, String attribute) { - - List attributes = invalidAttributes.get(element); - if (attributes != null) { - for (int i=0; i attributeList; - if (!invalidAttributes.containsKey(element)) { - attributeList = new ArrayList(); - attributeList.add(attribute); - invalidAttributes.put(element, attributeList); - } - else { - attributeList = invalidAttributes.get(element); - attributeList.add(attribute); - invalidAttributes.put(element,attributeList); - } - } - - // Add invalid attributes - public static void addInvalidElement(String element) { - for (int i=0; i>> 4) & 0x0F; - int two_halfs = 0; - do { - if ((0 <= halfbyte) && (halfbyte <= 9)) - buf.append((char) ('0' + halfbyte)); - else - buf.append((char) ('a' + (halfbyte - 10))); - halfbyte = element & 0x0F; - } while(two_halfs++ < 1); - } - return buf.toString(); - } - - - // Get/Set spelling settings - public static boolean getSpellSetting(String value) { - settings.beginGroup("Spell"); - String text = (String)settings.value(value, ""); - settings.endGroup(); - if (text.equalsIgnoreCase("true")) - return true; - if (text.equalsIgnoreCase("false")) - return false; - if (value.equalsIgnoreCase(Configuration.SPELL_IGNOREDIGITWORDS)) - return true; - if (value.equalsIgnoreCase(Configuration.SPELL_IGNOREINTERNETADDRESSES)) - return true; - if (value.equalsIgnoreCase(Configuration.SPELL_IGNOREUPPERCASE)) - return true; - if (value.equalsIgnoreCase(Configuration.SPELL_IGNORESENTENCECAPITALIZATION)) - return true; - return false; - } - public static void setSpellSetting(String setting, boolean val) { - settings.beginGroup("Spell"); - if (val) - settings.setValue(setting, "true"); - else - settings.setValue(setting, "false"); - settings.endGroup(); - } - - // Get/Set how we should display tags (color them, hide unused, or do nothing) - // What to do with inactive tags? - public static String tagBehavior() { - settings.beginGroup("General"); - String text = (String)settings.value("tagBehavior", "DoNothing"); - settings.endGroup(); - return text; - } - // What to do with inactive tags? - public static void setTagBehavior(String value) { - settings.beginGroup("General"); - settings.setValue("tagBehavior", value); - settings.endGroup(); - } - - - // Should the toolbar be visible? - public static boolean isToolbarButtonVisible(String window) { - settings.beginGroup("ToolbarButtonsVisible"); - try { - String text = (String)settings.value(window, "true"); - settings.endGroup(); - if (text.equalsIgnoreCase("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value(window, true); - settings.endGroup(); - return value; - } - } - public static void saveToolbarButtonsVisible(String column, boolean val) { - settings.beginGroup("ToolbarButtonsVisible"); - if (val) - settings.setValue(column, "true"); - else - settings.setValue(column, "false"); - settings.endGroup(); - } - - // Are thumbnails enabled? - - public static boolean enableThumbnails() { - settings.beginGroup("Debug"); - try { - String text = (String)settings.value("thumbnails", "true"); - settings.endGroup(); - if (text.equalsIgnoreCase("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value("thumbnails", true); - settings.endGroup(); - return value; - } - } - public static void setEnableThumbnails(boolean val) { - settings.beginGroup("Debug"); - if (val) - settings.setValue("thumbnails", "true"); - else - settings.setValue("thumbnails", "false"); - settings.endGroup(); - } - - // Trace used for performance tuning. Not normally used in production. - // Print date/time. Used mainly for performance tracing - public static void trace(boolean resetInterval) { - String fmt = "MM/dd/yy HH:mm:ss.SSSSSS"; - String dateTimeFormat = new String(fmt); - SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat); - Calendar cal = Calendar.getInstance(); - if (intervalTraceTime == null) - intervalTraceTime = Calendar.getInstance(); - if (startTraceTime == null) - startTraceTime = Calendar.getInstance(); - - float interval = (cal.getTimeInMillis() - intervalTraceTime.getTimeInMillis()); - float total = (cal.getTimeInMillis() - startTraceTime.getTimeInMillis()); - -// if (interval > 00.0) { - StackTraceElement[] exceptions = Thread.currentThread().getStackTrace(); - System.out.println("------------------------------------------"); - - System.out.println("Date/Time " +simple.format(cal.getTime())); - System.out.format("Interval Time: %-10.6f%n", interval); - System.out.format("Total Time: %-10.6f%n", total); - for (int i=2; i<5 && i", "")); - zoom = 2; - if (text.length() < 500) - zoom = 2; - if (text.length() < 250) - zoom = 3; - if (text.length() < 100) - zoom = 4; - if (text.length() < 50) - zoom = 5; - if (text.length() < 10) - zoom = 6; - } - } - return zoom; - } - - //********************** - //* List View settings - //********************** - public static void setListView(int view) { - settings.beginGroup("General"); - settings.setValue("listView", view); - settings.endGroup(); - } - public static int getListView() { - settings.beginGroup("General"); - Integer value; - try { - String val = (String)settings.value("listView", View_List_Wide); - value = new Integer(val.trim()); - } catch (Exception e) { - try { - value = (Integer)settings.value("listView", View_List_Wide); - } catch (Exception e1) { - value = View_List_Wide; - } - } - settings.endGroup(); - return value; - } - - - - //******************* - // Font Settings - //******************* - public static boolean overrideDefaultFont() { - settings.beginGroup("Font"); - try { - String text = (String)settings.value("overrideFont", "false"); - settings.endGroup(); - if (text.equalsIgnoreCase("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value("overrideFont", false); - settings.endGroup(); - return value; - } - - } - - //**************************************************** - // Get/Set the default font settings for a new note - //**************************************************** - public static void setOverrideDefaultFont(boolean value) { - settings.beginGroup("Font"); - settings.setValue("overrideFont", value); - settings.endGroup(); - } - public static String getDefaultFont() { - settings.beginGroup("Font"); - String val = (String)settings.value("font", ""); - settings.endGroup(); - return val; - } - public static void setDefaultFont(String value) { - settings.beginGroup("Font"); - settings.setValue("font", value); - settings.endGroup(); - } - public static String getDefaultFontSize() { - settings.beginGroup("Font"); - String val = (String)settings.value("fontSize", ""); - settings.endGroup(); - return val; - } - public static void setDefaultFontSize(String value) { - settings.beginGroup("Font"); - settings.setValue("fontSize", value); - settings.endGroup(); - } - - - //******************************************* - // Override the close & minimize instead. - //******************************************* - public static boolean minimizeOnClose() { - settings.beginGroup("General"); - try { - String text = (String)settings.value("minimizeOnClose", "false"); - settings.endGroup(); - if (text.equalsIgnoreCase("true") && QSystemTrayIcon.isSystemTrayAvailable()) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value("minimizeOnClose", false); - settings.endGroup(); - return value; - } - } - public static void setMinimizeOnClose(boolean value) { - settings.beginGroup("General"); - settings.setValue("minimizeOnClose", value); - settings.endGroup(); - } - - //********************************* - // Check version information - //********************************* - public static boolean checkVersionUpgrade() { - settings.beginGroup("Upgrade"); - try { - String text = (String)settings.value("checkForUpdates", "true"); - settings.endGroup(); - if (text.equalsIgnoreCase("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value("checkForUpdates", true); - settings.endGroup(); - return value; - } - } - public static void setCheckVersionUpgrade(boolean value) { - settings.beginGroup("Upgrade"); - settings.setValue("checkForUpdates", value); - settings.endGroup(); - } - public static String getUpdatesAvailableUrl() { - settings.beginGroup("Upgrade"); - String text = (String)settings.value("avialableUrl", "http://nevernote.sourceforge.net/versions.txt"); - settings.endGroup(); - return text; - } - public static String getUpdateAnnounceUrl() { - settings.beginGroup("Upgrade"); - String text = (String)settings.value("announceUrl", "http://nevernote.sourceforge.net/upgrade.html"); - settings.endGroup(); - return text; - } - - //******************* - // Index settings - //******************* - // Set/Get if we should index the text of a note - public static boolean indexNoteBody() { - settings.beginGroup("Index"); - try { - String value = (String)settings.value("indexNoteBody", "true"); - settings.endGroup(); - if (value.equals("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value("indexNoteBody", true); - settings.endGroup(); - return value; - } - } - public static void setIndexNoteTitle(boolean value) { - settings.beginGroup("Index"); - settings.setValue("indexNoteTitle", value); - settings.endGroup(); - } - // Set/Get if we should index the title of a note - public static boolean indexNoteTitle() { - settings.beginGroup("Index"); - try { - String value = (String)settings.value("indexNoteTitle", "true"); - settings.endGroup(); - if (value.equals("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value("indexNoteTitle", true); - settings.endGroup(); - return value; - } - } - public static void setIndexNoteBody(boolean value) { - settings.beginGroup("Index"); - settings.setValue("indexNoteBody", value); - settings.endGroup(); - } - // Set/Get if we should index any attachments - public static boolean indexAttachmentsLocally() { - settings.beginGroup("Index"); - try { - String value = (String)settings.value("indexAttachmentsLocally", "true"); - settings.endGroup(); - if (value.equals("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value("indexAttachmentsLocally", true); - settings.endGroup(); - return value; - } - } - public static void setIndexImageRecognition(boolean value) { - settings.beginGroup("Index"); - settings.setValue("indexImageRecognition", value); - settings.endGroup(); - } - public static boolean indexImageRecognition() { - settings.beginGroup("Index"); - try { - String value = (String)settings.value("indexImageRecognition", "true"); - settings.endGroup(); - if (value.equals("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value("indexImageRecognition", true); - settings.endGroup(); - return value; - } - } - public static void setIndexAttachmentsLocally(boolean value) { - settings.beginGroup("Index"); - settings.setValue("indexAttachmentsLocally", value); - settings.endGroup(); - } - // Get/Set characters that shouldn't be removed from a word - public static String getSpecialIndexCharacters() { - settings.beginGroup("Index"); - String text = (String)settings.value("specialCharacters", ""); - settings.endGroup(); - return text; - } - public static void setSpecialIndexCharacters(String value) { - settings.beginGroup("Index"); - settings.setValue("specialCharacters", value); - settings.endGroup(); - databaseCache = value; - } - - //***************************************************************************** - // Control how tag selection behaves (should they be "and" or "or" selections - //***************************************************************************** - public static boolean anyTagSelectionMatch() { - settings.beginGroup("General"); - try { - String value = (String)settings.value("anyTagSelectionMatch", "false"); - settings.endGroup(); - if (value.equals("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value("anyTagSelectionMatch", false); - settings.endGroup(); - return value; - } - } - public static void setAnyTagSelectionMatch(boolean value) { - settings.beginGroup("General"); - settings.setValue("anyTagSelectionMatch", value); - settings.endGroup(); - } - - //***************************************************************************** - // Control if a user receives a warning when trying to create a note-to-note link - // when the DB is not synchronized. - //***************************************************************************** - public static boolean bypassSynchronizationWarning() { - settings.beginGroup("User"); - try { - String value = (String)settings.value("bypassSynchronizationWarning", "false"); - settings.endGroup(); - if (value.equals("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value("bypassSynchronizationWarning", false); - settings.endGroup(); - return value; - } - } - public static void setBypassSynchronizationWarning(boolean value) { - settings.beginGroup("User"); - settings.setValue("bypassSynchronizationWarning", value); - settings.endGroup(); - } - - - //*********************** - //* Database cache size - //*********************** - public static String getDatabaseCacheSize() { - settings.beginGroup("Debug"); - String text = (String)settings.value("databaseCache", "16384"); - settings.endGroup(); - return text; - } - public static void setDatabaseCache(String value) { - settings.beginGroup("Debug"); - settings.setValue("databaseCache", value); - settings.endGroup(); - databaseCache = value; - } - - - // This is used to copy a class since Java's normal deep copy is wacked - public static Object deepCopy(Object oldObj) - { - ObjectOutputStream oos = null; - ObjectInputStream ois = null; - try - { - ByteArrayOutputStream bos = - new ByteArrayOutputStream(); // A - oos = new ObjectOutputStream(bos); // B - // serialize and pass the object - oos.writeObject(oldObj); // C - oos.flush(); // D - ByteArrayInputStream bin = - new ByteArrayInputStream(bos.toByteArray()); // E - ois = new ObjectInputStream(bin); // F - // return the new object - return ois.readObject(); // G - } - catch(Exception e) - { - Global.logger.log(logger.LOW, "Exception in ObjectCloner = " + e); - } - try { - oos.close(); - ois.close(); - } catch (IOException e) { - Global.logger.log(logger.LOW, "Exception in ObjectCloner = " + e); - e.printStackTrace(); - } - - return null; - } - - // If we should automatically select the children of any tag - public static boolean includeTagChildren() { - settings.beginGroup("General"); - try { - String value = (String)settings.value("includeTagChildren", "false"); - settings.endGroup(); - if (value.equals("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value("includeTagChildren", false); - settings.endGroup(); - return value; - } - - } - public static void setIncludeTagChildren(boolean value) { - settings.beginGroup("General"); - settings.setValue("includeTagChildren", value); - settings.endGroup(); - } - - // If we should automatically wildcard searches - public static boolean automaticWildcardSearches() { - settings.beginGroup("General"); - try { - String value = (String)settings.value("automaticWildcard", "false"); - settings.endGroup(); - if (value.equals("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value("automaticWildcard", false); - settings.endGroup(); - return value; - } - - } - public static void setAutomaticWildcardSearches(boolean value) { - settings.beginGroup("General"); - settings.setValue("automaticWildcard", value); - settings.endGroup(); - } - - // If we should automatically select the children of any tag - public static boolean displayRightToLeft() { - settings.beginGroup("General"); - try { - String value = (String)settings.value("displayRightToLeft", "false"); - settings.endGroup(); - if (value.equals("true")) - return true; - else - return false; - } catch (java.lang.ClassCastException e) { - Boolean value = (Boolean) settings.value("displayRightToLeft", false); - settings.endGroup(); - return value; - } - - } - public static void setDisplayRightToLeft(boolean value) { - settings.beginGroup("General"); - settings.setValue("displayRightToLeft", value); - settings.endGroup(); - } - - - //*********************** - //* Startup Notebook - //*********************** - public static String getStartupNotebook() { - settings.beginGroup("General"); - String text = (String)settings.value("startupNotebook", ""); - settings.endGroup(); - return text; - } - public static void setStartupNotebook(String value) { - settings.beginGroup("General"); - settings.setValue("startupNotebook", value); - settings.endGroup(); - databaseCache = value; - } -} - + } + settings.endGroup(); + return len; + } + + // get/set current debug message level + public static String getMessageLevel() { + settings.beginGroup("Debug"); + String text = (String)settings.value("messageLevel", "Low"); + settings.endGroup(); + setMessageLevel(text); + return text; + } + public static void setDateFormat(String format) { + settings.beginGroup("General"); + settings.setValue("dateFormat", format); + settings.endGroup(); + } + + // Get/Set user date/time formats + public static String getDateFormat() { + settings.beginGroup("General"); + String text = (String)settings.value("dateFormat", "MM/dd/yyyy"); + settings.endGroup(); + return text; + } + public static void setTimeFormat(String format) { + settings.beginGroup("General"); + settings.setValue("timeFormat", format); + settings.endGroup(); + } + public static String getTimeFormat() { + settings.beginGroup("General"); + String text = (String)settings.value("timeFormat", "HH:mm:ss"); + settings.endGroup(); + return text; + } + + // How often should we sync with Evernote? + public static String getSyncInterval() { + settings.beginGroup("General"); + String text = (String)settings.value("syncInterval", "15 minutes"); + settings.endGroup(); + return text; + } + public static void setSyncInterval(String format) { + settings.beginGroup("General"); + settings.setValue("syncInterval", format); + settings.endGroup(); + } + + // Get/Set the width of columns and their position for the + // next start. + public static void setColumnWidth(String col, int width) { + if (Global.getListView() == Global.View_List_Wide) + settings.beginGroup("ColumnWidths"); + else + settings.beginGroup("ColumnWidths-Narrow"); + settings.setValue(col, width); + settings.endGroup(); + } + public static int getColumnWidth(String col) { + int view = Global.getListView(); + if (view == Global.View_List_Wide) + settings.beginGroup("ColumnWidths"); + else + settings.beginGroup("ColumnWidths-Narrow"); + Integer width; + try { + String val = (String)settings.value(col, "0"); + width = new Integer(val.trim()); + } catch (Exception e) { + try { + width = (Integer)settings.value(col, 0); + } catch (Exception e1) { + width = 0; + } + } + settings.endGroup(); + return width; + } + public static void setColumnPosition(String col, int width) { + if (Global.getListView() == Global.View_List_Wide) + settings.beginGroup("ColumnPosition"); + else + settings.beginGroup("ColumnPosition-Narrow"); + settings.setValue(col, width); + settings.endGroup(); + } + public static int getColumnPosition(String col) { + if (Global.getListView() == Global.View_List_Wide) + settings.beginGroup("ColumnPosition"); + else + settings.beginGroup("ColumnPosition-Narrow"); + Integer width; + try { + String val = (String)settings.value(col, "-1"); + width = new Integer(val.trim()); + } catch (Exception e) { + try { + width = (Integer)settings.value(col, 0); + } catch (Exception e1) { + width = 0; + } + } + settings.endGroup(); + return width; + } + + // Ping the user when they try to delete or just do it. + public static boolean verifyDelete() { + settings.beginGroup("General"); + try { + String text = (String)settings.value("verifyDelete", "true"); + settings.endGroup(); + if (text.equalsIgnoreCase("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("verifyDelete", true); + settings.endGroup(); + return value; + } + } + public static void setVerifyDelete(boolean val) { + settings.beginGroup("General"); + if (val) + settings.setValue("verifyDelete", "true"); + else + settings.setValue("verifyDelete", "false"); + settings.endGroup(); + } + + // Should it start minimized? + public static boolean startMinimized() { + settings.beginGroup("General"); + try { + String text = (String)settings.value("startMinimized", "false"); + settings.endGroup(); + if (text.equalsIgnoreCase("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("startMinimized", false); + settings.endGroup(); + return value; + } + } + public static void setStartMinimized(boolean val) { + settings.beginGroup("General"); + if (val) + settings.setValue("startMinimized", "true"); + else + settings.setValue("startMinimized", "false"); + settings.endGroup(); + } + + // Should we upload the content of any deleted notes + public static boolean synchronizeDeletedContent() { + settings.beginGroup("General"); + try { + String text = (String)settings.value("syncDeletedContent", "false"); + settings.endGroup(); + if (text.equalsIgnoreCase("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("syncDeletedContent", false); + settings.endGroup(); + return value; + } + } + public static void setSynchronizeDeletedContent(boolean val) { + settings.beginGroup("General"); + if (val) + settings.setValue("syncDeletedContent", "true"); + else + settings.setValue("syncDeletedContent", "false"); + settings.endGroup(); + } + + // Is a section of the window visible? Used to hide things people don't + // want to see. + public static boolean isWindowVisible(String window) { + settings.beginGroup("WindowsVisible"); + try { + String defaultValue = "true"; + if (window.equalsIgnoreCase("noteInformation")) + defaultValue = "false"; + String text = (String)settings.value(window, defaultValue); + settings.endGroup(); + if (text.equalsIgnoreCase("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + boolean defaultValue = true; + if (window.equalsIgnoreCase("noteInformation")) + defaultValue = false; + Boolean value = (Boolean) settings.value("showTrayIcon", defaultValue); + settings.endGroup(); + return value; + } + } + public static void saveWindowVisible(String window, boolean val) { + settings.beginGroup("WindowsVisible"); + if (val) + settings.setValue(window, "true"); + else + settings.setValue(window, "false"); + settings.endGroup(); + } + + // Is a list in the column in the note list visible? + public static boolean isColumnVisible(String window) { + String defaultValue = "true"; + int view = Global.getListView(); + if (Global.getListView() == Global.View_List_Wide) + settings.beginGroup("ColumnsVisible"); + else + settings.beginGroup("ColumnsVisible-Narrow"); + if (window.equalsIgnoreCase("thumbnail") && view == Global.View_List_Wide) + defaultValue = "false"; + if (window.equalsIgnoreCase("thumbnail")) + defaultValue = "false"; + if (window.equalsIgnoreCase("Guid")) + defaultValue = "false"; + try { + String text = (String)settings.value(window, defaultValue); + settings.endGroup(); + if (text.equalsIgnoreCase("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + boolean defBool = false; + if (window.equalsIgnoreCase("true")) + defBool = true; + else + defBool = false; + Boolean value = (Boolean) settings.value(window, defBool); + settings.endGroup(); + return value; + } + } + public static void saveColumnVisible(String column, boolean val) { + if (Global.getListView() == Global.View_List_Wide) + settings.beginGroup("ColumnsVisible"); + else + settings.beginGroup("ColumnsVisible-Narrow"); + if (val) + settings.setValue(column, "true"); + else + settings.setValue(column, "false"); + settings.endGroup(); + } + + // Is a particular editor button visible? + public static boolean isEditorButtonVisible(String window) { + settings.beginGroup("EditorButtonsVisible"); + try { + String text = (String)settings.value(window, "true"); + settings.endGroup(); + if (text.equalsIgnoreCase("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value(window, true); + settings.endGroup(); + return value; + } + } + public static void saveEditorButtonsVisible(String column, boolean val) { + settings.beginGroup("EditorButtonsVisible"); + if (val) + settings.setValue(column, "true"); + else + settings.setValue(column, "false"); + settings.endGroup(); + } + + // Should the test fixes be enabled + public static boolean enableCarriageReturnFix() { + try { + settings.beginGroup("Debug"); + String text = (String)settings.value("enableCarriageReturnFix", "false"); + settings.endGroup(); + if (text.equalsIgnoreCase("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("enableCarriageReturnFix", false); + settings.endGroup(); + return value; + } + } + public static void saveCarriageReturnFix(boolean val) { + settings.beginGroup("Debug"); + if (val) + settings.setValue("enableCarriageReturnFix", "true"); + else + settings.setValue("enableCarriageReturnFix", "false"); + settings.endGroup(); + } + public static boolean enableHtmlEntitiesFix() { + try { + settings.beginGroup("Debug"); + String text = (String)settings.value("enableHtmlEntitiesFix", "false"); + settings.endGroup(); + if (text.equalsIgnoreCase("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("enableHtmlEntitiesFix", false); + settings.endGroup(); + return value; + } + } + public static void saveHtmlEntitiesFix(boolean val) { + settings.beginGroup("Debug"); + if (val) + settings.setValue("enableHtmlEntitiesFix", "true"); + else + settings.setValue("enableHtmlEntitiesFix", "false"); + settings.endGroup(); + } + +// public static void setIndexThreads(int val) { +// settings.beginGroup("General"); +// settings.setValue("indexThreads", val); +// settings.endGroup(); +// } +// public static int getIndexThreads() { +// settings.beginGroup("General"); +// Integer threads; +// try { +// String val = (String)settings.value("indexThreads", "1"); +// threads = new Integer(val.trim()); +// } catch (Exception e) { +// try { +// threads = (Integer)settings.value("indexThreads", 1); +// } catch (Exception e1) { +// threads = 1; +// } +// } +// settings.endGroup(); +// threads = 1; +// return threads; + + // Get/Set text zoom factor +// } + public static void setZoomFactor(double val) { + settings.beginGroup("General"); + settings.setValue("zoomFactor", val); + settings.endGroup(); + } + public static double getZoomFactor() { + settings.beginGroup("General"); + Double threads; + try { + String val = (String)settings.value("zoomFactor", "1.0"); + threads = new Double(val.trim()); + } catch (Exception e) { + try { + threads = (Double)settings.value("zoomFactor", 1.0); + } catch (Exception e1) { + threads = new Double(1); + } + } + settings.endGroup(); + return threads; + } + public static void setTextSizeMultiplier(double val) { + settings.beginGroup("General"); + settings.setValue("textMultiplier", val); + settings.endGroup(); + } + public static double getTextSizeMultiplier() { + settings.beginGroup("General"); + Double threads; + try { + String val = (String)settings.value("textMultiplier", "1"); + threads = new Double(val.trim()); + } catch (Exception e) { + try { + threads = (Double)settings.value("textMultiplier", 1); + } catch (Exception e1) { + threads = new Double(1); + } + } + settings.endGroup(); + return threads; + } + + + // Should we mimic Evernote and restrict the notebooks selected? + public static boolean getMimicEvernoteInterface() { + settings.beginGroup("General"); + try { + String text = (String)settings.value("mimicEvernoteInterface", "true"); + settings.endGroup(); + if (text.equalsIgnoreCase("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("mimicEvernoteInterface", true); + settings.endGroup(); + return value; + } + } + public static void setMimicEvernoteInterface(boolean value) { + settings.beginGroup("General"); + if (value) + settings.setValue("mimicEvernoteInterface", "true"); + else + settings.setValue("mimicEvernoteInterface", "false"); + settings.endGroup(); + } + + + // Synchronize with Evernote when closing? + public static boolean synchronizeOnClose() { + settings.beginGroup("General"); + try { + String text = (String)settings.value("synchronizeOnClose", "false"); + settings.endGroup(); + if (text.equalsIgnoreCase("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("synchronizeOnClose", false); + settings.endGroup(); + return value; + } + } + public static void setSynchronizeOnClose(boolean val) { + settings.beginGroup("General"); + if (val) + settings.setValue("synchronizeOnClose", "true"); + else + settings.setValue("synchronizeOnClose", "false"); + settings.endGroup(); + } + + // Get/set the database version. Not really used any more, but kept + // for compatibility. + public static void setDatabaseVersion(String version) { + settings.beginGroup("General"); + settings.setValue("databaseVersion", version); + settings.endGroup(); + } + public static String getDatabaseVersion() { + settings.beginGroup("General"); + String val = (String)settings.value("databaseVersion", "0.70"); + settings.endGroup(); + return val; + } + + // Get the URL (full path) of the main database + public static String getDatabaseUrl() { + settings.beginGroup("General"); + String val = (String)settings.value("DatabaseURL", ""); + settings.endGroup(); + if (val.equals("")) + val = "jdbc:h2:"+Global.getFileManager().getDbDirPath(Global.databaseName); + return val; + } + + // get the url (full path) of the searchable word database + public static String getIndexDatabaseUrl() { + settings.beginGroup("General"); + String val = (String)settings.value("IndexDatabaseURL", ""); + settings.endGroup(); + if (val.equals("")) + val = "jdbc:h2:"+Global.getFileManager().getDbDirPath(Global.indexDatabaseName); + return val; + } + + // Get the url (full path) of the attachment database + public static String getResourceDatabaseUrl() { + settings.beginGroup("General"); + String val = (String)settings.value("ResourceDatabaseURL", ""); + settings.endGroup(); + if (val.equals("")) + val = "jdbc:h2:"+Global.getFileManager().getDbDirPath(Global.resourceDatabaseName); + return val; + } + + // ICHANGED + // 操作履歴データベースのURL(フルパス)をゲット + public static String getBehaviorDatabaseUrl() { + settings.beginGroup("General"); + String val = (String) settings.value("BehaviorDatabaseURL", ""); + settings.endGroup(); + if (val.equals("")) + val = "jdbc:h2:" + + Global.getFileManager().getDbDirPath( + Global.behaviorDatabaseName); + return val; + } + + public static void setDatabaseUrl(String value) { + settings.beginGroup("General"); + settings.setValue("DatabaseURL", value); + settings.endGroup(); + } + public static void setIndexDatabaseUrl(String value) { + settings.beginGroup("General"); + settings.setValue("IndexDatabaseURL", value); + settings.endGroup(); + } + public static void setResourceDatabaseUrl(String value) { + settings.beginGroup("General"); + settings.setValue("ResourceDatabaseURL", value); + settings.endGroup(); + } + + // ICHANGED + public static void setBehaviorDatabaseUrl(String value) { + settings.beginGroup("General"); + settings.setValue("BehaviorDatabaseURL", value); + settings.endGroup(); + } + + public static String getDatabaseUserid() { + settings.beginGroup("General"); + String val = (String)settings.value("databaseUserid", ""); + settings.endGroup(); + return val; + } + public static String getDatabaseUserPassword() { + settings.beginGroup("General"); + String val = (String)settings.value("databaseUserPassword", ""); + settings.endGroup(); + return val; + } + + // get/Set the style sheet and the palette to control the look & feel + public static void setStyle(String style) { + settings.beginGroup("General"); + settings.setValue("style", style); + settings.endGroup(); + } + public static String getStyle() { + settings.beginGroup("General"); + String val = (String)settings.value("style", "Cleanlooks"); + settings.endGroup(); + return val; + } + public static boolean useStandardPalette() { + settings.beginGroup("General"); + try { + String text = (String)settings.value("standardPalette", "true"); + settings.endGroup(); + if (text.equalsIgnoreCase("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("standardPalette", true); + settings.endGroup(); + return value; + } + } + public static void setStandardPalette(boolean val) { + settings.beginGroup("General"); + if (val) + settings.setValue("standardPalette", "true"); + else + settings.setValue("standardPalette", "false"); + settings.endGroup(); + } + + // Set the amount of time to wait between indexing + // Get/Set interval when the index thread wakes up. + public static void setIndexThreadSleepInterval(int sleep) { + settings.beginGroup("General"); + settings.setValue("IndexThreadSleepInterval", sleep); + settings.endGroup(); + } + public static int getIndexThreadSleepInterval() { + settings.beginGroup("General"); + Integer sleep; + try { + String val = (String)settings.value("IndexThreadSleepInterval", "300"); + sleep = new Integer(val.trim()); + } catch (Exception e) { + try { + sleep = (Integer)settings.value("IndexThreadSleepInterval", 0); + } catch (Exception e1) { + sleep = 300; + } + } + settings.endGroup(); + return sleep; + } + + + // Get/Set a window state for later restoring + public static void saveState(String name, QByteArray state) { + int view = Global.getListView(); + if (view == Global.View_List_Narrow) + name = name +"Narrow"; + settings.beginGroup("SaveState"); + settings.setValue(name, state); + settings.endGroup(); + } + + public static QByteArray restoreState(String name) { + int view = Global.getListView(); + if (view == Global.View_List_Narrow) + name = name +"Narrow"; + settings.beginGroup("SaveState"); + QByteArray state = (QByteArray)settings.value(name); + settings.endGroup(); + return state; + } + public static void saveGeometry(String name, QByteArray state) { + int view = Global.getListView(); + if (view == Global.View_List_Narrow) + settings.beginGroup("SaveGeometryNarrow"); + else + settings.beginGroup("SaveGeometry"); + settings.setValue(name, state); + settings.endGroup(); + } + + public static QByteArray restoreGeometry(String name) { + int view = Global.getListView(); + if (view == Global.View_List_Narrow) + settings.beginGroup("SaveGeometryNarrow"); + else + settings.beginGroup("SaveGeometry"); + QByteArray state = (QByteArray)settings.value(name); + settings.endGroup(); + return state; + } + + + // Set how often to do an automatic save + public static void setAutoSaveInterval(int interval) { + settings.beginGroup("General"); + settings.setValue("autoSaveInterval", interval); + settings.endGroup(); + } + public static int getAutoSaveInterval() { + settings.beginGroup("General"); + Integer value; + try { + String val = (String)settings.value("autoSaveInterval", "5"); + value = new Integer(val.trim()); + } catch (Exception e) { + try { + value = (Integer)settings.value("autoSaveInterval", 5); + } catch (Exception e1) { + value = 5; + } + } + settings.endGroup(); + return value; + } + + // Add an invalid attribute & element to the database so we don't bother parsing it in the future + // These values we automatically remove from any note. + // Add invalid attributes + public static void addInvalidAttribute(String element, String attribute) { + + List attributes = invalidAttributes.get(element); + if (attributes != null) { + for (int i=0; i attributeList; + if (!invalidAttributes.containsKey(element)) { + attributeList = new ArrayList(); + attributeList.add(attribute); + invalidAttributes.put(element, attributeList); + } + else { + attributeList = invalidAttributes.get(element); + attributeList.add(attribute); + invalidAttributes.put(element,attributeList); + } + } + + // Add invalid attributes + public static void addInvalidElement(String element) { + for (int i=0; i>> 4) & 0x0F; + int two_halfs = 0; + do { + if ((0 <= halfbyte) && (halfbyte <= 9)) + buf.append((char) ('0' + halfbyte)); + else + buf.append((char) ('a' + (halfbyte - 10))); + halfbyte = element & 0x0F; + } while(two_halfs++ < 1); + } + return buf.toString(); + } + + + // Get/Set spelling settings + public static boolean getSpellSetting(String value) { + settings.beginGroup("Spell"); + String text = (String)settings.value(value, ""); + settings.endGroup(); + if (text.equalsIgnoreCase("true")) + return true; + if (text.equalsIgnoreCase("false")) + return false; + if (value.equalsIgnoreCase(Configuration.SPELL_IGNOREDIGITWORDS)) + return true; + if (value.equalsIgnoreCase(Configuration.SPELL_IGNOREINTERNETADDRESSES)) + return true; + if (value.equalsIgnoreCase(Configuration.SPELL_IGNOREUPPERCASE)) + return true; + if (value.equalsIgnoreCase(Configuration.SPELL_IGNORESENTENCECAPITALIZATION)) + return true; + return false; + } + public static void setSpellSetting(String setting, boolean val) { + settings.beginGroup("Spell"); + if (val) + settings.setValue(setting, "true"); + else + settings.setValue(setting, "false"); + settings.endGroup(); + } + + // Get/Set how we should display tags (color them, hide unused, or do nothing) + // What to do with inactive tags? + public static String tagBehavior() { + settings.beginGroup("General"); + String text = (String)settings.value("tagBehavior", "DoNothing"); + settings.endGroup(); + return text; + } + // What to do with inactive tags? + public static void setTagBehavior(String value) { + settings.beginGroup("General"); + settings.setValue("tagBehavior", value); + settings.endGroup(); + } + + + // Should the toolbar be visible? + public static boolean isToolbarButtonVisible(String window) { + settings.beginGroup("ToolbarButtonsVisible"); + try { + String text = (String)settings.value(window, "true"); + settings.endGroup(); + if (text.equalsIgnoreCase("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value(window, true); + settings.endGroup(); + return value; + } + } + public static void saveToolbarButtonsVisible(String column, boolean val) { + settings.beginGroup("ToolbarButtonsVisible"); + if (val) + settings.setValue(column, "true"); + else + settings.setValue(column, "false"); + settings.endGroup(); + } + + // Are thumbnails enabled? + + public static boolean enableThumbnails() { + settings.beginGroup("Debug"); + try { + String text = (String)settings.value("thumbnails", "true"); + settings.endGroup(); + if (text.equalsIgnoreCase("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("thumbnails", true); + settings.endGroup(); + return value; + } + } + public static void setEnableThumbnails(boolean val) { + settings.beginGroup("Debug"); + if (val) + settings.setValue("thumbnails", "true"); + else + settings.setValue("thumbnails", "false"); + settings.endGroup(); + } + + // Trace used for performance tuning. Not normally used in production. + // Print date/time. Used mainly for performance tracing + public static void trace(boolean resetInterval) { + String fmt = "MM/dd/yy HH:mm:ss.SSSSSS"; + String dateTimeFormat = new String(fmt); + SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat); + Calendar cal = Calendar.getInstance(); + if (intervalTraceTime == null) + intervalTraceTime = Calendar.getInstance(); + if (startTraceTime == null) + startTraceTime = Calendar.getInstance(); + + float interval = (cal.getTimeInMillis() - intervalTraceTime.getTimeInMillis()); + float total = (cal.getTimeInMillis() - startTraceTime.getTimeInMillis()); + +// if (interval > 00.0) { + StackTraceElement[] exceptions = Thread.currentThread().getStackTrace(); + System.out.println("------------------------------------------"); + + System.out.println("Date/Time " +simple.format(cal.getTime())); + System.out.format("Interval Time: %-10.6f%n", interval); + System.out.format("Total Time: %-10.6f%n", total); + for (int i=2; i<5 && i", "")); + zoom = 2; + if (text.length() < 500) + zoom = 2; + if (text.length() < 250) + zoom = 3; + if (text.length() < 100) + zoom = 4; + if (text.length() < 50) + zoom = 5; + if (text.length() < 10) + zoom = 6; + } + } + return zoom; + } + + //********************** + //* List View settings + //********************** + public static void setListView(int view) { + settings.beginGroup("General"); + settings.setValue("listView", view); + settings.endGroup(); + } + public static int getListView() { + settings.beginGroup("General"); + Integer value; + try { + String val = (String)settings.value("listView", View_List_Wide); + value = new Integer(val.trim()); + } catch (Exception e) { + try { + value = (Integer)settings.value("listView", View_List_Wide); + } catch (Exception e1) { + value = View_List_Wide; + } + } + settings.endGroup(); + return value; + } + + + + //******************* + // Font Settings + //******************* + public static boolean overrideDefaultFont() { + settings.beginGroup("Font"); + try { + String text = (String)settings.value("overrideFont", "false"); + settings.endGroup(); + if (text.equalsIgnoreCase("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("overrideFont", false); + settings.endGroup(); + return value; + } + + } + + //**************************************************** + // Get/Set the default font settings for a new note + //**************************************************** + public static void setOverrideDefaultFont(boolean value) { + settings.beginGroup("Font"); + settings.setValue("overrideFont", value); + settings.endGroup(); + } + public static String getDefaultFont() { + settings.beginGroup("Font"); + String val = (String)settings.value("font", ""); + settings.endGroup(); + return val; + } + public static void setDefaultFont(String value) { + settings.beginGroup("Font"); + settings.setValue("font", value); + settings.endGroup(); + } + public static String getDefaultFontSize() { + settings.beginGroup("Font"); + String val = (String)settings.value("fontSize", ""); + settings.endGroup(); + return val; + } + public static void setDefaultFontSize(String value) { + settings.beginGroup("Font"); + settings.setValue("fontSize", value); + settings.endGroup(); + } + + + //******************************************* + // Override the close & minimize instead. + //******************************************* + public static boolean minimizeOnClose() { + settings.beginGroup("General"); + try { + String text = (String)settings.value("minimizeOnClose", "false"); + settings.endGroup(); + if (text.equalsIgnoreCase("true") && QSystemTrayIcon.isSystemTrayAvailable()) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("minimizeOnClose", false); + settings.endGroup(); + return value; + } + } + public static void setMinimizeOnClose(boolean value) { + settings.beginGroup("General"); + settings.setValue("minimizeOnClose", value); + settings.endGroup(); + } + + //********************************* + // Check version information + //********************************* + public static boolean checkVersionUpgrade() { + settings.beginGroup("Upgrade"); + try { + String text = (String)settings.value("checkForUpdates", "true"); + settings.endGroup(); + if (text.equalsIgnoreCase("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("checkForUpdates", true); + settings.endGroup(); + return value; + } + } + public static void setCheckVersionUpgrade(boolean value) { + settings.beginGroup("Upgrade"); + settings.setValue("checkForUpdates", value); + settings.endGroup(); + } + public static String getUpdatesAvailableUrl() { + settings.beginGroup("Upgrade"); + String text = (String)settings.value("avialableUrl", "http://nevernote.sourceforge.net/versions.txt"); + settings.endGroup(); + return text; + } + public static String getUpdateAnnounceUrl() { + settings.beginGroup("Upgrade"); + String text = (String)settings.value("announceUrl", "http://nevernote.sourceforge.net/upgrade.html"); + settings.endGroup(); + return text; + } + + //******************* + // Index settings + //******************* + // Set/Get if we should index the text of a note + public static boolean indexNoteBody() { + settings.beginGroup("Index"); + try { + String value = (String)settings.value("indexNoteBody", "true"); + settings.endGroup(); + if (value.equals("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("indexNoteBody", true); + settings.endGroup(); + return value; + } + } + public static void setIndexNoteTitle(boolean value) { + settings.beginGroup("Index"); + settings.setValue("indexNoteTitle", value); + settings.endGroup(); + } + // Set/Get if we should index the title of a note + public static boolean indexNoteTitle() { + settings.beginGroup("Index"); + try { + String value = (String)settings.value("indexNoteTitle", "true"); + settings.endGroup(); + if (value.equals("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("indexNoteTitle", true); + settings.endGroup(); + return value; + } + } + public static void setIndexNoteBody(boolean value) { + settings.beginGroup("Index"); + settings.setValue("indexNoteBody", value); + settings.endGroup(); + } + // Set/Get if we should index any attachments + public static boolean indexAttachmentsLocally() { + settings.beginGroup("Index"); + try { + String value = (String)settings.value("indexAttachmentsLocally", "true"); + settings.endGroup(); + if (value.equals("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("indexAttachmentsLocally", true); + settings.endGroup(); + return value; + } + } + public static void setIndexImageRecognition(boolean value) { + settings.beginGroup("Index"); + settings.setValue("indexImageRecognition", value); + settings.endGroup(); + } + public static boolean indexImageRecognition() { + settings.beginGroup("Index"); + try { + String value = (String)settings.value("indexImageRecognition", "true"); + settings.endGroup(); + if (value.equals("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("indexImageRecognition", true); + settings.endGroup(); + return value; + } + } + public static void setIndexAttachmentsLocally(boolean value) { + settings.beginGroup("Index"); + settings.setValue("indexAttachmentsLocally", value); + settings.endGroup(); + } + // Get/Set characters that shouldn't be removed from a word + public static String getSpecialIndexCharacters() { + settings.beginGroup("Index"); + String text = (String)settings.value("specialCharacters", ""); + settings.endGroup(); + return text; + } + public static void setSpecialIndexCharacters(String value) { + settings.beginGroup("Index"); + settings.setValue("specialCharacters", value); + settings.endGroup(); + databaseCache = value; + } + + //***************************************************************************** + // Control how tag selection behaves (should they be "and" or "or" selections + //***************************************************************************** + public static boolean anyTagSelectionMatch() { + settings.beginGroup("General"); + try { + String value = (String)settings.value("anyTagSelectionMatch", "false"); + settings.endGroup(); + if (value.equals("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("anyTagSelectionMatch", false); + settings.endGroup(); + return value; + } + } + public static void setAnyTagSelectionMatch(boolean value) { + settings.beginGroup("General"); + settings.setValue("anyTagSelectionMatch", value); + settings.endGroup(); + } + + //***************************************************************************** + // Control if a user receives a warning when trying to create a note-to-note link + // when the DB is not synchronized. + //***************************************************************************** + public static boolean bypassSynchronizationWarning() { + settings.beginGroup("User"); + try { + String value = (String)settings.value("bypassSynchronizationWarning", "false"); + settings.endGroup(); + if (value.equals("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("bypassSynchronizationWarning", false); + settings.endGroup(); + return value; + } + } + public static void setBypassSynchronizationWarning(boolean value) { + settings.beginGroup("User"); + settings.setValue("bypassSynchronizationWarning", value); + settings.endGroup(); + } + + + //*********************** + //* Database cache size + //*********************** + public static String getDatabaseCacheSize() { + settings.beginGroup("Debug"); + String text = (String)settings.value("databaseCache", "16384"); + settings.endGroup(); + return text; + } + public static void setDatabaseCache(String value) { + settings.beginGroup("Debug"); + settings.setValue("databaseCache", value); + settings.endGroup(); + databaseCache = value; + } + + + // This is used to copy a class since Java's normal deep copy is wacked + public static Object deepCopy(Object oldObj) + { + ObjectOutputStream oos = null; + ObjectInputStream ois = null; + try + { + ByteArrayOutputStream bos = + new ByteArrayOutputStream(); // A + oos = new ObjectOutputStream(bos); // B + // serialize and pass the object + oos.writeObject(oldObj); // C + oos.flush(); // D + ByteArrayInputStream bin = + new ByteArrayInputStream(bos.toByteArray()); // E + ois = new ObjectInputStream(bin); // F + // return the new object + return ois.readObject(); // G + } + catch(Exception e) + { + Global.logger.log(logger.LOW, "Exception in ObjectCloner = " + e); + } + try { + oos.close(); + ois.close(); + } catch (IOException e) { + Global.logger.log(logger.LOW, "Exception in ObjectCloner = " + e); + e.printStackTrace(); + } + + return null; + } + + // If we should automatically select the children of any tag + public static boolean includeTagChildren() { + settings.beginGroup("General"); + try { + String value = (String)settings.value("includeTagChildren", "false"); + settings.endGroup(); + if (value.equals("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("includeTagChildren", false); + settings.endGroup(); + return value; + } + + } + public static void setIncludeTagChildren(boolean value) { + settings.beginGroup("General"); + settings.setValue("includeTagChildren", value); + settings.endGroup(); + } + + // If we should automatically wildcard searches + public static boolean automaticWildcardSearches() { + settings.beginGroup("General"); + try { + String value = (String)settings.value("automaticWildcard", "false"); + settings.endGroup(); + if (value.equals("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("automaticWildcard", false); + settings.endGroup(); + return value; + } + + } + public static void setAutomaticWildcardSearches(boolean value) { + settings.beginGroup("General"); + settings.setValue("automaticWildcard", value); + settings.endGroup(); + } + + // If we should automatically select the children of any tag + public static boolean displayRightToLeft() { + settings.beginGroup("General"); + try { + String value = (String)settings.value("displayRightToLeft", "false"); + settings.endGroup(); + if (value.equals("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("displayRightToLeft", false); + settings.endGroup(); + return value; + } + + } + public static void setDisplayRightToLeft(boolean value) { + settings.beginGroup("General"); + settings.setValue("displayRightToLeft", value); + settings.endGroup(); + } + + + //*********************** + //* Startup Notebook + //*********************** + public static String getStartupNotebook() { + settings.beginGroup("General"); + String text = (String)settings.value("startupNotebook", ""); + settings.endGroup(); + return text; + } + public static void setStartupNotebook(String value) { + settings.beginGroup("General"); + settings.setValue("startupNotebook", value); + settings.endGroup(); + databaseCache = value; + } + + // ICHANGED + // 複数ノート同時閲覧操作に対する重み付け + public static void setBrowseWeight(int weight) { + settings.beginGroup("RensoNoteList"); + settings.setValue("browseWeight", weight); + settings.endGroup(); + } + public static int getBrowseWeight() { + settings.beginGroup("RensoNoteList"); + Integer value; + try { + String val = (String)settings.value("browseWeight", 1); + value = new Integer(val.trim()); + } catch (Exception e) { + try { + value = (Integer)settings.value("browseWeight", 1); + } catch (Exception e1) { + value = 1; + } + } + settings.endGroup(); + return value; + } + + // ICHANGED + // ノート内容のコピー&ペースト操作に対する重み付け + public static void setCopyPasteWeight(int weight) { + settings.beginGroup("RensoNoteList"); + settings.setValue("copyPasteWeight", weight); + settings.endGroup(); + } + public static int getCopyPasteWeight() { + settings.beginGroup("RensoNoteList"); + Integer value; + try { + String val = (String)settings.value("copyPasteWeight", 3); + value = new Integer(val.trim()); + } catch (Exception e) { + try { + value = (Integer)settings.value("copyPasteWeight", 3); + } catch (Exception e1) { + value = 3; + } + } + settings.endGroup(); + return value; + } + + // ICHANGED + // 新規ノート追加操作に対する重み付け + public static void setAddNewNoteWeight(int weight) { + settings.beginGroup("RensoNoteList"); + settings.setValue("addNewNoteWeight", weight); + settings.endGroup(); + } + public static int getAddNewNoteWeight() { + settings.beginGroup("RensoNoteList"); + Integer value; + try { + String val = (String)settings.value("addNewNoteWeight", 1); + value = new Integer(val.trim()); + } catch (Exception e) { + try { + value = (Integer)settings.value("addNewNoteWeight", 1); + } catch (Exception e1) { + value = 1; + } + } + settings.endGroup(); + return value; + } + + // ICHANGED + // 連想ノートクリック操作に対する重み付け + public static void setRensoItemClickWeight(int weight) { + settings.beginGroup("RensoNoteList"); + settings.setValue("rensoItemClickWeight", weight); + settings.endGroup(); + } + public static int getRensoItemClickWeight() { + settings.beginGroup("RensoNoteList"); + Integer value; + try { + String val = (String)settings.value("rensoItemClickWeight", 10); + value = new Integer(val.trim()); + } catch (Exception e) { + try { + value = (Integer)settings.value("rensoItemClickWeight", 10); + } catch (Exception e1) { + value = 10; + } + } + settings.endGroup(); + return value; + } + + // ICHANGED + // タグ付け操作に対する重み付け + public static void setSameTagWeight(int weight) { + settings.beginGroup("RensoNoteList"); + settings.setValue("sameTagWeight", weight); + settings.endGroup(); + } + public static int getSameTagWeight() { + settings.beginGroup("RensoNoteList"); + Integer value; + try { + String val = (String)settings.value("sameTagWeight", 2); + value = new Integer(val.trim()); + } catch (Exception e) { + try { + value = (Integer)settings.value("sameTagWeight", 2); + } catch (Exception e1) { + value = 2; + } + } + settings.endGroup(); + return value; + } + + // ICHANGED + // ノートブック変更操作に対する重み付け + public static void setSameNotebookWeight(int weight) { + settings.beginGroup("RensoNoteList"); + settings.setValue("sameNotebookWeight", weight); + settings.endGroup(); + } + public static int getSameNotebookWeight() { + settings.beginGroup("RensoNoteList"); + Integer value; + try { + String val = (String)settings.value("sameNotebookWeight", 2); + value = new Integer(val.trim()); + } catch (Exception e) { + try { + value = (Integer)settings.value("sameNotebookWeight", 2); + } catch (Exception e1) { + value = 2; + } + } + settings.endGroup(); + return value; + } + + //******************* + // ノートのマージ・複製の関連ノートリストへの適用 + //******************* + // ICHANGED + public static void setMergeRensoNote(boolean value) { + settings.beginGroup("RensoNoteList"); + settings.setValue("mergeRensoNoteList", value); + settings.endGroup(); + } + // ICHANGED + public static boolean getMergeRensoNote() { + settings.beginGroup("RensoNoteList"); + try { + String value = (String)settings.value("mergeRensoNoteList", "true"); + settings.endGroup(); + if (value.equals("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("mergeRensoNoteList", true); + settings.endGroup(); + return value; + } + } + // ICHANGED + public static void setDuplicateRensoNote(boolean value) { + settings.beginGroup("RensoNoteList"); + settings.setValue("duplicateRensoNoteList", value); + settings.endGroup(); + } + // ICHANGED + public static boolean getDuplicateRensoNote() { + settings.beginGroup("RensoNoteList"); + try { + String value = (String)settings.value("duplicateRensoNoteList", "true"); + settings.endGroup(); + if (value.equals("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("duplicateRensoNoteList", true); + settings.endGroup(); + return value; + } + } + + // ICHANGED + // 連想ノートリストからノートを除外するときに確認メッセージを表示するかどうか + public static boolean verifyExclude() { + settings.beginGroup("RensoNoteList"); + try { + String text = (String)settings.value("verifyExclude", "true"); + settings.endGroup(); + if (text.equalsIgnoreCase("true")) + return true; + else + return false; + } catch (java.lang.ClassCastException e) { + Boolean value = (Boolean) settings.value("verifyExclude", true); + settings.endGroup(); + return value; + } + } + // ICHANGED + public static void setVerifyExclude(boolean val) { + settings.beginGroup("RensoNoteList"); + if (val) + settings.setValue("verifyExclude", "true"); + else + settings.setValue("verifyExclude", "false"); + settings.endGroup(); + } + + // ICHANGED + // 連想ノートリスト最大表示アイテム数 + public static void setRensoListItemMaximum(int maximum) { + settings.beginGroup("RensoNoteList"); + settings.setValue("rensoListMaximum", maximum); + settings.endGroup(); + } + public static int getRensoListItemMaximum() { + settings.beginGroup("RensoNoteList"); + Integer value; + try { + String val = (String)settings.value("rensoListMaximum", 20); + value = new Integer(val.trim()); + } catch (Exception e) { + try { + value = (Integer)settings.value("rensoListMaximum", 20); + } catch (Exception e1) { + value = 20; + } + } + settings.endGroup(); + return value; + } +} + diff --git a/src/cx/fbn/nevernote/NeverNote.java b/src/cx/fbn/nevernote/NeverNote.java index 681df70..65ba96e 100644 --- a/src/cx/fbn/nevernote/NeverNote.java +++ b/src/cx/fbn/nevernote/NeverNote.java @@ -87,6 +87,7 @@ import com.trolltech.qt.core.QTranslator; import com.trolltech.qt.core.QUrl; import com.trolltech.qt.core.Qt; import com.trolltech.qt.core.Qt.BGMode; +import com.trolltech.qt.core.Qt.DockWidgetArea; import com.trolltech.qt.core.Qt.ItemDataRole; import com.trolltech.qt.core.Qt.KeyboardModifier; import com.trolltech.qt.core.Qt.MouseButton; @@ -103,6 +104,7 @@ import com.trolltech.qt.gui.QComboBox; import com.trolltech.qt.gui.QCursor; import com.trolltech.qt.gui.QDesktopServices; import com.trolltech.qt.gui.QDialog; +import com.trolltech.qt.gui.QDockWidget; import com.trolltech.qt.gui.QFileDialog; import com.trolltech.qt.gui.QFileDialog.AcceptMode; import com.trolltech.qt.gui.QFileDialog.FileMode; @@ -112,6 +114,7 @@ import com.trolltech.qt.gui.QIcon; import com.trolltech.qt.gui.QImage; import com.trolltech.qt.gui.QKeySequence; import com.trolltech.qt.gui.QLabel; +import com.trolltech.qt.gui.QListWidgetItem; import com.trolltech.qt.gui.QMainWindow; import com.trolltech.qt.gui.QMenu; import com.trolltech.qt.gui.QMessageBox; @@ -175,13 +178,17 @@ import cx.fbn.nevernote.gui.DateAttributeFilterTable; import cx.fbn.nevernote.gui.ExternalBrowse; import cx.fbn.nevernote.gui.MainMenuBar; import cx.fbn.nevernote.gui.NotebookTreeWidget; +import cx.fbn.nevernote.gui.RensoNoteList; import cx.fbn.nevernote.gui.SavedSearchTreeWidget; import cx.fbn.nevernote.gui.SearchPanel; +import cx.fbn.nevernote.gui.TabBrowse; +import cx.fbn.nevernote.gui.TabBrowserWidget; import cx.fbn.nevernote.gui.TableView; import cx.fbn.nevernote.gui.TagTreeWidget; import cx.fbn.nevernote.gui.Thumbnailer; import cx.fbn.nevernote.gui.TrashTreeWidget; import cx.fbn.nevernote.gui.controls.QuotaProgressBar; +import cx.fbn.nevernote.neighbornote.ClipBoardObserver; import cx.fbn.nevernote.oauth.OAuthTokenizer; import cx.fbn.nevernote.oauth.OAuthWindow; import cx.fbn.nevernote.sql.DatabaseConnection; @@ -328,9 +335,11 @@ public class NeverNote extends QMainWindow{ HashMap noteCache; // Cash of note content HashMap readOnlyCache; // List of cashe notes that are read-only HashMap inkNoteCache; // List of cache notes that are ink notes - List historyGuids; // GUIDs of previously viewed items - int historyPosition; // Position within the viewed items - boolean fromHistory; // Is this from the history queue? + // ICHANGED + HashMap> historyGuids; // タブごとの以前見たノートのGUID + HashMap historyPosition; // Position within the viewed items + HashMap fromHistory; // Is this from the history queue? + String trashNoteGuid; // Guid to restore / set into or out of trash to save position List thumbGenerators; // generate preview image ThumbnailViewer thumbnailViewer; // View preview thumbnail; @@ -348,6 +357,18 @@ public class NeverNote extends QMainWindow{ private QTimer blockTimer; BrowserWindow blockingWindow; + // ICHANGED + private final TabBrowserWidget tabBrowser; // ブラウザウィンドウをタブ化 + private final HashMap tabWindows; // タブウィンドウ + private final RensoNoteList rensoNoteList; // 連想ノートリスト + private final QDockWidget rensoNoteListDock; // 連想ノートリストドックウィジェット + + // ICHANGED + ClipBoardObserver cbObserver; + + // ICHANGED + String rensoNotePressedItemGuid; + String iconPath = new String("classpath:cx/fbn/nevernote/icons/"); @@ -359,11 +380,14 @@ public class NeverNote extends QMainWindow{ // Application Constructor @SuppressWarnings("static-access") public NeverNote(DatabaseConnection dbConn) { + // ICHANGED + cbObserver = new ClipBoardObserver(); + conn = dbConn; if (conn.getConnection() == null) { String msg = new String(tr("Unable to connect to the database.\n\nThe most probable reason is that some other process\n" + - "is accessing the database or NixNote is already running.\n\n" + - "Please end any other process or shutdown the other NixNote before starting.\n\nExiting program.")); + "is accessing the database or NeighborNote is already running.\n\n" + + "Please end any other process or shutdown the other NeighborNote before starting.\n\nExiting program.")); QMessageBox.critical(null, tr("Database Connection Error") ,msg); System.exit(16); @@ -398,9 +422,12 @@ public class NeverNote extends QMainWindow{ QApplication.setStyle(Global.getStyle()); if (Global.useStandardPalette()) QApplication.setPalette(QApplication.style().standardPalette()); - setWindowTitle(tr("NixNote")); + setWindowTitle(tr("NeighborNote")); mainLeftRightSplitter = new QSplitter(); + // ICHANGED + mainLeftRightSplitter.setOrientation(Qt.Orientation.Horizontal); + setCentralWidget(mainLeftRightSplitter); leftSplitter1 = new QSplitter(); leftSplitter1.setOrientation(Qt.Orientation.Vertical); @@ -417,9 +444,13 @@ public class NeverNote extends QMainWindow{ listManager = new ListManager(conn, logger); logger.log(logger.EXTREME, "Building index runners & timers"); - indexRunner = new IndexRunner("indexRunner.log", - Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(), - Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword); + // ICHANGED Global.getBehaviorDatabaseUrl()を追加 + indexRunner = new IndexRunner("indexRunner.log", + Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), + Global.getResourceDatabaseUrl(), + Global.getBehaviorDatabaseUrl(), Global.getDatabaseUserid(), + Global.getDatabaseUserPassword(), Global.cipherPassword); + indexThread = new QThread(indexRunner, "Index Thread"); indexRunner.indexAttachmentsLocally = Global.indexAttachmentsLocally(); indexRunner.indexImageRecognition = Global.indexImageRecognition(); @@ -440,9 +471,12 @@ public class NeverNote extends QMainWindow{ logger.log(logger.EXTREME, "Setting sync thread & timers"); syncThreadsReady=1; - syncRunner = new SyncRunner("syncRunner.log", - Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(), - Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword); + // ICHANGED Global.getBehaviorDatabaseUrl()を追加 + syncRunner = new SyncRunner("syncRunner.log", Global.getDatabaseUrl(), + Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(), + Global.getBehaviorDatabaseUrl(), Global.getDatabaseUserid(), + Global.getDatabaseUserPassword(), Global.cipherPassword); + syncTime = new SyncTimes().timeValue(Global.getSyncInterval()); syncTimer = new QTimer(); syncTimer.timeout.connect(this, "syncTimer()"); @@ -464,9 +498,13 @@ public class NeverNote extends QMainWindow{ logger.log(logger.EXTREME, "Starting thumnail thread"); pdfReadyQueue = new ArrayList(); - thumbnailRunner = new ThumbnailRunner("thumbnailRunner.log", - Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(), - Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword); + // ICHANGED Global.getBehaviorDatabaseUrl()を追加 + thumbnailRunner = new ThumbnailRunner("thumbnailRunner.log", + Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), + Global.getResourceDatabaseUrl(), + Global.getBehaviorDatabaseUrl(), Global.getDatabaseUserid(), + Global.getDatabaseUserPassword(), Global.cipherPassword); + thumbnailThread = new QThread(thumbnailRunner, "Thumbnail Thread"); thumbnailRunner.noteSignal.thumbnailPageReady.connect(this, "thumbnailHTMLReady(String,QByteArray,Integer)"); thumbnailThread.start(); @@ -510,7 +548,8 @@ public class NeverNote extends QMainWindow{ tagTree = new TagTreeWidget(conn); savedSearchTree = new SavedSearchTreeWidget(); trashTree = new TrashTreeWidget(); - noteTableView = new TableView(logger, listManager); + // ICHANGED + noteTableView = new TableView(logger, listManager, this); searchField = new QComboBox(); searchField.setObjectName("searchField"); @@ -549,18 +588,55 @@ public class NeverNote extends QMainWindow{ noteCache = new HashMap(); readOnlyCache = new HashMap(); inkNoteCache = new HashMap(); - browserWindow = new BrowserWindow(conn); - + // ICHANGED + browserWindow = new BrowserWindow(conn, cbObserver); + + // ICHANGED 下から移動してきた。 + historyGuids = new HashMap>(); + historyPosition = new HashMap(); + fromHistory = new HashMap(); + + // ICHANGED タブブラウザ作成 + tabWindows = new HashMap(); + tabBrowser = new TabBrowserWidget(this); + tabBrowser.setStyleSheet("QTabBar::tab{width:150px;}"); + TabBrowse tab = new TabBrowse(conn, tabBrowser, cbObserver); + browserWindow = tab.getBrowserWindow(); + int index = tabBrowser.addNewTab(tab, ""); + tabWindows.put(index, tab); + tabBrowser.setTabsClosable(true); + tabBrowser.currentChanged.connect(this, "tabWindowChanged(int)"); + tabBrowser.tabCloseRequested.connect(this, "tabWindowClosing(int)"); + + // ICHANGED + // 履歴記録のハッシュマップを初期化 + historyGuids.put(index, new ArrayList()); + historyPosition.put(index, 0); + fromHistory.put(index, false); + mainLeftRightSplitter.addWidget(leftSplitter1); mainLeftRightSplitter.addWidget(browserIndexSplitter); - if (Global.getListView() == Global.View_List_Wide) { - browserIndexSplitter.addWidget(noteTableView); - browserIndexSplitter.addWidget(browserWindow); - } else { - mainLeftRightSplitter.addWidget(noteTableView); - mainLeftRightSplitter.addWidget(browserWindow); - } + // ICHANGED + // 連想ノートリストをセットアップ + rensoNoteList = new RensoNoteList(conn, this); + rensoNoteList.itemPressed.connect(this, + "rensoNoteItemPressed(QListWidgetItem)"); + rensoNoteListDock = new QDockWidget(tr("Renso Note List"), this); + rensoNoteListDock.setWidget(rensoNoteList); + addDockWidget(DockWidgetArea.RightDockWidgetArea, rensoNoteListDock); + + if (Global.getListView() == Global.View_List_Wide) { + browserIndexSplitter.addWidget(noteTableView); + // ICHANGED + browserIndexSplitter.addWidget(tabBrowser); + // browserIndexSplitter.addWidget(browserWindow); + } else { + mainLeftRightSplitter.addWidget(noteTableView); + // ICHANGED + mainLeftRightSplitter.addWidget(tabBrowser); + // mainLeftRightSplitter.addWidget(browserWindow); + } // Setup the thumbnail viewer thumbnailViewer = new ThumbnailViewer(); @@ -622,8 +698,15 @@ public class NeverNote extends QMainWindow{ savedSearchTree.itemSelectionChanged.connect(this, "updateSavedSearchSelection()"); savedSearchTree.setVisible(Global.isWindowVisible("savedSearchTree")); menuBar.hideSavedSearches.setChecked(Global.isWindowVisible("savedSearchTree")); + + // ICHANGED noteTableViewに新しいタブで開くを追加 + noteTableView.setOpenNewTabAction(menuBar.noteOpenNewTab); noteTableView.setAddAction(menuBar.noteAdd); + + // ICHANGED noteTableViewに新しいタブでノート追加を追加 + noteTableView.setAddNoteNewTabAction(menuBar.noteAddNewTab); + noteTableView.setDeleteAction(menuBar.noteDelete); noteTableView.setRestoreAction(menuBar.noteRestoreAction); noteTableView.setNoteDuplicateAction(menuBar.noteDuplicateAction); @@ -651,15 +734,21 @@ public class NeverNote extends QMainWindow{ if (!Global.isWindowVisible("editorButtonBar")) toggleEditorButtonBar(); + if (!Global.isWindowVisible("leftPanel")) menuBar.hideLeftSide.setChecked(true); if (Global.isWindowVisible("noteInformation")) toggleNoteInformation(); quotaBar.setVisible(Global.isWindowVisible("quota")); - if (!quotaBar.isVisible()) + // IFIXED quotaBar.isVisible() → Global.isWindowVisible("quota") + // なぜかquotaBar.isVisible()が常にfalseを返すようなので修正 + if (!Global.isWindowVisible("quota")) menuBar.hideQuota.setChecked(false); + searchField.setVisible(Global.isWindowVisible("searchField")); - if (!searchField.isVisible()) + // IFIXED !searchField.isVisible() → !Global.isWindowVisible("searchField") + // なぜかsearchField.isVisible()が常にfalseを返すようなので修正 + if (!Global.isWindowVisible("searchField")) menuBar.hideSearch.setChecked(false); if (searchField.isHidden() && quotaBar.isHidden() && zoomSpinner.isHidden() && notebookTree.isHidden()) @@ -686,7 +775,7 @@ public class NeverNote extends QMainWindow{ trayIcon = new QSystemTrayIcon(this); - trayIcon.setToolTip(tr("NixNote")); + trayIcon.setToolTip(tr("NeighborNote")); trayIcon.setContextMenu(trayMenu); trayIcon.activated.connect(this, "trayActivated(com.trolltech.qt.gui.QSystemTrayIcon$ActivationReason)"); @@ -694,9 +783,14 @@ public class NeverNote extends QMainWindow{ currentNoteGuid = Global.getLastViewedNoteGuid(); if (currentNoteGuid.equals("")) currentNote = new Note(); - historyGuids = new ArrayList(); - historyPosition = 0; - fromHistory = false; + + // ICHANGED + /* 上に移動したので要らない + historyGuids = new ArrayList(); + historyPosition = 0; + fromHistory = false; + */ + noteDirty = false; if (!currentNoteGuid.trim().equals("")) { currentNote = conn.getNoteTable().getNote(currentNoteGuid, true,true,false,false,true); @@ -748,8 +842,12 @@ public class NeverNote extends QMainWindow{ threadMonitorTimer.timeout.connect(this, "threadMonitorCheck()"); threadMonitorTimer.start(1000*10); // Check for threads every 10 seconds; - historyGuids.add(currentNoteGuid); - historyPosition = 1; + // ICHANGED たぶんこれはいらない + // IFIXED ? + /* + historyGuids.add(currentNoteGuid); + historyPosition = 1; + */ menuBar.blockSignals(true); menuBar.narrowListView.blockSignals(true); @@ -763,14 +861,18 @@ public class NeverNote extends QMainWindow{ menuBar.blockSignals(false); menuBar.narrowListView.blockSignals(false); menuBar.wideListView.blockSignals(false); - - if (Global.getListView() == Global.View_List_Wide) { - browserIndexSplitter.addWidget(noteTableView); - browserIndexSplitter.addWidget(browserWindow); - } else { - mainLeftRightSplitter.addWidget(noteTableView); - mainLeftRightSplitter.addWidget(browserWindow); - } + + // IFIXED + // 上に同じコードがあるよね? とりあえずコメントアウト + /* + * if (Global.getListView() == Global.View_List_Wide) { + * browserIndexSplitter.addWidget(noteTableView); // ICHANGED // + * browserIndexSplitter.addWidget(tabBrowser); + * browserIndexSplitter.addWidget(browserWindow); } else { + * mainLeftRightSplitter.addWidget(noteTableView); // ICHANGED // + * mainLeftRightSplitter.addWidget(tabBrowser); + * mainLeftRightSplitter.addWidget(browserWindow); } + */ messageTimer = new QTimer(); messageTimer.timeout.connect(this, "clearMessage()"); @@ -800,11 +902,10 @@ public class NeverNote extends QMainWindow{ } } - - - - if (Global.checkVersionUpgrade()) - checkForUpdates(); + if (Global.checkVersionUpgrade()) { + // ICHANGED TODO とりあえず封印 + // checkForUpdates(); + } } @@ -920,13 +1021,20 @@ public class NeverNote extends QMainWindow{ File f = Global.getFileManager().getDbDirFile(Global.databaseName + ".h2.db"); File fr = Global.getFileManager().getDbDirFile(Global.resourceDatabaseName + ".h2.db"); - File fi = Global.getFileManager().getDbDirFile(Global.resourceDatabaseName + ".h2.db"); + // IFIXED resourceDatabaseNameになっていたので修正 + File fi = Global.getFileManager().getDbDirFile(Global.indexDatabaseName + ".h2.db"); + // ICHANGED + File fb = Global.getFileManager().getDbDirFile(Global.behaviorDatabaseName + ".h2.db"); + if (!f.exists()) Global.setDatabaseUrl(""); if (!fr.exists()) Global.setResourceDatabaseUrl(""); if (!fi.exists()) Global.setIndexDatabaseUrl(""); + // ICHANGED + if (!fb.exists()) + Global.setBehaviorDatabaseUrl(""); if (Global.getDatabaseUrl().toUpperCase().indexOf("CIPHER=") > -1) { boolean goodCheck = false; @@ -940,8 +1048,9 @@ public class NeverNote extends QMainWindow{ Global.getDatabaseUserPassword(), Global.cipherPassword); } } + // ICHANGED Global.getBehaviorDatabaserUrl()を追加 DatabaseConnection dbConn = new DatabaseConnection(logger,Global.getDatabaseUrl(), - Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(), + Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(), Global.getBehaviorDatabaseUrl(), Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword, 0); return dbConn; } @@ -957,6 +1066,10 @@ public class NeverNote extends QMainWindow{ st.execute("shutdown"); st = conn.getIndexConnection().createStatement(); st.execute("shutdown"); + // ICHANGED + st = conn.getBehaviorConnection().createStatement(); + st.execute("shutdown"); + if (QMessageBox.question(this, tr("Are you sure"), tr("Are you sure you wish to encrypt the database?"), QMessageBox.StandardButton.Yes, @@ -964,9 +1077,14 @@ public class NeverNote extends QMainWindow{ ChangeFileEncryption.execute(dbPath, "NeverNote", encryptCipher, null, Global.cipherPassword.toCharArray(), true); ChangeFileEncryption.execute(dbPath, "Resources", encryptCipher, null, Global.cipherPassword.toCharArray(), true); ChangeFileEncryption.execute(dbPath, "Index", encryptCipher, null, Global.cipherPassword.toCharArray(), true); + // ICHANGED + ChangeFileEncryption.execute(dbPath, "Behavior", encryptCipher, null, Global.cipherPassword.toCharArray(), true); + Global.setDatabaseUrl(Global.getDatabaseUrl() + ";CIPHER="+encryptCipher); Global.setResourceDatabaseUrl(Global.getResourceDatabaseUrl() + ";CIPHER="+encryptCipher); Global.setIndexDatabaseUrl(Global.getIndexDatabaseUrl() + ";CIPHER="+encryptCipher); + // ICHANGED + Global.setBehaviorDatabaseUrl(Global.getBehaviorDatabaseUrl() + ";CIPHER=" + encryptCipher); QMessageBox.information(this, tr("Encryption Complete"), tr("Encryption is complete")); } @@ -1069,11 +1187,13 @@ public class NeverNote extends QMainWindow{ logger.log(logger.HIGH, "Entering NeverNote.closeEvent"); waitCursor(true); - if (currentNote!= null & browserWindow!=null) { - if (currentNote.getTitle() != null && browserWindow != null + if (currentNote != null & browserWindow != null) { + if (currentNote.getTitle() != null && browserWindow != null && !currentNote.getTitle().equals(browserWindow.getTitle())) - conn.getNoteTable().updateNoteTitle(currentNote.getGuid(), browserWindow.getTitle()); + conn.getNoteTable().updateNoteTitle(currentNote.getGuid(), + browserWindow.getTitle()); } + saveNote(); setMessage(tr("Beginning shutdown.")); @@ -1086,6 +1206,15 @@ public class NeverNote extends QMainWindow{ browser.close(); } + // ICHANGED タブブラウザに対してクローズ処理を行う + Collection win = tabWindows.values(); + Iterator it = win.iterator(); + tabBrowser.currentChanged.disconnect(); + tabBrowser.tabCloseRequested.disconnect(); + while (it.hasNext()) { + TabBrowse browser = it.next(); + browser.close(); + } externalFileEditedSaver(); if (Global.isConnected && Global.synchronizeOnClose()) { @@ -1302,6 +1431,7 @@ public class NeverNote extends QMainWindow{ @SuppressWarnings("unused") private void settings() { logger.log(logger.HIGH, "Entering NeverNote.settings"); + saveNoteColumnPositions(); saveNoteIndexWidth(); showColumns(); @@ -1323,8 +1453,14 @@ public class NeverNote extends QMainWindow{ else trayIcon.hide(); showColumns(); - if (menuBar.showEditorBar.isChecked()) - showEditorButtons(browserWindow); + if (menuBar.showEditorBar.isChecked()){ + // ICHANGED + for(int i = 0; i < tabBrowser.count(); i++){ + BrowserWindow browser = ((TabBrowse) tabBrowser.widget(i)).getBrowserWindow(); + showEditorButtons(browser); + } + + } // Reset the save timer if (Global.getAutoSaveInterval() > 0) @@ -1357,7 +1493,9 @@ public class NeverNote extends QMainWindow{ restoreState(Global.restoreState(objectName())); mainLeftRightSplitter.setObjectName("mainLeftRightSplitter"); browserIndexSplitter.setObjectName("browserIndexSplitter"); - leftSplitter1.setObjectName("leftSplitter1"); + leftSplitter1.setObjectName("leftSplitter1"); + // ICHANGED + rensoNoteListDock.setObjectName("rensoNoteListDock"); // Restore the actual positions. if (mainWindow) @@ -1365,6 +1503,8 @@ public class NeverNote extends QMainWindow{ mainLeftRightSplitter.restoreState(Global.restoreState(mainLeftRightSplitter.objectName())); browserIndexSplitter.restoreState(Global.restoreState(browserIndexSplitter.objectName())); leftSplitter1.restoreState(Global.restoreState(leftSplitter1.objectName())); + // ICHANGED + rensoNoteListDock.restoreGeometry(Global.restoreGeometry(rensoNoteListDock.objectName())); } // Save window positions for the next start @@ -1374,6 +1514,8 @@ public class NeverNote extends QMainWindow{ Global.saveState(browserIndexSplitter.objectName(), browserIndexSplitter.saveState()); Global.saveState(leftSplitter1.objectName(), leftSplitter1.saveState()); Global.saveState(objectName(), saveState()); + // ICHANGED + Global.saveGeometry(rensoNoteListDock.objectName(), rensoNoteListDock.saveGeometry()); } // Load the style sheet private void loadStyleSheet() { @@ -1512,6 +1654,12 @@ public class NeverNote extends QMainWindow{ menuBar.notebookShareAction.setEnabled(true); menuBar.notebookIconAction.setEnabled(true); menuBar.notebookStackAction.setEnabled(true); + + // ICHANGED ゴミ箱から元の画面に戻す。連想ノートリストをONに。 + if (!rensoNoteListDock.isEnabled()) { + rensoNoteListDock.setEnabled(true); + } + List selections = notebookTree.selectedItems(); selectedNotebookGUIDs.clear(); String guid = ""; @@ -1779,6 +1927,14 @@ public class NeverNote extends QMainWindow{ Iterator set = externalWindows.keySet().iterator(); while(set.hasNext()) externalWindows.get(set.next()).getBrowserWindow().setNotebookList(filteredBooks); + + // ICHANGED + Iteratorit = tabWindows.keySet().iterator(); + while (it.hasNext()) { + tabWindows.get(it.next()).getBrowserWindow() + .setNotebookList(filteredBooks); + } + logger.log(logger.HIGH, "Leaving NeverNote.editNotebook"); } // Publish a notebook @@ -1924,6 +2080,8 @@ public class NeverNote extends QMainWindow{ // A note's notebook has been updated @SuppressWarnings("unused") private void updateNoteNotebook(String guid, String notebookGuid) { + // ICHANGED 同じノートブックに入れられたノート間の履歴を登録 + conn.getHistoryTable().addSameNotebookHistory(guid, notebookGuid); // Update the list manager listManager.updateNoteNotebook(guid, notebookGuid); @@ -2017,6 +2175,14 @@ public class NeverNote extends QMainWindow{ while(set.hasNext()) externalWindows.get(set.next()).getBrowserWindow().setNotebookList(filteredBooks); + // ICHANGED + // 全てのタブウィンドウを更新 + Iterator it = tabWindows.keySet().iterator(); + while (it.hasNext()) { + tabWindows.get(it.next()).getBrowserWindow() + .setNotebookList(filteredBooks); + } + waitCursor(false); } // Change the notebook's icon @@ -2262,6 +2428,11 @@ public class NeverNote extends QMainWindow{ menuBar.noteRestoreAction.setVisible(false); + // ICHANGED ゴミ箱から元の画面に戻す。連想ノートリストをONに。 + if (!rensoNoteListDock.isEnabled()) { + rensoNoteListDock.setEnabled(true); + } + List selections = tagTree.selectedItems(); QTreeWidgetItem currentSelection; selectedTagGUIDs.clear(); @@ -2615,6 +2786,12 @@ public class NeverNote extends QMainWindow{ menuBar.savedSearchEditAction.setEnabled(true); menuBar.savedSearchDeleteAction.setEnabled(true); menuBar.savedSearchIconAction.setEnabled(true); + + // ICHANGED ゴミ箱から元の画面に戻す。連想ノートリストをONに。 + if (!rensoNoteListDock.isEnabled()) { + rensoNoteListDock.setEnabled(true); + } + List selections = savedSearchTree.selectedItems(); QTreeWidgetItem currentSelection; selectedSavedSearchGUID = ""; @@ -2770,7 +2947,7 @@ public class NeverNote extends QMainWindow{ logger.log(logger.HIGH, "Entering NeverNote.compactDatabase"); if (QMessageBox.question(this, tr("Confirmation"), tr("This will free unused space in the database, "+ "but please be aware that depending upon the size of your database this can be time consuming " + - "and NixNote will be unresponsive until it is complete. Do you wish to continue?"), + "and NeighborNote will be unresponsive until it is complete. Do you wish to continue?"), QMessageBox.StandardButton.Yes, QMessageBox.StandardButton.No)==StandardButton.No.value() && Global.verifyDelete() == true) { return; @@ -2820,10 +2997,11 @@ public class NeverNote extends QMainWindow{ @SuppressWarnings("unused") private void about() { logger.log(logger.HIGH, "Entering NeverNote.about"); + // ICHANGED based on...の記述を付加 QMessageBox.about(this, - tr("About NixNote"), - tr("

NixNote


Version ") - +Global.version + tr("About NeighborNote"), + tr("

NeighborNote


Version ") + +Global.version + "(based on NixNote 1.5)" //+"1.2.120724" +tr("
" +"Open Source Evernote Client.

" @@ -3065,7 +3243,7 @@ public class NeverNote extends QMainWindow{ attributeButton = toolBar.addAction(tr("Attributes")); QIcon attributeIcon = new QIcon(iconPath+"attribute.png"); attributeButton.setIcon(attributeIcon); - attributeButton.triggered.connect(this, "toggleNoteInformation()"); + attributeButton.triggered.connect(this, "toggleNoteAttributes()"); toggleAttributeButton(Global.isToolbarButtonVisible("attribute")); emailButton = toolBar.addAction(tr("Email")); @@ -3368,12 +3546,17 @@ public class NeverNote extends QMainWindow{ Global.showDeleted = false; menuBar.noteRestoreAction.setEnabled(false); menuBar.noteRestoreAction.setVisible(false); + // ICHANGED ゴミ箱から元の画面に戻す。連想ノートリストをONに。 + rensoNoteListDock.setEnabled(true); } else { trashNoteGuid = tempGuid; currentNoteGuid = trashNoteGuid; menuBar.noteRestoreAction.setEnabled(true); menuBar.noteRestoreAction.setVisible(true); + // ICHANGED ゴミ箱を開く。連想ノートリストをOFFに。 + rensoNoteListDock.setEnabled(false); + Global.showDeleted = true; } listManager.loadNotesIndex(); @@ -3409,6 +3592,11 @@ public class NeverNote extends QMainWindow{ listManager.loadNotesIndex(); noteIndexUpdated(false); + + // ICHANGED ゴミ箱から元の画面に戻す。連想ノートリストをONに。 + if (!rensoNoteListDock.isEnabled()) { + rensoNoteListDock.setEnabled(true); + } } } // Show/Hide trash window @@ -3577,6 +3765,11 @@ public class NeverNote extends QMainWindow{ // clearNotebookFilter(); clearTrashFilter(); // clearSavedSearchFilter(); + + // ICHANGED ゴミ箱から元の画面に戻す。連想ノートリストをONに。 + if (!rensoNoteListDock.isEnabled()) { + rensoNoteListDock.setEnabled(true); + } if (attributeTreeSelected == null || item.nativeId() != attributeTreeSelected.nativeId()) { if (item.childCount() > 0) { @@ -3688,6 +3881,31 @@ public class NeverNote extends QMainWindow{ saveNote(); + // ICHANGED + // Ctrlを押しながらノートテーブルを選択した時に選択ノート数0になってしまうのを止める + if (noteTableView.selectionModel().selectedRows().size() == 0) { + scrollToGuid(currentNoteGuid); + return; + } + + // ICHANGED + // 右クリックだったときの処理 + if (QApplication.mouseButtons().isSet(MouseButton.RightButton)) { + // 選択されたノート(current)のguidをcurrentnoteguidにセット + List selections = noteTableView.selectionModel().selectedRows(); + if(selections.size() > 0){ + selectedNoteGUIDs.clear(); + for(int i = 0; i < selections.size(); i++){ + int row = selections.get(i).row(); + QModelIndex index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition); + SortedMap ix = noteTableView.proxyModel.itemData(index); + currentNoteGuid = (String) ix.values().toArray()[0]; + selectedNoteGUIDs.add(currentNoteGuid); + } + } + return; + } + // If we have more than one selection, then set the merge note action to true. List selections = noteTableView.selectionModel().selectedRows(); if (selections.size() > 1) @@ -3697,14 +3915,26 @@ public class NeverNote extends QMainWindow{ // If the ctrl key is pressed, then they are selecting multiple // entries and we don't want to change the currently viewed note. + // ICHANGED if (QApplication.keyboardModifiers().isSet(KeyboardModifier.ControlModifier) && - QApplication.mouseButtons().isSet(MouseButton.LeftButton)) + QApplication.mouseButtons().isSet(MouseButton.LeftButton)){ + selectedNoteGUIDs.clear(); + for (int i=0; i ix = noteTableView.proxyModel.itemData(index); + selectedNoteGUIDs.add((String)ix.values().toArray()[0]); + } return; - - if (historyGuids.size() == 0) { + } + + // ICHANGED たぶんこれは不要 + // IFIXED ? + /*if (historyGuids.size() == 0) { historyGuids.add(currentNoteGuid); historyPosition = 1; - } + }*/ + noteTableView.showColumn(Global.noteTableGuidPosition); if (!Global.isColumnVisible("guid")) @@ -3737,6 +3967,7 @@ public class NeverNote extends QMainWindow{ downButton.setEnabled(false); index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition); SortedMap ix = noteTableView.proxyModel.itemData(index); + currentNoteGuid = (String)ix.values().toArray()[0]; selectedNoteGUIDs.add(currentNoteGuid); } @@ -3744,25 +3975,79 @@ public class NeverNote extends QMainWindow{ nextButton.setEnabled(true); prevButton.setEnabled(true); - if (!fromHistory) { - int endPosition = historyGuids.size()-1; - for (int j=historyPosition; j<=endPosition; j++) { - historyGuids.remove(historyGuids.size()-1); - } - historyGuids.add(currentNoteGuid); - historyPosition = historyGuids.size(); - } - if (historyPosition <= 1) - prevButton.setEnabled(false); - if (historyPosition == historyGuids.size()) - nextButton.setEnabled(false); - - fromHistory = false; + + // ICHANGED + int currentIndex = tabBrowser.currentIndex(); + ArrayList histGuids = historyGuids.get(currentIndex); + int histPosition = historyPosition.get(currentIndex); + boolean fromHist = fromHistory.get(currentIndex); + + // ICHANGED + if (!fromHist) { + int endPosition = histGuids.size() - 1; + + for (int j = histPosition; j <= endPosition; j++) { + histGuids.remove(histGuids.size() - 1); + } + histGuids.add(currentNoteGuid); + historyPosition.put(currentIndex, histGuids.size()); + histPosition = histGuids.size(); + } + if (histPosition <= 1){ + prevButton.setEnabled(false); + } + if (histPosition == histGuids.size()) + nextButton.setEnabled(false); + fromHistory.put(currentIndex, false); + fromHist = false; + scrollToGuid(currentNoteGuid); refreshEvernoteNote(true); - waitCursor(false); + + // ICHANGED + if (currentNoteGuid != null && !currentNoteGuid.equals("")) { + if (!Global.showDeleted) { // ゴミ箱じゃなければ + addBrowseHistory(); + } + } + + // ICHANGED + // 連想ノートリストを更新 + rensoNoteList.refreshRensoNoteList(currentNoteGuid); + + waitCursor(false); logger.log(logger.HIGH, "Leaving NeverNote.noteTableSelection"); - } + } + + + // ICHANGED + // 複数ノートの同時閲覧履歴をデータベースに保存 + private void addBrowseHistory() { + // このノートと他のタブウィンドウノートの関連性を内部データベースのHistoryテーブルに登録 + if (tabWindows.size() >= 2) { + Iterator it = tabWindows.keySet().iterator(); + while (it.hasNext()) { + int tabIndex = it.next(); + String nextGuid = ((TabBrowse) tabBrowser.widget(tabIndex)).getBrowserWindow().getNote().getGuid(); + // guid1=guid2のデータは登録しない + if (!currentNoteGuid.equals(nextGuid)) { + conn.getHistoryTable().addHistory("browse", currentNoteGuid, nextGuid); + } + } + } + // このノートと他の外部ウィンドウノートの関連性を内部データベースのHistoryテーブルに登録 + if (externalWindows.size() >= 1) { + Iterator it = externalWindows.keySet().iterator(); + while (it.hasNext()) { + String nextGuid = it.next(); + // guid1=guid2のデータは登録しない + if (!currentNoteGuid.equals(nextGuid)) { + conn.getHistoryTable().addHistory("browse", currentNoteGuid, nextGuid); + } + } + } + } + // Trigger a refresh when the note db has been updated private void noteIndexUpdated(boolean reload) { logger.log(logger.HIGH, "Entering NeverNote.noteIndexUpdated"); @@ -3800,9 +4085,13 @@ public class NeverNote extends QMainWindow{ String saveCurrentNoteGuid = new String(); String tempNoteGuid = new String(); - - historyGuids.clear(); - historyPosition = 0; + + // ICHANGED + int currentIndex = tabBrowser.currentIndex(); + ArrayList histGuids = historyGuids.get(currentIndex); + histGuids.clear(); + historyPosition.put(currentIndex, 0); + prevButton.setEnabled(false); nextButton.setEnabled(false); @@ -3840,48 +4129,68 @@ public class NeverNote extends QMainWindow{ logger.log(logger.HIGH, "Leaving NeverNote.refreshEvernoteNoteList"); } - // Called when the previous arrow button is clicked - @SuppressWarnings("unused") + + // ICHANGED + // Called when the previous arrow button is clicked + @SuppressWarnings("unused") private void previousViewedAction() { - if (!prevButton.isEnabled()) - return; - if (historyPosition == 0) - return; - historyPosition--; - if (historyPosition <= 0) - return; - String historyGuid = historyGuids.get(historyPosition-1); - fromHistory = true; - for (int i=0; i ix = noteTableView.model().itemData(modelIndex); - String tableGuid = (String)ix.values().toArray()[0]; - if (tableGuid.equals(historyGuid)) { - noteTableView.selectRow(i); - return; - } - } - } - } + int currentIndex = tabBrowser.currentIndex(); + ArrayList histGuids = historyGuids.get(currentIndex); + int histPosition = historyPosition.get(currentIndex); + boolean fromHist = fromHistory.get(currentIndex); + if (!prevButton.isEnabled()) + return; + if (histPosition == 0) + return; + histPosition--; + historyPosition.put(currentIndex, histPosition); + if (histPosition <= 0) + return; + String historyGuid = histGuids.get(histPosition - 1); + fromHistory.put(currentIndex, true); + fromHist = true; + for (int i = 0; i < noteTableView.model().rowCount(); i++) { + QModelIndex modelIndex = noteTableView.model().index(i, + Global.noteTableGuidPosition); + if (modelIndex != null) { + SortedMap ix = noteTableView.model().itemData( + modelIndex); + String tableGuid = (String) ix.values().toArray()[0]; + if (tableGuid.equals(historyGuid)) { + noteTableView.selectRow(i); + return; + } + } + } + } + @SuppressWarnings("unused") private void nextViewedAction() { if (!nextButton.isEnabled()) return; - String historyGuid = historyGuids.get(historyPosition); - historyPosition++; - fromHistory = true; - for (int i=0; i ix = noteTableView.model().itemData(modelIndex); - String tableGuid = (String)ix.values().toArray()[0]; - if (tableGuid.equals(historyGuid)) { - noteTableView.selectRow(i); - return; - } - } - } + // ICHANGED + int currentIndex = tabBrowser.currentIndex(); + ArrayList histGuids = historyGuids.get(currentIndex); + int histPosition = historyPosition.get(currentIndex); + boolean fromHist = fromHistory.get(currentIndex); + String historyGuid = histGuids.get(histPosition); + histPosition++; + historyPosition.put(currentIndex, histPosition); + fromHistory.put(currentIndex, true); + fromHist = true; + for (int i = 0; i < noteTableView.model().rowCount(); i++) { + QModelIndex modelIndex = noteTableView.model().index(i, + Global.noteTableGuidPosition); + if (modelIndex != null) { + SortedMap ix = noteTableView.model().itemData( + modelIndex); + String tableGuid = (String) ix.values().toArray()[0]; + if (tableGuid.equals(historyGuid)) { + noteTableView.selectRow(i); + return; + } + } + } } // Called when the up arrow is clicked @SuppressWarnings("unused") @@ -4213,6 +4522,10 @@ public class NeverNote extends QMainWindow{ } } } + + // ICHANGED + restoreSelectedNoteInfo(); + logger.log(logger.HIGH, "Leaving NeverNote.titleColorChanged"); } // A note has been pinned or unpinned @@ -4231,7 +4544,10 @@ public class NeverNote extends QMainWindow{ noteTableView.proxyModel.addGuid(selectedNoteGUIDs.get(j), meta); } - logger.log(logger.EXTREME, "Leaving NeverNote.setNoteDirty()"); + // ICHANGED + restoreSelectedNoteInfo(); + + logger.log(logger.EXTREME, "Leaving NeverNote.notePinned()"); } // Wide list was chosen public void narrowListView() { @@ -4255,7 +4571,9 @@ public class NeverNote extends QMainWindow{ menuBar.narrowListView.blockSignals(false); mainLeftRightSplitter.addWidget(noteTableView); - mainLeftRightSplitter.addWidget(browserWindow); + // ICHANGED browserWindow → tabBrowser + mainLeftRightSplitter.addWidget(tabBrowser); + restoreWindowState(false); noteTableView.repositionColumns(); noteTableView.resizeColumnWidths(); @@ -4294,7 +4612,9 @@ public class NeverNote extends QMainWindow{ menuBar.narrowListView.blockSignals(false); browserIndexSplitter.setVisible(true); browserIndexSplitter.addWidget(noteTableView); - browserIndexSplitter.addWidget(browserWindow); + // ICHANGED browserWindow → tabBrowser + browserIndexSplitter.addWidget(tabBrowser); + restoreWindowState(false); noteTableView.repositionColumns(); noteTableView.resizeColumnWidths(); @@ -4362,10 +4682,13 @@ public class NeverNote extends QMainWindow{ externalWindows.get(guid).raise(); return; } + Note note = conn.getNoteTable().getNote(guid, true, true, false, true, true); // We have a new external editor to create QIcon appIcon = new QIcon(iconPath+"nevernote.png"); - ExternalBrowse newBrowser = new ExternalBrowse(conn); + // ICHANGED + ExternalBrowse newBrowser = new ExternalBrowse(conn, cbObserver); + newBrowser.setWindowIcon(appIcon); externalWindows.put(guid, newBrowser); showEditorButtons(newBrowser.getBrowserWindow()); @@ -4400,9 +4723,191 @@ public class NeverNote extends QMainWindow{ private void externalWindowClosing(String guid) { externalWindows.remove(guid); } - - + // *************************************************************** + // *************************************************************** + // ** タブウィンドウの機能 + // *************************************************************** + // *************************************************************** + @SuppressWarnings("unused") + private void openNewTab() { + saveNote(); + + // selectedNoteGUIDsをディープコピー + List copySelected = new ArrayList(selectedNoteGUIDs); + + for (int i=0; i < copySelected.size() ; i++) { + openTabEditor(copySelected.get(i)); + } + } + + // ICHANGED 連想ノートリストから新しいタブで開く + @SuppressWarnings("unused") + private void openNewTabFromRNL(){ + if(rensoNotePressedItemGuid != null){ + String prevCurrentNoteGuid = new String(currentNoteGuid); + + saveNote(); + openTabEditor(rensoNotePressedItemGuid); + + // 連想ノートリストアイテムクリック操作を記録 + conn.getHistoryTable().addHistory("rensoItemClick", prevCurrentNoteGuid, rensoNotePressedItemGuid); + } + } + + // ICHANGED + private void openTabEditor(String guid) { + + Note note = conn.getNoteTable().getNote(guid, true, true, false, true, true); + // 新しいタブエディタを作成 + TabBrowse newBrowser = new TabBrowse(conn, tabBrowser, cbObserver); + showEditorButtons(newBrowser.getBrowserWindow()); + + // noteTableViewの選択を変更するとselectionChangedが発生してしまうので一度切断 + noteTableView.selectionModel().selectionChanged.disconnect(this, "noteTableSelection()"); + loadNoteBrowserInformation(newBrowser.getBrowserWindow(), guid, note); + // 再接続 + noteTableView.selectionModel().selectionChanged.connect(this, "noteTableSelection()"); + + setupBrowserWindowListeners(newBrowser.getBrowserWindow(), false); + + String noteTitle = note.getTitle(); + int index = tabBrowser.addNewTab(newBrowser, noteTitle); + tabWindows.put(index, newBrowser); + + // ExtendedInformationを必要があれば表示する + toggleNoteInformation(); + // Sourceを必要があれば表示する + viewSource(); + // EditorButtonsBarを必要があれば表示する + toggleEditorButtonBar(); + + // 履歴記録のハッシュマップを初期化 + ArrayList histGuids = new ArrayList(); + historyGuids.put(index, histGuids); + historyPosition.put(index, 0); + fromHistory.put(index, false); + + // 履歴に今開いたノートを追加 + histGuids.add(guid); + historyPosition.put(index, histGuids.size()); + + tabBrowser.setCurrentIndex(index); + + if (guid != null && !guid.equals("")) { + if (!Global.showDeleted) { // ゴミ箱じゃなければ + addBrowseHistory(); + } + } + } + + // ICHANGED タブが閉じられた + private void tabWindowClosing(int index) { + // タブが1つしかなかったら閉じない + if (tabBrowser.count() <= 1) { + return; + } + + TabBrowse t = (TabBrowse) tabBrowser.widget(index); + String guid = t.getBrowserWindow().getNote().getGuid(); + String content = t.getBrowserWindow().getContent(); + BrowserWindow browser = t.getBrowserWindow(); + // ノートが変更されていたら保存 + if (t.getNoteDirty()) { + saveNoteTabBrowser(guid, content, true, browser); + } + + // シグナル切断 + browser.noteSignal.tagsChanged.disconnect(); + browser.noteSignal.titleChanged.disconnect(); + browser.noteSignal.noteChanged.disconnect(); + browser.noteSignal.notebookChanged.disconnect(); + browser.noteSignal.createdDateChanged.disconnect(); + browser.noteSignal.alteredDateChanged.disconnect(); + + // ノートを削除 + tabWindows.remove(index); + tabBrowser.removeTab(index); + + // 履歴記録のハッシュマップを削除 + historyGuids.remove(index); + historyPosition.remove(index); + fromHistory.remove(index); + + // タブのインデックスを更新(削除によって空いた部分を詰める) + for(int i = index ; tabWindows.containsKey(i + 1) ; i++){ + // tabWindows + TabBrowse tab = tabWindows.get(i + 1); + tabWindows.put(i, tab); + tabWindows.remove(i + 1); + // historyGuids + ArrayList histGuids = historyGuids.get(i + 1); + historyGuids.put(i, histGuids); + historyGuids.remove(i + 1); + // historyPosition + int histPosition = historyPosition.get(i + 1); + historyPosition.put(i, histPosition); + historyPosition.remove(i + 1); + // fromHistory + boolean fromHist = fromHistory.get(i + 1); + fromHistory.put(i, fromHist); + fromHistory.remove(i + 1); + } + + // タブの閉じるボタンを押すと、tabWindowClosingより先にtabWindowChangedが呼ばれてしまうので、手動で呼びなおす + tabWindowChanged(tabBrowser.currentIndex()); + } + + @SuppressWarnings("unused") + private void noteAddNewTab() { + saveNote(); + + // ノート追加前に開いていたノートとの関連性を記録するためにguidをとっておく + TabBrowse prevTab = (TabBrowse)tabBrowser.currentWidget(); + String prevTabGuid = prevTab.getBrowserWindow().getNote().getGuid(); + + openEmptyTabEditor(); + addNote(); + + // 追加されたノートのguidを取得し、ノート追加操作履歴としてデータベースに登録 + TabBrowse addedTab = (TabBrowse)tabBrowser.currentWidget(); + String addedTabGuid = addedTab.getBrowserWindow().getNote().getGuid(); + if (prevTabGuid != null && !prevTabGuid.equals("")) { + if (addedTabGuid != null && !addedTabGuid.equals("")) { + if (!prevTabGuid.equals(addedTabGuid)) { + conn.getHistoryTable().addHistory("addNewNote", prevTabGuid, addedTabGuid); + } + } + } + } + + // ICHANGED + private void openEmptyTabEditor() { + // 新しいタブエディタを作成 + TabBrowse newBrowser = new TabBrowse(conn, tabBrowser, cbObserver); + showEditorButtons(newBrowser.getBrowserWindow()); + + setupBrowserWindowListeners(newBrowser.getBrowserWindow(), false); + + int index = tabBrowser.addNewTab(newBrowser, ""); + tabWindows.put(index, newBrowser); + + // ExtendedInformationを必要があれば表示する + toggleNoteInformation(); + // Sourceを必要があれば表示する + viewSource(); + // EditorButtonsBarを必要があれば表示する + toggleEditorButtonBar(); + + // 履歴記録のハッシュマップを初期化 + ArrayList histGuids = new ArrayList(); + historyGuids.put(index, histGuids); + historyPosition.put(index, 0); + fromHistory.put(index, false); + + tabBrowser.setCurrentIndex(index); + } + //*************************************************************** //*************************************************************** //** These functions deal with Note specific things @@ -4419,6 +4924,30 @@ public class NeverNote extends QMainWindow{ window.getBrowserWindow().setContent(unicode); } + // ICHANGED ↓↓↓ここから↓↓↓ + // 他のタブで同じノートを開いていないか探す。もしあったら、内容を更新する。 + Collection tabBrowsers = tabWindows.values(); + Iterator tabIterator = tabBrowsers.iterator(); + Collection tabIndexes = tabWindows.keySet(); + Iterator indexIterator = tabIndexes.iterator(); + + while (tabIterator.hasNext()) { + TabBrowse tab = tabIterator.next(); + int index = indexIterator.next(); + String guid = tab.getBrowserWindow().getNote().getGuid(); + + QTextCodec codec = QTextCodec.codecForName("UTF-8"); + QByteArray unicode = codec.fromUnicode(browserWindow.getContent()); + + if (guid.equals(currentNoteGuid)) { + if (index != tabBrowser.currentIndex()) { + TabBrowse window = tabWindows.get(index); + window.getBrowserWindow().setContent(unicode); + } + } + } + // ICHANGED ↑↑↑ここまで↑↑↑ + // If the note is dirty, then it is unsynchronized by default. if (noteDirty) return; @@ -4463,6 +4992,20 @@ public class NeverNote extends QMainWindow{ } } + + // ICHANGED + private void saveNoteTabBrowser(String guid, String content, Boolean save, + BrowserWindow browser) { + QTextCodec codec = QTextCodec.codecForName("UTF-8"); + QByteArray unicode = codec.fromUnicode(content); + noteCache.remove(guid); + noteCache.put(guid, unicode.toString()); + if (save) { + thumbnailRunner.addWork("GENERATE " + guid); + saveNote(guid, browser); + } + } + private void saveNote() { if (noteDirty) { saveNote(currentNoteGuid, browserWindow); @@ -4524,6 +5067,10 @@ public class NeverNote extends QMainWindow{ waitCursor(false); return; } + + // ICHANGED + tabBrowser.setTabTitle(tabBrowser.currentIndex(), currentNote.getTitle()); + loadNoteBrowserInformation(browserWindow, currentNoteGuid, currentNote); } @@ -4560,7 +5107,7 @@ public class NeverNote extends QMainWindow{ if (formatter.formatError) { waitCursor(false); QMessageBox.information(this, tr("Error"), - tr("NixNote had issues formatting this note." + + tr("NeighborNote had issues formatting this note." + " To protect your data this note is being marked as read-only.")); waitCursor(true); } @@ -4646,14 +5193,34 @@ public class NeverNote extends QMainWindow{ waitCursor(false); logger.log(logger.HIGH, "Leaving NeverNote.refreshEvernoteNote"); } + + // ICHANGED + @SuppressWarnings("unused") + private void toggleNoteAttributes() { + menuBar.noteAttributes.setChecked(!menuBar.noteAttributes.isChecked()); + toggleNoteInformation(); + } + // Save a generated thumbnail private void toggleNoteInformation() { logger.log(logger.HIGH, "Entering NeverNote.toggleNoteInformation"); - browserWindow.toggleInformation(); + + // ICHANGED + boolean isChecked = menuBar.noteAttributes.isChecked(); + + for(int i = 0; i < tabBrowser.count(); i++){ + BrowserWindow browser = ((TabBrowse) tabBrowser.widget(i)).getBrowserWindow(); + boolean isExtended = browser.isExtended(); + if((isChecked && !isExtended) || (!isChecked && isExtended)){ + browser.toggleInformation(); + } + } + menuBar.noteAttributes.setChecked(browserWindow.isExtended()); Global.saveWindowVisible("noteInformation", browserWindow.isExtended()); logger.log(logger.HIGH, "Leaving NeverNote.toggleNoteInformation"); } + // Listener triggered when a print button is pressed @SuppressWarnings("unused") private void printNote() { @@ -4755,6 +5322,9 @@ public class NeverNote extends QMainWindow{ if (QMessageBox.question(this, tr("Confirmation"), msg, QMessageBox.StandardButton.Yes, QMessageBox.StandardButton.No)==StandardButton.No.value() && Global.verifyDelete() == true) { + // ICHANGED + restoreSelectedNoteInfo(); + return; } } @@ -4778,6 +5348,9 @@ public class NeverNote extends QMainWindow{ if (QMessageBox.question(this, "Confirmation", msg, QMessageBox.StandardButton.Yes, QMessageBox.StandardButton.No)==StandardButton.No.value()) { + // ICHANGED + restoreSelectedNoteInfo(); + return; } } @@ -4796,9 +5369,68 @@ public class NeverNote extends QMainWindow{ } } listManager.expungeNote(selectedNoteGUIDs.get(i)); + + // ICHANGED + conn.getHistoryTable().expungeHistory(selectedNoteGUIDs.get(i)); + conn.getExcludedTable().expungeExcludedNote(selectedNoteGUIDs.get(i)); + conn.getStaredTable().expungeStaredNote(selectedNoteGUIDs.get(i)); + } } currentNoteGuid = ""; + + // ICHANGED ↓↓↓ここから↓↓↓ + // 削除したノートを外部ウィンドウで開いていたら、閉じる + Collection windows = externalWindows.values(); + Iterator windowIterator = windows.iterator(); + Collection guids = externalWindows.keySet(); + Iterator guidIterator = guids.iterator(); + List closeWindows = new ArrayList(); // イテレータ操作中に中身をいじっちゃダメなので + + while (windowIterator.hasNext()) { + ExternalBrowse browser = windowIterator.next(); + String guid = guidIterator.next(); + + for (int i = 0; i < selectedNoteGUIDs.size(); i++) { + if (guid.equals(selectedNoteGUIDs.get(i))) { + closeWindows.add(browser); + } + } + } + + for (int i = closeWindows.size() - 1; i >= 0; i--) { + closeWindows.get(i).close(); + } + // ICHANGED ↑↑↑ここまで↑↑↑ + + // ICHANGED ↓↓↓ここから↓↓↓ + // 削除したノートをタブで開いていたら、閉じる + Collection tabBrowsers = tabWindows.values(); + Iterator tabIterator = tabBrowsers.iterator(); + Collection tabIndexes = tabWindows.keySet(); + Iterator indexIterator = tabIndexes.iterator(); + List closeIndexes = new ArrayList(); //イテレータ操作中に中身をいじっちゃダメなので + + while (tabIterator.hasNext()) { + TabBrowse tab = tabIterator.next(); + int index = indexIterator.next(); + String guid = tab.getBrowserWindow().getNote().getGuid(); + + for(int i = 0; i < selectedNoteGUIDs.size(); i++){ + if(guid.equals(selectedNoteGUIDs.get(i))){ + closeIndexes.add(index); + } + } + } + + for(int i = closeIndexes.size() - 1; i >= 0; i--){ + tabWindowClosing(closeIndexes.get(i)); + } + // ICHANGED ↑↑↑ここまで↑↑↑ + + // ICHANGED + restoreSelectedNoteInfo(); + listManager.loadNotesIndex(); noteIndexUpdated(false); refreshEvernoteNote(true); @@ -4806,7 +5438,7 @@ public class NeverNote extends QMainWindow{ logger.log(logger.HIGH, "Leaving NeverNote.deleteNote"); } // Add a new note - @SuppressWarnings("unused") + // ICHANGED @SuppressWarnings("unused") を削除 private void addNote() { logger.log(logger.HIGH, "Inside NeverNote.addNote"); // browserWindow.setEnabled(true); @@ -4908,15 +5540,27 @@ public class NeverNote extends QMainWindow{ listManager.addNote(newNote, metadata); // noteTableView.insertRow(newNote, true, -1); + // ICHANGED + String prevCurrentNoteGuid = new String(currentNoteGuid); + currentNote = newNote; currentNoteGuid = currentNote.getGuid(); - noteTableView.clearSelection(); + // IFIXED こいつのせいで、ノート追加時にcurrentNoteGuidが更新されないので消す + // noteTableView.clearSelection(); + refreshEvernoteNote(true); listManager.countNotebookResults(listManager.getNoteIndex()); browserWindow.titleLabel.setFocus(); browserWindow.titleLabel.selectAll(); // notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter()); + // ICHANGED 新規に作成したノートとそれまで開いていたノートの関連性を追加 + if (prevCurrentNoteGuid != null && !prevCurrentNoteGuid.equals("")) { + if (currentNoteGuid != null && !currentNoteGuid.equals("")) { + conn.getHistoryTable().addHistory("addNewNote", prevCurrentNoteGuid, currentNoteGuid); + } + } + // If the window is hidden, then we want to popup this in an external window & if (!isVisible()) listDoubleClick(); @@ -4995,6 +5639,12 @@ public class NeverNote extends QMainWindow{ b.getBrowserWindow().getNote().setGuid(newGuid); externalWindows.put(newGuid, b); } + + // ICHANGED + for(int i = 0; i < tabBrowser.count(); i++){ + TabBrowse b = (TabBrowse)tabBrowser.widget(i); + b.getBrowserWindow().getNote().setGuid(newGuid); + } for (int i=0; i windows = externalWindows.values(); + Iterator windowIterator = windows.iterator(); + Collection guids = externalWindows.keySet(); + Iterator guidIterator = guids.iterator(); + List closeWindows = new ArrayList(); // イテレータ操作中に中身をいじっちゃダメなので + + while (windowIterator.hasNext()) { + ExternalBrowse browser = windowIterator.next(); + String guid = guidIterator.next(); + + for (int i = 0; i < sources.size(); i++) { + if (guid.equals(sources.get(i))) { + closeWindows.add(browser); + } + } + } + + for (int i = closeWindows.size() - 1; i >= 0; i--) { + closeWindows.get(i).close(); + } + // ICHANGED ↑↑↑ここまで↑↑↑ + + // ICHANGED ↓↓↓ここから↓↓↓ + // マージしたノート(child)をタブで開いていたら、閉じる + Collection tabBrowsers = tabWindows.values(); + Iterator tabIterator = tabBrowsers.iterator(); + Collection tabIndexes = tabWindows.keySet(); + Iterator indexIterator = tabIndexes.iterator(); + List closeIndexes = new ArrayList(); //イテレータ操作中に中身をいじっちゃダメなので + + while (tabIterator.hasNext()) { + TabBrowse tab = tabIterator.next(); + int tabIndex = indexIterator.next(); + String guid = tab.getBrowserWindow().getNote().getGuid(); + + for(int i = 0; i < sources.size(); i++){ + if(guid.equals(sources.get(i))){ + closeIndexes.add(tabIndex); + } + } + } + + for(int i = closeIndexes.size() - 1; i >= 0; i--){ + tabWindowClosing(closeIndexes.get(i)); + } + // ICHANGED ↑↑↑ここまで↑↑↑ + noteIndexUpdated(false); + // IFIXED + // ICHANGED マージ後の新しいノートコンテンツを表示するためキャッシュを削除 + noteCache.remove(masterGuid); + refreshEvernoteNote(true); waitCursor(false); } @@ -5262,7 +6003,7 @@ public class NeverNote extends QMainWindow{ } } msg = tr("An error has happened while saving the note \"") +title+ - tr("\".\n\nThis is probably due to a document that is too complex for NixNote to process. "+ + tr("\".\n\nThis is probably due to a document that is too complex for NeighborNote to process. "+ "As a result, changes to the note may not be saved properly in the database."+ "\n\nA cached copy is being preserved so you can recover any data, but data may" + "\nbe lost. Please review the note to recover any critical data before restarting."); @@ -5351,7 +6092,9 @@ public class NeverNote extends QMainWindow{ // If we've gotten this far, we have a good note. if (historyWindow == null) { - historyWindow = new OnlineNoteHistory(logger, conn); + // ICHANGED + historyWindow = new OnlineNoteHistory(logger, conn, cbObserver); + historyWindow.historyCombo.activated.connect(this, "reloadHistoryWindow(String)"); historyWindow.restoreAsNew.clicked.connect(this, "restoreHistoryNoteAsNew()"); historyWindow.restore.clicked.connect(this, "restoreHistoryNote()"); @@ -5763,7 +6506,7 @@ public class NeverNote extends QMainWindow{ thumbnailRunner.interrupt = true; indexRunner.addWork("SCAN"); } - logger.log(logger.EXTREME, "Leaving NixNote index timer"); + logger.log(logger.EXTREME, "Leaving NeighborNote index timer"); } @SuppressWarnings("unused") @@ -5797,7 +6540,7 @@ public class NeverNote extends QMainWindow{ tagDeadCount++; if (tagDeadCount > MAX && !disableTagThreadCheck) { QMessageBox.information(this, tr("A thread has died."), tr("It appears as the tag counter thread has died. I recommend "+ - "checking stopping NixNote, saving the logs for later viewing, and restarting. Sorry.")); + "checking stopping NeighborNote, saving the logs for later viewing, and restarting. Sorry.")); disableTagThreadCheck = true; } } else @@ -5808,7 +6551,7 @@ public class NeverNote extends QMainWindow{ notebookThreadDeadCount++; if (notebookThreadDeadCount > MAX && !disableNotebookThreadCheck) { QMessageBox.information(this, tr("A thread has died."), tr("It appears as the notebook counter thread has died. I recommend "+ - "checking stopping NixNote, saving the logs for later viewing, and restarting. Sorry.")); + "checking stopping NeighborNote, saving the logs for later viewing, and restarting. Sorry.")); disableNotebookThreadCheck=true; } } else @@ -5819,7 +6562,7 @@ public class NeverNote extends QMainWindow{ trashDeadCount++; if (trashDeadCount > MAX && !disableTrashThreadCheck) { QMessageBox.information(this, tr("A thread has died."), ("It appears as the trash counter thread has died. I recommend "+ - "checking stopping NixNote, saving the logs for later viewing, and restarting. Sorry.")); + "checking stopping NeighborNote, saving the logs for later viewing, and restarting. Sorry.")); disableTrashThreadCheck = true; } } else @@ -5830,7 +6573,7 @@ public class NeverNote extends QMainWindow{ saveThreadDeadCount++; if (saveThreadDeadCount > MAX && !disableSaveThreadCheck) { QMessageBox.information(this, tr("A thread has died."), tr("It appears as the note saver thread has died. I recommend "+ - "checking stopping NixNote, saving the logs for later viewing, and restarting. Sorry.")); + "checking stopping NeighborNote, saving the logs for later viewing, and restarting. Sorry.")); disableSaveThreadCheck = true; } } else @@ -5840,7 +6583,7 @@ public class NeverNote extends QMainWindow{ syncThreadDeadCount++; if (syncThreadDeadCount > MAX && !disableSyncThreadCheck) { QMessageBox.information(this, tr("A thread has died."), tr("It appears as the synchronization thread has died. I recommend "+ - "checking stopping NixNote, saving the logs for later viewing, and restarting. Sorry.")); + "checking stopping NeighborNote, saving the logs for later viewing, and restarting. Sorry.")); disableSyncThreadCheck = true; } } else @@ -5850,7 +6593,7 @@ public class NeverNote extends QMainWindow{ indexThreadDeadCount++; if (indexThreadDeadCount > MAX && !disableIndexThreadCheck) { QMessageBox.information(this, tr("A thread has died."), tr("It appears as the index thread has died. I recommend "+ - "checking stopping NixNote, saving the logs for later viewing, and restarting. Sorry.")); + "checking stopping NeighborNote, saving the logs for later viewing, and restarting. Sorry.")); disableIndexThreadCheck = true; } } else @@ -6532,7 +7275,11 @@ public class NeverNote extends QMainWindow{ //* View / Hide source HTML for a note //************************************************* public void viewSource() { - browserWindow.showSource(menuBar.viewSource.isChecked()); + // ICHANGED すべてのタブに対して + for(int i = 0; i < tabBrowser.count(); i++){ + BrowserWindow browser = ((TabBrowse) tabBrowser.widget(i)).getBrowserWindow(); + browser.showSource(menuBar.viewSource.isChecked()); + } } //************************************************* // Block the program. This is used for things @@ -6563,4 +7310,325 @@ public class NeverNote extends QMainWindow{ blockingWindow = null; blockSignals(false); } + + // ICHANGED + // タブが変更された + private void tabWindowChanged(int index) { + if (index < 0 || index >= tabBrowser.count()) { + return; + } + + saveNote(); + + TabBrowse tab = (TabBrowse) tabBrowser.widget(index); + if (tab.getBrowserWindow().getNote() != null) { + currentNoteGuid = tab.getBrowserWindow().getNote().getGuid(); + currentNote = tab.getBrowserWindow().getNote(); + } else { + currentNoteGuid = ""; + currentNote = null; + } + + // 選択ノートを更新 + selectedNoteGUIDs.clear(); + if (currentNoteGuid != null && !currentNoteGuid.equals("")) { + selectedNoteGUIDs.add(currentNoteGuid); + } + + // browserWindowを更新 + browserWindow.noteSignal.noteChanged.disconnect(this,"setNoteDirty()"); + browserWindow.focusLost.disconnect(this, "saveNote()"); + browserWindow = tab.getBrowserWindow(); + browserWindow.noteSignal.noteChanged.connect(this, "setNoteDirty()"); + browserWindow.focusLost.connect(this, "saveNote()"); + // メニューバーのボタンを新しいbrowserWindowに合わせる + menuBar.refreshTargetWindow(); + + // 現在ゴミ箱かつ移るタブがアクティブなら通常テーブルに、現在通常テーブルかつこれから非アクティブのタブに移るならゴミ箱を表示させる + boolean nextIsActive; + if (tab.getBrowserWindow().getNote() != null) { + nextIsActive = tab.getBrowserWindow().getNote().isActive(); + } else { + nextIsActive = true; + } + if (Global.showDeleted && nextIsActive) { + switchNoteTable(false); + } else if (!Global.showDeleted && !nextIsActive) { + switchNoteTable(true); + } + + // noteTableViewの選択を変更するとselectionChangedが発生してしまうので一度切断 + noteTableView.selectionModel().selectionChanged.disconnect(this,"noteTableSelection()"); + scrollToGuid(currentNoteGuid); + // 再接続 + noteTableView.selectionModel().selectionChanged.connect(this,"noteTableSelection()"); + + menuBar.noteDuplicateAction.setEnabled(true); + menuBar.noteOnlineHistoryAction.setEnabled(true); + menuBar.noteMergeAction.setEnabled(true); + + if (Global.showDeleted) { + menuBar.noteDuplicateAction.setEnabled(false); + } + if (!Global.isConnected) { + menuBar.noteOnlineHistoryAction.setEnabled(false); + } + menuBar.noteMergeAction.setEnabled(false); + try { + int row = noteTableView.selectionModel().selectedRows().get(0).row(); + if (row == 0) + upButton.setEnabled(false); + else + upButton.setEnabled(true); + if (row < listManager.getNoteTableModel().rowCount() - 1) + downButton.setEnabled(true); + else + downButton.setEnabled(false); + } catch (Exception e) { + upButton.setEnabled(false); + downButton.setEnabled(false); + } + + int currentIndex = tabBrowser.currentIndex(); + ArrayList histGuids = historyGuids.get(currentIndex); + int histPosition = historyPosition.get(currentIndex); + + // prev, nextボタンの有効・無効化 + nextButton.setEnabled(true); + prevButton.setEnabled(true); + + if (histPosition <= 1){ + prevButton.setEnabled(false); + } + if (histPosition == histGuids.size()){ + nextButton.setEnabled(false); + } + + refreshEvernoteNote(true); + + // 連想ノートリストを更新 + rensoNoteList.refreshRensoNoteList(currentNoteGuid); + } + + // ICHANGD + // 生存ノートテーブル→ゴミ箱(またはその逆)に切り替える + private void switchNoteTable(boolean toDeleted) { + clearNotebookFilter(); + clearTagFilter(); + clearAttributeFilter(); + clearSavedSearchFilter(); + + listManager.getSelectedNotebooks().clear(); + listManager.getSelectedTags().clear(); + listManager.setSelectedSavedSearch(""); + + // toggle the add buttons + newButton.setEnabled(!newButton.isEnabled()); + menuBar.noteAdd.setEnabled(newButton.isEnabled()); + menuBar.noteAdd.setVisible(true); + + if (!toDeleted) { // 生存ノートテーブルへ + trashTree.itemSelectionChanged.disconnect(this, "trashTreeSelection()"); + trashTree.clearSelection(); + trashTree.itemSelectionChanged.connect(this, "trashTreeSelection()"); + Global.showDeleted = false; + menuBar.noteRestoreAction.setEnabled(false); + menuBar.noteRestoreAction.setVisible(false); + // ICHANGED ゴミ箱から元の画面に戻す。連想ノートリストをONに。 + rensoNoteListDock.setEnabled(true); + } else { // ゴミ箱へ + trashTree.itemSelectionChanged.disconnect(this, "trashTreeSelection()"); + trashTree.setCurrentItem(trashTree.getTrashItem()); + trashTree.itemSelectionChanged.connect(this, "trashTreeSelection()"); + Global.showDeleted = true; + menuBar.noteRestoreAction.setEnabled(true); + menuBar.noteRestoreAction.setVisible(true); + // ICHANGED ゴミ箱を開く。連想ノートリストをOFFに。 + rensoNoteListDock.setEnabled(false); + } + + listManager.loadNotesIndex(); + // noteTableViewの選択を変更するとselectionChangedが発生してしまうので一度切断 + noteTableView.selectionModel().selectionChanged.disconnect(this,"noteTableSelection()"); + noteIndexUpdated(false); + // 再接続 + noteTableView.selectionModel().selectionChanged.connect(this,"noteTableSelection()"); + + browserWindow.setReadOnly(!newButton.isEnabled()); + } + + // ICHANGED + // ユーザが連想ノートリストのアイテムを選択した時の処理 + @SuppressWarnings("unused") + private void rensoNoteItemPressed(QListWidgetItem current) { + logger.log(logger.HIGH, "Nevernote.rensoNoteSelectionChangeに入った"); + + rensoNotePressedItemGuid = null; + // 右クリックだったときの処理 + if (QApplication.mouseButtons().isSet(MouseButton.RightButton)) { + rensoNotePressedItemGuid = rensoNoteList.getNoteGuid(current); + return; + } + + saveNote(); + + String prevCurrentNoteGuid = new String(currentNoteGuid); + + // 選択されたノート(current)のguidをcurrentnoteguidにセット + currentNoteGuid = rensoNoteList.getNoteGuid(current); + + // 選択ノートを更新 + selectedNoteGUIDs.clear(); + selectedNoteGUIDs.add(currentNoteGuid); + + nextButton.setEnabled(true); + prevButton.setEnabled(true); + + int currentIndex = tabBrowser.currentIndex(); + ArrayList histGuids = historyGuids.get(currentIndex); + int histPosition = historyPosition.get(currentIndex); + boolean fromHist = fromHistory.get(currentIndex); + + int endPosition = histGuids.size() - 1; + for (int j = histPosition; j <= endPosition; j++) { + histGuids.remove(histGuids.size() - 1); + } + + histGuids.add(currentNoteGuid); + historyPosition.put(currentIndex, histGuids.size()); + histPosition = histGuids.size(); + + if (histPosition <= 1) + prevButton.setEnabled(false); + if (histPosition == histGuids.size()) + nextButton.setEnabled(false); + + // noteTableViewの選択を変更するとselectionChangedが発生してしまうので一度切断 + noteTableView.selectionModel().selectionChanged.disconnect(this, "noteTableSelection()"); + scrollToGuid(currentNoteGuid); + // 再接続 + noteTableView.selectionModel().selectionChanged.connect(this, "noteTableSelection()"); + + refreshEvernoteNote(true); // Evernoteからノートをゲット(そしてブラウザに表示) + + // upButton, downButton, 選択リストア用のprevRowを設定 + int row = noteTableView.selectionModel().selectedRows().get(0).row(); + if (row == 0) + upButton.setEnabled(false); + else + upButton.setEnabled(true); + if (row < listManager.getNoteTableModel().rowCount() - 1) + downButton.setEnabled(true); + else + downButton.setEnabled(false); + + // 連想ノートリストアイテムクリック操作を記録 + conn.getHistoryTable().addHistory("rensoItemClick", prevCurrentNoteGuid, currentNoteGuid); + + // 連想ノートリストを更新 + rensoNoteList.refreshRensoNoteList(currentNoteGuid); + + logger.log(logger.HIGH, "Nevernote.rensoNoteSelectionChangeを出た"); + } + + // ICHANGED + public void restoreSelectedNoteInfo(){ + // 現在のタブからguid取得 + // currentNoteGuid = browserWindow.getNote().getGuid(); ↓と同じはずだけど敢えて使わない + int currentTabIndex = tabBrowser.currentIndex(); + TabBrowse currentTab = tabWindows.get(currentTabIndex); + currentNoteGuid = currentTab.getBrowserWindow().getNote().getGuid(); + + selectedNoteGUIDs.clear(); + selectedNoteGUIDs.add(currentNoteGuid); + + // noteTableViewの選択を変更するとselectionChangedが発生してしまうので一度切断 + noteTableView.selectionModel().selectionChanged.disconnect(this, "noteTableSelection()"); + scrollToGuid(currentNoteGuid); + // 再接続 + noteTableView.selectionModel().selectionChanged.connect(this, "noteTableSelection()"); + } + + // ICHANGED + // 関連ノートリストからノートを除外する + @SuppressWarnings("unused") + private void excludeNote() { + if (rensoNotePressedItemGuid != null) { + saveNote(); + excludeNote(rensoNotePressedItemGuid); + } + } + + // ICHANGED + // 関連ノートリストからノートを除外する + private void excludeNote(String guid) { + if (Global.verifyExclude()) { + String msg; + Note note = conn.getNoteTable().getNote(guid, false, false, false, false, false); + String title = note.getTitle(); + if (title != null) { + msg = new String(tr("Exclude note \"") +title +"\"?"); + } else { + msg = new String(tr("Exclude note selected note?")); + } + + if (QMessageBox.question(this, tr("Confirmation"), msg, + QMessageBox.StandardButton.Yes, + QMessageBox.StandardButton.No)==StandardButton.No.value() && Global.verifyDelete() == true) { + return; + } + } + + // Historyデータベースから除外するノートのデータを削除 + conn.getHistoryTable().expungeHistory(guid, currentNoteGuid); + + // 除外ノートテーブルに追加 + conn.getExcludedTable().addExclusion(guid, currentNoteGuid); + + rensoNoteList.refreshRensoNoteList(currentNoteGuid); + } + + // ICHANGED + // 関連ノートリストのノートにスターを付ける + @SuppressWarnings("unused") + private void starNote() { + if (rensoNotePressedItemGuid != null) { + saveNote(); + starNote(rensoNotePressedItemGuid); + } + } + + // ICHANGED + // 関連ノートリストのノートにスターを付ける + private void starNote(String guid) { + // スター付きノートテーブルに追加 + conn.getStaredTable().addStaredItem(currentNoteGuid, guid); + + rensoNoteList.refreshRensoNoteList(currentNoteGuid); + } + + // ICHANGED + // 関連ノートリストのノートからスターを外す + @SuppressWarnings("unused") + private void unstarNote() { + if (rensoNotePressedItemGuid != null) { + saveNote(); + unstarNote(rensoNotePressedItemGuid); + } + } + + // ICHANGED + // 関連ノートリストのノートからスターを外す + private void unstarNote(String guid) { + // スター付きノートテーブルから削除 + conn.getStaredTable().removeStaredItem(currentNoteGuid, guid); + + rensoNoteList.refreshRensoNoteList(currentNoteGuid); + } + + // ICHANGED + // currentNoteGuidを返す + public String getCurrentNoteGuid() { + return currentNoteGuid; + } } diff --git a/src/cx/fbn/nevernote/dialog/ConfigDialog.java b/src/cx/fbn/nevernote/dialog/ConfigDialog.java index 5e7e7bb..1c82a3b 100644 --- a/src/cx/fbn/nevernote/dialog/ConfigDialog.java +++ b/src/cx/fbn/nevernote/dialog/ConfigDialog.java @@ -52,6 +52,9 @@ public class ConfigDialog extends QDialog { private final ConfigAppearancePage appearancePage; private final ConfigSpellPage spellPage; private final ConfigIndexPage indexPage; + // ICHANGED + private final ConfigRensoNoteListPage rensoNoteListPage; + private final String iconPath = new String("classpath:cx/fbn/nevernote/icons/"); public ConfigDialog(QWidget parent) { @@ -71,12 +74,17 @@ public class ConfigDialog extends QDialog { indexPage = new ConfigIndexPage(this); debugPage = new ConfigDebugPage(this); spellPage = new ConfigSpellPage(this); + // ICHANGED + rensoNoteListPage = new ConfigRensoNoteListPage(this); + pagesWidget.addWidget(appearancePage); pagesWidget.addWidget(fontPage); pagesWidget.addWidget(indexPage); pagesWidget.addWidget(spellPage); pagesWidget.addWidget(connectionPage); pagesWidget.addWidget(debugPage); + // ICHANGED + pagesWidget.addWidget(rensoNoteListPage); QPushButton cancelButton = new QPushButton(tr("Cancel")); QPushButton okButton = new QPushButton(tr("OK")); @@ -214,7 +222,21 @@ public class ConfigDialog extends QDialog { Global.setDefaultFont(fontPage.getFont()); Global.setDefaultFontSize(fontPage.getFontSize()); Global.setDatabaseCache(debugPage.getDatabaseCacheSize()); - + + // ICHANGED + Global.setBrowseWeight(rensoNoteListPage.getBrowseWeight()); + Global.setCopyPasteWeight(rensoNoteListPage.getCopyPasteWeight()); + Global.setAddNewNoteWeight(rensoNoteListPage.getAddNewNoteWeight()); + Global.setRensoItemClickWeight(rensoNoteListPage.getRensoItemClickWeight()); + Global.setSameTagWeight(rensoNoteListPage.getSameTagWeight()); + Global.setSameNotebookWeight(rensoNoteListPage.getSameNotebookWeight()); + + // ICHANGED + Global.setMergeRensoNote(rensoNoteListPage.getMergeChecked()); + Global.setDuplicateRensoNote(rensoNoteListPage.getDuplicateChecked()); + Global.setVerifyExclude(rensoNoteListPage.getVerifyExcludeChecked()); + Global.setRensoListItemMaximum(rensoNoteListPage.getRensoListItemMaximum()); + close(); } @@ -245,7 +267,7 @@ public class ConfigDialog extends QDialog { formatsButton.setText(tr("Appearance")); formatsButton.setTextAlignment(AlignmentFlag.AlignHCenter.value()); formatsButton.setFlags(ItemFlag.ItemIsSelectable, ItemFlag.ItemIsEnabled); - formatsButton.setIcon(new QIcon(iconPath+"appearance.jpg")); + formatsButton.setIcon(new QIcon(iconPath+"appearance.png")); QListWidgetItem fontButton = new QListWidgetItem(contentsWidget); fontButton.setText(tr("Fonts")); @@ -277,6 +299,13 @@ public class ConfigDialog extends QDialog { debugButton.setFlags(ItemFlag.ItemIsSelectable, ItemFlag.ItemIsEnabled); debugButton.setIcon(new QIcon(iconPath+"debug.jpg")); + // ICHANGED + QListWidgetItem rensoListButton = new QListWidgetItem(contentsWidget); + rensoListButton.setText(tr("Renso Note List")); + rensoListButton.setTextAlignment(AlignmentFlag.AlignCenter.value()); + rensoListButton.setFlags(ItemFlag.ItemIsSelectable, ItemFlag.ItemIsEnabled); + rensoListButton.setIcon(new QIcon(iconPath+"rensoNoteList.png")); + contentsWidget.currentItemChanged.connect(this, "changePage(QListWidgetItem, QListWidgetItem)"); } @@ -293,7 +322,10 @@ public class ConfigDialog extends QDialog { debugPage.setDisableUploads(Global.disableUploads); debugPage.setEnableThumbnails(Global.enableThumbnails()); // if (Global.getUpdateSequenceNumber() > 0) - debugPage.serverCombo.setEnabled(false); + + // ICHANGED + // TODO ↓のコメントアウトは最終的に外す(設定のデバッグページのサーバー選択を使用不可にする) + // debugPage.serverCombo.setEnabled(false); appearancePage.setAutoSaveInterval(Global.getAutoSaveInterval()); connectionPage.setAutomaticLogin(Global.automaticLogin()); diff --git a/src/cx/fbn/nevernote/dialog/ConfigRensoNoteListPage.java b/src/cx/fbn/nevernote/dialog/ConfigRensoNoteListPage.java new file mode 100644 index 0000000..62b69f9 --- /dev/null +++ b/src/cx/fbn/nevernote/dialog/ConfigRensoNoteListPage.java @@ -0,0 +1,285 @@ +// ICHANGED +package cx.fbn.nevernote.dialog; + +import com.trolltech.qt.core.Qt; +import com.trolltech.qt.gui.QCheckBox; +import com.trolltech.qt.gui.QFormLayout; +import com.trolltech.qt.gui.QGroupBox; +import com.trolltech.qt.gui.QHBoxLayout; +import com.trolltech.qt.gui.QSlider; +import com.trolltech.qt.gui.QSpinBox; +import com.trolltech.qt.gui.QVBoxLayout; +import com.trolltech.qt.gui.QWidget; + +import cx.fbn.nevernote.Global; + +public class ConfigRensoNoteListPage extends QWidget { + private final QSlider browseSlider; + private final QSlider copyPasteSlider; + private final QSlider addNewNoteSlider; + private final QSlider rensoItemClickSlider; + private final QSlider sameTagSlider; + private final QSlider sameNotebookSlider; + + private final QSpinBox browseSpinner; + private final QSpinBox copyPasteSpinner; + private final QSpinBox addNewNoteSpinner; + private final QSpinBox rensoItemClickSpinner; + private final QSpinBox sameTagSpinner; + private final QSpinBox sameNotebookSpinner; + private final QSpinBox rensoListItemMaximumSpinner; + + private final QCheckBox mergeCheck; + private final QCheckBox duplicateCheck; + private final QCheckBox verifyExclude; + + public ConfigRensoNoteListPage(QWidget parent) { + // 操作履歴への重み付け + // browseHistory + browseSlider = new QSlider(); + browseSlider.setOrientation(Qt.Orientation.Horizontal); + browseSlider.setRange(0, 10); + browseSlider.setSingleStep(1); + browseSlider.setTickPosition(QSlider.TickPosition.TicksAbove); + browseSlider.setTickInterval(1); + browseSlider.setFocusPolicy(Qt.FocusPolicy.StrongFocus); + + browseSpinner = new QSpinBox(); + browseSpinner.setRange(0,10); + browseSpinner.setSingleStep(1); + + browseSlider.valueChanged.connect(browseSpinner, "setValue(int)"); + browseSpinner.valueChanged.connect(browseSlider, "setValue(int)"); + browseSlider.setValue(Global.getBrowseWeight()); + + QHBoxLayout browseLayout = new QHBoxLayout(); + browseLayout.addWidget(browseSlider); + browseLayout.addWidget(browseSpinner); + + + // copyPasteHistory + copyPasteSlider = new QSlider(); + copyPasteSlider.setOrientation(Qt.Orientation.Horizontal); + copyPasteSlider.setRange(0, 10); + copyPasteSlider.setSingleStep(1); + copyPasteSlider.setTickPosition(QSlider.TickPosition.TicksAbove); + copyPasteSlider.setTickInterval(1); + copyPasteSlider.setFocusPolicy(Qt.FocusPolicy.StrongFocus); + + copyPasteSpinner = new QSpinBox(); + copyPasteSpinner.setRange(0,10); + copyPasteSpinner.setSingleStep(1); + + copyPasteSlider.valueChanged.connect(copyPasteSpinner, "setValue(int)"); + copyPasteSpinner.valueChanged.connect(copyPasteSlider, "setValue(int)"); + copyPasteSlider.setValue(Global.getCopyPasteWeight()); + + + QHBoxLayout copyPasteLayout = new QHBoxLayout(); + copyPasteLayout.addWidget(copyPasteSlider); + copyPasteLayout.addWidget(copyPasteSpinner); + + + // addNewNoteHistory + addNewNoteSlider = new QSlider(); + addNewNoteSlider.setOrientation(Qt.Orientation.Horizontal); + addNewNoteSlider.setRange(0, 10); + addNewNoteSlider.setSingleStep(1); + addNewNoteSlider.setTickPosition(QSlider.TickPosition.TicksAbove); + addNewNoteSlider.setTickInterval(1); + addNewNoteSlider.setFocusPolicy(Qt.FocusPolicy.StrongFocus); + + addNewNoteSpinner = new QSpinBox(); + addNewNoteSpinner.setRange(0,10); + addNewNoteSpinner.setSingleStep(1); + + addNewNoteSlider.valueChanged.connect(addNewNoteSpinner, "setValue(int)"); + addNewNoteSpinner.valueChanged.connect(addNewNoteSlider, "setValue(int)"); + addNewNoteSlider.setValue(Global.getAddNewNoteWeight()); + + QHBoxLayout addNewNoteLayout = new QHBoxLayout(); + addNewNoteLayout.addWidget(addNewNoteSlider); + addNewNoteLayout.addWidget(addNewNoteSpinner); + + + // rensoItemClickHistory + rensoItemClickSlider = new QSlider(); + rensoItemClickSlider.setOrientation(Qt.Orientation.Horizontal); + rensoItemClickSlider.setRange(0, 10); + rensoItemClickSlider.setSingleStep(1); + rensoItemClickSlider.setTickPosition(QSlider.TickPosition.TicksAbove); + rensoItemClickSlider.setTickInterval(1); + rensoItemClickSlider.setFocusPolicy(Qt.FocusPolicy.StrongFocus); + + rensoItemClickSpinner = new QSpinBox(); + rensoItemClickSpinner.setRange(0,10); + rensoItemClickSpinner.setSingleStep(1); + + rensoItemClickSlider.valueChanged.connect(rensoItemClickSpinner, "setValue(int)"); + rensoItemClickSpinner.valueChanged.connect(rensoItemClickSlider, "setValue(int)"); + rensoItemClickSlider.setValue(Global.getRensoItemClickWeight()); + + QHBoxLayout rensoItemClickLayout = new QHBoxLayout(); + rensoItemClickLayout.addWidget(rensoItemClickSlider); + rensoItemClickLayout.addWidget(rensoItemClickSpinner); + + // sameTagHistory + sameTagSlider = new QSlider(); + sameTagSlider.setOrientation(Qt.Orientation.Horizontal); + sameTagSlider.setRange(0, 10); + sameTagSlider.setSingleStep(1); + sameTagSlider.setTickPosition(QSlider.TickPosition.TicksAbove); + sameTagSlider.setTickInterval(1); + sameTagSlider.setFocusPolicy(Qt.FocusPolicy.StrongFocus); + + sameTagSpinner = new QSpinBox(); + sameTagSpinner.setRange(0,10); + sameTagSpinner.setSingleStep(1); + + sameTagSlider.valueChanged.connect(sameTagSpinner, "setValue(int)"); + sameTagSpinner.valueChanged.connect(sameTagSlider, "setValue(int)"); + sameTagSlider.setValue(Global.getSameTagWeight()); + + QHBoxLayout sameTagLayout = new QHBoxLayout(); + sameTagLayout.addWidget(sameTagSlider); + sameTagLayout.addWidget(sameTagSpinner); + + // sameNotebookHistory + sameNotebookSlider = new QSlider(); + sameNotebookSlider.setOrientation(Qt.Orientation.Horizontal); + sameNotebookSlider.setRange(0, 10); + sameNotebookSlider.setSingleStep(1); + sameNotebookSlider.setTickPosition(QSlider.TickPosition.TicksAbove); + sameNotebookSlider.setTickInterval(1); + sameNotebookSlider.setFocusPolicy(Qt.FocusPolicy.StrongFocus); + + sameNotebookSpinner = new QSpinBox(); + sameNotebookSpinner.setRange(0,10); + sameNotebookSpinner.setSingleStep(1); + + sameNotebookSlider.valueChanged.connect(sameNotebookSpinner, "setValue(int)"); + sameNotebookSpinner.valueChanged.connect(sameNotebookSlider, "setValue(int)"); + sameNotebookSlider.setValue(Global.getSameNotebookWeight()); + + QHBoxLayout sameNotebookLayout = new QHBoxLayout(); + sameNotebookLayout.addWidget(sameNotebookSlider); + sameNotebookLayout.addWidget(sameNotebookSpinner); + + QFormLayout styleLayout = new QFormLayout(); + styleLayout.setHorizontalSpacing(10); + styleLayout.setVerticalSpacing(30); + styleLayout.addRow(tr("Browse Weight"), browseLayout); + styleLayout.addRow(tr("Copy&Paste Weight"), copyPasteLayout); + styleLayout.addRow(tr("Add New Note Weight"), addNewNoteLayout); + styleLayout.addRow(tr("Renso Item Click Weight"), rensoItemClickLayout); + styleLayout.addRow(tr("Same Tag Weight"), sameTagLayout); + styleLayout.addRow(tr("Same Notebook Weight"), sameNotebookLayout); + + QGroupBox weightingGroup = new QGroupBox(tr("Weighting")); + weightingGroup.setLayout(styleLayout); + + // ノートのマージ・複製の関連ノートリストへの適用 + mergeCheck = new QCheckBox(tr("When you merge the notes, also merge RensoNoteList")); + mergeCheck.setChecked(Global.getMergeRensoNote()); + duplicateCheck = new QCheckBox(tr("When you duplicate the notes, also duplicate RensoNoteList")); + duplicateCheck.setChecked(Global.getDuplicateRensoNote()); + verifyExclude = new QCheckBox(tr("Verify when you exclude the note")); + verifyExclude.setChecked(Global.verifyExclude()); + + // 連想ノートリスト最大アイテム表示数 + rensoListItemMaximumSpinner = new QSpinBox(); + rensoListItemMaximumSpinner.setRange(1,100); + rensoListItemMaximumSpinner.setSingleStep(1); + rensoListItemMaximumSpinner.setValue(Global.getRensoListItemMaximum()); + QFormLayout fLayout = new QFormLayout(); + fLayout.setHorizontalSpacing(100); + fLayout.addRow(tr("Renso Note List Item Maximum"), rensoListItemMaximumSpinner); + + // その他のレイアウト + QVBoxLayout othersLayout = new QVBoxLayout(); + othersLayout.addWidget(mergeCheck); + othersLayout.addWidget(duplicateCheck); + othersLayout.addWidget(verifyExclude); + othersLayout.addLayout(fLayout); + + QGroupBox othersGroup = new QGroupBox(tr("Others")); + othersGroup.setLayout(othersLayout); + + QVBoxLayout mainLayout = new QVBoxLayout(); + mainLayout.addWidget(weightingGroup); + mainLayout.addWidget(othersGroup); + mainLayout.addStretch(1); + setLayout(mainLayout); + + } + + //***************************************** + //* Browse Weight + //***************************************** + public int getBrowseWeight() { + return browseSpinner.value(); + } + + //***************************************** + //* Copy & Paste Weight + //***************************************** + public int getCopyPasteWeight() { + return copyPasteSpinner.value(); + } + + //***************************************** + //* Add New Note Weight + //***************************************** + public int getAddNewNoteWeight() { + return addNewNoteSpinner.value(); + } + + //***************************************** + //* Renso Item Click Weight + //***************************************** + public int getRensoItemClickWeight() { + return rensoItemClickSpinner.value(); + } + + //***************************************** + //* Same Tag Weight + //***************************************** + public int getSameTagWeight() { + return sameTagSpinner.value(); + } + + //***************************************** + //* Same Notebook Weight + //***************************************** + public int getSameNotebookWeight() { + return sameNotebookSpinner.value(); + } + + //***************************************** + //* Merge Check + //***************************************** + public boolean getMergeChecked() { + return mergeCheck.isChecked(); + } + + //***************************************** + //* DuplicateCheck + //***************************************** + public boolean getDuplicateChecked() { + return duplicateCheck.isChecked(); + } + + //***************************************** + //* VerifyExcludeCheck + //***************************************** + public boolean getVerifyExcludeChecked() { + return verifyExclude.isChecked(); + } + + //***************************************** + //* RensoNoteListItemMaximum + //***************************************** + public int getRensoListItemMaximum() { + return rensoListItemMaximumSpinner.value(); + } +} diff --git a/src/cx/fbn/nevernote/dialog/LogFileDialog.java b/src/cx/fbn/nevernote/dialog/LogFileDialog.java index 5240994..79f668f 100644 --- a/src/cx/fbn/nevernote/dialog/LogFileDialog.java +++ b/src/cx/fbn/nevernote/dialog/LogFileDialog.java @@ -84,7 +84,7 @@ public class LogFileDialog extends QDialog { fileCombo.addItem(tr("Index Log"), "IndexLog"); fileCombo.addItem(tr("Database Connection Log"), "DatabaseLog"); fileCombo.addItem(tr("Thumbnail Generator Log"), "ThumbnailLog"); - fileCombo.addItem(tr("NixNote Database SQL Trace File"), "NeverNoteDBLog"); + fileCombo.addItem(tr("NeighborNote Database SQL Trace File"), "NeverNoteDBLog"); fileCombo.addItem(tr("Index Database SQL Trace File"), "IndexDBLog"); fileCombo.addItem(tr("Resource Database SQL Trace File"), "ResourceDBLog"); diff --git a/src/cx/fbn/nevernote/dialog/NoteQuickLinkDialog.java b/src/cx/fbn/nevernote/dialog/NoteQuickLinkDialog.java index f8c85ea..be6c4e9 100644 --- a/src/cx/fbn/nevernote/dialog/NoteQuickLinkDialog.java +++ b/src/cx/fbn/nevernote/dialog/NoteQuickLinkDialog.java @@ -1,181 +1,189 @@ -/* - * This file is part of NixNote - * Copyright 2011 Randy Baumgarte - * - * This file may be licensed under the terms of of the - * GNU General Public License Version 2 (the ``GPL''). - * - * Software distributed under the License is distributed - * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either - * express or implied. See the GPL for the specific language - * governing rights and limitations. - * - * You should have received a copy of the GPL along with this - * program. If not, go to http://www.gnu.org/licenses/gpl.html - * or write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * -*/ - -package cx.fbn.nevernote.dialog; - -//********************************************** -//********************************************** -//* This is the dialog that shows a user -//* a quick popup of a note based upon its title. -//* It is used in the Quick Link function. -//********************************************** -//********************************************** - -import java.util.List; - -import com.evernote.edam.type.Note; -import com.trolltech.qt.core.QByteArray; -import com.trolltech.qt.core.QTemporaryFile; -import com.trolltech.qt.core.Qt.ContextMenuPolicy; -import com.trolltech.qt.gui.QComboBox; -import com.trolltech.qt.gui.QDialog; -import com.trolltech.qt.gui.QHBoxLayout; -import com.trolltech.qt.gui.QIcon; -import com.trolltech.qt.gui.QLabel; -import com.trolltech.qt.gui.QPushButton; -import com.trolltech.qt.gui.QVBoxLayout; - -import cx.fbn.nevernote.gui.BrowserWindow; -import cx.fbn.nevernote.sql.DatabaseConnection; -import cx.fbn.nevernote.utilities.ApplicationLogger; -import cx.fbn.nevernote.utilities.Pair; -import cx.fbn.nevernote.xml.NoteFormatter; - -public class NoteQuickLinkDialog extends QDialog { - public final QPushButton ok; - public final QPushButton cancel; - private final DatabaseConnection conn; - public final QComboBox titleCombo; - private final BrowserWindow browser; - private final ApplicationLogger logger; - List> results; - public boolean okPressed; - private List tempFiles; - private final String iconPath = new String("classpath:cx/fbn/nevernote/icons/"); - - // Constructor - public NoteQuickLinkDialog(ApplicationLogger l, DatabaseConnection c, String text) { - okPressed = false; - setWindowTitle(tr("Quick Link Notes")); - setWindowIcon(new QIcon(iconPath+"notebook-green.png")); - QVBoxLayout main = new QVBoxLayout(); - setLayout(main); - titleCombo = new QComboBox(this); - - QHBoxLayout comboLayout = new QHBoxLayout(); - comboLayout.addWidget(new QLabel(tr("Matching Notes:"))); - comboLayout.addWidget(titleCombo); - comboLayout.addStretch(100); - - main.addLayout(comboLayout); - - conn = c; - browser = new BrowserWindow(conn); - main.addWidget(browser); - browser.titleLabel.setVisible(false); - browser.notebookBox.setVisible(false); - browser.hideButtons(); - browser.tagEdit.setVisible(false); - browser.tagLabel.setVisible(false); - - QHBoxLayout buttonLayout = new QHBoxLayout(); - buttonLayout.addStretch(100); - ok = new QPushButton(tr("OK")); - ok.clicked.connect(this, "okPressed()"); - - cancel = new QPushButton(tr("Cancel")); - cancel.clicked.connect(this, "cancelPressed()"); - - buttonLayout.addWidget(ok); - buttonLayout.addWidget(cancel); - main.addLayout(buttonLayout); - - browser.getBrowser().setContextMenuPolicy(ContextMenuPolicy.NoContextMenu); - logger = l; - - // Search for matching notes - results = conn.getNoteTable().findNotesByTitle(text); - - // Add the results to the combo box - for (int i=0; i 0) { - Note currentNote = conn.getNoteTable().getNote(results.get(0).getFirst(), true, true, false, true, true); - setContent(currentNote); - } - } - - // Cancel button pressed - @SuppressWarnings("unused") - private void cancelPressed() { - this.close(); - } - - // OK button pressed - @SuppressWarnings("unused") - private void okPressed() { - okPressed = true; - close(); - } - - // When the selection changes, we refresh the browser window with the new content - @SuppressWarnings("unused") - private void selectionChanged(String text) { - int pos = titleCombo.currentIndex(); - String guid = results.get(pos).getFirst(); - Note note = conn.getNoteTable().getNote(guid, true, true, false, true, true); - setContent(note); - } - - // Return the note the user is currently viewing - public String getSelectedNote() { - int pos = titleCombo.currentIndex(); - return results.get(pos).getFirst(); - } - - - // Load the content of the note into the viewing window. - public void setContent(Note currentNote) { - NoteFormatter formatter = new NoteFormatter(logger, conn, tempFiles); - formatter.setNote(currentNote, false); - formatter.setHighlight(null); - formatter.setNoteHistory(true); - - StringBuffer js = new StringBuffer(); - - // We need to prepend the note with or encoded characters are ugly - js.append(""); - js.append(""); - js.append(""); - js.append(formatter.rebuildNoteHTML()); - js.append(""); - - browser.setNote(currentNote); - browser.setContent(new QByteArray(js.toString())); - } - - // give the results from the DB search back to the caller. - public List> getResults() { - return results; - } - - -} - - - - - - - - +/* + * This file is part of NixNote + * Copyright 2011 Randy Baumgarte + * + * This file may be licensed under the terms of of the + * GNU General Public License Version 2 (the ``GPL''). + * + * Software distributed under the License is distributed + * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the GPL for the specific language + * governing rights and limitations. + * + * You should have received a copy of the GPL along with this + * program. If not, go to http://www.gnu.org/licenses/gpl.html + * or write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * +*/ + +package cx.fbn.nevernote.dialog; + +//********************************************** +//********************************************** +//* This is the dialog that shows a user +//* a quick popup of a note based upon its title. +//* It is used in the Quick Link function. +//********************************************** +//********************************************** + +import java.util.List; + +import com.evernote.edam.type.Note; +import com.trolltech.qt.core.QByteArray; +import com.trolltech.qt.core.QTemporaryFile; +import com.trolltech.qt.core.Qt.ContextMenuPolicy; +import com.trolltech.qt.gui.QComboBox; +import com.trolltech.qt.gui.QDialog; +import com.trolltech.qt.gui.QHBoxLayout; +import com.trolltech.qt.gui.QIcon; +import com.trolltech.qt.gui.QLabel; +import com.trolltech.qt.gui.QPushButton; +import com.trolltech.qt.gui.QVBoxLayout; + +import cx.fbn.nevernote.gui.BrowserWindow; +import cx.fbn.nevernote.neighbornote.ClipBoardObserver; +import cx.fbn.nevernote.sql.DatabaseConnection; +import cx.fbn.nevernote.utilities.ApplicationLogger; +import cx.fbn.nevernote.utilities.Pair; +import cx.fbn.nevernote.xml.NoteFormatter; + +public class NoteQuickLinkDialog extends QDialog { + public final QPushButton ok; + public final QPushButton cancel; + private final DatabaseConnection conn; + public final QComboBox titleCombo; + private final BrowserWindow browser; + private final ApplicationLogger logger; + List> results; + public boolean okPressed; + private List tempFiles; + private final String iconPath = new String("classpath:cx/fbn/nevernote/icons/"); + // ICHANGED + private final ClipBoardObserver cbObserver; + + // ICHANGED 引数にcbObserver追加 + // Constructor + public NoteQuickLinkDialog(ApplicationLogger l, DatabaseConnection c, String text, ClipBoardObserver cbObserver) { + okPressed = false; + setWindowTitle(tr("Quick Link Notes")); + setWindowIcon(new QIcon(iconPath+"notebook-green.png")); + QVBoxLayout main = new QVBoxLayout(); + setLayout(main); + titleCombo = new QComboBox(this); + + QHBoxLayout comboLayout = new QHBoxLayout(); + comboLayout.addWidget(new QLabel(tr("Matching Notes:"))); + comboLayout.addWidget(titleCombo); + comboLayout.addStretch(100); + + main.addLayout(comboLayout); + + conn = c; + + // ICHANGED + this.cbObserver = cbObserver; + browser = new BrowserWindow(conn, this.cbObserver); + + main.addWidget(browser); + browser.titleLabel.setVisible(false); + browser.notebookBox.setVisible(false); + browser.hideButtons(); + browser.tagEdit.setVisible(false); + browser.tagLabel.setVisible(false); + + QHBoxLayout buttonLayout = new QHBoxLayout(); + buttonLayout.addStretch(100); + ok = new QPushButton(tr("OK")); + ok.clicked.connect(this, "okPressed()"); + + cancel = new QPushButton(tr("Cancel")); + cancel.clicked.connect(this, "cancelPressed()"); + + buttonLayout.addWidget(ok); + buttonLayout.addWidget(cancel); + main.addLayout(buttonLayout); + + browser.getBrowser().setContextMenuPolicy(ContextMenuPolicy.NoContextMenu); + logger = l; + + // Search for matching notes + results = conn.getNoteTable().findNotesByTitle(text); + + // Add the results to the combo box + for (int i=0; i 0) { + Note currentNote = conn.getNoteTable().getNote(results.get(0).getFirst(), true, true, false, true, true); + setContent(currentNote); + } + } + + // Cancel button pressed + @SuppressWarnings("unused") + private void cancelPressed() { + this.close(); + } + + // OK button pressed + @SuppressWarnings("unused") + private void okPressed() { + okPressed = true; + close(); + } + + // When the selection changes, we refresh the browser window with the new content + @SuppressWarnings("unused") + private void selectionChanged(String text) { + int pos = titleCombo.currentIndex(); + String guid = results.get(pos).getFirst(); + Note note = conn.getNoteTable().getNote(guid, true, true, false, true, true); + setContent(note); + } + + // Return the note the user is currently viewing + public String getSelectedNote() { + int pos = titleCombo.currentIndex(); + return results.get(pos).getFirst(); + } + + + // Load the content of the note into the viewing window. + public void setContent(Note currentNote) { + NoteFormatter formatter = new NoteFormatter(logger, conn, tempFiles); + formatter.setNote(currentNote, false); + formatter.setHighlight(null); + formatter.setNoteHistory(true); + + StringBuffer js = new StringBuffer(); + + // We need to prepend the note with or encoded characters are ugly + js.append(""); + js.append(""); + js.append(""); + js.append(formatter.rebuildNoteHTML()); + js.append(""); + + browser.setNote(currentNote); + browser.setContent(new QByteArray(js.toString())); + } + + // give the results from the DB search back to the caller. + public List> getResults() { + return results; + } + + +} + + + + + + + + diff --git a/src/cx/fbn/nevernote/dialog/OnlineNoteHistory.java b/src/cx/fbn/nevernote/dialog/OnlineNoteHistory.java index 6307ab8..254116b 100644 --- a/src/cx/fbn/nevernote/dialog/OnlineNoteHistory.java +++ b/src/cx/fbn/nevernote/dialog/OnlineNoteHistory.java @@ -1,165 +1,172 @@ -/* - * This file is part of NixNote - * Copyright 2009 Randy Baumgarte - * - * This file may be licensed under the terms of of the - * GNU General Public License Version 2 (the ``GPL''). - * - * Software distributed under the License is distributed - * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either - * express or implied. See the GPL for the specific language - * governing rights and limitations. - * - * You should have received a copy of the GPL along with this - * program. If not, go to http://www.gnu.org/licenses/gpl.html - * or write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * -*/ - -package cx.fbn.nevernote.dialog; - -//********************************************** -//********************************************** -//* This is the dialog that shows a user -//* the note's history from Evernote. -//********************************************** -//********************************************** - -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.List; - -import com.evernote.edam.notestore.NoteVersionId; -import com.evernote.edam.type.Note; -import com.trolltech.qt.core.QTemporaryFile; -import com.trolltech.qt.core.Qt.ContextMenuPolicy; -import com.trolltech.qt.gui.QComboBox; -import com.trolltech.qt.gui.QDialog; -import com.trolltech.qt.gui.QHBoxLayout; -import com.trolltech.qt.gui.QIcon; -import com.trolltech.qt.gui.QLabel; -import com.trolltech.qt.gui.QPushButton; -import com.trolltech.qt.gui.QVBoxLayout; - -import cx.fbn.nevernote.Global; -import cx.fbn.nevernote.gui.BrowserWindow; -import cx.fbn.nevernote.sql.DatabaseConnection; -import cx.fbn.nevernote.utilities.ApplicationLogger; -import cx.fbn.nevernote.xml.NoteFormatter; - -public class OnlineNoteHistory extends QDialog { - public final QPushButton restoreAsNew; - public final QPushButton restore; - private final DatabaseConnection conn; - public final QComboBox historyCombo; - private final BrowserWindow browser; - private final ApplicationLogger logger; - List tempFiles; - private final String iconPath = new String("classpath:cx/fbn/nevernote/icons/"); - - // Constructor - public OnlineNoteHistory(ApplicationLogger l, DatabaseConnection c) { - setWindowTitle(tr("Online Note History")); - setWindowIcon(new QIcon(iconPath+"notebook-green.png")); - QVBoxLayout main = new QVBoxLayout(); - setLayout(main); - historyCombo = new QComboBox(this); - - QHBoxLayout comboLayout = new QHBoxLayout(); - comboLayout.addWidget(new QLabel(tr("History Date:"))); - comboLayout.addWidget(historyCombo); - comboLayout.addStretch(100); - - main.addLayout(comboLayout); - - conn = c; - browser = new BrowserWindow(conn); - main.addWidget(browser); - browser.titleLabel.setVisible(false); - browser.notebookBox.setVisible(false); - browser.hideButtons(); - browser.tagEdit.setVisible(false); - browser.tagLabel.setVisible(false); - - QHBoxLayout buttonLayout = new QHBoxLayout(); - buttonLayout.addStretch(100); - restore = new QPushButton(tr("Restore Note")); - restore.clicked.connect(this, "restorePushed()"); - - restoreAsNew = new QPushButton(tr("Restore As New Note")); - restoreAsNew.clicked.connect(this, "restoreAsNewPushed()"); - QPushButton cancel = new QPushButton(tr("Cancel")); - cancel.clicked.connect(this, "cancelPressed()"); - - buttonLayout.addWidget(restore); - buttonLayout.addWidget(restoreAsNew); - buttonLayout.addWidget(cancel); - main.addLayout(buttonLayout); - - browser.getBrowser().setContextMenuPolicy(ContextMenuPolicy.NoContextMenu); - tempFiles = new ArrayList(); - logger = l; - } - - @SuppressWarnings("unused") - private void restoreAsNewPushed() { - this.close(); - } - @SuppressWarnings("unused") - private void restorePushed() { - this.close(); - } - @SuppressWarnings("unused") - private void cancelPressed() { - this.close(); - } - - public void setCurrent(boolean isDirty) { - if (isDirty) - historyCombo.addItem(new String(tr("Current (Non Synchronized)"))); - else - historyCombo.addItem(new String(tr("Current (Synchronized)"))); - - } - - public void load(List versions) { - String fmt = Global.getDateFormat() + " " + Global.getTimeFormat(); - String dateTimeFormat = new String(fmt); - SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat); - - for (int i=0; i or encoded characters are ugly - js.append(""); - js.append(""); - js.append(""); - js.append(formatter.rebuildNoteHTML()); - js.append(""); - - browser.setNote(currentNote); - browser.getBrowser().page().mainFrame().setHtml(js.toString()); - } -} - - - - - - - - +/* + * This file is part of NixNote + * Copyright 2009 Randy Baumgarte + * + * This file may be licensed under the terms of of the + * GNU General Public License Version 2 (the ``GPL''). + * + * Software distributed under the License is distributed + * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the GPL for the specific language + * governing rights and limitations. + * + * You should have received a copy of the GPL along with this + * program. If not, go to http://www.gnu.org/licenses/gpl.html + * or write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * +*/ + +package cx.fbn.nevernote.dialog; + +//********************************************** +//********************************************** +//* This is the dialog that shows a user +//* the note's history from Evernote. +//********************************************** +//********************************************** + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.List; + +import com.evernote.edam.notestore.NoteVersionId; +import com.evernote.edam.type.Note; +import com.trolltech.qt.core.QTemporaryFile; +import com.trolltech.qt.core.Qt.ContextMenuPolicy; +import com.trolltech.qt.gui.QComboBox; +import com.trolltech.qt.gui.QDialog; +import com.trolltech.qt.gui.QHBoxLayout; +import com.trolltech.qt.gui.QIcon; +import com.trolltech.qt.gui.QLabel; +import com.trolltech.qt.gui.QPushButton; +import com.trolltech.qt.gui.QVBoxLayout; + +import cx.fbn.nevernote.Global; +import cx.fbn.nevernote.gui.BrowserWindow; +import cx.fbn.nevernote.neighbornote.ClipBoardObserver; +import cx.fbn.nevernote.sql.DatabaseConnection; +import cx.fbn.nevernote.utilities.ApplicationLogger; +import cx.fbn.nevernote.xml.NoteFormatter; + +public class OnlineNoteHistory extends QDialog { + public final QPushButton restoreAsNew; + public final QPushButton restore; + private final DatabaseConnection conn; + public final QComboBox historyCombo; + private final BrowserWindow browser; + private final ApplicationLogger logger; + List tempFiles; + private final String iconPath = new String("classpath:cx/fbn/nevernote/icons/"); + // ICHANGED + private final ClipBoardObserver cbObserver; + + // ICHANGED 引数にcbObserver追加 + // Constructor + public OnlineNoteHistory(ApplicationLogger l, DatabaseConnection c, ClipBoardObserver cbObserver) { + setWindowTitle(tr("Online Note History")); + setWindowIcon(new QIcon(iconPath+"notebook-green.png")); + QVBoxLayout main = new QVBoxLayout(); + setLayout(main); + historyCombo = new QComboBox(this); + + QHBoxLayout comboLayout = new QHBoxLayout(); + comboLayout.addWidget(new QLabel(tr("History Date:"))); + comboLayout.addWidget(historyCombo); + comboLayout.addStretch(100); + + main.addLayout(comboLayout); + + conn = c; + // ICHANGED + this.cbObserver = cbObserver; + browser = new BrowserWindow(conn, this.cbObserver); + + main.addWidget(browser); + browser.titleLabel.setVisible(false); + browser.notebookBox.setVisible(false); + browser.hideButtons(); + browser.tagEdit.setVisible(false); + browser.tagLabel.setVisible(false); + + QHBoxLayout buttonLayout = new QHBoxLayout(); + buttonLayout.addStretch(100); + restore = new QPushButton(tr("Restore Note")); + restore.clicked.connect(this, "restorePushed()"); + + restoreAsNew = new QPushButton(tr("Restore As New Note")); + restoreAsNew.clicked.connect(this, "restoreAsNewPushed()"); + QPushButton cancel = new QPushButton(tr("Cancel")); + cancel.clicked.connect(this, "cancelPressed()"); + + buttonLayout.addWidget(restore); + buttonLayout.addWidget(restoreAsNew); + buttonLayout.addWidget(cancel); + main.addLayout(buttonLayout); + + browser.getBrowser().setContextMenuPolicy(ContextMenuPolicy.NoContextMenu); + tempFiles = new ArrayList(); + logger = l; + } + + @SuppressWarnings("unused") + private void restoreAsNewPushed() { + this.close(); + } + @SuppressWarnings("unused") + private void restorePushed() { + this.close(); + } + @SuppressWarnings("unused") + private void cancelPressed() { + this.close(); + } + + public void setCurrent(boolean isDirty) { + if (isDirty) + historyCombo.addItem(new String(tr("Current (Non Synchronized)"))); + else + historyCombo.addItem(new String(tr("Current (Synchronized)"))); + + } + + public void load(List versions) { + String fmt = Global.getDateFormat() + " " + Global.getTimeFormat(); + String dateTimeFormat = new String(fmt); + SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat); + + for (int i=0; i or encoded characters are ugly + js.append(""); + js.append(""); + js.append(""); + js.append(formatter.rebuildNoteHTML()); + js.append(""); + + browser.setNote(currentNote); + browser.getBrowser().page().mainFrame().setHtml(js.toString()); + } +} + + + + + + + + diff --git a/src/cx/fbn/nevernote/gui/BrowserWindow.java b/src/cx/fbn/nevernote/gui/BrowserWindow.java index 879f899..84eff8f 100644 --- a/src/cx/fbn/nevernote/gui/BrowserWindow.java +++ b/src/cx/fbn/nevernote/gui/BrowserWindow.java @@ -1,3488 +1,3529 @@ -/* - * This file is part of NixNote - * Copyright 2009 Randy Baumgarte - * - * This file may be licensed under the terms of of the - * GNU General Public License Version 2 (the ``GPL''). - * - * Software distributed under the License is distributed - * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either - * express or implied. See the GPL for the specific language - * governing rights and limitations. - * - * You should have received a copy of the GPL along with this - * program. If not, go to http://www.gnu.org/licenses/gpl.html - * or write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -package cx.fbn.nevernote.gui; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.net.FileNameMap; -import java.net.URI; -import java.net.URLConnection; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collections; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.StringTokenizer; - -import org.apache.commons.lang3.StringEscapeUtils; -import org.apache.commons.lang3.StringUtils; - -import com.evernote.edam.limits.Constants; -import com.evernote.edam.type.Data; -import com.evernote.edam.type.Note; -import com.evernote.edam.type.Notebook; -import com.evernote.edam.type.Resource; -import com.evernote.edam.type.ResourceAttributes; -import com.evernote.edam.type.Tag; -import com.evernote.edam.type.User; -import com.swabunga.spell.engine.Configuration; -import com.swabunga.spell.engine.SpellDictionary; -import com.swabunga.spell.engine.SpellDictionaryHashMap; -import com.swabunga.spell.engine.Word; -import com.swabunga.spell.event.SpellCheckEvent; -import com.swabunga.spell.event.SpellCheckListener; -import com.swabunga.spell.event.SpellChecker; -import com.swabunga.spell.event.StringWordTokenizer; -import com.trolltech.qt.core.QByteArray; -import com.trolltech.qt.core.QCoreApplication; -import com.trolltech.qt.core.QDataStream; -import com.trolltech.qt.core.QDateTime; -import com.trolltech.qt.core.QEvent; -import com.trolltech.qt.core.QEvent.Type; -import com.trolltech.qt.core.QFile; -import com.trolltech.qt.core.QFileSystemWatcher; -import com.trolltech.qt.core.QIODevice; -import com.trolltech.qt.core.QMimeData; -import com.trolltech.qt.core.QTextCodec; -import com.trolltech.qt.core.QTimer; -import com.trolltech.qt.core.QUrl; -import com.trolltech.qt.core.Qt; -import com.trolltech.qt.core.Qt.Key; -import com.trolltech.qt.core.Qt.KeyboardModifier; -import com.trolltech.qt.core.Qt.KeyboardModifiers; -import com.trolltech.qt.gui.QAction; -import com.trolltech.qt.gui.QApplication; -import com.trolltech.qt.gui.QCalendarWidget; -import com.trolltech.qt.gui.QClipboard; -import com.trolltech.qt.gui.QClipboard.Mode; -import com.trolltech.qt.gui.QColor; -import com.trolltech.qt.gui.QComboBox; -import com.trolltech.qt.gui.QDateEdit; -import com.trolltech.qt.gui.QDesktopServices; -import com.trolltech.qt.gui.QFileDialog; -import com.trolltech.qt.gui.QFileDialog.AcceptMode; -import com.trolltech.qt.gui.QFileDialog.FileMode; -import com.trolltech.qt.gui.QFont; -import com.trolltech.qt.gui.QFontDatabase; -import com.trolltech.qt.gui.QFormLayout; -import com.trolltech.qt.gui.QGridLayout; -import com.trolltech.qt.gui.QHBoxLayout; -import com.trolltech.qt.gui.QIcon; -import com.trolltech.qt.gui.QImage; -import com.trolltech.qt.gui.QKeyEvent; -import com.trolltech.qt.gui.QKeySequence; -import com.trolltech.qt.gui.QLabel; -import com.trolltech.qt.gui.QLineEdit; -import com.trolltech.qt.gui.QListWidgetItem; -import com.trolltech.qt.gui.QMatrix; -import com.trolltech.qt.gui.QMessageBox; -import com.trolltech.qt.gui.QPalette; -import com.trolltech.qt.gui.QPalette.ColorRole; -import com.trolltech.qt.gui.QPushButton; -import com.trolltech.qt.gui.QShortcut; -import com.trolltech.qt.gui.QSplitter; -import com.trolltech.qt.gui.QTextEdit; -import com.trolltech.qt.gui.QTextEdit.LineWrapMode; -import com.trolltech.qt.gui.QTimeEdit; -import com.trolltech.qt.gui.QToolButton; -import com.trolltech.qt.gui.QToolButton.ToolButtonPopupMode; -import com.trolltech.qt.gui.QVBoxLayout; -import com.trolltech.qt.gui.QWidget; -import com.trolltech.qt.network.QNetworkAccessManager; -import com.trolltech.qt.network.QNetworkReply; -import com.trolltech.qt.network.QNetworkReply.NetworkError; -import com.trolltech.qt.network.QNetworkRequest; -import com.trolltech.qt.webkit.QWebPage; -import com.trolltech.qt.webkit.QWebPage.WebAction; -import com.trolltech.qt.webkit.QWebSettings; -import com.trolltech.qt.webkit.QWebView; - -import cx.fbn.nevernote.Global; -import cx.fbn.nevernote.dialog.EnCryptDialog; -import cx.fbn.nevernote.dialog.EnDecryptDialog; -import cx.fbn.nevernote.dialog.GeoDialog; -import cx.fbn.nevernote.dialog.InsertLatexImage; -import cx.fbn.nevernote.dialog.InsertLinkDialog; -import cx.fbn.nevernote.dialog.NoteQuickLinkDialog; -import cx.fbn.nevernote.dialog.SpellCheck; -import cx.fbn.nevernote.dialog.TableDialog; -import cx.fbn.nevernote.dialog.TagAssign; -import cx.fbn.nevernote.evernote.EnCrypt; -import cx.fbn.nevernote.filters.FilterEditorTags; -import cx.fbn.nevernote.signals.NoteResourceSignal; -import cx.fbn.nevernote.signals.NoteSignal; -import cx.fbn.nevernote.sql.DatabaseConnection; -import cx.fbn.nevernote.utilities.ApplicationLogger; -import cx.fbn.nevernote.utilities.FileUtils; -import cx.fbn.nevernote.utilities.Pair; -import cx.fbn.nevernote.xml.HtmlTagModifier; - -public class BrowserWindow extends QWidget { - - public final QLineEdit titleLabel; - private final QLineEdit urlText; - private final QLabel authorLabel; - private final QLineEdit authorText; - private final QComboBox geoBox; - public final TagLineEdit tagEdit; - public final QLabel tagLabel; - private final QPushButton urlLabel; - private final QLabel alteredLabel; - private final QDateEdit alteredDate; - private final QTimeEdit alteredTime; - private final QDateEdit createdDate; - private final QTimeEdit createdTime; - private final QLabel subjectLabel; - private final QDateEdit subjectDate; - private final QTimeEdit subjectTime; - public final QComboBox notebookBox; - private final QLabel notebookLabel; - private final QLabel createdLabel; - public final QComboBox fontSize; - public final QAction fontSizeAction; - private boolean extendedOn; - public boolean buttonsVisible; - private final String iconPath; - public final ContentView browser; - private final QTextEdit sourceEdit; - private String sourceEditHeader; - Highlighter syntaxHighlighter; - private List allTags; - private List currentTags; - public NoteSignal noteSignal; - public Signal2 evernoteLinkClicked; - private List notebookList; - private Note currentNote; - private String saveNoteTitle; - private String saveTagList; - private boolean insideList; - private final DatabaseConnection conn; - private final QCalendarWidget createdCalendarWidget; - private final QCalendarWidget alteredCalendarWidget; - private final QCalendarWidget subjectCalendarWidget; - - public final QPushButton undoButton; - public final QAction undoAction; - public final QPushButton redoButton; - public final QAction redoAction; - public final QPushButton cutButton; - public final QAction cutAction; - public final QPushButton copyButton; - public final QAction copyAction; - public final QPushButton pasteButton; - public final QAction pasteAction; - public final QPushButton boldButton; - public final QAction boldAction; - public final QPushButton underlineButton; - public final QAction underlineAction; - public final QPushButton italicButton; - public final QAction italicAction; - public final Signal0 focusLost; - public final NoteResourceSignal resourceSignal; - - public QPushButton rightAlignButton; - public final QAction rightAlignAction; - public QPushButton leftAlignButton; - public final QAction leftAlignAction; - public QPushButton centerAlignButton; - public final QAction centerAlignAction; - - public final QPushButton strikethroughButton; - public final QAction strikethroughAction; - public final QPushButton hlineButton; - public final QAction hlineAction; - public final QPushButton indentButton; - public final QAction indentAction; - public final QPushButton outdentButton; - public final QAction outdentAction; - public final QPushButton bulletListButton; - public final QAction bulletListAction; - public final QPushButton numberListButton; - public final QAction numberListAction; - public final QPushButton spellCheckButton; - public final QAction spellCheckAction; - public final QPushButton todoButton; - public final QAction todoAction; - - public final QShortcut focusTitleShortcut; - public final QShortcut focusTagShortcut; - public final QShortcut focusNoteShortcut; - public final QShortcut focusUrlShortcut; - public final QShortcut focusAuthorShortcut; - - public EditorButtonBar buttonLayout; - public final QComboBox fontList; - public final QAction fontListAction; - public final QToolButton fontColor; - public final QAction fontColorAction; - private final ColorMenu fontColorMenu; - public final QToolButton fontHilight; - public final QAction fontHilightAction; - private final ColorMenu fontHilightColorMenu; - public final QFileSystemWatcher fileWatcher; - public int cursorPosition; - private boolean forceTextPaste; - private String selectedFile; - private String currentHyperlink; - public boolean keepPDFNavigationHidden; - private final ApplicationLogger logger; - SpellDictionary dictionary; - SpellDictionary userDictionary; - SpellChecker spellChecker; - SuggestionListener spellListener; - private final HashMap previewPageList; - boolean insertHyperlink; - boolean insideTable; - boolean insideEncryption; - public Signal1 blockApplication; - public Signal0 unblockApplication; - public boolean awaitingHttpResponse; - public long unblockTime; - private final QTimer setSourceTimer; - String latexGuid; // This is set if we are editing an existing LaTeX formula. Useful to track guid. - - - public static class SuggestionListener implements SpellCheckListener { - public boolean abortSpellCheck = false; - public boolean errorsFound = false; - private final SpellCheck spellCheckDialog; - - - private final BrowserWindow parent; - public SuggestionListener(BrowserWindow parent, SpellChecker checker) { - this.parent = parent; - spellCheckDialog = new SpellCheck(checker); - } - public void spellingError(SpellCheckEvent event) { - errorsFound = true; - spellCheckDialog.setWord(event.getInvalidWord()); - - @SuppressWarnings("unchecked") - List suggestions = event.getSuggestions(); - spellCheckDialog.clearSuggestions(); - if (!suggestions.isEmpty()) { -// spellCheckDialog.setCurrentSuggestion(suggestions.get(0).getWord()); - for (int i=0; i(); - titleLabel.setMaxLength(Constants.EDAM_NOTE_TITLE_LEN_MAX); - urlText = new QLineEdit(); - authorText = new QLineEdit(); - geoBox = new QComboBox(); - urlLabel = new QPushButton(); - urlLabel.clicked.connect(this, "sourceUrlClicked()"); - authorLabel = new QLabel(); - conn = c; - - focusLost = new Signal0(); - - tagEdit = new TagLineEdit(allTags); - tagLabel = new QLabel(tr("Tags:")); - tagEdit.focusLost.connect(this, "modifyTagsTyping()"); - - createdCalendarWidget = new QCalendarWidget(); - createdDate = new QDateEdit(); - createdDate.setDisplayFormat(Global.getDateFormat()); - createdDate.setCalendarPopup(true); - createdDate.setCalendarWidget(createdCalendarWidget); - createdTime = new QTimeEdit(); - createdDate.dateChanged.connect(this, "createdChanged()"); - createdTime.timeChanged.connect(this, "createdChanged()"); - - alteredCalendarWidget = new QCalendarWidget(); - alteredDate = new QDateEdit(); - alteredDate.setDisplayFormat(Global.getDateFormat()); - alteredDate.setCalendarPopup(true); - alteredDate.setCalendarWidget(alteredCalendarWidget); - alteredTime = new QTimeEdit(); - alteredLabel = new QLabel(tr("Altered:")); - alteredDate.dateChanged.connect(this, "alteredChanged()"); - alteredTime.timeChanged.connect(this, "alteredChanged()"); - - subjectCalendarWidget = new QCalendarWidget(); - subjectDate = new QDateEdit(); - subjectDate.setDisplayFormat(Global.getDateFormat()); - subjectDate.setCalendarPopup(true); - subjectDate.setCalendarWidget(subjectCalendarWidget); - subjectTime = new QTimeEdit(); - subjectLabel = new QLabel(tr("Subject Date:")); - subjectDate.dateChanged.connect(this, "subjectDateTimeChanged()"); - subjectTime.timeChanged.connect(this, "subjectDateTimeChanged()"); - authorText.textChanged.connect(this, "authorChanged()"); - urlText.textChanged.connect(this, "sourceUrlChanged()"); - - notebookBox = new QComboBox(); - notebookLabel = new QLabel(tr("Notebook")); - createdLabel = new QLabel(tr("Created:")); - // selectedText = new String(); - - urlLabel.setVisible(false); - urlText.setVisible(false); - authorLabel.setVisible(false); - - geoBox.setVisible(false); - geoBox.addItem(new QIcon(iconPath+"globe.png"), ""); - geoBox.addItem(new String(tr("Set"))); - geoBox.addItem(new String(tr("Clear"))); - geoBox.addItem(new String(tr("View On Map"))); - geoBox.activated.connect(this, "geoBoxChanged()"); - - authorText.setVisible(false); - createdDate.setVisible(false); - alteredLabel.setVisible(false); - //notebookBox.setVisible(false); - notebookLabel.setVisible(false); - createdLabel.setVisible(false); - createdTime.setVisible(false); - alteredDate.setVisible(false); - alteredTime.setVisible(false); - subjectLabel.setVisible(false); - subjectDate.setVisible(false); - subjectTime.setVisible(false); - extendedOn = false; - buttonsVisible = true; - setAcceptDrops(true); - - browser = new ContentView(this); - - browser.page().setLinkDelegationPolicy( - QWebPage.LinkDelegationPolicy.DelegateAllLinks); - browser.linkClicked.connect(this, "linkClicked(QUrl)"); - currentHyperlink = ""; - - //Setup the source editor - sourceEdit = new QTextEdit(this); - sourceEdit.setVisible(false); - sourceEdit.setTabChangesFocus(true); - sourceEdit.setLineWrapMode(LineWrapMode.NoWrap); - QFont font = new QFont(); - font.setFamily("Courier"); - font.setFixedPitch(true); - font.setPointSize(10); - sourceEdit.setFont(font); - syntaxHighlighter = new Highlighter(sourceEdit.document()); - sourceEdit.textChanged.connect(this, "sourceEdited()"); - - QVBoxLayout v = new QVBoxLayout(); - QFormLayout notebookLayout = new QFormLayout(); - QGridLayout dateLayout = new QGridLayout(); - titleLabel.setReadOnly(false); - titleLabel.editingFinished.connect(this, "titleEdited()"); - browser.page().contentsChanged.connect(this, "contentChanged()"); - browser.page().selectionChanged.connect(this, "selectionChanged()"); - browser.page().mainFrame().javaScriptWindowObjectCleared.connect(this, - "exposeToJavascript()"); - - notebookBox.activated.connect(this, "notebookChanged()"); - resourceSignal = new NoteResourceSignal(); - - QHBoxLayout tagLayout = new QHBoxLayout(); - v.addWidget(titleLabel, 0); - notebookLayout.addRow(notebookLabel, notebookBox); - tagLayout.addLayout(notebookLayout, 0); - tagLayout.stretch(4); - tagLayout.addWidget(tagLabel, 0); - tagLayout.addWidget(tagEdit, 1); - v.addLayout(tagLayout); - - QHBoxLayout urlLayout = new QHBoxLayout(); - urlLayout.addWidget(urlLabel, 0); - urlLayout.addWidget(urlText, 0); - v.addLayout(urlLayout); - - QHBoxLayout authorLayout = new QHBoxLayout(); - authorLayout.addWidget(authorLabel, 0); - authorLayout.addWidget(authorText, 0); - authorLayout.addWidget(geoBox); - v.addLayout(authorLayout); - - dateLayout.addWidget(createdLabel, 0, 0); - dateLayout.addWidget(createdDate, 0, 1); - dateLayout.addWidget(createdTime, 0, 2); - dateLayout.setColumnStretch(9, 100); - dateLayout.addWidget(alteredLabel, 0, 3); - dateLayout.addWidget(alteredDate, 0, 4); - dateLayout.addWidget(alteredTime, 0, 5); - dateLayout.addWidget(subjectLabel, 0, 6); - dateLayout.addWidget(subjectDate, 0, 7); - dateLayout.addWidget(subjectTime, 0, 8); - v.addLayout(dateLayout, 0); - - undoButton = newEditorButton("undo", tr("Undo Change")); - redoButton = newEditorButton("redo", tr("Redo Change")); - cutButton = newEditorButton("cut", tr("Cut")); - copyButton = newEditorButton("copy", tr("Copy")); - pasteButton = newEditorButton("paste", tr("Paste")); - boldButton = newEditorButton("bold", tr("Bold")); - underlineButton = newEditorButton("underline", tr("Underline")); - italicButton = newEditorButton("italic", tr("Italic")); - - rightAlignButton = newEditorButton("justifyRight", tr("Right Align")); - leftAlignButton = newEditorButton("justifyLeft", tr("Left Align")); - centerAlignButton = newEditorButton("justifyCenter", tr("Center Align")); - - strikethroughButton = newEditorButton("strikethrough", tr("Strikethrough")); - hlineButton = newEditorButton("hline", tr("Insert Horizontal Line")); - indentButton = newEditorButton("indent", tr("Shift Right")); - outdentButton = newEditorButton("outdent", tr("Shift Left")); - bulletListButton = newEditorButton("bulletList", tr("Bullet List")); - numberListButton = newEditorButton("numberList", tr("Number List")); - spellCheckButton = newEditorButton("spellCheck", tr("Spell Check")); - todoButton = newEditorButton("todo", tr("To-do")); - - - buttonLayout = new EditorButtonBar(); - v.addWidget(buttonLayout); - - undoAction = buttonLayout.addWidget(undoButton); - buttonLayout.toggleUndoVisible.triggered.connect(this, "toggleUndoVisible(Boolean)"); - redoAction = buttonLayout.addWidget(redoButton); - buttonLayout.toggleRedoVisible.triggered.connect(this, "toggleRedoVisible(Boolean)"); - - buttonLayout.addWidget(newSeparator()); - cutAction = buttonLayout.addWidget(cutButton); - buttonLayout.toggleCutVisible.triggered.connect(this, "toggleCutVisible(Boolean)"); - copyAction = buttonLayout.addWidget(copyButton); - buttonLayout.toggleCopyVisible.triggered.connect(this, "toggleCopyVisible(Boolean)"); - pasteAction = buttonLayout.addWidget(pasteButton); - buttonLayout.togglePasteVisible.triggered.connect(this, "togglePasteVisible(Boolean)"); - - buttonLayout.addWidget(newSeparator()); - boldAction = buttonLayout.addWidget(boldButton); - buttonLayout.toggleBoldVisible.triggered.connect(this, "toggleBoldVisible(Boolean)"); - italicAction = buttonLayout.addWidget(italicButton); - buttonLayout.toggleItalicVisible.triggered.connect(this, "toggleItalicVisible(Boolean)"); - underlineAction = buttonLayout.addWidget(underlineButton); - buttonLayout.toggleUnderlineVisible.triggered.connect(this, "toggleUnderlineVisible(Boolean)"); - strikethroughAction = buttonLayout.addWidget(strikethroughButton); - buttonLayout.toggleStrikethroughVisible.triggered.connect(this, "toggleStrikethroughVisible(Boolean)"); - - - buttonLayout.addWidget(newSeparator()); - leftAlignAction = buttonLayout.addWidget(leftAlignButton); - buttonLayout.toggleLeftAlignVisible.triggered.connect(this, "toggleLeftAlignVisible(Boolean)"); - centerAlignAction = buttonLayout.addWidget(centerAlignButton); - buttonLayout.toggleCenterAlignVisible.triggered.connect(this, "toggleCenterAlignVisible(Boolean)"); - rightAlignAction = buttonLayout.addWidget(rightAlignButton); - buttonLayout.toggleRightAlignVisible.triggered.connect(this, "toggleRightAlignVisible(Boolean)"); - - buttonLayout.addWidget(newSeparator()); - hlineAction = buttonLayout.addWidget(hlineButton); - buttonLayout.toggleHLineVisible.triggered.connect(this, "toggleHLineVisible(Boolean)"); - - indentAction = buttonLayout.addWidget(indentButton); - buttonLayout.toggleIndentVisible.triggered.connect(this, "toggleIndentVisible(Boolean)"); - outdentAction = buttonLayout.addWidget(outdentButton); - buttonLayout.toggleOutdentVisible.triggered.connect(this, "toggleOutdentVisible(Boolean)"); - bulletListAction = buttonLayout.addWidget(bulletListButton); - buttonLayout.toggleBulletListVisible.triggered.connect(this, "toggleBulletListVisible(Boolean)"); - numberListAction = buttonLayout.addWidget(numberListButton); - buttonLayout.toggleNumberListVisible.triggered.connect(this, "toggleNumberListVisible(Boolean)"); - - // Setup the font & font size combo boxes - buttonLayout.addWidget(newSeparator()); - fontList = new QComboBox(); - fontSize = new QComboBox(); - fontList.setToolTip("Font"); - fontSize.setToolTip("Font Size"); - fontList.activated.connect(this, "fontChanged(String)"); - fontSize.activated.connect(this, "fontSizeChanged(String)"); - fontListAction = buttonLayout.addWidget(fontList); - buttonLayout.toggleFontVisible.triggered.connect(this, "toggleFontListVisible(Boolean)"); - fontSizeAction = buttonLayout.addWidget(fontSize); - buttonLayout.toggleFontSizeVisible.triggered.connect(this, "toggleFontSizeVisible(Boolean)"); - QFontDatabase fonts = new QFontDatabase(); - List fontFamilies = fonts.families(); - for (int i = 0; i < fontFamilies.size(); i++) { - fontList.addItem(fontFamilies.get(i)); - if (i == 0) { - loadFontSize(fontFamilies.get(i)); - } - } - -// buttonLayout.addWidget(newSeparator(), 0); - fontColor = newToolButton("fontColor", tr("Font Color")); - fontColorMenu = new ColorMenu(this); - fontColor.setMenu(fontColorMenu.getMenu()); - fontColor.setPopupMode(ToolButtonPopupMode.MenuButtonPopup); - fontColor.setAutoRaise(false); - fontColorMenu.getMenu().triggered.connect(this, "fontColorClicked()"); - fontColorAction = buttonLayout.addWidget(fontColor); - buttonLayout.toggleFontColorVisible.triggered.connect(this, "toggleFontColorVisible(Boolean)"); - fontHilight = newToolButton("fontHilight", tr("Font Hilight Color")); - fontHilight.setPopupMode(ToolButtonPopupMode.MenuButtonPopup); - fontHilight.setAutoRaise(false); - fontHilightColorMenu = new ColorMenu(this); - fontHilightColorMenu.setDefault(QColor.yellow); - fontHilight.setMenu(fontHilightColorMenu.getMenu()); - fontHilightColorMenu.getMenu().triggered.connect(this, "fontHilightClicked()"); - fontHilightAction = buttonLayout.addWidget(fontHilight); - fontHilightColorMenu.setDefault(QColor.yellow); - buttonLayout.toggleFontHilight.triggered.connect(this, "toggleFontHilightVisible(Boolean)"); - - spellCheckAction = buttonLayout.addWidget(spellCheckButton); - buttonLayout.toggleNumberListVisible.triggered.connect(this, "spellCheckClicked()"); - buttonLayout.toggleSpellCheck.triggered.connect(this, "toggleSpellCheckVisible(Boolean)"); - - todoAction = buttonLayout.addWidget(todoButton); - buttonLayout.toggleNumberListVisible.triggered.connect(this, "todoClicked()"); - buttonLayout.toggleTodo.triggered.connect(this, "toggleTodoVisible(Boolean)"); - - // Setup the source browser); - -// buttonLayout.addWidget(new QLabel(), 1); - QSplitter editSplitter = new QSplitter(this); - editSplitter.addWidget(browser); - editSplitter.setOrientation(Qt.Orientation.Vertical); - editSplitter.addWidget(sourceEdit); - - - -// v.addWidget(browser, 1); -// v.addWidget(sourceEdit); - v.addWidget(editSplitter); - setLayout(v); - - browser.downloadAttachmentRequested.connect(this, - "downloadAttachment(QNetworkRequest)"); - browser.downloadImageRequested.connect(this, - "downloadImage(QNetworkRequest)"); - setTabOrder(notebookBox, tagEdit); - setTabOrder(tagEdit, browser); - - focusNoteShortcut = new QShortcut(this); - setupShortcut(focusNoteShortcut, "Focus_Note"); - focusNoteShortcut.activated.connect(this, "focusNote()"); - focusTitleShortcut = new QShortcut(this); - setupShortcut(focusTitleShortcut, "Focus_Title"); - focusTitleShortcut.activated.connect(this, "focusTitle()"); - focusTagShortcut = new QShortcut(this); - setupShortcut(focusTagShortcut, "Focus_Tag"); - focusTagShortcut.activated.connect(this, "focusTag()"); - focusAuthorShortcut = new QShortcut(this); - setupShortcut(focusAuthorShortcut, "Focus_Author"); - focusAuthorShortcut.activated.connect(this, "focusAuthor()"); - focusUrlShortcut = new QShortcut(this); - setupShortcut(focusUrlShortcut, "Focus_Url"); - focusUrlShortcut.activated.connect(this, "focusUrl()"); - - browser.page().mainFrame().setTextSizeMultiplier(Global.getTextSizeMultiplier()); - browser.page().mainFrame().setZoomFactor(Global.getZoomFactor()); - - previewPageList = new HashMap(); - - browser.page().microFocusChanged.connect(this, "microFocusChanged()"); - - //Setup colors - - QPalette pal = new QPalette(); - pal.setColor(ColorRole.Text, QColor.black); - titleLabel.setPalette(pal); - authorText.setPalette(pal); - authorLabel.setPalette(pal); - urlLabel.setPalette(pal); - urlText.setPalette(pal); - createdDate.setPalette(pal); - createdTime.setPalette(pal); - alteredDate.setPalette(pal); - alteredTime.setPalette(pal); - subjectDate.setPalette(pal); - subjectTime.setPalette(pal); - tagEdit.setPalette(pal); - notebookBox.setPalette(pal); - - blockApplication = new Signal1(); - unblockApplication = new Signal0(); - - setSourceTimer = new QTimer(); - setSourceTimer.timeout.connect(this, "setSource()"); - - logger.log(logger.HIGH, "Browser setup complete"); - } - - - - private void setupShortcut(QShortcut action, String text) { - if (!Global.shortcutKeys.containsAction(text)) - return; - action.setKey(new QKeySequence(Global.shortcutKeys.getShortcut(text))); - } - - - - - // Getter for the QWebView - public QWebView getBrowser() { - return browser; - } - - // Block signals while loading data or things are flagged as dirty by - // mistake - public void loadingData(boolean val) { - logger.log(logger.EXTREME, "Entering BrowserWindow.loadingData() " +val); - notebookBox.blockSignals(val); - browser.page().blockSignals(val); - browser.page().mainFrame().blockSignals(val); - titleLabel.blockSignals(val); - alteredDate.blockSignals(val); - alteredTime.blockSignals(val); - createdTime.blockSignals(val); - createdDate.blockSignals(val); - subjectDate.blockSignals(val); - subjectTime.blockSignals(val); - urlText.blockSignals(val); - authorText.blockSignals(val); - if (!val) - exposeToJavascript(); - logger.log(logger.EXTREME, "Exiting BrowserWindow.loadingData() " +val); - } - - // Enable/disable - public void setReadOnly(boolean v) { - setEnabled(true); - titleLabel.setEnabled(!v); - notebookBox.setEnabled(!v); - tagEdit.setEnabled(!v); - authorLabel.setEnabled(!v); - geoBox.setEnabled(!v); - urlText.setEnabled(!v); - createdDate.setEnabled(!v); - subjectDate.setEnabled(!v); - alteredDate.setEnabled(!v); - authorText.setEnabled(!v); - createdTime.setEnabled(!v); - alteredTime.setEnabled(!v); - subjectTime.setEnabled(!v); - getBrowser().setEnabled(true); - getBrowser().page().setContentEditable(!v); -// getBrowser().setEnabled(!v); - } - - // expose this class to Javascript on the web page - private void exposeToJavascript() { - browser.page().mainFrame().addToJavaScriptWindowObject("jambi", this); - } - - // Custom event queue - @Override - public boolean event(QEvent e) { - if (e.type().equals(QEvent.Type.FocusOut)) { - logger.log(logger.EXTREME, "Focus lost"); - focusLost.emit(); - } - return super.event(e); - } - - // clear out browser - public void clear() { - logger.log(logger.EXTREME, "Entering BrowserWindow.clear()"); - setNote(null); - setContent(new QByteArray()); - tagEdit.setText(""); - tagEdit.tagCompleter.reset(); - urlLabel.setText(tr("Source URL:")); - titleLabel.setText(""); - logger.log(logger.EXTREME, "Exiting BrowserWindow.clear()"); - } - - public void setContent(QByteArray data) { - sourceEdit.blockSignals(true); - browser.setContent(data); - setSource(); - } - // get/set current note - public void setNote(Note n) { - currentNote = n; - if (n == null) - n = new Note(); - saveNoteTitle = n.getTitle(); - - } - - public Note getNote() { - return currentNote; - } - - // New Editor Button - private QPushButton newEditorButton(String name, String toolTip) { - QPushButton button = new QPushButton(); -// QIcon icon = new QIcon(iconPath + name + ".gif"); - QIcon icon = new QIcon(iconPath + name + ".png"); - button.setIcon(icon); - button.setToolTip(toolTip); - button.clicked.connect(this, name + "Clicked()"); - return button; - } - // New Editor Button - private QToolButton newToolButton(String name, String toolTip) { - QToolButton button = new QToolButton(); -// QIcon icon = new QIcon(iconPath + name + ".gif"); - QIcon icon = new QIcon(iconPath + name + ".png"); - button.setIcon(icon); - button.setToolTip(toolTip); - button.clicked.connect(this, name + "Clicked()"); - return button; - } - - // New Separator - private QLabel newSeparator() { - return new QLabel(" "); - } - - // Set the title in the window - public void setTitle(String t) { - titleLabel.setText(t); - saveNoteTitle = t; - checkNoteTitle(); - } - - // Return the current text title - public String getTitle() { - return titleLabel.text(); - } - - // Set the tag name string - public void setTag(String t) { - saveTagList = t; - tagEdit.setText(t); - tagEdit.tagCompleter.reset(); - } - - // Set the source URL - public void setUrl(String t) { - urlLabel.setText(tr("Source URL:\t")); - urlText.setText(t); - } - - // The user want's to launch a web browser on the source of the URL - public void sourceUrlClicked() { - // Make sure we have a valid URL - if (urlText.text().trim().equals("")) - return; - - String url = urlText.text(); - if (!url.toLowerCase().startsWith(tr("http://"))) - url = tr("http://") +url; - - if (!QDesktopServices.openUrl(new QUrl(url))) { - logger.log(logger.LOW, "Error opening file :" +url); - } - } - - public void setAuthor(String t) { - authorLabel.setText(tr("Author:\t")); - authorText.setText(t); - } - - // Set the creation date - public void setCreation(long date) { - QDateTime dt = new QDateTime(); - dt.setTime_t((int) (date / 1000)); - createdDate.setDateTime(dt); - createdTime.setDateTime(dt); - createdDate.setDisplayFormat(Global.getDateFormat()); - createdTime.setDisplayFormat(Global.getTimeFormat()); - } - - // Set the creation date - public void setAltered(long date) { - QDateTime dt = new QDateTime(); - dt.setTime_t((int) (date / 1000)); - alteredDate.setDateTime(dt); - alteredTime.setDateTime(dt); - alteredDate.setDisplayFormat(Global.getDateFormat()); - alteredTime.setDisplayFormat(Global.getTimeFormat()); - } - - // Set the subject date - public void setSubjectDate(long date) { - QDateTime dt = new QDateTime(); - dt.setTime_t((int) (date / 1000)); - subjectDate.setDateTime(dt); - subjectTime.setDateTime(dt); - subjectDate.setDisplayFormat(Global.getDateFormat()); - subjectTime.setDisplayFormat(Global.getTimeFormat()); - } - - // Toggle the extended attribute information - public void toggleInformation() { - if (extendedOn) { - extendedOn = false; - } else { - extendedOn = true; - } - urlLabel.setVisible(extendedOn); - urlText.setVisible(extendedOn); - authorText.setVisible(extendedOn); - geoBox.setVisible(extendedOn); - authorLabel.setVisible(extendedOn); - createdDate.setVisible(extendedOn); - createdTime.setVisible(extendedOn); - createdLabel.setVisible(extendedOn); - alteredLabel.setVisible(extendedOn); - alteredDate.setVisible(extendedOn); - alteredTime.setVisible(extendedOn); - //notebookBox.setVisible(extendedOn); - notebookLabel.setVisible(extendedOn); - subjectLabel.setVisible(extendedOn); - subjectDate.setVisible(extendedOn); - subjectTime.setVisible(extendedOn); - } - - public void hideButtons() { - - undoButton.parentWidget().setVisible(false); - buttonsVisible = false; - } - - - // Is the extended view on? - public boolean isExtended() { - return extendedOn; - } - - // Listener for when a link is clicked - @SuppressWarnings("unused") - private void openFile() { - logger.log(logger.EXTREME, "Starting openFile()"); - File fileHandle = new File(selectedFile); - URI fileURL = fileHandle.toURI(); - String localURL = fileURL.toString(); - QUrl url = new QUrl(localURL); - QFile file = new QFile(selectedFile); - - logger.log(logger.EXTREME, "Adding to fileWatcher:"+file.fileName()); - fileWatcher.addPath(file.fileName()); - - if (!QDesktopServices.openUrl(url)) { - logger.log(logger.LOW, "Error opening file :" +url); - } - } - - - // Listener for when a link is clicked - @SuppressWarnings("unused") - private void linkClicked(QUrl url) { - logger.log(logger.EXTREME, "URL Clicked: " +url.toString()); - if (url.toString().startsWith("latex:")) { - int position = url.toString().lastIndexOf("."); - String guid = url.toString().substring(0,position); - position = guid.lastIndexOf("/"); - guid = guid.substring(position+1); - editLatex(guid); - return; - } - if (url.toString().startsWith("evernote:/view/")) { - StringTokenizer tokens = new StringTokenizer(url.toString().replace("evernote:/view/", ""), "/"); - tokens.nextToken(); - tokens.nextToken(); - String sid = tokens.nextToken(); - String lid = tokens.nextToken(); - - // Emit that we want to switch to a new note - evernoteLinkClicked.emit(sid, lid); - - return; - } - if (url.toString().startsWith("nnres://")) { - logger.log(logger.EXTREME, "URL is NN resource"); - if (url.toString().endsWith("/vnd.evernote.ink")) { - logger.log(logger.EXTREME, "Unable to open ink note"); - QMessageBox.information(this, tr("Unable Open"), tr("This is an ink note.\n"+ - "Ink notes are not supported since Evernote has not\n published any specifications on them\n" + - "and I'm too lazy to figure them out by myself.")); - return; - } - String fullName = url.toString().substring(8); - int index = fullName.indexOf("."); - String guid = ""; - String type = ""; - if (index >-1) { - type = fullName.substring(index+1); - guid = fullName.substring(0,index); - } - index = guid.indexOf(Global.attachmentNameDelimeter); - if (index > -1) { - guid = guid.substring(0,index); - } - List resList = currentNote.getResources(); - Resource res = null; - for (int i=0; i fileNames = dialog.selectedFiles(); //gets all selected filenames - if (fileNames.size() == 0) - return; - String sf = fileNames.get(0); - QFile saveFile = new QFile(sf); - mode.set(QFile.OpenModeFlag.WriteOnly); - saveFile.open(mode); - QDataStream saveOut = new QDataStream(saveFile); - saveOut.writeBytes(binData.toByteArray()); - saveFile.close(); - return; - } - } - } - return; - } - logger.log(logger.EXTREME, "Launching URL"); - QDesktopServices.openUrl(url); - } - - // Listener for when BOLD is clicked - @SuppressWarnings("unused") - private void undoClicked() { - browser.page().triggerAction(WebAction.Undo); - browser.setFocus(); - } - - // Listener for when BOLD is clicked - @SuppressWarnings("unused") - private void redoClicked() { - browser.page().triggerAction(WebAction.Redo); - browser.setFocus(); - } - - // Listener for when BOLD is clicked - @SuppressWarnings("unused") - private void boldClicked() { - browser.page().triggerAction(WebAction.ToggleBold); - microFocusChanged(); - browser.setFocus(); - } - - // Listener for when Italics is clicked - @SuppressWarnings("unused") - private void italicClicked() { - browser.page().triggerAction(WebAction.ToggleItalic); - microFocusChanged(); - browser.setFocus(); - } - - // Listener for when UNDERLINE is clicked - @SuppressWarnings("unused") - private void underlineClicked() { - browser.page().triggerAction(WebAction.ToggleUnderline); - microFocusChanged(); - browser.setFocus(); - } - - // Listener for when Strikethrough is clicked - @SuppressWarnings("unused") - private void strikethroughClicked() { - browser.page().mainFrame().evaluateJavaScript( - "document.execCommand('strikeThrough', false, '');"); - browser.setFocus(); - } - - // Listener for when cut is clicked - @SuppressWarnings("unused") - private void cutClicked() { - browser.page().triggerAction(WebAction.Cut); - browser.setFocus(); - } - - // Listener when COPY is clicked - @SuppressWarnings("unused") - private void copyClicked() { - browser.page().triggerAction(WebAction.Copy); - browser.setFocus(); - } - - // Listener when PASTE is clicked - public void pasteClicked() { - logger.log(logger.EXTREME, "Paste Clicked"); - if (forceTextPaste) { - pasteWithoutFormattingClicked(); - return; - } - QClipboard clipboard = QApplication.clipboard(); - QMimeData mime = clipboard.mimeData(); - - if (mime.hasImage()) { - logger.log(logger.EXTREME, "Image paste found"); - browser.setFocus(); - insertImage(mime); - browser.setFocus(); - return; - } - - if (mime.hasUrls()) { - logger.log(logger.EXTREME, "URL paste found"); - if (mime.text().startsWith("evernote:")) { - handleNoteLink(mime); - } else { - handleUrls(mime); - browser.setFocus(); - } - return; - } - - String text = mime.html(); - if (text.contains("en-tag") && mime.hasHtml()) { - logger.log(logger.EXTREME, "Intra-note paste found"); - text = fixInternotePaste(text); - mime.setHtml(text); - clipboard.setMimeData(mime); - } - - logger.log(logger.EXTREME, "Final paste choice encountered"); - browser.page().triggerAction(WebAction.Paste); - browser.setFocus(); - - } - - // Paste text without formatting - private void pasteWithoutFormattingClicked() { - logger.log(logger.EXTREME, "Paste without format clipped"); - QClipboard clipboard = QApplication.clipboard(); - QMimeData mime = clipboard.mimeData(); - if (!mime.hasText()) - return; - String text = mime.text(); - clipboard.clear(); - clipboard.setText(text, Mode.Clipboard); - browser.page().triggerAction(WebAction.Paste); - - // This is done because pasting into an encryption block - // can cause multiple cells (which can't happen). It - // just goes through the table, extracts the data, & - // puts it back as one table cell. - if (insideEncryption) { - String js = new String( "function fixEncryption() { " - +" var selObj = window.getSelection();" - +" var selRange = selObj.getRangeAt(0);" - +" var workingNode = window.getSelection().anchorNode;" - +" while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { " - +" workingNode = workingNode.parentNode;" - +" } " - +" workingNode.innerHTML = window.jambi.fixEncryptionPaste(workingNode.innerHTML);" - +"} fixEncryption();"); - browser.page().mainFrame().evaluateJavaScript(js); - } - } - - // This basically removes all the table tags and returns just the contents. - // This is called by JavaScript to fix encryption pastes. - public String fixEncryptionPaste(String data) { - data = data.replace("", ""); - data = data.replace("", ""); - data = data.replace("", ""); - data = data.replace("", ""); - data = data.replace("", ""); - data = data.replace("", "
"); - data = data.replace("

", "
"); - - return ""+data+""; - } - - // insert date/time - @SuppressWarnings("unused") - private void insertDateTime() { - String fmt = Global.getDateFormat() + " " + Global.getTimeFormat(); - String dateTimeFormat = new String(fmt); - SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat); - Calendar cal = Calendar.getInstance(); - - browser.page().mainFrame().evaluateJavaScript( - "document.execCommand('insertHtml', false, '"+simple.format(cal.getTime())+"');"); - - browser.setFocus(); - - } - - // Listener when Left is clicked - @SuppressWarnings("unused") - private void justifyLeftClicked() { - browser.page().mainFrame().evaluateJavaScript( - "document.execCommand('JustifyLeft', false, '');"); - browser.setFocus(); - } - - // Listener when Center is clicked - @SuppressWarnings("unused") - private void justifyCenterClicked() { - browser.page().mainFrame().evaluateJavaScript( - "document.execCommand('JustifyCenter', false, '');"); - browser.setFocus(); - } - - // Listener when Left is clicked - @SuppressWarnings("unused") - private void justifyRightClicked() { - browser.page().mainFrame().evaluateJavaScript( - "document.execCommand('JustifyRight', false, '');"); - browser.setFocus(); - } - - // Listener when HLINE is clicked - @SuppressWarnings("unused") - private void hlineClicked() { - browser.page().mainFrame().evaluateJavaScript( - "document.execCommand('insertHorizontalRule', false, '');"); - browser.setFocus(); - } - - // Listener when outdent is clicked - private void outdentClicked() { - browser.page().mainFrame().evaluateJavaScript( - "document.execCommand('outdent', false, '');"); - browser.setFocus(); - } - - // Listener when a bullet list is clicked - @SuppressWarnings("unused") - private void bulletListClicked() { - browser.page().mainFrame().evaluateJavaScript( - "document.execCommand('InsertUnorderedList', false, '');"); - browser.setFocus(); - } - - // Listener when a bullet list is clicked - @SuppressWarnings("unused") - private void numberListClicked() { - browser.page().mainFrame().evaluateJavaScript( - "document.execCommand('InsertOrderedList', false, '');"); - browser.setFocus(); - } - - // Listener when indent is clicked - private void indentClicked() { - browser.page().mainFrame().evaluateJavaScript( - "document.execCommand('indent', false, '');"); - browser.setFocus(); - } - - // Listener when the font name is changed - @SuppressWarnings("unused") - private void fontChanged(String font) { - browser.page().mainFrame().evaluateJavaScript( - "document.execCommand('fontName',false,'" + font + "');"); - browser.setFocus(); - } - - // Listener when a font size is changed - @SuppressWarnings("unused") - private void fontSizeChanged(String font) { - String text = browser.selectedText(); - if (text.trim().equalsIgnoreCase("")) - return; - - String selectedText = browser.selectedText(); - String url = ""+selectedText +"
"; - String script = "document.execCommand('insertHtml', false, '"+url+"');"; - browser.page().mainFrame().evaluateJavaScript(script); -/* browser.page().mainFrame().evaluateJavaScript( - "document.execCommand('fontSize',false,'" - + font + "');"); -*/ - browser.setFocus(); - } - - // Load the font combo box based upon the font selected - private void loadFontSize(String name) { - QFontDatabase db = new QFontDatabase(); - fontSize.clear(); - List points = db.pointSizes(name); - for (int i=0; i"); - browser.page().mainFrame().evaluateJavaScript( - script_start + todo + script_end); - browser.setFocus(); - } - - // Encrypt the selected text - @SuppressWarnings("unused") - private void encryptText() { - String text = browser.selectedText(); - if (text.trim().equalsIgnoreCase("")) - return; - text = new String(text.replaceAll("\n", "
")); - - EnCryptDialog dialog = new EnCryptDialog(); - dialog.exec(); - if (!dialog.okPressed()) { - return; - } - - EnCrypt crypt = new EnCrypt(); - String encrypted = crypt.encrypt(text, dialog.getPassword().trim(), 64); - String decrypted = crypt.decrypt(encrypted, dialog.getPassword().trim(), 64); - - if (encrypted.trim().equals("")) { - QMessageBox.information(this, tr("Error"), tr("Error Encrypting String")); - return; - } - StringBuffer buffer = new StringBuffer(encrypted.length() + 100); - buffer.append("\"");"); - - String script_start = new String( - "document.execCommand('insertHtml', false, '"); - String script_end = new String("');"); - browser.page().mainFrame().evaluateJavaScript( - script_start + buffer.toString() + script_end); - } - - - // Insert a Quick hyperlink - public void insertQuickLink() { - logger.log(logger.EXTREME, "Inserting link"); - String text = browser.selectedText(); - if (text.trim().equalsIgnoreCase("")) - return; - - NoteQuickLinkDialog dialog = new NoteQuickLinkDialog(logger, conn, text); - if (dialog.getResults().size() == 0) { - QMessageBox.critical(null, tr("No Matches Found") ,tr("No matching notes found.")); - return; - } - if (dialog.getResults().size() > 1) { - dialog.exec(); - if (!dialog.okPressed) { - logger.log(logger.EXTREME, "Insert link canceled"); - return; - } - } - - User user = Global.getUserInformation(); - String dUrl = new String("evernote:///view/") + new String(user.getId() + "/" +user.getShardId() +"/" - +dialog.getSelectedNote()+"/"+dialog.getSelectedNote() +"/ " +"style=\"color:#69aa35\""); - - String url = ""+text +""; - String script = "document.execCommand('insertHtml', false, '"+url+"');"; - browser.page().mainFrame().evaluateJavaScript(script); - contentChanged(); - } - - // Insert a hyperlink - public void insertLink() { - logger.log(logger.EXTREME, "Inserting link"); - String text = browser.selectedText(); - if (text.trim().equalsIgnoreCase("")) - return; - - InsertLinkDialog dialog = new InsertLinkDialog(insertHyperlink); - if (currentHyperlink != null && currentHyperlink != "") { - dialog.setUrl(currentHyperlink); - } - dialog.exec(); - if (!dialog.okPressed()) { - logger.log(logger.EXTREME, "Insert link canceled"); - return; - } - - // Take care of inserting new links - if (insertHyperlink) { - String selectedText = browser.selectedText(); - if (dialog.getUrl().trim().equals("")) - return; - logger.log(logger.EXTREME, "Inserting link on text "+selectedText); - logger.log(logger.EXTREME, "URL Link " +dialog.getUrl().trim()); - String dUrl = StringUtils.replace(dialog.getUrl().trim(), "'", "\\'"); - String url = ""+selectedText +""; - String script = "document.execCommand('insertHtml', false, '"+url+"');"; - browser.page().mainFrame().evaluateJavaScript(script); - return; - } - - // Edit existing links - String js = new String( "function getCursorPos() {" - +"var cursorPos;" - +"if (window.getSelection) {" - +" var selObj = window.getSelection();" - +" var selRange = selObj.getRangeAt(0);" - +" var workingNode = window.getSelection().anchorNode.parentNode;" - +" while(workingNode != null) { " - +" if (workingNode.nodeName.toLowerCase()=='a') workingNode.setAttribute('href','" +dialog.getUrl() +"');" - +" workingNode = workingNode.parentNode;" - +" }" - +"}" - +"} getCursorPos();"); - browser.page().mainFrame().evaluateJavaScript(js); - - if (!dialog.getUrl().trim().equals("")) { - contentChanged(); - return; - } - - // Remove URL - js = new String( "function getCursorPos() {" - +"var cursorPos;" - +"if (window.getSelection) {" - +" var selObj = window.getSelection();" - +" var selRange = selObj.getRangeAt(0);" - +" var workingNode = window.getSelection().anchorNode.parentNode;" - +" while(workingNode != null) { " - +" if (workingNode.nodeName.toLowerCase()=='a') { " - +" workingNode.removeAttribute('href');" - +" workingNode.removeAttribute('title');" - +" var text = document.createTextNode(workingNode.innerText);" - +" workingNode.parentNode.insertBefore(text, workingNode);" - +" workingNode.parentNode.removeChild(workingNode);" - +" }" - +" workingNode = workingNode.parentNode;" - +" }" - +"}" - +"} getCursorPos();"); - browser.page().mainFrame().evaluateJavaScript(js); - - contentChanged(); - - - } - - - // Insert a hyperlink - public void insertLatex() { - editLatex(null); - } - public void editLatex(String guid) { - logger.log(logger.EXTREME, "Inserting latex"); - String text = browser.selectedText(); - if (text.trim().equalsIgnoreCase("\n") || text.trim().equalsIgnoreCase("")) { - InsertLatexImage dialog = new InsertLatexImage(); - if (guid != null) { - String formula = conn.getNoteTable().noteResourceTable.getNoteSourceUrl(guid).replace("http://latex.codecogs.com/gif.latex?", ""); - dialog.setFormula(formula); - } - dialog.exec(); - if (!dialog.okPressed()) { - logger.log(logger.EXTREME, "Edit LaTex canceled"); - return; - } - text = dialog.getFormula().trim(); - } - blockApplication.emit(this); - logger.log(logger.EXTREME, "Inserting LaTeX formula:" +text); - latexGuid = guid; - text = StringUtils.replace(text, "'", "\\'"); - String url = "http://latex.codecogs.com/gif.latex?" +text; - logger.log(logger.EXTREME, "Sending request to codecogs --> " + url); - QNetworkAccessManager manager = new QNetworkAccessManager(this); - manager.finished.connect(this, "insertLatexImageReady(QNetworkReply)"); - unblockTime = new GregorianCalendar().getTimeInMillis()+5000; - awaitingHttpResponse = true; - manager.get(new QNetworkRequest(new QUrl(url))); - } - - public void insertLatexImageReady(QNetworkReply reply) { - logger.log(logger.EXTREME, "Response received from CodeCogs"); - if (reply.error() != NetworkError.NoError) - return; - - unblockTime = -1; - if (!awaitingHttpResponse) - return; - - awaitingHttpResponse = false; - QUrl replyUrl = reply.url(); - QByteArray image = reply.readAll(); - reply.close(); - logger.log(logger.EXTREME, "New image size: " +image.size()); - - Resource newRes = null; - QFile tfile; - String path; - if (latexGuid == null) { - logger.log(logger.EXTREME, "Creating temporary gif"); - path = Global.getFileManager().getResDirPath("latex-temp.gif"); - tfile = new QFile(path); - tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly)); - logger.log(logger.EXTREME, "File Open: " +tfile.errorString()); - tfile.write(image); - logger.log(logger.EXTREME, "Bytes writtes: "+tfile.size()); - tfile.close(); - logger.log(logger.EXTREME, "Creating resource"); - int sequence = 0; - if (currentNote.getResources() != null || currentNote.getResources().size() > 0) - sequence = currentNote.getResources().size(); - newRes = createResource(path,sequence ,"image/gif", false); - QImage pix = new QImage(); - pix.loadFromData(image); - newRes.setHeight(new Integer(pix.height()).shortValue()); - newRes.setWidth(new Integer(pix.width()).shortValue()); - logger.log(logger.EXTREME, "Renaming temporary file to " +newRes.getGuid()+".gif"); - path = Global.getFileManager().getResDirPath(newRes.getGuid()+".gif"); - tfile.rename(path); - } else { - newRes = conn.getNoteTable().noteResourceTable.getNoteResource(latexGuid, false); - path = Global.getFileManager().getResDirPath(newRes.getGuid()+".gif"); - tfile = new QFile(path); - tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly)); - tfile.write(image); - tfile.close(); - newRes.getData().setBody(image.toByteArray()); - // Calculate the new hash value - MessageDigest md; - - logger.log(logger.EXTREME, "Generating MD5"); - try { - md = MessageDigest.getInstance("MD5"); - md.update(image.toByteArray()); - byte[] hash = md.digest(); - newRes.getData().setBodyHash(hash); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - } - QImage pix = new QImage(); - pix.loadFromData(image); - newRes.setHeight(new Integer(pix.height()).shortValue()); - newRes.setWidth(new Integer(pix.width()).shortValue()); - conn.getNoteTable().noteResourceTable.updateNoteResource(newRes, true); - } - - logger.log(logger.EXTREME, "Setting source: " +replyUrl.toString()); - newRes.getAttributes().setSourceURL(replyUrl.toString()); - conn.getNoteTable().noteResourceTable.updateNoteSourceUrl(newRes.getGuid(), replyUrl.toString(), true); - - for(int i=0; i"); - - String script_start = new String("document.execCommand('insertHTML', false, '"); - String script_end = new String("');"); - browser.page().mainFrame().evaluateJavaScript( - script_start + buffer + script_end); - } else { - HtmlTagModifier modifier = new HtmlTagModifier(getContent()); - modifier.modifyLatexTagHash(newRes); - String newContent = modifier.getHtml(); - setContent(new QByteArray(newContent)); - } - - logger.log(logger.EXTREME, "New HTML set\n" +browser.page().currentFrame().toHtml()); - QWebSettings.setMaximumPagesInCache(0); - QWebSettings.setObjectCacheCapacities(0, 0, 0); - - browser.page().mainFrame().setHtml(browser.page().mainFrame().toHtml()); - browser.reload(); - contentChanged(); -// resourceSignal.contentChanged.emit(path); - unblockTime = -1; - unblockApplication.emit(); - return; - - } - - - - // Insert a table - public void insertTable() { - TableDialog dialog = new TableDialog(); - dialog.exec(); - if (!dialog.okPressed()) { - return; - } - - int cols = dialog.getCols(); - int rows = dialog.getRows(); - int width = dialog.getWidth(); - boolean percent = dialog.isPercent(); - - String newHTML = ""; - - for (int i=0; i"; - for (int j=0; j "; - } - newHTML = newHTML +""; - } - newHTML = newHTML+"
"; - - String script = "document.execCommand('insertHtml', false, '"+newHTML+"');"; - browser.page().mainFrame().evaluateJavaScript(script); - } - - - // Text content changed - @SuppressWarnings("unused") - private void selectionChanged() { - browser.encryptAction.setEnabled(true); - browser.insertLinkAction.setEnabled(true); - browser.insertQuickLinkAction.setEnabled(true); - String scriptStart = "var selection_text = (window.getSelection()).toString();" - + "var range = (window.getSelection()).getRangeAt(0);" - + "var parent_html = range.commonAncestorContainer.innerHTML;" - + "if (parent_html == undefined) {window.jambi.saveSelectedText(selection_text); return;}" - + "var first_text = range.startContainer.nodeValue.substr(range.startOffset);" - + "var last_text = (range.endContainer.nodeValue).substring(0,range.endOffset);" - + "var start = parent_html.indexOf(first_text);" - + "var end = parent_html.indexOf(last_text,start+1)+last_text.length;" - + "var value = parent_html.substring(start,end);" - + "window.jambi.saveSelectedText(value);" ; - browser.page().mainFrame().evaluateJavaScript(scriptStart); - - } - - public void saveSelectedText(String text) { - boolean enabled = true; - if (text.trim().length() == 0) - enabled=false; - if (text.indexOf("en-tag=\"en-crypt\"") >= 0) - enabled=false; - if (text.indexOf("= 0) - enabled=false; - if (text.indexOf("= 0) - enabled=false; - if (text.indexOf("= 0) - enabled=false; - - browser.encryptAction.setEnabled(enabled); - browser.insertLinkAction.setEnabled(enabled); - browser.insertQuickLinkAction.setEnabled(enabled); -// selectedText = text; - } - - // Decrypt clicked text - public void decryptText(String id, String text, String hint) { - EnCrypt crypt = new EnCrypt(); - String plainText = null; - Calendar currentTime = new GregorianCalendar(); - Long l = new Long(currentTime.getTimeInMillis()); - String slot = new String(Long.toString(l)); - - // First, try to decrypt with any keys we already have - for (int i=0; i passwordPair = new Pair(); - passwordPair.setFirst(dialog.getPassword()); - passwordPair.setSecond(dialog.getHint()); - Global.passwordSafe.put(slot, passwordPair); -// removeEncryption(id, plainText.replaceAll("\n", "
"), dialog.permanentlyDecrypt(), slot); - removeEncryption(id, plainText, dialog.permanentlyDecrypt(), slot); - if (dialog.rememberPassword()) { - Pair pair = new Pair(); - pair.setFirst(dialog.getPassword()); - pair.setSecond(dialog.getHint()); - Global.passwordRemember.add(pair); - } - - } - - // Get the editor tag line - public TagLineEdit getTagLine() { - return tagEdit; - } - - // Modify a note's tags - @SuppressWarnings("unused") - private void modifyTags() { - TagAssign tagWindow = new TagAssign(allTags, currentTags, !conn.getNotebookTable().isLinked(currentNote.getNotebookGuid())); - tagWindow.exec(); - if (tagWindow.okClicked()) { - currentTags.clear(); - StringBuffer tagDisplay = new StringBuffer(); - - List newTags = tagWindow.getTagList() - .selectedItems(); - for (int i = 0; i < newTags.size(); i++) { - currentTags.add(newTags.get(i).text()); - tagDisplay.append(newTags.get(i).text()); - if (i < newTags.size() - 1) { - tagDisplay.append(Global.tagDelimeter + " "); - } - } - tagEdit.setText(tagDisplay.toString()); - noteSignal.tagsChanged.emit(currentNote.getGuid(), currentTags); - } - } - - // Tag line has been modified by typing text - @SuppressWarnings("unused") - private void modifyTagsTyping() { - String completionText = ""; - if (tagEdit.currentCompleterSelection != null && !tagEdit.currentCompleterSelection.equals("")) { - completionText = tagEdit.currentCompleterSelection; - tagEdit.currentCompleterSelection = ""; - } - - if (tagEdit.text().equalsIgnoreCase(saveTagList)) - return; - - // We know something has changed... - String oldTagArray[] = saveTagList.split(Global.tagDelimeter); - String newTagArray[]; - if (!completionText.equals("")) { - String before = tagEdit.text().substring(0,tagEdit.cursorPosition()); - int lastDelimiter = before.lastIndexOf(Global.tagDelimeter); - if (lastDelimiter > 0) - before = before.substring(0,before.lastIndexOf(Global.tagDelimeter)); - else - before = ""; - String after = tagEdit.text().substring(tagEdit.cursorPosition()); - newTagArray = (before+Global.tagDelimeter+completionText+Global.tagDelimeter+after).split(Global.tagDelimeter); - } - else { - newTagArray = tagEdit.text().split(Global.tagDelimeter); - } - - // Remove any traling or leading blanks - for (int i=0; i newTagList = new ArrayList(); - List oldTagList = new ArrayList(); - - for (int i = 0; i < oldTagArray.length; i++) - if (!oldTagArray[i].trim().equals("")) - oldTagList.add(oldTagArray[i]); - for (int i = 0; i < newTagArray.length; i++) - if (!newTagArray[i].trim().equals("")) - newTagList.add(newTagArray[i]); - - if (conn.getNotebookTable().isLinked(currentNote.getNotebookGuid())) { - for (int i=newTagList.size()-1; i>=0; i--) { - boolean found = false; - for (int j=0; j= 0; i--) { - String nTag = newTagList.get(i); - for (int j = oldTagList.size() - 1; j >= 0; j--) { - String oTag = oldTagList.get(j); - if (oTag.equalsIgnoreCase(nTag)) { - oldTagList.remove(j); - newTagList.remove(i); - j = -1; - } - } - } - - if (oldTagList.size() != 0 || newTagList.size() != 0) { - currentTags.clear(); - newTagArray = tagEdit.text().split(Global.tagDelimeter); - for (int i = 0; i < newTagArray.length; i++) - if (!newTagArray[i].trim().equals("")) - currentTags.add(newTagArray[i].trim()); - - noteSignal.tagsChanged.emit(currentNote.getGuid(), currentTags); - } - - } - - // Tab button was pressed - public void tabPressed() { - if (insideEncryption) - return; - if (!insideList && !insideTable) { - String script_start = new String( - "document.execCommand('insertHtml', false, '     ');"); - browser.page().mainFrame().evaluateJavaScript(script_start); - return; - } - if (insideList) { - indentClicked(); - } - if (insideTable) { - String js = new String( "function getCursorPosition() { " - +" var selObj = window.getSelection();" - +" var selRange = selObj.getRangeAt(0);" - +" var workingNode = window.getSelection().anchorNode;" - +" var rowCount = 0;" - +" var colCount = 0;" - +" while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { " - +" if (workingNode.nodeName.toLowerCase()=='tr') {" - +" rowCount = rowCount+1;" - +" }" - +" if (workingNode.nodeName.toLowerCase() == 'td') {" - +" colCount = colCount+1;" - +" }" - +" if (workingNode.previousSibling != null)" - +" workingNode = workingNode.previousSibling;" - +" else " - +" workingNode = workingNode.parentNode;" - +" }" - +" var nodes = workingNode.getElementsByTagName('tr');" - +" var tableRows = nodes.length;" - +" nodes = nodes[0].getElementsByTagName('td');" - +" var tableColumns = nodes.length;" - +" window.jambi.setTableCursorPositionTab(rowCount, colCount, tableRows, tableColumns);" - +"} getCursorPosition();"); - browser.page().mainFrame().evaluateJavaScript(js); - } - } - - // If a user presses tab from within a table - public void setTableCursorPositionTab(int currentRow, int currentCol, int tableRows, int tableColumns) { - if (tableRows == currentRow && currentCol == tableColumns) { - insertTableRow(); - } - KeyboardModifiers modifiers = new KeyboardModifiers(KeyboardModifier.NoModifier); - QKeyEvent right = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Right.value(), modifiers); - QKeyEvent end = new QKeyEvent(Type.KeyPress, Qt.Key.Key_End.value(), modifiers); - QKeyEvent end2 = new QKeyEvent(Type.KeyPress, Qt.Key.Key_End.value(), modifiers); - getBrowser().focusWidget(); - QCoreApplication.postEvent(getBrowser(), end); - QCoreApplication.postEvent(getBrowser(), right); - QCoreApplication.postEvent(getBrowser(), end2); - } - - public void backtabPressed() { - if (insideEncryption) - return; - if (insideList) - outdentClicked(); - if (insideTable) { - String js = new String( "function getCursorPosition() { " - +" var selObj = window.getSelection();" - +" var selRange = selObj.getRangeAt(0);" - +" var workingNode = window.getSelection().anchorNode;" - +" var rowCount = 0;" - +" var colCount = 0;" - +" while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { " - +" if (workingNode.nodeName.toLowerCase()=='tr') {" - +" rowCount = rowCount+1;" - +" }" - +" if (workingNode.nodeName.toLowerCase() == 'td') {" - +" colCount = colCount+1;" - +" }" - +" if (workingNode.previousSibling != null)" - +" workingNode = workingNode.previousSibling;" - +" else " - +" workingNode = workingNode.parentNode;" - +" }" - +" var nodes = workingNode.getElementsByTagName('tr');" - +" var tableRows = nodes.length;" - +" nodes = nodes[0].getElementsByTagName('td');" - +" var tableColumns = nodes.length;" - +" window.jambi.setTableCursorPositionBackTab(rowCount, colCount, tableRows, tableColumns);" - +"} getCursorPosition();"); - browser.page().mainFrame().evaluateJavaScript(js); - - } - } - - // If a user presses backtab from within a table - public void setTableCursorPositionBackTab(int currentRow, int currentCol, int tableRows, int tableColumns) { - if (currentRow == 1 && currentCol == 1) { - return; - } - KeyboardModifiers modifiers = new KeyboardModifiers(KeyboardModifier.NoModifier); - QKeyEvent left = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Left.value(), modifiers); - QKeyEvent home = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Home.value(), modifiers); - getBrowser().focusWidget(); - QCoreApplication.postEvent(getBrowser(), home); - QCoreApplication.postEvent(getBrowser(), left); - } - - - public void setInsideList() { - insideList = true; - } - - // The title has been edited - @SuppressWarnings("unused") - private void titleEdited() { - // If we don't have a good note, or if the current title - // matches the old title then we don't need to do anything - if (currentNote == null) - return; - if (currentNote.getTitle().trim().equals(titleLabel.text().trim())) - return; - - // If we have a real change, we need to save it. - String text = titleLabel.text().trim(); - if (text.equals("")) - text = tr("Untitled Note"); - noteSignal.titleChanged.emit(currentNote.getGuid(), text); - currentNote.setTitle(text); - saveNoteTitle = text; - checkNoteTitle(); - } - - // Set the list of note tags - public void setAllTags(List l) { - allTags = l; - tagEdit.setTagList(l); - } - - // Setter for the current tags - public void setCurrentTags(List s) { - currentTags = s; - } - - // Save the list of notebooks - public void setNotebookList(List n) { - notebookList = n; - loadNotebookList(); - } - - // Load the notebook list and select the current notebook - private void loadNotebookList() { - if (notebookBox.count() != 0) - notebookBox.clear(); - if (notebookList == null) - return; - - for (int i = 0; i < notebookList.size(); i++) { - notebookBox.addItem(notebookList.get(i).getName()); - if (currentNote != null) { - if (currentNote.getNotebookGuid().equals( - notebookList.get(i).getGuid())) { - notebookBox.setCurrentIndex(i); - } - } - } - } - - - // Set the notebook for a note - public void setNotebook(String notebook) { - currentNote.setNotebookGuid(notebook); - loadNotebookList(); - } - - // Get the contents of the editor - public String getContent() { - return browser.page().currentFrame().toHtml(); - } - - // The note contents have changed - public void contentChanged() { - String content = getContent(); - - // This puts in a 1/2 second delay - // before updating the source editor. - // It improves response when someone is doing - // frequent updates on a large note. - // If the source editor isn't visible, then there - // is no point to doing any of this. - if (sourceEdit.isVisible()) { - setSourceTimer.stop(); - setSourceTimer.setInterval(500); - setSourceTimer.setSingleShot(true); - setSourceTimer.start(); - } - - checkNoteTitle(); - noteSignal.noteChanged.emit(currentNote.getGuid(), content); - } - - // The notebook selection has changed - @SuppressWarnings("unused") - private void notebookChanged() { - boolean changed = false; - String n = notebookBox.currentText(); - for (int i = 0; i < notebookList.size(); i++) { - if (n.equals(notebookList.get(i).getName())) { - if (!notebookList.get(i).getGuid().equals(currentNote.getNotebookGuid())) { - String guid = conn.getNotebookTable().findNotebookByName(n); - if (conn.getNotebookTable().isLinked(guid)) { - tagEdit.setText(""); - noteSignal.tagsChanged.emit(currentNote.getGuid(), new ArrayList()); - FilterEditorTags t = new FilterEditorTags(conn, logger); - setAllTags(t.getValidTags(currentNote)); - } - currentNote.setNotebookGuid(notebookList.get(i).getGuid()); - changed = true; - } - i = notebookList.size(); - } - } - - // If the notebook changed, signal the update - if (changed) - noteSignal.notebookChanged.emit(currentNote.getGuid(), currentNote - .getNotebookGuid()); - } - - // Check the note title - private void checkNoteTitle() { - String text = browser.page().currentFrame().toPlainText(); - if (saveNoteTitle == null) - saveNoteTitle = new String(); - text = text.trim(); - if (!saveNoteTitle.trim().equals("") && !saveNoteTitle.trim().equals("Untitled Note")) - text = saveNoteTitle.trim(); - int newLine = text.indexOf("\n"); - if (newLine > 0) - text = text.substring(0,newLine); - if (saveNoteTitle.trim().equals("") || saveNoteTitle.trim().equals("Untitled Note")) { - if (text.trim().equals("")) - text = tr("Untitled Note"); - titleLabel.setText(text); - } else { - if (text.length() > Constants.EDAM_NOTE_TITLE_LEN_MAX) - titleLabel.setText(text.substring(0, Constants.EDAM_NOTE_TITLE_LEN_MAX)); - else { - titleLabel.blockSignals(true); - if (text.trim().equals("")) - titleLabel.setText(tr("Untitled Note")); - else - titleLabel.setText(text); - titleLabel.blockSignals(false); - } - } - if (currentNote != null && titleLabel != null && !currentNote.getTitle().equals(text)) - noteSignal.titleChanged.emit(currentNote.getGuid(), text); - } - - // Return the note contents so we can email them - public String getContentsToEmail() { - return browser.page().currentFrame().toPlainText().trim(); - /* - * int body = browser.page().currentFrame().toHtml().indexOf(""); - * String temp = browser.page().currentFrame().toHtml(); if (body == -1) - * temp = "Test"; else temp = - * ""+temp.substring(body); return temp; // return - * urlEncode(browser.page().currentFrame().toHtml()); - */ - } - - // Insert an image into the editor - private void insertImage(QMimeData mime) { - logger.log(logger.EXTREME, "Entering insertImage"); - QImage img = (QImage) mime.imageData(); - String script_start = new String( - "document.execCommand('insertHTML', false, '"); - String script_end = new String("');"); - - long now = new Date().getTime(); - String path = Global.getFileManager().getResDirPath( - (new Long(now).toString()) + ".jpg"); - - // This block is just a hack to make sure we wait at least 1ms so we - // don't - // have collisions on image names - long i = new Date().getTime(); - while (now == i) - i = new Date().getTime(); - - // Open the file & write the data - QFile tfile = new QFile(path); - tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly)); - if (!img.save(tfile)) { - tfile.close(); - return; - } - tfile.close(); - - Resource newRes = createResource(QUrl.fromLocalFile(path).toString(), 0, "image/jpeg", false); - if (newRes == null) - return; - currentNote.getResources().add(newRes); - - // do the actual insert into the note - StringBuffer buffer = new StringBuffer(100); - buffer.append(""); - - browser.page().mainFrame().evaluateJavaScript( - script_start + buffer + script_end); - - return; - } - - // Handle pasting of a note-to-note link - private void handleNoteLink(QMimeData mime) { - for (int i=0; i"); - url.append(note.getTitle()); - url.append("
"); - if (mime.urls().size() > 1) - url.append(" "); - browser.page().mainFrame().evaluateJavaScript( - script_start + url + script_end); - } - } - } - - // Handle URLs that are trying to be pasted - public void handleUrls(QMimeData mime) { - logger.log(logger.EXTREME, "Starting handleUrls"); - FileNameMap fileNameMap = URLConnection.getFileNameMap(); - - List urlList = mime.urls(); - String url = new String(); - String script_start = new String( - "document.execCommand('createLink', false, '"); - String script_end = new String("');"); - - for (int i = 0; i < urlList.size(); i++) { - url = urlList.get(i).toString(); - // Find out what type of file we have - String mimeType = fileNameMap.getContentTypeFor(url); - - // If null returned, we need to guess at the file type - if (mimeType == null) - mimeType = "application/" - + url.substring(url.lastIndexOf(".") + 1); - - // Check if we have an image or some other type of file - if (url.substring(0, 5).equalsIgnoreCase("file:") - && mimeType.substring(0, 5).equalsIgnoreCase("image")) { - handleLocalImageURLPaste(mime, mimeType); - return; - } - - boolean smallEnough = checkFileAttachmentSize(url); - if (smallEnough - && url.substring(0, 5).equalsIgnoreCase("file:") - && !mimeType.substring(0, 5).equalsIgnoreCase("image")) { - handleLocalAttachment(mime, mimeType); - return; - } - browser.page().mainFrame().evaluateJavaScript( - script_start + url + script_end); - } - return; - } - - // If a URL being pasted is an image URL, then attach the image - private void handleLocalImageURLPaste(QMimeData mime, String mimeType) { - List urlList = mime.urls(); - String url = new String(); - String script_start_image = new String( - "document.execCommand('insertHtml', false, '"); - String script_end = new String("');"); - StringBuffer buffer; - - // Copy the image over into the resource directory and create a new resource - // record for each url pasted - for (int i = 0; i < urlList.size(); i++) { - url = urlList.get(i).toString(); - - Resource newRes = createResource(url, i, mimeType, false); - if (newRes == null) - return; - currentNote.getResources().add(newRes); - buffer = new StringBuffer(100); - - // Open the file & write the data - String fileName = Global.getFileManager().getResDirPath(newRes.getGuid()); - QFile tfile = new QFile(fileName); - tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly)); - tfile.write(newRes.getData().getBody()); - tfile.close(); - buffer.append(script_start_image); - buffer.append(""); - buffer.append(script_end); - browser.page().mainFrame().evaluateJavaScript(buffer.toString()); - } - return; - } - - - // If a URL being pasted is a local file URL, then attach the file - private void handleLocalAttachment(QMimeData mime, String mimeType) { - logger.log(logger.EXTREME, "Attaching local file"); - List urlList = mime.urls(); - String script_start = new String( - "document.execCommand('insertHtml', false, '"); - String script_end = new String("');"); - StringBuffer buffer; - - String[] type = mimeType.split("/"); - String icon = findIcon(type[1]); - if (icon.equals("attachment.png")) - icon = findIcon(type[0]); - buffer = new StringBuffer(100); - - for (int i = 0; i < urlList.size(); i++) { - String url = urlList.get(i).toString(); - - // Start building the HTML - if (icon.equals("attachment.png")) - icon = findIcon(url.substring(url.lastIndexOf(".")+1)); - String imageURL = FileUtils.toFileURLString(Global.getFileManager().getImageDirFile(icon)); - - logger.log(logger.EXTREME, "Creating resource "); - Resource newRes = createResource(url, i, mimeType, true); - if (newRes == null) - return; - logger.log(logger.EXTREME, "New resource size: " +newRes.getData().getSize()); - currentNote.getResources().add(newRes); - - String fileName = newRes.getGuid() + Global.attachmentNameDelimeter+newRes.getAttributes().getFileName(); - // If we have a PDF, we need to setup the preview. - if (icon.equalsIgnoreCase("pdf.png") && Global.pdfPreview()) { - logger.log(logger.EXTREME, "Setting up PDF preview"); - if (newRes.getAttributes() != null && - newRes.getAttributes().getFileName() != null && - !newRes.getAttributes().getFileName().trim().equals("")) - fileName = newRes.getGuid()+Global.attachmentNameDelimeter+ - newRes.getAttributes().getFileName(); - else - fileName = newRes.getGuid()+".pdf"; - QFile file = new QFile(Global.getFileManager().getResDirPath(fileName)); - QFile.OpenMode mode = new QFile.OpenMode(); - mode.set(QFile.OpenModeFlag.WriteOnly); - file.open(mode); - QDataStream out = new QDataStream(file); -// Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(newRes.getGuid(), true); - QByteArray binData = new QByteArray(newRes.getData().getBody()); -// resBinary = null; - out.writeBytes(binData.toByteArray()); - file.close(); - - PDFPreview pdfPreview = new PDFPreview(); - if (pdfPreview.setupPreview(Global.getFileManager().getResDirPath(fileName), "pdf",0)) { - imageURL = file.fileName() + ".png"; - } - } - - logger.log(logger.EXTREME, "Generating link tags"); - buffer.delete(0, buffer.length()); - buffer.append(""); - buffer.append(""); - buffer.append(""); - browser.page().mainFrame().evaluateJavaScript( - script_start + buffer.toString() + script_end); - } - return; - } - - private Resource createResource(String url, int sequence, String mime, boolean attachment) { - logger.log(logger.EXTREME, "Inside create resource"); - QFile resourceFile; - //These two lines are added to handle odd characters in the name like #. Without it - // toLocalFile() chokes and returns the wrong name. - logger.log(logger.EXTREME, "File URL:" +url); - String whichOS = System.getProperty("os.name"); - if (whichOS.contains("Windows")) - url = url.replace("file:///", ""); - else - url = url.replace("file://", ""); - String urlTest = new QUrl(url).toLocalFile(); - logger.log(logger.EXTREME, "File URL toLocalFile():" +urlTest); - urlTest = url; - if (!urlTest.equals("")) - url = urlTest; -// url = url.replace("/", File.separator); - logger.log(logger.EXTREME, "Reading from file to create resource:" +url); - resourceFile = new QFile(url); - resourceFile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly)); - logger.log(logger.EXTREME, "Error opening file "+url.toString() +": "+resourceFile.errorString()); - byte[] fileData = resourceFile.readAll().toByteArray(); - resourceFile.close(); - logger.log(logger.EXTREME, "File Length: " +fileData.length); - if (fileData.length == 0) - return null; - MessageDigest md; - try { - logger.log(logger.EXTREME, "Generating MD5"); - md = MessageDigest.getInstance("MD5"); - md.update(fileData); - byte[] hash = md.digest(); - - Resource r = new Resource(); - Calendar time = new GregorianCalendar(); - long prevTime = time.getTimeInMillis(); - while (prevTime == time.getTimeInMillis()) { - time = new GregorianCalendar(); - } - r.setGuid(time.getTimeInMillis()+new Integer(sequence).toString()); - r.setNoteGuid(currentNote.getGuid()); - r.setMime(mime); - r.setActive(true); - r.setUpdateSequenceNum(0); - r.setWidth((short) 0); - r.setHeight((short) 0); - r.setDuration((short) 0); - - Data d = new Data(); - d.setBody(fileData); - d.setBodyIsSet(true); - d.setBodyHash(hash); - d.setBodyHashIsSet(true); - r.setData(d); - d.setSize(fileData.length); - - int fileNamePos = url.lastIndexOf(File.separator); - if (fileNamePos == -1) - fileNamePos = url.lastIndexOf("/"); - String fileName = url.substring(fileNamePos+1); - ResourceAttributes a = new ResourceAttributes(); - a.setAltitude(0); - a.setAltitudeIsSet(false); - a.setLongitude(0); - a.setLongitudeIsSet(false); - a.setLatitude(0); - a.setLatitudeIsSet(false); - a.setCameraMake(""); - a.setCameraMakeIsSet(false); - a.setCameraModel(""); - a.setCameraModelIsSet(false); - a.setAttachment(attachment); - a.setAttachmentIsSet(true); - a.setClientWillIndex(false); - a.setClientWillIndexIsSet(true); - a.setRecoType(""); - a.setRecoTypeIsSet(false); - a.setSourceURL(url); - a.setSourceURLIsSet(true); - a.setTimestamp(0); - a.setTimestampIsSet(false); - a.setFileName(fileName); - a.setFileNameIsSet(true); - r.setAttributes(a); - - conn.getNoteTable().noteResourceTable.saveNoteResource(r, true); - logger.log(logger.EXTREME, "Resource created"); - return r; - } catch (NoSuchAlgorithmException e1) { - e1.printStackTrace(); - } - return null; - } - - - // find the appropriate icon for an attachment - private String findIcon(String appl) { - appl = appl.toLowerCase(); - File f = Global.getFileManager().getImageDirFile(appl + ".png"); - if (f.exists()) - return appl+".png"; - return "attachment.png"; - } - - - - // Check the file attachment to be sure it isn't over 25 mb - private boolean checkFileAttachmentSize(String url) { - String fileName = url.substring(8); - QFile resourceFile = new QFile(fileName); - resourceFile.open(new QIODevice.OpenMode( - QIODevice.OpenModeFlag.ReadOnly)); - long size = resourceFile.size(); - resourceFile.close(); - size = size / 1024 / 1024; - if (size < 50 && Global.isPremium()) - return true; - if (size < 25) - return true; - - String error = tr("A file attachment may not exceed 25MB."); - QMessageBox.information(this, tr("Attachment Size"), error); - return false; - } - - - @SuppressWarnings("unused") - private void createdChanged() { - QDateTime dt = new QDateTime(); - dt.setDate(createdDate.date()); - dt.setTime(createdTime.time()); - noteSignal.createdDateChanged.emit(currentNote.getGuid(), dt); - - } - - @SuppressWarnings("unused") - private void alteredChanged() { - QDateTime dt = new QDateTime(); - dt.setDate(alteredDate.date()); - dt.setTime(alteredTime.time()); - noteSignal.alteredDateChanged.emit(currentNote.getGuid(), dt); - } - - @SuppressWarnings("unused") - private void subjectDateTimeChanged() { - QDateTime dt = new QDateTime(); - dt.setDate(subjectDate.date()); - dt.setTime(subjectTime.time()); - noteSignal.subjectDateChanged.emit(currentNote.getGuid(), dt); - - } - - @SuppressWarnings("unused") - private void sourceUrlChanged() { - noteSignal.sourceUrlChanged.emit(currentNote.getGuid(), urlText.text()); - } - - @SuppressWarnings("unused") - private void authorChanged() { - noteSignal.authorChanged.emit(currentNote.getGuid(), authorText.text()); - } - - @SuppressWarnings("unused") - private void geoBoxChanged() { - int index = geoBox.currentIndex(); - geoBox.setCurrentIndex(0); - if (index == 1) { - GeoDialog box = new GeoDialog(); - box.setLongitude(currentNote.getAttributes().getLongitude()); - box.setLatitude(currentNote.getAttributes().getLatitude()); - box.setAltitude(currentNote.getAttributes().getAltitude()); - box.exec(); - if (!box.okPressed()) - return; - double alt = box.getAltitude(); - double lat = box.getLatitude(); - double lon = box.getLongitude(); - if (alt != currentNote.getAttributes().getAltitude() || - lon != currentNote.getAttributes().getLongitude() || - lat != currentNote.getAttributes().getLatitude()) { - noteSignal.geoChanged.emit(currentNote.getGuid(), lon, lat, alt); - currentNote.getAttributes().setAltitude(alt); - currentNote.getAttributes().setLongitude(lon); - currentNote.getAttributes().setLatitude(lat); - } - } - - if (index == 2) { - noteSignal.geoChanged.emit(currentNote.getGuid(), 0.0, 0.0, 0.0); - currentNote.getAttributes().setAltitude(0.0); - currentNote.getAttributes().setLongitude(0.0); - currentNote.getAttributes().setLatitude(0.0); - } - - if (index == 3 || index == 0) { - QDesktopServices.openUrl(new QUrl("http://maps.google.com/maps?z=6&q="+currentNote.getAttributes().getLatitude() +"," +currentNote.getAttributes().getLongitude())); - } - } - - // ************************************************************ - // * User chose to save an attachment. Pares out the request * - // * into a guid & file. Save the result. * - // ************************************************************ - public void downloadAttachment(QNetworkRequest request) { - String guid; - QFileDialog fd = new QFileDialog(this); - fd.setFileMode(FileMode.AnyFile); - fd.setConfirmOverwrite(true); - fd.setWindowTitle(tr("Save File")); - fd.setAcceptMode(AcceptMode.AcceptSave); - fd.setDirectory(System.getProperty("user.home")); - String name = request.url().toString(); - - int pos = name.lastIndexOf(Global.attachmentNameDelimeter); - if (pos > -1) { - guid = name.substring(0, pos).replace("nnres://", ""); - name = name.substring(pos +Global.attachmentNameDelimeter.length()); - fd.selectFile(name); - pos = name.lastIndexOf('.'); - if (pos > -1) { - String mimeType = "(*." + name.substring(pos + 1) - + ");; All Files (*)"; - fd.setFilter(tr(mimeType)); - } - } else { - guid = name; - } - - // Strip URL prefix and base dir - guid = guid.replace("nnres://", "") - .replace(FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath()), ""); - guid = guid.replace("file://", "").replace("/", "") - .replace(FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath()), ""); - - pos = guid.lastIndexOf('.'); - if (pos > 0) - guid = guid.substring(0,pos); - if (fd.exec() != 0 && fd.selectedFiles().size() > 0) { - name = name.replace('\\', '/'); - Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true); - QFile saveFile = new QFile(fd.selectedFiles().get(0)); - QFile.OpenMode mode = new QFile.OpenMode(); - mode.set(QFile.OpenModeFlag.WriteOnly); - saveFile.open(mode); - QDataStream saveOut = new QDataStream(saveFile); - QByteArray binData = new QByteArray(resBinary.getData().getBody()); - saveOut.writeBytes(binData.toByteArray()); - saveFile.close(); - - } - } - - - // ************************************************************ - // * User chose to save an attachment. Pares out the request * - // * into a guid & file. Save the result. --- DONE FROM downloadAttachment now!!!!! - // ************************************************************ - public void downloadImage(QNetworkRequest request) { - QFileDialog fd = new QFileDialog(this); - fd.setFileMode(FileMode.AnyFile); - fd.setConfirmOverwrite(true); - fd.setWindowTitle(tr("Save File")); - fd.setAcceptMode(AcceptMode.AcceptSave); - fd.setDirectory(System.getProperty("user.home")); - String name = request.url().toString(); - name = name.replace("nnres://", ""); - String dPath = FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath()); - name = name.replace(dPath, ""); - int pos = name.lastIndexOf('.'); - String guid = name; - if (pos > -1) { - String mimeType = "(*." + name.substring(pos + 1) - + ");; All Files (*)"; - fd.setFilter(tr(mimeType)); - guid = guid.substring(0,pos); - } - pos = name.lastIndexOf(Global.attachmentNameDelimeter); - if (pos > -1) { - guid = name.substring(0, pos); - fd.selectFile(name.substring(pos+Global.attachmentNameDelimeter.length())); - } - if (fd.exec() != 0 && fd.selectedFiles().size() > 0) { - Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true); - String fileName = fd.selectedFiles().get(0); - QFile saveFile = new QFile(fileName); - QFile.OpenMode mode = new QFile.OpenMode(); - mode.set(QFile.OpenModeFlag.WriteOnly); - saveFile.open(mode); - QDataStream saveOut = new QDataStream(saveFile); - QByteArray binData = new QByteArray(resBinary.getData().getBody()); - saveOut.writeBytes(binData.toByteArray()); - saveFile.close(); - } - } - - - // ************************************************************* - // * decrypt any hidden text. We could do an XML parse, but - // * it is quicker here just to scan for an " - +plainText+""; - } - - String html = browser.page().mainFrame().toHtml(); - String text = html; - int imagePos = html.indexOf("0; ) { - // Find the end tag - endPos = text.indexOf(">", imagePos); - String tag = text.substring(imagePos-1,endPos); - if (tag.indexOf("id=\""+id+"\"") > -1) { - text = text.substring(0,imagePos) +plainText+text.substring(endPos+1); - QTextCodec codec = QTextCodec.codecForName("UTF-8"); - QByteArray unicode = codec.fromUnicode(text); - setContent(unicode); - if (permanent) - contentChanged(); - } - imagePos = text.indexOf("=0;) { - endPos = text.indexOf(">", startPos+1); - String segment = text.substring(startPos, endPos); - if (segment.indexOf("en-tag") > -1) { - String newSegment = segment; - - int guidStartPos = segment.indexOf("guid=\""); - int guidEndPos = segment.indexOf("\"", guidStartPos+7); - String guid = segment.substring(guidStartPos+6,guidEndPos); - - int mimeStartPos = segment.indexOf("type"); - int mimeEndPos = segment.indexOf("\"", mimeStartPos+7); - String mime = segment.substring(mimeStartPos+6,mimeEndPos); - - int srcStartPos = segment.indexOf("src"); - int srcEndPos = segment.indexOf("\"", srcStartPos+6); - String src = segment.substring(srcStartPos+5,srcEndPos); - - Calendar currentTime = new GregorianCalendar(); - Long l = new Long(currentTime.getTimeInMillis()); - long prevTime = l; - while (l==prevTime) { - currentTime = new GregorianCalendar(); - l= new Long(currentTime.getTimeInMillis()); - } - - Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true); - // if r==null, then the image doesn't exist (it was probably cut out of another note, so - // we need to recereate it - if (r==null) { - r = createResource(src, 1, mime, false); - if (r==null) - return ""; - } - String randint = new String(Long.toString(l)); - String extension = null; - if (r.getMime()!= null) { - extension = r.getMime().toLowerCase(); - if (extension.indexOf("/")>-1) - extension = extension.substring(extension.indexOf("/")+1); - } - String newFile = randint; - if (r.getAttributes().getFileName() != null && r.getAttributes().getFileName() != "") - if (!locTag.startsWith("src")) - newFile = newFile+Global.attachmentNameDelimeter+r.getAttributes().getFileName(); - r.setNoteGuid(currentNote.getGuid()); - - r.setGuid(randint); - conn.getNoteTable().noteResourceTable.saveNoteResource(r, true); - QFile f = new QFile(Global.getFileManager().getResDirPath(newFile)); - QByteArray bin = new QByteArray(r.getData().getBody()); - f.open(QFile.OpenModeFlag.WriteOnly); - f.write(bin); - f.close(); - newSegment = newSegment.replace("guid=\""+guid, "guid=\""+randint); - currentNote.getResources().add(r); - - int startSrcPos = newSegment.indexOf(locTag); - int endSrcPos = newSegment.indexOf("\"",startSrcPos+locTag.length()+1); - String source; - if (locTag.startsWith("src")) { - source = newSegment.substring(startSrcPos+locTag.length(),endSrcPos); - newSegment = newSegment.replace(source, - FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath(newFile))); - } else { - source = newSegment.substring(startSrcPos+locTag.length(),endSrcPos); - newSegment = newSegment.replace(source, newFile); - } - - text = text.substring(0,startPos) + newSegment + text.substring(endPos); - } - startPos = text.indexOf(type, startPos+1); - } - return text; - } - - - public void nextPage(String file) { - logger.log(logger.EXTREME, "Starting nextPage()"); - - Integer pageNumber; - if (previewPageList.containsKey(file)) - pageNumber = previewPageList.get(file)+1; - else - pageNumber = 2; - previewPageList.remove(file); - previewPageList.put(file, pageNumber); - PDFPreview pdfPreview = new PDFPreview(); - boolean goodPreview = pdfPreview.setupPreview(file, "pdf", pageNumber); - if (goodPreview) { - -// String html = getContent(); - QWebSettings.setMaximumPagesInCache(0); - QWebSettings.setObjectCacheCapacities(0, 0, 0); -// browser.setContent(new QByteArray()); - browser.setHtml(browser.page().mainFrame().toHtml()); - browser.reload(); -// browser.setContent(new QByteArray(html)); -// browser.triggerPageAction(WebAction.Reload); -// pdfMouseOver(selectedFile); - } - } - - public void previousPage(String file) { - logger.log(logger.EXTREME, "Starting previousPage()"); - - Integer pageNumber; - if (previewPageList.containsKey(file)) - pageNumber = previewPageList.get(file)-1; - else - pageNumber = 1; - previewPageList.remove(file); - previewPageList.put(file, pageNumber); - PDFPreview pdfPreview = new PDFPreview(); - boolean goodPreview = pdfPreview.setupPreview(file, "pdf", pageNumber); - if (goodPreview) { - -// String html = getContent(); - QWebSettings.setMaximumPagesInCache(0); - QWebSettings.setObjectCacheCapacities(0, 0, 0); - browser.setHtml(browser.page().mainFrame().toHtml()); - browser.reload(); -// browser.setContent(new QByteArray(html)); -// browser.triggerPageAction(WebAction.Reload); - } - } - -/* public void pdfMouseOver(String name) { - int pageNumber; - if (previewPageList.containsKey(selectedFile)) - pageNumber = previewPageList.get(selectedFile)+1; - else - pageNumber = 1; - - if (pageNumber <= 1) - browser.previousPageAction.setEnabled(false); - else - browser.previousPageAction.setEnabled(true); - - PDFPreview pdf = new PDFPreview(); - int totalPages = pdf.getPageCount(name); - if (previewPageList.containsKey(selectedFile)) - pageNumber = previewPageList.get(selectedFile)+1; - else - pageNumber = 1; - if (totalPages > pageNumber) - browser.nextPageAction.setEnabled(true); - else - browser.nextPageAction.setEnabled(false); - } - - - public void pdfMouseOut() { -// browser.nextPageAction.setVisible(false); -// browser.previousPageAction.setVisible(false); - } -*/ - - @SuppressWarnings("unused") - private void toggleUndoVisible(Boolean toggle) { - undoAction.setVisible(toggle); - Global.saveEditorButtonsVisible("undo", toggle); - } - @SuppressWarnings("unused") - private void toggleRedoVisible(Boolean toggle) { - redoAction.setVisible(toggle); - Global.saveEditorButtonsVisible("redo", toggle); - } - @SuppressWarnings("unused") - private void toggleCutVisible(Boolean toggle) { - cutAction.setVisible(toggle); - Global.saveEditorButtonsVisible("cut", toggle); - } - @SuppressWarnings("unused") - private void toggleCopyVisible(Boolean toggle) { - copyAction.setVisible(toggle); - Global.saveEditorButtonsVisible("copy", toggle); - } - @SuppressWarnings("unused") - private void togglePasteVisible(Boolean toggle) { - pasteAction.setVisible(toggle); - Global.saveEditorButtonsVisible("paste", toggle); - } - @SuppressWarnings("unused") - private void toggleBoldVisible(Boolean toggle) { - boldAction.setVisible(toggle); - Global.saveEditorButtonsVisible("bold", toggle); - } - @SuppressWarnings("unused") - private void toggleItalicVisible(Boolean toggle) { - italicAction.setVisible(toggle); - Global.saveEditorButtonsVisible("italic", toggle); - } - @SuppressWarnings("unused") - private void toggleUnderlineVisible(Boolean toggle) { - underlineAction.setVisible(toggle); - Global.saveEditorButtonsVisible("underline", toggle); - } - @SuppressWarnings("unused") - private void toggleStrikethroughVisible(Boolean toggle) { - strikethroughAction.setVisible(toggle); - Global.saveEditorButtonsVisible("strikethrough", toggle); - } - @SuppressWarnings("unused") - private void toggleLeftAlignVisible(Boolean toggle) { - leftAlignAction.setVisible(toggle); - Global.saveEditorButtonsVisible("alignLeft", toggle); - } - @SuppressWarnings("unused") - private void toggleRightAlignVisible(Boolean toggle) { - rightAlignAction.setVisible(toggle); - Global.saveEditorButtonsVisible("alignRight", toggle); - } - @SuppressWarnings("unused") - private void toggleCenterAlignVisible(Boolean toggle) { - centerAlignAction.setVisible(toggle); - Global.saveEditorButtonsVisible("alignCenter", toggle); - } - @SuppressWarnings("unused") - private void toggleHLineVisible(Boolean toggle) { - hlineAction.setVisible(toggle); - Global.saveEditorButtonsVisible("hline", toggle); - } - @SuppressWarnings("unused") - private void toggleIndentVisible(Boolean toggle) { - indentAction.setVisible(toggle); - Global.saveEditorButtonsVisible("indent", toggle); - } - @SuppressWarnings("unused") - private void toggleTodoVisible(Boolean toggle) { - todoAction.setVisible(toggle); - Global.saveEditorButtonsVisible("todo", toggle); - } - @SuppressWarnings("unused") - private void toggleOutdentVisible(Boolean toggle) { - outdentAction.setVisible(toggle); - Global.saveEditorButtonsVisible("outdent", toggle); - } - @SuppressWarnings("unused") - private void toggleBulletListVisible(Boolean toggle) { - bulletListAction.setVisible(toggle); - Global.saveEditorButtonsVisible("bulletList", toggle); - } - @SuppressWarnings("unused") - private void toggleNumberListVisible(Boolean toggle) { - numberListAction.setVisible(toggle); - Global.saveEditorButtonsVisible("numberList", toggle); - } - @SuppressWarnings("unused") - private void toggleFontListVisible(Boolean toggle) { - fontListAction.setVisible(toggle); - Global.saveEditorButtonsVisible("font", toggle); - } - @SuppressWarnings("unused") - private void toggleFontColorVisible(Boolean toggle) { - fontColorAction.setVisible(toggle); - Global.saveEditorButtonsVisible("fontColor", toggle); - } - @SuppressWarnings("unused") - private void toggleFontSizeVisible(Boolean toggle) { - fontSizeAction.setVisible(toggle); - Global.saveEditorButtonsVisible("fontSize", toggle); - } - @SuppressWarnings("unused") - private void toggleFontHilightVisible(Boolean toggle) { - fontHilightAction.setVisible(toggle); - Global.saveEditorButtonsVisible("fontHilight", toggle); - } - @SuppressWarnings("unused") - private void toggleSpellCheckVisible(Boolean toggle) { - spellCheckAction.setVisible(toggle); - Global.saveEditorButtonsVisible("spellCheck", toggle); - } - - - private void setupDictionary() { - File wordList = new File(Global.getFileManager().getSpellDirPath()+Locale.getDefault()+".dic"); - try { - dictionary = new SpellDictionaryHashMap(wordList); - spellChecker = new SpellChecker(dictionary); - - File userWordList; - userWordList = new File(Global.getFileManager().getSpellDirPathUser()+"user.dic"); - - // Get the local user spell dictionary - try { - userDictionary = new SpellDictionaryHashMap(userWordList); - } catch (FileNotFoundException e) { - userWordList.createNewFile(); - userDictionary = new SpellDictionaryHashMap(userWordList); - } catch (IOException e) { - userWordList.createNewFile(); - userDictionary = new SpellDictionaryHashMap(userWordList); - } - - spellListener = new SuggestionListener(this, spellChecker); - - // Add the user dictionary - spellChecker.addSpellCheckListener(spellListener); - spellChecker.setUserDictionary(userDictionary); - - } catch (FileNotFoundException e) { - QMessageBox.critical(this, tr("Spell Check Error"), - tr("Dictionary ")+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+ - tr(".dic was not found.")); - } catch (IOException e) { - QMessageBox.critical(this, tr("Spell Check Error"), - tr("Dictionary ")+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+ - tr(".dic is invalid.")); - } - - } - - // Invoke spell checker dialog - @SuppressWarnings("unused") - private void spellCheckClicked() { - - if (spellChecker == null) { - setupDictionary(); - } - - // Read user settings - spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREDIGITWORDS, - Global.getSpellSetting(Configuration.SPELL_IGNOREDIGITWORDS)); - spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREINTERNETADDRESSES, - Global.getSpellSetting(Configuration.SPELL_IGNOREINTERNETADDRESSES)); - spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREMIXEDCASE, - Global.getSpellSetting(Configuration.SPELL_IGNOREMIXEDCASE)); - spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREUPPERCASE, - Global.getSpellSetting(Configuration.SPELL_IGNOREUPPERCASE)); - spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNORESENTENCECAPITALIZATION, - Global.getSpellSetting(Configuration.SPELL_IGNORESENTENCECAPITALIZATION)); - - spellListener.abortSpellCheck = false; - spellListener.errorsFound = false; - String content = getBrowser().page().mainFrame().toPlainText(); - StringWordTokenizer tokenizer = new StringWordTokenizer(content); - if (!tokenizer.hasMoreWords()) - return; - getBrowser().page().action(WebAction.MoveToStartOfDocument); - - getBrowser().setFocus(); - boolean found; - - // Move to the start of page - KeyboardModifiers ctrl = new KeyboardModifiers(KeyboardModifier.ControlModifier.value()); - QKeyEvent home = new QKeyEvent(Type.KeyPress, Key.Key_Home.value(), ctrl); - browser.keyPressEvent(home); - getBrowser().setFocus(); - - tokenizer = new StringWordTokenizer(content); - String word; - - while(tokenizer.hasMoreWords()) { - word = tokenizer.nextWord(); - found = getBrowser().page().findText(word); - if (found && !spellListener.abortSpellCheck) { - spellChecker.checkSpelling(new StringWordTokenizer(word)); - getBrowser().setFocus(); - } - } - - // Go to the end of the document & finish up. - home = new QKeyEvent(Type.KeyPress, Key.Key_End.value(), ctrl); - browser.keyPressEvent(home); - if (!spellListener.errorsFound) - QMessageBox.information(this, tr("Spell Check Complete"), - tr("No Errors Found")); - - } - - // Source edited - @SuppressWarnings("unused") - private void sourceEdited() { - QTextCodec codec = QTextCodec.codecForLocale(); - codec = QTextCodec.codecForName("UTF-8"); - String content = codec.fromUnicode(sourceEdit.toHtml()).toString(); - content = StringEscapeUtils.unescapeHtml4(removeTags(content)); - QByteArray data = new QByteArray(sourceEditHeader+content+""); - getBrowser().setContent(data); - checkNoteTitle(); - if (currentNote != null && sourceEdit != null) - noteSignal.noteChanged.emit(currentNote.getGuid(), sourceEdit.toPlainText()); - } - - private void setSource() { - String text = getContent(); - sourceEdit.blockSignals(true); - int body = text.indexOf(" 0) { - body = text.indexOf(">",body); - if (body > 0) { - sourceEditHeader =text.substring(0, body+1); - text = text.substring(body+1); - } - } - text = text.replace("", ""); - sourceEdit.setPlainText(text); - sourceEdit.setReadOnly(!getBrowser().page().isContentEditable()); - //syntaxHighlighter.rehighlight(); - sourceEdit.blockSignals(false); - } - - // show/hide view source window - public void showSource(boolean value) { - setSource(); - sourceEdit.setVisible(value); - } - - // Remove HTML tags - private String removeTags(String text) { - StringBuffer buffer = new StringBuffer(text); - boolean inTag = false; - int bodyPosition = text.indexOf("=0; i--) { - if (buffer.charAt(i) == '>') - inTag = true; - if (buffer.charAt(i) == '<') - inTag = false; - if (inTag || buffer.charAt(i) == '<' || i allTags; + private List currentTags; + public NoteSignal noteSignal; + public Signal2 evernoteLinkClicked; + private List notebookList; + private Note currentNote; + private String saveNoteTitle; + private String saveTagList; + private boolean insideList; + private final DatabaseConnection conn; + private final QCalendarWidget createdCalendarWidget; + private final QCalendarWidget alteredCalendarWidget; + private final QCalendarWidget subjectCalendarWidget; + + public final QPushButton undoButton; + public final QAction undoAction; + public final QPushButton redoButton; + public final QAction redoAction; + public final QPushButton cutButton; + public final QAction cutAction; + public final QPushButton copyButton; + public final QAction copyAction; + public final QPushButton pasteButton; + public final QAction pasteAction; + public final QPushButton boldButton; + public final QAction boldAction; + public final QPushButton underlineButton; + public final QAction underlineAction; + public final QPushButton italicButton; + public final QAction italicAction; + public final Signal0 focusLost; + public final NoteResourceSignal resourceSignal; + + public QPushButton rightAlignButton; + public final QAction rightAlignAction; + public QPushButton leftAlignButton; + public final QAction leftAlignAction; + public QPushButton centerAlignButton; + public final QAction centerAlignAction; + + public final QPushButton strikethroughButton; + public final QAction strikethroughAction; + public final QPushButton hlineButton; + public final QAction hlineAction; + public final QPushButton indentButton; + public final QAction indentAction; + public final QPushButton outdentButton; + public final QAction outdentAction; + public final QPushButton bulletListButton; + public final QAction bulletListAction; + public final QPushButton numberListButton; + public final QAction numberListAction; + public final QPushButton spellCheckButton; + public final QAction spellCheckAction; + public final QPushButton todoButton; + public final QAction todoAction; + + public final QShortcut focusTitleShortcut; + public final QShortcut focusTagShortcut; + public final QShortcut focusNoteShortcut; + public final QShortcut focusUrlShortcut; + public final QShortcut focusAuthorShortcut; + + public EditorButtonBar buttonLayout; + public final QComboBox fontList; + public final QAction fontListAction; + public final QToolButton fontColor; + public final QAction fontColorAction; + private final ColorMenu fontColorMenu; + public final QToolButton fontHilight; + public final QAction fontHilightAction; + private final ColorMenu fontHilightColorMenu; + public final QFileSystemWatcher fileWatcher; + public int cursorPosition; + private boolean forceTextPaste; + private String selectedFile; + private String currentHyperlink; + public boolean keepPDFNavigationHidden; + private final ApplicationLogger logger; + SpellDictionary dictionary; + SpellDictionary userDictionary; + SpellChecker spellChecker; + SuggestionListener spellListener; + private final HashMap previewPageList; + boolean insertHyperlink; + boolean insideTable; + boolean insideEncryption; + public Signal1 blockApplication; + public Signal0 unblockApplication; + public boolean awaitingHttpResponse; + public long unblockTime; + private final QTimer setSourceTimer; + String latexGuid; // This is set if we are editing an existing LaTeX formula. Useful to track guid. + + // ICHANGED + private final ClipBoardObserver cbObserver; + + public static class SuggestionListener implements SpellCheckListener { + public boolean abortSpellCheck = false; + public boolean errorsFound = false; + private final SpellCheck spellCheckDialog; + + + private final BrowserWindow parent; + public SuggestionListener(BrowserWindow parent, SpellChecker checker) { + this.parent = parent; + spellCheckDialog = new SpellCheck(checker); + } + public void spellingError(SpellCheckEvent event) { + errorsFound = true; + spellCheckDialog.setWord(event.getInvalidWord()); + + @SuppressWarnings("unchecked") + List suggestions = event.getSuggestions(); + spellCheckDialog.clearSuggestions(); + if (!suggestions.isEmpty()) { +// spellCheckDialog.setCurrentSuggestion(suggestions.get(0).getWord()); + for (int i=0; i(); + titleLabel.setMaxLength(Constants.EDAM_NOTE_TITLE_LEN_MAX); + urlText = new QLineEdit(); + authorText = new QLineEdit(); + geoBox = new QComboBox(); + urlLabel = new QPushButton(); + urlLabel.clicked.connect(this, "sourceUrlClicked()"); + authorLabel = new QLabel(); + conn = c; + + // ICHANGED + this.cbObserver = cbObserver; + + focusLost = new Signal0(); + + tagEdit = new TagLineEdit(allTags); + tagLabel = new QLabel(tr("Tags:")); + tagEdit.focusLost.connect(this, "modifyTagsTyping()"); + + createdCalendarWidget = new QCalendarWidget(); + createdDate = new QDateEdit(); + createdDate.setDisplayFormat(Global.getDateFormat()); + createdDate.setCalendarPopup(true); + createdDate.setCalendarWidget(createdCalendarWidget); + createdTime = new QTimeEdit(); + createdDate.dateChanged.connect(this, "createdChanged()"); + createdTime.timeChanged.connect(this, "createdChanged()"); + + alteredCalendarWidget = new QCalendarWidget(); + alteredDate = new QDateEdit(); + alteredDate.setDisplayFormat(Global.getDateFormat()); + alteredDate.setCalendarPopup(true); + alteredDate.setCalendarWidget(alteredCalendarWidget); + alteredTime = new QTimeEdit(); + alteredLabel = new QLabel(tr("Altered:")); + alteredDate.dateChanged.connect(this, "alteredChanged()"); + alteredTime.timeChanged.connect(this, "alteredChanged()"); + + subjectCalendarWidget = new QCalendarWidget(); + subjectDate = new QDateEdit(); + subjectDate.setDisplayFormat(Global.getDateFormat()); + subjectDate.setCalendarPopup(true); + subjectDate.setCalendarWidget(subjectCalendarWidget); + subjectTime = new QTimeEdit(); + subjectLabel = new QLabel(tr("Subject Date:")); + subjectDate.dateChanged.connect(this, "subjectDateTimeChanged()"); + subjectTime.timeChanged.connect(this, "subjectDateTimeChanged()"); + authorText.textChanged.connect(this, "authorChanged()"); + urlText.textChanged.connect(this, "sourceUrlChanged()"); + + notebookBox = new QComboBox(); + notebookLabel = new QLabel(tr("Notebook")); + createdLabel = new QLabel(tr("Created:")); + // selectedText = new String(); + + urlLabel.setVisible(false); + urlText.setVisible(false); + authorLabel.setVisible(false); + + geoBox.setVisible(false); + geoBox.addItem(new QIcon(iconPath+"globe.png"), ""); + geoBox.addItem(new String(tr("Set"))); + geoBox.addItem(new String(tr("Clear"))); + geoBox.addItem(new String(tr("View On Map"))); + geoBox.activated.connect(this, "geoBoxChanged()"); + + authorText.setVisible(false); + createdDate.setVisible(false); + alteredLabel.setVisible(false); + //notebookBox.setVisible(false); + notebookLabel.setVisible(false); + createdLabel.setVisible(false); + createdTime.setVisible(false); + alteredDate.setVisible(false); + alteredTime.setVisible(false); + subjectLabel.setVisible(false); + subjectDate.setVisible(false); + subjectTime.setVisible(false); + extendedOn = false; + buttonsVisible = true; + setAcceptDrops(true); + + browser = new ContentView(this); + + browser.page().setLinkDelegationPolicy( + QWebPage.LinkDelegationPolicy.DelegateAllLinks); + browser.linkClicked.connect(this, "linkClicked(QUrl)"); + currentHyperlink = ""; + + //Setup the source editor + sourceEdit = new QTextEdit(this); + sourceEdit.setVisible(false); + sourceEdit.setTabChangesFocus(true); + sourceEdit.setLineWrapMode(LineWrapMode.NoWrap); + QFont font = new QFont(); + font.setFamily("Courier"); + font.setFixedPitch(true); + font.setPointSize(10); + sourceEdit.setFont(font); + syntaxHighlighter = new Highlighter(sourceEdit.document()); + sourceEdit.textChanged.connect(this, "sourceEdited()"); + + QVBoxLayout v = new QVBoxLayout(); + QFormLayout notebookLayout = new QFormLayout(); + QGridLayout dateLayout = new QGridLayout(); + titleLabel.setReadOnly(false); + titleLabel.editingFinished.connect(this, "titleEdited()"); + browser.page().contentsChanged.connect(this, "contentChanged()"); + browser.page().selectionChanged.connect(this, "selectionChanged()"); + browser.page().mainFrame().javaScriptWindowObjectCleared.connect(this, + "exposeToJavascript()"); + + notebookBox.activated.connect(this, "notebookChanged()"); + resourceSignal = new NoteResourceSignal(); + + QHBoxLayout tagLayout = new QHBoxLayout(); + v.addWidget(titleLabel, 0); + notebookLayout.addRow(notebookLabel, notebookBox); + tagLayout.addLayout(notebookLayout, 0); + tagLayout.stretch(4); + tagLayout.addWidget(tagLabel, 0); + tagLayout.addWidget(tagEdit, 1); + v.addLayout(tagLayout); + + QHBoxLayout urlLayout = new QHBoxLayout(); + urlLayout.addWidget(urlLabel, 0); + urlLayout.addWidget(urlText, 0); + v.addLayout(urlLayout); + + QHBoxLayout authorLayout = new QHBoxLayout(); + authorLayout.addWidget(authorLabel, 0); + authorLayout.addWidget(authorText, 0); + authorLayout.addWidget(geoBox); + v.addLayout(authorLayout); + + dateLayout.addWidget(createdLabel, 0, 0); + dateLayout.addWidget(createdDate, 0, 1); + dateLayout.addWidget(createdTime, 0, 2); + dateLayout.setColumnStretch(9, 100); + dateLayout.addWidget(alteredLabel, 0, 3); + dateLayout.addWidget(alteredDate, 0, 4); + dateLayout.addWidget(alteredTime, 0, 5); + dateLayout.addWidget(subjectLabel, 0, 6); + dateLayout.addWidget(subjectDate, 0, 7); + dateLayout.addWidget(subjectTime, 0, 8); + v.addLayout(dateLayout, 0); + + undoButton = newEditorButton("undo", tr("Undo Change")); + redoButton = newEditorButton("redo", tr("Redo Change")); + cutButton = newEditorButton("cut", tr("Cut")); + copyButton = newEditorButton("copy", tr("Copy")); + pasteButton = newEditorButton("paste", tr("Paste")); + boldButton = newEditorButton("bold", tr("Bold")); + underlineButton = newEditorButton("underline", tr("Underline")); + italicButton = newEditorButton("italic", tr("Italic")); + + rightAlignButton = newEditorButton("justifyRight", tr("Right Align")); + leftAlignButton = newEditorButton("justifyLeft", tr("Left Align")); + centerAlignButton = newEditorButton("justifyCenter", tr("Center Align")); + + strikethroughButton = newEditorButton("strikethrough", tr("Strikethrough")); + hlineButton = newEditorButton("hline", tr("Insert Horizontal Line")); + indentButton = newEditorButton("indent", tr("Shift Right")); + outdentButton = newEditorButton("outdent", tr("Shift Left")); + bulletListButton = newEditorButton("bulletList", tr("Bullet List")); + numberListButton = newEditorButton("numberList", tr("Number List")); + spellCheckButton = newEditorButton("spellCheck", tr("Spell Check")); + todoButton = newEditorButton("todo", tr("To-do")); + + + buttonLayout = new EditorButtonBar(); + v.addWidget(buttonLayout); + + undoAction = buttonLayout.addWidget(undoButton); + buttonLayout.toggleUndoVisible.triggered.connect(this, "toggleUndoVisible(Boolean)"); + redoAction = buttonLayout.addWidget(redoButton); + buttonLayout.toggleRedoVisible.triggered.connect(this, "toggleRedoVisible(Boolean)"); + + buttonLayout.addWidget(newSeparator()); + cutAction = buttonLayout.addWidget(cutButton); + buttonLayout.toggleCutVisible.triggered.connect(this, "toggleCutVisible(Boolean)"); + copyAction = buttonLayout.addWidget(copyButton); + buttonLayout.toggleCopyVisible.triggered.connect(this, "toggleCopyVisible(Boolean)"); + pasteAction = buttonLayout.addWidget(pasteButton); + buttonLayout.togglePasteVisible.triggered.connect(this, "togglePasteVisible(Boolean)"); + + buttonLayout.addWidget(newSeparator()); + boldAction = buttonLayout.addWidget(boldButton); + buttonLayout.toggleBoldVisible.triggered.connect(this, "toggleBoldVisible(Boolean)"); + italicAction = buttonLayout.addWidget(italicButton); + buttonLayout.toggleItalicVisible.triggered.connect(this, "toggleItalicVisible(Boolean)"); + underlineAction = buttonLayout.addWidget(underlineButton); + buttonLayout.toggleUnderlineVisible.triggered.connect(this, "toggleUnderlineVisible(Boolean)"); + strikethroughAction = buttonLayout.addWidget(strikethroughButton); + buttonLayout.toggleStrikethroughVisible.triggered.connect(this, "toggleStrikethroughVisible(Boolean)"); + + + buttonLayout.addWidget(newSeparator()); + leftAlignAction = buttonLayout.addWidget(leftAlignButton); + buttonLayout.toggleLeftAlignVisible.triggered.connect(this, "toggleLeftAlignVisible(Boolean)"); + centerAlignAction = buttonLayout.addWidget(centerAlignButton); + buttonLayout.toggleCenterAlignVisible.triggered.connect(this, "toggleCenterAlignVisible(Boolean)"); + rightAlignAction = buttonLayout.addWidget(rightAlignButton); + buttonLayout.toggleRightAlignVisible.triggered.connect(this, "toggleRightAlignVisible(Boolean)"); + + buttonLayout.addWidget(newSeparator()); + hlineAction = buttonLayout.addWidget(hlineButton); + buttonLayout.toggleHLineVisible.triggered.connect(this, "toggleHLineVisible(Boolean)"); + + indentAction = buttonLayout.addWidget(indentButton); + buttonLayout.toggleIndentVisible.triggered.connect(this, "toggleIndentVisible(Boolean)"); + outdentAction = buttonLayout.addWidget(outdentButton); + buttonLayout.toggleOutdentVisible.triggered.connect(this, "toggleOutdentVisible(Boolean)"); + bulletListAction = buttonLayout.addWidget(bulletListButton); + buttonLayout.toggleBulletListVisible.triggered.connect(this, "toggleBulletListVisible(Boolean)"); + numberListAction = buttonLayout.addWidget(numberListButton); + buttonLayout.toggleNumberListVisible.triggered.connect(this, "toggleNumberListVisible(Boolean)"); + + // Setup the font & font size combo boxes + buttonLayout.addWidget(newSeparator()); + fontList = new QComboBox(); + fontSize = new QComboBox(); + fontList.setToolTip("Font"); + fontSize.setToolTip("Font Size"); + fontList.activated.connect(this, "fontChanged(String)"); + fontSize.activated.connect(this, "fontSizeChanged(String)"); + fontListAction = buttonLayout.addWidget(fontList); + buttonLayout.toggleFontVisible.triggered.connect(this, "toggleFontListVisible(Boolean)"); + fontSizeAction = buttonLayout.addWidget(fontSize); + buttonLayout.toggleFontSizeVisible.triggered.connect(this, "toggleFontSizeVisible(Boolean)"); + QFontDatabase fonts = new QFontDatabase(); + List fontFamilies = fonts.families(); + for (int i = 0; i < fontFamilies.size(); i++) { + fontList.addItem(fontFamilies.get(i)); + if (i == 0) { + loadFontSize(fontFamilies.get(i)); + } + } + +// buttonLayout.addWidget(newSeparator(), 0); + fontColor = newToolButton("fontColor", tr("Font Color")); + fontColorMenu = new ColorMenu(this); + fontColor.setMenu(fontColorMenu.getMenu()); + fontColor.setPopupMode(ToolButtonPopupMode.MenuButtonPopup); + fontColor.setAutoRaise(false); + fontColorMenu.getMenu().triggered.connect(this, "fontColorClicked()"); + fontColorAction = buttonLayout.addWidget(fontColor); + buttonLayout.toggleFontColorVisible.triggered.connect(this, "toggleFontColorVisible(Boolean)"); + fontHilight = newToolButton("fontHilight", tr("Font Hilight Color")); + fontHilight.setPopupMode(ToolButtonPopupMode.MenuButtonPopup); + fontHilight.setAutoRaise(false); + fontHilightColorMenu = new ColorMenu(this); + fontHilightColorMenu.setDefault(QColor.yellow); + fontHilight.setMenu(fontHilightColorMenu.getMenu()); + fontHilightColorMenu.getMenu().triggered.connect(this, "fontHilightClicked()"); + fontHilightAction = buttonLayout.addWidget(fontHilight); + fontHilightColorMenu.setDefault(QColor.yellow); + buttonLayout.toggleFontHilight.triggered.connect(this, "toggleFontHilightVisible(Boolean)"); + + spellCheckAction = buttonLayout.addWidget(spellCheckButton); + buttonLayout.toggleNumberListVisible.triggered.connect(this, "spellCheckClicked()"); + buttonLayout.toggleSpellCheck.triggered.connect(this, "toggleSpellCheckVisible(Boolean)"); + + todoAction = buttonLayout.addWidget(todoButton); + buttonLayout.toggleNumberListVisible.triggered.connect(this, "todoClicked()"); + buttonLayout.toggleTodo.triggered.connect(this, "toggleTodoVisible(Boolean)"); + + // Setup the source browser); + +// buttonLayout.addWidget(new QLabel(), 1); + QSplitter editSplitter = new QSplitter(this); + editSplitter.addWidget(browser); + editSplitter.setOrientation(Qt.Orientation.Vertical); + editSplitter.addWidget(sourceEdit); + + + +// v.addWidget(browser, 1); +// v.addWidget(sourceEdit); + v.addWidget(editSplitter); + setLayout(v); + + browser.downloadAttachmentRequested.connect(this, + "downloadAttachment(QNetworkRequest)"); + browser.downloadImageRequested.connect(this, + "downloadImage(QNetworkRequest)"); + setTabOrder(notebookBox, tagEdit); + setTabOrder(tagEdit, browser); + + focusNoteShortcut = new QShortcut(this); + setupShortcut(focusNoteShortcut, "Focus_Note"); + focusNoteShortcut.activated.connect(this, "focusNote()"); + focusTitleShortcut = new QShortcut(this); + setupShortcut(focusTitleShortcut, "Focus_Title"); + focusTitleShortcut.activated.connect(this, "focusTitle()"); + focusTagShortcut = new QShortcut(this); + setupShortcut(focusTagShortcut, "Focus_Tag"); + focusTagShortcut.activated.connect(this, "focusTag()"); + focusAuthorShortcut = new QShortcut(this); + setupShortcut(focusAuthorShortcut, "Focus_Author"); + focusAuthorShortcut.activated.connect(this, "focusAuthor()"); + focusUrlShortcut = new QShortcut(this); + setupShortcut(focusUrlShortcut, "Focus_Url"); + focusUrlShortcut.activated.connect(this, "focusUrl()"); + + browser.page().mainFrame().setTextSizeMultiplier(Global.getTextSizeMultiplier()); + browser.page().mainFrame().setZoomFactor(Global.getZoomFactor()); + + previewPageList = new HashMap(); + + browser.page().microFocusChanged.connect(this, "microFocusChanged()"); + + //Setup colors + + QPalette pal = new QPalette(); + pal.setColor(ColorRole.Text, QColor.black); + titleLabel.setPalette(pal); + authorText.setPalette(pal); + authorLabel.setPalette(pal); + urlLabel.setPalette(pal); + urlText.setPalette(pal); + createdDate.setPalette(pal); + createdTime.setPalette(pal); + alteredDate.setPalette(pal); + alteredTime.setPalette(pal); + subjectDate.setPalette(pal); + subjectTime.setPalette(pal); + tagEdit.setPalette(pal); + notebookBox.setPalette(pal); + + blockApplication = new Signal1(); + unblockApplication = new Signal0(); + + setSourceTimer = new QTimer(); + setSourceTimer.timeout.connect(this, "setSource()"); + + logger.log(logger.HIGH, "Browser setup complete"); + } + + + + private void setupShortcut(QShortcut action, String text) { + if (!Global.shortcutKeys.containsAction(text)) + return; + action.setKey(new QKeySequence(Global.shortcutKeys.getShortcut(text))); + } + + + + + // Getter for the QWebView + public QWebView getBrowser() { + return browser; + } + + // Block signals while loading data or things are flagged as dirty by + // mistake + public void loadingData(boolean val) { + logger.log(logger.EXTREME, "Entering BrowserWindow.loadingData() " +val); + notebookBox.blockSignals(val); + browser.page().blockSignals(val); + browser.page().mainFrame().blockSignals(val); + titleLabel.blockSignals(val); + alteredDate.blockSignals(val); + alteredTime.blockSignals(val); + createdTime.blockSignals(val); + createdDate.blockSignals(val); + subjectDate.blockSignals(val); + subjectTime.blockSignals(val); + urlText.blockSignals(val); + authorText.blockSignals(val); + if (!val) + exposeToJavascript(); + logger.log(logger.EXTREME, "Exiting BrowserWindow.loadingData() " +val); + } + + // Enable/disable + public void setReadOnly(boolean v) { + setEnabled(true); + titleLabel.setEnabled(!v); + notebookBox.setEnabled(!v); + tagEdit.setEnabled(!v); + authorLabel.setEnabled(!v); + geoBox.setEnabled(!v); + urlText.setEnabled(!v); + createdDate.setEnabled(!v); + subjectDate.setEnabled(!v); + alteredDate.setEnabled(!v); + authorText.setEnabled(!v); + createdTime.setEnabled(!v); + alteredTime.setEnabled(!v); + subjectTime.setEnabled(!v); + getBrowser().setEnabled(true); + getBrowser().page().setContentEditable(!v); +// getBrowser().setEnabled(!v); + } + + // expose this class to Javascript on the web page + private void exposeToJavascript() { + browser.page().mainFrame().addToJavaScriptWindowObject("jambi", this); + } + + // Custom event queue + @Override + public boolean event(QEvent e) { + if (e.type().equals(QEvent.Type.FocusOut)) { + logger.log(logger.EXTREME, "Focus lost"); + focusLost.emit(); + } + return super.event(e); + } + + // clear out browser + public void clear() { + logger.log(logger.EXTREME, "Entering BrowserWindow.clear()"); + setNote(null); + setContent(new QByteArray()); + tagEdit.setText(""); + tagEdit.tagCompleter.reset(); + urlLabel.setText(tr("Source URL:")); + titleLabel.setText(""); + logger.log(logger.EXTREME, "Exiting BrowserWindow.clear()"); + } + + public void setContent(QByteArray data) { + sourceEdit.blockSignals(true); + browser.setContent(data); + setSource(); + } + // get/set current note + public void setNote(Note n) { + currentNote = n; + if (n == null) + n = new Note(); + saveNoteTitle = n.getTitle(); + + } + + public Note getNote() { + return currentNote; + } + + // New Editor Button + private QPushButton newEditorButton(String name, String toolTip) { + QPushButton button = new QPushButton(); +// QIcon icon = new QIcon(iconPath + name + ".gif"); + QIcon icon = new QIcon(iconPath + name + ".png"); + button.setIcon(icon); + // ICHANGED + button.setIconSize(new QSize(16, 16)); + + button.setToolTip(toolTip); + button.clicked.connect(this, name + "Clicked()"); + return button; + } + // New Editor Button + private QToolButton newToolButton(String name, String toolTip) { + QToolButton button = new QToolButton(); +// QIcon icon = new QIcon(iconPath + name + ".gif"); + QIcon icon = new QIcon(iconPath + name + ".png"); + button.setIcon(icon); + // ICHANGED + button.setIconSize(new QSize(16, 16)); + + button.setToolTip(toolTip); + button.clicked.connect(this, name + "Clicked()"); + return button; + } + + // New Separator + private QLabel newSeparator() { + return new QLabel(" "); + } + + // Set the title in the window + public void setTitle(String t) { + titleLabel.setText(t); + saveNoteTitle = t; + checkNoteTitle(); + } + + // Return the current text title + public String getTitle() { + return titleLabel.text(); + } + + // Set the tag name string + public void setTag(String t) { + saveTagList = t; + tagEdit.setText(t); + tagEdit.tagCompleter.reset(); + } + + // Set the source URL + public void setUrl(String t) { + urlLabel.setText(tr("Source URL:\t")); + urlText.setText(t); + } + + // The user want's to launch a web browser on the source of the URL + public void sourceUrlClicked() { + // Make sure we have a valid URL + if (urlText.text().trim().equals("")) + return; + + String url = urlText.text(); + if (!url.toLowerCase().startsWith(tr("http://"))) + url = tr("http://") +url; + + if (!QDesktopServices.openUrl(new QUrl(url))) { + logger.log(logger.LOW, "Error opening file :" +url); + } + } + + public void setAuthor(String t) { + authorLabel.setText(tr("Author:\t")); + authorText.setText(t); + } + + // Set the creation date + public void setCreation(long date) { + QDateTime dt = new QDateTime(); + dt.setTime_t((int) (date / 1000)); + createdDate.setDateTime(dt); + createdTime.setDateTime(dt); + createdDate.setDisplayFormat(Global.getDateFormat()); + createdTime.setDisplayFormat(Global.getTimeFormat()); + } + + // Set the creation date + public void setAltered(long date) { + QDateTime dt = new QDateTime(); + dt.setTime_t((int) (date / 1000)); + alteredDate.setDateTime(dt); + alteredTime.setDateTime(dt); + alteredDate.setDisplayFormat(Global.getDateFormat()); + alteredTime.setDisplayFormat(Global.getTimeFormat()); + } + + // Set the subject date + public void setSubjectDate(long date) { + QDateTime dt = new QDateTime(); + dt.setTime_t((int) (date / 1000)); + subjectDate.setDateTime(dt); + subjectTime.setDateTime(dt); + subjectDate.setDisplayFormat(Global.getDateFormat()); + subjectTime.setDisplayFormat(Global.getTimeFormat()); + } + + // Toggle the extended attribute information + public void toggleInformation() { + if (extendedOn) { + extendedOn = false; + } else { + extendedOn = true; + } + urlLabel.setVisible(extendedOn); + urlText.setVisible(extendedOn); + authorText.setVisible(extendedOn); + geoBox.setVisible(extendedOn); + authorLabel.setVisible(extendedOn); + createdDate.setVisible(extendedOn); + createdTime.setVisible(extendedOn); + createdLabel.setVisible(extendedOn); + alteredLabel.setVisible(extendedOn); + alteredDate.setVisible(extendedOn); + alteredTime.setVisible(extendedOn); + //notebookBox.setVisible(extendedOn); + notebookLabel.setVisible(extendedOn); + subjectLabel.setVisible(extendedOn); + subjectDate.setVisible(extendedOn); + subjectTime.setVisible(extendedOn); + } + + public void hideButtons() { + + undoButton.parentWidget().setVisible(false); + buttonsVisible = false; + } + + + // Is the extended view on? + public boolean isExtended() { + return extendedOn; + } + + // Listener for when a link is clicked + @SuppressWarnings("unused") + private void openFile() { + logger.log(logger.EXTREME, "Starting openFile()"); + File fileHandle = new File(selectedFile); + URI fileURL = fileHandle.toURI(); + String localURL = fileURL.toString(); + QUrl url = new QUrl(localURL); + QFile file = new QFile(selectedFile); + + logger.log(logger.EXTREME, "Adding to fileWatcher:"+file.fileName()); + fileWatcher.addPath(file.fileName()); + + if (!QDesktopServices.openUrl(url)) { + logger.log(logger.LOW, "Error opening file :" +url); + } + } + + + // Listener for when a link is clicked + @SuppressWarnings("unused") + private void linkClicked(QUrl url) { + logger.log(logger.EXTREME, "URL Clicked: " +url.toString()); + if (url.toString().startsWith("latex:")) { + int position = url.toString().lastIndexOf("."); + String guid = url.toString().substring(0,position); + position = guid.lastIndexOf("/"); + guid = guid.substring(position+1); + editLatex(guid); + return; + } + if (url.toString().startsWith("evernote:/view/")) { + StringTokenizer tokens = new StringTokenizer(url.toString().replace("evernote:/view/", ""), "/"); + tokens.nextToken(); + tokens.nextToken(); + String sid = tokens.nextToken(); + String lid = tokens.nextToken(); + + // Emit that we want to switch to a new note + evernoteLinkClicked.emit(sid, lid); + + return; + } + if (url.toString().startsWith("nnres://")) { + logger.log(logger.EXTREME, "URL is NN resource"); + if (url.toString().endsWith("/vnd.evernote.ink")) { + logger.log(logger.EXTREME, "Unable to open ink note"); + QMessageBox.information(this, tr("Unable Open"), tr("This is an ink note.\n"+ + "Ink notes are not supported since Evernote has not\n published any specifications on them\n" + + "and I'm too lazy to figure them out by myself.")); + return; + } + String fullName = url.toString().substring(8); + int index = fullName.indexOf("."); + String guid = ""; + String type = ""; + if (index >-1) { + type = fullName.substring(index+1); + guid = fullName.substring(0,index); + } + index = guid.indexOf(Global.attachmentNameDelimeter); + if (index > -1) { + guid = guid.substring(0,index); + } + List resList = currentNote.getResources(); + Resource res = null; + for (int i=0; i fileNames = dialog.selectedFiles(); //gets all selected filenames + if (fileNames.size() == 0) + return; + String sf = fileNames.get(0); + QFile saveFile = new QFile(sf); + mode.set(QFile.OpenModeFlag.WriteOnly); + saveFile.open(mode); + QDataStream saveOut = new QDataStream(saveFile); + saveOut.writeBytes(binData.toByteArray()); + saveFile.close(); + return; + } + } + } + return; + } + logger.log(logger.EXTREME, "Launching URL"); + QDesktopServices.openUrl(url); + } + + // Listener for when BOLD is clicked + @SuppressWarnings("unused") + private void undoClicked() { + browser.page().triggerAction(WebAction.Undo); + browser.setFocus(); + } + + // Listener for when BOLD is clicked + @SuppressWarnings("unused") + private void redoClicked() { + browser.page().triggerAction(WebAction.Redo); + browser.setFocus(); + } + + // Listener for when BOLD is clicked + @SuppressWarnings("unused") + private void boldClicked() { + browser.page().triggerAction(WebAction.ToggleBold); + microFocusChanged(); + browser.setFocus(); + } + + // Listener for when Italics is clicked + @SuppressWarnings("unused") + private void italicClicked() { + browser.page().triggerAction(WebAction.ToggleItalic); + microFocusChanged(); + browser.setFocus(); + } + + // Listener for when UNDERLINE is clicked + @SuppressWarnings("unused") + private void underlineClicked() { + browser.page().triggerAction(WebAction.ToggleUnderline); + microFocusChanged(); + browser.setFocus(); + } + + // Listener for when Strikethrough is clicked + @SuppressWarnings("unused") + private void strikethroughClicked() { + browser.page().mainFrame().evaluateJavaScript( + "document.execCommand('strikeThrough', false, '');"); + browser.setFocus(); + } + + // Listener for when cut is clicked + @SuppressWarnings("unused") + private void cutClicked() { + // ICHANGED + cbObserver.setCopySourceGuid(currentNote.getGuid(), browser.page().selectedText()); + + browser.page().triggerAction(WebAction.Cut); + browser.setFocus(); + } + + // Listener when COPY is clicked + @SuppressWarnings("unused") + private void copyClicked() { + // ICHANGED + cbObserver.setCopySourceGuid(currentNote.getGuid(), browser.page().selectedText()); + + browser.page().triggerAction(WebAction.Copy); + browser.setFocus(); + } + + // Listener when PASTE is clicked + public void pasteClicked() { + logger.log(logger.EXTREME, "Paste Clicked"); + if (forceTextPaste) { + pasteWithoutFormattingClicked(); + return; + } + + // ICHANGED コピー&ペーストの操作履歴をデータベースに登録 + String srcGuid = cbObserver.getSourceGuid(); + String dstGuid = currentNote.getGuid(); + if(srcGuid != null && dstGuid != null){ + if(!srcGuid.equals(dstGuid)){ + conn.getHistoryTable().addHistory("copy & paste", srcGuid, dstGuid); + } + } + + QClipboard clipboard = QApplication.clipboard(); + QMimeData mime = clipboard.mimeData(); + + if (mime.hasImage()) { + logger.log(logger.EXTREME, "Image paste found"); + browser.setFocus(); + insertImage(mime); + browser.setFocus(); + return; + } + + if (mime.hasUrls()) { + logger.log(logger.EXTREME, "URL paste found"); + if (mime.text().startsWith("evernote:")) { + handleNoteLink(mime); + } else { + handleUrls(mime); + browser.setFocus(); + } + return; + } + + String text = mime.html(); + if (text.contains("en-tag") && mime.hasHtml()) { + logger.log(logger.EXTREME, "Intra-note paste found"); + text = fixInternotePaste(text); + mime.setHtml(text); + clipboard.setMimeData(mime); + } + + logger.log(logger.EXTREME, "Final paste choice encountered"); + browser.page().triggerAction(WebAction.Paste); + browser.setFocus(); + + } + + // Paste text without formatting + private void pasteWithoutFormattingClicked() { + logger.log(logger.EXTREME, "Paste without format clipped"); + QClipboard clipboard = QApplication.clipboard(); + QMimeData mime = clipboard.mimeData(); + if (!mime.hasText()) + return; + + // ICHANGED コピー&ペーストの操作履歴をデータベースに登録 + String srcGuid = cbObserver.getSourceGuid(); + String dstGuid = currentNote.getGuid(); + if(srcGuid != null && dstGuid != null){ + if(!srcGuid.equals(dstGuid)){ + conn.getHistoryTable().addHistory("copy & paste", srcGuid, dstGuid); + } + } + + String text = mime.text(); + clipboard.clear(); + clipboard.setText(text, Mode.Clipboard); + browser.page().triggerAction(WebAction.Paste); + + // This is done because pasting into an encryption block + // can cause multiple cells (which can't happen). It + // just goes through the table, extracts the data, & + // puts it back as one table cell. + if (insideEncryption) { + String js = new String( "function fixEncryption() { " + +" var selObj = window.getSelection();" + +" var selRange = selObj.getRangeAt(0);" + +" var workingNode = window.getSelection().anchorNode;" + +" while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { " + +" workingNode = workingNode.parentNode;" + +" } " + +" workingNode.innerHTML = window.jambi.fixEncryptionPaste(workingNode.innerHTML);" + +"} fixEncryption();"); + browser.page().mainFrame().evaluateJavaScript(js); + } + } + + // This basically removes all the table tags and returns just the contents. + // This is called by JavaScript to fix encryption pastes. + public String fixEncryptionPaste(String data) { + data = data.replace("", ""); + data = data.replace("", ""); + data = data.replace("", ""); + data = data.replace("", ""); + data = data.replace("", ""); + data = data.replace("", "
"); + data = data.replace("

", "
"); + + return ""+data+""; + } + + // insert date/time + @SuppressWarnings("unused") + private void insertDateTime() { + String fmt = Global.getDateFormat() + " " + Global.getTimeFormat(); + String dateTimeFormat = new String(fmt); + SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat); + Calendar cal = Calendar.getInstance(); + + browser.page().mainFrame().evaluateJavaScript( + "document.execCommand('insertHtml', false, '"+simple.format(cal.getTime())+"');"); + + browser.setFocus(); + + } + + // Listener when Left is clicked + @SuppressWarnings("unused") + private void justifyLeftClicked() { + browser.page().mainFrame().evaluateJavaScript( + "document.execCommand('JustifyLeft', false, '');"); + browser.setFocus(); + } + + // Listener when Center is clicked + @SuppressWarnings("unused") + private void justifyCenterClicked() { + browser.page().mainFrame().evaluateJavaScript( + "document.execCommand('JustifyCenter', false, '');"); + browser.setFocus(); + } + + // Listener when Left is clicked + @SuppressWarnings("unused") + private void justifyRightClicked() { + browser.page().mainFrame().evaluateJavaScript( + "document.execCommand('JustifyRight', false, '');"); + browser.setFocus(); + } + + // Listener when HLINE is clicked + @SuppressWarnings("unused") + private void hlineClicked() { + browser.page().mainFrame().evaluateJavaScript( + "document.execCommand('insertHorizontalRule', false, '');"); + browser.setFocus(); + } + + // Listener when outdent is clicked + private void outdentClicked() { + browser.page().mainFrame().evaluateJavaScript( + "document.execCommand('outdent', false, '');"); + browser.setFocus(); + } + + // Listener when a bullet list is clicked + @SuppressWarnings("unused") + private void bulletListClicked() { + browser.page().mainFrame().evaluateJavaScript( + "document.execCommand('InsertUnorderedList', false, '');"); + browser.setFocus(); + } + + // Listener when a bullet list is clicked + @SuppressWarnings("unused") + private void numberListClicked() { + browser.page().mainFrame().evaluateJavaScript( + "document.execCommand('InsertOrderedList', false, '');"); + browser.setFocus(); + } + + // Listener when indent is clicked + private void indentClicked() { + browser.page().mainFrame().evaluateJavaScript( + "document.execCommand('indent', false, '');"); + browser.setFocus(); + } + + // Listener when the font name is changed + @SuppressWarnings("unused") + private void fontChanged(String font) { + browser.page().mainFrame().evaluateJavaScript( + "document.execCommand('fontName',false,'" + font + "');"); + browser.setFocus(); + } + + // Listener when a font size is changed + @SuppressWarnings("unused") + private void fontSizeChanged(String font) { + String text = browser.selectedText(); + if (text.trim().equalsIgnoreCase("")) + return; + + String selectedText = browser.selectedText(); + String url = ""+selectedText +""; + String script = "document.execCommand('insertHtml', false, '"+url+"');"; + browser.page().mainFrame().evaluateJavaScript(script); +/* browser.page().mainFrame().evaluateJavaScript( + "document.execCommand('fontSize',false,'" + + font + "');"); +*/ + browser.setFocus(); + } + + // Load the font combo box based upon the font selected + private void loadFontSize(String name) { + QFontDatabase db = new QFontDatabase(); + fontSize.clear(); + List points = db.pointSizes(name); + for (int i=0; i"); + browser.page().mainFrame().evaluateJavaScript( + script_start + todo + script_end); + browser.setFocus(); + } + + // Encrypt the selected text + @SuppressWarnings("unused") + private void encryptText() { + String text = browser.selectedText(); + if (text.trim().equalsIgnoreCase("")) + return; + text = new String(text.replaceAll("\n", "
")); + + EnCryptDialog dialog = new EnCryptDialog(); + dialog.exec(); + if (!dialog.okPressed()) { + return; + } + + EnCrypt crypt = new EnCrypt(); + String encrypted = crypt.encrypt(text, dialog.getPassword().trim(), 64); + String decrypted = crypt.decrypt(encrypted, dialog.getPassword().trim(), 64); + + if (encrypted.trim().equals("")) { + QMessageBox.information(this, tr("Error"), tr("Error Encrypting String")); + return; + } + StringBuffer buffer = new StringBuffer(encrypted.length() + 100); + buffer.append("\"");"); + + String script_start = new String( + "document.execCommand('insertHtml', false, '"); + String script_end = new String("');"); + browser.page().mainFrame().evaluateJavaScript( + script_start + buffer.toString() + script_end); + } + + + // Insert a Quick hyperlink + public void insertQuickLink() { + logger.log(logger.EXTREME, "Inserting link"); + String text = browser.selectedText(); + if (text.trim().equalsIgnoreCase("")) + return; + + // ICHANGED + NoteQuickLinkDialog dialog = new NoteQuickLinkDialog(logger, conn, text, cbObserver); + + if (dialog.getResults().size() == 0) { + QMessageBox.critical(null, tr("No Matches Found") ,tr("No matching notes found.")); + return; + } + if (dialog.getResults().size() > 1) { + dialog.exec(); + if (!dialog.okPressed) { + logger.log(logger.EXTREME, "Insert link canceled"); + return; + } + } + + User user = Global.getUserInformation(); + String dUrl = new String("evernote:///view/") + new String(user.getId() + "/" +user.getShardId() +"/" + +dialog.getSelectedNote()+"/"+dialog.getSelectedNote() +"/ " +"style=\"color:#69aa35\""); + + String url = ""+text +""; + String script = "document.execCommand('insertHtml', false, '"+url+"');"; + browser.page().mainFrame().evaluateJavaScript(script); + contentChanged(); + } + + // Insert a hyperlink + public void insertLink() { + logger.log(logger.EXTREME, "Inserting link"); + String text = browser.selectedText(); + if (text.trim().equalsIgnoreCase("")) + return; + + InsertLinkDialog dialog = new InsertLinkDialog(insertHyperlink); + if (currentHyperlink != null && currentHyperlink != "") { + dialog.setUrl(currentHyperlink); + } + dialog.exec(); + if (!dialog.okPressed()) { + logger.log(logger.EXTREME, "Insert link canceled"); + return; + } + + // Take care of inserting new links + if (insertHyperlink) { + String selectedText = browser.selectedText(); + if (dialog.getUrl().trim().equals("")) + return; + logger.log(logger.EXTREME, "Inserting link on text "+selectedText); + logger.log(logger.EXTREME, "URL Link " +dialog.getUrl().trim()); + String dUrl = StringUtils.replace(dialog.getUrl().trim(), "'", "\\'"); + String url = ""+selectedText +""; + String script = "document.execCommand('insertHtml', false, '"+url+"');"; + browser.page().mainFrame().evaluateJavaScript(script); + return; + } + + // Edit existing links + String js = new String( "function getCursorPos() {" + +"var cursorPos;" + +"if (window.getSelection) {" + +" var selObj = window.getSelection();" + +" var selRange = selObj.getRangeAt(0);" + +" var workingNode = window.getSelection().anchorNode.parentNode;" + +" while(workingNode != null) { " + +" if (workingNode.nodeName.toLowerCase()=='a') workingNode.setAttribute('href','" +dialog.getUrl() +"');" + +" workingNode = workingNode.parentNode;" + +" }" + +"}" + +"} getCursorPos();"); + browser.page().mainFrame().evaluateJavaScript(js); + + if (!dialog.getUrl().trim().equals("")) { + contentChanged(); + return; + } + + // Remove URL + js = new String( "function getCursorPos() {" + +"var cursorPos;" + +"if (window.getSelection) {" + +" var selObj = window.getSelection();" + +" var selRange = selObj.getRangeAt(0);" + +" var workingNode = window.getSelection().anchorNode.parentNode;" + +" while(workingNode != null) { " + +" if (workingNode.nodeName.toLowerCase()=='a') { " + +" workingNode.removeAttribute('href');" + +" workingNode.removeAttribute('title');" + +" var text = document.createTextNode(workingNode.innerText);" + +" workingNode.parentNode.insertBefore(text, workingNode);" + +" workingNode.parentNode.removeChild(workingNode);" + +" }" + +" workingNode = workingNode.parentNode;" + +" }" + +"}" + +"} getCursorPos();"); + browser.page().mainFrame().evaluateJavaScript(js); + + contentChanged(); + + + } + + + // Insert a hyperlink + public void insertLatex() { + editLatex(null); + } + public void editLatex(String guid) { + logger.log(logger.EXTREME, "Inserting latex"); + String text = browser.selectedText(); + if (text.trim().equalsIgnoreCase("\n") || text.trim().equalsIgnoreCase("")) { + InsertLatexImage dialog = new InsertLatexImage(); + if (guid != null) { + String formula = conn.getNoteTable().noteResourceTable.getNoteSourceUrl(guid).replace("http://latex.codecogs.com/gif.latex?", ""); + dialog.setFormula(formula); + } + dialog.exec(); + if (!dialog.okPressed()) { + logger.log(logger.EXTREME, "Edit LaTex canceled"); + return; + } + text = dialog.getFormula().trim(); + } + blockApplication.emit(this); + logger.log(logger.EXTREME, "Inserting LaTeX formula:" +text); + latexGuid = guid; + text = StringUtils.replace(text, "'", "\\'"); + String url = "http://latex.codecogs.com/gif.latex?" +text; + logger.log(logger.EXTREME, "Sending request to codecogs --> " + url); + QNetworkAccessManager manager = new QNetworkAccessManager(this); + manager.finished.connect(this, "insertLatexImageReady(QNetworkReply)"); + unblockTime = new GregorianCalendar().getTimeInMillis()+5000; + awaitingHttpResponse = true; + manager.get(new QNetworkRequest(new QUrl(url))); + } + + public void insertLatexImageReady(QNetworkReply reply) { + logger.log(logger.EXTREME, "Response received from CodeCogs"); + if (reply.error() != NetworkError.NoError) + return; + + unblockTime = -1; + if (!awaitingHttpResponse) + return; + + awaitingHttpResponse = false; + QUrl replyUrl = reply.url(); + QByteArray image = reply.readAll(); + reply.close(); + logger.log(logger.EXTREME, "New image size: " +image.size()); + + Resource newRes = null; + QFile tfile; + String path; + if (latexGuid == null) { + logger.log(logger.EXTREME, "Creating temporary gif"); + path = Global.getFileManager().getResDirPath("latex-temp.gif"); + tfile = new QFile(path); + tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly)); + logger.log(logger.EXTREME, "File Open: " +tfile.errorString()); + tfile.write(image); + logger.log(logger.EXTREME, "Bytes writtes: "+tfile.size()); + tfile.close(); + logger.log(logger.EXTREME, "Creating resource"); + int sequence = 0; + if (currentNote.getResources() != null || currentNote.getResources().size() > 0) + sequence = currentNote.getResources().size(); + newRes = createResource(path,sequence ,"image/gif", false); + QImage pix = new QImage(); + pix.loadFromData(image); + newRes.setHeight(new Integer(pix.height()).shortValue()); + newRes.setWidth(new Integer(pix.width()).shortValue()); + logger.log(logger.EXTREME, "Renaming temporary file to " +newRes.getGuid()+".gif"); + path = Global.getFileManager().getResDirPath(newRes.getGuid()+".gif"); + tfile.rename(path); + } else { + newRes = conn.getNoteTable().noteResourceTable.getNoteResource(latexGuid, false); + path = Global.getFileManager().getResDirPath(newRes.getGuid()+".gif"); + tfile = new QFile(path); + tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly)); + tfile.write(image); + tfile.close(); + newRes.getData().setBody(image.toByteArray()); + // Calculate the new hash value + MessageDigest md; + + logger.log(logger.EXTREME, "Generating MD5"); + try { + md = MessageDigest.getInstance("MD5"); + md.update(image.toByteArray()); + byte[] hash = md.digest(); + newRes.getData().setBodyHash(hash); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + QImage pix = new QImage(); + pix.loadFromData(image); + newRes.setHeight(new Integer(pix.height()).shortValue()); + newRes.setWidth(new Integer(pix.width()).shortValue()); + conn.getNoteTable().noteResourceTable.updateNoteResource(newRes, true); + } + + logger.log(logger.EXTREME, "Setting source: " +replyUrl.toString()); + newRes.getAttributes().setSourceURL(replyUrl.toString()); + conn.getNoteTable().noteResourceTable.updateNoteSourceUrl(newRes.getGuid(), replyUrl.toString(), true); + + for(int i=0; i"); + + String script_start = new String("document.execCommand('insertHTML', false, '"); + String script_end = new String("');"); + browser.page().mainFrame().evaluateJavaScript( + script_start + buffer + script_end); + } else { + HtmlTagModifier modifier = new HtmlTagModifier(getContent()); + modifier.modifyLatexTagHash(newRes); + String newContent = modifier.getHtml(); + setContent(new QByteArray(newContent)); + } + + logger.log(logger.EXTREME, "New HTML set\n" +browser.page().currentFrame().toHtml()); + QWebSettings.setMaximumPagesInCache(0); + QWebSettings.setObjectCacheCapacities(0, 0, 0); + + browser.page().mainFrame().setHtml(browser.page().mainFrame().toHtml()); + browser.reload(); + contentChanged(); +// resourceSignal.contentChanged.emit(path); + unblockTime = -1; + unblockApplication.emit(); + return; + + } + + + + // Insert a table + public void insertTable() { + TableDialog dialog = new TableDialog(); + dialog.exec(); + if (!dialog.okPressed()) { + return; + } + + int cols = dialog.getCols(); + int rows = dialog.getRows(); + int width = dialog.getWidth(); + boolean percent = dialog.isPercent(); + + String newHTML = ""; + + for (int i=0; i"; + for (int j=0; j "; + } + newHTML = newHTML +""; + } + newHTML = newHTML+"
"; + + String script = "document.execCommand('insertHtml', false, '"+newHTML+"');"; + browser.page().mainFrame().evaluateJavaScript(script); + } + + + // Text content changed + @SuppressWarnings("unused") + private void selectionChanged() { + browser.encryptAction.setEnabled(true); + browser.insertLinkAction.setEnabled(true); + browser.insertQuickLinkAction.setEnabled(true); + String scriptStart = "var selection_text = (window.getSelection()).toString();" + + "var range = (window.getSelection()).getRangeAt(0);" + + "var parent_html = range.commonAncestorContainer.innerHTML;" + + "if (parent_html == undefined) {window.jambi.saveSelectedText(selection_text); return;}" + + "var first_text = range.startContainer.nodeValue.substr(range.startOffset);" + + "var last_text = (range.endContainer.nodeValue).substring(0,range.endOffset);" + + "var start = parent_html.indexOf(first_text);" + + "var end = parent_html.indexOf(last_text,start+1)+last_text.length;" + + "var value = parent_html.substring(start,end);" + + "window.jambi.saveSelectedText(value);" ; + browser.page().mainFrame().evaluateJavaScript(scriptStart); + + } + + public void saveSelectedText(String text) { + boolean enabled = true; + if (text.trim().length() == 0) + enabled=false; + if (text.indexOf("en-tag=\"en-crypt\"") >= 0) + enabled=false; + if (text.indexOf("= 0) + enabled=false; + if (text.indexOf("= 0) + enabled=false; + if (text.indexOf("= 0) + enabled=false; + + browser.encryptAction.setEnabled(enabled); + browser.insertLinkAction.setEnabled(enabled); + browser.insertQuickLinkAction.setEnabled(enabled); +// selectedText = text; + } + + // Decrypt clicked text + public void decryptText(String id, String text, String hint) { + EnCrypt crypt = new EnCrypt(); + String plainText = null; + Calendar currentTime = new GregorianCalendar(); + Long l = new Long(currentTime.getTimeInMillis()); + String slot = new String(Long.toString(l)); + + // First, try to decrypt with any keys we already have + for (int i=0; i passwordPair = new Pair(); + passwordPair.setFirst(dialog.getPassword()); + passwordPair.setSecond(dialog.getHint()); + Global.passwordSafe.put(slot, passwordPair); +// removeEncryption(id, plainText.replaceAll("\n", "
"), dialog.permanentlyDecrypt(), slot); + removeEncryption(id, plainText, dialog.permanentlyDecrypt(), slot); + if (dialog.rememberPassword()) { + Pair pair = new Pair(); + pair.setFirst(dialog.getPassword()); + pair.setSecond(dialog.getHint()); + Global.passwordRemember.add(pair); + } + + } + + // Get the editor tag line + public TagLineEdit getTagLine() { + return tagEdit; + } + + // Modify a note's tags + @SuppressWarnings("unused") + private void modifyTags() { + TagAssign tagWindow = new TagAssign(allTags, currentTags, !conn.getNotebookTable().isLinked(currentNote.getNotebookGuid())); + tagWindow.exec(); + if (tagWindow.okClicked()) { + currentTags.clear(); + StringBuffer tagDisplay = new StringBuffer(); + + List newTags = tagWindow.getTagList() + .selectedItems(); + for (int i = 0; i < newTags.size(); i++) { + currentTags.add(newTags.get(i).text()); + tagDisplay.append(newTags.get(i).text()); + if (i < newTags.size() - 1) { + tagDisplay.append(Global.tagDelimeter + " "); + } + } + tagEdit.setText(tagDisplay.toString()); + noteSignal.tagsChanged.emit(currentNote.getGuid(), currentTags); + } + } + + // Tag line has been modified by typing text + @SuppressWarnings("unused") + private void modifyTagsTyping() { + String completionText = ""; + if (tagEdit.currentCompleterSelection != null && !tagEdit.currentCompleterSelection.equals("")) { + completionText = tagEdit.currentCompleterSelection; + tagEdit.currentCompleterSelection = ""; + } + + if (tagEdit.text().equalsIgnoreCase(saveTagList)) + return; + + // We know something has changed... + String oldTagArray[] = saveTagList.split(Global.tagDelimeter); + String newTagArray[]; + if (!completionText.equals("")) { + String before = tagEdit.text().substring(0,tagEdit.cursorPosition()); + int lastDelimiter = before.lastIndexOf(Global.tagDelimeter); + if (lastDelimiter > 0) + before = before.substring(0,before.lastIndexOf(Global.tagDelimeter)); + else + before = ""; + String after = tagEdit.text().substring(tagEdit.cursorPosition()); + newTagArray = (before+Global.tagDelimeter+completionText+Global.tagDelimeter+after).split(Global.tagDelimeter); + } + else { + newTagArray = tagEdit.text().split(Global.tagDelimeter); + } + + // Remove any traling or leading blanks + for (int i=0; i newTagList = new ArrayList(); + List oldTagList = new ArrayList(); + + for (int i = 0; i < oldTagArray.length; i++) + if (!oldTagArray[i].trim().equals("")) + oldTagList.add(oldTagArray[i]); + for (int i = 0; i < newTagArray.length; i++) + if (!newTagArray[i].trim().equals("")) + newTagList.add(newTagArray[i]); + + if (conn.getNotebookTable().isLinked(currentNote.getNotebookGuid())) { + for (int i=newTagList.size()-1; i>=0; i--) { + boolean found = false; + for (int j=0; j= 0; i--) { + String nTag = newTagList.get(i); + for (int j = oldTagList.size() - 1; j >= 0; j--) { + String oTag = oldTagList.get(j); + if (oTag.equalsIgnoreCase(nTag)) { + oldTagList.remove(j); + newTagList.remove(i); + j = -1; + } + } + } + + if (oldTagList.size() != 0 || newTagList.size() != 0) { + currentTags.clear(); + newTagArray = tagEdit.text().split(Global.tagDelimeter); + for (int i = 0; i < newTagArray.length; i++) + if (!newTagArray[i].trim().equals("")) + currentTags.add(newTagArray[i].trim()); + + noteSignal.tagsChanged.emit(currentNote.getGuid(), currentTags); + } + + } + + // Tab button was pressed + public void tabPressed() { + if (insideEncryption) + return; + if (!insideList && !insideTable) { + String script_start = new String( + "document.execCommand('insertHtml', false, '     ');"); + browser.page().mainFrame().evaluateJavaScript(script_start); + return; + } + if (insideList) { + indentClicked(); + } + if (insideTable) { + String js = new String( "function getCursorPosition() { " + +" var selObj = window.getSelection();" + +" var selRange = selObj.getRangeAt(0);" + +" var workingNode = window.getSelection().anchorNode;" + +" var rowCount = 0;" + +" var colCount = 0;" + +" while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { " + +" if (workingNode.nodeName.toLowerCase()=='tr') {" + +" rowCount = rowCount+1;" + +" }" + +" if (workingNode.nodeName.toLowerCase() == 'td') {" + +" colCount = colCount+1;" + +" }" + +" if (workingNode.previousSibling != null)" + +" workingNode = workingNode.previousSibling;" + +" else " + +" workingNode = workingNode.parentNode;" + +" }" + +" var nodes = workingNode.getElementsByTagName('tr');" + +" var tableRows = nodes.length;" + +" nodes = nodes[0].getElementsByTagName('td');" + +" var tableColumns = nodes.length;" + +" window.jambi.setTableCursorPositionTab(rowCount, colCount, tableRows, tableColumns);" + +"} getCursorPosition();"); + browser.page().mainFrame().evaluateJavaScript(js); + } + } + + // If a user presses tab from within a table + public void setTableCursorPositionTab(int currentRow, int currentCol, int tableRows, int tableColumns) { + if (tableRows == currentRow && currentCol == tableColumns) { + insertTableRow(); + } + KeyboardModifiers modifiers = new KeyboardModifiers(KeyboardModifier.NoModifier); + QKeyEvent right = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Right.value(), modifiers); + QKeyEvent end = new QKeyEvent(Type.KeyPress, Qt.Key.Key_End.value(), modifiers); + QKeyEvent end2 = new QKeyEvent(Type.KeyPress, Qt.Key.Key_End.value(), modifiers); + getBrowser().focusWidget(); + QCoreApplication.postEvent(getBrowser(), end); + QCoreApplication.postEvent(getBrowser(), right); + QCoreApplication.postEvent(getBrowser(), end2); + } + + public void backtabPressed() { + if (insideEncryption) + return; + if (insideList) + outdentClicked(); + if (insideTable) { + String js = new String( "function getCursorPosition() { " + +" var selObj = window.getSelection();" + +" var selRange = selObj.getRangeAt(0);" + +" var workingNode = window.getSelection().anchorNode;" + +" var rowCount = 0;" + +" var colCount = 0;" + +" while(workingNode != null && workingNode.nodeName.toLowerCase() != 'table') { " + +" if (workingNode.nodeName.toLowerCase()=='tr') {" + +" rowCount = rowCount+1;" + +" }" + +" if (workingNode.nodeName.toLowerCase() == 'td') {" + +" colCount = colCount+1;" + +" }" + +" if (workingNode.previousSibling != null)" + +" workingNode = workingNode.previousSibling;" + +" else " + +" workingNode = workingNode.parentNode;" + +" }" + +" var nodes = workingNode.getElementsByTagName('tr');" + +" var tableRows = nodes.length;" + +" nodes = nodes[0].getElementsByTagName('td');" + +" var tableColumns = nodes.length;" + +" window.jambi.setTableCursorPositionBackTab(rowCount, colCount, tableRows, tableColumns);" + +"} getCursorPosition();"); + browser.page().mainFrame().evaluateJavaScript(js); + + } + } + + // If a user presses backtab from within a table + public void setTableCursorPositionBackTab(int currentRow, int currentCol, int tableRows, int tableColumns) { + if (currentRow == 1 && currentCol == 1) { + return; + } + KeyboardModifiers modifiers = new KeyboardModifiers(KeyboardModifier.NoModifier); + QKeyEvent left = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Left.value(), modifiers); + QKeyEvent home = new QKeyEvent(Type.KeyPress, Qt.Key.Key_Home.value(), modifiers); + getBrowser().focusWidget(); + QCoreApplication.postEvent(getBrowser(), home); + QCoreApplication.postEvent(getBrowser(), left); + } + + + public void setInsideList() { + insideList = true; + } + + // The title has been edited + @SuppressWarnings("unused") + private void titleEdited() { + // If we don't have a good note, or if the current title + // matches the old title then we don't need to do anything + if (currentNote == null) + return; + if (currentNote.getTitle().trim().equals(titleLabel.text().trim())) + return; + + // If we have a real change, we need to save it. + String text = titleLabel.text().trim(); + if (text.equals("")) + text = tr("Untitled Note"); + noteSignal.titleChanged.emit(currentNote.getGuid(), text); + currentNote.setTitle(text); + saveNoteTitle = text; + checkNoteTitle(); + } + + // Set the list of note tags + public void setAllTags(List l) { + allTags = l; + tagEdit.setTagList(l); + } + + // Setter for the current tags + public void setCurrentTags(List s) { + currentTags = s; + } + + // Save the list of notebooks + public void setNotebookList(List n) { + notebookList = n; + loadNotebookList(); + } + + // Load the notebook list and select the current notebook + private void loadNotebookList() { + if (notebookBox.count() != 0) + notebookBox.clear(); + if (notebookList == null) + return; + + for (int i = 0; i < notebookList.size(); i++) { + notebookBox.addItem(notebookList.get(i).getName()); + if (currentNote != null) { + if (currentNote.getNotebookGuid().equals( + notebookList.get(i).getGuid())) { + notebookBox.setCurrentIndex(i); + } + } + } + } + + + // Set the notebook for a note + public void setNotebook(String notebook) { + currentNote.setNotebookGuid(notebook); + loadNotebookList(); + } + + // Get the contents of the editor + public String getContent() { + return browser.page().currentFrame().toHtml(); + } + + // The note contents have changed + public void contentChanged() { + String content = getContent(); + + // This puts in a 1/2 second delay + // before updating the source editor. + // It improves response when someone is doing + // frequent updates on a large note. + // If the source editor isn't visible, then there + // is no point to doing any of this. + if (sourceEdit.isVisible()) { + setSourceTimer.stop(); + setSourceTimer.setInterval(500); + setSourceTimer.setSingleShot(true); + setSourceTimer.start(); + } + + checkNoteTitle(); + noteSignal.noteChanged.emit(currentNote.getGuid(), content); + } + + // The notebook selection has changed + @SuppressWarnings("unused") + private void notebookChanged() { + boolean changed = false; + String n = notebookBox.currentText(); + for (int i = 0; i < notebookList.size(); i++) { + if (n.equals(notebookList.get(i).getName())) { + if (!notebookList.get(i).getGuid().equals(currentNote.getNotebookGuid())) { + String guid = conn.getNotebookTable().findNotebookByName(n); + if (conn.getNotebookTable().isLinked(guid)) { + tagEdit.setText(""); + noteSignal.tagsChanged.emit(currentNote.getGuid(), new ArrayList()); + FilterEditorTags t = new FilterEditorTags(conn, logger); + setAllTags(t.getValidTags(currentNote)); + } + currentNote.setNotebookGuid(notebookList.get(i).getGuid()); + changed = true; + } + i = notebookList.size(); + } + } + + // If the notebook changed, signal the update + if (changed) + noteSignal.notebookChanged.emit(currentNote.getGuid(), currentNote + .getNotebookGuid()); + } + + // Check the note title + private void checkNoteTitle() { + String text = browser.page().currentFrame().toPlainText(); + if (saveNoteTitle == null) + saveNoteTitle = new String(); + text = text.trim(); + if (!saveNoteTitle.trim().equals("") && !saveNoteTitle.trim().equals("Untitled Note")) + text = saveNoteTitle.trim(); + int newLine = text.indexOf("\n"); + if (newLine > 0) + text = text.substring(0,newLine); + if (saveNoteTitle.trim().equals("") || saveNoteTitle.trim().equals("Untitled Note")) { + if (text.trim().equals("")) + text = tr("Untitled Note"); + titleLabel.setText(text); + } else { + if (text.length() > Constants.EDAM_NOTE_TITLE_LEN_MAX) + titleLabel.setText(text.substring(0, Constants.EDAM_NOTE_TITLE_LEN_MAX)); + else { + titleLabel.blockSignals(true); + if (text.trim().equals("")) + titleLabel.setText(tr("Untitled Note")); + else + titleLabel.setText(text); + titleLabel.blockSignals(false); + } + } + if (currentNote != null && titleLabel != null && !currentNote.getTitle().equals(text)) + noteSignal.titleChanged.emit(currentNote.getGuid(), text); + } + + // Return the note contents so we can email them + public String getContentsToEmail() { + return browser.page().currentFrame().toPlainText().trim(); + /* + * int body = browser.page().currentFrame().toHtml().indexOf(""); + * String temp = browser.page().currentFrame().toHtml(); if (body == -1) + * temp = "Test"; else temp = + * ""+temp.substring(body); return temp; // return + * urlEncode(browser.page().currentFrame().toHtml()); + */ + } + + // Insert an image into the editor + private void insertImage(QMimeData mime) { + logger.log(logger.EXTREME, "Entering insertImage"); + QImage img = (QImage) mime.imageData(); + String script_start = new String( + "document.execCommand('insertHTML', false, '"); + String script_end = new String("');"); + + long now = new Date().getTime(); + String path = Global.getFileManager().getResDirPath( + (new Long(now).toString()) + ".jpg"); + + // This block is just a hack to make sure we wait at least 1ms so we + // don't + // have collisions on image names + long i = new Date().getTime(); + while (now == i) + i = new Date().getTime(); + + // Open the file & write the data + QFile tfile = new QFile(path); + tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly)); + if (!img.save(tfile)) { + tfile.close(); + return; + } + tfile.close(); + + Resource newRes = createResource(QUrl.fromLocalFile(path).toString(), 0, "image/jpeg", false); + if (newRes == null) + return; + currentNote.getResources().add(newRes); + + // do the actual insert into the note + StringBuffer buffer = new StringBuffer(100); + buffer.append(""); + + browser.page().mainFrame().evaluateJavaScript( + script_start + buffer + script_end); + + return; + } + + // Handle pasting of a note-to-note link + private void handleNoteLink(QMimeData mime) { + for (int i=0; i"); + url.append(note.getTitle()); + url.append("
"); + if (mime.urls().size() > 1) + url.append(" "); + browser.page().mainFrame().evaluateJavaScript( + script_start + url + script_end); + } + } + } + + // Handle URLs that are trying to be pasted + public void handleUrls(QMimeData mime) { + logger.log(logger.EXTREME, "Starting handleUrls"); + FileNameMap fileNameMap = URLConnection.getFileNameMap(); + + List urlList = mime.urls(); + String url = new String(); + String script_start = new String( + "document.execCommand('createLink', false, '"); + String script_end = new String("');"); + + for (int i = 0; i < urlList.size(); i++) { + url = urlList.get(i).toString(); + // Find out what type of file we have + String mimeType = fileNameMap.getContentTypeFor(url); + + // If null returned, we need to guess at the file type + if (mimeType == null) + mimeType = "application/" + + url.substring(url.lastIndexOf(".") + 1); + + // Check if we have an image or some other type of file + if (url.substring(0, 5).equalsIgnoreCase("file:") + && mimeType.substring(0, 5).equalsIgnoreCase("image")) { + handleLocalImageURLPaste(mime, mimeType); + return; + } + + boolean smallEnough = checkFileAttachmentSize(url); + if (smallEnough + && url.substring(0, 5).equalsIgnoreCase("file:") + && !mimeType.substring(0, 5).equalsIgnoreCase("image")) { + handleLocalAttachment(mime, mimeType); + return; + } + browser.page().mainFrame().evaluateJavaScript( + script_start + url + script_end); + } + return; + } + + // If a URL being pasted is an image URL, then attach the image + private void handleLocalImageURLPaste(QMimeData mime, String mimeType) { + List urlList = mime.urls(); + String url = new String(); + String script_start_image = new String( + "document.execCommand('insertHtml', false, '"); + String script_end = new String("');"); + StringBuffer buffer; + + // Copy the image over into the resource directory and create a new resource + // record for each url pasted + for (int i = 0; i < urlList.size(); i++) { + url = urlList.get(i).toString(); + + Resource newRes = createResource(url, i, mimeType, false); + if (newRes == null) + return; + currentNote.getResources().add(newRes); + buffer = new StringBuffer(100); + + // Open the file & write the data + String fileName = Global.getFileManager().getResDirPath(newRes.getGuid()); + QFile tfile = new QFile(fileName); + tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly)); + tfile.write(newRes.getData().getBody()); + tfile.close(); + buffer.append(script_start_image); + buffer.append(""); + buffer.append(script_end); + browser.page().mainFrame().evaluateJavaScript(buffer.toString()); + } + return; + } + + + // If a URL being pasted is a local file URL, then attach the file + private void handleLocalAttachment(QMimeData mime, String mimeType) { + logger.log(logger.EXTREME, "Attaching local file"); + List urlList = mime.urls(); + String script_start = new String( + "document.execCommand('insertHtml', false, '"); + String script_end = new String("');"); + StringBuffer buffer; + + String[] type = mimeType.split("/"); + String icon = findIcon(type[1]); + if (icon.equals("attachment.png")) + icon = findIcon(type[0]); + buffer = new StringBuffer(100); + + for (int i = 0; i < urlList.size(); i++) { + String url = urlList.get(i).toString(); + + // Start building the HTML + if (icon.equals("attachment.png")) + icon = findIcon(url.substring(url.lastIndexOf(".")+1)); + String imageURL = FileUtils.toFileURLString(Global.getFileManager().getImageDirFile(icon)); + + logger.log(logger.EXTREME, "Creating resource "); + Resource newRes = createResource(url, i, mimeType, true); + if (newRes == null) + return; + logger.log(logger.EXTREME, "New resource size: " +newRes.getData().getSize()); + currentNote.getResources().add(newRes); + + String fileName = newRes.getGuid() + Global.attachmentNameDelimeter+newRes.getAttributes().getFileName(); + // If we have a PDF, we need to setup the preview. + if (icon.equalsIgnoreCase("pdf.png") && Global.pdfPreview()) { + logger.log(logger.EXTREME, "Setting up PDF preview"); + if (newRes.getAttributes() != null && + newRes.getAttributes().getFileName() != null && + !newRes.getAttributes().getFileName().trim().equals("")) + fileName = newRes.getGuid()+Global.attachmentNameDelimeter+ + newRes.getAttributes().getFileName(); + else + fileName = newRes.getGuid()+".pdf"; + QFile file = new QFile(Global.getFileManager().getResDirPath(fileName)); + QFile.OpenMode mode = new QFile.OpenMode(); + mode.set(QFile.OpenModeFlag.WriteOnly); + file.open(mode); + QDataStream out = new QDataStream(file); +// Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(newRes.getGuid(), true); + QByteArray binData = new QByteArray(newRes.getData().getBody()); +// resBinary = null; + out.writeBytes(binData.toByteArray()); + file.close(); + + PDFPreview pdfPreview = new PDFPreview(); + if (pdfPreview.setupPreview(Global.getFileManager().getResDirPath(fileName), "pdf",0)) { + imageURL = file.fileName() + ".png"; + } + } + + logger.log(logger.EXTREME, "Generating link tags"); + buffer.delete(0, buffer.length()); + buffer.append(""); + buffer.append(""); + buffer.append(""); + browser.page().mainFrame().evaluateJavaScript( + script_start + buffer.toString() + script_end); + } + return; + } + + private Resource createResource(String url, int sequence, String mime, boolean attachment) { + logger.log(logger.EXTREME, "Inside create resource"); + QFile resourceFile; + //These two lines are added to handle odd characters in the name like #. Without it + // toLocalFile() chokes and returns the wrong name. + logger.log(logger.EXTREME, "File URL:" +url); + String whichOS = System.getProperty("os.name"); + if (whichOS.contains("Windows")) + url = url.replace("file:///", ""); + else + url = url.replace("file://", ""); + String urlTest = new QUrl(url).toLocalFile(); + logger.log(logger.EXTREME, "File URL toLocalFile():" +urlTest); + urlTest = url; + if (!urlTest.equals("")) + url = urlTest; +// url = url.replace("/", File.separator); + logger.log(logger.EXTREME, "Reading from file to create resource:" +url); + resourceFile = new QFile(url); + resourceFile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly)); + logger.log(logger.EXTREME, "Error opening file "+url.toString() +": "+resourceFile.errorString()); + byte[] fileData = resourceFile.readAll().toByteArray(); + resourceFile.close(); + logger.log(logger.EXTREME, "File Length: " +fileData.length); + if (fileData.length == 0) + return null; + MessageDigest md; + try { + logger.log(logger.EXTREME, "Generating MD5"); + md = MessageDigest.getInstance("MD5"); + md.update(fileData); + byte[] hash = md.digest(); + + Resource r = new Resource(); + Calendar time = new GregorianCalendar(); + long prevTime = time.getTimeInMillis(); + while (prevTime == time.getTimeInMillis()) { + time = new GregorianCalendar(); + } + r.setGuid(time.getTimeInMillis()+new Integer(sequence).toString()); + r.setNoteGuid(currentNote.getGuid()); + r.setMime(mime); + r.setActive(true); + r.setUpdateSequenceNum(0); + r.setWidth((short) 0); + r.setHeight((short) 0); + r.setDuration((short) 0); + + Data d = new Data(); + d.setBody(fileData); + d.setBodyIsSet(true); + d.setBodyHash(hash); + d.setBodyHashIsSet(true); + r.setData(d); + d.setSize(fileData.length); + + int fileNamePos = url.lastIndexOf(File.separator); + if (fileNamePos == -1) + fileNamePos = url.lastIndexOf("/"); + String fileName = url.substring(fileNamePos+1); + ResourceAttributes a = new ResourceAttributes(); + a.setAltitude(0); + a.setAltitudeIsSet(false); + a.setLongitude(0); + a.setLongitudeIsSet(false); + a.setLatitude(0); + a.setLatitudeIsSet(false); + a.setCameraMake(""); + a.setCameraMakeIsSet(false); + a.setCameraModel(""); + a.setCameraModelIsSet(false); + a.setAttachment(attachment); + a.setAttachmentIsSet(true); + a.setClientWillIndex(false); + a.setClientWillIndexIsSet(true); + a.setRecoType(""); + a.setRecoTypeIsSet(false); + a.setSourceURL(url); + a.setSourceURLIsSet(true); + a.setTimestamp(0); + a.setTimestampIsSet(false); + a.setFileName(fileName); + a.setFileNameIsSet(true); + r.setAttributes(a); + + conn.getNoteTable().noteResourceTable.saveNoteResource(r, true); + logger.log(logger.EXTREME, "Resource created"); + return r; + } catch (NoSuchAlgorithmException e1) { + e1.printStackTrace(); + } + return null; + } + + + // find the appropriate icon for an attachment + private String findIcon(String appl) { + appl = appl.toLowerCase(); + File f = Global.getFileManager().getImageDirFile(appl + ".png"); + if (f.exists()) + return appl+".png"; + return "attachment.png"; + } + + + + // Check the file attachment to be sure it isn't over 25 mb + private boolean checkFileAttachmentSize(String url) { + String fileName = url.substring(8); + QFile resourceFile = new QFile(fileName); + resourceFile.open(new QIODevice.OpenMode( + QIODevice.OpenModeFlag.ReadOnly)); + long size = resourceFile.size(); + resourceFile.close(); + size = size / 1024 / 1024; + if (size < 50 && Global.isPremium()) + return true; + if (size < 25) + return true; + + String error = tr("A file attachment may not exceed 25MB."); + QMessageBox.information(this, tr("Attachment Size"), error); + return false; + } + + + @SuppressWarnings("unused") + private void createdChanged() { + QDateTime dt = new QDateTime(); + dt.setDate(createdDate.date()); + dt.setTime(createdTime.time()); + noteSignal.createdDateChanged.emit(currentNote.getGuid(), dt); + + } + + @SuppressWarnings("unused") + private void alteredChanged() { + QDateTime dt = new QDateTime(); + dt.setDate(alteredDate.date()); + dt.setTime(alteredTime.time()); + noteSignal.alteredDateChanged.emit(currentNote.getGuid(), dt); + } + + @SuppressWarnings("unused") + private void subjectDateTimeChanged() { + QDateTime dt = new QDateTime(); + dt.setDate(subjectDate.date()); + dt.setTime(subjectTime.time()); + noteSignal.subjectDateChanged.emit(currentNote.getGuid(), dt); + + } + + @SuppressWarnings("unused") + private void sourceUrlChanged() { + noteSignal.sourceUrlChanged.emit(currentNote.getGuid(), urlText.text()); + } + + @SuppressWarnings("unused") + private void authorChanged() { + noteSignal.authorChanged.emit(currentNote.getGuid(), authorText.text()); + } + + @SuppressWarnings("unused") + private void geoBoxChanged() { + int index = geoBox.currentIndex(); + geoBox.setCurrentIndex(0); + if (index == 1) { + GeoDialog box = new GeoDialog(); + box.setLongitude(currentNote.getAttributes().getLongitude()); + box.setLatitude(currentNote.getAttributes().getLatitude()); + box.setAltitude(currentNote.getAttributes().getAltitude()); + box.exec(); + if (!box.okPressed()) + return; + double alt = box.getAltitude(); + double lat = box.getLatitude(); + double lon = box.getLongitude(); + if (alt != currentNote.getAttributes().getAltitude() || + lon != currentNote.getAttributes().getLongitude() || + lat != currentNote.getAttributes().getLatitude()) { + noteSignal.geoChanged.emit(currentNote.getGuid(), lon, lat, alt); + currentNote.getAttributes().setAltitude(alt); + currentNote.getAttributes().setLongitude(lon); + currentNote.getAttributes().setLatitude(lat); + } + } + + if (index == 2) { + noteSignal.geoChanged.emit(currentNote.getGuid(), 0.0, 0.0, 0.0); + currentNote.getAttributes().setAltitude(0.0); + currentNote.getAttributes().setLongitude(0.0); + currentNote.getAttributes().setLatitude(0.0); + } + + if (index == 3 || index == 0) { + QDesktopServices.openUrl(new QUrl("http://maps.google.com/maps?z=6&q="+currentNote.getAttributes().getLatitude() +"," +currentNote.getAttributes().getLongitude())); + } + } + + // ************************************************************ + // * User chose to save an attachment. Pares out the request * + // * into a guid & file. Save the result. * + // ************************************************************ + public void downloadAttachment(QNetworkRequest request) { + String guid; + QFileDialog fd = new QFileDialog(this); + fd.setFileMode(FileMode.AnyFile); + fd.setConfirmOverwrite(true); + fd.setWindowTitle(tr("Save File")); + fd.setAcceptMode(AcceptMode.AcceptSave); + fd.setDirectory(System.getProperty("user.home")); + String name = request.url().toString(); + + int pos = name.lastIndexOf(Global.attachmentNameDelimeter); + if (pos > -1) { + guid = name.substring(0, pos).replace("nnres://", ""); + name = name.substring(pos +Global.attachmentNameDelimeter.length()); + fd.selectFile(name); + pos = name.lastIndexOf('.'); + if (pos > -1) { + String mimeType = "(*." + name.substring(pos + 1) + + ");; All Files (*)"; + fd.setFilter(tr(mimeType)); + } + } else { + guid = name; + } + + // Strip URL prefix and base dir + guid = guid.replace("nnres://", "") + .replace(FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath()), ""); + guid = guid.replace("file://", "").replace("/", "") + .replace(FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath()), ""); + + pos = guid.lastIndexOf('.'); + if (pos > 0) + guid = guid.substring(0,pos); + if (fd.exec() != 0 && fd.selectedFiles().size() > 0) { + name = name.replace('\\', '/'); + Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true); + QFile saveFile = new QFile(fd.selectedFiles().get(0)); + QFile.OpenMode mode = new QFile.OpenMode(); + mode.set(QFile.OpenModeFlag.WriteOnly); + saveFile.open(mode); + QDataStream saveOut = new QDataStream(saveFile); + QByteArray binData = new QByteArray(resBinary.getData().getBody()); + saveOut.writeBytes(binData.toByteArray()); + saveFile.close(); + + } + } + + + // ************************************************************ + // * User chose to save an attachment. Pares out the request * + // * into a guid & file. Save the result. --- DONE FROM downloadAttachment now!!!!! + // ************************************************************ + public void downloadImage(QNetworkRequest request) { + QFileDialog fd = new QFileDialog(this); + fd.setFileMode(FileMode.AnyFile); + fd.setConfirmOverwrite(true); + fd.setWindowTitle(tr("Save File")); + fd.setAcceptMode(AcceptMode.AcceptSave); + fd.setDirectory(System.getProperty("user.home")); + String name = request.url().toString(); + name = name.replace("nnres://", ""); + String dPath = FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath()); + name = name.replace(dPath, ""); + int pos = name.lastIndexOf('.'); + String guid = name; + if (pos > -1) { + String mimeType = "(*." + name.substring(pos + 1) + + ");; All Files (*)"; + fd.setFilter(tr(mimeType)); + guid = guid.substring(0,pos); + } + pos = name.lastIndexOf(Global.attachmentNameDelimeter); + if (pos > -1) { + guid = name.substring(0, pos); + fd.selectFile(name.substring(pos+Global.attachmentNameDelimeter.length())); + } + if (fd.exec() != 0 && fd.selectedFiles().size() > 0) { + Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true); + String fileName = fd.selectedFiles().get(0); + QFile saveFile = new QFile(fileName); + QFile.OpenMode mode = new QFile.OpenMode(); + mode.set(QFile.OpenModeFlag.WriteOnly); + saveFile.open(mode); + QDataStream saveOut = new QDataStream(saveFile); + QByteArray binData = new QByteArray(resBinary.getData().getBody()); + saveOut.writeBytes(binData.toByteArray()); + saveFile.close(); + } + } + + + // ************************************************************* + // * decrypt any hidden text. We could do an XML parse, but + // * it is quicker here just to scan for an " + +plainText+""; + } + + String html = browser.page().mainFrame().toHtml(); + String text = html; + int imagePos = html.indexOf("0; ) { + // Find the end tag + endPos = text.indexOf(">", imagePos); + String tag = text.substring(imagePos-1,endPos); + if (tag.indexOf("id=\""+id+"\"") > -1) { + text = text.substring(0,imagePos) +plainText+text.substring(endPos+1); + QTextCodec codec = QTextCodec.codecForName("UTF-8"); + QByteArray unicode = codec.fromUnicode(text); + setContent(unicode); + if (permanent) + contentChanged(); + } + imagePos = text.indexOf("=0;) { + endPos = text.indexOf(">", startPos+1); + String segment = text.substring(startPos, endPos); + if (segment.indexOf("en-tag") > -1) { + String newSegment = segment; + + int guidStartPos = segment.indexOf("guid=\""); + int guidEndPos = segment.indexOf("\"", guidStartPos+7); + String guid = segment.substring(guidStartPos+6,guidEndPos); + + int mimeStartPos = segment.indexOf("type"); + int mimeEndPos = segment.indexOf("\"", mimeStartPos+7); + String mime = segment.substring(mimeStartPos+6,mimeEndPos); + + int srcStartPos = segment.indexOf("src"); + int srcEndPos = segment.indexOf("\"", srcStartPos+6); + String src = segment.substring(srcStartPos+5,srcEndPos); + + Calendar currentTime = new GregorianCalendar(); + Long l = new Long(currentTime.getTimeInMillis()); + long prevTime = l; + while (l==prevTime) { + currentTime = new GregorianCalendar(); + l= new Long(currentTime.getTimeInMillis()); + } + + Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true); + // if r==null, then the image doesn't exist (it was probably cut out of another note, so + // we need to recereate it + if (r==null) { + r = createResource(src, 1, mime, false); + if (r==null) + return ""; + } + String randint = new String(Long.toString(l)); + String extension = null; + if (r.getMime()!= null) { + extension = r.getMime().toLowerCase(); + if (extension.indexOf("/")>-1) + extension = extension.substring(extension.indexOf("/")+1); + } + String newFile = randint; + if (r.getAttributes().getFileName() != null && r.getAttributes().getFileName() != "") + if (!locTag.startsWith("src")) + newFile = newFile+Global.attachmentNameDelimeter+r.getAttributes().getFileName(); + r.setNoteGuid(currentNote.getGuid()); + + r.setGuid(randint); + conn.getNoteTable().noteResourceTable.saveNoteResource(r, true); + QFile f = new QFile(Global.getFileManager().getResDirPath(newFile)); + QByteArray bin = new QByteArray(r.getData().getBody()); + f.open(QFile.OpenModeFlag.WriteOnly); + f.write(bin); + f.close(); + newSegment = newSegment.replace("guid=\""+guid, "guid=\""+randint); + currentNote.getResources().add(r); + + int startSrcPos = newSegment.indexOf(locTag); + int endSrcPos = newSegment.indexOf("\"",startSrcPos+locTag.length()+1); + String source; + if (locTag.startsWith("src")) { + source = newSegment.substring(startSrcPos+locTag.length(),endSrcPos); + newSegment = newSegment.replace(source, + FileUtils.toForwardSlashedPath(Global.getFileManager().getResDirPath(newFile))); + } else { + source = newSegment.substring(startSrcPos+locTag.length(),endSrcPos); + newSegment = newSegment.replace(source, newFile); + } + + text = text.substring(0,startPos) + newSegment + text.substring(endPos); + } + startPos = text.indexOf(type, startPos+1); + } + return text; + } + + + public void nextPage(String file) { + logger.log(logger.EXTREME, "Starting nextPage()"); + + Integer pageNumber; + if (previewPageList.containsKey(file)) + pageNumber = previewPageList.get(file)+1; + else + pageNumber = 2; + previewPageList.remove(file); + previewPageList.put(file, pageNumber); + PDFPreview pdfPreview = new PDFPreview(); + boolean goodPreview = pdfPreview.setupPreview(file, "pdf", pageNumber); + if (goodPreview) { + +// String html = getContent(); + QWebSettings.setMaximumPagesInCache(0); + QWebSettings.setObjectCacheCapacities(0, 0, 0); +// browser.setContent(new QByteArray()); + browser.setHtml(browser.page().mainFrame().toHtml()); + browser.reload(); +// browser.setContent(new QByteArray(html)); +// browser.triggerPageAction(WebAction.Reload); +// pdfMouseOver(selectedFile); + } + } + + public void previousPage(String file) { + logger.log(logger.EXTREME, "Starting previousPage()"); + + Integer pageNumber; + if (previewPageList.containsKey(file)) + pageNumber = previewPageList.get(file)-1; + else + pageNumber = 1; + previewPageList.remove(file); + previewPageList.put(file, pageNumber); + PDFPreview pdfPreview = new PDFPreview(); + boolean goodPreview = pdfPreview.setupPreview(file, "pdf", pageNumber); + if (goodPreview) { + +// String html = getContent(); + QWebSettings.setMaximumPagesInCache(0); + QWebSettings.setObjectCacheCapacities(0, 0, 0); + browser.setHtml(browser.page().mainFrame().toHtml()); + browser.reload(); +// browser.setContent(new QByteArray(html)); +// browser.triggerPageAction(WebAction.Reload); + } + } + +/* public void pdfMouseOver(String name) { + int pageNumber; + if (previewPageList.containsKey(selectedFile)) + pageNumber = previewPageList.get(selectedFile)+1; + else + pageNumber = 1; + + if (pageNumber <= 1) + browser.previousPageAction.setEnabled(false); + else + browser.previousPageAction.setEnabled(true); + + PDFPreview pdf = new PDFPreview(); + int totalPages = pdf.getPageCount(name); + if (previewPageList.containsKey(selectedFile)) + pageNumber = previewPageList.get(selectedFile)+1; + else + pageNumber = 1; + if (totalPages > pageNumber) + browser.nextPageAction.setEnabled(true); + else + browser.nextPageAction.setEnabled(false); + } + + + public void pdfMouseOut() { +// browser.nextPageAction.setVisible(false); +// browser.previousPageAction.setVisible(false); + } +*/ + + @SuppressWarnings("unused") + private void toggleUndoVisible(Boolean toggle) { + undoAction.setVisible(toggle); + Global.saveEditorButtonsVisible("undo", toggle); + } + @SuppressWarnings("unused") + private void toggleRedoVisible(Boolean toggle) { + redoAction.setVisible(toggle); + Global.saveEditorButtonsVisible("redo", toggle); + } + @SuppressWarnings("unused") + private void toggleCutVisible(Boolean toggle) { + cutAction.setVisible(toggle); + Global.saveEditorButtonsVisible("cut", toggle); + } + @SuppressWarnings("unused") + private void toggleCopyVisible(Boolean toggle) { + copyAction.setVisible(toggle); + Global.saveEditorButtonsVisible("copy", toggle); + } + @SuppressWarnings("unused") + private void togglePasteVisible(Boolean toggle) { + pasteAction.setVisible(toggle); + Global.saveEditorButtonsVisible("paste", toggle); + } + @SuppressWarnings("unused") + private void toggleBoldVisible(Boolean toggle) { + boldAction.setVisible(toggle); + Global.saveEditorButtonsVisible("bold", toggle); + } + @SuppressWarnings("unused") + private void toggleItalicVisible(Boolean toggle) { + italicAction.setVisible(toggle); + Global.saveEditorButtonsVisible("italic", toggle); + } + @SuppressWarnings("unused") + private void toggleUnderlineVisible(Boolean toggle) { + underlineAction.setVisible(toggle); + Global.saveEditorButtonsVisible("underline", toggle); + } + @SuppressWarnings("unused") + private void toggleStrikethroughVisible(Boolean toggle) { + strikethroughAction.setVisible(toggle); + Global.saveEditorButtonsVisible("strikethrough", toggle); + } + @SuppressWarnings("unused") + private void toggleLeftAlignVisible(Boolean toggle) { + leftAlignAction.setVisible(toggle); + Global.saveEditorButtonsVisible("alignLeft", toggle); + } + @SuppressWarnings("unused") + private void toggleRightAlignVisible(Boolean toggle) { + rightAlignAction.setVisible(toggle); + Global.saveEditorButtonsVisible("alignRight", toggle); + } + @SuppressWarnings("unused") + private void toggleCenterAlignVisible(Boolean toggle) { + centerAlignAction.setVisible(toggle); + Global.saveEditorButtonsVisible("alignCenter", toggle); + } + @SuppressWarnings("unused") + private void toggleHLineVisible(Boolean toggle) { + hlineAction.setVisible(toggle); + Global.saveEditorButtonsVisible("hline", toggle); + } + @SuppressWarnings("unused") + private void toggleIndentVisible(Boolean toggle) { + indentAction.setVisible(toggle); + Global.saveEditorButtonsVisible("indent", toggle); + } + @SuppressWarnings("unused") + private void toggleTodoVisible(Boolean toggle) { + todoAction.setVisible(toggle); + Global.saveEditorButtonsVisible("todo", toggle); + } + @SuppressWarnings("unused") + private void toggleOutdentVisible(Boolean toggle) { + outdentAction.setVisible(toggle); + Global.saveEditorButtonsVisible("outdent", toggle); + } + @SuppressWarnings("unused") + private void toggleBulletListVisible(Boolean toggle) { + bulletListAction.setVisible(toggle); + Global.saveEditorButtonsVisible("bulletList", toggle); + } + @SuppressWarnings("unused") + private void toggleNumberListVisible(Boolean toggle) { + numberListAction.setVisible(toggle); + Global.saveEditorButtonsVisible("numberList", toggle); + } + @SuppressWarnings("unused") + private void toggleFontListVisible(Boolean toggle) { + fontListAction.setVisible(toggle); + Global.saveEditorButtonsVisible("font", toggle); + } + @SuppressWarnings("unused") + private void toggleFontColorVisible(Boolean toggle) { + fontColorAction.setVisible(toggle); + Global.saveEditorButtonsVisible("fontColor", toggle); + } + @SuppressWarnings("unused") + private void toggleFontSizeVisible(Boolean toggle) { + fontSizeAction.setVisible(toggle); + Global.saveEditorButtonsVisible("fontSize", toggle); + } + @SuppressWarnings("unused") + private void toggleFontHilightVisible(Boolean toggle) { + fontHilightAction.setVisible(toggle); + Global.saveEditorButtonsVisible("fontHilight", toggle); + } + @SuppressWarnings("unused") + private void toggleSpellCheckVisible(Boolean toggle) { + spellCheckAction.setVisible(toggle); + Global.saveEditorButtonsVisible("spellCheck", toggle); + } + + + private void setupDictionary() { + File wordList = new File(Global.getFileManager().getSpellDirPath()+Locale.getDefault()+".dic"); + try { + dictionary = new SpellDictionaryHashMap(wordList); + spellChecker = new SpellChecker(dictionary); + + File userWordList; + userWordList = new File(Global.getFileManager().getSpellDirPathUser()+"user.dic"); + + // Get the local user spell dictionary + try { + userDictionary = new SpellDictionaryHashMap(userWordList); + } catch (FileNotFoundException e) { + userWordList.createNewFile(); + userDictionary = new SpellDictionaryHashMap(userWordList); + } catch (IOException e) { + userWordList.createNewFile(); + userDictionary = new SpellDictionaryHashMap(userWordList); + } + + spellListener = new SuggestionListener(this, spellChecker); + + // Add the user dictionary + spellChecker.addSpellCheckListener(spellListener); + spellChecker.setUserDictionary(userDictionary); + + } catch (FileNotFoundException e) { + QMessageBox.critical(this, tr("Spell Check Error"), + tr("Dictionary ")+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+ + tr(".dic was not found.")); + } catch (IOException e) { + QMessageBox.critical(this, tr("Spell Check Error"), + tr("Dictionary ")+ Global.getFileManager().getSpellDirPath()+Locale.getDefault()+ + tr(".dic is invalid.")); + } + + } + + // Invoke spell checker dialog + @SuppressWarnings("unused") + private void spellCheckClicked() { + + if (spellChecker == null) { + setupDictionary(); + } + + // Read user settings + spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREDIGITWORDS, + Global.getSpellSetting(Configuration.SPELL_IGNOREDIGITWORDS)); + spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREINTERNETADDRESSES, + Global.getSpellSetting(Configuration.SPELL_IGNOREINTERNETADDRESSES)); + spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREMIXEDCASE, + Global.getSpellSetting(Configuration.SPELL_IGNOREMIXEDCASE)); + spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNOREUPPERCASE, + Global.getSpellSetting(Configuration.SPELL_IGNOREUPPERCASE)); + spellChecker.getConfiguration().setBoolean(Configuration.SPELL_IGNORESENTENCECAPITALIZATION, + Global.getSpellSetting(Configuration.SPELL_IGNORESENTENCECAPITALIZATION)); + + spellListener.abortSpellCheck = false; + spellListener.errorsFound = false; + String content = getBrowser().page().mainFrame().toPlainText(); + StringWordTokenizer tokenizer = new StringWordTokenizer(content); + if (!tokenizer.hasMoreWords()) + return; + getBrowser().page().action(WebAction.MoveToStartOfDocument); + + getBrowser().setFocus(); + boolean found; + + // Move to the start of page + KeyboardModifiers ctrl = new KeyboardModifiers(KeyboardModifier.ControlModifier.value()); + QKeyEvent home = new QKeyEvent(Type.KeyPress, Key.Key_Home.value(), ctrl); + browser.keyPressEvent(home); + getBrowser().setFocus(); + + tokenizer = new StringWordTokenizer(content); + String word; + + while(tokenizer.hasMoreWords()) { + word = tokenizer.nextWord(); + found = getBrowser().page().findText(word); + if (found && !spellListener.abortSpellCheck) { + spellChecker.checkSpelling(new StringWordTokenizer(word)); + getBrowser().setFocus(); + } + } + + // Go to the end of the document & finish up. + home = new QKeyEvent(Type.KeyPress, Key.Key_End.value(), ctrl); + browser.keyPressEvent(home); + if (!spellListener.errorsFound) + QMessageBox.information(this, tr("Spell Check Complete"), + tr("No Errors Found")); + + } + + // Source edited + @SuppressWarnings("unused") + private void sourceEdited() { + QTextCodec codec = QTextCodec.codecForLocale(); + codec = QTextCodec.codecForName("UTF-8"); + String content = codec.fromUnicode(sourceEdit.toHtml()).toString(); + content = StringEscapeUtils.unescapeHtml4(removeTags(content)); + QByteArray data = new QByteArray(sourceEditHeader+content+""); + getBrowser().setContent(data); + checkNoteTitle(); + if (currentNote != null && sourceEdit != null) + noteSignal.noteChanged.emit(currentNote.getGuid(), sourceEdit.toPlainText()); + } + + private void setSource() { + String text = getContent(); + sourceEdit.blockSignals(true); + int body = text.indexOf(" 0) { + body = text.indexOf(">",body); + if (body > 0) { + sourceEditHeader =text.substring(0, body+1); + text = text.substring(body+1); + } + } + text = text.replace("", ""); + sourceEdit.setPlainText(text); + sourceEdit.setReadOnly(!getBrowser().page().isContentEditable()); + //syntaxHighlighter.rehighlight(); + sourceEdit.blockSignals(false); + } + + // show/hide view source window + public void showSource(boolean value) { + setSource(); + sourceEdit.setVisible(value); + } + + // Remove HTML tags + private String removeTags(String text) { + StringBuffer buffer = new StringBuffer(text); + boolean inTag = false; + int bodyPosition = text.indexOf("=0; i--) { + if (buffer.charAt(i) == '>') + inTag = true; + if (buffer.charAt(i) == '<') + inTag = false; + if (inTag || buffer.charAt(i) == '<' || i contentsChanged; - public Signal1 windowClosing; - boolean noteDirty; - String saveTitle; - private final FindDialog find; // Text search in note dialog -// ExternalBrowserMenuBar menu; - ExternalBrowserMenuBar menu; - - // Constructor - public ExternalBrowse(DatabaseConnection c) { - setAttribute(WidgetAttribute.WA_QuitOnClose, false); - setWindowTitle(tr("NixNote")); - conn = c; - contentsChanged = new Signal4(); - windowClosing = new Signal1(); - browser = new BrowserWindow(conn); - menu = new ExternalBrowserMenuBar(this); - for (int i=0; i tags) { - if (guid.equals(getBrowserWindow().getNote().getGuid())) { - StringBuffer tagLine = new StringBuffer(100); - for (int i=0; i0) - tagLine.append(Global.tagDelimeter+" "); - tagLine.append(tags.get(i)); - - } - getBrowserWindow().loadingData(true); - getBrowserWindow().getTagLine().setText(tagLine.toString()); - getBrowserWindow().loadingData(false); - } - } - - - @SuppressWarnings("unused") - private void findText() { - find.show(); - find.setFocusOnTextField(); - } - @SuppressWarnings("unused") - private void doFindText() { - browser.getBrowser().page().findText(find.getText(), find.getFlags()); - find.setFocus(); - } - - - @SuppressWarnings("unused") - private void printNote() { - - QPrintDialog dialog = new QPrintDialog(); - if (dialog.exec() == QDialog.DialogCode.Accepted.value()) { - QPrinter printer = dialog.printer(); - browser.getBrowser().print(printer); - } - } - - // Listener triggered when the email button is pressed - @SuppressWarnings("unused") - private void emailNote() { - if (Desktop.isDesktopSupported()) { - Desktop desktop = Desktop.getDesktop(); - - String text2 = browser.getContentsToEmail(); - QUrl url = new QUrl("mailto:"); - url.addQueryItem("subject", browser.getTitle()); - url.addQueryItem("body", text2); - QDesktopServices.openUrl(url); - } - } -} +/* + * This file is part of NixNote + * Copyright 2009 Randy Baumgarte + * + * This file may be licensed under the terms of of the + * GNU General Public License Version 2 (the ``GPL''). + * + * Software distributed under the License is distributed + * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the GPL for the specific language + * governing rights and limitations. + * + * You should have received a copy of the GPL along with this + * program. If not, go to http://www.gnu.org/licenses/gpl.html + * or write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * +*/ + +package cx.fbn.nevernote.gui; + +import java.awt.Desktop; +import java.util.List; + +import com.trolltech.qt.core.QUrl; +import com.trolltech.qt.core.Qt.WidgetAttribute; +import com.trolltech.qt.gui.QCloseEvent; +import com.trolltech.qt.gui.QDesktopServices; +import com.trolltech.qt.gui.QDialog; +import com.trolltech.qt.gui.QMdiSubWindow; +import com.trolltech.qt.gui.QPrintDialog; +import com.trolltech.qt.gui.QPrinter; + +import cx.fbn.nevernote.Global; +import cx.fbn.nevernote.dialog.FindDialog; +import cx.fbn.nevernote.neighbornote.ClipBoardObserver; +import cx.fbn.nevernote.sql.DatabaseConnection; + +public class ExternalBrowse extends QMdiSubWindow { + private final DatabaseConnection conn; + private final BrowserWindow browser; + public Signal4 contentsChanged; + public Signal1 windowClosing; + boolean noteDirty; + String saveTitle; + private final FindDialog find; // Text search in note dialog +// ExternalBrowserMenuBar menu; + ExternalBrowserMenuBar menu; + + // ICHANGED + private final ClipBoardObserver cbObserver; + + // Constructor + // ICHANGED cbObserver引数を追加 + public ExternalBrowse(DatabaseConnection c, ClipBoardObserver cbObserver) { + setAttribute(WidgetAttribute.WA_QuitOnClose, false); + setWindowTitle(tr("NeighborNote")); + conn = c; + // ICHANGED + this.cbObserver = cbObserver; + + contentsChanged = new Signal4(); + windowClosing = new Signal1(); + // ICHANGED + browser = new BrowserWindow(conn, this.cbObserver); + + menu = new ExternalBrowserMenuBar(this); + for (int i=0; i tags) { + if (guid.equals(getBrowserWindow().getNote().getGuid())) { + StringBuffer tagLine = new StringBuffer(100); + for (int i=0; i0) + tagLine.append(Global.tagDelimeter+" "); + tagLine.append(tags.get(i)); + + } + getBrowserWindow().loadingData(true); + getBrowserWindow().getTagLine().setText(tagLine.toString()); + getBrowserWindow().loadingData(false); + } + } + + + @SuppressWarnings("unused") + private void findText() { + find.show(); + find.setFocusOnTextField(); + } + @SuppressWarnings("unused") + private void doFindText() { + browser.getBrowser().page().findText(find.getText(), find.getFlags()); + find.setFocus(); + } + + + @SuppressWarnings("unused") + private void printNote() { + + QPrintDialog dialog = new QPrintDialog(); + if (dialog.exec() == QDialog.DialogCode.Accepted.value()) { + QPrinter printer = dialog.printer(); + browser.getBrowser().print(printer); + } + } + + // Listener triggered when the email button is pressed + @SuppressWarnings("unused") + private void emailNote() { + if (Desktop.isDesktopSupported()) { + Desktop desktop = Desktop.getDesktop(); + + String text2 = browser.getContentsToEmail(); + QUrl url = new QUrl("mailto:"); + url.addQueryItem("subject", browser.getTitle()); + url.addQueryItem("body", text2); + QDesktopServices.openUrl(url); + } + } +} diff --git a/src/cx/fbn/nevernote/gui/MainMenuBar.java b/src/cx/fbn/nevernote/gui/MainMenuBar.java index 1bfbe8d..c6f4397 100644 --- a/src/cx/fbn/nevernote/gui/MainMenuBar.java +++ b/src/cx/fbn/nevernote/gui/MainMenuBar.java @@ -1,835 +1,1008 @@ -/* - * This file is part of NixNote - * Copyright 2009 Randy Baumgarte - * - * This file may be licensed under the terms of of the - * GNU General Public License Version 2 (the ``GPL''). - * - * Software distributed under the License is distributed - * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either - * express or implied. See the GPL for the specific language - * governing rights and limitations. - * - * You should have received a copy of the GPL along with this - * program. If not, go to http://www.gnu.org/licenses/gpl.html - * or write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * -*/ -package cx.fbn.nevernote.gui; - -import com.trolltech.qt.gui.QAction; -import com.trolltech.qt.gui.QMenu; -import com.trolltech.qt.gui.QMenuBar; - -import cx.fbn.nevernote.Global; -import cx.fbn.nevernote.NeverNote; - -public class MainMenuBar extends QMenuBar { - - private final NeverNote parent; - public QAction printAction; // Action when a user selects Print from the file menu - public QAction connectAction; // Connect/Disconnect to Evernote - public QAction fullReindexAction; // Action when a user wants to reindex the entire database - public QAction synchronizeAction; // Synchronize data with Evernote - public QAction selectiveSyncAction; // Specify which notebooks or tags to ignore - public QAction settingsAction; // Show user config settings - public QAction emailAction; // Action when a user selects "email" - public QAction backupAction; // Backup the database - public QAction restoreAction; // Restore from a backup - public QAction emptyTrashAction; // Action when a user wants to clear the trash file - public QAction exitAction; // Action when user selects "exit" - public QAction aboutAction; // Action when a user selects "About" - public QAction checkForUpdates; // Check for newer versions - public QAction loggerAction; // Action when a user selects "Log" - public QAction releaseAction; // Release notes - - public QAction noteAdd; // Add a note - public QAction noteAttributes; // Action when a user selects note attributes - public QAction noteTags; // Assign a note tags - public QAction noteDelete; // Delete the current note - public QAction noteRestoreAction; // Restore a note - public QAction noteReindex; // Action when a user wants to reindex a note - public QAction noteDuplicateAction; // Duplicate an existing note - public QAction noteMergeAction; // Merge notes - public QAction noteExportAction; // Export notes - public QAction noteImportAction; // Import notes - public QAction noteCopyAsUrlAction; // Copy the note as a URL - - public QAction editFind; // find text in the current note - public QAction editUndo; // Undo last change - public QAction editRedo; // Redo last change - public QAction editCut; // Cut selected text - public QAction editPaste; // Paste selected text - public QAction editPasteWithoutFormat; // Paste selected text - public QAction editCopy; // Copy selected text; - - public QAction wideListView; // View with list on the top - public QAction narrowListView; // View with list on the side - public QAction thumbnailView; // view thumbnails - public QAction hideSavedSearches; // show/hide saved searches - public QAction hideZoom; // show/hide the zoom spinner - public QAction hideSearch; // Show/hide the search window - public QAction hideQuota; // show/hide the quota window - public QAction hideNotebooks; // show/hide notebooks - public QAction hideTags; // show/hide tags - public QAction hideAttributes; // show/hide note information - public QAction hideTrash; // show/hide trash tree - public QAction hideNoteList; // show/hide the list of notes - public QAction showEditorBar; // show/hide the editor button bar - public QAction hideLeftSide; // Hide the entire left side - public QAction viewSource; // View the source HTML of a note - - public QAction formatBold; // Bold selected text - public QAction formatItalic; // Italics selected text - public QAction formatUnderline; // Underline selected text - public QAction formatStrikethrough; // Strikethrough selected text - public QAction formatSuperscript; // Superscript selected text - public QAction formatSubscript; // Subscript selected text - public QAction formatNumberList; // insert a numbered list - public QAction formatBulletList; // insert a bulleted list; - public QAction alignLeftAction; // Left justify text - public QAction alignRightAction; // Right justify text - public QAction alignCenterAction; // Center text - public QAction horizontalLineAction; // Insert a horizontal line - public QAction indentAction; // Indent - public QAction outdentAction; // outdent menu action - - public QAction noteOnlineHistoryAction; // Pull note history from Evernote - - public QAction accountAction; // Account dialog box action - public QAction disableIndexing; // put indexing on hold. -// public QAction compactAction; // free unused space in the database - public QAction databaseStatusAction; // Current database status - public QAction folderImportAction; // Automatically import files - public QAction spellCheckAction; // Spell checker - public QAction encryptDatabaseAction; // Encrypt the local database - - public QAction notebookEditAction; // Edit the selected notebook - public QAction notebookAddAction; // Add a new notebook - public QAction notebookDeleteAction; // Delete a notebook - public QAction notebookPublishAction; // Publish a notebook - public QAction notebookShareAction; // Share a notebook with others - public QAction notebookCloseAction; // Close notebooks - public QAction notebookIconAction; // Change the icon - public QAction notebookStackAction; // Stack/Unstack the icon. - - public QAction savedSearchAddAction; // Add a saved search - public QAction savedSearchEditAction; // Edit a saved search - public QAction savedSearchDeleteAction; // Delete a saved search - public QAction savedSearchIconAction; // Change a saved search icon - - public QAction tagEditAction; // Edit a tag - public QAction tagAddAction; // Add a tag - public QAction tagDeleteAction; // Delete a tag - public QAction tagIconAction; // Change the icon - public QAction tagMergeAction; // Merge tags - - //************************************************************************** - //* Menu Bar Titles - //************************************************************************** - - private QMenu fileMenu; // File menu - private QMenu noteMenu; // Note menu - private QMenu notebookMenu; // Notebook menu - private QMenu tagMenu; // Tag menu - private QMenu savedSearchMenu; // Saved Searches - - private QMenu editMenu; // Edit menu - - private QMenu formatMenu; // Text format menu - private QMenu viewMenu; // show/hide stuff - private QMenu listMenu; // bullet or numbered list - private QMenu indentMenu; // indent or outdent menu - private QMenu alignMenu; // Left/Right/Center justify - -// private QMenu onlineMenu; // View online stuff (if connected) - - private QMenu toolsMenu; // Tools menu - - private QMenu helpMenu; - - public MainMenuBar(NeverNote p) { - parent = p; - - - fullReindexAction = new QAction(tr("Reindex Database"), this); - fullReindexAction.setToolTip(tr("Reindex all notes")); - fullReindexAction.triggered.connect(parent, "fullReindex()"); - setupShortcut(fullReindexAction, "Tools_Reindex_Database"); - - printAction = new QAction(tr("Print"), this); - printAction.setToolTip(tr("Print the current note")); - printAction.triggered.connect(parent, "printNote()"); - setupShortcut(printAction, "File_Print"); - - emailAction = new QAction(tr("Email"), this); - emailAction.setToolTip(tr("Email the current note")); - emailAction.triggered.connect(parent, "emailNote()"); - setupShortcut(emailAction, "File_Email"); - - backupAction = new QAction(tr("Backup Database"), this); - backupAction.setToolTip(tr("Backup the current database")); - backupAction.triggered.connect(parent, "databaseBackup()"); - setupShortcut(backupAction, "File_Backup"); - - restoreAction = new QAction(tr("Restore Database"), this); - restoreAction.setToolTip(tr("Restore the database from a backup")); - restoreAction.triggered.connect(parent, "databaseRestore()"); - setupShortcut(restoreAction, "File_Restore"); - - emptyTrashAction = new QAction(tr("Empty Trash"), this); - emptyTrashAction.setToolTip(tr("Empty the trash folder")); - emptyTrashAction.triggered.connect(parent, "emptyTrash()"); - setupShortcut(emptyTrashAction, "File_Empty_Trash"); - - noteRestoreAction = new QAction(tr("Restore"), this); - noteRestoreAction.setToolTip(tr("Restore a deleted file from the trash")); - noteRestoreAction.triggered.connect(parent, "restoreNote()"); - noteRestoreAction.setVisible(false); - setupShortcut(noteRestoreAction, "File_Note_Restore"); - - settingsAction = new QAction(tr("Preferences"), this); - settingsAction.setToolTip(tr("Program settings")); - settingsAction.triggered.connect(parent, "settings()"); - setupShortcut(settingsAction, "Edit_Preferences"); - - exitAction = new QAction(tr("Exit"), this); - exitAction.setToolTip(tr("Close the program")); - exitAction.triggered.connect(parent, "closeNeverNote()"); - exitAction.setShortcut("Ctrl+Q"); - setupShortcut(exitAction, "File_Exit"); - - noteAttributes = new QAction(tr("Extended Information"), this); - noteAttributes.setToolTip(tr("Show/Hide extended note attributes")); - noteAttributes.triggered.connect(parent, "toggleNoteInformation()"); - noteAttributes.setShortcut("F8"); - setupShortcut(noteAttributes, "View_Extended_Information"); - - noteReindex = new QAction(tr("Reindex"), this); - noteReindex.setToolTip(tr("Reindex this note")); - noteReindex.triggered.connect(parent, "reindexNote()"); - setupShortcut(noteReindex, "File_Note_Reindex"); - - noteDuplicateAction = new QAction(tr("Duplicate"), this); - noteDuplicateAction.setToolTip(tr("Duplicate this note")); - noteDuplicateAction.triggered.connect(parent, "duplicateNote()"); - setupShortcut(noteReindex, "File_Note_Duplicate"); - - noteMergeAction = new QAction(tr("Merge Notes"), this); - noteMergeAction.setToolTip(tr("Merge Multiple notes")); - noteMergeAction.triggered.connect(parent, "mergeNotes()"); - setupShortcut(noteMergeAction, "File_Note_Merge"); - - noteExportAction = new QAction(tr("Export Selected Notes"), this); - noteExportAction.setToolTip(tr("Export selected notes")); - noteExportAction.triggered.connect(parent, "exportNotes()"); - setupShortcut(noteExportAction, "File_Note_Export"); - - noteCopyAsUrlAction = new QAction(tr("Copy as URL"), this); - noteCopyAsUrlAction.setToolTip(tr("Copy as URL")); - noteCopyAsUrlAction.triggered.connect(parent, "copyAsUrlClicked()"); - setupShortcut(noteCopyAsUrlAction, "Note_Copy_As_Url"); - - noteImportAction = new QAction(tr("Import Notes"), this); - noteImportAction.setToolTip(tr("Import notes")); - noteImportAction.triggered.connect(parent, "importNotes()"); - setupShortcut(noteImportAction, "File_Note_Import"); - - noteAdd = new QAction(tr("Add"), this); - noteAdd.setToolTip(tr("Add a new note")); - noteAdd.triggered.connect(parent, "addNote()"); - setupShortcut(noteAdd, "File_Note_Add"); - - noteTags = new QAction(tr("Modify Tags"), this); - noteTags.setToolTip(tr("Change the tags assigned to this note")); - noteTags.triggered.connect(parent.browserWindow, "modifyTags()"); - setupShortcut(noteTags, "File_Note_Modify_Tags"); - - noteDelete = new QAction(tr("Delete"), this); - noteDelete.setToolTip(tr("Delete this note")); - noteDelete.triggered.connect(parent, "deleteNote()"); - setupShortcut(noteDelete, "File_Note_Delete"); - - editFind = new QAction(tr("Find In Note"), this); - editFind.setToolTip(tr("Find a string in the current note")); - editFind.triggered.connect(parent, "findText()"); - setupShortcut(editFind, "Edit_Find_In_Note"); - //editFind.setShortcut("Ctrl+F"); - - editUndo = new QAction(tr("Undo"), this); - editUndo.setToolTip(tr("Undo")); - editUndo.triggered.connect(parent.browserWindow, "undoClicked()"); - setupShortcut(editUndo, "Edit_Undo"); - //editUndo.setShortcut("Ctrl+Z"); - - editRedo = new QAction(tr("Redo"), this); - editRedo.setToolTip(tr("Redo")); - editRedo.triggered.connect(parent.browserWindow, "redoClicked()"); - setupShortcut(editRedo, "Edit_Redo"); - //editRedo.setShortcut("Ctrl+Y"); - - editCut = new QAction(tr("Cut"), this); - editCut.setToolTip(tr("Cut")); - editCut.triggered.connect(parent.browserWindow, "cutClicked()"); - setupShortcut(editCut, "Edit_Cut"); - //editCut.setShortcut("Ctrl+X"); - - editCopy = new QAction(tr("Copy"), this); - editCopy.setToolTip(tr("Copy")); - editCopy.triggered.connect(parent.browserWindow, "copyClicked()"); - setupShortcut(editCopy, "Edit_Copy"); - //editCopy.setShortcut("Ctrl+C"); - - - editPaste = new QAction(tr("Paste"), this); - editPaste.setToolTip(tr("Paste")); - editPaste.triggered.connect(parent.browserWindow, "pasteClicked()"); - setupShortcut(editPaste, "Edit_Paste"); - - editPasteWithoutFormat = new QAction(tr("Paste Without Formatting"), this); - editPasteWithoutFormat.setToolTip(tr("Paste Without Formatting")); - editPasteWithoutFormat.triggered.connect(parent.browserWindow, "pasteWithoutFormattingClicked()"); - setupShortcut(editPasteWithoutFormat, "Edit_Paste_Without_Formatting"); - - hideNoteList = new QAction(tr("Show Note List"), this); - hideNoteList.setToolTip(tr("Show/Hide Note List")); - hideNoteList.triggered.connect(parent, "toggleNoteListWindow()"); - hideNoteList.setCheckable(true); - hideNoteList.setChecked(true); - setupShortcut(hideNoteList, "View_Show_Note_List"); - - hideTags = new QAction(tr("Show Tags"), this); - hideTags.setToolTip(tr("Show/Hide Tags")); - hideTags.triggered.connect(parent, "toggleTagWindow()"); - hideTags.setCheckable(true); - hideTags.setChecked(true); - setupShortcut(hideTags, "View_Show_Tags"); - - hideNotebooks = new QAction(tr("Show Notebooks"), this); - hideNotebooks.setToolTip(tr("Show/Hide Notebooks")); - hideNotebooks.triggered.connect(parent, "toggleNotebookWindow()"); - hideNotebooks.setCheckable(true); - hideNotebooks.setChecked(true); - setupShortcut(hideNotebooks, "View_Show_Notebooks"); - - hideZoom = new QAction(tr("Show Zoom"), this); - hideZoom.setToolTip(tr("Show/Hide Zoom")); - hideZoom.triggered.connect(parent, "toggleZoomWindow()"); - hideZoom.setCheckable(true); - hideZoom.setChecked(true); - setupShortcut(hideZoom, "View_Show_Zoom"); - - hideQuota = new QAction(tr("Show Quota Bar"), this); - hideQuota.setToolTip(tr("Show/Hide Quota")); - hideQuota.triggered.connect(parent, "toggleQuotaWindow()"); - hideQuota.setCheckable(true); - hideQuota.setChecked(true); - setupShortcut(hideQuota, "View_Show_Quota"); - - hideSearch = new QAction(tr("Show Search Box"), this); - hideSearch.setToolTip(tr("Show/Hide Search Box")); - hideSearch.triggered.connect(parent, "toggleSearchWindow()"); - hideSearch.setCheckable(true); - hideSearch.setChecked(true); - setupShortcut(hideSearch, "View_Show_Search"); - - wideListView = new QAction(tr("Wide List View"), this); - wideListView.setToolTip(tr("Wide List View")); - wideListView.setCheckable(true); - wideListView.changed.connect(parent, "wideListView()"); - setupShortcut(wideListView, "View_Wide_List"); - - narrowListView = new QAction(tr("Narrow List View"), this); - narrowListView.setToolTip(tr("Narrow List View")); - narrowListView.setCheckable(true); - narrowListView.changed.connect(parent, "narrowListView()"); - setupShortcut(narrowListView, "View_Narrow_List"); - - thumbnailView = new QAction(tr("Preview"), this); - thumbnailView.setToolTip(tr("Preview Notes")); - thumbnailView.triggered.connect(parent, "thumbnailView()"); - setupShortcut(thumbnailView, "View_Thumbnail"); - - hideSavedSearches = new QAction(tr("Show Saved Searches"), this); - hideSavedSearches.setToolTip(tr("Show/Hide Saved Searches")); - hideSavedSearches.triggered.connect(parent, "toggleSavedSearchWindow()"); - hideSavedSearches.setCheckable(true); - hideSavedSearches.setChecked(true); - setupShortcut(hideSavedSearches, "View_Show_SavedSearches"); - - hideAttributes = new QAction(tr("Show Attribute Searches"), this); - hideAttributes.setToolTip(tr("Show/Hide Attribute Searches")); - hideAttributes.triggered.connect(parent, "toggleAttributesWindow()"); - hideAttributes.setCheckable(true); - hideAttributes.setChecked(true); - setupShortcut(hideAttributes, "View_Show_Attribute_Searches"); - - hideTrash = new QAction(tr("Show Trash"), this); - hideTrash.setToolTip(tr("Show/Hide Trash Tree")); - hideTrash.triggered.connect(parent, "toggleTrashWindow()"); - hideTrash.setCheckable(true); - hideTrash.setChecked(true); - setupShortcut(hideTrash, "View_Show_Trash"); - - - showEditorBar = new QAction(tr("Show Editor Button Bar"), this); - showEditorBar.setToolTip(tr("Show/Hide Editor Button Bar")); - showEditorBar.triggered.connect(parent, "toggleEditorButtonBar()"); - showEditorBar.setCheckable(true); - showEditorBar.setChecked(true); - setupShortcut(showEditorBar, "View_Show_Editor_Button_Bar"); - - - hideLeftSide = new QAction(tr("Hide Left Side Panels"), this); - hideLeftSide.setToolTip(tr("Hide The Entire Left Side")); - hideLeftSide.triggered.connect(parent, "toggleLeftSide()"); - hideLeftSide.setCheckable(true); - hideLeftSide.setChecked(false); - setupShortcut(hideLeftSide, "View_Show_Left_Side"); - //hideLeftSide.setShortcut("F11"); - - viewSource = new QAction(tr("View Source"), this); - viewSource.setToolTip(tr("View the source HTML for a note")); - viewSource.triggered.connect(parent, "viewSource()"); - viewSource.setCheckable(true); - viewSource.setChecked(false); - setupShortcut(viewSource, "View_Source"); - //hideLeftSide.setShortcut("F11"); - - alignLeftAction = new QAction(tr("Left"), this); - alignLeftAction.setToolTip(tr("Left Align")); - alignLeftAction.triggered.connect(parent.browserWindow, "justifyLeftClicked()"); - setupShortcut(alignLeftAction, "Format_Alignment_Left"); - //alignLeftAction.setShortcut("Ctrl+L"); - - alignRightAction = new QAction(tr("Right"), this); - alignRightAction.setToolTip(tr("Right Align")); - alignRightAction.triggered.connect(parent.browserWindow, "justifyRightClicked()"); - setupShortcut(alignRightAction, "Format_Alignment_Right"); - //alignRightAction.setShortcut("Ctrl+R"); - - alignCenterAction = new QAction(tr("Center"), this); - alignCenterAction.setToolTip(tr("Center Align")); - alignCenterAction.triggered.connect(parent.browserWindow, "justifyCenterClicked()"); - setupShortcut(alignCenterAction, "Format_Alignment_Center"); - //alignCenterAction.setShortcut("Ctrl+C"); - - formatBold = new QAction(tr("Bold"), this); - formatBold.setToolTip(tr("Bold")); - formatBold.triggered.connect(parent.browserWindow, "boldClicked()"); - setupShortcut(formatBold, "Format_Bold"); - //formatBold.setShortcut("Ctrl+B"); - - formatItalic = new QAction(tr("Italic"), this); - formatItalic.setToolTip(tr("Italic")); - formatItalic.triggered.connect(parent.browserWindow, "italicClicked()"); - setupShortcut(formatItalic, "Format_Italic"); - //formatItalic.setShortcut("Ctrl+I"); - - formatUnderline = new QAction(tr("Underline"), this); - formatUnderline.setToolTip(tr("Underline")); - formatUnderline.triggered.connect(parent.browserWindow, "underlineClicked()"); - setupShortcut(formatUnderline, "Format_Underline"); -// formatUnderline.setShortcut("Ctrl+U"); - - - formatSuperscript = new QAction(tr("Superscript"), this); - formatSuperscript.setToolTip(tr("Superscript")); - formatSuperscript.triggered.connect(parent.browserWindow, "superscriptClicked()"); - setupShortcut(formatSuperscript, "Format_Superscript"); - - - formatSubscript = new QAction(tr("Subscript"), this); - formatSubscript.setToolTip(tr("Subscript")); - formatSubscript.triggered.connect(parent.browserWindow, "subscriptClicked()"); - setupShortcut(formatSubscript, "Format_Subscript"); - - - formatStrikethrough = new QAction(tr("Strikethrough"), this); - formatStrikethrough.setToolTip(tr("Strikethrough")); - formatStrikethrough.triggered.connect(parent.browserWindow, "strikethroughClicked()"); - setupShortcut(formatStrikethrough, "Format_Strikethrough"); - - horizontalLineAction = new QAction(tr("Horizontal Line"), this); - horizontalLineAction.setToolTip(tr("Horizontal Line")); - horizontalLineAction.triggered.connect(parent.browserWindow, "hlineClicked()"); - setupShortcut(horizontalLineAction, "Format_Horizontal_Line"); - - formatBulletList = new QAction(tr("Bulleted List"), this); -// formatBulletList.setText(tr("Numbered List")); - formatBulletList.triggered.connect(parent.browserWindow, "bulletListClicked()"); - setupShortcut(formatBulletList, "Format_List_Bullet"); -// formatBulletList.setShortcut("Ctrl+Shift+B"); - - formatNumberList = new QAction(tr("Numbered List"), this); - formatNumberList.setText(tr("Numbered list")); - formatNumberList.triggered.connect(parent.browserWindow, "numberListClicked()"); - setupShortcut(formatNumberList, "Format_List_Numbered"); -// formatNumberList.setShortcut("Ctrl+Shift+O"); - - indentAction = new QAction(tr(">> Increase"), this); - indentAction.setText(tr(">> Increase")); - indentAction.triggered.connect(parent.browserWindow, "indentClicked()"); - setupShortcut(indentAction, "Format_Indent_Increase"); - //indentAction.setShortcut("Ctrl+M"); - - outdentAction = new QAction(tr("<< Decrease"), this); - outdentAction.setText(tr("<< Decrease")); - outdentAction.triggered.connect(parent.browserWindow, "outdentClicked()"); - setupShortcut(outdentAction, "Format_Indent_Decrease"); - //outdentAction.setShortcut("Ctrl+Shift+M"); - - notebookAddAction = new QAction(tr("Add"), this); - notebookAddAction.triggered.connect(parent, "addNotebook()"); - setupShortcut(notebookAddAction, "File_Notebook_Add"); - - notebookEditAction = new QAction(tr("Edit"), this); - notebookEditAction.setEnabled(false); - notebookEditAction.triggered.connect(parent, "editNotebook()"); - setupShortcut(notebookEditAction, "File_Notebook_Edit"); - - notebookDeleteAction = new QAction(tr("Delete"), this); - notebookDeleteAction.setEnabled(false); - notebookDeleteAction.triggered.connect(parent, "deleteNotebook()"); - setupShortcut(notebookDeleteAction, "File_Notebook_Delete"); - - notebookPublishAction = new QAction(tr("Share With The World"), this); - notebookPublishAction.setEnabled(false); - notebookPublishAction.setVisible(false); - notebookPublishAction.triggered.connect(parent, "publishNotebook()"); - setupShortcut(notebookPublishAction, "File_Notebook_Publish"); - - notebookShareAction = new QAction(tr("Share With Individuals"), this); - notebookShareAction.setEnabled(false); - notebookShareAction.setVisible(false); - notebookShareAction.triggered.connect(parent, "shareNotebook()"); - setupShortcut(notebookShareAction, "File_Notebook_Share"); - - - notebookCloseAction = new QAction(tr("Open/Close Notebooks"), this); - notebookCloseAction.setEnabled(true); - notebookCloseAction.triggered.connect(parent, "closeNotebooks()"); - setupShortcut(notebookCloseAction, "File_Notebook_Close"); - - notebookIconAction = new QAction(tr("Change Icon"), this); - notebookIconAction.setEnabled(false); - notebookIconAction.triggered.connect(parent, "setNotebookIcon()"); - setupShortcut(notebookIconAction, "File_Notebook_Icon"); - - notebookStackAction = new QAction(tr("Set Stack"), this); - notebookStackAction.setEnabled(false); - notebookStackAction.triggered.connect(parent, "stackNotebook()"); - setupShortcut(notebookStackAction, "File_Notebook_Stack"); - - tagAddAction = new QAction(tr("Add"),this); - tagAddAction.triggered.connect(parent, "addTag()"); - setupShortcut(tagAddAction, "File_Tag_Add"); - - tagEditAction = new QAction(tr("Edit"), this); - tagEditAction.triggered.connect(parent, "editTag()"); - tagEditAction.setEnabled(false); - setupShortcut(tagEditAction, "File_Tag_Edit"); - - tagDeleteAction = new QAction(tr("Delete"), this); - tagDeleteAction.triggered.connect(parent, "deleteTag()"); - tagDeleteAction.setEnabled(false); - setupShortcut(tagDeleteAction, "File_Tag_Delete"); - - tagIconAction = new QAction(tr("Change Icon"), this); - tagIconAction.triggered.connect(parent, "setTagIcon()"); - tagIconAction.setEnabled(false); - setupShortcut(tagIconAction, "File_Tag_Icon"); - - tagMergeAction = new QAction(tr("Merge Tags"), this); - tagMergeAction.triggered.connect(parent, "mergeTags()"); - tagMergeAction.setEnabled(false); - setupShortcut(tagMergeAction, "File_Tag_Merge"); - - savedSearchAddAction = new QAction(tr("Add"),this); - savedSearchAddAction.triggered.connect(parent, "addSavedSearch()"); - setupShortcut(savedSearchAddAction, "File_SavedSearch_Add"); - - savedSearchEditAction = new QAction(tr("Edit"), this); - savedSearchEditAction.triggered.connect(parent, "editSavedSearch()"); - savedSearchEditAction.setEnabled(false); - setupShortcut(savedSearchEditAction, "File_SavedSearch_Edit"); - - savedSearchDeleteAction = new QAction(tr("Delete"), this); - savedSearchDeleteAction.triggered.connect(parent, "deleteSavedSearch()"); - savedSearchDeleteAction.setEnabled(false); - setupShortcut(savedSearchDeleteAction, "File_SavedSearch_Delete"); - - savedSearchIconAction = new QAction(tr("Change Icon"), this); - savedSearchIconAction.triggered.connect(parent, "setSavedSearchIcon()"); - savedSearchIconAction.setEnabled(false); - setupShortcut(savedSearchIconAction, "File_SavedSearch_Icon"); - - connectAction = new QAction(tr("Connect"), this); - connectAction.setToolTip("Connect to Evernote"); - connectAction.triggered.connect(parent, "remoteConnect()"); - setupShortcut(connectAction, "Tools_Connect"); - - synchronizeAction = new QAction(tr("Synchronize with Evernote"), this); - synchronizeAction.setToolTip("Delete all local data & get a fresh copy"); - synchronizeAction.triggered.connect(parent, "evernoteSync()"); - synchronizeAction.setEnabled(false); - setupShortcut(synchronizeAction, "Tools_Synchronize"); - //synchronizeAction.setShortcut("F9"); - - noteOnlineHistoryAction = new QAction(tr("Note History"), this); - noteOnlineHistoryAction.triggered.connect(parent, "viewNoteHistory()"); - noteOnlineHistoryAction.setEnabled(false); - setupShortcut(noteOnlineHistoryAction, "File_Note_History"); - - selectiveSyncAction = new QAction(tr("Selective Synchronize"), this); - selectiveSyncAction.setToolTip("Selectively ignore some notes"); - selectiveSyncAction.triggered.connect(parent, "setupSelectiveSync()"); - selectiveSyncAction.setEnabled(false); - setupShortcut(synchronizeAction, "File_Selective_Sync"); - - - - accountAction = new QAction(tr("Account Information"), this); - accountAction.setToolTip(tr("Account Information")); - accountAction.triggered.connect(parent, "accountInformation()"); - setupShortcut(accountAction, "Tools_Account_Information"); - -// compactAction = new QAction(tr("Compact Database"), this); -// compactAction.setToolTip(tr("Free unused database space")); -// compactAction.triggered.connect(parent, "compactDatabase()"); -// setupShortcut(compactAction, "Tools_Compact_Database"); - - databaseStatusAction = new QAction(tr("Database Status"), this); - databaseStatusAction.setToolTip(tr("Show current database information")); - databaseStatusAction.triggered.connect(parent, "databaseStatus()"); - setupShortcut(databaseStatusAction, "Tools_Database_Status"); - - - disableIndexing = new QAction(tr("Disable Note Indexing"), this); - disableIndexing.setToolTip(tr("Manually Stop Note Indexing")); - disableIndexing.triggered.connect(parent, "toggleNoteIndexing()"); - disableIndexing.setCheckable(true); - disableIndexing.setChecked(false); - setupShortcut(disableIndexing, "Tools_Disable_Note_Indexing"); - - - folderImportAction = new QAction(tr("Automatic Folder Importing"), this); - folderImportAction.setToolTip(tr("Import Files Automatically")); - folderImportAction.triggered.connect(parent, "folderImport()"); - setupShortcut(folderImportAction, "Tools_Folder_Import"); - - spellCheckAction = new QAction(tr("Spell Check"), this); - spellCheckAction.setToolTip(tr("Check for spelling errors")); - spellCheckAction.triggered.connect(parent.browserWindow, "spellCheckClicked()"); - setupShortcut(spellCheckAction, "Tools_Spell_Check"); - - encryptDatabaseAction = new QAction(tr("Encrypt Database"), this); - encryptDatabaseAction.setToolTip(tr("Encrypt the database upon shutdown")); - encryptDatabaseAction.triggered.connect(parent, "doDatabaseEncrypt()"); - setupShortcut(encryptDatabaseAction, "Tools_Database_Encrypt"); - if (Global.cipherPassword != null && Global.cipherPassword != "") { - encryptDatabaseAction.setText("Decrypt Database"); - encryptDatabaseAction.setToolTip("Decrypt the database upon shutdown"); - } - - loggerAction = new QAction(tr("Logs"), this); - loggerAction.setToolTip(tr("Show the detailed application log")); - loggerAction.triggered.connect(parent, "logger()"); - setupShortcut(loggerAction, "About_Log"); - - releaseAction = new QAction(tr("Release Notes"), this); - releaseAction.setToolTip(tr("Release notes")); - releaseAction.triggered.connect(parent, "releaseNotes()"); - setupShortcut(releaseAction, "About_Release_Notes"); - - checkForUpdates = new QAction(tr("Check For Updates"), this); - checkForUpdates.setToolTip(tr("Check for newer versions")); - checkForUpdates.triggered.connect(parent, "checkForUpdates()"); - setupShortcut(checkForUpdates, "Help_Check_For_Updates"); - - aboutAction = new QAction(tr("About"), this); - aboutAction.setToolTip(tr("About NixNote")); - aboutAction.triggered.connect(parent, "about()"); - setupShortcut(aboutAction, "About_About"); - - setupMenuBar(); - } - - public void setupMenuBar() { - fileMenu = addMenu(tr("&File")); - - noteMenu = fileMenu.addMenu(tr("&Note")); - notebookMenu = fileMenu.addMenu(tr("Notebook")); - tagMenu = fileMenu.addMenu(tr("Tag")); - savedSearchMenu = fileMenu.addMenu(tr("Saved Searches")); - fileMenu.addSeparator(); - fileMenu.addAction(emailAction); - fileMenu.addAction(printAction); - fileMenu.addSeparator(); - fileMenu.addAction(noteImportAction); - fileMenu.addAction(noteExportAction); - fileMenu.addAction(backupAction); - fileMenu.addAction(restoreAction); - fileMenu.addSeparator(); - fileMenu.addAction(selectiveSyncAction); - //fileMenu.addAction(parent.browserWindow.browser.downloadAttachment); - fileMenu.addSeparator(); - fileMenu.addAction(emptyTrashAction); - fileMenu.addAction(exitAction); - - editMenu = addMenu(tr("&Edit")); - editMenu.addAction(editFind); - editMenu.addSeparator(); - editMenu.addAction(editUndo); - editMenu.addAction(editRedo); - editMenu.addSeparator(); - editMenu.addAction(editCut); - editMenu.addAction(editCopy); - editMenu.addAction(editPaste); - editMenu.addAction(editPasteWithoutFormat); - editMenu.addSeparator(); - editMenu.addAction(settingsAction); - - viewMenu = addMenu(tr("&View")); - viewMenu.addAction(noteAttributes); - viewMenu.addAction(viewSource); - viewMenu.addSeparator(); - viewMenu.addAction(wideListView); - viewMenu.addAction(narrowListView); - viewMenu.addAction(thumbnailView); - viewMenu.addSeparator(); - viewMenu.addAction(hideNoteList); - viewMenu.addAction(hideSearch); - viewMenu.addAction(hideQuota); - viewMenu.addAction(hideZoom); - viewMenu.addAction(hideNotebooks); - viewMenu.addAction(hideTags); - viewMenu.addAction(hideAttributes); - viewMenu.addAction(hideSavedSearches); - viewMenu.addAction(hideTrash); - viewMenu.addAction(showEditorBar); - viewMenu.addAction(hideLeftSide); - - formatMenu = addMenu(tr("F&ormat")); - formatMenu.addAction(formatBold); - formatMenu.addAction(formatUnderline); - formatMenu.addAction(formatItalic); - formatMenu.addSeparator(); - formatMenu.addAction(formatStrikethrough); - formatMenu.addAction(horizontalLineAction); - formatMenu.addSeparator(); - formatMenu.addAction(formatSuperscript); - formatMenu.addAction(formatSubscript); - formatMenu.addSeparator(); - //formatMenu.addAction(parent.browserWindow.browser.todoAction); - //formatMenu.addAction(parent.browserWindow.browser.encryptAction); - //formatMenu.addAction(parent.browserWindow.browser.insertLinkAction); - //formatMenu.addAction(parent.browserWindow.browser.insertQuickLinkAction); - //formatMenu.addAction(parent.browserWindow.browser.insertLatexAction); - formatMenu.addMenu(parent.browserWindow.browser.tableMenu); - formatMenu.addMenu(parent.browserWindow.browser.imageMenu); - formatMenu.addSeparator(); - - alignMenu = formatMenu.addMenu(tr("Alignment")); - alignMenu.addAction(alignLeftAction); - alignMenu.addAction(alignCenterAction); - alignMenu.addAction(alignRightAction); - - listMenu = formatMenu.addMenu(tr("Lists")); - listMenu.addAction(formatBulletList); - listMenu.addAction(formatNumberList); - indentMenu = formatMenu.addMenu(tr("Indent")); - indentMenu.addAction(indentAction); - indentMenu.addAction(outdentAction); - - noteAttributes.setCheckable(true); - noteMenu.addAction(noteAdd); - noteMenu.addAction(noteDelete); - //noteMenu.addAction(noteCopyAsUrlAction); - noteMenu.addAction(noteReindex); - noteMenu.addSeparator(); - noteMenu.addAction(noteTags); - noteMenu.addAction(noteRestoreAction); - noteMenu.addSeparator(); - noteMenu.addAction(noteOnlineHistoryAction); - noteMenu.addAction(noteDuplicateAction); - noteMenu.addAction(noteMergeAction); - - - notebookMenu.addAction(notebookAddAction); - notebookMenu.addAction(notebookEditAction); - notebookMenu.addAction(notebookDeleteAction); - notebookMenu.addSeparator(); - notebookMenu.addAction(notebookPublishAction); - notebookMenu.addAction(notebookShareAction); - notebookMenu.addSeparator(); - notebookMenu.addAction(notebookStackAction); - notebookMenu.addAction(notebookCloseAction); - notebookMenu.addSeparator(); - notebookMenu.addAction(notebookIconAction); - - tagMenu.addAction(tagAddAction); - tagMenu.addAction(tagEditAction); - tagMenu.addAction(tagDeleteAction); - tagMenu.addAction(tagMergeAction); - tagMenu.addSeparator(); - tagMenu.addAction(tagIconAction); - - savedSearchMenu.addAction(savedSearchAddAction); - savedSearchMenu.addAction(savedSearchEditAction); - savedSearchMenu.addAction(savedSearchDeleteAction); - savedSearchMenu.addSeparator(); - savedSearchMenu.addAction(savedSearchIconAction); - -// onlineMenu = addMenu(tr("&Online")); -// onlineMenu.addAction(synchronizeAction); -// onlineMenu.addAction(connectAction); -// onlineMenu.addSeparator(); -// onlineMenu.addAction(noteOnlineHistoryAction); -// onlineMenu.addAction(selectiveSyncAction); - - toolsMenu = addMenu(tr("&Tools")); - toolsMenu.addAction(synchronizeAction); - toolsMenu.addAction(connectAction); - toolsMenu.addSeparator(); - toolsMenu.addAction(spellCheckAction); - toolsMenu.addAction(accountAction); - toolsMenu.addAction(fullReindexAction); - toolsMenu.addAction(disableIndexing); -// toolsMenu.addAction(compactAction); - toolsMenu.addSeparator(); - toolsMenu.addAction(encryptDatabaseAction); - toolsMenu.addAction(databaseStatusAction); - toolsMenu.addSeparator(); - toolsMenu.addAction(folderImportAction); - - helpMenu = addMenu(tr("&Help")); - helpMenu.addAction(releaseAction); - helpMenu.addAction(checkForUpdates); - helpMenu.addAction(loggerAction); - helpMenu.addSeparator(); - helpMenu.addAction(aboutAction); - - addMenu(fileMenu); - addMenu(editMenu); - addMenu(viewMenu); - addMenu(formatMenu); -// addMenu(onlineMenu); - addMenu(toolsMenu); - addMenu(helpMenu); - - } - - public void setupToolBarVisible() { - viewMenu.addAction(parent.toolBar.toggleViewAction()); - setupShortcut(parent.toolBar.toggleViewAction(), "View_Toolbar"); - } - - private void setupShortcut(QAction action, String text) { - if (!Global.shortcutKeys.containsAction(text)) - return; - action.setShortcut(Global.shortcutKeys.getShortcut(text)); - } - -} +/* + * This file is part of NixNote + * Copyright 2009 Randy Baumgarte + * + * This file may be licensed under the terms of of the + * GNU General Public License Version 2 (the ``GPL''). + * + * Software distributed under the License is distributed + * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the GPL for the specific language + * governing rights and limitations. + * + * You should have received a copy of the GPL along with this + * program. If not, go to http://www.gnu.org/licenses/gpl.html + * or write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * +*/ +package cx.fbn.nevernote.gui; + +import com.trolltech.qt.gui.QAction; +import com.trolltech.qt.gui.QMenu; +import com.trolltech.qt.gui.QMenuBar; + +import cx.fbn.nevernote.Global; +import cx.fbn.nevernote.NeverNote; + +public class MainMenuBar extends QMenuBar { + + private final NeverNote parent; + public QAction printAction; // Action when a user selects Print from the file menu + public QAction connectAction; // Connect/Disconnect to Evernote + public QAction fullReindexAction; // Action when a user wants to reindex the entire database + public QAction synchronizeAction; // Synchronize data with Evernote + public QAction selectiveSyncAction; // Specify which notebooks or tags to ignore + public QAction settingsAction; // Show user config settings + public QAction emailAction; // Action when a user selects "email" + public QAction backupAction; // Backup the database + public QAction restoreAction; // Restore from a backup + public QAction emptyTrashAction; // Action when a user wants to clear the trash file + public QAction exitAction; // Action when user selects "exit" + public QAction aboutAction; // Action when a user selects "About" + public QAction checkForUpdates; // Check for newer versions + public QAction loggerAction; // Action when a user selects "Log" + public QAction releaseAction; // Release notes + + public QAction noteAdd; // Add a note + public QAction noteAttributes; // Action when a user selects note attributes + public QAction noteTags; // Assign a note tags + public QAction noteDelete; // Delete the current note + public QAction noteRestoreAction; // Restore a note + public QAction noteReindex; // Action when a user wants to reindex a note + public QAction noteDuplicateAction; // Duplicate an existing note + public QAction noteMergeAction; // Merge notes + public QAction noteExportAction; // Export notes + public QAction noteImportAction; // Import notes + public QAction noteCopyAsUrlAction; // Copy the note as a URL + // ICHANGED + public QAction noteOpenNewTab; // 新しいタブで開く + public QAction noteAddNewTab; // 新しいタブでノート追加 + + public QAction editFind; // find text in the current note + public QAction editUndo; // Undo last change + public QAction editRedo; // Redo last change + public QAction editCut; // Cut selected text + public QAction editPaste; // Paste selected text + public QAction editPasteWithoutFormat; // Paste selected text + public QAction editCopy; // Copy selected text; + + public QAction wideListView; // View with list on the top + public QAction narrowListView; // View with list on the side + public QAction thumbnailView; // view thumbnails + public QAction hideSavedSearches; // show/hide saved searches + public QAction hideZoom; // show/hide the zoom spinner + public QAction hideSearch; // Show/hide the search window + public QAction hideQuota; // show/hide the quota window + public QAction hideNotebooks; // show/hide notebooks + public QAction hideTags; // show/hide tags + public QAction hideAttributes; // show/hide note information + public QAction hideTrash; // show/hide trash tree + public QAction hideNoteList; // show/hide the list of notes + public QAction showEditorBar; // show/hide the editor button bar + public QAction hideLeftSide; // Hide the entire left side + public QAction viewSource; // View the source HTML of a note + + public QAction formatBold; // Bold selected text + public QAction formatItalic; // Italics selected text + public QAction formatUnderline; // Underline selected text + public QAction formatStrikethrough; // Strikethrough selected text + public QAction formatSuperscript; // Superscript selected text + public QAction formatSubscript; // Subscript selected text + public QAction formatNumberList; // insert a numbered list + public QAction formatBulletList; // insert a bulleted list; + public QAction alignLeftAction; // Left justify text + public QAction alignRightAction; // Right justify text + public QAction alignCenterAction; // Center text + public QAction horizontalLineAction; // Insert a horizontal line + public QAction indentAction; // Indent + public QAction outdentAction; // outdent menu action + + public QAction noteOnlineHistoryAction; // Pull note history from Evernote + + public QAction accountAction; // Account dialog box action + public QAction disableIndexing; // put indexing on hold. +// public QAction compactAction; // free unused space in the database + public QAction databaseStatusAction; // Current database status + public QAction folderImportAction; // Automatically import files + public QAction spellCheckAction; // Spell checker + public QAction encryptDatabaseAction; // Encrypt the local database + + public QAction notebookEditAction; // Edit the selected notebook + public QAction notebookAddAction; // Add a new notebook + public QAction notebookDeleteAction; // Delete a notebook + public QAction notebookPublishAction; // Publish a notebook + public QAction notebookShareAction; // Share a notebook with others + public QAction notebookCloseAction; // Close notebooks + public QAction notebookIconAction; // Change the icon + public QAction notebookStackAction; // Stack/Unstack the icon. + + public QAction savedSearchAddAction; // Add a saved search + public QAction savedSearchEditAction; // Edit a saved search + public QAction savedSearchDeleteAction; // Delete a saved search + public QAction savedSearchIconAction; // Change a saved search icon + + public QAction tagEditAction; // Edit a tag + public QAction tagAddAction; // Add a tag + public QAction tagDeleteAction; // Delete a tag + public QAction tagIconAction; // Change the icon + public QAction tagMergeAction; // Merge tags + + //************************************************************************** + //* Menu Bar Titles + //************************************************************************** + + private QMenu fileMenu; // File menu + private QMenu noteMenu; // Note menu + private QMenu notebookMenu; // Notebook menu + private QMenu tagMenu; // Tag menu + private QMenu savedSearchMenu; // Saved Searches + + private QMenu editMenu; // Edit menu + + private QMenu formatMenu; // Text format menu + private QMenu viewMenu; // show/hide stuff + private QMenu listMenu; // bullet or numbered list + private QMenu indentMenu; // indent or outdent menu + private QMenu alignMenu; // Left/Right/Center justify + +// private QMenu onlineMenu; // View online stuff (if connected) + + private QMenu toolsMenu; // Tools menu + + private QMenu helpMenu; + + // ICHANGED + private QMenu tableMenu; + private QMenu imageMenu; + private BrowserWindow prevBW; + + public MainMenuBar(NeverNote p) { + parent = p; + + // ICHANGED + prevBW = parent.browserWindow; + + fullReindexAction = new QAction(tr("Reindex Database"), this); + fullReindexAction.setToolTip(tr("Reindex all notes")); + fullReindexAction.triggered.connect(parent, "fullReindex()"); + setupShortcut(fullReindexAction, "Tools_Reindex_Database"); + + printAction = new QAction(tr("Print"), this); + printAction.setToolTip(tr("Print the current note")); + printAction.triggered.connect(parent, "printNote()"); + setupShortcut(printAction, "File_Print"); + + emailAction = new QAction(tr("Email"), this); + emailAction.setToolTip(tr("Email the current note")); + emailAction.triggered.connect(parent, "emailNote()"); + setupShortcut(emailAction, "File_Email"); + + backupAction = new QAction(tr("Backup Database"), this); + backupAction.setToolTip(tr("Backup the current database")); + backupAction.triggered.connect(parent, "databaseBackup()"); + setupShortcut(backupAction, "File_Backup"); + + restoreAction = new QAction(tr("Restore Database"), this); + restoreAction.setToolTip(tr("Restore the database from a backup")); + restoreAction.triggered.connect(parent, "databaseRestore()"); + setupShortcut(restoreAction, "File_Restore"); + + emptyTrashAction = new QAction(tr("Empty Trash"), this); + emptyTrashAction.setToolTip(tr("Empty the trash folder")); + emptyTrashAction.triggered.connect(parent, "emptyTrash()"); + setupShortcut(emptyTrashAction, "File_Empty_Trash"); + + noteRestoreAction = new QAction(tr("Restore"), this); + noteRestoreAction.setToolTip(tr("Restore a deleted file from the trash")); + noteRestoreAction.triggered.connect(parent, "restoreNote()"); + noteRestoreAction.setVisible(false); + setupShortcut(noteRestoreAction, "File_Note_Restore"); + + settingsAction = new QAction(tr("Preferences"), this); + settingsAction.setToolTip(tr("Program settings")); + settingsAction.triggered.connect(parent, "settings()"); + setupShortcut(settingsAction, "Edit_Preferences"); + + exitAction = new QAction(tr("Exit"), this); + exitAction.setToolTip(tr("Close the program")); + exitAction.triggered.connect(parent, "closeNeverNote()"); + exitAction.setShortcut("Ctrl+Q"); + setupShortcut(exitAction, "File_Exit"); + + noteAttributes = new QAction(tr("Extended Information"), this); + noteAttributes.setToolTip(tr("Show/Hide extended note attributes")); + noteAttributes.triggered.connect(parent, "toggleNoteInformation()"); + noteAttributes.setShortcut("F8"); + setupShortcut(noteAttributes, "View_Extended_Information"); + + noteReindex = new QAction(tr("Reindex"), this); + noteReindex.setToolTip(tr("Reindex this note")); + noteReindex.triggered.connect(parent, "reindexNote()"); + setupShortcut(noteReindex, "File_Note_Reindex"); + + noteDuplicateAction = new QAction(tr("Duplicate"), this); + noteDuplicateAction.setToolTip(tr("Duplicate this note")); + noteDuplicateAction.triggered.connect(parent, "duplicateNote()"); + setupShortcut(noteReindex, "File_Note_Duplicate"); + + noteMergeAction = new QAction(tr("Merge Notes"), this); + noteMergeAction.setToolTip(tr("Merge Multiple notes")); + noteMergeAction.triggered.connect(parent, "mergeNotes()"); + setupShortcut(noteMergeAction, "File_Note_Merge"); + + noteExportAction = new QAction(tr("Export Selected Notes"), this); + noteExportAction.setToolTip(tr("Export selected notes")); + noteExportAction.triggered.connect(parent, "exportNotes()"); + setupShortcut(noteExportAction, "File_Note_Export"); + + noteCopyAsUrlAction = new QAction(tr("Copy as URL"), this); + noteCopyAsUrlAction.setToolTip(tr("Copy as URL")); + noteCopyAsUrlAction.triggered.connect(parent, "copyAsUrlClicked()"); + setupShortcut(noteCopyAsUrlAction, "Note_Copy_As_Url"); + + noteImportAction = new QAction(tr("Import Notes"), this); + noteImportAction.setToolTip(tr("Import notes")); + noteImportAction.triggered.connect(parent, "importNotes()"); + setupShortcut(noteImportAction, "File_Note_Import"); + + noteAdd = new QAction(tr("Add"), this); + noteAdd.setToolTip(tr("Add a new note")); + noteAdd.triggered.connect(parent, "addNote()"); + setupShortcut(noteAdd, "File_Note_Add"); + + noteTags = new QAction(tr("Modify Tags"), this); + noteTags.setToolTip(tr("Change the tags assigned to this note")); + noteTags.triggered.connect(parent.browserWindow, "modifyTags()"); + setupShortcut(noteTags, "File_Note_Modify_Tags"); + + noteDelete = new QAction(tr("Delete"), this); + noteDelete.setToolTip(tr("Delete this note")); + noteDelete.triggered.connect(parent, "deleteNote()"); + setupShortcut(noteDelete, "File_Note_Delete"); + + // ICHANGED 新しいタブで開くアクション生成 + noteOpenNewTab = new QAction(tr("Open in New Tab"), this); + noteOpenNewTab.setToolTip(tr("Open this note in new tab")); + noteOpenNewTab.triggered.connect(parent, "openNewTab()"); + setupShortcut(noteOpenNewTab, "File_Note_Open_New_Tab"); + + // ICHANGED 新しいタブでノート追加アクション生成 + noteAddNewTab = new QAction(tr("Add in New Tab"), this); + noteAddNewTab.setToolTip(tr("Add a new note in new tab")); + noteAddNewTab.triggered.connect(parent, "noteAddNewTab()"); + setupShortcut(noteAddNewTab, "File_Note_Add_New_Tab"); + + editFind = new QAction(tr("Find In Note"), this); + editFind.setToolTip(tr("Find a string in the current note")); + editFind.triggered.connect(parent, "findText()"); + setupShortcut(editFind, "Edit_Find_In_Note"); + //editFind.setShortcut("Ctrl+F"); + + editUndo = new QAction(tr("Undo"), this); + editUndo.setToolTip(tr("Undo")); + editUndo.triggered.connect(parent.browserWindow, "undoClicked()"); + setupShortcut(editUndo, "Edit_Undo"); + //editUndo.setShortcut("Ctrl+Z"); + + editRedo = new QAction(tr("Redo"), this); + editRedo.setToolTip(tr("Redo")); + editRedo.triggered.connect(parent.browserWindow, "redoClicked()"); + setupShortcut(editRedo, "Edit_Redo"); + //editRedo.setShortcut("Ctrl+Y"); + + editCut = new QAction(tr("Cut"), this); + editCut.setToolTip(tr("Cut")); + editCut.triggered.connect(parent.browserWindow, "cutClicked()"); + setupShortcut(editCut, "Edit_Cut"); + //editCut.setShortcut("Ctrl+X"); + + editCopy = new QAction(tr("Copy"), this); + editCopy.setToolTip(tr("Copy")); + editCopy.triggered.connect(parent.browserWindow, "copyClicked()"); + setupShortcut(editCopy, "Edit_Copy"); + //editCopy.setShortcut("Ctrl+C"); + + + editPaste = new QAction(tr("Paste"), this); + editPaste.setToolTip(tr("Paste")); + editPaste.triggered.connect(parent.browserWindow, "pasteClicked()"); + setupShortcut(editPaste, "Edit_Paste"); + + editPasteWithoutFormat = new QAction(tr("Paste Without Formatting"), this); + editPasteWithoutFormat.setToolTip(tr("Paste Without Formatting")); + editPasteWithoutFormat.triggered.connect(parent.browserWindow, "pasteWithoutFormattingClicked()"); + setupShortcut(editPasteWithoutFormat, "Edit_Paste_Without_Formatting"); + + hideNoteList = new QAction(tr("Show Note List"), this); + hideNoteList.setToolTip(tr("Show/Hide Note List")); + hideNoteList.triggered.connect(parent, "toggleNoteListWindow()"); + hideNoteList.setCheckable(true); + hideNoteList.setChecked(true); + setupShortcut(hideNoteList, "View_Show_Note_List"); + + hideTags = new QAction(tr("Show Tags"), this); + hideTags.setToolTip(tr("Show/Hide Tags")); + hideTags.triggered.connect(parent, "toggleTagWindow()"); + hideTags.setCheckable(true); + hideTags.setChecked(true); + setupShortcut(hideTags, "View_Show_Tags"); + + hideNotebooks = new QAction(tr("Show Notebooks"), this); + hideNotebooks.setToolTip(tr("Show/Hide Notebooks")); + hideNotebooks.triggered.connect(parent, "toggleNotebookWindow()"); + hideNotebooks.setCheckable(true); + hideNotebooks.setChecked(true); + setupShortcut(hideNotebooks, "View_Show_Notebooks"); + + hideZoom = new QAction(tr("Show Zoom"), this); + hideZoom.setToolTip(tr("Show/Hide Zoom")); + hideZoom.triggered.connect(parent, "toggleZoomWindow()"); + hideZoom.setCheckable(true); + hideZoom.setChecked(true); + setupShortcut(hideZoom, "View_Show_Zoom"); + + hideQuota = new QAction(tr("Show Quota Bar"), this); + hideQuota.setToolTip(tr("Show/Hide Quota")); + hideQuota.triggered.connect(parent, "toggleQuotaWindow()"); + hideQuota.setCheckable(true); + hideQuota.setChecked(true); + setupShortcut(hideQuota, "View_Show_Quota"); + + hideSearch = new QAction(tr("Show Search Box"), this); + hideSearch.setToolTip(tr("Show/Hide Search Box")); + hideSearch.triggered.connect(parent, "toggleSearchWindow()"); + hideSearch.setCheckable(true); + hideSearch.setChecked(true); + setupShortcut(hideSearch, "View_Show_Search"); + + wideListView = new QAction(tr("Wide List View"), this); + wideListView.setToolTip(tr("Wide List View")); + wideListView.setCheckable(true); + wideListView.changed.connect(parent, "wideListView()"); + setupShortcut(wideListView, "View_Wide_List"); + + narrowListView = new QAction(tr("Narrow List View"), this); + narrowListView.setToolTip(tr("Narrow List View")); + narrowListView.setCheckable(true); + narrowListView.changed.connect(parent, "narrowListView()"); + setupShortcut(narrowListView, "View_Narrow_List"); + + thumbnailView = new QAction(tr("Preview"), this); + thumbnailView.setToolTip(tr("Preview Notes")); + thumbnailView.triggered.connect(parent, "thumbnailView()"); + setupShortcut(thumbnailView, "View_Thumbnail"); + + hideSavedSearches = new QAction(tr("Show Saved Searches"), this); + hideSavedSearches.setToolTip(tr("Show/Hide Saved Searches")); + hideSavedSearches.triggered.connect(parent, "toggleSavedSearchWindow()"); + hideSavedSearches.setCheckable(true); + hideSavedSearches.setChecked(true); + setupShortcut(hideSavedSearches, "View_Show_SavedSearches"); + + hideAttributes = new QAction(tr("Show Attribute Searches"), this); + hideAttributes.setToolTip(tr("Show/Hide Attribute Searches")); + hideAttributes.triggered.connect(parent, "toggleAttributesWindow()"); + hideAttributes.setCheckable(true); + hideAttributes.setChecked(true); + setupShortcut(hideAttributes, "View_Show_Attribute_Searches"); + + hideTrash = new QAction(tr("Show Trash"), this); + hideTrash.setToolTip(tr("Show/Hide Trash Tree")); + hideTrash.triggered.connect(parent, "toggleTrashWindow()"); + hideTrash.setCheckable(true); + hideTrash.setChecked(true); + setupShortcut(hideTrash, "View_Show_Trash"); + + + showEditorBar = new QAction(tr("Show Editor Button Bar"), this); + showEditorBar.setToolTip(tr("Show/Hide Editor Button Bar")); + showEditorBar.triggered.connect(parent, "toggleEditorButtonBar()"); + showEditorBar.setCheckable(true); + showEditorBar.setChecked(true); + setupShortcut(showEditorBar, "View_Show_Editor_Button_Bar"); + + + hideLeftSide = new QAction(tr("Hide Left Side Panels"), this); + hideLeftSide.setToolTip(tr("Hide The Entire Left Side")); + hideLeftSide.triggered.connect(parent, "toggleLeftSide()"); + hideLeftSide.setCheckable(true); + hideLeftSide.setChecked(false); + setupShortcut(hideLeftSide, "View_Show_Left_Side"); + //hideLeftSide.setShortcut("F11"); + + viewSource = new QAction(tr("View Source"), this); + viewSource.setToolTip(tr("View the source HTML for a note")); + viewSource.triggered.connect(parent, "viewSource()"); + viewSource.setCheckable(true); + viewSource.setChecked(false); + setupShortcut(viewSource, "View_Source"); + //hideLeftSide.setShortcut("F11"); + + alignLeftAction = new QAction(tr("Left"), this); + alignLeftAction.setToolTip(tr("Left Align")); + alignLeftAction.triggered.connect(parent.browserWindow, "justifyLeftClicked()"); + setupShortcut(alignLeftAction, "Format_Alignment_Left"); + //alignLeftAction.setShortcut("Ctrl+L"); + + alignRightAction = new QAction(tr("Right"), this); + alignRightAction.setToolTip(tr("Right Align")); + alignRightAction.triggered.connect(parent.browserWindow, "justifyRightClicked()"); + setupShortcut(alignRightAction, "Format_Alignment_Right"); + //alignRightAction.setShortcut("Ctrl+R"); + + alignCenterAction = new QAction(tr("Center"), this); + alignCenterAction.setToolTip(tr("Center Align")); + alignCenterAction.triggered.connect(parent.browserWindow, "justifyCenterClicked()"); + setupShortcut(alignCenterAction, "Format_Alignment_Center"); + //alignCenterAction.setShortcut("Ctrl+C"); + + formatBold = new QAction(tr("Bold"), this); + formatBold.setToolTip(tr("Bold")); + formatBold.triggered.connect(parent.browserWindow, "boldClicked()"); + setupShortcut(formatBold, "Format_Bold"); + //formatBold.setShortcut("Ctrl+B"); + + formatItalic = new QAction(tr("Italic"), this); + formatItalic.setToolTip(tr("Italic")); + formatItalic.triggered.connect(parent.browserWindow, "italicClicked()"); + setupShortcut(formatItalic, "Format_Italic"); + //formatItalic.setShortcut("Ctrl+I"); + + formatUnderline = new QAction(tr("Underline"), this); + formatUnderline.setToolTip(tr("Underline")); + formatUnderline.triggered.connect(parent.browserWindow, "underlineClicked()"); + setupShortcut(formatUnderline, "Format_Underline"); +// formatUnderline.setShortcut("Ctrl+U"); + + + formatSuperscript = new QAction(tr("Superscript"), this); + formatSuperscript.setToolTip(tr("Superscript")); + formatSuperscript.triggered.connect(parent.browserWindow, "superscriptClicked()"); + setupShortcut(formatSuperscript, "Format_Superscript"); + + + formatSubscript = new QAction(tr("Subscript"), this); + formatSubscript.setToolTip(tr("Subscript")); + formatSubscript.triggered.connect(parent.browserWindow, "subscriptClicked()"); + setupShortcut(formatSubscript, "Format_Subscript"); + + + formatStrikethrough = new QAction(tr("Strikethrough"), this); + formatStrikethrough.setToolTip(tr("Strikethrough")); + formatStrikethrough.triggered.connect(parent.browserWindow, "strikethroughClicked()"); + setupShortcut(formatStrikethrough, "Format_Strikethrough"); + + horizontalLineAction = new QAction(tr("Horizontal Line"), this); + horizontalLineAction.setToolTip(tr("Horizontal Line")); + horizontalLineAction.triggered.connect(parent.browserWindow, "hlineClicked()"); + setupShortcut(horizontalLineAction, "Format_Horizontal_Line"); + + formatBulletList = new QAction(tr("Bulleted List"), this); +// formatBulletList.setText(tr("Numbered List")); + formatBulletList.triggered.connect(parent.browserWindow, "bulletListClicked()"); + setupShortcut(formatBulletList, "Format_List_Bullet"); +// formatBulletList.setShortcut("Ctrl+Shift+B"); + + formatNumberList = new QAction(tr("Numbered List"), this); + formatNumberList.setText(tr("Numbered list")); + formatNumberList.triggered.connect(parent.browserWindow, "numberListClicked()"); + setupShortcut(formatNumberList, "Format_List_Numbered"); +// formatNumberList.setShortcut("Ctrl+Shift+O"); + + indentAction = new QAction(tr(">> Increase"), this); + indentAction.setText(tr(">> Increase")); + indentAction.triggered.connect(parent.browserWindow, "indentClicked()"); + setupShortcut(indentAction, "Format_Indent_Increase"); + //indentAction.setShortcut("Ctrl+M"); + + outdentAction = new QAction(tr("<< Decrease"), this); + outdentAction.setText(tr("<< Decrease")); + outdentAction.triggered.connect(parent.browserWindow, "outdentClicked()"); + setupShortcut(outdentAction, "Format_Indent_Decrease"); + //outdentAction.setShortcut("Ctrl+Shift+M"); + + notebookAddAction = new QAction(tr("Add"), this); + notebookAddAction.triggered.connect(parent, "addNotebook()"); + setupShortcut(notebookAddAction, "File_Notebook_Add"); + + notebookEditAction = new QAction(tr("Edit"), this); + notebookEditAction.setEnabled(false); + notebookEditAction.triggered.connect(parent, "editNotebook()"); + setupShortcut(notebookEditAction, "File_Notebook_Edit"); + + notebookDeleteAction = new QAction(tr("Delete"), this); + notebookDeleteAction.setEnabled(false); + notebookDeleteAction.triggered.connect(parent, "deleteNotebook()"); + setupShortcut(notebookDeleteAction, "File_Notebook_Delete"); + + notebookPublishAction = new QAction(tr("Share With The World"), this); + notebookPublishAction.setEnabled(false); + notebookPublishAction.setVisible(false); + notebookPublishAction.triggered.connect(parent, "publishNotebook()"); + setupShortcut(notebookPublishAction, "File_Notebook_Publish"); + + notebookShareAction = new QAction(tr("Share With Individuals"), this); + notebookShareAction.setEnabled(false); + notebookShareAction.setVisible(false); + notebookShareAction.triggered.connect(parent, "shareNotebook()"); + setupShortcut(notebookShareAction, "File_Notebook_Share"); + + + notebookCloseAction = new QAction(tr("Open/Close Notebooks"), this); + notebookCloseAction.setEnabled(true); + notebookCloseAction.triggered.connect(parent, "closeNotebooks()"); + setupShortcut(notebookCloseAction, "File_Notebook_Close"); + + notebookIconAction = new QAction(tr("Change Icon"), this); + notebookIconAction.setEnabled(false); + notebookIconAction.triggered.connect(parent, "setNotebookIcon()"); + setupShortcut(notebookIconAction, "File_Notebook_Icon"); + + notebookStackAction = new QAction(tr("Set Stack"), this); + notebookStackAction.setEnabled(false); + notebookStackAction.triggered.connect(parent, "stackNotebook()"); + setupShortcut(notebookStackAction, "File_Notebook_Stack"); + + tagAddAction = new QAction(tr("Add"),this); + tagAddAction.triggered.connect(parent, "addTag()"); + setupShortcut(tagAddAction, "File_Tag_Add"); + + tagEditAction = new QAction(tr("Edit"), this); + tagEditAction.triggered.connect(parent, "editTag()"); + tagEditAction.setEnabled(false); + setupShortcut(tagEditAction, "File_Tag_Edit"); + + tagDeleteAction = new QAction(tr("Delete"), this); + tagDeleteAction.triggered.connect(parent, "deleteTag()"); + tagDeleteAction.setEnabled(false); + setupShortcut(tagDeleteAction, "File_Tag_Delete"); + + tagIconAction = new QAction(tr("Change Icon"), this); + tagIconAction.triggered.connect(parent, "setTagIcon()"); + tagIconAction.setEnabled(false); + setupShortcut(tagIconAction, "File_Tag_Icon"); + + tagMergeAction = new QAction(tr("Merge Tags"), this); + tagMergeAction.triggered.connect(parent, "mergeTags()"); + tagMergeAction.setEnabled(false); + setupShortcut(tagMergeAction, "File_Tag_Merge"); + + savedSearchAddAction = new QAction(tr("Add"),this); + savedSearchAddAction.triggered.connect(parent, "addSavedSearch()"); + setupShortcut(savedSearchAddAction, "File_SavedSearch_Add"); + + savedSearchEditAction = new QAction(tr("Edit"), this); + savedSearchEditAction.triggered.connect(parent, "editSavedSearch()"); + savedSearchEditAction.setEnabled(false); + setupShortcut(savedSearchEditAction, "File_SavedSearch_Edit"); + + savedSearchDeleteAction = new QAction(tr("Delete"), this); + savedSearchDeleteAction.triggered.connect(parent, "deleteSavedSearch()"); + savedSearchDeleteAction.setEnabled(false); + setupShortcut(savedSearchDeleteAction, "File_SavedSearch_Delete"); + + savedSearchIconAction = new QAction(tr("Change Icon"), this); + savedSearchIconAction.triggered.connect(parent, "setSavedSearchIcon()"); + savedSearchIconAction.setEnabled(false); + setupShortcut(savedSearchIconAction, "File_SavedSearch_Icon"); + + connectAction = new QAction(tr("Connect"), this); + connectAction.setToolTip("Connect to Evernote"); + connectAction.triggered.connect(parent, "remoteConnect()"); + setupShortcut(connectAction, "Tools_Connect"); + + synchronizeAction = new QAction(tr("Synchronize with Evernote"), this); + synchronizeAction.setToolTip("Delete all local data & get a fresh copy"); + synchronizeAction.triggered.connect(parent, "evernoteSync()"); + synchronizeAction.setEnabled(false); + setupShortcut(synchronizeAction, "Tools_Synchronize"); + //synchronizeAction.setShortcut("F9"); + + noteOnlineHistoryAction = new QAction(tr("Note History"), this); + noteOnlineHistoryAction.triggered.connect(parent, "viewNoteHistory()"); + noteOnlineHistoryAction.setEnabled(false); + setupShortcut(noteOnlineHistoryAction, "File_Note_History"); + + selectiveSyncAction = new QAction(tr("Selective Synchronize"), this); + selectiveSyncAction.setToolTip("Selectively ignore some notes"); + selectiveSyncAction.triggered.connect(parent, "setupSelectiveSync()"); + selectiveSyncAction.setEnabled(false); + setupShortcut(synchronizeAction, "File_Selective_Sync"); + + + + accountAction = new QAction(tr("Account Information"), this); + accountAction.setToolTip(tr("Account Information")); + accountAction.triggered.connect(parent, "accountInformation()"); + setupShortcut(accountAction, "Tools_Account_Information"); + +// compactAction = new QAction(tr("Compact Database"), this); +// compactAction.setToolTip(tr("Free unused database space")); +// compactAction.triggered.connect(parent, "compactDatabase()"); +// setupShortcut(compactAction, "Tools_Compact_Database"); + + databaseStatusAction = new QAction(tr("Database Status"), this); + databaseStatusAction.setToolTip(tr("Show current database information")); + databaseStatusAction.triggered.connect(parent, "databaseStatus()"); + setupShortcut(databaseStatusAction, "Tools_Database_Status"); + + + disableIndexing = new QAction(tr("Disable Note Indexing"), this); + disableIndexing.setToolTip(tr("Manually Stop Note Indexing")); + disableIndexing.triggered.connect(parent, "toggleNoteIndexing()"); + disableIndexing.setCheckable(true); + disableIndexing.setChecked(false); + setupShortcut(disableIndexing, "Tools_Disable_Note_Indexing"); + + + folderImportAction = new QAction(tr("Automatic Folder Importing"), this); + folderImportAction.setToolTip(tr("Import Files Automatically")); + folderImportAction.triggered.connect(parent, "folderImport()"); + setupShortcut(folderImportAction, "Tools_Folder_Import"); + + spellCheckAction = new QAction(tr("Spell Check"), this); + spellCheckAction.setToolTip(tr("Check for spelling errors")); + spellCheckAction.triggered.connect(parent.browserWindow, "spellCheckClicked()"); + setupShortcut(spellCheckAction, "Tools_Spell_Check"); + + encryptDatabaseAction = new QAction(tr("Encrypt Database"), this); + encryptDatabaseAction.setToolTip(tr("Encrypt the database upon shutdown")); + encryptDatabaseAction.triggered.connect(parent, "doDatabaseEncrypt()"); + setupShortcut(encryptDatabaseAction, "Tools_Database_Encrypt"); + if (Global.cipherPassword != null && Global.cipherPassword != "") { + encryptDatabaseAction.setText("Decrypt Database"); + encryptDatabaseAction.setToolTip("Decrypt the database upon shutdown"); + } + + loggerAction = new QAction(tr("Logs"), this); + loggerAction.setToolTip(tr("Show the detailed application log")); + loggerAction.triggered.connect(parent, "logger()"); + setupShortcut(loggerAction, "About_Log"); + + releaseAction = new QAction(tr("Release Notes"), this); + releaseAction.setToolTip(tr("Release notes")); + releaseAction.triggered.connect(parent, "releaseNotes()"); + setupShortcut(releaseAction, "About_Release_Notes"); + + checkForUpdates = new QAction(tr("Check For Updates"), this); + checkForUpdates.setToolTip(tr("Check for newer versions")); + checkForUpdates.triggered.connect(parent, "checkForUpdates()"); + setupShortcut(checkForUpdates, "Help_Check_For_Updates"); + // ICHANGED TODO とりあえず封印 + checkForUpdates.setEnabled(false); + + aboutAction = new QAction(tr("About"), this); + aboutAction.setToolTip(tr("About NeighborNote")); + aboutAction.triggered.connect(parent, "about()"); + setupShortcut(aboutAction, "About_About"); + + setupMenuBar(); + } + + public void setupMenuBar() { + fileMenu = addMenu(tr("&File")); + + noteMenu = fileMenu.addMenu(tr("&Note")); + notebookMenu = fileMenu.addMenu(tr("Notebook")); + tagMenu = fileMenu.addMenu(tr("Tag")); + savedSearchMenu = fileMenu.addMenu(tr("Saved Searches")); + fileMenu.addSeparator(); + fileMenu.addAction(emailAction); + fileMenu.addAction(printAction); + fileMenu.addSeparator(); + fileMenu.addAction(noteImportAction); + fileMenu.addAction(noteExportAction); + fileMenu.addAction(backupAction); + fileMenu.addAction(restoreAction); + fileMenu.addSeparator(); + fileMenu.addAction(selectiveSyncAction); + //fileMenu.addAction(parent.browserWindow.browser.downloadAttachment); + fileMenu.addSeparator(); + fileMenu.addAction(emptyTrashAction); + fileMenu.addAction(exitAction); + + editMenu = addMenu(tr("&Edit")); + editMenu.addAction(editFind); + editMenu.addSeparator(); + editMenu.addAction(editUndo); + editMenu.addAction(editRedo); + editMenu.addSeparator(); + editMenu.addAction(editCut); + editMenu.addAction(editCopy); + editMenu.addAction(editPaste); + editMenu.addAction(editPasteWithoutFormat); + editMenu.addSeparator(); + editMenu.addAction(settingsAction); + + viewMenu = addMenu(tr("&View")); + viewMenu.addAction(noteAttributes); + viewMenu.addAction(viewSource); + viewMenu.addSeparator(); + viewMenu.addAction(wideListView); + viewMenu.addAction(narrowListView); + viewMenu.addAction(thumbnailView); + viewMenu.addSeparator(); + viewMenu.addAction(hideNoteList); + viewMenu.addAction(hideSearch); + viewMenu.addAction(hideQuota); + viewMenu.addAction(hideZoom); + viewMenu.addAction(hideNotebooks); + viewMenu.addAction(hideTags); + viewMenu.addAction(hideAttributes); + viewMenu.addAction(hideSavedSearches); + viewMenu.addAction(hideTrash); + viewMenu.addAction(showEditorBar); + viewMenu.addAction(hideLeftSide); + + formatMenu = addMenu(tr("F&ormat")); + formatMenu.addAction(formatBold); + formatMenu.addAction(formatUnderline); + formatMenu.addAction(formatItalic); + formatMenu.addSeparator(); + formatMenu.addAction(formatStrikethrough); + formatMenu.addAction(horizontalLineAction); + formatMenu.addSeparator(); + formatMenu.addAction(formatSuperscript); + formatMenu.addAction(formatSubscript); + formatMenu.addSeparator(); + //formatMenu.addAction(parent.browserWindow.browser.todoAction); + //formatMenu.addAction(parent.browserWindow.browser.encryptAction); + //formatMenu.addAction(parent.browserWindow.browser.insertLinkAction); + //formatMenu.addAction(parent.browserWindow.browser.insertQuickLinkAction); + //formatMenu.addAction(parent.browserWindow.browser.insertLatexAction); + formatMenu.addMenu(parent.browserWindow.browser.tableMenu); + formatMenu.addMenu(parent.browserWindow.browser.imageMenu); + formatMenu.addSeparator(); + + // ICHANGED + // ライブラリにremoveMenu()が存在しないので、removeAction()で消せるようにTable,Imageメニューをここで再定義 + tableMenu = new QMenu(); + tableMenu.setTitle(tr("Table")); + tableMenu.addAction(parent.browserWindow.browser.insertTableAction); + tableMenu.addAction(parent.browserWindow.browser.insertTableRowAction); + tableMenu + .addAction(parent.browserWindow.browser.insertTableColumnAction); + tableMenu.addAction(parent.browserWindow.browser.deleteTableRowAction); + tableMenu + .addAction(parent.browserWindow.browser.deleteTableColumnAction); + imageMenu = new QMenu(); + imageMenu.setTitle(tr("Image")); + imageMenu.addAction(parent.browserWindow.browser.downloadImage); + imageMenu.addAction(parent.browserWindow.browser.rotateImageRight); + imageMenu.addAction(parent.browserWindow.browser.rotateImageLeft); + + alignMenu = formatMenu.addMenu(tr("Alignment")); + alignMenu.addAction(alignLeftAction); + alignMenu.addAction(alignCenterAction); + alignMenu.addAction(alignRightAction); + + listMenu = formatMenu.addMenu(tr("Lists")); + listMenu.addAction(formatBulletList); + listMenu.addAction(formatNumberList); + indentMenu = formatMenu.addMenu(tr("Indent")); + indentMenu.addAction(indentAction); + indentMenu.addAction(outdentAction); + + noteAttributes.setCheckable(true); + // ICHANGED + noteMenu.addAction(noteOpenNewTab); + + noteMenu.addAction(noteAdd); + // ICHANGED + noteMenu.addAction(noteAddNewTab); + + noteMenu.addAction(noteDelete); + //noteMenu.addAction(noteCopyAsUrlAction); + noteMenu.addAction(noteReindex); + noteMenu.addSeparator(); + noteMenu.addAction(noteTags); + noteMenu.addAction(noteRestoreAction); + noteMenu.addSeparator(); + noteMenu.addAction(noteOnlineHistoryAction); + noteMenu.addAction(noteDuplicateAction); + noteMenu.addAction(noteMergeAction); + + + notebookMenu.addAction(notebookAddAction); + notebookMenu.addAction(notebookEditAction); + notebookMenu.addAction(notebookDeleteAction); + notebookMenu.addSeparator(); + notebookMenu.addAction(notebookPublishAction); + notebookMenu.addAction(notebookShareAction); + notebookMenu.addSeparator(); + notebookMenu.addAction(notebookStackAction); + notebookMenu.addAction(notebookCloseAction); + notebookMenu.addSeparator(); + notebookMenu.addAction(notebookIconAction); + + tagMenu.addAction(tagAddAction); + tagMenu.addAction(tagEditAction); + tagMenu.addAction(tagDeleteAction); + tagMenu.addAction(tagMergeAction); + tagMenu.addSeparator(); + tagMenu.addAction(tagIconAction); + + savedSearchMenu.addAction(savedSearchAddAction); + savedSearchMenu.addAction(savedSearchEditAction); + savedSearchMenu.addAction(savedSearchDeleteAction); + savedSearchMenu.addSeparator(); + savedSearchMenu.addAction(savedSearchIconAction); + +// onlineMenu = addMenu(tr("&Online")); +// onlineMenu.addAction(synchronizeAction); +// onlineMenu.addAction(connectAction); +// onlineMenu.addSeparator(); +// onlineMenu.addAction(noteOnlineHistoryAction); +// onlineMenu.addAction(selectiveSyncAction); + + toolsMenu = addMenu(tr("&Tools")); + toolsMenu.addAction(synchronizeAction); + toolsMenu.addAction(connectAction); + toolsMenu.addSeparator(); + toolsMenu.addAction(spellCheckAction); + toolsMenu.addAction(accountAction); + toolsMenu.addAction(fullReindexAction); + toolsMenu.addAction(disableIndexing); +// toolsMenu.addAction(compactAction); + toolsMenu.addSeparator(); + toolsMenu.addAction(encryptDatabaseAction); + toolsMenu.addAction(databaseStatusAction); + toolsMenu.addSeparator(); + toolsMenu.addAction(folderImportAction); + + helpMenu = addMenu(tr("&Help")); + helpMenu.addAction(releaseAction); + helpMenu.addAction(checkForUpdates); + helpMenu.addAction(loggerAction); + helpMenu.addSeparator(); + helpMenu.addAction(aboutAction); + + addMenu(fileMenu); + addMenu(editMenu); + addMenu(viewMenu); + addMenu(formatMenu); +// addMenu(onlineMenu); + addMenu(toolsMenu); + addMenu(helpMenu); + + } + + public void setupToolBarVisible() { + viewMenu.addAction(parent.toolBar.toggleViewAction()); + setupShortcut(parent.toolBar.toggleViewAction(), "View_Toolbar"); + } + + private void setupShortcut(QAction action, String text) { + if (!Global.shortcutKeys.containsAction(text)) + return; + action.setShortcut(Global.shortcutKeys.getShortcut(text)); + } + + // ICHANGED + public void refreshTargetWindow() { + // 以前のブラウザウィンドウとの接続を切断 + noteTags.triggered.disconnect(prevBW, "modifyTags()"); + editUndo.triggered.disconnect(prevBW, "undoClicked()"); + editRedo.triggered.disconnect(prevBW, "redoClicked()"); + editCut.triggered.disconnect(prevBW, "cutClicked()"); + editCopy.triggered.disconnect(prevBW, "copyClicked()"); + editPaste.triggered.disconnect(prevBW, "pasteClicked()"); + editPasteWithoutFormat.triggered.disconnect(prevBW, + "pasteWithoutFormattingClicked()"); + + alignLeftAction.triggered.disconnect(prevBW, "justifyLeftClicked()"); + alignRightAction.triggered.disconnect(prevBW, "justifyRightClicked()"); + alignCenterAction.triggered + .disconnect(prevBW, "justifyCenterClicked()"); + formatBold.triggered.disconnect(prevBW, "boldClicked()"); + formatItalic.triggered.disconnect(prevBW, "italicClicked()"); + formatUnderline.triggered.disconnect(prevBW, "underlineClicked()"); + formatSuperscript.triggered.disconnect(prevBW, "superscriptClicked()"); + formatSubscript.triggered.disconnect(prevBW, "subscriptClicked()"); + formatStrikethrough.triggered.disconnect(prevBW, + "strikethroughClicked()"); + horizontalLineAction.triggered.disconnect(prevBW, "hlineClicked()"); + formatBulletList.triggered.disconnect(prevBW, "bulletListClicked()"); + formatNumberList.triggered.disconnect(prevBW, "numberListClicked()"); + indentAction.triggered.disconnect(prevBW, "indentClicked()"); + outdentAction.triggered.disconnect(prevBW, "outdentClicked()"); + + spellCheckAction.triggered.disconnect(prevBW, "spellCheckClicked()"); + + // 新たなブラウザウィンドウと接続 + noteTags.triggered.connect(parent.browserWindow, "modifyTags()"); + editUndo.triggered.connect(parent.browserWindow, "undoClicked()"); + editRedo.triggered.connect(parent.browserWindow, "redoClicked()"); + editCut.triggered.connect(parent.browserWindow, "cutClicked()"); + editCopy.triggered.connect(parent.browserWindow, "copyClicked()"); + editPaste.triggered.connect(parent.browserWindow, "pasteClicked()"); + editPasteWithoutFormat.triggered.connect(parent.browserWindow, + "pasteWithoutFormattingClicked()"); + + alignLeftAction.triggered.connect(parent.browserWindow, + "justifyLeftClicked()"); + alignRightAction.triggered.connect(parent.browserWindow, + "justifyRightClicked()"); + alignCenterAction.triggered.connect(parent.browserWindow, + "justifyCenterClicked()"); + formatBold.triggered.connect(parent.browserWindow, "boldClicked()"); + formatItalic.triggered.connect(parent.browserWindow, "italicClicked()"); + formatUnderline.triggered.connect(parent.browserWindow, + "underlineClicked()"); + formatSuperscript.triggered.connect(parent.browserWindow, + "superscriptClicked()"); + formatSubscript.triggered.connect(parent.browserWindow, + "subscriptClicked()"); + formatStrikethrough.triggered.connect(parent.browserWindow, + "strikethroughClicked()"); + horizontalLineAction.triggered.connect(parent.browserWindow, + "hlineClicked()"); + formatBulletList.triggered.connect(parent.browserWindow, + "bulletListClicked()"); + formatNumberList.triggered.connect(parent.browserWindow, + "numberListClicked()"); + indentAction.triggered.connect(parent.browserWindow, "indentClicked()"); + outdentAction.triggered.connect(parent.browserWindow, + "outdentClicked()"); + + spellCheckAction.triggered.connect(parent.browserWindow, + "spellCheckClicked()"); + + // メニューバーに新しいアクションを挿入 + fileMenu.insertAction(prevBW.browser.downloadAttachment, + parent.browserWindow.browser.downloadAttachment); + + formatMenu.insertAction(prevBW.browser.todoAction, + parent.browserWindow.browser.todoAction); + formatMenu.insertAction(prevBW.browser.encryptAction, + parent.browserWindow.browser.encryptAction); + formatMenu.insertAction(prevBW.browser.insertLinkAction, + parent.browserWindow.browser.insertLinkAction); + formatMenu.insertAction(prevBW.browser.insertQuickLinkAction, + parent.browserWindow.browser.insertQuickLinkAction); + formatMenu.insertAction(prevBW.browser.insertLatexAction, + parent.browserWindow.browser.insertLatexAction); + + tableMenu.insertAction(prevBW.browser.insertTableAction, + parent.browserWindow.browser.insertTableAction); + tableMenu.insertAction(prevBW.browser.insertTableRowAction, + parent.browserWindow.browser.insertTableRowAction); + tableMenu.insertAction(prevBW.browser.insertTableColumnAction, + parent.browserWindow.browser.insertTableColumnAction); + tableMenu.insertAction(prevBW.browser.deleteTableRowAction, + parent.browserWindow.browser.deleteTableRowAction); + tableMenu.insertAction(prevBW.browser.deleteTableColumnAction, + parent.browserWindow.browser.deleteTableColumnAction); + + imageMenu.insertAction(prevBW.browser.downloadImage, + parent.browserWindow.browser.downloadImage); + imageMenu.insertAction(prevBW.browser.rotateImageRight, + parent.browserWindow.browser.rotateImageRight); + imageMenu.insertAction(prevBW.browser.rotateImageLeft, + parent.browserWindow.browser.rotateImageLeft); + + // メニューバーから古いアクションを削除 + fileMenu.removeAction(prevBW.browser.downloadAttachment); + + formatMenu.removeAction(prevBW.browser.todoAction); + formatMenu.removeAction(prevBW.browser.encryptAction); + formatMenu.removeAction(prevBW.browser.insertLinkAction); + formatMenu.removeAction(prevBW.browser.insertQuickLinkAction); + formatMenu.removeAction(prevBW.browser.insertLatexAction); + + tableMenu.removeAction(prevBW.browser.insertTableAction); + tableMenu.removeAction(prevBW.browser.insertTableRowAction); + tableMenu.removeAction(prevBW.browser.insertTableColumnAction); + tableMenu.removeAction(prevBW.browser.deleteTableRowAction); + tableMenu.removeAction(prevBW.browser.deleteTableColumnAction); + + imageMenu.removeAction(prevBW.browser.downloadImage); + imageMenu.removeAction(prevBW.browser.rotateImageRight); + imageMenu.removeAction(prevBW.browser.rotateImageLeft); + + // prevBWを更新 + prevBW = parent.browserWindow; + } + +} diff --git a/src/cx/fbn/nevernote/gui/NoteTableContextMenu.java b/src/cx/fbn/nevernote/gui/NoteTableContextMenu.java new file mode 100644 index 0000000..ec8ba13 --- /dev/null +++ b/src/cx/fbn/nevernote/gui/NoteTableContextMenu.java @@ -0,0 +1,55 @@ +// ICHANGED +package cx.fbn.nevernote.gui; + +import com.trolltech.qt.core.Qt; +import com.trolltech.qt.gui.QKeyEvent; +import com.trolltech.qt.gui.QMenu; +import com.trolltech.qt.gui.QMouseEvent; + +public class NoteTableContextMenu extends QMenu { + private final TableView parent; + + public NoteTableContextMenu(TableView tableView) { + this.parent = tableView; + } + + + @Override + protected void mousePressEvent(QMouseEvent event){ + super.mousePressEvent(event); + + int x = event.x(); + int y = event.y(); + + if(x < 0 || this.width() < x){ + parent.restoreSelectedNoteInfo(); + }else if(y < 0 || this.height() < y){ + parent.restoreSelectedNoteInfo(); + } + } + + // ノートテーブルでマウス右ボタンを押してコンテキストメニューを出し、そのままコンテキストメニュー上を通過してコンテキストメニュー外でボタンを離すと + // コンテキストメニューが閉じてしまう問題への対処 + @Override + protected void mouseReleaseEvent(QMouseEvent event){ + super.mouseReleaseEvent(event); + + int x = event.x(); + int y = event.y(); + + if(x < 0 || this.width() < x){ + parent.restoreSelectedNoteInfo(); + }else if(y < 0 || this.height() < y){ + parent.restoreSelectedNoteInfo(); + } + } + + @Override + protected void keyPressEvent(QKeyEvent event){ + super.keyPressEvent(event); + + if(event.key() == Qt.Key.Key_Escape.value()){ + parent.restoreSelectedNoteInfo(); + } + } +} diff --git a/src/cx/fbn/nevernote/gui/RensoNoteList.java b/src/cx/fbn/nevernote/gui/RensoNoteList.java new file mode 100644 index 0000000..a54feb5 --- /dev/null +++ b/src/cx/fbn/nevernote/gui/RensoNoteList.java @@ -0,0 +1,289 @@ +// ICHANGED +package cx.fbn.nevernote.gui; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import com.evernote.edam.type.Note; +import com.trolltech.qt.core.QSize; +import com.trolltech.qt.core.Qt.MouseButton; +import com.trolltech.qt.gui.QAction; +import com.trolltech.qt.gui.QApplication; +import com.trolltech.qt.gui.QContextMenuEvent; +import com.trolltech.qt.gui.QListWidget; +import com.trolltech.qt.gui.QListWidgetItem; +import com.trolltech.qt.gui.QMenu; + +import cx.fbn.nevernote.Global; +import cx.fbn.nevernote.NeverNote; +import cx.fbn.nevernote.sql.DatabaseConnection; +import cx.fbn.nevernote.utilities.ApplicationLogger; + +public class RensoNoteList extends QListWidget { + private final DatabaseConnection conn; + private final ApplicationLogger logger; + private final HashMap rensoNoteListItems; + private final List rensoNoteListTrueItems; + private String rensoNotePressedItemGuid; + + private final QAction openNewTabAction; + private final QAction starAction; + private final QAction unstarAction; + private final QAction excludeNoteAction; + private final NeverNote parent; + private final QMenu menu; + private int allPointSum; + + public RensoNoteList(DatabaseConnection c, NeverNote p) { + logger = new ApplicationLogger("rensoNoteList.log"); + logger.log(logger.HIGH, "Setting up rensoNoteList"); + allPointSum = 0; + + conn = c; + this.parent = p; + rensoNoteListItems = new HashMap(); + rensoNoteListTrueItems = new ArrayList(); + + this.itemPressed.connect(this, "rensoNoteItemPressed(QListWidgetItem)"); + + // コンテキストメニュー作成 + menu = new QMenu(this); + // 新しいタブで開くアクション生成 + openNewTabAction = new QAction(tr("Open in New Tab"), this); + openNewTabAction.setToolTip(tr("Open this note in new tab")); + openNewTabAction.triggered.connect(parent, "openNewTabFromRNL()"); + // スターをつけるアクション生成 + starAction = new QAction(tr("STAR"), this); + starAction.setToolTip(tr("Star this item")); + starAction.triggered.connect(parent, "starNote()"); + // スターを外すアクション生成 + unstarAction = new QAction(tr("UNSTAR"), this); + unstarAction.setToolTip(tr("Unstar this item")); + unstarAction.triggered.connect(parent, "unstarNote()"); + // このノートを除外するアクション生成 + excludeNoteAction = new QAction(tr("Exclude"), this); + excludeNoteAction.setToolTip(tr("Exclude this note from RensoNoteList")); + excludeNoteAction.triggered.connect(parent, "excludeNote()"); + // コンテキストメニューに登録 + menu.addAction(openNewTabAction); + menu.addAction(excludeNoteAction); + menu.aboutToHide.connect(this, "contextMenuHidden()"); + + logger.log(logger.HIGH, "rensoNoteList setup complete"); + } + + public void refreshRensoNoteList(String guid) { + logger.log(logger.HIGH, "Entering RensoNoteList.refreshRensoNoteList"); + + this.clear(); + rensoNoteListItems.clear(); + rensoNoteListTrueItems.clear(); + + if (!this.isEnabled()) { + return; + } + if (guid == null || guid.equals("")) { + return; + } + + HashMap mergedHistory = new HashMap(); + + // browseHistory + HashMap browseHistory = conn.getHistoryTable().getBehaviorHistory("browse", guid); + addWeight(browseHistory, Global.getBrowseWeight()); + mergedHistory = mergeHistory(browseHistory, new HashMap()); + + // copy&pasteHistory + HashMap copyAndPasteHistory = conn.getHistoryTable().getBehaviorHistory("copy & paste", guid); + addWeight(copyAndPasteHistory, Global.getCopyPasteWeight()); + mergedHistory = mergeHistory(copyAndPasteHistory, mergedHistory); + + // addNewNoteHistory + HashMap addNewNoteHistory = conn.getHistoryTable().getBehaviorHistory("addNewNote", guid); + addWeight(addNewNoteHistory, Global.getAddNewNoteWeight()); + mergedHistory = mergeHistory(addNewNoteHistory, mergedHistory); + + // rensoItemClickHistory + HashMap rensoItemClickHistory = conn.getHistoryTable().getBehaviorHistory("rensoItemClick", guid); + addWeight(rensoItemClickHistory, Global.getRensoItemClickWeight()); + mergedHistory = mergeHistory(rensoItemClickHistory, mergedHistory); + + // sameTagHistory + HashMap sameTagHistory = conn.getHistoryTable().getBehaviorHistory("sameTag", guid); + addWeight(sameTagHistory, Global.getSameTagWeight()); + mergedHistory = mergeHistory(sameTagHistory, mergedHistory); + + // sameNotebookNoteHistory + HashMap sameNotebookHistory = conn.getHistoryTable().getBehaviorHistory("sameNotebook", guid); + addWeight(sameNotebookHistory, Global.getSameNotebookWeight()); + mergedHistory = mergeHistory(sameNotebookHistory, mergedHistory); + + // すべての関連ポイントの合計を取得(関連度のパーセント算出に利用) + allPointSum = 0; + for (int p : mergedHistory.values()) { + allPointSum += p; + } + + addRensoNoteList(mergedHistory); + + logger.log(logger.HIGH, "Leaving RensoNoteList.refreshRensoNoteList"); + } + + // 操作回数に重み付けする + private void addWeight(HashMap history, int weight){ + Set keySet = history.keySet(); + Iterator hist_iterator = keySet.iterator(); + while(hist_iterator.hasNext()){ + String key = hist_iterator.next(); + history.put(key, history.get(key) * weight); + } + } + + // 引数1と引数2をマージしたハッシュマップを返す + private HashMap mergeHistory(HashMap History1, HashMap History2){ + HashMap mergedHistory = new HashMap(); + + mergedHistory.putAll(History1); + + Set keySet = History2.keySet(); + Iterator hist2_iterator = keySet.iterator(); + while(hist2_iterator.hasNext()){ + String key = hist2_iterator.next(); + if(mergedHistory.containsKey(key)){ + mergedHistory.put(key, mergedHistory.get(key) + History2.get(key)); + }else { + mergedHistory.put(key, History2.get(key)); + } + } + + return mergedHistory; + } + + private void addRensoNoteList(HashMap History){ + String currentNoteGuid = new String(parent.getCurrentNoteGuid()); + + // スター付きノートとスター無しノートを分ける + HashMap staredNotes = new HashMap(); // スター付きノートのマップ + HashMap normalNotes = new HashMap(); // スター無しノートのマップ + for (String nextGuid: History.keySet()) { + int relationPoint = History.get(nextGuid); + boolean isStared = conn.getStaredTable().existNote(currentNoteGuid, nextGuid); + if (isStared) { + staredNotes.put(nextGuid, relationPoint); + } else { + normalNotes.put(nextGuid, relationPoint); + } + } + + // 連想ノートリストアイテムの最大表示数まで繰り返す + for (int i = 0; i < Global.getRensoListItemMaximum(); i++) { + // スター付きノートがあれば先に処理する + HashMap tmpMap = new HashMap(); + if (!staredNotes.isEmpty()) { + tmpMap = staredNotes; + }else if (!normalNotes.isEmpty()) { + tmpMap = normalNotes; + } + + // 操作回数が多い順に取り出して連想ノートリストに追加する + if (!tmpMap.isEmpty()) { + int maxNum = -1; + String maxGuid = new String(); + + for (String nextGuid: tmpMap.keySet()) { + int relationPoint = tmpMap.get(nextGuid); + + // 最大ノート探索する + if (relationPoint > maxNum) { + maxNum = relationPoint; + maxGuid = nextGuid; + } + } + + // 次の最大値探索で邪魔なので最大値をHashMapから削除 + tmpMap.remove(maxGuid); + + // 関連度最大のノートがアクティブか確認 + Note maxNote = conn.getNoteTable().getNote(maxGuid, true, false, false, false, true); + boolean isNoteActive = false; + if(maxNote != null) { + isNoteActive = maxNote.isActive(); + } + + // 存在していて、かつ関連度0でなければノート情報を取得して連想ノートリストに追加 + if (isNoteActive && maxNum > 0) { + // スター付きか確認 + boolean isStared; + isStared = conn.getStaredTable().existNote(currentNoteGuid, maxGuid); + + QListWidgetItem item = new QListWidgetItem(); + RensoNoteListItem myItem = new RensoNoteListItem(maxNote, maxNum, isStared, allPointSum, conn, this); + item.setSizeHint(new QSize(0, 90)); + this.addItem(item); + this.setItemWidget(item, myItem); + rensoNoteListItems.put(item, maxGuid); + rensoNoteListTrueItems.add(myItem); + } else { + break; + } + } + } + } + + // リストのアイテムから対象ノートのguidを取得 + public String getNoteGuid(QListWidgetItem item) { + return rensoNoteListItems.get(item); + } + + // 関連ノートリストの右クリックメニュー + @Override + public void contextMenuEvent(QContextMenuEvent event){ + // STAR, UNSTARがあれば、一度消す + List menuActions = new ArrayList(menu.actions()); + if (menuActions.contains(starAction)) { + menu.removeAction(starAction); + } + if (menuActions.contains(unstarAction)) { + menu.removeAction(unstarAction); + } + + // 対象アイテムがスター付きなら「UNSTAR」、スター無しなら「STAR」を追加 + String currentNoteGuid = parent.getCurrentNoteGuid(); + boolean isExist = conn.getStaredTable().existNote(currentNoteGuid, rensoNotePressedItemGuid); + if (isExist) { + menu.insertAction(excludeNoteAction, unstarAction); + } else { + menu.insertAction(excludeNoteAction, starAction); + } + + // コンテキストメニューを表示 + menu.exec(event.globalPos()); + } + + // コンテキストメニューが表示されているかどうか + public boolean isContextMenuVisible() { + return menu.isVisible(); + } + + // コンテキストメニューが閉じられた時 + @SuppressWarnings("unused") + private void contextMenuHidden() { + for (int i = 0; i < rensoNoteListTrueItems.size(); i++) { + RensoNoteListItem item = rensoNoteListTrueItems.get(i); + item.setDefaultBackground(); + } + } + + // ユーザが連想ノートリストのアイテムを選択した時の処理 + @SuppressWarnings("unused") + private void rensoNoteItemPressed(QListWidgetItem current) { + rensoNotePressedItemGuid = null; + // 右クリックだったときの処理 + if (QApplication.mouseButtons().isSet(MouseButton.RightButton)) { + rensoNotePressedItemGuid = getNoteGuid(current); + } + } +} diff --git a/src/cx/fbn/nevernote/gui/RensoNoteListItem.java b/src/cx/fbn/nevernote/gui/RensoNoteListItem.java new file mode 100644 index 0000000..9c36e9e --- /dev/null +++ b/src/cx/fbn/nevernote/gui/RensoNoteListItem.java @@ -0,0 +1,168 @@ +// ICHANGED +package cx.fbn.nevernote.gui; + +import java.text.SimpleDateFormat; + +import com.evernote.edam.type.Note; +import com.trolltech.qt.core.QEvent; +import com.trolltech.qt.core.QFile; +import com.trolltech.qt.core.QRectF; +import com.trolltech.qt.core.Qt; +import com.trolltech.qt.gui.QColor; +import com.trolltech.qt.gui.QFont; +import com.trolltech.qt.gui.QImage; +import com.trolltech.qt.gui.QMouseEvent; +import com.trolltech.qt.gui.QPaintEvent; +import com.trolltech.qt.gui.QPainter; +import com.trolltech.qt.gui.QPalette; +import com.trolltech.qt.gui.QTextOption; +import com.trolltech.qt.gui.QWidget; + +import cx.fbn.nevernote.Global; +import cx.fbn.nevernote.sql.DatabaseConnection; + +public class RensoNoteListItem extends QWidget{ + private final DatabaseConnection conn; + private final String noteGuid; + private final String noteTitle; + private final int relationPoints; + private final String noteCreated; + private final String tagNames; + private String noteContent; + private final RensoNoteList parent; + private final boolean isStared; + private final int allPointSum; + + private final String iconPath = new String("classpath:cx/fbn/nevernote/icons/"); + + public RensoNoteListItem(Note note, int relationPoints, boolean isStared, int allPointSum, DatabaseConnection c, RensoNoteList parent){ + + this.conn = c; + this.parent = parent; + this.isStared = isStared; + this.allPointSum = allPointSum; + this.noteGuid = new String(note.getGuid()); + + this.noteTitle = new String(note.getTitle()); + this.relationPoints = relationPoints; + SimpleDateFormat simple = new SimpleDateFormat("yyyy/MM/dd"); + this.noteCreated = new StringBuilder(simple.format(note.getCreated())).toString(); + + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < note.getTagNames().size(); i++) { + sb.append(note.getTagNames().get(i)); + if(i + 1 < note.getTagNames().size()){ + sb.append(Global.tagDelimeter + " "); + } + } + + this.tagNames = new String(sb); + + // this.noteContent = new String(note.getContent()); + this.noteContent = conn.getNoteTable().getNoteContentNoUTFConversion(note.getGuid()); + this.noteContent = this.noteContent.replaceAll("<.+?>", ""); + this.noteContent = this.noteContent.replaceAll("\\s{2,}", " "); + String kaigyo = System.getProperty("line.separator"); + this.noteContent = this.noteContent.replaceAll(kaigyo, ""); + + QPalette p = new QPalette(); + p.setColor(QPalette.ColorRole.Window, new QColor(255, 255, 255)); + this.setPalette(p); + this.setAutoFillBackground(true); + this.setBackgroundRole(QPalette.ColorRole.Window); + } + + @Override + protected void paintEvent(QPaintEvent event){ + QPainter painter = new QPainter(this); + + // 枠線 + painter.setPen(QColor.lightGray); + painter.drawLine(0, rect().height() - 1, rect().width() - 1, rect().height() - 1); + + // 項目の中身 + // フォント設定 + painter.setPen(QColor.black); + QFont titleFont = new QFont(); + titleFont.setPixelSize(15); + titleFont.setBold(true); + QFont normalFont = new QFont(); + normalFont.setPixelSize(12); + + // タイトル + painter.setFont(titleFont); + painter.drawText(85, 3, size().width() - 130, 20, Qt.AlignmentFlag.AlignLeft.value(), noteTitle); + // 関連度 + double ratio = (double)relationPoints / allPointSum; + int green = (int) (255 * (1.0 - ratio)); + painter.setPen(new QColor(255, green, 0)); + painter.drawText(size().width() - 40, 3, 40, 20, Qt.AlignmentFlag.AlignRight.value(), String.valueOf((int)(ratio * 100)) + "%"); + // ノート作成日時 + painter.setFont(normalFont); + painter.setPen(new QColor(60, 65, 255)); + painter.drawText(85, 23, 75, 17, Qt.AlignmentFlag.AlignLeft.value(), noteCreated); + // タグ + painter.setPen(QColor.black); + painter.drawText(165, 23, size().width() - 165, 17, Qt.AlignmentFlag.AlignLeft.value(), tagNames); + // ノート内容 + QTextOption option = new QTextOption(); + option.setAlignment(Qt.AlignmentFlag.AlignLeft); + option.setUseDesignMetrics(true); + painter.drawText(new QRectF(85, 40, width() - 85, 40), noteContent, option); + + // サムネイル + QImage img; + String thumbnailName = Global.getFileManager().getResDirPath("thumbnail-" + noteGuid + ".png"); + QFile thumbnail = new QFile(thumbnailName); + if (!thumbnail.exists()) { + img = new QImage(); + img.loadFromData(conn.getNoteTable().getThumbnail(noteGuid)); + } else { + img = new QImage(thumbnailName); + } + painter.drawImage(2, 4, img, 0, 0, 80, rect().height() - 10); + painter.setPen(QColor.lightGray); + painter.drawRect(2, 4, 80, rect().height() - 10); + + // スター + if (isStared) { + QImage starImage = new QImage(iconPath+"star.png"); + starImage = starImage.scaled(30, 30, Qt.AspectRatioMode.IgnoreAspectRatio, Qt.TransformationMode.SmoothTransformation); + painter.drawImage(0, 0, starImage, 0, 0, starImage.width(), starImage.height()); + } + + painter.end(); + } + + @Override + protected void enterEvent(QEvent e){ + if (!parent.isContextMenuVisible()) { + QPalette p = new QPalette(); + p.setColor(QPalette.ColorRole.Window, new QColor(225, 235, 255)); + this.setPalette(p); + } + } + + @Override + protected void leaveEvent(QEvent e){ + if (!parent.isContextMenuVisible()) { + setDefaultBackground(); + } + } + + @Override + protected void mousePressEvent(QMouseEvent e) { + QPalette p = new QPalette(); + p.setColor(QPalette.ColorRole.Window, new QColor(165, 175, 255)); + this.setPalette(p); + + super.mousePressEvent(e); + } + + public void setDefaultBackground() { + QPalette p = new QPalette(); + p.setColor(QPalette.ColorRole.Window, new QColor(255, 255, 255)); + this.setPalette(p); + } +} diff --git a/src/cx/fbn/nevernote/gui/ShortcutKeys.java b/src/cx/fbn/nevernote/gui/ShortcutKeys.java index 913cb57..8d9d103 100644 --- a/src/cx/fbn/nevernote/gui/ShortcutKeys.java +++ b/src/cx/fbn/nevernote/gui/ShortcutKeys.java @@ -34,6 +34,10 @@ public class ShortcutKeys { public String File_Note_Delete; // Delete a tag public String File_Note_Restore; // Undelete a note public String File_Note_Duplicate; // duplicate a note + // ICHANGED + public String File_Note_Open_New_Tab; // 新しいタブでノートを開く + public String File_Note_Add_New_Tab; // 新しいタブでノート追加 + public String File_Notebook_Add; // Add a notebook public String File_Notebook_Edit; // Edit an existing notebook public String File_Notebook_Delete; // Delete the existing notebook @@ -127,6 +131,10 @@ public class ShortcutKeys { File_Note_Delete = new String(); // Delete a tag File_Note_Restore = new String(); // Undelete a note File_Note_Duplicate = new String(); // Duplicate a note + // ICHANGED + File_Note_Add_New_Tab = new String(); // 新しいタブでノートを開く + File_Note_Open_New_Tab = new String(); // 新しいタブでノート追加 + File_Notebook_Add = new String(); // Add a notebook File_Notebook_Edit = new String(); // Edit an existing notebook File_Notebook_Delete = new String(); // Delete the existing notebook @@ -223,6 +231,9 @@ public class ShortcutKeys { loadKey("File_Backup", File_Backup); loadKey("File_Restore", File_Restore); loadKey("File_Exit", File_Exit); + // ICHANGED + loadKey("File_Note_Add_New_Tab", File_Note_Add_New_Tab); + loadKey("File_Note_Open_New_Tab", File_Note_Open_New_Tab); loadKey("Edit_Find_In_Note", Edit_Find_In_Note); loadKey("Edit_Undo", Edit_Undo); diff --git a/src/cx/fbn/nevernote/gui/TabBrowse.java b/src/cx/fbn/nevernote/gui/TabBrowse.java new file mode 100644 index 0000000..3924d32 --- /dev/null +++ b/src/cx/fbn/nevernote/gui/TabBrowse.java @@ -0,0 +1,149 @@ +// ICHANGED +package cx.fbn.nevernote.gui; + +import java.awt.Desktop; + +import com.trolltech.qt.core.QUrl; +import com.trolltech.qt.gui.QDesktopServices; +import com.trolltech.qt.gui.QDialog; +import com.trolltech.qt.gui.QPrintDialog; +import com.trolltech.qt.gui.QPrinter; +import com.trolltech.qt.gui.QVBoxLayout; +import com.trolltech.qt.gui.QWidget; + +import cx.fbn.nevernote.dialog.FindDialog; +import cx.fbn.nevernote.neighbornote.ClipBoardObserver; +import cx.fbn.nevernote.sql.DatabaseConnection; + +public class TabBrowse extends QWidget { + private final DatabaseConnection conn; + private final BrowserWindow browser; + public Signal4 contentsChanged; + private boolean noteDirty; + String saveTitle; + private final FindDialog find; // Text search in note dialog + private final TabBrowserWidget parent; + private final ClipBoardObserver cbObserver; + + // コンストラクタ + public TabBrowse(DatabaseConnection c, TabBrowserWidget p, ClipBoardObserver cbObserver) { + conn = c; + parent = p; + this.cbObserver = cbObserver; + contentsChanged = new Signal4(); + browser = new BrowserWindow(conn, this.cbObserver); + QVBoxLayout v = new QVBoxLayout(); + v.addWidget(browser); + setLayout(v); + noteDirty = false; + browser.titleLabel.textChanged.connect(this, "titleChanged(String)"); + browser.getBrowser().page().contentsChanged.connect(this, + "contentChanged()"); + find = new FindDialog(); + find.getOkButton().clicked.connect(this, "doFindText()"); + } + + @SuppressWarnings("unused") + private void contentChanged() { + noteDirty = true; + contentsChanged.emit(getBrowserWindow().getNote().getGuid(), + getBrowserWindow().getContent(), false, getBrowserWindow()); + } + + public BrowserWindow getBrowserWindow() { + return browser; + } + + + @SuppressWarnings("unused") + private void titleChanged(String value) { + int index = parent.indexOf(this); + if(index >= 0){ + parent.setTabTitle(index, value); + } + } + + /* + @SuppressWarnings("unused") + private void updateTitle(String guid, String title) { + if (guid.equals(getBrowserWindow().getNote().getGuid()) + && (saveTitle != null && !title.equals(saveTitle) || saveTitle == null)) { + saveTitle = title; + getBrowserWindow().loadingData(true); + getBrowserWindow().setTitle(title); + getBrowserWindow().getNote().setTitle(title); + getBrowserWindow().loadingData(false); + } + } + */ + + /* + @SuppressWarnings("unused") + private void updateNotebook(String guid, String notebook) { + if (guid.equals(getBrowserWindow().getNote().getGuid())) { + getBrowserWindow().loadingData(true); + getBrowserWindow().setNotebook(notebook); + getBrowserWindow().loadingData(false); + } + } + */ + + /* + @SuppressWarnings("unused") + private void updateTags(String guid, List tags) { + if (guid.equals(getBrowserWindow().getNote().getGuid())) { + StringBuffer tagLine = new StringBuffer(100); + for (int i = 0; i < tags.size(); i++) { + if (i > 0) + tagLine.append(Global.tagDelimeter + " "); + tagLine.append(tags.get(i)); + + } + getBrowserWindow().loadingData(true); + getBrowserWindow().getTagLine().setText(tagLine.toString()); + getBrowserWindow().loadingData(false); + } + } + */ + + @SuppressWarnings("unused") + private void findText() { + find.show(); + find.setFocusOnTextField(); + } + + @SuppressWarnings("unused") + private void doFindText() { + browser.getBrowser().page().findText(find.getText(), find.getFlags()); + find.setFocus(); + } + + @SuppressWarnings("unused") + private void printNote() { + + QPrintDialog dialog = new QPrintDialog(); + if (dialog.exec() == QDialog.DialogCode.Accepted.value()) { + QPrinter printer = dialog.printer(); + browser.getBrowser().print(printer); + } + } + + // Listener triggered when the email button is pressed + @SuppressWarnings("unused") + private void emailNote() { + if (Desktop.isDesktopSupported()) { + Desktop desktop = Desktop.getDesktop(); + + String text2 = browser.getContentsToEmail(); + QUrl url = new QUrl("mailto:"); + url.addQueryItem("subject", browser.getTitle()); + url.addQueryItem("body", text2); + QDesktopServices.openUrl(url); + } + } + + // noteDirtyの値を返す + public boolean getNoteDirty() { + return noteDirty; + } +} diff --git a/src/cx/fbn/nevernote/gui/TabBrowserBar.java b/src/cx/fbn/nevernote/gui/TabBrowserBar.java new file mode 100644 index 0000000..a64eea1 --- /dev/null +++ b/src/cx/fbn/nevernote/gui/TabBrowserBar.java @@ -0,0 +1,27 @@ +// ICHANGED +package cx.fbn.nevernote.gui; + +import com.trolltech.qt.core.Qt; +import com.trolltech.qt.gui.QLabel; +import com.trolltech.qt.gui.QTabBar; + +public class TabBrowserBar extends QTabBar { + + public TabBrowserBar(){ + super(); + } + + public void addNewTab(int index, String title){ + QLabel label = new QLabel(title); + label.setAlignment(Qt.AlignmentFlag.AlignLeft); + int tabWidth = this.tabSizeHint(index).width(); + label.setFixedWidth(tabWidth - 35); + this.setTabButton(index, QTabBar.ButtonPosition.LeftSide, label); + } + + public void setTabTitle(int index, String title) { + QLabel label = (QLabel)this.tabButton(index, QTabBar.ButtonPosition.LeftSide); + label.setText(title); + } + +} diff --git a/src/cx/fbn/nevernote/gui/TabBrowserWidget.java b/src/cx/fbn/nevernote/gui/TabBrowserWidget.java new file mode 100644 index 0000000..bc920bb --- /dev/null +++ b/src/cx/fbn/nevernote/gui/TabBrowserWidget.java @@ -0,0 +1,28 @@ +// ICHANGED +package cx.fbn.nevernote.gui; + +import com.trolltech.qt.gui.QTabWidget; +import com.trolltech.qt.gui.QWidget; + +public class TabBrowserWidget extends QTabWidget { + TabBrowserBar bar; + + public TabBrowserWidget(QWidget parent) { + super(parent); + bar = new TabBrowserBar(); + this.setTabBar(bar); + } + + public int addNewTab(QWidget widget, String title){ + int index = this.addTab(widget, new String()); + bar.addNewTab(index, title); + this.setTabToolTip(index, title); + return index; + } + + public void setTabTitle(int index, String title) { + bar.setTabTitle(index, title); + this.setTabToolTip(index, title); + } + +} diff --git a/src/cx/fbn/nevernote/gui/TableView.java b/src/cx/fbn/nevernote/gui/TableView.java index ac4f571..189b0d2 100644 --- a/src/cx/fbn/nevernote/gui/TableView.java +++ b/src/cx/fbn/nevernote/gui/TableView.java @@ -1,575 +1,612 @@ -/* - * This file is part of NixNote - * Copyright 2009 Randy Baumgarte - * - * This file may be licensed under the terms of of the - * GNU General Public License Version 2 (the ``GPL''). - * - * Software distributed under the License is distributed - * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either - * express or implied. See the GPL for the specific language - * governing rights and limitations. - * - * You should have received a copy of the GPL along with this - * program. If not, go to http://www.gnu.org/licenses/gpl.html - * or write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * -*/ -package cx.fbn.nevernote.gui; - -import java.util.List; -import java.util.SortedMap; - -import com.evernote.edam.type.Note; -import com.trolltech.qt.core.QByteArray; -import com.trolltech.qt.core.QModelIndex; -import com.trolltech.qt.core.Qt; -import com.trolltech.qt.core.Qt.Orientation; -import com.trolltech.qt.core.Qt.SortOrder; -import com.trolltech.qt.gui.QAbstractItemView; -import com.trolltech.qt.gui.QAction; -import com.trolltech.qt.gui.QApplication; -import com.trolltech.qt.gui.QColor; -import com.trolltech.qt.gui.QContextMenuEvent; -import com.trolltech.qt.gui.QDragEnterEvent; -import com.trolltech.qt.gui.QDropEvent; -import com.trolltech.qt.gui.QFontMetrics; -import com.trolltech.qt.gui.QKeyEvent; -import com.trolltech.qt.gui.QKeySequence.StandardKey; -import com.trolltech.qt.gui.QMenu; -import com.trolltech.qt.gui.QTableView; - -import cx.fbn.nevernote.Global; -import cx.fbn.nevernote.evernote.NoteMetadata; -import cx.fbn.nevernote.filters.NoteSortFilterProxyModel; -import cx.fbn.nevernote.signals.NoteSignal; -import cx.fbn.nevernote.utilities.ApplicationLogger; -import cx.fbn.nevernote.utilities.ListManager; - -public class TableView extends QTableView { - private final ListManager runner; - private final ApplicationLogger logger; - public NoteSortFilterProxyModel proxyModel; // note sort model - private QAction deleteAction; - private QAction addAction; - private QAction restoreAction; - private QAction noteHistoryAction; - private QAction duplicateAction; - private QAction mergeNotesAction; - - // Note title colors - private QAction noteTitleColorWhite; - private QAction noteTitleColorRed; - private QAction noteTitleColorBlue; - private QAction noteTitleColorGreen; - private QAction noteTitleColorYellow; - private QAction noteTitleColorBlack; - private QAction noteTitleColorGray; - private QAction noteTitleColorCyan; - private QAction noteTitleColorMagenta; - private QAction notePinned; - private QAction copyAsUrlAction; - - - - public TableViewHeader header; - int fontHeight; - public Signal1 rowChanged; - public Signal0 resetViewport; - public NoteSignal noteSignal; - - public TableView(ApplicationLogger l, ListManager m) { - logger = l; - header = new TableViewHeader(Orientation.Horizontal,this); - setHorizontalHeader(header); - header.setMovable(true); - header.subjectDateAction.toggled.connect(this, "toggleSubjectDate(Boolean)"); - header.createdDateAction.toggled.connect(this, "toggleCreationDate(Boolean)"); - header.changedDateAction.toggled.connect(this, "toggleChangedDate(Boolean)"); - header.authorAction.toggled.connect(this, "toggleAuthor(Boolean)"); - header.urlAction.toggled.connect(this, "toggleSourceUrl(Boolean)"); - header.pinnedAction.toggled.connect(this, "togglePinned(Boolean)"); - header.tagsAction.toggled.connect(this, "toggleTags(Boolean)"); - header.notebookAction.toggled.connect(this, "toggleNotebook(Boolean)"); - header.synchronizedAction.toggled.connect(this, "toggleSynchronized(Boolean)"); - header.guidAction.toggled.connect(this, "toggleGuid(Boolean)"); - header.thumbnailAction.toggled.connect(this, "toggleThumbnail(Boolean)"); - header.titleAction.toggled.connect(this, "toggleTitle(Boolean)"); - - noteSignal = new NoteSignal(); - setAcceptDrops(true); - setDragEnabled(true); - setDragDropMode(QAbstractItemView.DragDropMode.DragDrop); - setDropIndicatorShown(false); - - runner = m; - - runner.getNoteTableModel().setHeaderData(Global.noteTableCreationPosition, Qt.Orientation.Horizontal, tr("Date Created"), Qt.ItemDataRole.DisplayRole); - runner.getNoteTableModel().setHeaderData(Global.noteTableTagPosition, Qt.Orientation.Horizontal, tr("Tags"), Qt.ItemDataRole.DisplayRole); - runner.getNoteTableModel().setHeaderData(Global.noteTableGuidPosition, Qt.Orientation.Horizontal, tr("Guid"), Qt.ItemDataRole.DisplayRole); - runner.getNoteTableModel().setHeaderData(Global.noteTableNotebookPosition, Qt.Orientation.Horizontal, tr("Notebook"), Qt.ItemDataRole.DisplayRole); - runner.getNoteTableModel().setHeaderData(Global.noteTableTitlePosition, Qt.Orientation.Horizontal, tr("Title"), Qt.ItemDataRole.DisplayRole); - runner.getNoteTableModel().setHeaderData(Global.noteTableChangedPosition, Qt.Orientation.Horizontal, tr("Date Changed"), Qt.ItemDataRole.DisplayRole); - runner.getNoteTableModel().setHeaderData(Global.noteTableAuthorPosition, Qt.Orientation.Horizontal, tr("Author"), Qt.ItemDataRole.DisplayRole); - runner.getNoteTableModel().setHeaderData(Global.noteTableSourceUrlPosition, Qt.Orientation.Horizontal, tr("Source Url"), Qt.ItemDataRole.DisplayRole); - runner.getNoteTableModel().setHeaderData(Global.noteTableSubjectDatePosition, Qt.Orientation.Horizontal, tr("Subject Date"), Qt.ItemDataRole.DisplayRole); - runner.getNoteTableModel().setHeaderData(Global.noteTableSynchronizedPosition, Qt.Orientation.Horizontal, tr("Sync"), Qt.ItemDataRole.DisplayRole); - runner.getNoteTableModel().setHeaderData(Global.noteTablePinnedPosition, Qt.Orientation.Horizontal, tr("Pinned"), Qt.ItemDataRole.DisplayRole); - runner.getNoteTableModel().setHeaderData(Global.noteTableThumbnailPosition, Qt.Orientation.Horizontal, tr("Thumbnail"), Qt.ItemDataRole.DisplayRole); - header.sortIndicatorChanged.connect(this, "resetViewport()"); - - proxyModel = new NoteSortFilterProxyModel(this); - proxyModel.setSourceModel(runner.getNoteTableModel()); - setAlternatingRowColors(false); - setModel(proxyModel); - runner.getNoteTableModel().setSortProxyModel(proxyModel); - - setSortingEnabled(true); - int sortCol = proxyModel.sortColumn(); - SortOrder sortOrder = proxyModel.sortOrder(); - sortByColumn(sortCol, sortOrder); - - setSelectionBehavior(SelectionBehavior.SelectRows); - setSelectionMode(SelectionMode.SingleSelection); - verticalHeader().setVisible(false); - hideColumn(Global.noteTableGuidPosition); // Hide the guid column - setShowGrid(false); - setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers); - - QFontMetrics f = QApplication.fontMetrics(); - fontHeight = f.height(); - rowChanged = new Signal1(); - resetViewport = new Signal0(); - - NoteTableDateDelegate dateDelegate = new NoteTableDateDelegate(); - setItemDelegateForColumn(Global.noteTableCreationPosition, dateDelegate); - setItemDelegateForColumn(Global.noteTableChangedPosition, dateDelegate); - setItemDelegateForColumn(Global.noteTableSubjectDatePosition, dateDelegate); - - } - - // This should rescroll to the current item in the list when a column is - // sorted. Somehow I can't get this to work, but this part is correct. - @SuppressWarnings("unused") - private void resetViewport() { -// if (currentIndex() == null) -// return; - -// resetViewport.emit(); - } - - - public void load(boolean reload) { - proxyModel.clear(); - setSortingEnabled(false); - QFontMetrics f = QApplication.fontMetrics(); - if (!Global.isColumnVisible("thumbnail")) - verticalHeader().setDefaultSectionSize(f.height()); - else { - if (Global.getListView() == Global.View_List_Wide) - verticalHeader().setDefaultSectionSize(Global.smallThumbnailSize.height()); - else - verticalHeader().setDefaultSectionSize(Global.largeThumbnailSize.height()); - } - for (int i=0; i=0) header.moveSection(from, to); - - from = header.visualIndex(Global.noteTableTitlePosition); - to = Global.getColumnPosition("noteTableTitlePosition"); - if (to>=0) header.moveSection(from, to); - - from = header.visualIndex(Global.noteTableTagPosition); - to = Global.getColumnPosition("noteTableTagPosition"); - if (to>=0) header.moveSection(from, to); - - from = header.visualIndex(Global.noteTableNotebookPosition); - to = Global.getColumnPosition("noteTableNotebookPosition"); - if (to>=0) header.moveSection(from, to); - - from = header.visualIndex(Global.noteTableChangedPosition); - to = Global.getColumnPosition("noteTableChangedPosition"); - if (to>=0) header.moveSection(from, to); - - from = header.visualIndex(Global.noteTableSourceUrlPosition); - to = Global.getColumnPosition("noteTableSourceUrlPosition"); - if (to>=0) header.moveSection(from, to); - - from = header.visualIndex(Global.noteTableAuthorPosition); - to = Global.getColumnPosition("noteTableAuthorPosition"); - if (to>=0) header.moveSection(from, to); - - from = header.visualIndex(Global.noteTableSubjectDatePosition); - to = Global.getColumnPosition("noteTableSubjectDatePosition"); - if (to>=0) header.moveSection(from, to); - - from = header.visualIndex(Global.noteTableSynchronizedPosition); - to = Global.getColumnPosition("noteTableSynchronizedPosition"); - if (to>=0) header.moveSection(from, to); - - from = header.visualIndex(Global.noteTablePinnedPosition); - to = Global.getColumnPosition("noteTablePinnedPosition"); - if (to>=0) header.moveSection(from, to); - - - from = header.visualIndex(Global.noteTableGuidPosition); - to = Global.getColumnPosition("noteTableGuidPosition"); - if (to>=0) header.moveSection(from, to); - - - from = header.visualIndex(Global.noteTableThumbnailPosition); - to = Global.getColumnPosition("noteTableThumbnailPosition"); - if (to>=0) header.moveSection(from, to); - - } - - public void resizeColumnWidths() { - int width; - width = Global.getColumnWidth("noteTableCreationPosition"); - if (width>0) setColumnWidth(Global.noteTableCreationPosition, width); - width = Global.getColumnWidth("noteTableChangedPosition"); - if (width>0) setColumnWidth(Global.noteTableChangedPosition, width); - width = Global.getColumnWidth("noteTableTitlePosition"); - if (width>0) setColumnWidth(Global.noteTableTitlePosition, width); - width = Global.getColumnWidth("noteTableTagPosition"); - if (width>0) setColumnWidth(Global.noteTableTagPosition, width); - width = Global.getColumnWidth("noteTableGuidPosition"); - if (width>0) setColumnWidth(Global.noteTableGuidPosition, width); - width = Global.getColumnWidth("noteTableNotebookPosition"); - if (width>0) setColumnWidth(Global.noteTableNotebookPosition, width); - width = Global.getColumnWidth("noteTableSourceUrlPosition"); - if (width>0) setColumnWidth(Global.noteTableSourceUrlPosition, width); - width = Global.getColumnWidth("noteTableAuthorPosition"); - if (width>0) setColumnWidth(Global.noteTableAuthorPosition, width); - width = Global.getColumnWidth("noteTableSubjectDatePosition"); - if (width>0) setColumnWidth(Global.noteTableSubjectDatePosition, width); - width = Global.getColumnWidth("noteTableSynchronizedPosition"); - if (width>0) setColumnWidth(Global.noteTableSynchronizedPosition, width); - width = Global.getColumnWidth("noteTableThumbnailPosition"); - if (width>0) setColumnWidth(Global.noteTablePinnedPosition, width); - width = Global.getColumnWidth("noteTablePinnedPosition"); - if (width>0) setColumnWidth(Global.noteTableThumbnailPosition, width); - width = Global.getColumnWidth("noteTableGuidPosition"); - if (width>0) setColumnWidth(Global.noteTableGuidPosition, width); - - } - - public void resizeRowHeights() { - int height; - if (!Global.isColumnVisible("thumbnail") || !Global.enableThumbnails()) { - QFontMetrics f = QApplication.fontMetrics(); - verticalHeader().setDefaultSectionSize(f.height()); - height = fontHeight; - } else { - if (Global.getListView() == Global.View_List_Wide) { - verticalHeader().setDefaultSectionSize(Global.smallThumbnailSize.height()); - height = Global.smallThumbnailSize.height(); - } else { - verticalHeader().setDefaultSectionSize(Global.largeThumbnailSize.height()); - height = Global.largeThumbnailSize.height(); - } - } - for (int i=0; i runner.getNoteTableModel().rowCount()) - runner.getNoteTableModel().insertRow(0); - - if (row < 0) { - row = runner.getNoteTableModel().rowCount(); - runner.getNoteTableModel().insertRow(row); - } - if (newNote) { - resizeRowHeights(); - } - } - protected boolean filterAcceptsRow(int sourceRow, QModelIndex sourceParent) { - return true; - } - - public void setAddAction(QAction a) { - addAction = a; - } - - public void setMergeNotesAction(QAction a) { - mergeNotesAction = a; - } - - public void setCopyAsUrlAction(QAction a) { - copyAsUrlAction = a; - } - - public void setNoteHistoryAction(QAction a) { - noteHistoryAction = a; - } - - public void setDeleteAction(QAction d) { - deleteAction = d; - } - - public void setRestoreAction(QAction r) { - restoreAction = r; - } - public void setNoteDuplicateAction(QAction d) { - duplicateAction = d; - } - - @Override - public void keyPressEvent(QKeyEvent e) { - if (e.matches(StandardKey.MoveToStartOfDocument)) { - if (runner.getNoteTableModel().rowCount() > 0) { - clearSelection(); - selectRow(0); - } - } - if (e.matches(StandardKey.MoveToEndOfDocument)) { - if (runner.getNoteTableModel().rowCount() > 0) { - clearSelection(); - selectRow(model().rowCount()-1); - } - } - super.keyPressEvent(e); - } - - @Override - public void contextMenuEvent(QContextMenuEvent event) { - QMenu menu = new QMenu(this); - if (Global.showDeleted) { - menu.addAction(restoreAction); - } else { - menu.addAction(addAction); - } - menu.addAction(deleteAction); - menu.addSeparator(); - menu.addAction(duplicateAction); - menu.addAction(copyAsUrlAction); - menu.addSeparator(); - menu.addAction(noteHistoryAction); - menu.addAction(mergeNotesAction); - - QMenu titleColorMenu = new QMenu(); - titleColorMenu.setTitle(tr("Title Color")); - menu.addMenu(titleColorMenu); - noteTitleColorWhite = new QAction(titleColorMenu); - noteTitleColorRed = new QAction(titleColorMenu); - noteTitleColorBlue = new QAction(titleColorMenu); - noteTitleColorGreen = new QAction(titleColorMenu); - noteTitleColorYellow = new QAction(titleColorMenu); - noteTitleColorBlack = new QAction(titleColorMenu); - noteTitleColorGray = new QAction(titleColorMenu); - noteTitleColorCyan = new QAction(titleColorMenu); - noteTitleColorMagenta = new QAction(titleColorMenu); - - notePinned = new QAction(titleColorMenu); - menu.addAction(notePinned); - - noteTitleColorWhite.setText(tr("White")); - noteTitleColorRed.setText(tr("Red")); - noteTitleColorBlue.setText(tr("Blue")); - noteTitleColorGreen.setText(tr("Green")); - noteTitleColorYellow.setText(tr("Yellow")); - noteTitleColorBlack.setText(tr("Black")); - noteTitleColorGray.setText(tr("Gray")); - noteTitleColorCyan.setText(tr("Cyan")); - noteTitleColorMagenta.setText(tr("Magenta")); - notePinned.setText(tr("Pin/Unpin")); - - titleColorMenu.addAction(noteTitleColorWhite); - titleColorMenu.addAction(noteTitleColorRed); - titleColorMenu.addAction(noteTitleColorBlue); - titleColorMenu.addAction(noteTitleColorGreen); - titleColorMenu.addAction(noteTitleColorYellow); - titleColorMenu.addAction(noteTitleColorBlack); - titleColorMenu.addAction(noteTitleColorGray); - titleColorMenu.addAction(noteTitleColorCyan); - titleColorMenu.addAction(noteTitleColorMagenta); - - noteTitleColorWhite.triggered.connect(this, "titleColorWhite()"); - - noteTitleColorWhite.triggered.connect(this, "titleColorWhite()"); - noteTitleColorRed.triggered.connect(this, "titleColorRed()"); - noteTitleColorBlue.triggered.connect(this, "titleColorBlue()"); - noteTitleColorGreen.triggered.connect(this, "titleColorGreen()"); - noteTitleColorYellow.triggered.connect(this, "titleColorYellow()"); - noteTitleColorBlack.triggered.connect(this, "titleColorBlack()"); - noteTitleColorGray.triggered.connect(this, "titleColorGray()"); - noteTitleColorCyan.triggered.connect(this, "titleColorCyan()"); - noteTitleColorMagenta.triggered.connect(this, "titleColorMagenta()"); - notePinned.triggered.connect(this, "notePinned()"); - menu.exec(event.globalPos()); - } - - - @SuppressWarnings("unused") - private void titleColorWhite() {noteSignal.titleColorChanged.emit(QColor.white.rgb());} - @SuppressWarnings("unused") - private void titleColorRed() {noteSignal.titleColorChanged.emit(QColor.red.rgb());} - @SuppressWarnings("unused") - private void titleColorBlue() {noteSignal.titleColorChanged.emit(QColor.blue.rgb());} - @SuppressWarnings("unused") - private void titleColorGreen() {noteSignal.titleColorChanged.emit(QColor.green.rgb());} - @SuppressWarnings("unused") - private void titleColorYellow(){noteSignal.titleColorChanged.emit(QColor.yellow.rgb());} - @SuppressWarnings("unused") - private void titleColorBlack() {noteSignal.titleColorChanged.emit(QColor.black.rgb());} - @SuppressWarnings("unused") - private void titleColorGray() {noteSignal.titleColorChanged.emit(QColor.gray.rgb());} - @SuppressWarnings("unused") - private void titleColorCyan() {noteSignal.titleColorChanged.emit(QColor.cyan.rgb());} - @SuppressWarnings("unused") - private void titleColorMagenta() {noteSignal.titleColorChanged.emit(QColor.magenta.rgb());} - @SuppressWarnings("unused") - private void notePinned() {noteSignal.notePinned.emit();} - - - @Override - public void dragEnterEvent(QDragEnterEvent event) { - StringBuffer guid = new StringBuffer(1000); - - showColumn(Global.noteTableGuidPosition); - List selections = selectionModel().selectedRows(); - hideColumn(Global.noteTableGuidPosition); - - if (selections.size() > 0) { - QModelIndex index; - for (int i=0; i ix = proxyModel.itemData(index); - guid.append((String)ix.values().toArray()[0]); - guid.append(" "); - } - } - event.mimeData().setData("application/x-nevernote-note", new QByteArray(guid.toString())); - event.accept(); - - } - - @Override - public void dropEvent(QDropEvent event) { - if (event.source() == this) - event.ignore(); - } - - // Return a column width - public int getColumnWidth(int col) { - return columnWidth(col); - } - - public void toggleSubjectDate(Boolean toggle) { - Global.saveColumnVisible("dateSubject", toggle); - setColumnHidden(Global.noteTableSubjectDatePosition, !toggle); - } - - public void toggleChangedDate(Boolean toggle) { - Global.saveColumnVisible("dateChanged", toggle); - setColumnHidden(Global.noteTableChangedPosition, !toggle); - } - - - public void toggleCreationDate(Boolean toggle) { - Global.saveColumnVisible("dateCreated", toggle); - setColumnHidden(Global.noteTableCreationPosition, !toggle); - } - - public void toggleSourceUrl(Boolean toggle) { - Global.saveColumnVisible("sourceUrl", toggle); - setColumnHidden(Global.noteTableSourceUrlPosition, !toggle); - } - - public void toggleAuthor(Boolean toggle) { - Global.saveColumnVisible("author", toggle); - setColumnHidden(Global.noteTableAuthorPosition, !toggle); - } - - public void toggleNotebook(Boolean toggle) { - Global.saveColumnVisible("notebook", toggle); - setColumnHidden(Global.noteTableNotebookPosition, !toggle); - } - - public void toggleTitle(Boolean toggle) { - Global.saveColumnVisible("title", toggle); - setColumnHidden(Global.noteTableTitlePosition, !toggle); - } - - public void toggleTags(Boolean toggle) { - Global.saveColumnVisible("tags", toggle); - setColumnHidden(Global.noteTableTagPosition, !toggle); - } - - public void toggleSynchronized(Boolean toggle) { - Global.saveColumnVisible("synchronized", toggle); - setColumnHidden(Global.noteTableSynchronizedPosition, !toggle); - } - public void togglePinned(Boolean toggle) { - Global.saveColumnVisible("pinned", toggle); - setColumnHidden(Global.noteTablePinnedPosition, !toggle); - } - public void toggleGuid(Boolean toggle) { - Global.saveColumnVisible("guid", toggle); - setColumnHidden(Global.noteTableGuidPosition, !toggle); - } - public void toggleThumbnail(Boolean toggle) { - Global.saveColumnVisible("thumbnail", toggle); - int size; - if (!toggle) { - QFontMetrics f = QApplication.fontMetrics(); - size = f.height(); - verticalHeader().setDefaultSectionSize(f.height()); - } else - size = Global.smallThumbnailSize.height(); - for (int i=0; i rowChanged; + public Signal0 resetViewport; + public NoteSignal noteSignal; + + // ICHANGED + private final NeverNote parent; + + // ICHANGED parent引数を追加 + public TableView(ApplicationLogger l, ListManager m, NeverNote parent) { + // ICHANGED + this.parent = parent; + + logger = l; + header = new TableViewHeader(Orientation.Horizontal,this); + setHorizontalHeader(header); + header.setMovable(true); + header.subjectDateAction.toggled.connect(this, "toggleSubjectDate(Boolean)"); + header.createdDateAction.toggled.connect(this, "toggleCreationDate(Boolean)"); + header.changedDateAction.toggled.connect(this, "toggleChangedDate(Boolean)"); + header.authorAction.toggled.connect(this, "toggleAuthor(Boolean)"); + header.urlAction.toggled.connect(this, "toggleSourceUrl(Boolean)"); + header.pinnedAction.toggled.connect(this, "togglePinned(Boolean)"); + header.tagsAction.toggled.connect(this, "toggleTags(Boolean)"); + header.notebookAction.toggled.connect(this, "toggleNotebook(Boolean)"); + header.synchronizedAction.toggled.connect(this, "toggleSynchronized(Boolean)"); + header.guidAction.toggled.connect(this, "toggleGuid(Boolean)"); + header.thumbnailAction.toggled.connect(this, "toggleThumbnail(Boolean)"); + header.titleAction.toggled.connect(this, "toggleTitle(Boolean)"); + + noteSignal = new NoteSignal(); + setAcceptDrops(true); + setDragEnabled(true); + setDragDropMode(QAbstractItemView.DragDropMode.DragDrop); + setDropIndicatorShown(false); + + runner = m; + + runner.getNoteTableModel().setHeaderData(Global.noteTableCreationPosition, Qt.Orientation.Horizontal, tr("Date Created"), Qt.ItemDataRole.DisplayRole); + runner.getNoteTableModel().setHeaderData(Global.noteTableTagPosition, Qt.Orientation.Horizontal, tr("Tags"), Qt.ItemDataRole.DisplayRole); + runner.getNoteTableModel().setHeaderData(Global.noteTableGuidPosition, Qt.Orientation.Horizontal, tr("Guid"), Qt.ItemDataRole.DisplayRole); + runner.getNoteTableModel().setHeaderData(Global.noteTableNotebookPosition, Qt.Orientation.Horizontal, tr("Notebook"), Qt.ItemDataRole.DisplayRole); + runner.getNoteTableModel().setHeaderData(Global.noteTableTitlePosition, Qt.Orientation.Horizontal, tr("Title"), Qt.ItemDataRole.DisplayRole); + runner.getNoteTableModel().setHeaderData(Global.noteTableChangedPosition, Qt.Orientation.Horizontal, tr("Date Changed"), Qt.ItemDataRole.DisplayRole); + runner.getNoteTableModel().setHeaderData(Global.noteTableAuthorPosition, Qt.Orientation.Horizontal, tr("Author"), Qt.ItemDataRole.DisplayRole); + runner.getNoteTableModel().setHeaderData(Global.noteTableSourceUrlPosition, Qt.Orientation.Horizontal, tr("Source Url"), Qt.ItemDataRole.DisplayRole); + runner.getNoteTableModel().setHeaderData(Global.noteTableSubjectDatePosition, Qt.Orientation.Horizontal, tr("Subject Date"), Qt.ItemDataRole.DisplayRole); + runner.getNoteTableModel().setHeaderData(Global.noteTableSynchronizedPosition, Qt.Orientation.Horizontal, tr("Sync"), Qt.ItemDataRole.DisplayRole); + runner.getNoteTableModel().setHeaderData(Global.noteTablePinnedPosition, Qt.Orientation.Horizontal, tr("Pinned"), Qt.ItemDataRole.DisplayRole); + runner.getNoteTableModel().setHeaderData(Global.noteTableThumbnailPosition, Qt.Orientation.Horizontal, tr("Thumbnail"), Qt.ItemDataRole.DisplayRole); + header.sortIndicatorChanged.connect(this, "resetViewport()"); + + proxyModel = new NoteSortFilterProxyModel(this); + proxyModel.setSourceModel(runner.getNoteTableModel()); + setAlternatingRowColors(false); + setModel(proxyModel); + runner.getNoteTableModel().setSortProxyModel(proxyModel); + + setSortingEnabled(true); + int sortCol = proxyModel.sortColumn(); + SortOrder sortOrder = proxyModel.sortOrder(); + sortByColumn(sortCol, sortOrder); + + setSelectionBehavior(SelectionBehavior.SelectRows); + setSelectionMode(SelectionMode.SingleSelection); + verticalHeader().setVisible(false); + hideColumn(Global.noteTableGuidPosition); // Hide the guid column + setShowGrid(false); + setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers); + + QFontMetrics f = QApplication.fontMetrics(); + fontHeight = f.height(); + rowChanged = new Signal1(); + resetViewport = new Signal0(); + + NoteTableDateDelegate dateDelegate = new NoteTableDateDelegate(); + setItemDelegateForColumn(Global.noteTableCreationPosition, dateDelegate); + setItemDelegateForColumn(Global.noteTableChangedPosition, dateDelegate); + setItemDelegateForColumn(Global.noteTableSubjectDatePosition, dateDelegate); + + } + + // This should rescroll to the current item in the list when a column is + // sorted. Somehow I can't get this to work, but this part is correct. + @SuppressWarnings("unused") + private void resetViewport() { +// if (currentIndex() == null) +// return; + +// resetViewport.emit(); + } + + + public void load(boolean reload) { + proxyModel.clear(); + setSortingEnabled(false); + QFontMetrics f = QApplication.fontMetrics(); + if (!Global.isColumnVisible("thumbnail")) + verticalHeader().setDefaultSectionSize(f.height()); + else { + if (Global.getListView() == Global.View_List_Wide) + verticalHeader().setDefaultSectionSize(Global.smallThumbnailSize.height()); + else + verticalHeader().setDefaultSectionSize(Global.largeThumbnailSize.height()); + } + for (int i=0; i=0) header.moveSection(from, to); + + from = header.visualIndex(Global.noteTableTitlePosition); + to = Global.getColumnPosition("noteTableTitlePosition"); + if (to>=0) header.moveSection(from, to); + + from = header.visualIndex(Global.noteTableTagPosition); + to = Global.getColumnPosition("noteTableTagPosition"); + if (to>=0) header.moveSection(from, to); + + from = header.visualIndex(Global.noteTableNotebookPosition); + to = Global.getColumnPosition("noteTableNotebookPosition"); + if (to>=0) header.moveSection(from, to); + + from = header.visualIndex(Global.noteTableChangedPosition); + to = Global.getColumnPosition("noteTableChangedPosition"); + if (to>=0) header.moveSection(from, to); + + from = header.visualIndex(Global.noteTableSourceUrlPosition); + to = Global.getColumnPosition("noteTableSourceUrlPosition"); + if (to>=0) header.moveSection(from, to); + + from = header.visualIndex(Global.noteTableAuthorPosition); + to = Global.getColumnPosition("noteTableAuthorPosition"); + if (to>=0) header.moveSection(from, to); + + from = header.visualIndex(Global.noteTableSubjectDatePosition); + to = Global.getColumnPosition("noteTableSubjectDatePosition"); + if (to>=0) header.moveSection(from, to); + + from = header.visualIndex(Global.noteTableSynchronizedPosition); + to = Global.getColumnPosition("noteTableSynchronizedPosition"); + if (to>=0) header.moveSection(from, to); + + from = header.visualIndex(Global.noteTablePinnedPosition); + to = Global.getColumnPosition("noteTablePinnedPosition"); + if (to>=0) header.moveSection(from, to); + + + from = header.visualIndex(Global.noteTableGuidPosition); + to = Global.getColumnPosition("noteTableGuidPosition"); + if (to>=0) header.moveSection(from, to); + + + from = header.visualIndex(Global.noteTableThumbnailPosition); + to = Global.getColumnPosition("noteTableThumbnailPosition"); + if (to>=0) header.moveSection(from, to); + + } + + public void resizeColumnWidths() { + int width; + width = Global.getColumnWidth("noteTableCreationPosition"); + if (width>0) setColumnWidth(Global.noteTableCreationPosition, width); + width = Global.getColumnWidth("noteTableChangedPosition"); + if (width>0) setColumnWidth(Global.noteTableChangedPosition, width); + width = Global.getColumnWidth("noteTableTitlePosition"); + if (width>0) setColumnWidth(Global.noteTableTitlePosition, width); + width = Global.getColumnWidth("noteTableTagPosition"); + if (width>0) setColumnWidth(Global.noteTableTagPosition, width); + width = Global.getColumnWidth("noteTableGuidPosition"); + if (width>0) setColumnWidth(Global.noteTableGuidPosition, width); + width = Global.getColumnWidth("noteTableNotebookPosition"); + if (width>0) setColumnWidth(Global.noteTableNotebookPosition, width); + width = Global.getColumnWidth("noteTableSourceUrlPosition"); + if (width>0) setColumnWidth(Global.noteTableSourceUrlPosition, width); + width = Global.getColumnWidth("noteTableAuthorPosition"); + if (width>0) setColumnWidth(Global.noteTableAuthorPosition, width); + width = Global.getColumnWidth("noteTableSubjectDatePosition"); + if (width>0) setColumnWidth(Global.noteTableSubjectDatePosition, width); + width = Global.getColumnWidth("noteTableSynchronizedPosition"); + if (width>0) setColumnWidth(Global.noteTableSynchronizedPosition, width); + width = Global.getColumnWidth("noteTableThumbnailPosition"); + if (width>0) setColumnWidth(Global.noteTablePinnedPosition, width); + width = Global.getColumnWidth("noteTablePinnedPosition"); + if (width>0) setColumnWidth(Global.noteTableThumbnailPosition, width); + width = Global.getColumnWidth("noteTableGuidPosition"); + if (width>0) setColumnWidth(Global.noteTableGuidPosition, width); + + } + + public void resizeRowHeights() { + int height; + if (!Global.isColumnVisible("thumbnail") || !Global.enableThumbnails()) { + QFontMetrics f = QApplication.fontMetrics(); + verticalHeader().setDefaultSectionSize(f.height()); + height = fontHeight; + } else { + if (Global.getListView() == Global.View_List_Wide) { + verticalHeader().setDefaultSectionSize(Global.smallThumbnailSize.height()); + height = Global.smallThumbnailSize.height(); + } else { + verticalHeader().setDefaultSectionSize(Global.largeThumbnailSize.height()); + height = Global.largeThumbnailSize.height(); + } + } + for (int i=0; i runner.getNoteTableModel().rowCount()) + runner.getNoteTableModel().insertRow(0); + + if (row < 0) { + row = runner.getNoteTableModel().rowCount(); + runner.getNoteTableModel().insertRow(row); + } + if (newNote) { + resizeRowHeights(); + } + } + protected boolean filterAcceptsRow(int sourceRow, QModelIndex sourceParent) { + return true; + } + + public void setAddAction(QAction a) { + addAction = a; + } + + public void setMergeNotesAction(QAction a) { + mergeNotesAction = a; + } + + public void setCopyAsUrlAction(QAction a) { + copyAsUrlAction = a; + } + + public void setNoteHistoryAction(QAction a) { + noteHistoryAction = a; + } + + public void setDeleteAction(QAction d) { + deleteAction = d; + } + + public void setRestoreAction(QAction r) { + restoreAction = r; + } + public void setNoteDuplicateAction(QAction d) { + duplicateAction = d; + } + + // ICHANGED + public void setOpenNewTabAction(QAction t) { + openNewTabAction = t; + } + + // ICHANGED + public void setAddNoteNewTabAction(QAction t) { + addNoteNewTabAction = t; + } + + @Override + public void keyPressEvent(QKeyEvent e) { + if (e.matches(StandardKey.MoveToStartOfDocument)) { + if (runner.getNoteTableModel().rowCount() > 0) { + clearSelection(); + selectRow(0); + } + } + if (e.matches(StandardKey.MoveToEndOfDocument)) { + if (runner.getNoteTableModel().rowCount() > 0) { + clearSelection(); + selectRow(model().rowCount()-1); + } + } + super.keyPressEvent(e); + } + + @Override + public void contextMenuEvent(QContextMenuEvent event) { + // ICHANGED QMenu から NoteTableContextMenu へ + NoteTableContextMenu menu = new NoteTableContextMenu(this); + + // ICHANGED + menu.addAction(openNewTabAction); + + // ICHANGED + menu.addSeparator(); + if (Global.showDeleted) { + menu.addAction(restoreAction); + } else { + menu.addAction(addAction); + menu.addAction(addNoteNewTabAction); + } + menu.addSeparator(); + + menu.addAction(deleteAction); + menu.addSeparator(); + menu.addAction(duplicateAction); + menu.addAction(copyAsUrlAction); + menu.addSeparator(); + menu.addAction(noteHistoryAction); + menu.addAction(mergeNotesAction); + + // ICHANGED QMenu から NoteTableContextMenu へ + NoteTableContextMenu titleColorMenu = new NoteTableContextMenu(this); + + titleColorMenu.setTitle(tr("Title Color")); + menu.addMenu(titleColorMenu); + noteTitleColorWhite = new QAction(titleColorMenu); + noteTitleColorRed = new QAction(titleColorMenu); + noteTitleColorBlue = new QAction(titleColorMenu); + noteTitleColorGreen = new QAction(titleColorMenu); + noteTitleColorYellow = new QAction(titleColorMenu); + noteTitleColorBlack = new QAction(titleColorMenu); + noteTitleColorGray = new QAction(titleColorMenu); + noteTitleColorCyan = new QAction(titleColorMenu); + noteTitleColorMagenta = new QAction(titleColorMenu); + + notePinned = new QAction(titleColorMenu); + menu.addAction(notePinned); + + noteTitleColorWhite.setText(tr("White")); + noteTitleColorRed.setText(tr("Red")); + noteTitleColorBlue.setText(tr("Blue")); + noteTitleColorGreen.setText(tr("Green")); + noteTitleColorYellow.setText(tr("Yellow")); + noteTitleColorBlack.setText(tr("Black")); + noteTitleColorGray.setText(tr("Gray")); + noteTitleColorCyan.setText(tr("Cyan")); + noteTitleColorMagenta.setText(tr("Magenta")); + notePinned.setText(tr("Pin/Unpin")); + + titleColorMenu.addAction(noteTitleColorWhite); + titleColorMenu.addAction(noteTitleColorRed); + titleColorMenu.addAction(noteTitleColorBlue); + titleColorMenu.addAction(noteTitleColorGreen); + titleColorMenu.addAction(noteTitleColorYellow); + titleColorMenu.addAction(noteTitleColorBlack); + titleColorMenu.addAction(noteTitleColorGray); + titleColorMenu.addAction(noteTitleColorCyan); + titleColorMenu.addAction(noteTitleColorMagenta); + + noteTitleColorWhite.triggered.connect(this, "titleColorWhite()"); + + noteTitleColorWhite.triggered.connect(this, "titleColorWhite()"); + noteTitleColorRed.triggered.connect(this, "titleColorRed()"); + noteTitleColorBlue.triggered.connect(this, "titleColorBlue()"); + noteTitleColorGreen.triggered.connect(this, "titleColorGreen()"); + noteTitleColorYellow.triggered.connect(this, "titleColorYellow()"); + noteTitleColorBlack.triggered.connect(this, "titleColorBlack()"); + noteTitleColorGray.triggered.connect(this, "titleColorGray()"); + noteTitleColorCyan.triggered.connect(this, "titleColorCyan()"); + noteTitleColorMagenta.triggered.connect(this, "titleColorMagenta()"); + notePinned.triggered.connect(this, "notePinned()"); + menu.exec(event.globalPos()); + } + + + @SuppressWarnings("unused") + private void titleColorWhite() {noteSignal.titleColorChanged.emit(QColor.white.rgb());} + @SuppressWarnings("unused") + private void titleColorRed() {noteSignal.titleColorChanged.emit(QColor.red.rgb());} + @SuppressWarnings("unused") + private void titleColorBlue() {noteSignal.titleColorChanged.emit(QColor.blue.rgb());} + @SuppressWarnings("unused") + private void titleColorGreen() {noteSignal.titleColorChanged.emit(QColor.green.rgb());} + @SuppressWarnings("unused") + private void titleColorYellow(){noteSignal.titleColorChanged.emit(QColor.yellow.rgb());} + @SuppressWarnings("unused") + private void titleColorBlack() {noteSignal.titleColorChanged.emit(QColor.black.rgb());} + @SuppressWarnings("unused") + private void titleColorGray() {noteSignal.titleColorChanged.emit(QColor.gray.rgb());} + @SuppressWarnings("unused") + private void titleColorCyan() {noteSignal.titleColorChanged.emit(QColor.cyan.rgb());} + @SuppressWarnings("unused") + private void titleColorMagenta() {noteSignal.titleColorChanged.emit(QColor.magenta.rgb());} + @SuppressWarnings("unused") + private void notePinned() {noteSignal.notePinned.emit();} + + + @Override + public void dragEnterEvent(QDragEnterEvent event) { + StringBuffer guid = new StringBuffer(1000); + + showColumn(Global.noteTableGuidPosition); + List selections = selectionModel().selectedRows(); + hideColumn(Global.noteTableGuidPosition); + + if (selections.size() > 0) { + QModelIndex index; + for (int i=0; i ix = proxyModel.itemData(index); + guid.append((String)ix.values().toArray()[0]); + guid.append(" "); + } + } + event.mimeData().setData("application/x-nevernote-note", new QByteArray(guid.toString())); + event.accept(); + + } + + @Override + public void dropEvent(QDropEvent event) { + if (event.source() == this) + event.ignore(); + } + + // Return a column width + public int getColumnWidth(int col) { + return columnWidth(col); + } + + public void toggleSubjectDate(Boolean toggle) { + Global.saveColumnVisible("dateSubject", toggle); + setColumnHidden(Global.noteTableSubjectDatePosition, !toggle); + } + + public void toggleChangedDate(Boolean toggle) { + Global.saveColumnVisible("dateChanged", toggle); + setColumnHidden(Global.noteTableChangedPosition, !toggle); + } + + + public void toggleCreationDate(Boolean toggle) { + Global.saveColumnVisible("dateCreated", toggle); + setColumnHidden(Global.noteTableCreationPosition, !toggle); + } + + public void toggleSourceUrl(Boolean toggle) { + Global.saveColumnVisible("sourceUrl", toggle); + setColumnHidden(Global.noteTableSourceUrlPosition, !toggle); + } + + public void toggleAuthor(Boolean toggle) { + Global.saveColumnVisible("author", toggle); + setColumnHidden(Global.noteTableAuthorPosition, !toggle); + } + + public void toggleNotebook(Boolean toggle) { + Global.saveColumnVisible("notebook", toggle); + setColumnHidden(Global.noteTableNotebookPosition, !toggle); + } + + public void toggleTitle(Boolean toggle) { + Global.saveColumnVisible("title", toggle); + setColumnHidden(Global.noteTableTitlePosition, !toggle); + } + + public void toggleTags(Boolean toggle) { + Global.saveColumnVisible("tags", toggle); + setColumnHidden(Global.noteTableTagPosition, !toggle); + } + + public void toggleSynchronized(Boolean toggle) { + Global.saveColumnVisible("synchronized", toggle); + setColumnHidden(Global.noteTableSynchronizedPosition, !toggle); + } + public void togglePinned(Boolean toggle) { + Global.saveColumnVisible("pinned", toggle); + setColumnHidden(Global.noteTablePinnedPosition, !toggle); + } + public void toggleGuid(Boolean toggle) { + Global.saveColumnVisible("guid", toggle); + setColumnHidden(Global.noteTableGuidPosition, !toggle); + } + public void toggleThumbnail(Boolean toggle) { + Global.saveColumnVisible("thumbnail", toggle); + int size; + if (!toggle) { + QFontMetrics f = QApplication.fontMetrics(); + size = f.height(); + verticalHeader().setDefaultSectionSize(f.height()); + } else + size = Global.smallThumbnailSize.height(); + for (int i=0; i|w|<$R09H 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 diff --git a/src/cx/fbn/nevernote/icons/appearance.png b/src/cx/fbn/nevernote/icons/appearance.png new file mode 100644 index 0000000000000000000000000000000000000000..844109da5ecc7a16ee27ef14564387a60c83fbc0 GIT binary patch literal 3298 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 OjX*|%|4y6-BmV`Xx(Sc~ literal 1384 zcmex=OMR%SMKMkWTJq>TUr zBQrA-6EinAD@2-+iJ66gRgg_l$WYiZQAsVZu(+{l@y1OTjhtLULQ5u2TDa(-vZ`}X z5m2`zBgkl&u^^g}1t`J_lu{OCU}9oqWlZAvIPj2tMOlE`SNqrU8|}HC{`t>PT7U7ot4`3W2OP@6H9KmP zzo|crh)UOsFITZU2mn`T6?Y!rL1RaK{8(5E3`GZ{3Rqc&pm1} ze*D31-(=3zRBkO#iLl$e+n-scwKF*t%FT5xk@xzV`6I|Svu@}9CGXDc)QsWodK4lw zWx29+Ph;rG@8L^qkDR)8IXR_eMN_q}^y<)iSI@sY{VgmrX{W_kqjeV(6{@D+bt)_a zIZ~_i$hKD9qbv)RRlO`2DtwKuq>FdT_3zR)x^8^AP%kQa!nT>Yo-a>Xu6a{YUD zX0>r^%#5?8roF8_c~L79Cg!GUdHiS4KJeg2gTmuu?p>?GWs}R&9*RB)*D{jfE}izf z#bVwTR`tU9e14j9Uhay!o7>Cha&^^%TR}Vpx4NVxZfhMcDeOJ@_Q2BqDJwoIG)>;2 zG`Tv~&*$~!Wy`K;?2&)jvHoT3^q>KGobaWfzw{tenntUn+Xdi8N_h zk(39@i#?A=NPqHwc+2zh3R!jKcz0(FzhWJo9kQ9)%redv=d~(Vi{86?`rYeqp=w%r zlVr1GJb9;!6m40!cY@WYMfF`fvo_y*di;d;O?RK!j)teZS#}&!Jnn zyn6hOwI14ermco!I{U74r%Nx73r(sE(@>3@6SCxZ>b!?q4=ta$vhqDPeCfL+x!Lvt z=c~ncqO~VqFbQg%5c0ZHy79sJz@^_N-nw&a))$Uk=k4#mdFmU>8s1`1S6)_7VSoL2 z%;rVj+r@LgeVMAEQ!r^w+vVOr5sPvsq}-h=sN3=4@q+&hfuBz*|FmDZx^=eS=CoPy zU9V1s9cNzX{&cl+O=;;r)2*R}&5w%ow{G=|{ZrL`E4Sy?;{x-$R%`DRd=C5(uxoAX zyE`>aD;G`m{2H|T-i}Jq;0T5U2L@q>tLox6?b>%~+g+9Ay}M;|kK*PjR+f`*-h8_{ zZvBH`CIq$wA@$839Mxsd1t2{p5;spZsUIl&vi~vtSw9-M-7s zn#Q?r4>%P1r?Rh>P}`Y!dHucR>%3RSRB$p{9^-CKZv6E=oPFJ_*vr#ZqQ%^!ns~iR zRj2T9&xxsY3|%*OpAW;0`^ssuLdF8gN;YAaZhJ^DRQu;v1+9$Qsyh3v#{D@VSy!gz zZ(01WD!DV`s@IZROJm=k|D?7rZ1Lv5i;h2ATGjS5XL8z%)54L_-8n5wwC6gd%>REA E040n*NB{r; diff --git a/src/cx/fbn/nevernote/icons/rensoNoteList.png b/src/cx/fbn/nevernote/icons/rensoNoteList.png new file mode 100644 index 0000000000000000000000000000000000000000..1196a3fad6759822ed803f2d18b39db7a96f15f8 GIT binary patch literal 9557 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 literal 0 HcmV?d00001 diff --git a/src/cx/fbn/nevernote/icons/splash_logo.png b/src/cx/fbn/nevernote/icons/splash_logo.png index cc577372e2a4c1d80a933e28c4f8a31d04f62b64..b11abb73cb165451508795a44bfedba1e314011f 100644 GIT binary patch literal 29727 zcmY(p1y~$Svo<{V26rd81`8V89fG^NySr;}cb7mC+%>pE2=4Cg4*x#Sd){-tf3ItH zXL@_OyQ)j>s_ICEuM$Y``0xM#AW2DzDggjw5cs|i1PlH~uoIL6|3EtnOR0dsA0LoO z1o-)bgQTW2xc~e=7lbfPmIt^I&qYkbMcLlW#of@!6mWNUXSB4lb~ZM2FlDrNGS52W z#RmWqKuT0d#UuM9$K8NXJ?Ejz-pt!x%T=b4;vRdsMmgK6j8jsWreGI+2~D_ddt*cL z!ErOzFN7S9G&w#VfTKt|VxzWmJXcja*E*G6em)yJk7HP3xi)ia5KCM)_Y_~uxL><( zIQQ9q9wGAp-r#{I$Us37R1h@ertp?2Gzy??OACJZw=G2?@v^DbO6i|}|7oC;LM7=% zHSr%0tDr{s&s#k!W;Qm6s@kwMY(8xeKrLSoxGS@Lh75eB;CFPBXq|vDc#(J-3rHbU z7I6?XuSqm2$m7ePViFg$k{^GCyb{^x9 z{PxdoQHsD)ire%p8tx!CtVT}FCe4mGdKC_)kyX+`2)_=P>w z1^BGrl0yV(Q2wPk3ZFbqWggb@`A=J$U% ziYz)XWV0chjo+y-B1M7;r#Jx}gbH5Ii0H2WN-`m_NV+|EH8dF4d-G+(xTL5TIts=n zxgOAwK~$)Ws6*fu=4x222`axjSTF-Xkmj zp1c&O4&iSdh}DQHY~$t7=O3Of!W?S;m+_{=V#ElzXqs z>7j+W{yW`fP=F0K>6qC6O-E`>G3;{-nlO{(`@dI(Y4AevgZ@WK{vAx1#3196sRIi- z1E0#|U-2lZh0i1bEMpcymML5Vyx{f`&p9D2lSUz}fAAtU4!T?L9bjO^^N+ZVWz?w?#*S;xoZ6;ElYrRk3gHeq{I)8@_Lw(r7BzPK~sA;OvPv5v4(|U@m|g})5F4tnA zY1ICR&*w+3l_HooKZC)t|BtYQ)FyC1Yo5h&lyR?5BESB0-QSpK5Lqiwt&F!;WyaP4 zk2|ysHKb)A z8=o9n80+6HQJ($GLe2TDFCF)3ZS9<4^>gz!ynLUs{{;qI7Zh;uqp0htk#kE|SvJ#= zqY@gRC<#UCmc>m~jPZ~-d%6rHUVmK1=vr-S@w|49v-P#f3rQS<8N~SiNuA@~*o;Hf z4~e%|Ux5V=qpb%ljJL>fMJg>QfTV!pqa=O}ez{k@g-CqlCy0Q=>8l{bZp3)jo%WNG z$~4C1wXW9{PR7@Pd4ZZEj3Tj8F_PpUO}^3(A({Y~IS9F$r)Y#Xh$9~tUoWr*Z3peL z;pJ?NaK&?5Q}H_-sY-cx{UqBu?Skc*=3|y#wgH6)Zst@|Odw#Vo?hj<+0ghX@hy|D z$vwIM7c-u_@jScN!$8O+atac#p#<9jP{GYul^%PSv@(@hjs){S-ycqQALG@t%~j6W z=Ygu2I!D(deBl+cPS%UB+fS`X`_?maHH_x!TY9n24g;i6(dah9zu2X?bf(dR^Kz23xW-KjyQc$6ghGw7z!yL)uCYG3S% zV&w_nd-#}qNN&>Z-_NhNlt{;%BAotL#Z`@qkCb~iH6or~8YgX6Ij`2JgK7+{OG%8% z+-*BA#R0+Nqq(@(!}{v$m>)3dJ7#DpDykPV)e3sy;wV0k3A!lv{7(JuUz3>+jrvJZ zK`;MfB~5Y_XUjJQa=ls)!=K---yg|3`+-O0uB}pcO^0w@BtUR=#;tDqc=?@n0#e49 zbiHP?wG>I2&>Bs1%s-NJ zKwR$qX=0w(_78`jtL>>+XAnmE`~O*dR`~%*Q~A6f%@Tk1nxq8odf>YLoS(HBQ)QS9 zAoN4tmRG5u&uVB4q3#&|UaguLz0Lk81id(5{`sMB&6L=4Gq3BAT~&n) zx@RTiA7eks3zpFqaWTH2XNkKb;+4B{Vh^&leqMrr{-lDq-Wmnp?8qrLu{y67w-u~R zIy$K=e_2x%T+gzw$4;i5DbyH=u_~92hgCii9{Il!$b*{V;-qvHNyp;!(xVPZm7XRI zuHzTur%lnBDXAKPVAX*8uXp;_@zpg_;DwQBtC7aV63_8BpDGK0jgqZOEx*}~T@EP& z!cUw1KW%%~T8*-q$)%U1lLk-HRKky3BFfTrBia5w(Sl^nt3y7`B9*F|o^aIjD9ukB z7YjlUT@zis2s!@VNA~Vr4>NG@e)HiCEWe&>OGhWy+K#qgowW2U8pf9%Gq{gM-PT7>&kDlkHCHaW824+GbS!xC%amL;@=ga>v-_9i?k-J#O^WaE^~Hy>_$c z*Gj~VbfUUOTyJ#I{d<(F0Rh~W0&e!aAJtFseQ^Bh?**W|Lf>AbkB?5{bZ!rpW0nSt z{9!_w{r^>8R;B@vX0jj+j%gk~|NfVvx3N!o4}k(lw)@xhC0!E-hoNpy5bFATK(?ld z4KWV>?c(uk>17z-h?lLg$DS6{?yIVWXJftH>EhhA6+>b(H>=$&*m1>>pJ@{Z7Oqmr`-&k5xf8z3*p6dPOyum!7zzV4yY#`N-Yo$t|7TC zPvd{nwO?q%J$I1hmu9u2oe8Lgv$>@Qmi|;vQJKAxrd=M!Jz-+2%0)x=RsT+%VP-7m zRnj_It33!CmT>cNCf8Rql2vh^^E>Lz^FLK4wwU2KZMRlVu@T&U6)*#*7biGdM797U2QvnAY{Vg50!=Ew?%X!l^@~a(RSD?>_1f+$P zH*qo4;Rl%rKd;FLulzv*zE3W$(rLKUf5N*&)O}ufBi4To-|ph`?GO5)@9}UXaZf`j zU8=&OAMpQZllg$;Vr<-FUhsRv$xL63_oymH%SR6VJ|5qYXcg0I2_J;MvP2R>giin< z6;F};a=J+`%?d+v^7?an<`w|J9QhS`Qt1|+^GWZ_%P*AY#OKA|?s0XL5;avYJ#GvS z40TjKu!u8~j2MCLTD+3wiQjMM0gWi(U0snBbZ*S+d7-~Q%2TXtAQZz4I5ssTKLE+l zQwcOwRT(J~3(t#YCkHUV2!>Mwc3t@3&-!Kn@O`|U)V)8Se{*Qls))p)q%-9B7i9cn zc_1WW4HZ+%H>=w3GW-$ygak=z}lcix`QtsjzV;PHxqn+9c zKw!m4xNK?+UCqu5+LISk=0g0h5S(@1~J{OFZ!2+5bNaP#1y z8>TS&&<846SHEkDYvV|{1abHafpT8vm%G5p&YPNh_w+Qo=S4aBmx8a;f)gZTVgHMf zbGf+0rH{~jY}W7RWnoW#$S7iH!e$LYOSA_!00G>x->5^P6)Q(SQ&j+9SVDo;=e}T& z5Fs~FQGN^qux%V!)Ar%YtUH$|CL~<69*UW){khY=ee%ow^>E+Olnt_LNiktOqj|gDNP%%6NMB&Zszo zRgn@8odkBa7U9Hzqk5y`Lt!-o1a7b`mQ0|G#iu$&3Y2$W1)u zb?x`vua*x6oWaTYmd;5aQQoPkGeoBSe47{7d z|G3D_o`C3EPgyD6pfa1m8;rNh2A}Dk>GfJd|CCt48GVFdrvnr2HtHR%K5`JXBS$F! zNHZpgIjl7cyOV!o_$g$Ft01j9MqvJ43uvT@D>Pr0rx9cW0lcJ5dSh&SkO5NfeIw6r ze)sdaozL%n1`4<>u?iGpdjG0fJh>+bnx0aV{2{!kYbBdS=OVwoOWG23U`z2d!dzkY zyEZBt-8e>3Zb3Vt!()HOcS0aOI~B{%2a(Ztvrpq&#omhRX;UW%IEa4raIPe!n|oj@ zANvXjzD203OX5-a7+dqd_Js4_r=fJbT|*X*M{EAfZ);MEm3|dFdnJK(vqkTW>=9q^qI!#S^w_p>ROQ$-hD0S@V;+v{3jE$y!qn@W z_-l~RkJdTAFmkx;Zfx@{ctJ35CS$qYHV)~?v&t~@@f<(WCD!s?uN>8?Y^3fg9q1@> z?a%Gi_)+c*0ZE5@O#p9;q2H%W5DinTn`GYb<9MzO{u`gbLeqQ3oiAMOTlJ*5J|oA( z*?n$=CWEzp`||{Gy8#bLKR)JhzyV~weY>Qf!D^sRby<13N@cjuQ>4Ly>2f$-yUyY{iOv1w+!ZH5 z33k4*?_1aUk1w=2dV@`*_G_^Te7v`iz($r<^>r9Q=S|a(COtj^zk`h+YH$!O_7y1) zSHMK_1yjqCcCL5sm{)%k5|Q%|=L>w!nkfmRIRs6M3flNL?F;hs$7v|Rp&WBrS;t}*6p^7d{7e`Cbpj?27&57#o8N25DGN-G(+SdAU~O|V^w*- zLEmea_-%c@%IoHNzG0nP%K+UuGfnTU>63h}*R3)@uba*=D0z}3apto%+%`X_F?Y7& zbc*B7WTA_SX^mP7V6Oja{H$K&y=AZrclP=_UX+ehPpHSnXb$(Y`9$YhwekKou?u(j z9L^IYA^fr$G0$U`s_yFYdfU}i)w|{C)9r+C`?JqBCuY=lzwPpHoFB;Z zdrg%wMbyDch|3?y=Xq`?fgp5kj9EAIOq@?NZl2eXI9H#i&R9lZr*c|&OW%-L$` z6=bsu6t@m8xC&JEK*fyvX!f1Ay^}DI6QTWIyUCzwaL>A4`qR4XZas6VEzo%8|!ym zwFz8?u14i`-5<=8T}GsyyJa^y&}~#h0u7yqf2E)!V7i^;$`aY2X-h=0#!qwl$Af?eElc<{$8|+2y|`rJrr1jakDL*Z-XomBrrmJIfv~WOA6UX z-&A=A3BV7EaEHKWdCd>8tqlk0#sDPPaTR%AE|TnJ9|qs{KV=c~E2L96$DJ;}A7gXW zXj%+Ns`6>SU9=I)`d$8bzieGJ!d~+U_D;(53o+rB-P;lg6{JBpZ+~7`68zm#jcGZo zS{ZA*?Dt@pw0IMqVy)&CY7AUx@_;C-DE%6agIGPF{bwK&(w6BGRnJ-1*m=*0?6$3? zrU-;l1(~s{b=JIo>57kLn8&_4IrMNg3X9hB@*0+50r5hHQMASI?q9H39K^pOu;;+{ zGJlB6S4n9SSFq7cR+^nj%uMk<(|9Z3n{QlA%+)g02z%;H7)u_S(W-X#wPIkKgFSN zzclW5y7z7`!=sAPENh03^3ADL+^&Eiu3+MH-|rfm zjQk`buftjv-7i!+>yIy&m>0M`F8d13-L5bGQ2MbYd`~?$W0xq@j<_iEWV zs$CgdAU{Cl#)cQeG#0I~(eW~{NON^QRs*XbrwxuF$Y~SB+e%5(%2dlcWD<1;GqZ%( zut|kd_4*@m?=8EWlrTeBqlkLbYW;q%^~W#N1;yosO8Y0&F7iZg{aDlkD7w3G4?oML zH=H0XO6tO0!;BdrW3V&JB_u~_c;mv z`yM`afv(rMNwZ|z-0oBtlsYXOc0xX%`or9~HC74_)(O|F3p$GT%v*Se#!-p%a1xcJ zYdB20eEC}Y(|b$I_tj|L+r-YyyHxawv1s0)wQ6m2 z<3g*i?y%u4B=u|OGY<)SOC0@pk%nPkvHIX?bQExq351pBrk}ypB~? zt31N2Q&VD?2P6AiuC^OZO9u~u7G~OU{&4@E_$Sqrv75<-SpEBc9D#wiEnj~xI*B1_5x(iyK|0_c0|&kz>aE{n(lL)GYMFoGUGuhJ7szLqcAI zJJk(3^crr0J?OC95dJ&D)W+tIw7z~%9(G>pQP!eu{i0-MB z+vBjtoOkWb548Yd?+`Z;^{tGRny2gtzJ!2_^XkC2Pi&O)L#}wry)W+iEf-IxD0*+d zf@vWpzY@+1IPYAJ4-O*hVnsaA!$=|n0Cy;<%bH(>)X8fL`q2(ICrSQ5NAKcv4;eH_qL1p%HFLEy!FKb`)#$oro!xjqw*^Rw zB678jezeeVdA)I9VQsW|>xkh@t7(vdJwxunH7H#|^lI1eNrVPl$^9BD8g0RwaSS=9 zipT5v*=|kQ_}As=?o~ahMcw)Fg@n6L`ls9)DkFZ^EtS=0frmG=sKN_9P@pcQvxQZ2 zJ&Vy1r6oloC6fjn=Oaf^`R0dpP#38N2?!wUtPuzD8SPiO-==fcjc`*LekM_ba&bEL zv=*DCRH-d9M_yMts@74TC|T`3MQ|ZD4A`p z(@hM1XA3{=bhIvT&1_xIXKn=mIan%qer{MG|LgPyinwo!a<68)%hTdBW5xQHTF*__ zZ84M2)xODnh5E#Xk2i z4Kn*|5#y)v44N^`US3_I&k~!f^$36-XOvFEZAGvCQyNq5aL4d|hvP|_{E82GFKkT9 z<(OLhZSINfP4g->k~q|zSgidERWy+xK%WA_!T!?0(c$M{CSWT=16pg%otn8&`CZAd zckl4%085Aj1k^kE>U^4x^X{z-Gg2aSy48SK=%n&JE>1_n$av`e*rGbUfiunXOf_lS zd|WPP4W-z{l|$t=GJ>%+)JG*ns({L%i`{?jVG~=G|mh*T40saj5Vx$8$pW&Ki(PPwl!AMzv z*^I|W+d_ zzF;U#DPkojSksMjIU}}hh#w$^9pj2isScq`NczsYdQR0|gbfIOvsU}U(uIQoiI%5R z#Vp#tLJ$jc+x>lA$KoTVgdkv`s7>xjMTL=qoQaIzGS}I8SUYd0eYvR&2+mp&tgwkm zTrY96=p%2t_d#3`YGTR#jN{VnaILQgN^w_1rSg3#GT4 zq7h>%LaqkcNk{&n##Qq+quH+p7aE1ABh&N zSDQB~B4Jm9rUJ_u&qP_TjIKK&973tAfdDN%?}V&EnlJ`~C@$RVPl(da(biU+JY6sE znIAxa)y(bY7mSokOfHmPI`(bG{T=?V2TzlEg$iCo2u};(J4;Tc=X>JwmpyYnQgvUt zR~?p;v?-RZkVHX>k9+qZGo6Li_kmNsq<4qr@pjo6P3^k)pGH?i@L7LMKoA#I=9=zP z;mC+_Cmodctqp;ydHkMcfs@C_b4T?rdNA;u;Xz8v$M7HXpnDL}eneFu>}?nUA-dlh zFSk%`KXO0uc+($M4R@G*|B%(n-6oq=)wvQmo@Ry<0FiDhQc+1$Q{M43I)za~{_LlT2Y=AlgH2}1?eRWo!3v>0UK zoOOSdo6mNvc3=zPF*8cB{i-!Lrm=tTK4ece&7a&=SmG$Zq5c3fjY;o9vZefu#f4rzOD=n_0_fjDqill6%oA$bzA43#7g$!i z>Q)Gi_wpP^8s@1U$u6WZVPn5{>R12%y0=!Tmm|2=u6!47Vc*Fp(c`1~XNUYoNMJeDU^o2vBVq&FNc>7a%C}%X-Brk_*hoT*}Y%55}~VNKlZ;TI3Nj#K1=C z?qDN==YP)v5PyLOLI3cV+b%8Vxc<9sZX;3EM_G|r?h^p?r$^BJ5)AY{;$yw5lOTTo zBR6{X*6HH49r2y<^Rnb8yV!FyVVV-&$E{B(nW*YMF{Fj(hiB}yAS&jJZEY42MT0Z4 zF(OHxRQz0gxdWCE4cVM3El=;sf?j!+fU7iATK131B)G}nRhsp2g;rY0AN|YWSiinJ zesJ$F(b=17EguSz23HNgc@Bwg8;a3tePTs2|E-so*#Dg+PS!&Lfg2TEFwscmw&tiF*x^0)-~wf{hi^m@+K3nPB% zy>{|PijqC)mN&VppYH7B=bBy@&CLGFw6N1VMQ<4O3(MxY_bQq{R&XAk`s;LPAvZ4E zwc+V3)!N!P-=<@%RaqY;M5fr6%GB1NUm4G8bX?fwuOG9zW=x-gSW;ZF`*&(-i6d{} z*|Cg?(r)M>4JvpFUy&xdX!Alv`Ha0~r0Tx4Ln%eN-&+_`H~_CpbInHx7WPi_Zi9RyunUq|W3;F4Nja(PF==1H9wsNW-AUAllnWrCrHl-LA7^6{O1{U@*EB)*1OceM1ExmFp8I`{ zGIfTEg4r59YMtVxw>(hDT%#=YxJb#GxvL#j>o0Grd0&?F>UzkE(ykGn1zt=grI!~*D zle52WvC?)voRu>XSm@VNhkmm7ye@0}inUz1@KU1ddW%FV#V`V8+IV zU|fe>eF!rD^JD-Xpa9-0A!}&k%W80TF(fgHTe$Sk@1}IAucN&{04^0HTGB-MR4{^P z;wVB#lKE077)C8`)ISgQ{d$zGWDp$=WkkeKez~u-@6!LttBTmJn)z4L6GG`D9CY(T znvT=EWmICA)3!`8$YkU)m6duD*JGRfgXOoWrZnhP@XAZ3Ji2It4dCK~J+T|`WvbRas>nf4HkL_~TYuzY&b>Y%0 zK&)Zq;Q|Fq82b-ym~I^yblyAQu18V1XYtAeEuz5oEslv|1YMjWP!@N{r*r zt8V16ef2hrG4F3YIFaYGwojn1^4dBGBffQe`}1{mn)7uqDenE5QZFv8sS5%S+gvIU z-Mo0i_|!Jxis#_eetUP%_}a*QCd_$z zX-vQ%EG%EC5Z>HRF%xSU#BDo>4~9ubx~%-RP9_9o!UOxo{wt7xip02dS+ybSDykwC zJscoSl^~A5&i@Sw6QH4pVg?itlhX0A;d#9EI!{;6(lSHsPVehQ{k;XsB_aF1AwLa^K< zvs$AZo^}|FNRWX)PkWziF@ zd~q{-7){V$!-|3_>Axwlg6q3qiWU5WDg%>LZW{3kDTlQ3h=1J{%!d^ejA$wucZFOl zfBSQ$`3I=GJ(i=AT9{v!K8N~w&#&CsO`%P?BywVX{R>4wPJ~|`mbC$m3Y{JyVL@o# z*T0(we^F3~+iRCjb!Fo};cB{{XQk!wxvEVra|AR&3x;r!rHyK){7rN>$(RzJ>V@*X z{n#Wikk@6MdwKYbatJ2=nCPm|01cRt&N1TrP;8h82VKuk`~0)E0;XeF z=I-a#vh3L$_6{AZbCMkgL0@;xJO3`oF!Nb~ty&U$C<(19xQ3amG} zqUDT6YP3U%VR_NvX1CCf$>VL8Tk5yXtRQ*GfwcYPx~5JxCaM$^^bf+ujYZZ_fx!DH z6qTPBiRz9igmP*hyB=5jT1}(VylHEi(@jFbW>EtmsM^-?4QaEw?rtcMe2%vy<89-Z za#0;xK-~D+!OkaBTyQj-og+)Gn}F4mgx8)}F1x?q(3tsjmyO34&hv!bWGFT?!LYrI_Qbgl&6|Xs+3ft+Nr($bg$baO3e2Gkx>1QV%kV= zVL5SDXR3YQ1q>K4OP3fb;Fg6%PpS-EfUw)e9jL^Ug$ofSwhZx05TRtBGP<#xOV2Lv=Yn?nmMVmE+VYCpS6+&XObUCfjJb(e(6* zHvf%NhN4_Q*96_d8RC;i{R~oxa@nkK5TzfylqkNft@=I@9TH8=*Lblz?&lEQ?i^0B zOLt_Sw-0jKCS_SL-RHN~uMk}!RWLQXP!vZH`cWwQ??a#n{ms;tkEFMp?r-#?22b-R zC<&6XdyZ`>k?T(rC^S>zyq9Ps(Ak$x!DOz`Dqj_jgTv08b;Z|S0?X_vTE%Mjt9c8a zZna(7LW)?LMk)6{5!iPmvlLfk$cJev$oHqkh>5(4%mol%7xG>MKt@}bqIg48vD!Q) z3(Yu(yF+c|pXQ7mvl9d^Ya`j@)IUn4LhCI2%${~g_c+%!g6@<+|JL(ak8;XuNY`azP=PuM>rLDq@T&Wu#CzCtd=w)Yox3S%pq)g@weXwk$4e zA@F(wPQlYsdZeYULr2mSBs=%rt3Rw+ldfM)^{z}#=#!TqqBRT?o8IKS$WK1#k!)lNBZ*|{BoylXrdgGdbCYj>Xe^?5cd%xGt5JeeQ;RC598`vz z3?BulV5K27IFeq|n6SxPicA{t1*44B??aqqkn)G z^jyM4f6Mv4VLqZc)idD{1v!PMycYxuE&XjCNJwVf%y1hF!mxa<(xcO(&k|$_5E-%q zCM79X78gS)Gp6lPu}o(z7^G%K-%Ib$;#L~mZ(C=PLzNU2MVJZUr;EsqD-;Kl+?CLq zQm#uwP8PyH%%NjWGnPP-!$C&Z1SXv2q>;VFt-de5A8Raa{w26ItTC@QrHn&OA1ke1 z%a3#33p>=W9R5PMMq9J)HhFP#A~M# zWxd6GH#5a8co?_fa3qImuokg7$8K@)Y|tKttuf-9U#MefnXz`mm9xWtFg2?Yc|!DS zi4vOrLg$~!ER0h7_G_iSF2C&*@1~XdhPKj1s$vBd1%X<6=wQ;;w*7Hr{hb(Xu5%&F zcf!h885Rw5msk?ucNvGk%LHfc`|l&cnW|B2Yct;y z0%?V$m6XuheLRQwLy9LX)pXD0hv&=obB2cGof+@f2EQtOI@ZzJ2?~+s`MD4sO$=Br zr|SWv$MS_eYmPj>jc&MB4_>?!gR2&S4sH&vep^uC;rsS|xV^20{NVB>+c9@f?-Au_Wosc=VO|7BFs=9 zfOf_vL-j+CFUwCXky8h6y zYg~WdfTCtxs-9CN!-FsNOelQbRbSs|PdyPR%;RGvWpz}Mt+pZ%xwm^6$uq5|&+g#2 zGs`nnmuCR-k&msKqEo}2s?1-p87J|Dv)q{-Q}b)aY29oMv*kR%ajO`;y|auNO=Hg& zNEpDXg##W)&Q1-Fk`npBED8j`i}`r+gtTD8n&?$cv;UJ>#@9$Kd0gr(u7w2xp2qgV z*HdJYA#|1%K|)QhePR+}ZnLS?nIi-bGyV0Y*ePE{UY8UrO-!7iryfLqIge!cQ{kIw zinCbD=C&(BC`NqNmK6f0!LT)mDRsli5)8h+PO7_2b(6|5-fT!kLmEE13HzRG=YU)quMaBusD05S{i5OKKp!_ zw}7-L?#d(%JqiYJ_Cb=@i4u%v;Vt&cvdo|Zl6%loCVJ*ZsZk5Jbu7#4{d$M~L}ZfN_ccAjqVoGww6j*FbJN;p8SKae zcn?jI*nNPqe@_S3pa=WY3LvkHpCqM!)8P}8E7%B#e`hlmq)Q=7sYrEJ&K4)0yK%kG zNbHhMxL(*CCRV70+kS$*h<ES+=<>Aj7$#XABt{S!1p2~g+Joh)qoDu$WvQcVF^FHv) zd6}MNEF^#x3p2amwP%ram#KQ@I2rI^|J7%6p{l7g%5S~o-Dx48Z87x7$>HdwR(F+& ziRRs41it^)P-hGhGgYZ1^7xj4Pe+{riFCVVdSBL4J<&Lq`rPC$-N$n~$YCW4x{rxm z`nBqyIpt6tvoQv>he#`$fhg!|H1>i8Q0a=>7%Q>-%msxWk@eF=v7poM*0b^x!V>M{ zRB*Vqj&f!DH8fh~UC2@65X&_THiYU3^K0YpX?L2wtTKgP+gobFe$XI@eu5?)xW=74 z+5iG9kdWr}*TfcaRG~`}Ai&Gl`eN$-b+`Q8=XBcrPCi$6!V?47snjy&a=H)8-owR6 zk))xWHnGY2!rItnQ1C)(e&oaVhYpd^+OXtsQ zlf6G9cFbHp54!RNwcuWRh$#_FyLDv$wl;~ zN+|Wi7*5ARGbIGIKg)jYC<#z`4!P5%mMk_`PpVN79;#FsBj7Yh{C;n4?|ay49L&SC z-HG7%re2EHUmIOK?KV^2Zn$mI=Gt&N&N_)j|4rcJb7^vxo~2U@D`K~cp6BccnSLL6 zij3-K2$%^eJIx#EQPC{d-N##m%G1`LuX_bMnAS%hp@9wfFD7lRZ}ywE;4?*s#^G$=qTZ4Wq>Z#C1DjgkcY~_uuZHtkZn+f9S2FH+$Yvd#&-k z3r|M;XhKSRi?93fYbh*(#$klaF~86vc*Nu^9T#^gBHbBgcyqB5A+nuJgzt;Bp zg&>s2vH?q1>)06$5%^Zh#{ttH3eP87TGyj9aB7A1wW)oZoRq--4TKs*w#$Uo9@qPG z^g)8#UuVjn)uYE(_7oT zUr#HTy)z@FGN)k7&u|fu1+H4fw862tKBWdonYtp$x$W)t?{;5@>cWE~h);Vk8Ko38 zV0Bsl`-G&MwQPT^r%^}dtghnq$3>2i^W@CS(Q*G_GuH9m06}c(a(Qm$-8VCpITSyi zC6XQym?^eb`4F)iJF#71!$wbNtQqFyA(0t^_(y}j*vDwF${XRsPX7B(f{P#HETUH{mM9ccfqbanMELj3@LBnmcA{wJ2nt(78cu4$(04~sj zyhOvnm%^Drsb%-~=jkT~4m(D1Wn~4b+18@ZdHna8bEyB=Xgml5G9Lf4Co!7cpM5zE zgW$LXmRrAFI?y^z_Em6B z^15HO?h>ErPP?=ioA#FWmWkinZp8eCBs}uBo;oTWB{UjUCZWV9iD+6%3QM;LF6#6P zO)D%m42v0YuB!Q|zwPL`ga3=lH=a)VM7292%$ww5G)G$J=ZYzLL)bT{s6vgX(ub7K zRCY@ls%T=dw+tjd348vgX!=dP{>aQlYd^=acEBX&#EB{tENNU?&Gixaqw~$AW8Zr` zep)Z0D(>s28M0^hIT;Jp4F>He7XPk1sTHNb6vL&3NJVBpAQoUtai zQLyimvh-|_axcP|49~gN`$p`nT$Xc(E(rLIRXytN#@}@?GvrMaoRnj`sln_U4QBrWdX%Pxgn!TJuf7XJZ(QM+Xd`{pjK`hYA=ZpM*SH6$-_TFdru&klnaoO6xna4WEN{BSd zas^k(Hl}zY{reha7MGCb-4n&>2bLop2R`&MV0oB3?%u!=FMP-$%jN55!4OfHd3Cq< zIM^xZI?^YD5Yn{%fq^iiu1 zvpH6-C1lJeE`57a=d{fYiH@D&b6mO5yO$x#*$!W}Jqv_E94)Te{0N%z&_Iiku%K1_ zJ>#H++aihv0qh`itMp7}TkfEn=FirSJ(s--Z0QgWg$tZ;yqN8itMk|2QlHO&eJW0q z-C|eM{_H1K=OLRc$9q9%nxizD;-jdyS}~ywJ;HAu3ivU@d zUm&Oz`bcl!Be{hExjO?MM z3l4fiJ31Ep4)2(4?eVL;uF9TI#?K?&KpA4w8o&98qEDRT_i0cb>DpI6fV$3SgIXvQQFbY;fDM$xG|cUfT(Q zr>7kl)XS?v;grvQ1^gVkpD=Ps8$uF6`1vh8LzGt_fW&^NoX*78Fs9NGTvQpKURU{k z>1lJZ8bclCmZQ1q6H4^F1qaY$B;75_XQi^+WMeYvhHhr*3HKw3*O^9klreR6X&nhI zId={cB0^KrHPGdbiC7#l-ZDvqV`k&$zBNgU7V0$wK);A5S7%m6li`fO?5}=rlt49? zD?>s~t?0AoxF)N}X_+S@?=#w_N=|yX-5r-BI0-=QRVBt3(KvN%DZxLzkzv>(=sKL2 zNL6>yP*sGwOntvX^j)DCjx+k7M}^#!bIm$sYNohe(w`c8yu$v9ro&tNNSda zDeJUfgw@Q)3M}$$o#-WdBbgJ{+GL+)d@2d4M;Q052moB z=#P2zJFt-`57%c8Hk*`oH68aORS~_PA|+@jWMtWICPIE`C&zEl!NFz`bWV^_K?72+ z!dI;fd!4ycV0(qLrUfc*psB}0@$&%0+p)Fx=0kxjMqjfYRt54I4!84oH#{9)O5x^; z-%S<-CAy)Zv^#sHa*e^^SN8J+mM%_4zqf8Zis>2>rS^mJh&OymNH+ZU<#-6Mw^dKN zojQ+a&6>QcVd^Xh?L$EHYH(2{K+1YRx2>cgt#h`7CIX`xQ(fZVxIhVKR5Aaou!AzB zIDY}ZlEI=1zKAR-r+g@RQtFDeI088VKH*=rr_+>3{+K2M-k7D5DCq$wT&kq8D>Ywt{bj%?$$ znveZRL%ONWdN8M8QAjFl6 zAH_Lyjx?NDyZ9v+d8c4gr>f|0`;8D|p>nOt(ZvpJ4gJke zD9G{-N~>CRMzyGu)IfkzMHB#FML&tkBa#1qm3?JUTtTz;;vOInG&l(o+#$HTyK8WF zSzLp=2Dilt?jg9_;_mM5-{!sVz5l)DfLxgkrW$F zBSr7mgaM{`zH%PhiclC%S?5{^Nhj_Am{2S4UzSSE9Njs76Or~W?=g$pj1QgegRO2o z+6qfX{*H*oB#3zC`N9zxf|~e|j&D9zVi+x4^mR6#Yciw8_NBoIvWNlhCuVdc8$Tlz zT28J^a0*KxrLLMZpAhHAsb3k-M*?$2I{y4-=hUBOWq197G~WQ@{eff6Yre9;N^b7P z!FMfgwu$?Cz+PFT#e{&it(An{;}Mg8_dwi5dle*FkIs(Fc2@P*Q*hn!>O7Ce0LY*&}Ut1NkRi z$bNgeY`!T?@WLVM)sM9g!o(c*5dQtpn~8=!9~F;hf>q+$QrU~4?Zl?bfQP)JM8t5l z5g@bkLKTmEG$&^PY$9}0aTNt1)7AuT5?alyN8(3m&8u07_-`36JW7K+C(iGSV}e6d`P13V{71t>+C418&k6lzZ1r@JQICb|o^OO|kRNgK{nj z#b}jHp6l<@@Kuod@fA%c+plr5$obP`5c`n>i}xsj5Ul?yDqMR*483y^#=$4a()CeF zJDSp?HGbXe_We|C;*GGxs4OYuRpVvv}40Lyz6B z1!5a#bWQi{XX|o-lj&V6O8&&(eeE{kM%zg}tjej?eZAfSkCdZw-MASUyTn4BuKZH= z3Yh3v8O2;PY}%9uH=RPxe@Nm=A$w3={WPmQS+vpiw%fWJFGCpLQrVk7NyD87fSMaT zK{^jxDIZ@5gkHe3ZVJcsd5Rn#$8kH~l5z4|#SwlGnS^%5&4>5eYkc$ZYN&O5#TJt? zp(9M((NCn+eTv^yQqwchqf8fQI+Mg-OyeKs^iAxmT#5XE{?PiXGy2$GcLkNv9*#HA zSw$e52P1OjF)u{(Rg>1qZ@=thGj#U;bVN6k?&cD{B+ButI26FDp~A&fzaW9^IWY&c z%4z`sl&Q~eeWEa>BTj(^d?_fbO>$ER2}FtNg+qpt^>{i4__J75$k$$CK;vcc&b+Na zti{Zyv>MZKqaUFwPIUGQY}4FsgC8Tqb|3F2UJ{o%0%{~wWN+0N4B6)Di*yY$*s8_o zHRSLm!UmES+UtU;70xcEIUF#KJ$>VTe<)aEPwIadP44rG ztZ~5GLQCSXjc!)ewc{bWmGQOQ#|#z18sc?a!{ndEm*1N7x#efr1RswO0kkKWuz&@y z@9{wkYOO5fk9teoW0@r>)PpM9rITEa?Qh2k?@>>RVR$}UIHVucue6*|qXCu4~U z^m&S)LWGKYR=m5?kT2UsCqe1%zm$YiOOhOg)QV;rE{Kh*<`CFB^!Qq5kJTR?46m)2kb?dXVyMvv9Kp=k^8tes`2W)@At#Z3y7LBV3Yd&);e zpB;cn<|q3eR^?&-G=0z)#7sRJjK*6jQQQ{DF*gzm6m67e3O;vt<1xFDK{jwUbw59o zB#zvcpD(`;=%KG8k;-4A@{Fe~TQNFWVuz-w8@W6SkM~Zz8&Zz5E$9Xy@d0wbs)WVn zv&_FbCf*>DBhinobJI;f(7~sef$Au{t&eXis}k|K9SC#!_B9J^e}i_P9&)#B_~d7j zrU8|`*b7k`N_hCUDmBV>1}?7`wcA}=?dnaWWjtOR7N^lo>lQKsKRtK0yhu&ooKOr_ zE;p&U`qR0@RA#;Z>^nRuQX*gSJQLmfoQ$rLw0ZwAWfrUb`GJ!)%VSt2Suu%=JHd@~ zD-q^6R^;VUIvj7Ygk*Tu!vPt83DJMoI}-PZqPZFG=y)DIHu_vA`57pJB6se)>k%|_ zcv1zbjJVj#!D|B`l6Af~GUn2>EFLu=zlmW%kz9+6co--n+|&;Cu^*d~e~gSQD#LINr81yiGD-?h4S9OLM(J1ZT} zT^c7j776;G93_ToDwE-|iGz7$RKKz}Q!s1j`!#^4ROjP;>jW_3pzW9iD5K$Eu_L)? zN$M0k&vof=?y9)DO#2d?UdNrgSA0`x>K(7epRd?QI-FXvpr9xa&6?Gk?J>$aru|c4 zpf<)Suo9|PuC}cZi$q$ElvFeRW{O=93$^Prj8kYDbag`wG*{Dr<$D$e)5;)0tCYLN z{aqALBfVYS;0-}*89r^h7xOmG#x)}H{mE}{UdO9*KOK&S-97qW(nT!&K#35+89lSZ z)#AxnPF=pW+KQf7+5^mSUjE|zwTw#Zv+oZlRbl6Yw>6Hp9%1f-No5t!5KW};N3kR$2`*y+Yf`y34blV^*)-< zrM4>wMX3I*=-T_e`TTa-xhA~BK!q(QbVZLVn3S;XH;j7>qW5=cMZ8y)(S&{p{pp|l z7q?oKG^!}cX9CpO9dI~+&p`AB|EEu^?-sMp%*ekO+b9%i#JL*e0ws6;sDFCoTHev# zYO<6#kSVbKEE2i~x*B0s=gf=hO!OnFp09C~LGW8|0&Du@yiJ$1Ssh!KyLYO8z<;XE zKh;kL83Fv!Y&m1?1RkH2GRql{Im26m9i9ecK{C;MeTiXS`ZUzl4&V}G@phIXSwhy* z$~7c+zmza~jpx2CB^pR2wl?v%F&QUvgx+`!2Db_S*+NjPW_>hP;u@wkS&M^IMrKY@ zio{%_UHZfMJil{?;Sh_R=2ZLR=w6XKdNfa4%sKaclMKtTJpH`)e7zla9q2V>Eo6?} z&R~!RSbhCCHy`tMw6zHu-{Zn6fC9wacJa;WH;t=Frqd$FN-(|tRqw@P#$P^Ra5w)p z&z{VYdv<&_18zcY=iVkpgeGQ1qK5*>UZf33Q)m;Pe6NjbDk|LQkoP|(33M}DbY<+P z2v2xd_vFin)A&r41WKU)&pXUy>jY~P=d_LmRx zA}@%0^>zDpOLi*-R<~LlF+lYz97tAM9`k43)^^QSrWng&>rrRV#MzTu&?K-kw+F-A zm`zS<0YcZfv6ZDunasR;)3~MTyr=W5u$`CV*IIE!@ex=*J<-oYqD=kf$Oe-j_ea~G zeYb?q_nrpSgBYVfmL5h&t2@r}^;7M2xp_U^0v7V8k|^B<`p}7B0ATa)Ygzc{P=A(E ztjE_nH&II5a-OY^ub=&#EQ>EwX+)||Em#3r*zsnch$Uabf=oSpkktnvz8KZferGYK zSTalpOzTsK(}^$Q3Jg>c5qkTjd4PtIIHDaW6ge6FSytqwDcsRJMe%bCA!Z10Lb4sw z2%`@1N4milOV>VjlPHs?$P^=r7cg;VzzA`Ued;D+6&PwrO1;_OF6sdra4sBz`o-wN zHPSBt!>5bh{Sm|N(KXaAtHXN!o9GX?TsxU7%J6*x3KvlPSFaTq{)&dO|~8vuz<)9Ze8vEaG}E;B?Z1cJEe6a3D*95*~rhBG1CJgkD_e(tGp9I0Dxdtgfu{t zGLd>K4N1gs#06l$v=t9iVL3f4`z2g|s7WYr6Oek(U!FOKHl4<(TA`&eWdFHt>u zze!y6QOVTq_3e&Sd_>uMeBuzik_!KMw*Cc1rHcs|aSczY*|{~~ubLlyQDn;`@#&TC zb?J_sF7`}PA-eblHS6lKUoM?R?Q_RMD;zATgOBW#qfD^>%gozPl&n$Y(iF2OyY-vd zo{!Q$e}%ewz{^Q_f_OwS>o5`tq5P?s@?ZdE;!UKYDlVUK8OKE_0fIx6PA9+V5uYyBog8!(8AAC)aN`k&* zZm#{|EF0+3wZcE7GG3)@JGSXRC+D5)8U9IOyp#Z4@06Rb-9ZhW%5gg~+h#`T%uUqG zb(DNRu7$$YFPt!(R379Keh0d-wA;C;lqo_~ilD6AW~B zzXf%ouW}*=1IS$bG4O19@JPNdY}n&2lC0^)rsI3}zww`+RG3He)##t#n@pHboQ--! zUD9!cL&@M7+36h!Hi0YEWq|JUK=ZvfCAHPr*>t7ZSyxlF4iZ>NeEf9BcHGA!vtAi> zM<4U1@nLTvtn{B|GH1;BM+SdE#c^_Dg{fl(%2n?b{;ICf{vShQrTQ$b(JPOaZl~fS z8LQJ1T5ca9k5JPyvpvT+|Z|uOXJhu%L@FQ#aiwtxAFTx z5-b{TsM_2Kmr*BY^7N8;KcnchJFkV|x#d9xx=O7d=>8sSuh%RUx!6_)1PEFT5+i-5 z3~4bbh8Ijk3pvL6bYLg$2k9K+|0bE6G8W-EpTXR-YoC)8S$2<@LgypP)5gi~cr?1v zy{6b(lEa-=8V?Itn{0-ZgQNC1C`-I*YlH%guP?%MhwN7a`xN)D;i)Qr!)L;h{)GM} z^>NDKss4f)C6j8`D$N%zas2EV-JQRotHG{_%F!Z5ajo_!7NJTZyPS{x;)x~HNUW~2 z-WFDTK|YDr{|oiP7)#rJ;k zy!~3u-tKnNa*LJStzFb=&84?rE=8)nqwG>~@j~u6wYy0Izu%ySe0R92$OE3$dVeLI8O*P|LEq5do)kSVh_p1Hen&m?0xv^jhn|o=hDwIja@h?GAe}?zqmw`>^ZQ4UnPQu2Mnt2v zQ<52-=<%A_jT?g;-tYTQhki(6KmxRCtO(sba!Gc6B%{KKa}O^+=P_l*)2*Dvr+JC| z+6(5G*>Dtg{~0?J0Kl5ZEvD*l;c@u8dA2>D#}&zZ>vqmYW>4$5p84oghQ;rbKL@p6 zoZQdK3%`cy@pREbbpbfrMT_t@VnDmx4+i#|f-0&%DU zOjo+e`Orl=l|spDcI*ffNTkUYgD%4F-s_B>v{3*Lagh7)?sG?dwY}Q& zFWhJzZ`6-0j>d+5kt-8rJl4n9fH=!_*EU`L2`gh}vcE-lxC2(OiUAcxiAKZP6$7vp za~!E7uEk;u6Y5kJ*qm!)EBbe9V3Ky*4!UDUxntv6yb(v;Lw!biXzh}wI{*oC2sZ!& zMGGO;d=djSX33(MXKZ2cM3OE>LM7%2CngHr%XLaJDFFJOBD(gn;CHbqGFz;5ano?5 z*TS-mo_^8sF)A!uYfUKNJEQ#^g(PRnPE|)?q)F&R+wGJ^(l&d$BJC~_i9iuA10`l| z_#WnHtxcz76-u0mR8#J4bBB*!5UchePZCU-CwrEu+Ca=@ckMP6KiB==jGK0;iQG>g zx0enM9E(0&taQh`%Sn%9UFkcIejdK){EB_+ti47`$S=P3Ap1QbWRHWZ6;vG@8Ii*I z)7{=@Yi0a4HV0SKXuQzd^Fc9E_sg;EubG0Xk$y?G+~lz)H(A{rp82?pl5}=hwW%}w zq#vjWK9hrfT9nI3OID{&-x?McWi|WO!bzw;0w`!!(+9yb|z?v zdGz!QAAe8W)P2r;b&meM&{mncDZq6DetIf~_sa{GN`Q4beeyp2*qbzfxP{Kv7p5IL ztVA5@X_a#I15;nb@Ub}3_Ppa=uV$X-Z%ZYw)@O!!v*#Uf`d70Ycc0XpLJL`%5y{_t zk<462M|0G6cu)Wb4%VyR%-=_*%tXEpm>LZx?1p)-0ncgHY?%9{nRUb|eAh_u8qF?c z#Pe*iztO2I+6>i;#Q%=B7^6SS*rv+X7dW)L#t5Z(MBhy*)(aYcD(ZwAi}f__$Dpe> z>%?%ge@bM*^Z!@g3TmR0ccP(E@r>(H5G5h)v<$_nikDbn(yqGYjei|*N z(|>D6og6O|A#{^WtD5GVeYJ4kDq7b$!#bsDof1A+diM(6tN;bzKaR1jx8~la zw-z`TC@l`d_C)suQCog(0(O{1cq2?%V9goa4NZNF-~*o=9|9+* zxFN2nUg&mtlNbh0!3>r zmZII;+8f^NS>(v{B$WQquZ@rR5fbc)R{MIj9<5CaDhnaS{%SicPy0a?qtOzoqe&9>uNP^gsx3G z6~zQCTMBp4wtAMcy>zN;gFj+Q2tmi=XY<&@hgbVGW@fAm8IGXHqz4H|CONZ>NP{-}jq3F%SIk>!FOsag_bV)d8Z{(R#InSF@I7RE)-IZWU zrlH%EO;&%TBa-!MwH+P_qx8>Xj6Lw~74`R5_K1>C=hJHR)=!eVHgLuywT^4mM=Vvz z2G)k_n15Nmy(L_sV-A&BRcN6kqwRjgQtnmS52tB}H9hD>1tzPhWe}X})|?f;tf}$# z85vZ1J*LR;HvvRaTfz&*h0-Tzy0f-lRW8anI9B+T`L8Jgl9*KcqyZp5YEP2ELIP`@ zgE#thpH!1({2&|CD;uX@q@aezR_8N^G}pSpA`7}fs(Hjcs_xG);2%~OxSoHUrN1qm zXH8ySlaM#0;NSw7X0prOTKMfMb@=+2UwGlbSMYsEeDt4m5O$q^u$xZZALu+S$^iN= z0;Ri0-_0gUof)pvqpU-JuIRLU`B7X_m(n#pu4nRjeuKetm4@ccH+H&8c004p_lKHD zr8*-A`)hYK%Jw`{x6Y^`^@@I1c3z1(6?k;e3=}RuB+zjn1o*qHuB}bz zQ@fJvC#hhb+AnVj@b1OhOC?W&PE)9jhKT^ev&uQ3^9@vk3bjL!rbQq=9;#3JeO zoUuk6CKsD8y}bIe8s$?tnTpXubs;SjkF8oAf0}XOizt$ObIsgQcA_6@hmGjYI~6sqO@$J*NTl)FNybRyCY77m8;mf z)sPfS7*k22-~BB%eK~8*&nIXM>?t}c4=H@BGva#e9DlA2J0~f#uPX6|O@8JibB>fD zsDxK%@Y@QeOcSusr^q5rATiKvsXubF9;2Tv_;|!BzAvLhB6gEQtTU9h%+*4R@P)I4WEBiXz zYv1$R#4(W^C#sw`0{zf-G&?XG&TpAh2I*&iU{)w6q7z>#I+CrmCTFtV^K}^>H_}Mi z_^Fi7ovuElxt-P$9 zi&uf0$;slRS3fKwWs&RLTm@@$7z~+mNZs>Yy!QNf`*t3q3vvvBrac)Dby7gOa9_U* zMUbx~cvw^D@_SedyNjx$E2rbc4hjNL2HRg=n`@jSzyET7*}0wS-ivTxa(*8>pf{UE z>S5aHeD=G+A@tq3ILPfIj85u&Po92oz|MZJ)j{;OYq`0Zc)L5OT();rF);gRw*8G6 zgkxs6?yxN~-=_0EKv)2CS|B74UUVkW$De+flK&N;sP$Qhz^hWt$K!cMfp*R3Vh>^ zS-ttg=I!hS^%ZO&Evk{EhH5y|=yWE3Y%D^nsTROPs#1^1mjI_fdfBA=3-fc+~1Sg(4fZ z&FM~u2)KSKCz<;}B)op-F@hG_3g4+xL3Xwi!2R>q!=bwM*OE$aSmu=5pl_Mp+^4IF zv1gBq%iOBvrZ3Bx>)M`PhJI9nywo>|Is7%}26ylCw~+3X88Z{B?MKcfXPWmp3|)Rt zxb)BH?}k9DwUpV|tajij?k==%5||4cHo!xdSRG?e9F<&9&>oBeUqDvf?e;|~P?4z@ z_EktdDTz@I5vpK_`rxLu;*3%1V{@^tuGe=k01BETjJ`3AOKVdx?eh60iuz}nCCPwe z!lD(9rh2EIZ%z(T3rBuDAy(odB^$jZvbk#k?^z@I1B~n+5>w|)A`}!TXq?P1{nif^ zv{X_bA9(pWK7W|VEI}eOto`9vX%i7l(R+S9k;yoH_JOBEoh>8k_oc-yBAf{1|BA^z zR7Qv}UP1bkgtuB_Vzru4QM!avy}LFHyb}>2};I3s<*$b=rp zEYrrc5aWK#lP9NpK7iQ{rs`iKyGvMByg*nS{?)!%K>tNb98k*aNU%Q$$^GlXO zsn=yB!5EOKC9IXkn(0t3AOEnB07>2s?yRJ0ci_}}*$#F33klWgiPtF|X)lSf-u$L2bqCPG2GbKd0qDVsTh>Y3Z<6_IlYc5POGHuKV?EJ9+FslJ0p{wth;gz9aZCO z^}XQMtiu!ICd3;MN^c+SBnG@8Sa=mY+MjAkGe+LsN z4LipBWXLFnhiCyvdCT>{WqL8Q$lvYXX3$ezPtyEZa+0FFBr5t^tlDecTHb?V-#`?r zs}g`eh3>&*vlz19slEm$RELhVGGY`W=Eji12?2G2o#0(5(MuO8nn~4N&+)gpS8Lt* zU!b{L)GC)d^&Uda}z9|)1A;Y zcQ}|cZW@#%>(!EAzvAJW3(r5~7ft_2&sJ4TSh3W&UB#2G4h(&b!ld zy_UC5SBHl<6PK$fSJSI3Jq#S;L@5mNEZ9E|74k`}9!c&9GJjawn~ffOaP9T457dP5 zq{>J`>_G`wl~s4u|%$5N5Fw3nBF`YV;sQF7A`C3vvkX(25gaehQopA$3ud zC<_N)Fk9h0w9g0Z-`3P0SAmN3+~ppjw^I#P-VNqtz2V0IH}ejGX^12})_qa6f?ogy zonKw9Ti-p5wC44&A_~mTjnw{blgxc{jpzeoNDU{9t$fbrX1okDTqr`30A{J1D0|aU zHRQwdiP0wf)JlUemeghMKvK*GX9y=T50Y-)=6kbgkM3i;d$42qo&KSYS`_b}ycBrD zB2iQxbl6{{+{PMga(5tl<^+Q|xpm~wHg6jIr09yDEVc-TCQo!v6Q6<1{H|-@>6&q! zi=X6@j{)MSfs;Z+L##BRxvHOjmCvU2BDnE8JFOG0Yr45UC=&U%t40VX!NnmC6b)cz zg&1jC9zy~NT5}EGH{p_K*V5ntH9AY=PI)FC@>CWc1+Wn$pWr)0nDDJc-u?tLH2AzX zxD(N%9sBf^Gb>Y;8GjIp6Z7=rAh=%3#{npr`@<9d zSYh)9(v@R2*}pv&a!;*s1MaJFUUZ)?tr+yU4-V{>kEDsq z-EW?%^>eIk+B!t~FF`2%JQ4~R7=;%}+7g(er@1kz%taiqGPFLZJ>6%O>)h{G#|An) zyl#K_GqDUFaiZb5vuDRV&GnBDZdZI~5>u^CSA|N+8LfCYoK+?>e;`5wvUs0`o!yt! z-LKAX8%AEEMwzaxuvBnS z8yxLPES;)8#N9A{lmUqJgjvaF1M_@mrxl_~3`AU2ZzU<<;EPa%4sv6#@ft#6X^`kj z0-~+EnA-Et-!AWCUx6ci0k5|SlnEAee=OPHL3O8%mpXP2!@2tV;X=s-qlau@`uh=- zC|Hv0N3oeZdcQ?}J> z*@aeELb^j-F&Vtj)^l(3zKoJUi6N{BxV@DdIxd*e{*u|ieQ<|*2n8s__Ey9u9|hGh za@lJ>A0P_)n2hV`yg%=zqWe^Oo1O%-`>N+7C5WzZ-*oXHVf^r9^n#CXS8{^LWHQ7M z00b>jyMJTyCldse<#m{i+(gWDO~L>Q{eZhKMZoc783BIK{GtiqvLUUl>2+*3_3nK? z`*O&+xWznj=U2}}J(jSc)#( zt{frThEU(-dwBgV>FSop+hs(~ =v^LkW6lpK@fdU>61iuLp;r)fJ4Lww11*{=;e z_Zz>9CxOZ#P@Tx)4=ExMIG%i}uE`ut@F$taW*BZva-;MYgb+rAx6>lVo7NSW>!?=B zV2p#~PIsG`envD_R7NO3urR~j`{}c>0Vx+qN+4$+?JwW=?9PoE_b_BFdrGQ*2L8iQ z_|hLtrNaHo>{&pw7A!3BT}a?^AHS*5>OXRPEk-rKy(n0Sq4#K3p0z5k)>oUMfixZ$P0LFGp_< z{w~C5*}^@!*lAnlx8aI#%G=~E_rX+C%!m)BFKG0^#aq=?rusDG~BDZiYdFEpneIR*M zy1qRQ8zYET%0=qG0ekjj+P|xf5H$h4sV8RDC`u_1g%Mm~g${NqC?2fvwCF_3nPqf1 z-WMmk1$^4raZtvSDe(Q)E-s8v1o!avL^RfGfAL@YI6VGFC;?HChqnq*!2eUgq&TZs z3e9L+21L1NPFQ!__qRWU2=7i(q+Hz-rgXo<6o5Aq<7a29#Ax=|xLRVAod3gYMCG|$ z35+4a4-yJHXKmR;9^29O^|A^EV5(TgAMplkTV@K`51yx?Xx`3`Uzz16|2tXL_88SR z3B}5!Q_X{0_US6UcW+4Z{dMi}tTzn_Ca!KO!o+eRkJF{LJv73*Ee*(VdBf@w7=@A$ zKSWCjQ3NBTde{i>!_yP-#m&vhr9Rg?;mBfLmkVr=N>-MkVzh|motL7PlbV#R5Lk3q zQhm1`RtQ;S%>~u~4L5Q)eeSm%QqR?7(+Sqv*_t;HccROp#ph8iasX&1k6~HX#1y}{ z*wTXnyNg9bNGq|7S;&+dQyQLh!K}v2G&?Ci+x?s1K<6&E#C|a-`|vO_BS5A)qe>q* zgN-adHkgypRO5a)pf{r7vsCGToZwfJg9(vJL}euiqiAT|yxqZ_wccK*p#vonVd%$U zRd3xJZfF+m+2t7);0XYL36*h{vkJZ5{p6;hehtU}gi1dv_dg>*0GfxWdyM=juk0xY z1D+tm4waK_6;GZRtB;y2I2kehIuq6}msF}uS^~o~PqLIk^25#uhUlgU4qDFz;1jLP zKi5k9-@3^QxtR82Bu!oiQU^hRpISxeDIn)g99bCdP;yu4usZZxsT|~HxV%6Y2;&4@ zZ3;!p(y&Dog=0yT^*3OnNz?yh1=Xr4W^wq%l zh~Yc=|BR)=&7;gsPviZY9oBIWLc{KXBxGHcaH+Krg-a-T5(xO=4bU_gA@lyc>N+^yQ=8(fdQCSo+sm7VAeSok} zD4iL$=<#pp-x68~Y?1w+swL@4DDwt>>?EjSkY?~f%y;@P@MH`+vJGF(I<$bXgrwpA z2Z#u{$Pp6&oRJ$Yxf~9n|L_U%AAwo`kRxpEHV*n7+5gcisU#Fj8fc3CzgjXJ<)ljy zz5^e_7)Xj3Na`#of+2(fD}+%f-96t8xd8d7Arl1t|NaUX5Ttee@^2tmp}4Icz@NyX kD%k&whN$eK|MKpxAsEM}%J~U$m?uC=OkT7~*f8+_0Y00=1poj5 literal 17907 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 NsIa6^iNJTS{{vSOf1dyV diff --git a/src/cx/fbn/nevernote/icons/star.png b/src/cx/fbn/nevernote/icons/star.png new file mode 100644 index 0000000000000000000000000000000000000000..ed65e419bdd99c82009d1a91fdb8264240245e6c GIT binary patch literal 4105 zcmV+k5ccnhP))DqdJL_HS-6W1Xx*hx@Qp-52${v#A72Fg?_l&PXjr~pn12t^zy$Jls@ zv-UncyWZW|+1Yt%X1ZIt{GsmIZt1F9YDv94UsYGNq}%GN^Xa?i-lKD`gp`ua3fmM@ zz+=Fzz#8xj@Tg%)`=VAX0mNn{#5Tn+@bAEW-=SxK_ZgOSI$x{g&@Ofb65#U$$pE+m z_-Kdgk{ULpLTpoP2Mz%}Aw_0@U4|t~ovT$k*sKcqB;jNLYzKa^Lv=|Nn@%CNDYoIM zqtK%0abVi8WI6jO%Y(Ko3W_~0e%lC*6+}!M-bZw(65_6se)5@iYO+yIqyFhRK4(*Cz#LmHuZT1tGR6 zCV^k|@83{I4dE(z*fxcpN##<;rXU3P1Yp$f5SI=iE*lCI)NfF#WE!|HtIDN`t|!Dc z#W?V5{`~=U)X<}&|L``|kxikJt|tWe9iXp%huATQwre=_2l@?Lp*P^iuLM4jdhJq1 zR}*5JVhs3o|Nc;Q)KCcZC7-fQ(bd=7)s+K24)oXW5ZeaOc8|3DVTelh0{5g=yA05^ zgxIDS0e-{3zoj~AD1`cwPj|CQy0&6?>KLrwA*TA#_KZe8f&TVwDwSLXygza6GD24p zQhgfuG5`L^>ZqZhqrW3mC8Dj$WsI&Q1o%y$VUQuV^r7t?i+v*fhOJNxsAM1T({0x- zLv$S>wkZaI-}3L*Z`=WK?`aA24yO5OzAm8hl}psNV6O)-Gy%o`9(9kTu-JyP;H^y{~(Na9VBQD_1kxOA&(mT zy{0%yX((T(lJC5Z^Syvd;$i`xqPRfTsdi4-l#pte`ci@h-;I~^lzMuN80hiTk<$_w zK0!zuuKS9z)8bW8-9b3YF6MKG#Y&u&6AqbLtaCS_M-p9ZaRG%F8#FaGpPbTv$V{tb4~ggH^oz=I|F=iy9+9#XARo|M1K)s6k*bL+;x#FC6Aotby!)i619$8EqT5zI_}H? z1Ij}+qt`VtRGS$w)TYr@h}y)YPE?caI4VRSdJBkR0Y(*Mt(KAYI;@nCtLsR6-Ba6| za&lKO2YeevR-bnDIJx&-**dV71kElsQTH}N`F2zlx4A?h3O$IPy!ZT50%eEtONYHV z!$CYPRvuypZ~%o;w0#rg-oGasQsOonnHavq>qP@+Gm8iVL|I9^sE!FaJtxWmFP%;hyHyM^( zt{;b73;Ywl5IBIgdxYG*S9ycABuJwfh}#`*M^!1SP_CD#ymZ9#B|-cEc$Zy^TMCE^vgpu(gaI0a-*#;Y{Vp+B+ zcHxDh1DR=J+W`6d_o*@hgJ@CV=ogrgN-|WHwAVc{)|Ioep9kJ;Sn^!JzG1;d+Z31L zDP>pSN0;=G|KNVrBufto@2phIXR1OqQF3LS%FBn5rHaZr-vw?nEO}mauvN5oD;_C( z13#QF$bEP}qTd((N_c0b*KA}!)JDC+kIUsXDlZ>FmX&1u2k;)ll1pJWZ}~i=I=}B( z6brqGv0ic?+V73rAyS1eK2aHzuaYa5S1G@I1S-mq{=Wk6H7vQ(%-)e6P*o?+{4?;@ zzzK$n9x21cM0Zx=@@H}$H7&S@wdQzaaSX1E6JgnRq`|t%=jzj$lr4{;*$Or#?L?{9aN!v zZjs8t<6+M`{sy?eon;1-W}SQ$)x?(`o&4QDgxETmjY=-^Ak&>&q;l|e?^qB|0v|Cf zsgzACB+ARGF6#1Ez`cQkd7a!{d(n0b))|I)%|={fc3{xx&Mr`SZ6=J2KLb7*mQfM~ zi4*0jsX~8_YO%1KM(*}KXqOH*zu2tD7Af5b?(BIghfai%@u$GYl8^x@WiD2yhCPld zSwa`&ZrhD^`Dk~JEh3h8&&+#dsPQGkl7VFLc93c+scnicp_l=MCdl19jW#`+qTyqf zPoOII^f@X=PKI6f7Ys{2l)!8aNIkdLHpL$RX7HaNchfGk>G60fxd>y6`eW{?b5xFo zlJS^f$w!me%a7EjBN&!^82EJHfCT5iX2Ol5dX&0xmr9?pq_1p*@-n1+i^sy1nT=;h zemtBu8IaNZ5W|w6!&@J*5w08mxpXK|#3Qy@6W64?Q0F^+!my;3+)_bgIbr8%{|+(S z+q`}6P{KiERkul{KiY7s%G8WCKsc1(2r#0)Po8cDz?|Y*T~ASe5=V8 zopkJ-Aw&p7pJMKwzkQEl?1(|ZC`3h_^&$!d5W+j(1#FHctGYzr&iZ{DGi*B;6l^uf zj5P&G2t-d{g7Q^aEM1<34+-%fwC9Ku_nI1s4RhSBplG&=DDs|@A`3zk1HvK=%|-`; zf-0htOw8+)WABVY26{t!O%O>XP0Gu)3eK_9ILA&QSIeR0lg^UtR7@)iryf+uK)phU z=ePsTxca^9;GCGnIXy=$H_ACZhdw@nHaU*S@m zp2d0NY%qOON}SnqICJOG$41Fbj)9(z-xY-(Z#HscVqEHkq@Cn21vET>7DER4AKMe` z1;vduIWEqrIh+%-VHxH@=o-0+arE&~(2}>#rB@FlR~vGs9iTsIB6Sp`tq^r{)%4D9 zL6qy_o}R~vNt5;XHgFzqd8q(or9$Q8DV*6k^eq$UBSUQw(A7iNOUEr2ZJeX0aTi(|=P>Xn@KluS za@!Q|1wISBrCB-6Fwmza(fW*L#Q<18@B?rfIu$1jODbP@)eh1mTv`Zclv&yO3^*9TB0eHOKu4OeF{cE-=}T& zv`lGf8Et5g+?EMt6D5iT2okanuVaxIX%Z6RKiK%lwGz&;Gq|Vcp}8^_fIkBMxY?ZU zIH=BM`igCer|@0@{xG0icidfAq_nVzJ~D*9Wzt*ks&-A`ex&;e(Q3~?N@bkmvp8?e z`A52b*ub9vUsNqSkp`+0Fdw%~@fUdSNPG~*3P=FX`~uGTMfA~O^vMZCJ{K0#O3krn z+GNp_$2ocmXGRg`XhaG4GGMj40C8MY=ZycMZHh1By(S~@Rye>5$IQ*+%zNP&eN_1l z#ngg~X-(KE;`Oi^14nti)k4J%@Rz`63`-tMT#*E*E{^aZo@&Cqx~{2iuJeW^Tfglx z0@5PnEx-#gej8ZK%ICEcr}of6xW6P4N!Ab&jvcTTS!{!;;UYb^iYc15gi|TyL9w00000NkvXX Hu0mjf^7GlB literal 0 HcmV?d00001 diff --git a/src/cx/fbn/nevernote/neighbornote/ClipBoardObserver.java b/src/cx/fbn/nevernote/neighbornote/ClipBoardObserver.java new file mode 100644 index 0000000..ae857a3 --- /dev/null +++ b/src/cx/fbn/nevernote/neighbornote/ClipBoardObserver.java @@ -0,0 +1,37 @@ +package cx.fbn.nevernote.neighbornote; + +import com.trolltech.qt.gui.QApplication; + +public class ClipBoardObserver { + private String SourceGuid; + private boolean internalFlg; // アプリケーション内コピーかどうかのフラグ + + public ClipBoardObserver() { + SourceGuid = new String(""); + internalFlg = false; + QApplication.clipboard().dataChanged.connect(this, "clipboardDataChanged()"); + } + + public void setCopySourceGuid(String guid, String text) { + if (!text.equals("")) { + SourceGuid = guid; + internalFlg = true; + } + } + + public String getSourceGuid() { + if (SourceGuid.equals("")) { + return null; + } + return SourceGuid; + } + + @SuppressWarnings("unused") + private void clipboardDataChanged() { + // 外部アプリケーションでコピー・カットが行われた時のための対処 + if (!internalFlg) { + SourceGuid = ""; + } + internalFlg = false; + } +} diff --git a/src/cx/fbn/nevernote/oauth/OAuthWindow.java b/src/cx/fbn/nevernote/oauth/OAuthWindow.java index 128b2fe..979d6eb 100644 --- a/src/cx/fbn/nevernote/oauth/OAuthWindow.java +++ b/src/cx/fbn/nevernote/oauth/OAuthWindow.java @@ -40,8 +40,10 @@ import cx.fbn.nevernote.Global; import cx.fbn.nevernote.utilities.ApplicationLogger; public class OAuthWindow extends QDialog { - private final static String consumerKey = "baumgarr"; - private final static String consumerSecret = "60d4cdedb074b0ac"; + // ICHANGED 自分のキーに変更 + private final static String consumerKey = "kimaira792"; + private final static String consumerSecret = "c66706d41e06bf22"; + public String response; private final String temporaryCredUrl; @@ -84,7 +86,7 @@ public class OAuthWindow extends QDialog { // Build the window - setWindowTitle(tr("Please Grant Nixnote Access")); + setWindowTitle(tr("Please Grant NeighborNote Access")); setWindowIcon(new QIcon(iconPath+"icons/password.png")); grid = new QGridLayout(); setLayout(grid); diff --git a/src/cx/fbn/nevernote/sql/DatabaseConnection.java b/src/cx/fbn/nevernote/sql/DatabaseConnection.java index f81da8f..6014093 100644 --- a/src/cx/fbn/nevernote/sql/DatabaseConnection.java +++ b/src/cx/fbn/nevernote/sql/DatabaseConnection.java @@ -43,18 +43,27 @@ public class DatabaseConnection { private InkImagesTable inkImagesTable; private SyncTable syncTable; private SystemIconTable systemIconTable; + // ICHANGED + private HistoryTable historyTable; + private ExcludedTable excludedTable; + private StaredTable staredTable; + private final ApplicationLogger logger; private Connection conn; private Connection indexConn; private Connection resourceConn; + // ICHANGED + private Connection behaviorConn; + int throttle; int id; - - public DatabaseConnection(ApplicationLogger l, String url, String iurl, String rurl, String userid, String password, String cypherPassword, int throttle) { + // ICHANGED String burlを追加 + public DatabaseConnection(ApplicationLogger l, String url, String iurl, String rurl, String burl, String userid, String password, String cypherPassword, int throttle) { logger = l; this.throttle = throttle; - dbSetup(url, iurl, rurl, userid, password, cypherPassword); + // ICHANGED burlを追加 + dbSetup(url, iurl, rurl, burl, userid, password, cypherPassword); } private void setupTables() { @@ -71,6 +80,11 @@ public class DatabaseConnection { sharedNotebookTable = new SharedNotebookTable(logger, this); systemIconTable = new SystemIconTable(logger, this); inkImagesTable = new InkImagesTable(logger, this); + // ICHANGED + historyTable = new HistoryTable(logger, this); + excludedTable = new ExcludedTable(logger, this); + staredTable = new StaredTable(logger, this); + } @@ -80,7 +94,8 @@ public class DatabaseConnection { } // Initialize the database connection - public void dbSetup(String url,String indexUrl, String resourceUrl, String userid, String userPassword, String cypherPassword) { + // ICHANGED String behaviorUrlを追加 + public void dbSetup(String url,String indexUrl, String resourceUrl, String behaviorUrl, String userid, String userPassword, String cypherPassword) { logger.log(logger.HIGH, "Entering DatabaseConnection.dbSetup " +id); @@ -101,6 +116,9 @@ public class DatabaseConnection { boolean indexDbExists = f.exists(); f = Global.getFileManager().getDbDirFile(Global.resourceDatabaseName + ".h2.db"); boolean resourceDbExists = f.exists(); + // ICHANGED + f = Global.getFileManager().getDbDirFile(Global.behaviorDatabaseName + ".h2.db"); + boolean behaviorDbExists = f.exists(); logger.log(logger.HIGH, "Entering RDatabaseConnection.dbSetup"); @@ -121,6 +139,9 @@ public class DatabaseConnection { } indexConn = DriverManager.getConnection(indexUrl,userid,passwordString); resourceConn = DriverManager.getConnection(resourceUrl,userid,passwordString); + // ICHANGED + behaviorConn = DriverManager.getConnection(behaviorUrl, userid, passwordString); + // conn = DriverManager.getConnection(url+";AUTO_SERVER=TRUE",userid,passwordString); } catch (SQLException e) { e.printStackTrace(); @@ -151,6 +172,14 @@ public class DatabaseConnection { executeSql("Update note set indexneeded='true'"); } + // ICHANGED + // 操作履歴テーブルと除外ノートテーブルとスター付きノートテーブルを作る + if (!behaviorDbExists) { + createHistoryTables(); + createExcludedTables(); + createStaredTables(); + } + // If we encrypted/decrypted it the last time, we need to reconnect the tables. // if (Global.relinkTables) { // NSqlQuery query = new NSqlQuery(conn); @@ -309,6 +338,21 @@ public class DatabaseConnection { noteTable.noteResourceTable.createTable(); } + // ICHANGED + public void createHistoryTables() { + historyTable.createTable(); + } + + // ICHANGED + public void createExcludedTables() { + excludedTable.createTable(); + } + + // ICHANGED + public void createStaredTables() { + staredTable.createTable(); + } + public Connection getConnection() { return conn; } @@ -319,6 +363,11 @@ public class DatabaseConnection { return resourceConn; } + // ICHANGED + public Connection getBehaviorConnection() { + return behaviorConn; + } + //*************************************************************** //* Table get methods //*************************************************************** @@ -361,6 +410,21 @@ public class DatabaseConnection { public InkImagesTable getInkImagesTable() { return inkImagesTable; } + + // ICHANGED + public HistoryTable getHistoryTable() { + return historyTable; + } + + // ICHANGED + public ExcludedTable getExcludedTable() { + return excludedTable; + } + + // ICHANGED + public StaredTable getStaredTable() { + return staredTable; + } //**************************************************************** //* Begin/End transactions diff --git a/src/cx/fbn/nevernote/sql/ExcludedTable.java b/src/cx/fbn/nevernote/sql/ExcludedTable.java new file mode 100644 index 0000000..6458894 --- /dev/null +++ b/src/cx/fbn/nevernote/sql/ExcludedTable.java @@ -0,0 +1,157 @@ +// ICHANGED +package cx.fbn.nevernote.sql; + +import cx.fbn.nevernote.sql.driver.NSqlQuery; +import cx.fbn.nevernote.utilities.ApplicationLogger; + +public class ExcludedTable { + private final ApplicationLogger logger; + private final DatabaseConnection db; + + // コンストラクタ + public ExcludedTable(ApplicationLogger l, DatabaseConnection d) { + logger = l; + db = d; + } + + // テーブル作成 + public void createTable() { + NSqlQuery query = new NSqlQuery(db.getBehaviorConnection()); + logger.log(logger.HIGH, "ExcludedNotesテーブルを作成しています..."); + if (!query.exec("Create table ExcludedNotes (id integer primary key auto_increment, guid1 varchar, guid2 varchar)")) + logger.log(logger.HIGH, "ExcludedNotesテーブル作成失敗!!!"); + } + + // テーブルをドロップ + public void dropTable() { + NSqlQuery query = new NSqlQuery(db.getBehaviorConnection()); + query.exec("Drop table ExcludedNotes"); + } + + // ExcludedNotesテーブルにアイテムを1つ追加 + public void addExclusion(String guid1, String guid2) { + NSqlQuery query = new NSqlQuery(db.getBehaviorConnection()); + query.prepare("Insert Into ExcludedNotes (guid1, guid2) Values(:guid1, :guid2)"); + query.bindValue(":guid1", guid1); + query.bindValue(":guid2", guid2); + if (!query.exec()) { + logger.log(logger.MEDIUM, "ExcludedNotesテーブルへのアイテム追加に失敗"); + logger.log(logger.MEDIUM, query.lastError()); + } + } + + // masterGuidとchildGuidをマージ + public void mergeHistoryGuid(String masterGuid, String childGuid) { + NSqlQuery excludedNotesQuery = new NSqlQuery(db.getBehaviorConnection()); + boolean check = false; + + // マージ後に重複してしまうデータを先に削除 + excludedNotesQuery.prepare("Delete from ExcludedNotes where (guid1=:oldGuid1 and guid2=:newGuid1) or (guid1=:newGuid2 and guid2=:oldGuid2)"); + excludedNotesQuery.bindValue(":oldGuid1", masterGuid); + excludedNotesQuery.bindValue(":newGuid1", childGuid); + excludedNotesQuery.bindValue(":oldGuid2", masterGuid); + excludedNotesQuery.bindValue(":newGuid2", childGuid); + check = excludedNotesQuery.exec(); + if(!check){ + logger.log(logger.MEDIUM, "excludedNotesテーブルの重複削除で失敗"); + logger.log(logger.MEDIUM, excludedNotesQuery.lastError()); + } + + updateExcludedNoteGuid(masterGuid, childGuid); + } + + // ExcludedNotesテーブルのGuidを更新 + public void updateExcludedNoteGuid(String newGuid, String oldGuid){ + NSqlQuery excludedNotesQuery = new NSqlQuery(db.getBehaviorConnection()); + boolean check = false; + + excludedNotesQuery.prepare("Update ExcludedNotes set guid1=:newGuid where guid1=:oldGuid"); + excludedNotesQuery.bindValue(":newGuid", newGuid); + excludedNotesQuery.bindValue(":oldGuid", oldGuid); + check = excludedNotesQuery.exec(); + if (!check) { + logger.log(logger.MEDIUM, "ExcludedNotesテーブルのguid1のところでguid更新失敗"); + logger.log(logger.MEDIUM, excludedNotesQuery.lastError()); + } + excludedNotesQuery.prepare("Update ExcludedNotes set guid2=:newGuid where guid2=:oldGuid"); + excludedNotesQuery.bindValue(":newGuid", newGuid); + excludedNotesQuery.bindValue(":oldGuid", oldGuid); + check = excludedNotesQuery.exec(); + if (!check) { + logger.log(logger.MEDIUM, "ExcludedNotesテーブルのguid2のところでguid更新失敗"); + logger.log(logger.MEDIUM, excludedNotesQuery.lastError()); + } + } + + // ExcludedNotesテーブルに引数guidのノートが存在するか + public boolean existNote(String guid1, String guid2) { + NSqlQuery excludedNotesQuery = new NSqlQuery(db.getBehaviorConnection()); + + // 2つの引数guidを含むアイテムの存在確認 + excludedNotesQuery.prepare("Select * from ExcludedNotes where Exists(Select * from ExcludedNotes where (guid1=:guid1_1 and guid2=:guid2_1) or (guid1=:guid2_2 and guid2=:guid1_2))"); + excludedNotesQuery.bindValue(":guid1_1", guid1); + excludedNotesQuery.bindValue(":guid2_1", guid2); + excludedNotesQuery.bindValue(":guid1_2", guid1); + excludedNotesQuery.bindValue(":guid2_2", guid2); + + if (!excludedNotesQuery.exec()) { + logger.log(logger.MEDIUM, "ExcludedNotesテーブルからguid1=" + guid1 + "かつguid2=" + guid2 + "(またはその逆)のアイテムの存在確認失敗"); + logger.log(logger.MEDIUM, excludedNotesQuery.lastError()); + } + + if (excludedNotesQuery.next()) { + return true; + } + + return false; + } + + // oldGuidのノートの除外ノートをnewGuidのノートの除外ノートとして複製 + public void duplicateExcludedNotes(String newGuid, String oldGuid) { + NSqlQuery excludedNotesQuery = new NSqlQuery(db.getBehaviorConnection()); + + // guid1 = oldGuidの除外ノートを取得 + excludedNotesQuery.prepare("Select guid2 from ExcludedNotes where guid1=:oldGuid"); + excludedNotesQuery.bindValue(":oldGuid", oldGuid); + if(!excludedNotesQuery.exec()){ + logger.log(logger.MEDIUM, "ExcludedNotesテーブルからguid1=" + oldGuid + "のアイテム取得失敗"); + logger.log(logger.MEDIUM, excludedNotesQuery.lastError()); + } + // guid1 = newGuidの除外ノートとして複製 + while(excludedNotesQuery.next()){ + String guid2 = excludedNotesQuery.valueString(0); + + addExclusion(newGuid, guid2); + } + + // guid2 = oldGuidの除外ノートを取得 + excludedNotesQuery.prepare("Select guid1 from ExcludedNotes where guid2=:oldGuid"); + excludedNotesQuery.bindValue(":oldGuid", oldGuid); + if(!excludedNotesQuery.exec()){ + logger.log(logger.MEDIUM, "ExcludedNotesテーブルからguid2=" + oldGuid + "のアイテム取得失敗"); + logger.log(logger.MEDIUM, excludedNotesQuery.lastError()); + } + // guid2 = newGuidの除外ノートとして複製 + while(excludedNotesQuery.next()){ + String guid1 = excludedNotesQuery.valueString(0); + + addExclusion(guid1, newGuid); + } + } + + // guidを含む列をExcludedNotesテーブルから削除 + public void expungeExcludedNote(String guid) { + NSqlQuery query = new NSqlQuery(db.getBehaviorConnection()); + boolean check; + + query.prepare("Delete from ExcludedNotes where guid1=:guid1 or guid2=:guid2"); + query.bindValue(":guid1", guid); + query.bindValue(":guid2", guid); + + check = query.exec(); + if(!check){ + logger.log(logger.MEDIUM, "ExcludedNotesテーブルからguid=" + guid + "のデータ削除に失敗"); + logger.log(logger.MEDIUM, query.lastError()); + } + } +} diff --git a/src/cx/fbn/nevernote/sql/HistoryTable.java b/src/cx/fbn/nevernote/sql/HistoryTable.java new file mode 100644 index 0000000..485ff59 --- /dev/null +++ b/src/cx/fbn/nevernote/sql/HistoryTable.java @@ -0,0 +1,284 @@ +// ICHANGED +package cx.fbn.nevernote.sql; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import cx.fbn.nevernote.sql.driver.NSqlQuery; +import cx.fbn.nevernote.utilities.ApplicationLogger; + +public class HistoryTable { + private final ApplicationLogger logger; + private final DatabaseConnection db; + + // コンストラクタ + public HistoryTable(ApplicationLogger l, DatabaseConnection d) { + logger = l; + db = d; + } + + // テーブル作成 + public void createTable() { + NSqlQuery query = new NSqlQuery(db.getBehaviorConnection()); + logger.log(logger.HIGH, "Historyテーブルを作成しています..."); + if (!query + .exec("Create table History (id integer primary key auto_increment, behaviorType varchar," + + "guid1 varchar, guid2 varchar)")) + logger.log(logger.HIGH, "Historyテーブル作成失敗!!!"); + } + + // テーブルをドロップ + public void dropTable() { + NSqlQuery query = new NSqlQuery(db.getBehaviorConnection()); + query.exec("Drop table History"); + } + + // Historyテーブルにアイテムを1つ追加 + public void addHistory(String behaviorType, String guid1, String guid2) { + NSqlQuery query = new NSqlQuery(db.getBehaviorConnection()); + boolean excludedCheck = false; + + if (behaviorType == null) { + return; + } + if (guid1 == null || guid1.equals("")) { + return; + } + if (guid2 == null || guid2.equals("")) { + return; + } + if (guid1.equals(guid2)) { + return; + } + + // 除外ノートに指定されていないかチェックする + excludedCheck = db.getExcludedTable().existNote(guid1, guid2); + + if (!excludedCheck) { + query.prepare("Insert Into History (behaviorType, guid1, guid2) Values(:behaviorType, :guid1, :guid2)"); + query.bindValue(":behaviorType", behaviorType); + query.bindValue(":guid1", guid1); + query.bindValue(":guid2", guid2); + if (!query.exec()) { + logger.log(logger.MEDIUM, "Historyテーブルへのアイテム追加に失敗"); + logger.log(logger.MEDIUM, query.lastError()); + } + } + } + + // masterGuidとchildGuidをマージ + public void mergeHistoryGuid(String masterGuid, String childGuid) { + NSqlQuery histQuery = new NSqlQuery(db.getBehaviorConnection()); + boolean check = false; + + // マージ後に重複してしまうデータを先に削除 + histQuery.prepare("Delete from history where (guid1=:oldGuid1 and guid2=:newGuid1) or (guid1=:newGuid2 and guid2=:oldGuid2)"); + histQuery.bindValue(":oldGuid1", masterGuid); + histQuery.bindValue(":newGuid1", childGuid); + histQuery.bindValue(":oldGuid2", masterGuid); + histQuery.bindValue(":newGuid2", childGuid); + check = histQuery.exec(); + if(!check){ + logger.log(logger.MEDIUM, "historyテーブルの重複削除で失敗"); + logger.log(logger.MEDIUM, histQuery.lastError()); + } + + updateHistoryGuid(masterGuid, childGuid); + } + + // HistoryテーブルのGuidを更新 + public void updateHistoryGuid(String newGuid, String oldGuid){ + NSqlQuery histQuery = new NSqlQuery(db.getBehaviorConnection()); + boolean check = false; + + histQuery.prepare("Update history set guid1=:newGuid where guid1=:oldGuid"); + histQuery.bindValue(":newGuid", newGuid); + histQuery.bindValue(":oldGuid", oldGuid); + check = histQuery.exec(); + if (!check) { + logger.log(logger.MEDIUM, "historyテーブルのguid1のところでguid更新失敗"); + logger.log(logger.MEDIUM, histQuery.lastError()); + } + histQuery.prepare("Update history set guid2=:newGuid where guid2=:oldGuid"); + histQuery.bindValue(":newGuid", newGuid); + histQuery.bindValue(":oldGuid", oldGuid); + check = histQuery.exec(); + if (!check) { + logger.log(logger.MEDIUM, "historyテーブルのguid2のところでguid更新失敗"); + logger.log(logger.MEDIUM, histQuery.lastError()); + } + } + + // Historyテーブルから引数ノートと関連のあるノートのguidと回数をゲット + public HashMap getBehaviorHistory(String behaviorType, String guid) { + NSqlQuery query = new NSqlQuery(db.getBehaviorConnection()); + HashMap behaviorHist = new HashMap(); + + // guid1=guidの履歴一覧を取得 + query.prepare("Select guid2 from History where behaviorType=:behaviorType and guid1=:guid1"); + query.bindValue(":behaviorType", behaviorType); + query.bindValue(":guid1", guid); + if (!query.exec()) { + logger.log(logger.MEDIUM, + "HistoryテーブルからbehaviorType=" + behaviorType + "かつguid1=" + guid + "のアイテム取得失敗"); + logger.log(logger.MEDIUM, query.lastError()); + } + // HashMapに記録 + while (query.next()) { + // すでにHashMapに登録されていたら、回数を+1 + String key = query.valueString(0); + if (behaviorHist.containsKey(key)) { + behaviorHist.put(key, behaviorHist.get(key) + 1); + } else { // そうでないなら新規登録 + behaviorHist.put(key, 1); + } + } + + // guid2=guidの履歴一覧を取得 + query.prepare("Select guid1 from History where behaviorType=:behaviorType and guid2=:guid2"); + query.bindValue(":behaviorType", behaviorType); + query.bindValue(":guid2", guid); + if (!query.exec()) { + logger.log(logger.MEDIUM, + "HistoryテーブルからbehaviorType=" + behaviorType + "かつguid2=" + guid + "のアイテム取得失敗"); + logger.log(logger.MEDIUM, query.lastError()); + } + // HashMapに記録 + while (query.next()) { + // すでにHashMapに登録されていたら、回数を+1 + String key = query.valueString(0); + if (behaviorHist.containsKey(key)) { + behaviorHist.put(key, behaviorHist.get(key) + 1); + } else { // そうでないなら新規登録 + behaviorHist.put(key, 1); + } + } + return behaviorHist; + } + + // oldGuidのノートの操作履歴をnewGuidのノートの操作履歴として複製 + public void duplicateHistory(String newGuid, String oldGuid) { + NSqlQuery histQuery = new NSqlQuery(db.getBehaviorConnection()); + + // guid1 = oldGuidの履歴一覧を取得 + histQuery.prepare("Select behaviorType, guid2 from History where guid1=:oldGuid"); + histQuery.bindValue(":oldGuid", oldGuid); + if(!histQuery.exec()){ + logger.log(logger.MEDIUM, "Historyテーブルからguid1=" + oldGuid + "のアイテム取得失敗"); + logger.log(logger.MEDIUM, histQuery.lastError()); + } + // guid1 = newGuidの履歴として複製 + while(histQuery.next()){ + String behaviorType = histQuery.valueString(0); + String guid2 = histQuery.valueString(1); + + addHistory(behaviorType, newGuid, guid2); + } + + // guid2 = oldGuidの履歴一覧を取得 + histQuery.prepare("Select behaviorType, guid1 from History where guid2=:oldGuid"); + histQuery.bindValue(":oldGuid", oldGuid); + if(!histQuery.exec()){ + logger.log(logger.MEDIUM, "Historyテーブルからguid2=" + oldGuid + "のアイテム取得失敗"); + logger.log(logger.MEDIUM, histQuery.lastError()); + } + // guid2 = newGuidの履歴として複製 + while(histQuery.next()){ + String behaviorType = histQuery.valueString(0); + String guid1 = histQuery.valueString(1); + + addHistory(behaviorType, guid1, newGuid); + } + } + + // guidを含む列をHistoryテーブルから削除 + public void expungeHistory(String guid) { + NSqlQuery query = new NSqlQuery(db.getBehaviorConnection()); + boolean check; + + query.prepare("Delete from History where guid1=:guid1 or guid2=:guid2"); + query.bindValue(":guid1", guid); + query.bindValue(":guid2", guid); + + check = query.exec(); + if(!check){ + logger.log(logger.MEDIUM, "historyテーブルからguid=" + guid + "のデータ削除に失敗"); + logger.log(logger.MEDIUM, query.lastError()); + } + } + + // guid1とguid2を指定してHistoryテーブルから削除 + public void expungeHistory(String guid1, String guid2) { + NSqlQuery query = new NSqlQuery(db.getBehaviorConnection()); + boolean check; + + query.prepare("Delete from History where guid1=:guid1 and guid2=:guid2"); + query.bindValue(":guid1", guid1); + query.bindValue(":guid2", guid2); + + check = query.exec(); + if(!check){ + logger.log(logger.MEDIUM, "historyテーブルからguid1=" + guid1 + "かつguid2=" + guid2 + "のデータ削除に失敗"); + logger.log(logger.MEDIUM, query.lastError()); + } + + // guid1とguid2が逆のパターンも削除 + query.prepare("Delete from History where guid1=:guid1 and guid2=:guid2"); + query.bindValue(":guid1", guid2); + query.bindValue(":guid2", guid1); + + check = query.exec(); + if(!check){ + logger.log(logger.MEDIUM, "historyテーブルからguid1=" + guid2 + "かつguid2=" + guid1 + "のデータ削除に失敗"); + logger.log(logger.MEDIUM, query.lastError()); + } + } + + // 同じタグが付けられたノート間の履歴を登録 + public void addSameTagHistory(String noteGuid, String tagGuid) { + if (noteGuid == null || noteGuid.equals("")) { + return; + } + if (tagGuid == null || tagGuid.equals("")) { + return; + } + + // そのタグが新しいタグでないなら終了 + List prevTags = new ArrayList(db.getNoteTable().noteTagsTable.getNoteTags(noteGuid)); + for (int i = 0; i < prevTags.size(); i++) { + System.out.println(prevTags.get(i)); + if (tagGuid.equals(prevTags.get(i))) { + return; + } + } + + // すでにそのタグが付いているノートを取得 + List sameTagNoteGuids = new ArrayList(db.getNoteTable().noteTagsTable.getTagNotes(tagGuid)); + + for (int i = 0; i < sameTagNoteGuids.size(); i++) { + String guid = sameTagNoteGuids.get(i); + addHistory("sameTag", noteGuid, guid); + } + } + + // 同じノートブックに入れられたノート間の履歴を登録 + public void addSameNotebookHistory(String noteGuid, String notebookGuid) { + if (noteGuid == null || noteGuid.equals("")) { + return; + } + if (notebookGuid == null || notebookGuid.equals("")) { + return; + } + + // すでにそのノートブックに属しているノートを取得 + List sameNotebookNoteGuids = new ArrayList(db.getNoteTable().getNotesByNotebook(notebookGuid)); + + for (int i = 0; i < sameNotebookNoteGuids.size(); i++) { + String guid = sameNotebookNoteGuids.get(i); + if (!noteGuid.equals(guid)) { + addHistory("sameNotebook", noteGuid, guid); + } + } + } +} diff --git a/src/cx/fbn/nevernote/sql/NoteTable.java b/src/cx/fbn/nevernote/sql/NoteTable.java index 3df5ac4..d3219a9 100644 --- a/src/cx/fbn/nevernote/sql/NoteTable.java +++ b/src/cx/fbn/nevernote/sql/NoteTable.java @@ -1,1707 +1,1768 @@ -/* - * This file is part of NixNote - * Copyright 2009 Randy Baumgarte - * - * This file may be licensed under the terms of of the - * GNU General Public License Version 2 (the ``GPL''). - * - * Software distributed under the License is distributed - * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either - * express or implied. See the GPL for the specific language - * governing rights and limitations. - * - * You should have received a copy of the GPL along with this - * program. If not, go to http://www.gnu.org/licenses/gpl.html - * or write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * -*/ - - -package cx.fbn.nevernote.sql; - -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -import org.apache.commons.lang3.StringEscapeUtils; - -import com.evernote.edam.type.Note; -import com.evernote.edam.type.NoteAttributes; -import com.evernote.edam.type.Resource; -import com.evernote.edam.type.Tag; -import com.trolltech.qt.core.QByteArray; -import com.trolltech.qt.core.QDateTime; -import com.trolltech.qt.core.QTextCodec; -import com.trolltech.qt.gui.QPixmap; - -import cx.fbn.nevernote.Global; -import cx.fbn.nevernote.evernote.EnmlConverter; -import cx.fbn.nevernote.evernote.NoteMetadata; -import cx.fbn.nevernote.sql.driver.NSqlQuery; -import cx.fbn.nevernote.utilities.ApplicationLogger; -import cx.fbn.nevernote.utilities.Pair; - -public class NoteTable { - private final ApplicationLogger logger; - public final NoteTagsTable noteTagsTable; - public NoteResourceTable noteResourceTable; - private final DatabaseConnection db; - int id; - - // Prepared Queries to improve speed - private NSqlQuery getQueryWithContent; - private NSqlQuery getQueryWithoutContent; - private NSqlQuery getAllQueryWithoutContent; - - // Constructor - public NoteTable(ApplicationLogger l, DatabaseConnection d) { - logger = l; - db = d; - id = 0; - noteResourceTable = new NoteResourceTable(logger, db); - noteTagsTable = new NoteTagsTable(logger, db); - getQueryWithContent = null; - getQueryWithoutContent = null; - } - // Create the table - public void createTable() { - //getQueryWithContent = new NSqlQuery(db.getConnection()); - //getQueryWithoutContent = new NSqlQuery(db.getConnection()); - NSqlQuery query = new NSqlQuery(db.getConnection()); - logger.log(logger.HIGH, "Creating table Note..."); - if (!query.exec("Create table Note (guid varchar primary key, " + - "updateSequenceNumber integer, title varchar, content varchar, contentHash varchar, "+ - "contentLength integer, created timestamp, updated timestamp, deleted timestamp, " - +"active integer, notebookGuid varchar, attributeSubjectDate timestamp, "+ - "attributeLatitude double, attributeLongitude double, attributeAltitude double,"+ - "attributeAuthor varchar, attributeSource varchar, attributeSourceUrl varchar, "+ - "attributeSourceApplication varchar, indexNeeded boolean, isExpunged boolean, " + - "isDirty boolean)")) - logger.log(logger.HIGH, "Table Note creation FAILED!!!"); - if (!query.exec("CREATE INDEX unindexed_notess on note (indexneeded desc, guid);")) - logger.log(logger.HIGH, "Note unindexed_notes index creation FAILED!!!"); - if (!query.exec("CREATE INDEX unsynchronized_notes on note (isDirty desc, guid);")) - logger.log(logger.HIGH, "note unsynchronized_notes index creation FAILED!!!"); - noteTagsTable.createTable(); -// noteResourceTable.createTable(); - } - // Drop the table - public void dropTable() { - NSqlQuery query = new NSqlQuery(db.getConnection()); - query.exec("Drop table Note"); - noteTagsTable.dropTable(); - noteResourceTable.dropTable(); - } - // Save Note List from Evernote - public void addNote(Note n, boolean isDirty) { - logger.log(logger.EXTREME, "Inside addNote"); - if (n == null) - return; - - SimpleDateFormat simple = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - - NSqlQuery query = new NSqlQuery(db.getConnection()); - query.prepare("Insert Into Note (" - +"guid, updateSequenceNumber, title, content, " - +"contentHash, contentLength, created, updated, deleted, active, notebookGuid, " - +"attributeSubjectDate, attributeLatitude, attributeLongitude, attributeAltitude, " - +"attributeAuthor, attributeSource, attributeSourceUrl, attributeSourceApplication, " - +"indexNeeded, isExpunged, isDirty, titlecolor, thumbnailneeded" - +") Values(" - +":guid, :updateSequenceNumber, :title, :content, " - +":contentHash, :contentLength, :created, :updated, :deleted, :active, :notebookGuid, " - +":attributeSubjectDate, :attributeLatitude, :attributeLongitude, :attributeAltitude, " - +":attributeAuthor, :attributeSource, :attributeSourceUrl, :attributeSourceApplication, " - +":indexNeeded, :isExpunged, :isDirty, -1, true) "); - - StringBuilder created = new StringBuilder(simple.format(n.getCreated())); - StringBuilder updated = new StringBuilder(simple.format(n.getUpdated())); - StringBuilder deleted = new StringBuilder(simple.format(n.getDeleted())); - - - - query.bindValue(":guid", n.getGuid()); - query.bindValue(":updateSequenceNumber", n.getUpdateSequenceNum()); - query.bindValue(":title", n.getTitle()); - if (isDirty) { - EnmlConverter enml = new EnmlConverter(logger); - query.bindValue(":content", enml.fixEnXMLCrap(enml.fixEnMediaCrap(n.getContent()))); - } - else - query.bindValue(":content", n.getContent()); - query.bindValue(":contentHash", n.getContentHash()); - query.bindValue(":contentLength", n.getContentLength()); - query.bindValue(":created", created.toString()); - query.bindValue(":updated", updated.toString()); - query.bindValue(":deleted", deleted.toString()); - query.bindValue(":active", n.isActive()); - query.bindValue(":notebookGuid", n.getNotebookGuid()); - - if (n.getAttributes() != null) { - created = new StringBuilder(simple.format(n.getAttributes().getSubjectDate())); - query.bindValue(":attributeSubjectDate", created.toString()); - query.bindValue(":attributeLatitude", n.getAttributes().getLatitude()); - query.bindValue(":attributeLongitude", n.getAttributes().getLongitude()); - query.bindValue(":attributeAltitude", n.getAttributes().getAltitude()); - query.bindValue(":attributeAuthor", n.getAttributes().getAuthor()); - query.bindValue(":attributeSource", n.getAttributes().getSource()); - query.bindValue(":attributeSourceUrl", n.getAttributes().getSourceURL()); - query.bindValue(":attributeSourceApplication", n.getAttributes().getSourceApplication()); - } else { - created = new StringBuilder(simple.format(n.getCreated())); - query.bindValue(":attributeSubjectDate", created.toString()); - query.bindValue(":attributeLatitude", 0.0); - query.bindValue(":attributeLongitude", 0.0); - query.bindValue(":attributeAltitude", 0.0); - query.bindValue(":attributeAuthor", ""); - query.bindValue(":attributeSource", ""); - query.bindValue(":attributeSourceUrl", ""); - query.bindValue(":attributeSourceApplication", ""); - } - query.bindValue(":indexNeeded", true); - query.bindValue(":isExpunged", false); - query.bindValue(":isDirty", isDirty); - - - if (!query.exec()) - logger.log(logger.MEDIUM, query.lastError()); - - // Save the note tags - if (n.getTagGuids() != null) { - for (int i=0; i " +query.lastError().toString()); - logger.log(logger.EXTREME, " -> " +query.lastError()); - return null; - } - Note n = mapNoteFromQuery(query, loadContent, loadResources, loadRecognition, loadBinary, loadTags); - n.setContent(fixCarriageReturn(n.getContent())); - n.getAttributes().setContentClassIsSet(false); - return n; - } - // Get a note by Guid - public Note mapNoteFromQuery(NSqlQuery query, boolean loadContent, boolean loadResources, boolean loadRecognition, boolean loadBinary, boolean loadTags) { - DateFormat indfm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S"); -// indfm = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy"); - - Note n = new Note(); - NoteAttributes na = new NoteAttributes(); - n.setAttributes(na); - - n.setGuid(query.valueString(0)); - n.setUpdateSequenceNum(new Integer(query.valueString(1))); - n.setTitle(query.valueString(2)); - - try { - n.setCreated(indfm.parse(query.valueString(3)).getTime()); - n.setUpdated(indfm.parse(query.valueString(4)).getTime()); - n.setDeleted(indfm.parse(query.valueString(5)).getTime()); - } catch (ParseException e) { - e.printStackTrace(); - } - - n.setActive(query.valueBoolean(6,true)); - n.setNotebookGuid(query.valueString(7)); - - try { - String attributeSubjectDate = query.valueString(8); - if (!attributeSubjectDate.equals("")) - na.setSubjectDate(indfm.parse(attributeSubjectDate).getTime()); - } catch (ParseException e) { - e.printStackTrace(); - } - na.setLatitude(new Float(query.valueString(9))); - na.setLongitude(new Float(query.valueString(10))); - na.setAltitude(new Float(query.valueString(11))); - na.setAuthor(query.valueString(12)); - na.setSource(query.valueString(13)); - na.setSourceURL(query.valueString(14)); - na.setSourceApplication(query.valueString(15)); - na.setContentClass(query.valueString(16)); - - if (loadTags) { - List tagGuids = noteTagsTable.getNoteTags(n.getGuid()); - List tagNames = new ArrayList(); - TagTable tagTable = db.getTagTable(); - for (int i=0; i 0) { - unicode = query.valueString(17); - //System.out.println(unicode); - //unicode = unicode.replace("<", "&_lt;"); - //unicode = codec.fromUnicode(StringEscapeUtils.unescapeHtml(unicode)).toString(); - //unicode = unicode.replace("&_lt;", "<"); - //System.out.println("************************"); - int j=1; - for (int i=buffer.indexOf("&#"); i != -1 && buffer.indexOf("&#", i)>0; i=buffer.indexOf("&#",i+1)) { - j = buffer.indexOf(";",i)+1; - if (i resources = noteResourceTable.getNoteResourcesRecognition(n.getGuid()); - n.setResources(resources); - } else { - // We need to merge the recognition resources with the note resources retrieved earlier - for (int i=0; i notes = getNotesByNotebook(notebookGuid); - for (int i=0; i guids = new ArrayList(); - List usns = new ArrayList(); - while (query.next()) { - guids.add(query.valueString(0)); - Integer usn = new Integer(query.valueString(1)); - usns.add(usn); - } - - for (int i=0; i getDirty() { - String guid; - Note tempNote; - List notes = new ArrayList(); - List index = new ArrayList(); - - boolean check; - NSqlQuery query = new NSqlQuery(db.getConnection()); - - check = query.exec("Select guid from Note where isDirty = true and isExpunged = false and notebookGuid not in (select guid from notebook where local = true or linked = true)"); - if (!check) - logger.log(logger.EXTREME, "Note SQL retrieve has failed: " +query.lastError().toString()); - - // Get a list of the notes - while (query.next()) { - guid = new String(); - guid = query.valueString(0); - index.add(guid); - } - - // Start getting notes - for (int i=0; i getDirtyLinkedNotes() { - String guid; - Note tempNote; - List notes = new ArrayList(); - List index = new ArrayList(); - - boolean check; - NSqlQuery query = new NSqlQuery(db.getConnection()); - - check = query.exec("Select guid from Note where isDirty = true and isExpunged = false and notebookGuid in (select guid from notebook where linked = true)"); - if (!check) - logger.log(logger.EXTREME, "Note SQL retrieve has failed: " +query.lastError().toString()); - - // Get a list of the notes - while (query.next()) { - guid = new String(); - guid = query.valueString(0); - index.add(guid); - } - - // Start getting notes - for (int i=0; i getDirtyLinked(String notebookGuid) { - String guid; - Note tempNote; - List notes = new ArrayList(); - List index = new ArrayList(); - - boolean check; - NSqlQuery query = new NSqlQuery(db.getConnection()); - - query.prepare("Select guid from Note where isDirty = true and isExpunged = false and notebookGuid=:notebookGuid"); - query.bindValue(":notebookGuid", notebookGuid); - check = query.exec(); - if (!check) - logger.log(logger.EXTREME, "Note SQL retrieve has failed getting dirty linked notes: " +query.lastError().toString()); - - // Get a list of the notes - while (query.next()) { - guid = new String(); - guid = query.valueString(0); - index.add(guid); - } - - // Start getting notes - for (int i=0; i getNotesByNotebook(String notebookGuid) { - List notes = new ArrayList(); - List index = new ArrayList(); - - boolean check; - NSqlQuery query = new NSqlQuery(db.getConnection()); - - check = query.prepare("Select guid from Note where notebookguid=:notebookguid"); - if (!check) - logger.log(logger.EXTREME, "Note SQL retrieve has failed: " +query.lastError().toString()); - query.bindValue(":notebookguid", notebookGuid); - query. exec(); - - // Get a list of the notes - while (query.next()) { - index.add(query.valueString(0)); - } - - return notes; - } - // Get a list of notes that need to be updated - public boolean isNoteDirty(String guid) { - - boolean check; - NSqlQuery query = new NSqlQuery(db.getConnection()); - - check = query.prepare("Select guid from Note where isDirty = true and guid=:guid"); - query.bindValue(":guid", guid); - check = query.exec(); - if (!check) - logger.log(logger.EXTREME, "Note SQL retrieve has failed: " +query.lastError().toString()); - - boolean returnValue; - // Get a list of the notes - if (query.next()) - returnValue = true; - else - returnValue = false; - - return returnValue; - } - - // Reset the dirty bit - public void resetDirtyFlag(String guid) { - logger.log(logger.LOW, "Resetting dirty flag for " +guid); - NSqlQuery query = new NSqlQuery(db.getConnection()); - - query.prepare("Update note set isdirty=false where guid=:guid"); - query.bindValue(":guid", guid); - if (!query.exec()) - logger.log(logger.EXTREME, "Error resetting note dirty field."); - } - // Get all notes - public List getAllGuids() { - List notes = new ArrayList(); - - boolean check; - NSqlQuery query = new NSqlQuery(db.getConnection()); - - check = query.exec("Select guid from Note"); - if (!check) - logger.log(logger.EXTREME, "Notebook SQL retrieve has failed: "+query.lastError()); - - // Get a list of the notes - while (query.next()) { - notes.add(new String(query.valueString(0))); - } - return notes; - } - // Get all notes - public List getAllNotes() { - List notes = new ArrayList(); - prepareQueries(); - boolean check; - if (getAllQueryWithoutContent == null) - prepareQueries(); - NSqlQuery query = getAllQueryWithoutContent; - check = query.exec(); - if (!check) - logger.log(logger.EXTREME, "Notebook SQL retrieve has failed: "+query.lastError()); - // Get a list of the notes - while (query.next()) { - notes.add(mapNoteFromQuery(query, false, false, false, false, true)); - } - return notes; - } - // Count unindexed notes - public int getUnindexedCount() { - NSqlQuery query = new NSqlQuery(db.getConnection()); - query.exec("select count(*) from note where indexneeded=true and isExpunged = false"); - query.next(); - int returnValue = new Integer(query.valueString(0)); - return returnValue; - } - // Count unsynchronized notes - public int getDirtyCount() { - NSqlQuery query = new NSqlQuery(db.getConnection()); - query.exec("select count(guid) from note where isDirty=true and isExpunged = false"); - query.next(); - int returnValue = new Integer(query.valueString(0)); - logger.log(logger.LOW, "dirty count: " +returnValue); - //query.exec("select count(guid) from note where isDirty=true and Active = 0 and isExpunged = false"); - //query.next(); - //logger.log(logger.LOW, "dirty count (active only): " +query.valueString(0)); - //query.exec("Select count(guid) from Note where isDirty = true and isExpunged = false and notebookGuid not in (select guid from notebook where local = true or linked = true)"); - //query.next(); - //logger.log(logger.LOW, "dirty count (no l&l notebooks): " +query.valueString(0)); - //logger.log(logger.LOW, "Beginning stack trace"); - //logger.log(logger.LOW, Thread.currentThread().getStackTrace()); - - //logger.log(logger.LOW, "*************************"); - //logger.log(logger.LOW, "*** DIRTY RECORD DUMP ***"); - //logger.log(logger.LOW, "*************************"); - //List recs = getDirty(); - //for (int i=0; i"+a0+"", "
 
"); - return note.replace("
", "
 
"); - } - - // Expunge notes that we don't want to synchronize - public List expungeIgnoreSynchronizedNotes(List notebooks, Listtags, List linked) { - - List noteGuids = new ArrayList(); - for (int i=0; i notes = findNotesByNotebook(notebooks.get(i)); - for (int j=0; j notes = findNotesByTag(tags.get(i)); - for (int j=0; j linkedTags = db.getTagTable().getTagsForNotebook(notebookGuid); - for (int j=0; j notes = findNotesByNotebook(notebookGuid); - for (int j=0; j findNotesByNotebook(String notebook) { - List values = new ArrayList(); - NSqlQuery query = new NSqlQuery(db.getConnection()); - query.prepare("Select guid from note where notebookguid=:notebook"); - - query.bindValue(":notebook", notebook); - query.exec(); - while (query.next()) { - values.add(query.valueString(0)); - } - return values; - } - - public List findNotesByTag(String tag) { - List values = new ArrayList(); - NSqlQuery query = new NSqlQuery(db.getConnection()); - query.prepare("Select distinct noteguid from notetags where tagguid=:tag"); - - query.bindValue(":tag", tag); - query.exec(); - while (query.next()) { - values.add(query.valueString(0)); - } - return values; - } - - // Find a note based upon its title. - public List> findNotesByTitle(String text) { - List> results = new ArrayList>(); - boolean check; - NSqlQuery query = new NSqlQuery(db.getConnection()); - - check = query.prepare("Select guid,title from Note where lower(title) like :title"); - if (!check) - logger.log(logger.EXTREME, "Note SQL prepare for search by title has failed: " +query.lastError().toString()); - - query.bindValue(":title", "%"+text.toLowerCase()+"%"); - query.exec(); - // Get a list of the notes - while (query.next()) { - Pair p = new Pair(); - p.setFirst(query.valueString(0)); - p.setSecond(query.valueString(1)); - results.add(p); - } - return results; - } - - - - //******************************************************************************** - //******************************************************************************** - //* Indexing Functions - //******************************************************************************** - //******************************************************************************** - // set/unset a note to be reindexed - public void setIndexNeeded(String guid, Boolean flag) { - NSqlQuery query = new NSqlQuery(db.getConnection()); - query.prepare("Update Note set indexNeeded=:flag where guid=:guid"); - - if (flag) - query.bindValue(":flag", 1); - else - query.bindValue(":flag", 0); - query.bindValue(":guid", guid); - if (!query.exec()) { - logger.log(logger.MEDIUM, "Note indexNeeded update failed."); - logger.log(logger.MEDIUM, query.lastError()); - } - List r = noteResourceTable.getNoteResources(guid, false); - for (int i=0; r!= null && i getUnindexed() { - String guid; - List index = new ArrayList(); - NSqlQuery query = new NSqlQuery(db.getConnection()); - - if (!query.exec("Select guid from Note where isExpunged = false and indexNeeded = true and DATEDIFF('MINUTE',updated,CURRENT_TIMESTAMP)>5")) - logger.log(logger.EXTREME, "Note SQL retrieve has failed on getUnindexed()."); - - // Get a list of the notes - while (query.next()) { - guid = new String(); - guid = query.valueString(0); - index.add(guid); - } - return index; - } - public List getNextUnindexed(int limit) { - List guids = new ArrayList(); - - NSqlQuery query = new NSqlQuery(db.getConnection()); - - if (!query.exec("Select guid from Note where isExpunged = false and indexNeeded = true and DATEDIFF('MINUTE',Updated,CURRENT_TIMESTAMP)>5 limit " +limit)) - logger.log(logger.EXTREME, "Note SQL retrieve has failed on getUnindexed()."); - - // Get a list of the notes - String guid; - while (query.next()) { - guid = new String(); - guid = query.valueString(0); - guids.add(guid); - } - return guids; - } - - - // Get note meta information - public void updateNoteMetadata(NoteMetadata meta) { - NSqlQuery query = new NSqlQuery(db.getConnection()); - if (!query.prepare("Update Note set titleColor=:color, pinned=:pinned, attributeSourceApplication=:metaString where guid=:guid")) - logger.log(logger.EXTREME, "Note SQL prepare has failed on updateNoteMetadata."); - query.bindValue(":color", meta.getColor()); - query.bindValue(":pinned", meta.isPinned()); - query.bindValue(":guid", meta.getGuid()); - query.bindValue(":metaString", buildMetadataString(meta)); - if (!query.exec()) - logger.log(logger.EXTREME, "Note SQL exec has failed on updateNoteMetadata."); - return; - } - - // Get all note meta information - public HashMap getNotesMetaInformation() { - HashMap returnValue = new HashMap(); - NSqlQuery query = new NSqlQuery(db.getConnection()); - - if (!query.exec("Select guid,titleColor, isDirty, pinned from Note")) - logger.log(logger.EXTREME, "Note SQL retrieve has failed on getNoteMetaInformation."); - - // Get a list of the notes - while (query.next()) { - NoteMetadata note = new NoteMetadata(); - note.setGuid(query.valueString(0)); - note.setColor(query.valueInteger(1)); - note.setDirty(query.valueBoolean(2, false)); - int pinned = query.valueInteger(3); - if (pinned > 0) - note.setPinned(true); - returnValue.put(note.getGuid(), note); - } - - return returnValue; - } - // Get note meta information - public NoteMetadata getNoteMetaInformation(String guid) { - NSqlQuery query = new NSqlQuery(db.getConnection()); - - if (!query.prepare("Select guid,titleColor, isDirty, pinned from Note where guid=:guid")) { - logger.log(logger.EXTREME, "Note SQL retrieve has failed on getNoteMetaInformation."); - return null; - } - query.bindValue(":guid", guid); - query.exec(); - - // Get a list of the notes - while (query.next()) { - NoteMetadata note = new NoteMetadata(); - note.setGuid(query.valueString(0)); - note.setColor(query.valueInteger(1)); - note.setDirty(query.valueBoolean(2, false)); - int pinned = query.valueInteger(3); - if (pinned > 0) - note.setPinned(true); - return note; - } - - return null; - } - - - //********************************************************************************** - //* Thumbnail functions - //********************************************************************************** - // Set if a new thumbnail is needed - public void setThumbnailNeeded(String guid, boolean needed) { - - boolean check; - NSqlQuery query = new NSqlQuery(db.getConnection()); - - check = query.prepare("Update note set thumbnailneeded = :needed where guid=:guid"); - query.bindValue(":guid", guid); - query.bindValue(":needed", needed); - check = query.exec(); - if (!check) - logger.log(logger.EXTREME, "Note SQL set thumbail needed failed: " +query.lastError().toString()); - - } - // Is a thumbail needed for this guid? - public boolean isThumbnailNeeded(String guid) { - - boolean check; - NSqlQuery query = new NSqlQuery(db.getConnection()); - - check = query.prepare("select thumbnailneeded from note where guid=:guid"); - query.bindValue(":guid", guid); - check = query.exec(); - if (!check) - logger.log(logger.EXTREME, "Note SQL isThumbnailNeeded query failed: " +query.lastError().toString()); - - boolean returnValue; - // Get a list of the notes - if (query.next()) - returnValue = query.valueBoolean(0, false); - else - returnValue = false; - - return returnValue; - } - // Set if a new thumbnail is needed - public void setThumbnail(String guid, QByteArray thumbnail) { - - boolean check; - NSqlQuery query = new NSqlQuery(db.getConnection()); - - check = query.prepare("Update note set thumbnail = :thumbnail where guid=:guid"); - query.bindValue(":guid", guid); - query.bindValue(":thumbnail", thumbnail.toByteArray()); - check = query.exec(); - if (!check) - logger.log(logger.EXTREME, "Note SQL set thumbail failed: " +query.lastError().toString()); - - } - // Set if a new thumbnail is needed - public QByteArray getThumbnail(String guid) { - - boolean check; - NSqlQuery query = new NSqlQuery(db.getConnection()); - - check = query.prepare("Select thumbnail from note where guid=:guid"); - query.bindValue(":guid", guid); - check = query.exec(); - if (!check) - logger.log(logger.EXTREME, "Note SQL get thumbail failed: " +query.lastError().toString()); - // Get a list of the notes - if (query.next()) { - try { - if (query.getBlob(0) != null) { - return new QByteArray(query.getBlob(0)); - } - } catch (java.lang.IllegalArgumentException e) { - return null; - } - } - return null; - } - // Get all thumbnails - public HashMap getThumbnails() { - boolean check; - NSqlQuery query = new NSqlQuery(db.getConnection()); - HashMap map = new HashMap(); - - check = query.prepare("Select guid,thumbnail from note where thumbnailneeded=false and isExpunged=false"); - check = query.exec(); - if (!check) - logger.log(logger.EXTREME, "Note SQL get thumbail failed: " +query.lastError().toString()); - // Get a list of the notes - while (query.next()) { - try { - if (query.getBlob(1) != null) { - QByteArray data = new QByteArray(query.getBlob(1)); - QPixmap img = new QPixmap(); - if (img.loadFromData(data)) { - img = img.scaled(Global.largeThumbnailSize); - map.put(query.valueString(0), img); - } - } - } catch (java.lang.IllegalArgumentException e) { - logger.log(logger.HIGH, "Error retrieving thumbnail " +e.getMessage()); - } - } - return map; - } - // Get a list of notes that need thumbnails - public List findThumbnailsNeeded() { - - boolean check; - NSqlQuery query = new NSqlQuery(db.getConnection()); - - check = query.prepare("select guid from note where thumbnailneeded=true and isExpunged=false and DATEDIFF('MINUTE',updated,CURRENT_TIMESTAMP)>5 limit 5"); - check = query.exec(); - if (!check) - logger.log(logger.EXTREME, "Note SQL findThumbnailsNeeded query failed: " +query.lastError().toString()); - - - // Get a list of the notes - List values = new ArrayList(); - while (query.next()) { - values.add(query.valueString(0)); - } - - return values; - } - // Get a count of thumbnails needed - public int getThumbnailNeededCount() { - - boolean check; - NSqlQuery query = new NSqlQuery(db.getConnection()); - - check = query.prepare("select count(guid) from note where thumbnailneeded=true and isExpunged=false and DATEDIFF('MINUTE',updated,CURRENT_TIMESTAMP)>5 limit 2"); - check = query.exec(); - if (!check) - logger.log(logger.EXTREME, "Note SQL findThumbnailNeededCount query failed: " +query.lastError().toString()); - - if (query.next()) { - return query.valueInteger(0); - } - - return 0; - } - - //*********************************************************************************** - public String findAlternateGuid(String guid) { - boolean check; - NSqlQuery query = new NSqlQuery(db.getConnection()); - - check = query.prepare("select guid from note where original_guid=:guid"); - query.bindValue(":guid", guid); - check = query.exec(); - if (!check) - logger.log(logger.EXTREME, "Note SQL findAlternateguid query failed: " +query.lastError().toString()); - - if (query.next()) { - return query.valueString(0); - } - - return null; - } - - //* Check if a note guid exists - public boolean guidExists(String guid) { - boolean check; - NSqlQuery query = new NSqlQuery(db.getConnection()); - - check = query.prepare("select guid from note where guid=:guid"); - query.bindValue(":guid", guid); - check = query.exec(); - if (!check) - logger.log(logger.EXTREME, "Note SQL guidExists query failed: " +query.lastError().toString()); - - if (query.next()) { - return true; - } - - return false; - } - - // Update a note content's hash. This happens if a resource is edited outside of NN - public void updateResourceContentHash(String guid, String oldHash, String newHash) { - Note n = getNote(guid, true, false, false, false,false); - int position = n.getContent().indexOf("-1;) { - endPos = n.getContent().indexOf(">", position+1); - String oldSegment = n.getContent().substring(position,endPos); - int hashPos = oldSegment.indexOf("hash=\""); - int hashEnd = oldSegment.indexOf("\"", hashPos+7); - String hash = oldSegment.substring(hashPos+6, hashEnd); - if (hash.equalsIgnoreCase(oldHash)) { - String newSegment = oldSegment.replace(oldHash, newHash); - String content = n.getContent().substring(0,position) + - newSegment + - n.getContent().substring(endPos); - NSqlQuery query = new NSqlQuery(db.getConnection()); - query.prepare("update note set isdirty=true, thumbnailneeded=true, content=:content where guid=:guid"); - query.bindValue(":content", content); - query.bindValue(":guid", n.getGuid()); - query.exec(); - } - - position = n.getContent().indexOf(" 0) - metaString = metaString.substring(0,endPos); - - String value = parseMetaString(metaString, "titleColor"); - if (value != null) - meta.setColor(Integer.parseInt(value)); - - value = parseMetaString(metaString, "pinned"); - if (value != null && value.equals(true)) - meta.setPinned(true); - - return meta; - } - - // Given a metadata string from attribute.sourceApplication, we - // extract the information for a given key. - private String parseMetaString(String metaString, String key) { - int startPos = metaString.indexOf(key); - if (startPos < 0) - return null; - - String value = metaString.substring(startPos+key.length()+1); - int endPos = value.indexOf(";"); - if (endPos > 0) - value = value.substring(0,endPos); - - return value; - } - - // Given a set of metadata, we build a string that can be inserted - // into the attribute.sourceApplication string. - private String buildMetadataString(NoteMetadata meta) { - StringBuffer value = new StringBuffer(removeExistingMetaString(meta.getGuid())); - StringBuffer metaString = new StringBuffer(); - - if (meta.isPinned()) { - metaString.append("pinned=true;"); - } - if (meta.getColor() != -1) { - metaString.append("titleColor=" +new Integer(meta.getColor()).toString()+";"); - } - if (metaString.length()>0) { - - // Adda any missing ";" or " " at the end of the existing - // string. - if (value.length()>1 && (!value.toString().trim().endsWith(";") || !value.toString().trim().endsWith(";"))) - value.append("; "); - - value.append("baumgarte:{"); - value.append(metaString); - value.append("};"); - return value.toString(); - } - return null; - } - - // This will remove the existing metadata string from the attribute.sourceApplication string. - private String removeExistingMetaString(String guid) { - NSqlQuery query = new NSqlQuery(db.getConnection()); - - if (!query.prepare("Select attributeSourceApplication from Note where guid=:guid")) { - logger.log(logger.EXTREME, "Note SQL retrieve has failed in removeExistingMetaString."); - return null; - } - query.bindValue(":guid", guid); - query.exec(); - - // Get the application source string - String sourceApplication = null; - while (query.next()) { - sourceApplication = query.valueString(0); - } - if (sourceApplication == null) - return ""; - - String consumerKey = "baumgarte:{"; - int startPos = sourceApplication.indexOf(consumerKey); - if (startPos < 0 ) - return sourceApplication; - String startString = sourceApplication.substring(0,startPos); - String metaString = sourceApplication.substring(startPos); - String endString = metaString.substring(metaString.indexOf("};")+2); - - return startString+endString; - } - + } + logger.log(logger.EXTREME, "Leaving addNote"); + } + // Setup queries for get to save time later + private void prepareQueries() { + if (getQueryWithContent == null) { + getQueryWithContent = new NSqlQuery(db.getConnection()); + if (!getQueryWithContent.prepare("Select " + +"guid, updateSequenceNumber, title, " + +"created, updated, deleted, active, notebookGuid, " + +"attributeSubjectDate, attributeLatitude, attributeLongitude, attributeAltitude, " + +"attributeAuthor, attributeSource, attributeSourceUrl, attributeSourceApplication, " + +"attributeContentClass, " + +"content, contentHash, contentLength" + +" from Note where guid=:guid and isExpunged=false")) { + logger.log(logger.EXTREME, "Note SQL select prepare with content has failed."); + logger.log(logger.MEDIUM, getQueryWithContent.lastError()); + } + } + + if (getQueryWithoutContent == null) { + getQueryWithoutContent = new NSqlQuery(db.getConnection()); + if (!getQueryWithoutContent.prepare("Select " + +"guid, updateSequenceNumber, title, " + +"created, updated, deleted, active, notebookGuid, " + +"attributeSubjectDate, attributeLatitude, attributeLongitude, attributeAltitude, " + +"attributeAuthor, attributeSource, attributeSourceUrl, attributeSourceApplication, " + +"attributeContentClass" + +" from Note where guid=:guid and isExpunged=false")) { + logger.log(logger.EXTREME, "Note SQL select prepare without content has failed."); + logger.log(logger.MEDIUM, getQueryWithoutContent.lastError()); + } + } + + if (getAllQueryWithoutContent == null) { + getAllQueryWithoutContent = new NSqlQuery(db.getConnection()); + + if (!getAllQueryWithoutContent.prepare("Select " + +"guid, updateSequenceNumber, title, " + +"created, updated, deleted, active, notebookGuid, " + +"attributeSubjectDate, attributeLatitude, attributeLongitude, attributeAltitude, " + +"attributeAuthor, attributeSource, attributeSourceUrl, attributeSourceApplication, " + +"attributeContentClass " + +" from Note where isExpunged = false")) { + logger.log(logger.EXTREME, "Note SQL select prepare without content has failed."); + logger.log(logger.MEDIUM, getQueryWithoutContent.lastError()); + } + } + } + + + // Get a note's content in blob format for index. + public String getNoteContentNoUTFConversion(String guid) { + NSqlQuery query = new NSqlQuery(db.getConnection()); + query.prepare("Select content from note where guid=:guid"); + query.bindValue(":guid", guid); + query.exec(); + query.next(); + return query.valueString(0); + } + // Get a note by Guid + public Note getNote(String noteGuid, boolean loadContent, boolean loadResources, boolean loadRecognition, boolean loadBinary, boolean loadTags) { + + // ICHANGED 自分のキーに変更 +// extractMetadata("otherKey:{values};kimaira792:{titleColor=fff;pinned=true;};finalKey:{values1);"); + if (noteGuid == null) + return null; + if (noteGuid.trim().equals("")) + return null; + + prepareQueries(); + NSqlQuery query; + if (loadContent) { + query = getQueryWithContent; + } else { + query = getQueryWithoutContent; + } + + query.bindValue(":guid", noteGuid); + if (!query.exec()) { + logger.log(logger.EXTREME, "Note SQL select exec has failed."); + logger.log(logger.MEDIUM, query.lastError()); + return null; + } + if (!query.next()) { + logger.log(logger.EXTREME, "SQL Retrieve failed for note guid " +noteGuid + " in getNote()"); + logger.log(logger.EXTREME, " -> " +query.lastError().toString()); + logger.log(logger.EXTREME, " -> " +query.lastError()); + return null; + } + Note n = mapNoteFromQuery(query, loadContent, loadResources, loadRecognition, loadBinary, loadTags); + n.setContent(fixCarriageReturn(n.getContent())); + n.getAttributes().setContentClassIsSet(false); + return n; + } + // Get a note by Guid + public Note mapNoteFromQuery(NSqlQuery query, boolean loadContent, boolean loadResources, boolean loadRecognition, boolean loadBinary, boolean loadTags) { + DateFormat indfm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S"); +// indfm = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy"); + + Note n = new Note(); + NoteAttributes na = new NoteAttributes(); + n.setAttributes(na); + + n.setGuid(query.valueString(0)); + n.setUpdateSequenceNum(new Integer(query.valueString(1))); + n.setTitle(query.valueString(2)); + + try { + n.setCreated(indfm.parse(query.valueString(3)).getTime()); + n.setUpdated(indfm.parse(query.valueString(4)).getTime()); + n.setDeleted(indfm.parse(query.valueString(5)).getTime()); + } catch (ParseException e) { + e.printStackTrace(); + } + + n.setActive(query.valueBoolean(6,true)); + n.setNotebookGuid(query.valueString(7)); + + try { + String attributeSubjectDate = query.valueString(8); + if (!attributeSubjectDate.equals("")) + na.setSubjectDate(indfm.parse(attributeSubjectDate).getTime()); + } catch (ParseException e) { + e.printStackTrace(); + } + na.setLatitude(new Float(query.valueString(9))); + na.setLongitude(new Float(query.valueString(10))); + na.setAltitude(new Float(query.valueString(11))); + na.setAuthor(query.valueString(12)); + na.setSource(query.valueString(13)); + na.setSourceURL(query.valueString(14)); + na.setSourceApplication(query.valueString(15)); + na.setContentClass(query.valueString(16)); + + if (loadTags) { + List tagGuids = noteTagsTable.getNoteTags(n.getGuid()); + List tagNames = new ArrayList(); + TagTable tagTable = db.getTagTable(); + for (int i=0; i 0) { + unicode = query.valueString(17); + //System.out.println(unicode); + //unicode = unicode.replace("<", "&_lt;"); + //unicode = codec.fromUnicode(StringEscapeUtils.unescapeHtml(unicode)).toString(); + //unicode = unicode.replace("&_lt;", "<"); + //System.out.println("************************"); + int j=1; + for (int i=buffer.indexOf("&#"); i != -1 && buffer.indexOf("&#", i)>0; i=buffer.indexOf("&#",i+1)) { + j = buffer.indexOf(";",i)+1; + if (i resources = noteResourceTable.getNoteResourcesRecognition(n.getGuid()); + n.setResources(resources); + } else { + // We need to merge the recognition resources with the note resources retrieved earlier + for (int i=0; i notes = getNotesByNotebook(notebookGuid); + for (int i=0; i guids = new ArrayList(); + List usns = new ArrayList(); + while (query.next()) { + guids.add(query.valueString(0)); + Integer usn = new Integer(query.valueString(1)); + usns.add(usn); + } + + for (int i=0; i getDirty() { + String guid; + Note tempNote; + List notes = new ArrayList(); + List index = new ArrayList(); + + boolean check; + NSqlQuery query = new NSqlQuery(db.getConnection()); + + check = query.exec("Select guid from Note where isDirty = true and isExpunged = false and notebookGuid not in (select guid from notebook where local = true or linked = true)"); + if (!check) + logger.log(logger.EXTREME, "Note SQL retrieve has failed: " +query.lastError().toString()); + + // Get a list of the notes + while (query.next()) { + guid = new String(); + guid = query.valueString(0); + index.add(guid); + } + + // Start getting notes + for (int i=0; i getDirtyLinkedNotes() { + String guid; + Note tempNote; + List notes = new ArrayList(); + List index = new ArrayList(); + + boolean check; + NSqlQuery query = new NSqlQuery(db.getConnection()); + + check = query.exec("Select guid from Note where isDirty = true and isExpunged = false and notebookGuid in (select guid from notebook where linked = true)"); + if (!check) + logger.log(logger.EXTREME, "Note SQL retrieve has failed: " +query.lastError().toString()); + + // Get a list of the notes + while (query.next()) { + guid = new String(); + guid = query.valueString(0); + index.add(guid); + } + + // Start getting notes + for (int i=0; i getDirtyLinked(String notebookGuid) { + String guid; + Note tempNote; + List notes = new ArrayList(); + List index = new ArrayList(); + + boolean check; + NSqlQuery query = new NSqlQuery(db.getConnection()); + + query.prepare("Select guid from Note where isDirty = true and isExpunged = false and notebookGuid=:notebookGuid"); + query.bindValue(":notebookGuid", notebookGuid); + check = query.exec(); + if (!check) + logger.log(logger.EXTREME, "Note SQL retrieve has failed getting dirty linked notes: " +query.lastError().toString()); + + // Get a list of the notes + while (query.next()) { + guid = new String(); + guid = query.valueString(0); + index.add(guid); + } + + // Start getting notes + for (int i=0; i getNotesByNotebook(String notebookGuid) { + List notes = new ArrayList(); + // IFIXED List index = new ArrayList(); + + boolean check; + NSqlQuery query = new NSqlQuery(db.getConnection()); + + check = query.prepare("Select guid from Note where notebookguid=:notebookguid"); + if (!check) + logger.log(logger.EXTREME, "Note SQL retrieve has failed: " +query.lastError().toString()); + query.bindValue(":notebookguid", notebookGuid); + query. exec(); + + // Get a list of the notes + while (query.next()) { + // IFIXED index.add(query.valueString(0)); + notes.add(query.valueString(0)); + } + + return notes; + } + // Get a list of notes that need to be updated + public boolean isNoteDirty(String guid) { + + boolean check; + NSqlQuery query = new NSqlQuery(db.getConnection()); + + check = query.prepare("Select guid from Note where isDirty = true and guid=:guid"); + query.bindValue(":guid", guid); + check = query.exec(); + if (!check) + logger.log(logger.EXTREME, "Note SQL retrieve has failed: " +query.lastError().toString()); + + boolean returnValue; + // Get a list of the notes + if (query.next()) + returnValue = true; + else + returnValue = false; + + return returnValue; + } + + // Reset the dirty bit + public void resetDirtyFlag(String guid) { + logger.log(logger.LOW, "Resetting dirty flag for " +guid); + NSqlQuery query = new NSqlQuery(db.getConnection()); + + query.prepare("Update note set isdirty=false where guid=:guid"); + query.bindValue(":guid", guid); + if (!query.exec()) + logger.log(logger.EXTREME, "Error resetting note dirty field."); + } + // Get all notes + public List getAllGuids() { + List notes = new ArrayList(); + + boolean check; + NSqlQuery query = new NSqlQuery(db.getConnection()); + + check = query.exec("Select guid from Note"); + if (!check) + logger.log(logger.EXTREME, "Notebook SQL retrieve has failed: "+query.lastError()); + + // Get a list of the notes + while (query.next()) { + notes.add(new String(query.valueString(0))); + } + return notes; + } + // Get all notes + public List getAllNotes() { + List notes = new ArrayList(); + prepareQueries(); + boolean check; + if (getAllQueryWithoutContent == null) + prepareQueries(); + NSqlQuery query = getAllQueryWithoutContent; + check = query.exec(); + if (!check) + logger.log(logger.EXTREME, "Notebook SQL retrieve has failed: "+query.lastError()); + // Get a list of the notes + while (query.next()) { + notes.add(mapNoteFromQuery(query, false, false, false, false, true)); + } + return notes; + } + // Count unindexed notes + public int getUnindexedCount() { + NSqlQuery query = new NSqlQuery(db.getConnection()); + query.exec("select count(*) from note where indexneeded=true and isExpunged = false"); + query.next(); + int returnValue = new Integer(query.valueString(0)); + return returnValue; + } + // Count unsynchronized notes + public int getDirtyCount() { + NSqlQuery query = new NSqlQuery(db.getConnection()); + query.exec("select count(guid) from note where isDirty=true and isExpunged = false"); + query.next(); + int returnValue = new Integer(query.valueString(0)); + logger.log(logger.LOW, "dirty count: " +returnValue); + //query.exec("select count(guid) from note where isDirty=true and Active = 0 and isExpunged = false"); + //query.next(); + //logger.log(logger.LOW, "dirty count (active only): " +query.valueString(0)); + //query.exec("Select count(guid) from Note where isDirty = true and isExpunged = false and notebookGuid not in (select guid from notebook where local = true or linked = true)"); + //query.next(); + //logger.log(logger.LOW, "dirty count (no l&l notebooks): " +query.valueString(0)); + //logger.log(logger.LOW, "Beginning stack trace"); + //logger.log(logger.LOW, Thread.currentThread().getStackTrace()); + + //logger.log(logger.LOW, "*************************"); + //logger.log(logger.LOW, "*** DIRTY RECORD DUMP ***"); + //logger.log(logger.LOW, "*************************"); + //List recs = getDirty(); + //for (int i=0; i"+a0+"
", "
 
"); + return note.replace("
", "
 
"); + } + + // Expunge notes that we don't want to synchronize + public List expungeIgnoreSynchronizedNotes(List notebooks, Listtags, List linked) { + + List noteGuids = new ArrayList(); + for (int i=0; i notes = findNotesByNotebook(notebooks.get(i)); + for (int j=0; j notes = findNotesByTag(tags.get(i)); + for (int j=0; j linkedTags = db.getTagTable().getTagsForNotebook(notebookGuid); + for (int j=0; j notes = findNotesByNotebook(notebookGuid); + for (int j=0; j findNotesByNotebook(String notebook) { + List values = new ArrayList(); + NSqlQuery query = new NSqlQuery(db.getConnection()); + query.prepare("Select guid from note where notebookguid=:notebook"); + + query.bindValue(":notebook", notebook); + query.exec(); + while (query.next()) { + values.add(query.valueString(0)); + } + return values; + } + + public List findNotesByTag(String tag) { + List values = new ArrayList(); + NSqlQuery query = new NSqlQuery(db.getConnection()); + query.prepare("Select distinct noteguid from notetags where tagguid=:tag"); + + query.bindValue(":tag", tag); + query.exec(); + while (query.next()) { + values.add(query.valueString(0)); + } + return values; + } + + // Find a note based upon its title. + public List> findNotesByTitle(String text) { + List> results = new ArrayList>(); + boolean check; + NSqlQuery query = new NSqlQuery(db.getConnection()); + + check = query.prepare("Select guid,title from Note where lower(title) like :title"); + if (!check) + logger.log(logger.EXTREME, "Note SQL prepare for search by title has failed: " +query.lastError().toString()); + + query.bindValue(":title", "%"+text.toLowerCase()+"%"); + query.exec(); + // Get a list of the notes + while (query.next()) { + Pair p = new Pair(); + p.setFirst(query.valueString(0)); + p.setSecond(query.valueString(1)); + results.add(p); + } + return results; + } + + + + //******************************************************************************** + //******************************************************************************** + //* Indexing Functions + //******************************************************************************** + //******************************************************************************** + // set/unset a note to be reindexed + public void setIndexNeeded(String guid, Boolean flag) { + NSqlQuery query = new NSqlQuery(db.getConnection()); + query.prepare("Update Note set indexNeeded=:flag where guid=:guid"); + + if (flag) + query.bindValue(":flag", 1); + else + query.bindValue(":flag", 0); + query.bindValue(":guid", guid); + if (!query.exec()) { + logger.log(logger.MEDIUM, "Note indexNeeded update failed."); + logger.log(logger.MEDIUM, query.lastError()); + } + List r = noteResourceTable.getNoteResources(guid, false); + for (int i=0; r!= null && i getUnindexed() { + String guid; + List index = new ArrayList(); + NSqlQuery query = new NSqlQuery(db.getConnection()); + + if (!query.exec("Select guid from Note where isExpunged = false and indexNeeded = true and DATEDIFF('MINUTE',updated,CURRENT_TIMESTAMP)>5")) + logger.log(logger.EXTREME, "Note SQL retrieve has failed on getUnindexed()."); + + // Get a list of the notes + while (query.next()) { + guid = new String(); + guid = query.valueString(0); + index.add(guid); + } + return index; + } + public List getNextUnindexed(int limit) { + List guids = new ArrayList(); + + NSqlQuery query = new NSqlQuery(db.getConnection()); + + if (!query.exec("Select guid from Note where isExpunged = false and indexNeeded = true and DATEDIFF('MINUTE',Updated,CURRENT_TIMESTAMP)>5 limit " +limit)) + logger.log(logger.EXTREME, "Note SQL retrieve has failed on getUnindexed()."); + + // Get a list of the notes + String guid; + while (query.next()) { + guid = new String(); + guid = query.valueString(0); + guids.add(guid); + } + return guids; + } + + + // Get note meta information + public void updateNoteMetadata(NoteMetadata meta) { + NSqlQuery query = new NSqlQuery(db.getConnection()); + if (!query.prepare("Update Note set titleColor=:color, pinned=:pinned, attributeSourceApplication=:metaString where guid=:guid")) + logger.log(logger.EXTREME, "Note SQL prepare has failed on updateNoteMetadata."); + query.bindValue(":color", meta.getColor()); + query.bindValue(":pinned", meta.isPinned()); + query.bindValue(":guid", meta.getGuid()); + query.bindValue(":metaString", buildMetadataString(meta)); + if (!query.exec()) + logger.log(logger.EXTREME, "Note SQL exec has failed on updateNoteMetadata."); + return; + } + + // Get all note meta information + public HashMap getNotesMetaInformation() { + HashMap returnValue = new HashMap(); + NSqlQuery query = new NSqlQuery(db.getConnection()); + + if (!query.exec("Select guid,titleColor, isDirty, pinned from Note")) + logger.log(logger.EXTREME, "Note SQL retrieve has failed on getNoteMetaInformation."); + + // Get a list of the notes + while (query.next()) { + NoteMetadata note = new NoteMetadata(); + note.setGuid(query.valueString(0)); + note.setColor(query.valueInteger(1)); + note.setDirty(query.valueBoolean(2, false)); + int pinned = query.valueInteger(3); + if (pinned > 0) + note.setPinned(true); + returnValue.put(note.getGuid(), note); + } + + return returnValue; + } + // Get note meta information + public NoteMetadata getNoteMetaInformation(String guid) { + NSqlQuery query = new NSqlQuery(db.getConnection()); + + if (!query.prepare("Select guid,titleColor, isDirty, pinned from Note where guid=:guid")) { + logger.log(logger.EXTREME, "Note SQL retrieve has failed on getNoteMetaInformation."); + return null; + } + query.bindValue(":guid", guid); + query.exec(); + + // Get a list of the notes + while (query.next()) { + NoteMetadata note = new NoteMetadata(); + note.setGuid(query.valueString(0)); + note.setColor(query.valueInteger(1)); + note.setDirty(query.valueBoolean(2, false)); + int pinned = query.valueInteger(3); + if (pinned > 0) + note.setPinned(true); + return note; + } + + return null; + } + + + //********************************************************************************** + //* Thumbnail functions + //********************************************************************************** + // Set if a new thumbnail is needed + public void setThumbnailNeeded(String guid, boolean needed) { + + boolean check; + NSqlQuery query = new NSqlQuery(db.getConnection()); + + check = query.prepare("Update note set thumbnailneeded = :needed where guid=:guid"); + query.bindValue(":guid", guid); + query.bindValue(":needed", needed); + check = query.exec(); + if (!check) + logger.log(logger.EXTREME, "Note SQL set thumbail needed failed: " +query.lastError().toString()); + + } + // Is a thumbail needed for this guid? + public boolean isThumbnailNeeded(String guid) { + + boolean check; + NSqlQuery query = new NSqlQuery(db.getConnection()); + + check = query.prepare("select thumbnailneeded from note where guid=:guid"); + query.bindValue(":guid", guid); + check = query.exec(); + if (!check) + logger.log(logger.EXTREME, "Note SQL isThumbnailNeeded query failed: " +query.lastError().toString()); + + boolean returnValue; + // Get a list of the notes + if (query.next()) + returnValue = query.valueBoolean(0, false); + else + returnValue = false; + + return returnValue; + } + // Set if a new thumbnail is needed + public void setThumbnail(String guid, QByteArray thumbnail) { + + boolean check; + NSqlQuery query = new NSqlQuery(db.getConnection()); + + check = query.prepare("Update note set thumbnail = :thumbnail where guid=:guid"); + query.bindValue(":guid", guid); + query.bindValue(":thumbnail", thumbnail.toByteArray()); + check = query.exec(); + if (!check) + logger.log(logger.EXTREME, "Note SQL set thumbail failed: " +query.lastError().toString()); + + } + // Set if a new thumbnail is needed + public QByteArray getThumbnail(String guid) { + + boolean check; + NSqlQuery query = new NSqlQuery(db.getConnection()); + + check = query.prepare("Select thumbnail from note where guid=:guid"); + query.bindValue(":guid", guid); + check = query.exec(); + if (!check) + logger.log(logger.EXTREME, "Note SQL get thumbail failed: " +query.lastError().toString()); + // Get a list of the notes + if (query.next()) { + try { + if (query.getBlob(0) != null) { + return new QByteArray(query.getBlob(0)); + } + } catch (java.lang.IllegalArgumentException e) { + return null; + } + } + return null; + } + // Get all thumbnails + public HashMap getThumbnails() { + boolean check; + NSqlQuery query = new NSqlQuery(db.getConnection()); + HashMap map = new HashMap(); + + check = query.prepare("Select guid,thumbnail from note where thumbnailneeded=false and isExpunged=false"); + check = query.exec(); + if (!check) + logger.log(logger.EXTREME, "Note SQL get thumbail failed: " +query.lastError().toString()); + // Get a list of the notes + while (query.next()) { + try { + if (query.getBlob(1) != null) { + QByteArray data = new QByteArray(query.getBlob(1)); + QPixmap img = new QPixmap(); + if (img.loadFromData(data)) { + img = img.scaled(Global.largeThumbnailSize); + map.put(query.valueString(0), img); + } + } + } catch (java.lang.IllegalArgumentException e) { + logger.log(logger.HIGH, "Error retrieving thumbnail " +e.getMessage()); + } + } + return map; + } + // Get a list of notes that need thumbnails + public List findThumbnailsNeeded() { + + boolean check; + NSqlQuery query = new NSqlQuery(db.getConnection()); + + check = query.prepare("select guid from note where thumbnailneeded=true and isExpunged=false and DATEDIFF('MINUTE',updated,CURRENT_TIMESTAMP)>5 limit 5"); + check = query.exec(); + if (!check) + logger.log(logger.EXTREME, "Note SQL findThumbnailsNeeded query failed: " +query.lastError().toString()); + + + // Get a list of the notes + List values = new ArrayList(); + while (query.next()) { + values.add(query.valueString(0)); + } + + return values; + } + // Get a count of thumbnails needed + public int getThumbnailNeededCount() { + + boolean check; + NSqlQuery query = new NSqlQuery(db.getConnection()); + + check = query.prepare("select count(guid) from note where thumbnailneeded=true and isExpunged=false and DATEDIFF('MINUTE',updated,CURRENT_TIMESTAMP)>5 limit 2"); + check = query.exec(); + if (!check) + logger.log(logger.EXTREME, "Note SQL findThumbnailNeededCount query failed: " +query.lastError().toString()); + + if (query.next()) { + return query.valueInteger(0); + } + + return 0; + } + + //*********************************************************************************** + public String findAlternateGuid(String guid) { + boolean check; + NSqlQuery query = new NSqlQuery(db.getConnection()); + + check = query.prepare("select guid from note where original_guid=:guid"); + query.bindValue(":guid", guid); + check = query.exec(); + if (!check) + logger.log(logger.EXTREME, "Note SQL findAlternateguid query failed: " +query.lastError().toString()); + + if (query.next()) { + return query.valueString(0); + } + + return null; + } + + //* Check if a note guid exists + public boolean guidExists(String guid) { + boolean check; + NSqlQuery query = new NSqlQuery(db.getConnection()); + + check = query.prepare("select guid from note where guid=:guid"); + query.bindValue(":guid", guid); + check = query.exec(); + if (!check) + logger.log(logger.EXTREME, "Note SQL guidExists query failed: " +query.lastError().toString()); + + if (query.next()) { + return true; + } + + return false; + } + + // Update a note content's hash. This happens if a resource is edited outside of NN + public void updateResourceContentHash(String guid, String oldHash, String newHash) { + Note n = getNote(guid, true, false, false, false,false); + int position = n.getContent().indexOf("-1;) { + endPos = n.getContent().indexOf(">", position+1); + String oldSegment = n.getContent().substring(position,endPos); + int hashPos = oldSegment.indexOf("hash=\""); + int hashEnd = oldSegment.indexOf("\"", hashPos+7); + String hash = oldSegment.substring(hashPos+6, hashEnd); + if (hash.equalsIgnoreCase(oldHash)) { + String newSegment = oldSegment.replace(oldHash, newHash); + String content = n.getContent().substring(0,position) + + newSegment + + n.getContent().substring(endPos); + NSqlQuery query = new NSqlQuery(db.getConnection()); + query.prepare("update note set isdirty=true, thumbnailneeded=true, content=:content where guid=:guid"); + query.bindValue(":content", content); + query.bindValue(":guid", n.getGuid()); + query.exec(); + } + + position = n.getContent().indexOf(" 0) + metaString = metaString.substring(0,endPos); + + String value = parseMetaString(metaString, "titleColor"); + if (value != null) + meta.setColor(Integer.parseInt(value)); + + value = parseMetaString(metaString, "pinned"); + if (value != null && value.equals(true)) + meta.setPinned(true); + + return meta; + } + + // Given a metadata string from attribute.sourceApplication, we + // extract the information for a given key. + private String parseMetaString(String metaString, String key) { + int startPos = metaString.indexOf(key); + if (startPos < 0) + return null; + + String value = metaString.substring(startPos+key.length()+1); + int endPos = value.indexOf(";"); + if (endPos > 0) + value = value.substring(0,endPos); + + return value; + } + + // Given a set of metadata, we build a string that can be inserted + // into the attribute.sourceApplication string. + private String buildMetadataString(NoteMetadata meta) { + StringBuffer value = new StringBuffer(removeExistingMetaString(meta.getGuid())); + StringBuffer metaString = new StringBuffer(); + + if (meta.isPinned()) { + metaString.append("pinned=true;"); + } + if (meta.getColor() != -1) { + metaString.append("titleColor=" +new Integer(meta.getColor()).toString()+";"); + } + if (metaString.length()>0) { + + // Adda any missing ";" or " " at the end of the existing + // string. + if (value.length()>1 && (!value.toString().trim().endsWith(";") || !value.toString().trim().endsWith(";"))) + value.append("; "); + + // ICHANGED 自分のキーに変更 + value.append("kimaira792:{"); + value.append(metaString); + value.append("};"); + return value.toString(); + } + return null; + } + + // This will remove the existing metadata string from the attribute.sourceApplication string. + private String removeExistingMetaString(String guid) { + NSqlQuery query = new NSqlQuery(db.getConnection()); + + if (!query.prepare("Select attributeSourceApplication from Note where guid=:guid")) { + logger.log(logger.EXTREME, "Note SQL retrieve has failed in removeExistingMetaString."); + return null; + } + query.bindValue(":guid", guid); + query.exec(); + + // Get the application source string + String sourceApplication = null; + while (query.next()) { + sourceApplication = query.valueString(0); + } + if (sourceApplication == null) + return ""; + + // ICHANGED 自分のキーに変更 + String consumerKey = "kimaira792:{"; + int startPos = sourceApplication.indexOf(consumerKey); + if (startPos < 0 ) + return sourceApplication; + String startString = sourceApplication.substring(0,startPos); + String metaString = sourceApplication.substring(startPos); + String endString = metaString.substring(metaString.indexOf("};")+2); + + return startString+endString; + } + public void dumpDirtyNotes() { logger.log(logger.LOW, "Dirty Notes: "); List noteList = this.getDirty(); for (int i=0; i " + query.lastError().toString()); + logger.log(logger.EXTREME, " -> " + query.lastError()); + return null; + } + + String noteTitle = query.valueString(0); + + return noteTitle; + } + + /* + * // ICHANGED // ノートがアクティブかどうか調べる public boolean isNoteActive(String guid){ + * if(guid == null) return false; if(guid.trim().equals("")) return false; + * + * NSqlQuery query = new NSqlQuery(db.getConnection()); + * query.prepare("Select active from Note where guid=:guid"); + * query.bindValue(":guid", guid); if(!query.exec()){ + * logger.log(logger.EXTREME, "note.isNoteActive SQL retrieve has failed."); + * return false; } if(!query.next()){ logger.log(logger.EXTREME, + * "SQL Retrieve failed for note guid " +guid + " in isNoteActive()"); + * return false; } + * + * boolean retVal = query.valueBoolean(0, false); return retVal; } + */ + +} + + + + + diff --git a/src/cx/fbn/nevernote/sql/StaredTable.java b/src/cx/fbn/nevernote/sql/StaredTable.java new file mode 100644 index 0000000..0a1f940 --- /dev/null +++ b/src/cx/fbn/nevernote/sql/StaredTable.java @@ -0,0 +1,172 @@ +/* + * クラスを現在作成中。インスタンスの生成および呼び出し部分は未着手。 + */ + +package cx.fbn.nevernote.sql; + +import cx.fbn.nevernote.sql.driver.NSqlQuery; +import cx.fbn.nevernote.utilities.ApplicationLogger; + +public class StaredTable { + private final ApplicationLogger logger; + private final DatabaseConnection db; + + // コンストラクタ + public StaredTable(ApplicationLogger l, DatabaseConnection d) { + logger = l; + db = d; + } + + // テーブル作成 + public void createTable() { + NSqlQuery query = new NSqlQuery(db.getBehaviorConnection()); + logger.log(logger.HIGH, "StaredNotesテーブルを作成しています..."); + if (!query.exec("Create table StaredNotes (id integer primary key auto_increment, masterGuid varchar, staredGuid varchar)")) + logger.log(logger.HIGH, "StaredNotesテーブル作成失敗!!!"); + } + + // テーブルをドロップ + public void dropTable() { + NSqlQuery query = new NSqlQuery(db.getBehaviorConnection()); + query.exec("Drop table StaredNotes"); + } + + // StaredNotesテーブルにアイテムを1つ追加 + public void addStaredItem(String masterGuid, String staredGuid) { + NSqlQuery query = new NSqlQuery(db.getBehaviorConnection()); + query.prepare("Insert Into StaredNotes (masterGuid, staredGuid) Values(:masterGuid, :staredGuid)"); + query.bindValue(":masterGuid", masterGuid); + query.bindValue(":staredGuid", staredGuid); + if (!query.exec()) { + logger.log(logger.MEDIUM, "StaredNotesテーブルへのアイテム追加に失敗"); + logger.log(logger.MEDIUM, query.lastError()); + } + } + + // StaredNotesテーブルからアイテムを1つ削除 + public void removeStaredItem(String masterGuid, String staredGuid) { + NSqlQuery query = new NSqlQuery(db.getBehaviorConnection()); + query.prepare("Delete from StaredNotes where (masterGuid=:masterGuid and staredGuid=:staredGuid)"); + query.bindValue(":masterGuid", masterGuid); + query.bindValue(":staredGuid", staredGuid); + if (!query.exec()) { + logger.log(logger.MEDIUM, "StaredNotesテーブルからのアイテム削除に失敗"); + logger.log(logger.MEDIUM, query.lastError()); + } + } + + // guidを含む列をStaredNotesテーブルから削除 + public void expungeStaredNote(String guid) { + NSqlQuery query = new NSqlQuery(db.getBehaviorConnection()); + boolean check; + + query.prepare("Delete from StaredNotes where masterGuid=:masterGuid or staredGuid=:staredGuid"); + query.bindValue(":masterGuid", guid); + query.bindValue(":staredGuid", guid); + + check = query.exec(); + if(!check){ + logger.log(logger.MEDIUM, "StaredNotesテーブルからguid=" + guid + "のデータ削除に失敗"); + logger.log(logger.MEDIUM, query.lastError()); + } + } + + // masterGuidとchildGuidをマージ + public void mergeHistoryGuid(String masterGuid, String childGuid) { + NSqlQuery staredNotesQuery = new NSqlQuery(db.getBehaviorConnection()); + boolean check = false; + + // マージ後に重複してしまうデータを先に削除 + staredNotesQuery.prepare("Delete from StaredNotes where (masterGuid=:masterGuid1 and staredGuid=:staredGuid1) or (masterGuid=:masterGuid2 and staredGuid=:staredGuid2)"); + staredNotesQuery.bindValue(":masterGuid1", masterGuid); + staredNotesQuery.bindValue(":childGuid1", childGuid); + staredNotesQuery.bindValue(":masterGuid2", childGuid); + staredNotesQuery.bindValue(":staredGuid2", masterGuid); + check = staredNotesQuery.exec(); + if(!check){ + logger.log(logger.MEDIUM, "staredNotesテーブルの重複削除で失敗"); + logger.log(logger.MEDIUM, staredNotesQuery.lastError()); + } + + updateStaredNoteGuid(masterGuid, childGuid); + } + + // StaredNotesテーブルのGuidを更新 + public void updateStaredNoteGuid(String newGuid, String oldGuid){ + NSqlQuery staredNotesQuery = new NSqlQuery(db.getBehaviorConnection()); + boolean check = false; + + staredNotesQuery.prepare("Update StaredNotes set masterGuid=:newGuid where masterGuid=:oldGuid"); + staredNotesQuery.bindValue(":newGuid", newGuid); + staredNotesQuery.bindValue(":oldGuid", oldGuid); + check = staredNotesQuery.exec(); + if (!check) { + logger.log(logger.MEDIUM, "StaredNotesテーブルのmasterGuidのところでguid更新失敗"); + logger.log(logger.MEDIUM, staredNotesQuery.lastError()); + } + staredNotesQuery.prepare("Update StaredNotes set staredGuid=:newGuid where staredGuid=:oldGuid"); + staredNotesQuery.bindValue(":newGuid", newGuid); + staredNotesQuery.bindValue(":oldGuid", oldGuid); + check = staredNotesQuery.exec(); + if (!check) { + logger.log(logger.MEDIUM, "StaredNotesテーブルのstaredGuidのところでguid更新失敗"); + logger.log(logger.MEDIUM, staredNotesQuery.lastError()); + } + } + + // StaredNotesテーブルに引数guidのノートが存在するか + public boolean existNote(String masterGuid, String staredGuid) { + NSqlQuery staredNotesQuery = new NSqlQuery(db.getBehaviorConnection()); + + // 2つの引数guidを含むアイテムの存在確認 + staredNotesQuery.prepare("Select * from StaredNotes where Exists(Select * from StaredNotes where (masterGuid=:masterGuid1 and staredGuid=:staredGuid1) or (masterGuid=:masterGuid2 and staredGuid=:staredGuid2))"); + staredNotesQuery.bindValue(":masterGuid1", masterGuid); + staredNotesQuery.bindValue(":staredGuid1", staredGuid); + staredNotesQuery.bindValue(":masterGuid2", masterGuid); + staredNotesQuery.bindValue(":staredGuid2", staredGuid); + + if (!staredNotesQuery.exec()) { + logger.log(logger.MEDIUM, "StaredNotesテーブルからmasterGuid=" + masterGuid + "かつstaredGuid=" + staredGuid + "(またはその逆)のアイテムの存在確認失敗"); + logger.log(logger.MEDIUM, staredNotesQuery.lastError()); + } + + if (staredNotesQuery.next()) { + return true; + } + + return false; + } + + // oldGuidのノートの除外ノートをnewGuidのノートの除外ノートとして複製 + public void duplicateStaredNotes(String newGuid, String oldGuid) { + NSqlQuery staredNotesQuery = new NSqlQuery(db.getBehaviorConnection()); + + // masterGuid = oldGuidのスター付きノートを取得 + staredNotesQuery.prepare("Select staredGuid from StaredNotes where masterGuid=:oldGuid"); + staredNotesQuery.bindValue(":oldGuid", oldGuid); + if(!staredNotesQuery.exec()){ + logger.log(logger.MEDIUM, "StaredNotesテーブルからmasterGuid=" + oldGuid + "のアイテム取得失敗"); + logger.log(logger.MEDIUM, staredNotesQuery.lastError()); + } + // masterGuid = newGuidのスター付きノートとして複製 + while(staredNotesQuery.next()){ + String staredGuid = staredNotesQuery.valueString(0); + + addStaredItem(newGuid, staredGuid); + } + + // staredGuid = oldGuidの除外ノートを取得 + staredNotesQuery.prepare("Select masterGuid from StaredNotes where staredGuid=:oldGuid"); + staredNotesQuery.bindValue(":oldGuid", oldGuid); + if(!staredNotesQuery.exec()){ + logger.log(logger.MEDIUM, "StaredNotesテーブルからstaredGuid=" + oldGuid + "のアイテム取得失敗"); + logger.log(logger.MEDIUM, staredNotesQuery.lastError()); + } + // staredGuid = newGuidの除外ノートとして複製 + while(staredNotesQuery.next()){ + String masterGuid = staredNotesQuery.valueString(0); + + addStaredItem(masterGuid, newGuid); + } + } +} diff --git a/src/cx/fbn/nevernote/threads/CounterRunner.java b/src/cx/fbn/nevernote/threads/CounterRunner.java index dc1fb57..d2cdcfe 100644 --- a/src/cx/fbn/nevernote/threads/CounterRunner.java +++ b/src/cx/fbn/nevernote/threads/CounterRunner.java @@ -1,320 +1,323 @@ -/* - * This file is part of NixNote - * Copyright 2009 Randy Baumgarte - * - * This file may be licensed under the terms of of the - * GNU General Public License Version 2 (the ``GPL''). - * - * Software distributed under the License is distributed - * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either - * express or implied. See the GPL for the specific language - * governing rights and limitations. - * - * You should have received a copy of the GPL along with this - * program. If not, go to http://www.gnu.org/licenses/gpl.html - * or write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * -*/ - -package cx.fbn.nevernote.threads; - -import java.util.ArrayList; -import java.util.List; -import java.util.Vector; -import java.util.concurrent.LinkedBlockingQueue; - -import com.evernote.edam.type.Note; -import com.trolltech.qt.core.QMutex; -import com.trolltech.qt.core.QObject; - -import cx.fbn.nevernote.filters.NotebookCounter; -import cx.fbn.nevernote.filters.TagCounter; -import cx.fbn.nevernote.signals.NotebookSignal; -import cx.fbn.nevernote.signals.TagSignal; -import cx.fbn.nevernote.signals.TrashSignal; -import cx.fbn.nevernote.sql.DatabaseConnection; -import cx.fbn.nevernote.utilities.ApplicationLogger; - -public class CounterRunner extends QObject implements Runnable { - - private class NoteRecord { - public String notebookGuid; - public Vector tags; - public boolean active; - - public NoteRecord() { - tags = new Vector(); - } - } - private final ApplicationLogger logger; - private volatile boolean keepRunning; - public int ID; - public volatile NotebookSignal notebookSignal; - public volatile TrashSignal trashSignal; - public volatile TagSignal tagSignal; - private volatile Vector records; - public int type; - public QMutex threadLock; - - public static int EXIT=0; - public static int NOTEBOOK=1; - public static int TAG=2; - public static int TRASH=3; - - public boolean ready = false; - public boolean abortCount = false; - private final DatabaseConnection conn; - - private volatile LinkedBlockingQueue readyQueue = new LinkedBlockingQueue(); - - - //********************************************* - //* Constructor * - //********************************************* - public CounterRunner(String logname, int t, String u, String i, String r, String uid, String pswd, String cpswd) { - type = t; - - threadLock = new QMutex(); - logger = new ApplicationLogger(logname); -// setAutoDelete(false); - conn = new DatabaseConnection(logger, u, i, r, uid, pswd, cpswd, 300); - keepRunning = true; - notebookSignal = new NotebookSignal(); - tagSignal = new TagSignal(); - trashSignal = new TrashSignal(); - - records = new Vector(); - } - - - - //********************************************* - //* Run unit * - //********************************************* - @Override - public void run() { - boolean keepRunning = true; - - thread().setPriority(Thread.MIN_PRIORITY); - while(keepRunning) { - ready = true; - try { - - type = readyQueue.take(); - threadLock.lock(); - if (type == EXIT) - keepRunning = false; - if (type == NOTEBOOK) - countNotebookResults(); - if (type == TAG) - countTagResults(); - if (type == TRASH) - countTrashResults(); - threadLock.unlock(); - } catch (InterruptedException e) {} - } - conn.dbShutdown(); - } - - - - public void setNoteIndex(List idx) { - abortCount = true; - threadLock.lock(); - abortCount = false; - records.clear(); - if (idx != null) { - for (int i=0; i nCounter = new ArrayList(); - for (int i=0; i counter = new ArrayList(); - List allTags = conn.getTagTable().getAll(); - - if (abortCount) - return; - if (allTags == null) - return; - for (int k=0; k> tagCounts = conn.getNoteTable().noteTagsTable.getTagCounts(); - if (abortCount) - return; - for (int i=0; tagCounts != null && i tags = conn.getNoteTable().noteTagsTable.getAllNoteTags(); - for (int i=noteIndex.size()-1; i>=0; i--) { - if (abortCount) - return; - String note = noteIndex.get(i); - for (int x=0; tags!= null && x tCounter = new ArrayList(); - for (int i=0; i tags = records.get(i).tags; - for (int z=0; z tags; + public boolean active; + + public NoteRecord() { + tags = new Vector(); + } + } + private final ApplicationLogger logger; + private volatile boolean keepRunning; + public int ID; + public volatile NotebookSignal notebookSignal; + public volatile TrashSignal trashSignal; + public volatile TagSignal tagSignal; + private volatile Vector records; + public int type; + public QMutex threadLock; + + public static int EXIT=0; + public static int NOTEBOOK=1; + public static int TAG=2; + public static int TRASH=3; + + public boolean ready = false; + public boolean abortCount = false; + private final DatabaseConnection conn; + + private volatile LinkedBlockingQueue readyQueue = new LinkedBlockingQueue(); + + + //********************************************* + //* Constructor * + //********************************************* + // ICHANGED String bを追加 + public CounterRunner(String logname, int t, String u, String i, String r, String b, String uid, String pswd, String cpswd) { + type = t; + + threadLock = new QMutex(); + logger = new ApplicationLogger(logname); +// setAutoDelete(false); + // ICHANGED bを追加 + conn = new DatabaseConnection(logger, u, i, r, b, uid, pswd, cpswd, 300); + + keepRunning = true; + notebookSignal = new NotebookSignal(); + tagSignal = new TagSignal(); + trashSignal = new TrashSignal(); + + records = new Vector(); + } + + + + //********************************************* + //* Run unit * + //********************************************* + @Override + public void run() { + boolean keepRunning = true; + + thread().setPriority(Thread.MIN_PRIORITY); + while(keepRunning) { + ready = true; + try { + + type = readyQueue.take(); + threadLock.lock(); + if (type == EXIT) + keepRunning = false; + if (type == NOTEBOOK) + countNotebookResults(); + if (type == TAG) + countTagResults(); + if (type == TRASH) + countTrashResults(); + threadLock.unlock(); + } catch (InterruptedException e) {} + } + conn.dbShutdown(); + } + + + + public void setNoteIndex(List idx) { + abortCount = true; + threadLock.lock(); + abortCount = false; + records.clear(); + if (idx != null) { + for (int i=0; i nCounter = new ArrayList(); + for (int i=0; i counter = new ArrayList(); + List allTags = conn.getTagTable().getAll(); + + if (abortCount) + return; + if (allTags == null) + return; + for (int k=0; k> tagCounts = conn.getNoteTable().noteTagsTable.getTagCounts(); + if (abortCount) + return; + for (int i=0; tagCounts != null && i tags = conn.getNoteTable().noteTagsTable.getAllNoteTags(); + for (int i=noteIndex.size()-1; i>=0; i--) { + if (abortCount) + return; + String note = noteIndex.get(i); + for (int x=0; tags!= null && x tCounter = new ArrayList(); + for (int i=0; i tags = records.get(i).tags; + for (int z=0; z workQueue; - private static int MAX_QUEUED_WAITING = 1000; - public boolean interrupt; - public boolean idle; - public boolean indexAttachmentsLocally = true; - public volatile IndexSignal signal; - private final TreeSet foundWords; - int uncommittedCount = 0; - - - public IndexRunner(String logname, String u, String i, String r, String uid, String pswd, String cpswd) { - foundWords = new TreeSet(); - logger = new ApplicationLogger(logname); - conn = new DatabaseConnection(logger, u, i, r, uid, pswd, cpswd, 500); - indexType = SCAN; - guid = null; - keepRunning = true; - doc = new QDomDocument(); - workQueue=new LinkedBlockingQueue(MAX_QUEUED_WAITING); - } - - public void setIndexType(int t) { - indexType = t; - } - - - @Override - public void run() { - thread().setPriority(Thread.MIN_PRIORITY); - noteSignal = new NoteSignal(); - resourceSignal = new NoteResourceSignal(); - signal = new IndexSignal(); - logger.log(logger.EXTREME, "Starting index thread "); - while (keepRunning) { - idle=true; - try { - conn.commitTransaction(); - uncommittedCount = 0; - String work = workQueue.take(); - idle=false; - if (work.startsWith("SCAN")) { - guid=null; - interrupt = false; - indexType = SCAN; - } - if (work.startsWith("REINDEXALL")) { - guid = null; - indexType=REINDEXALL; - } - if (work.startsWith("REINDEXNOTE")) { - work = work.replace("REINDEXNOTE ", ""); - guid = work; - indexType = REINDEXNOTE; - } - if (work.startsWith("STOP")) { - keepRunning = false; - guid = null; - } - logger.log(logger.EXTREME, "Type:" +indexType); - if (indexType == SCAN && keepRunning) { - logger.log(logger.MEDIUM, "Scanning for unindexed notes & resources"); - scanUnindexed(); - setIndexType(0); - } - if (indexType == REINDEXALL && keepRunning) { - logger.log(logger.MEDIUM, "Marking all for reindex"); - reindexAll(); - setIndexType(0); - } - if (indexType == REINDEXNOTE && keepRunning) { - reindexNote(); - } - } catch (InterruptedException e) { - logger.log(logger.LOW, "Thread interrupted exception: " +e.getMessage()); - } - } - logger.log(logger.EXTREME, "Shutting down database"); - conn.dbShutdown(); - logger.log(logger.EXTREME, "Database shut down. Exiting thread"); - } - - // Reindex a note - public void indexNoteContent() { - foundWords.clear(); - - logger.log(logger.EXTREME, "Entering indexRunner.indexNoteContent()"); - - logger.log(logger.EXTREME, "Getting note content"); - Note n = conn.getNoteTable().getNote(guid,true,false,true,true, true); - String data; - if (indexNoteBody) { - data = n.getContent(); - data = conn.getNoteTable().getNoteContentNoUTFConversion(n.getGuid()); - - logger.log(logger.EXTREME, "Removing any encrypted data"); - data = removeEnCrypt(data.toString()); - logger.log(logger.EXTREME, "Removing xml markups"); - } else - data = ""; - String text; - if (indexNoteTitle) - text = removeTags(StringEscapeUtils.unescapeHtml4(data) +" "+ n.getTitle()); - else - text = removeTags(StringEscapeUtils.unescapeHtml4(data)); - - logger.log(logger.EXTREME, "Splitting words"); - String[] result = text.toString().split(regex); - conn.commitTransaction(); - conn.beginTransaction(); - logger.log(logger.EXTREME, "Deleting existing words for note from index"); - conn.getWordsTable().expungeFromWordIndex(guid, "CONTENT"); - - logger.log(logger.EXTREME, "Number of words found: " +result.length); - for (int j=0; j=0; i--) { - if (buffer.charAt(i) == '>') - inTag = true; - if (buffer.charAt(i) == '<') - inTag = false; - if (inTag || buffer.charAt(i) == '<') - buffer.deleteCharAt(i); - } - - return buffer.toString(); - } - - - public synchronized boolean addWork(String request) { - if (workQueue.size() == 0) { - workQueue.offer(request); - return true; - } - return false; - } - - public synchronized int getWorkQueueSize() { - return workQueue.size(); - } - - public void indexResource() { - - if (guid == null) - return; - foundWords.clear(); - Resource r = conn.getNoteTable().noteResourceTable.getNoteResourceRecognition(guid); - if (!indexImageRecognition || - r == null || r.getRecognition() == null || - r.getRecognition().getBody() == null || - r.getRecognition().getBody().length == 0) - resourceBinary = new QByteArray(" "); - else - resourceBinary = new QByteArray(r.getRecognition().getBody()); - - conn.commitTransaction(); - conn.beginTransaction(); - conn.getWordsTable().expungeFromWordIndex(r.getNoteGuid(), "RESOURCE"); - // This is due to an old bug & can be removed at some point in the future 11/23/2010 - conn.getWordsTable().expungeFromWordIndex(guid, "RESOURCE"); - conn.commitTransaction(); - uncommittedCount = 0; - conn.beginTransaction(); - - doc.setContent(resourceBinary); - QDomElement docElem = doc.documentElement(); - - // look for text tags - QDomNodeList anchors = docElem.elementsByTagName("t"); - for (int i=0; i 100) { - conn.commitTransaction(); - uncommittedCount=0; - } - } - } - - if (Global.keepRunning && indexAttachmentsLocally) { - conn.commitTransaction(); - uncommittedCount = 0; - conn.beginTransaction(); - indexResourceContent(guid); - } - - if (Global.keepRunning) - conn.getNoteTable().noteResourceTable.setIndexNeeded(guid,false); - conn.commitTransaction(); - uncommittedCount = 0; - } - - private void indexResourceContent(String guid) { - Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true); - if (r != null && r.getMime() != null) { - if (r.getMime().equalsIgnoreCase("application/pdf")) { - indexResourcePDF(r); - return; - } - if (r.getMime().equalsIgnoreCase("application/docx") || - r.getMime().equalsIgnoreCase("application/xlsx") || - r.getMime().equalsIgnoreCase("application/pptx")) { - indexResourceOOXML(r); - return; - } - if (r.getMime().equalsIgnoreCase("application/vsd") || - r.getMime().equalsIgnoreCase("application/ppt") || - r.getMime().equalsIgnoreCase("application/xls") || - r.getMime().equalsIgnoreCase("application/msg") || - r.getMime().equalsIgnoreCase("application/doc")) { - indexResourceOffice(r); - return; - } - if (r.getMime().equalsIgnoreCase("application/rtf")) { - indexResourceRTF(r); - return; - } - if (r.getMime().equalsIgnoreCase("application/odf") || - r.getMime().equalsIgnoreCase("application/odt") || - r.getMime().equalsIgnoreCase("application/odp") || - r.getMime().equalsIgnoreCase("application/odg") || - r.getMime().equalsIgnoreCase("application/odb") || - r.getMime().equalsIgnoreCase("application/ods")) { - indexResourceODF(r); - return; - } - } - } - - - private void indexResourceRTF(Resource r) { - - Data d = r.getData(); - for (int i=0; i<20 && d.getSize() == 0; i++) - d = r.getData(); - if (d.getSize()== 0) - return; - - QTemporaryFile f = writeResource(d); - if (!keepRunning) { - return; - } - - InputStream input; - try { - input = new FileInputStream(new File(f.fileName())); - ContentHandler textHandler = new BodyContentHandler(-1); - Metadata metadata = new Metadata(); - RTFParser parser = new RTFParser(); - ParseContext context = new ParseContext(); - parser.parse(input, textHandler, metadata, context); - String[] result = textHandler.toString().split(regex); - for (int i=0; i", index)+11; - if (endPos > -1 && index > -1) { - content = content.substring(0,index)+content.substring(endPos); - index = content.indexOf("=0; i--) { - if (!Character.isLetterOrDigit(buffer.charAt(i)) && specialIndexCharacters.indexOf(buffer.charAt(i)) == -1) - buffer.deleteCharAt(i); - else - break; - } - buffer = buffer.reverse(); - for (int i=buffer.length()-1; i>=0; i--) { - if (!Character.isLetterOrDigit(buffer.charAt(i))) - buffer.deleteCharAt(i); - else - break; - } - buffer = buffer.reverse(); - if (buffer.length() > 0) { - // We have a good word, now let's trim off junk at the beginning or end - if (!foundWords.contains(buffer.toString())) { - foundWords.add(buffer.toString()); - foundWords.add(word); - conn.getWordsTable().addWordToNoteIndex(guid, buffer.toString(), type, 100); - uncommittedCount++; - if (uncommittedCount > 100) { - conn.commitTransaction(); - uncommittedCount=0; - } - } - } - return; - } - - private void scanUnindexed() { - List notes = conn.getNoteTable().getUnindexed(); - guid = null; - boolean started = false; - if (notes.size() > 0) { - signal.indexStarted.emit(); - started = true; - } - for (int i=0; i unindexedResources = conn.getNoteTable().noteResourceTable.getUnindexed(); - if (unindexedResources.size() > 0 && !started) { - signal.indexStarted.emit(); - started = true; - } - for (int i=0; i guids = conn.getWordsTable().getGuidList(); - logger.log(logger.LOW, "GUIDS in index: " +guids.size()); - for (int i=0; i workQueue; + private static int MAX_QUEUED_WAITING = 1000; + public boolean interrupt; + public boolean idle; + public boolean indexAttachmentsLocally = true; + public volatile IndexSignal signal; + private final TreeSet foundWords; + int uncommittedCount = 0; + + // ICHANGED String bを追加 + public IndexRunner(String logname, String u, String i, String r, String b, String uid, String pswd, String cpswd) { + foundWords = new TreeSet(); + logger = new ApplicationLogger(logname); + // ICHANGED bを追加 + conn = new DatabaseConnection(logger, u, i, r, b, uid, pswd, cpswd, 500); + indexType = SCAN; + guid = null; + keepRunning = true; + doc = new QDomDocument(); + workQueue=new LinkedBlockingQueue(MAX_QUEUED_WAITING); + } + + public void setIndexType(int t) { + indexType = t; + } + + + @Override + public void run() { + thread().setPriority(Thread.MIN_PRIORITY); + noteSignal = new NoteSignal(); + resourceSignal = new NoteResourceSignal(); + signal = new IndexSignal(); + logger.log(logger.EXTREME, "Starting index thread "); + while (keepRunning) { + idle=true; + try { + conn.commitTransaction(); + uncommittedCount = 0; + String work = workQueue.take(); + idle=false; + if (work.startsWith("SCAN")) { + guid=null; + interrupt = false; + indexType = SCAN; + } + if (work.startsWith("REINDEXALL")) { + guid = null; + indexType=REINDEXALL; + } + if (work.startsWith("REINDEXNOTE")) { + work = work.replace("REINDEXNOTE ", ""); + guid = work; + indexType = REINDEXNOTE; + } + if (work.startsWith("STOP")) { + keepRunning = false; + guid = null; + } + logger.log(logger.EXTREME, "Type:" +indexType); + if (indexType == SCAN && keepRunning) { + logger.log(logger.MEDIUM, "Scanning for unindexed notes & resources"); + scanUnindexed(); + setIndexType(0); + } + if (indexType == REINDEXALL && keepRunning) { + logger.log(logger.MEDIUM, "Marking all for reindex"); + reindexAll(); + setIndexType(0); + } + if (indexType == REINDEXNOTE && keepRunning) { + reindexNote(); + } + } catch (InterruptedException e) { + logger.log(logger.LOW, "Thread interrupted exception: " +e.getMessage()); + } + } + logger.log(logger.EXTREME, "Shutting down database"); + conn.dbShutdown(); + logger.log(logger.EXTREME, "Database shut down. Exiting thread"); + } + + // Reindex a note + public void indexNoteContent() { + foundWords.clear(); + + logger.log(logger.EXTREME, "Entering indexRunner.indexNoteContent()"); + + logger.log(logger.EXTREME, "Getting note content"); + Note n = conn.getNoteTable().getNote(guid,true,false,true,true, true); + String data; + if (indexNoteBody) { + data = n.getContent(); + data = conn.getNoteTable().getNoteContentNoUTFConversion(n.getGuid()); + + logger.log(logger.EXTREME, "Removing any encrypted data"); + data = removeEnCrypt(data.toString()); + logger.log(logger.EXTREME, "Removing xml markups"); + } else + data = ""; + String text; + if (indexNoteTitle) + text = removeTags(StringEscapeUtils.unescapeHtml4(data) +" "+ n.getTitle()); + else + text = removeTags(StringEscapeUtils.unescapeHtml4(data)); + + logger.log(logger.EXTREME, "Splitting words"); + String[] result = text.toString().split(regex); + conn.commitTransaction(); + conn.beginTransaction(); + logger.log(logger.EXTREME, "Deleting existing words for note from index"); + conn.getWordsTable().expungeFromWordIndex(guid, "CONTENT"); + + logger.log(logger.EXTREME, "Number of words found: " +result.length); + for (int j=0; j=0; i--) { + if (buffer.charAt(i) == '>') + inTag = true; + if (buffer.charAt(i) == '<') + inTag = false; + if (inTag || buffer.charAt(i) == '<') + buffer.deleteCharAt(i); + } + + return buffer.toString(); + } + + + public synchronized boolean addWork(String request) { + if (workQueue.size() == 0) { + workQueue.offer(request); + return true; + } + return false; + } + + public synchronized int getWorkQueueSize() { + return workQueue.size(); + } + + public void indexResource() { + + if (guid == null) + return; + foundWords.clear(); + Resource r = conn.getNoteTable().noteResourceTable.getNoteResourceRecognition(guid); + if (!indexImageRecognition || + r == null || r.getRecognition() == null || + r.getRecognition().getBody() == null || + r.getRecognition().getBody().length == 0) + resourceBinary = new QByteArray(" "); + else + resourceBinary = new QByteArray(r.getRecognition().getBody()); + + conn.commitTransaction(); + conn.beginTransaction(); + conn.getWordsTable().expungeFromWordIndex(r.getNoteGuid(), "RESOURCE"); + // This is due to an old bug & can be removed at some point in the future 11/23/2010 + conn.getWordsTable().expungeFromWordIndex(guid, "RESOURCE"); + conn.commitTransaction(); + uncommittedCount = 0; + conn.beginTransaction(); + + doc.setContent(resourceBinary); + QDomElement docElem = doc.documentElement(); + + // look for text tags + QDomNodeList anchors = docElem.elementsByTagName("t"); + for (int i=0; i 100) { + conn.commitTransaction(); + uncommittedCount=0; + } + } + } + + if (Global.keepRunning && indexAttachmentsLocally) { + conn.commitTransaction(); + uncommittedCount = 0; + conn.beginTransaction(); + indexResourceContent(guid); + } + + if (Global.keepRunning) + conn.getNoteTable().noteResourceTable.setIndexNeeded(guid,false); + conn.commitTransaction(); + uncommittedCount = 0; + } + + private void indexResourceContent(String guid) { + Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true); + if (r != null && r.getMime() != null) { + if (r.getMime().equalsIgnoreCase("application/pdf")) { + indexResourcePDF(r); + return; + } + if (r.getMime().equalsIgnoreCase("application/docx") || + r.getMime().equalsIgnoreCase("application/xlsx") || + r.getMime().equalsIgnoreCase("application/pptx")) { + indexResourceOOXML(r); + return; + } + if (r.getMime().equalsIgnoreCase("application/vsd") || + r.getMime().equalsIgnoreCase("application/ppt") || + r.getMime().equalsIgnoreCase("application/xls") || + r.getMime().equalsIgnoreCase("application/msg") || + r.getMime().equalsIgnoreCase("application/doc")) { + indexResourceOffice(r); + return; + } + if (r.getMime().equalsIgnoreCase("application/rtf")) { + indexResourceRTF(r); + return; + } + if (r.getMime().equalsIgnoreCase("application/odf") || + r.getMime().equalsIgnoreCase("application/odt") || + r.getMime().equalsIgnoreCase("application/odp") || + r.getMime().equalsIgnoreCase("application/odg") || + r.getMime().equalsIgnoreCase("application/odb") || + r.getMime().equalsIgnoreCase("application/ods")) { + indexResourceODF(r); + return; + } + } + } + + + private void indexResourceRTF(Resource r) { + + Data d = r.getData(); + for (int i=0; i<20 && d.getSize() == 0; i++) + d = r.getData(); + if (d.getSize()== 0) + return; + + QTemporaryFile f = writeResource(d); + if (!keepRunning) { + return; + } + + InputStream input; + try { + input = new FileInputStream(new File(f.fileName())); + ContentHandler textHandler = new BodyContentHandler(-1); + Metadata metadata = new Metadata(); + RTFParser parser = new RTFParser(); + ParseContext context = new ParseContext(); + parser.parse(input, textHandler, metadata, context); + String[] result = textHandler.toString().split(regex); + for (int i=0; i", index)+11; + if (endPos > -1 && index > -1) { + content = content.substring(0,index)+content.substring(endPos); + index = content.indexOf("=0; i--) { + if (!Character.isLetterOrDigit(buffer.charAt(i)) && specialIndexCharacters.indexOf(buffer.charAt(i)) == -1) + buffer.deleteCharAt(i); + else + break; + } + buffer = buffer.reverse(); + for (int i=buffer.length()-1; i>=0; i--) { + if (!Character.isLetterOrDigit(buffer.charAt(i))) + buffer.deleteCharAt(i); + else + break; + } + buffer = buffer.reverse(); + if (buffer.length() > 0) { + // We have a good word, now let's trim off junk at the beginning or end + if (!foundWords.contains(buffer.toString())) { + foundWords.add(buffer.toString()); + foundWords.add(word); + conn.getWordsTable().addWordToNoteIndex(guid, buffer.toString(), type, 100); + uncommittedCount++; + if (uncommittedCount > 100) { + conn.commitTransaction(); + uncommittedCount=0; + } + } + } + return; + } + + private void scanUnindexed() { + List notes = conn.getNoteTable().getUnindexed(); + guid = null; + boolean started = false; + if (notes.size() > 0) { + signal.indexStarted.emit(); + started = true; + } + for (int i=0; i unindexedResources = conn.getNoteTable().noteResourceTable.getUnindexed(); + if (unindexedResources.size() > 0 && !started) { + signal.indexStarted.emit(); + started = true; + } + for (int i=0; i guids = conn.getWordsTable().getGuidList(); + logger.log(logger.LOW, "GUIDS in index: " +guids.size()); + for (int i=0; i> workQueue = new LinkedBlockingQueue>(); - - - //********************************************* - //* Constructor * - //********************************************* - public SaveRunner(String logname, String u, String i, String r, String uid, String pswd, String cpswd) { - logger = new ApplicationLogger(logname); - conn = new DatabaseConnection(logger, u, i, r, uid, pswd, cpswd, 0); - threadLock = new QMutex(); - keepRunning = true; - noteSignals = new NoteSignal(); - } - - public SaveRunner(ApplicationLogger l, DatabaseConnection c) { - logger = l; - conn = c; - keepRunning = true; - noteSignals = new NoteSignal(); - } - - - - //********************************************* - //* Run unit * - //********************************************* - @Override - public void run() { - thread().setPriority(Thread.MIN_PRIORITY); - boolean keepRunning = true; - - while(keepRunning) { - try { - Pair content; - idle = true; - content = workQueue.take(); - if (!content.getFirst().equalsIgnoreCase("stop")) { - idle = false; - - // This is a bit of a hack. It causes this thread to pause for 0.2 seconds. - // This helps make sure that the main thread gets to the - // database first when switching notes, othrewise it really - // slows things down when fetching new notes. - GregorianCalendar now = new GregorianCalendar(); - long prev = now.getTimeInMillis(); - prev = prev+200; - while (prev>now.getTimeInMillis()) { - now = new GregorianCalendar(); - } - - updateNoteContent(content.getFirst(), content.getSecond()); - } else { - return; - } - threadLock.unlock(); - } catch (InterruptedException e) { } - } - conn.dbShutdown(); - } - - - public synchronized void addWork(String guid, String content) { - while(workQueue.size() > 0) {} - Pair pair = new Pair(guid, content); - workQueue.offer(pair); - } - - public synchronized void release(String guid, String content) { - Pair pair = new Pair(guid, content); - workQueue.add(pair); - } - - public synchronized int getWorkQueueSize() { - return workQueue.size(); - } - - - //********************************************* - //* Getter & Setter method to tell the thread * - //* to keep running. * - //********************************************* - public void setKeepRunning(boolean b) { - keepRunning = b; - } - public boolean keepRunning() { - return keepRunning; - } - - public boolean isIdle() { - return idle; - } - - - //********************************************* - //* Do the actual work * - //********************************************* - public void updateNoteContent(String guid, String content) { - logger.log(logger.HIGH, "Entering ListManager.updateNoteContent"); - - // Actually save the content - EnmlConverter enml = new EnmlConverter(logger); - String newContent = enml.convert(guid, content); - String fixedContent = enml.fixEnXMLCrap(newContent); - if (fixedContent != null) { - conn.getNoteTable().updateNoteContent(guid, fixedContent); - logger.log(logger.EXTREME, "Saving new note resources"); - List oldResources = conn.getNoteTable().noteResourceTable.getNoteResources(guid, false); - List newResources = enml.getResources(); - removeObsoleteResources(oldResources, newResources); - } else { - noteSignals.noteSaveRunnerError.emit(guid, null); - } - logger.log(logger.HIGH, "Leaving ListManager.updateNoteContent"); - } - - // Remove resources that are no longer needed - private void removeObsoleteResources(List oldResources, List newResources) { - if (oldResources == null || oldResources.size() == 0) - return; - if (newResources == null || newResources.size() == 0) { - for (int i=0; i> workQueue = new LinkedBlockingQueue>(); + + + //********************************************* + //* Constructor * + //********************************************* + // ICHANGED String bを追加 + public SaveRunner(String logname, String u, String i, String r, String b, String uid, String pswd, String cpswd) { + logger = new ApplicationLogger(logname); + // ICHANGED bを追加 + conn = new DatabaseConnection(logger, u, i, r, b, uid, pswd, cpswd, 0); + threadLock = new QMutex(); + keepRunning = true; + noteSignals = new NoteSignal(); + } + + public SaveRunner(ApplicationLogger l, DatabaseConnection c) { + logger = l; + conn = c; + keepRunning = true; + noteSignals = new NoteSignal(); + } + + + + //********************************************* + //* Run unit * + //********************************************* + @Override + public void run() { + thread().setPriority(Thread.MIN_PRIORITY); + boolean keepRunning = true; + + while(keepRunning) { + try { + Pair content; + idle = true; + content = workQueue.take(); + if (!content.getFirst().equalsIgnoreCase("stop")) { + idle = false; + + // This is a bit of a hack. It causes this thread to pause for 0.2 seconds. + // This helps make sure that the main thread gets to the + // database first when switching notes, othrewise it really + // slows things down when fetching new notes. + GregorianCalendar now = new GregorianCalendar(); + long prev = now.getTimeInMillis(); + prev = prev+200; + while (prev>now.getTimeInMillis()) { + now = new GregorianCalendar(); + } + + updateNoteContent(content.getFirst(), content.getSecond()); + } else { + return; + } + threadLock.unlock(); + } catch (InterruptedException e) { } + } + conn.dbShutdown(); + } + + + public synchronized void addWork(String guid, String content) { + while(workQueue.size() > 0) {} + Pair pair = new Pair(guid, content); + workQueue.offer(pair); + } + + public synchronized void release(String guid, String content) { + Pair pair = new Pair(guid, content); + workQueue.add(pair); + } + + public synchronized int getWorkQueueSize() { + return workQueue.size(); + } + + + //********************************************* + //* Getter & Setter method to tell the thread * + //* to keep running. * + //********************************************* + public void setKeepRunning(boolean b) { + keepRunning = b; + } + public boolean keepRunning() { + return keepRunning; + } + + public boolean isIdle() { + return idle; + } + + + //********************************************* + //* Do the actual work * + //********************************************* + public void updateNoteContent(String guid, String content) { + logger.log(logger.HIGH, "Entering ListManager.updateNoteContent"); + + // Actually save the content + EnmlConverter enml = new EnmlConverter(logger); + String newContent = enml.convert(guid, content); + String fixedContent = enml.fixEnXMLCrap(newContent); + if (fixedContent != null) { + conn.getNoteTable().updateNoteContent(guid, fixedContent); + logger.log(logger.EXTREME, "Saving new note resources"); + List oldResources = conn.getNoteTable().noteResourceTable.getNoteResources(guid, false); + List newResources = enml.getResources(); + removeObsoleteResources(oldResources, newResources); + } else { + noteSignals.noteSaveRunnerError.emit(guid, null); + } + logger.log(logger.HIGH, "Leaving ListManager.updateNoteContent"); + } + + // Remove resources that are no longer needed + private void removeObsoleteResources(List oldResources, List newResources) { + if (oldResources == null || oldResources.size() == 0) + return; + if (newResources == null || newResources.size() == 0) { + for (int i=0; i errorSharedNotebooks; - public volatile HashMap errorSharedNotebooksIgnored; - public volatile boolean isConnected; - public volatile boolean keepRunning; - public volatile String authToken; - private long evernoteUpdateCount; - private final String userAgent = "NixNote/" + System.getProperty("os.name") - +"/"+System.getProperty("java.vendor") + "/" - + System.getProperty("java.version") +";"; - - public volatile NoteStore.Client localNoteStore; - private UserStore.Client userStore; - - public volatile StatusSignal status; - public volatile TagSignal tagSignal; - public volatile NotebookSignal notebookSignal; - public volatile NoteIndexSignal noteIndexSignal; - public volatile NoteSignal noteSignal; - public volatile SavedSearchSignal searchSignal; - public volatile NoteResourceSignal resourceSignal; - public volatile SyncSignal syncSignal; - public volatile boolean authRefreshNeeded; - public volatile boolean syncNeeded; - public volatile boolean disableUploads; - public volatile boolean syncDeletedContent; - private volatile List dirtyNoteGuids; - - public volatile String username = ""; - public volatile String password = ""; - public volatile String userStoreUrl; -// private final static String consumerKey = "baumgarte"; -// private final static String consumerSecret = "eb8b5740e17cb55f"; - public String noteStoreUrlBase; - private THttpClient userStoreTrans; - private TBinaryProtocol userStoreProt; - //private AuthenticationResult authResult; - private AuthenticationResult linkedAuthResult; - private User user; -// private long authTimeRemaining; - public long authRefreshTime; - public long failedRefreshes = 0; - public THttpClient noteStoreTrans; - public TBinaryProtocol noteStoreProt; - public String noteStoreUrl; - public long sequenceDate; - public int updateSequenceNumber; - private boolean refreshNeeded; - private volatile LinkedBlockingQueue workQueue; - private static int MAX_QUEUED_WAITING = 1000; - String dbuid; - String dburl; - String indexUrl; - String resourceUrl; - String dbpswd; - String dbcpswd; - private final TreeSet ignoreTags; - private final TreeSet ignoreNotebooks; - private final TreeSet ignoreLinkedNotebooks; - private HashMap badTagSync; - - - - public SyncRunner(String logname, String u, String i, String r, String uid, String pswd, String cpswd) { - logger = new ApplicationLogger(logname); - - noteSignal = new NoteSignal(); - status = new StatusSignal(); - tagSignal = new TagSignal(); - notebookSignal = new NotebookSignal(); - noteIndexSignal = new NoteIndexSignal(); - noteSignal = new NoteSignal(); - searchSignal = new SavedSearchSignal(); - syncSignal = new SyncSignal(); - resourceSignal = new NoteResourceSignal(); - resourceUrl = r; - indexUrl = i; - dbuid = uid; - dburl = u; - dbpswd = pswd; - dbcpswd = cpswd; -// this.setAutoDelete(false); - - isConnected = false; - syncNeeded = false; - authRefreshNeeded = false; - keepRunning = true; - idle = true; - disableUploads = false; - ignoreTags = new TreeSet(); - ignoreNotebooks = new TreeSet(); - ignoreLinkedNotebooks = new TreeSet(); - -// setAutoDelete(false); - workQueue=new LinkedBlockingQueue(MAX_QUEUED_WAITING); - } - @Override - public void run() { - errorSharedNotebooks = new ArrayList(); - errorSharedNotebooksIgnored = new HashMap(); - try { - logger.log(logger.EXTREME, "Starting thread"); - conn = new DatabaseConnection(logger, dburl, indexUrl, resourceUrl, dbuid, dbpswd, dbcpswd, 200); - while(keepRunning) { - logger.log(logger.EXTREME, "Blocking until work is found"); - String work = workQueue.take(); - logger.log(logger.LOW, "Dirty Notes Before Sync: " +new Integer(conn.getNoteTable().getDirtyCount()).toString()); - logger.log(logger.EXTREME, "Work found: " +work); - if (work.equalsIgnoreCase("stop")) { - idle=false; - return; - } - conn.getNoteTable().dumpDirtyNotes(); // Debugging statement - idle=false; - error=false; - if (syncNeeded) { - logger.log(logger.EXTREME, "SyncNeeded is true"); - refreshNeeded=false; - sequenceDate = conn.getSyncTable().getLastSequenceDate(); - updateSequenceNumber = conn.getSyncTable().getUpdateSequenceNumber(); - try { - logger.log(logger.EXTREME, "Beginning sync"); - evernoteSync(localNoteStore); - logger.log(logger.EXTREME, "Sync finished"); - } catch (UnknownHostException e) { - status.message.emit(e.getMessage()); - } - } - idle=true; - logger.log(logger.EXTREME, "Signaling refresh finished. refreshNeeded=" +refreshNeeded); - syncSignal.finished.emit(refreshNeeded); - if (error) { - syncSignal.errorDisconnect.emit(); - status.message.emit(tr("Error synchronizing - see log for details.")); - } - logger.log(logger.LOW, "Dirty Notes After Sync: " +new Integer(conn.getNoteTable().getDirtyCount()).toString()); - conn.getNoteTable().dumpDirtyNotes(); - logger.log(logger.LOW, "---"); - } - } - catch (InterruptedException e1) { - e1.printStackTrace(); - } - conn.dbShutdown(); - } - - - public DatabaseConnection getConnection() { - return conn; - } - - public boolean isIdle() { - return idle; - } - - - public void setConnected(boolean c) { - isConnected = c; - } - public void setKeepRunning(boolean r) { - logger.log(logger.EXTREME, "Setting keepRunning=" +r); - keepRunning = r; - } - public void setNoteStore(NoteStore.Client c) { - logger.log(logger.EXTREME, "Setting NoteStore in sync thread"); - localNoteStore = c; - } - public void setUserStore(UserStore.Client c) { - logger.log(logger.EXTREME, "Setting UserStore in sync thread"); - userStore = c; - } - - public void setEvernoteUpdateCount(long s) { - logger.log(logger.EXTREME, "Setting Update Count in sync thread"); - evernoteUpdateCount = s; - } - - //*************************************************************** - //*************************************************************** - //** These functions deal with Evernote communications - //*************************************************************** - //*************************************************************** - // Synchronize changes with Evernote - @SuppressWarnings("unused") - private void evernoteSync(Client noteStore) throws java.net.UnknownHostException { - logger.log(logger.HIGH, "Entering SyncRunner.evernoteSync"); - - // Rebuild list of tags & notebooks to ignore - ignoreNotebooks.clear(); - List ignore = conn.getSyncTable().getIgnoreRecords("NOTEBOOK"); - for (int i=0; i sequenceDate) { - logger.log(logger.EXTREME, "Full sequence date has expired"); - sequenceDate = 0; - conn.getSyncTable().setLastSequenceDate(0); - updateSequenceNumber = 0; - conn.getSyncTable().setUpdateSequenceNumber(0); - } - // Check for "special" sync instructions - String syncLinked = conn.getSyncTable().getRecord("FullLinkedNotebookSync"); - String syncShared = conn.getSyncTable().getRecord("FullSharedNotebookSync"); - String syncNotebooks = conn.getSyncTable().getRecord("FullNotebookSync"); - String syncInkNoteImages = conn.getSyncTable().getRecord("FullInkNoteImageSync"); - if (syncLinked != null) { - downloadAllLinkedNotebooks(localNoteStore); - } - if (syncShared != null) { - downloadAllSharedNotebooks(localNoteStore); - } - if (syncNotebooks != null) { - downloadAllNotebooks(localNoteStore); - } - - if (syncInkNoteImages != null) { - List guids = conn.getNoteTable().noteResourceTable.findInkNotes(); - for (int i=0; i updateSequenceNumber) { - logger.log(logger.EXTREME, "Refresh needed is true"); - refreshNeeded = true; - logger.log(logger.EXTREME, "Downloading changes"); - syncRemoteToLocal(localNoteStore); - } - - //***************************************** - //* Sync linked/shared notebooks - //***************************************** - //syncLinkedNotebooks(); - //conn.getNoteTable().getDirty(); - //disableUploads = true; /// DELETE THIS LINE!!!! - if (!disableUploads) { - logger.log(logger.EXTREME, "Uploading changes"); - // Synchronize remote changes - if (!error) - syncExpunged(localNoteStore); - if (!error) - syncLocalTags(localNoteStore); - if (!error) - syncLocalNotebooks(localNoteStore); - if (!error) - syncLocalLinkedNotebooks(localNoteStore); - if (!error) - syncDeletedNotes(localNoteStore); - if (!error) - syncLocalNotes(); - if (!error) - syncLocalSavedSearches(localNoteStore); - } - - status.message.emit(tr("Cleaning up")); - List notes = conn.getNoteTable().expungeIgnoreSynchronizedNotes(conn.getSyncTable().getIgnoreRecords("NOTEBOOK"), - conn.getSyncTable().getIgnoreRecords("TAG"), conn.getSyncTable().getIgnoreRecords("LINKEDNOTEBOOK")); - if (notes.size() > 0) - syncSignal.refreshLists.emit(); - - //***************************************** - //* End of synchronization - //***************************************** - if (refreshNeeded) - syncSignal.refreshLists.emit(); - - if (!error) { - logger.log(logger.LOW, "Sync completed. Errors=" +error); - if (!disableUploads) - status.message.emit(tr("Synchronizing complete")); - else - status.message.emit(tr("Download syncronization complete. Uploads have been disabled.")); - - logger.log(logger.EXTREME, "Saving sync time"); - if (syncState.getCurrentTime() > sequenceDate) - sequenceDate = syncState.getCurrentTime(); - if (syncState.getUpdateCount() > updateSequenceNumber) - updateSequenceNumber = syncState.getUpdateCount(); - conn.getSyncTable().setLastSequenceDate(sequenceDate); - conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber); - } - } - logger.log(logger.HIGH, "Leaving SyncRunner.evernoteSync"); - } - - // Sync deleted items with Evernote - private void syncExpunged(Client noteStore) { - logger.log(logger.HIGH, "Entering SyncRunner.syncExpunged"); - - List expunged = conn.getDeletedTable().getAllDeleted(); - boolean error = false; - for (int i=0; i errorSharedNotebooks; + public volatile HashMap errorSharedNotebooksIgnored; + public volatile boolean isConnected; + public volatile boolean keepRunning; + public volatile String authToken; + private long evernoteUpdateCount; + private final String userAgent = "NeighborNote/" + System.getProperty("os.name") + +"/"+System.getProperty("java.vendor") + "/" + + System.getProperty("java.version") +";"; + + public volatile NoteStore.Client localNoteStore; + private UserStore.Client userStore; + + public volatile StatusSignal status; + public volatile TagSignal tagSignal; + public volatile NotebookSignal notebookSignal; + public volatile NoteIndexSignal noteIndexSignal; + public volatile NoteSignal noteSignal; + public volatile SavedSearchSignal searchSignal; + public volatile NoteResourceSignal resourceSignal; + public volatile SyncSignal syncSignal; + public volatile boolean authRefreshNeeded; + public volatile boolean syncNeeded; + public volatile boolean disableUploads; + public volatile boolean syncDeletedContent; + private volatile List dirtyNoteGuids; + + public volatile String username = ""; + public volatile String password = ""; + public volatile String userStoreUrl; +// private final static String consumerKey = "baumgarte"; +// private final static String consumerSecret = "eb8b5740e17cb55f"; + public String noteStoreUrlBase; + private THttpClient userStoreTrans; + private TBinaryProtocol userStoreProt; + //private AuthenticationResult authResult; + private AuthenticationResult linkedAuthResult; + private User user; +// private long authTimeRemaining; + public long authRefreshTime; + public long failedRefreshes = 0; + public THttpClient noteStoreTrans; + public TBinaryProtocol noteStoreProt; + public String noteStoreUrl; + public long sequenceDate; + public int updateSequenceNumber; + private boolean refreshNeeded; + private volatile LinkedBlockingQueue workQueue; + private static int MAX_QUEUED_WAITING = 1000; + String dbuid; + String dburl; + String indexUrl; + String resourceUrl; + // ICHANGED + String behaviorUrl; + + String dbpswd; + String dbcpswd; + private final TreeSet ignoreTags; + private final TreeSet ignoreNotebooks; + private final TreeSet ignoreLinkedNotebooks; + private HashMap badTagSync; + + + // ICHANGED String bを追加 + public SyncRunner(String logname, String u, String i, String r, String b, String uid, String pswd, String cpswd) { + logger = new ApplicationLogger(logname); + + noteSignal = new NoteSignal(); + status = new StatusSignal(); + tagSignal = new TagSignal(); + notebookSignal = new NotebookSignal(); + noteIndexSignal = new NoteIndexSignal(); + noteSignal = new NoteSignal(); + searchSignal = new SavedSearchSignal(); + syncSignal = new SyncSignal(); + resourceSignal = new NoteResourceSignal(); + resourceUrl = r; + indexUrl = i; + // ICHANGED + behaviorUrl = b; + + dbuid = uid; + dburl = u; + dbpswd = pswd; + dbcpswd = cpswd; +// this.setAutoDelete(false); + + isConnected = false; + syncNeeded = false; + authRefreshNeeded = false; + keepRunning = true; + idle = true; + disableUploads = false; + ignoreTags = new TreeSet(); + ignoreNotebooks = new TreeSet(); + ignoreLinkedNotebooks = new TreeSet(); + +// setAutoDelete(false); + workQueue=new LinkedBlockingQueue(MAX_QUEUED_WAITING); + } + @Override + public void run() { + errorSharedNotebooks = new ArrayList(); + errorSharedNotebooksIgnored = new HashMap(); + try { + logger.log(logger.EXTREME, "Starting thread"); + // ICHANGED behaviorUrlを追加 + conn = new DatabaseConnection(logger, dburl, indexUrl, resourceUrl, behaviorUrl, dbuid, dbpswd, dbcpswd, 200); + while(keepRunning) { + logger.log(logger.EXTREME, "Blocking until work is found"); + String work = workQueue.take(); + logger.log(logger.LOW, "Dirty Notes Before Sync: " +new Integer(conn.getNoteTable().getDirtyCount()).toString()); + logger.log(logger.EXTREME, "Work found: " +work); + if (work.equalsIgnoreCase("stop")) { + idle=false; + return; + } + conn.getNoteTable().dumpDirtyNotes(); // Debugging statement + idle=false; + error=false; + if (syncNeeded) { + logger.log(logger.EXTREME, "SyncNeeded is true"); + refreshNeeded=false; + sequenceDate = conn.getSyncTable().getLastSequenceDate(); + updateSequenceNumber = conn.getSyncTable().getUpdateSequenceNumber(); + try { + logger.log(logger.EXTREME, "Beginning sync"); + evernoteSync(localNoteStore); + logger.log(logger.EXTREME, "Sync finished"); + } catch (UnknownHostException e) { + status.message.emit(e.getMessage()); + } + } + idle=true; + logger.log(logger.EXTREME, "Signaling refresh finished. refreshNeeded=" +refreshNeeded); + syncSignal.finished.emit(refreshNeeded); + if (error) { + syncSignal.errorDisconnect.emit(); + status.message.emit(tr("Error synchronizing - see log for details.")); + } + logger.log(logger.LOW, "Dirty Notes After Sync: " +new Integer(conn.getNoteTable().getDirtyCount()).toString()); + conn.getNoteTable().dumpDirtyNotes(); + logger.log(logger.LOW, "---"); + } + } + catch (InterruptedException e1) { + e1.printStackTrace(); + } + conn.dbShutdown(); + } + + + public DatabaseConnection getConnection() { + return conn; + } + + public boolean isIdle() { + return idle; + } + + + public void setConnected(boolean c) { + isConnected = c; + } + public void setKeepRunning(boolean r) { + logger.log(logger.EXTREME, "Setting keepRunning=" +r); + keepRunning = r; + } + public void setNoteStore(NoteStore.Client c) { + logger.log(logger.EXTREME, "Setting NoteStore in sync thread"); + localNoteStore = c; + } + public void setUserStore(UserStore.Client c) { + logger.log(logger.EXTREME, "Setting UserStore in sync thread"); + userStore = c; + } + + public void setEvernoteUpdateCount(long s) { + logger.log(logger.EXTREME, "Setting Update Count in sync thread"); + evernoteUpdateCount = s; + } + + //*************************************************************** + //*************************************************************** + //** These functions deal with Evernote communications + //*************************************************************** + //*************************************************************** + // Synchronize changes with Evernote + @SuppressWarnings("unused") + private void evernoteSync(Client noteStore) throws java.net.UnknownHostException { + logger.log(logger.HIGH, "Entering SyncRunner.evernoteSync"); + + // Rebuild list of tags & notebooks to ignore + ignoreNotebooks.clear(); + List ignore = conn.getSyncTable().getIgnoreRecords("NOTEBOOK"); + for (int i=0; i sequenceDate) { + logger.log(logger.EXTREME, "Full sequence date has expired"); + sequenceDate = 0; + conn.getSyncTable().setLastSequenceDate(0); + updateSequenceNumber = 0; + conn.getSyncTable().setUpdateSequenceNumber(0); + } + // Check for "special" sync instructions + String syncLinked = conn.getSyncTable().getRecord("FullLinkedNotebookSync"); + String syncShared = conn.getSyncTable().getRecord("FullSharedNotebookSync"); + String syncNotebooks = conn.getSyncTable().getRecord("FullNotebookSync"); + String syncInkNoteImages = conn.getSyncTable().getRecord("FullInkNoteImageSync"); + if (syncLinked != null) { + downloadAllLinkedNotebooks(localNoteStore); + } + if (syncShared != null) { + downloadAllSharedNotebooks(localNoteStore); + } + if (syncNotebooks != null) { + downloadAllNotebooks(localNoteStore); + } + + if (syncInkNoteImages != null) { + List guids = conn.getNoteTable().noteResourceTable.findInkNotes(); + for (int i=0; i updateSequenceNumber) { + logger.log(logger.EXTREME, "Refresh needed is true"); + refreshNeeded = true; + logger.log(logger.EXTREME, "Downloading changes"); + syncRemoteToLocal(localNoteStore); + } + + //***************************************** + //* Sync linked/shared notebooks + //***************************************** + //syncLinkedNotebooks(); + //conn.getNoteTable().getDirty(); + //disableUploads = true; /// DELETE THIS LINE!!!! + if (!disableUploads) { + logger.log(logger.EXTREME, "Uploading changes"); + // Synchronize remote changes + if (!error) + syncExpunged(localNoteStore); + if (!error) + syncLocalTags(localNoteStore); + if (!error) + syncLocalNotebooks(localNoteStore); + if (!error) + syncLocalLinkedNotebooks(localNoteStore); + if (!error) + syncDeletedNotes(localNoteStore); + if (!error) + syncLocalNotes(); + if (!error) + syncLocalSavedSearches(localNoteStore); + } + + status.message.emit(tr("Cleaning up")); + List notes = conn.getNoteTable().expungeIgnoreSynchronizedNotes(conn.getSyncTable().getIgnoreRecords("NOTEBOOK"), + conn.getSyncTable().getIgnoreRecords("TAG"), conn.getSyncTable().getIgnoreRecords("LINKEDNOTEBOOK")); + if (notes.size() > 0) + syncSignal.refreshLists.emit(); + + //***************************************** + //* End of synchronization + //***************************************** + if (refreshNeeded) + syncSignal.refreshLists.emit(); + + if (!error) { + logger.log(logger.LOW, "Sync completed. Errors=" +error); + if (!disableUploads) + status.message.emit(tr("Synchronizing complete")); + else + status.message.emit(tr("Download syncronization complete. Uploads have been disabled.")); + + logger.log(logger.EXTREME, "Saving sync time"); + if (syncState.getCurrentTime() > sequenceDate) + sequenceDate = syncState.getCurrentTime(); + if (syncState.getUpdateCount() > updateSequenceNumber) + updateSequenceNumber = syncState.getUpdateCount(); + conn.getSyncTable().setLastSequenceDate(sequenceDate); + conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber); + } + } + logger.log(logger.HIGH, "Leaving SyncRunner.evernoteSync"); + } + + // Sync deleted items with Evernote + private void syncExpunged(Client noteStore) { + logger.log(logger.HIGH, "Entering SyncRunner.syncExpunged"); + + List expunged = conn.getDeletedTable().getAllDeleted(); + boolean error = false; + for (int i=0; i notes = conn.getNoteTable().getDirty(); - // Sync the local notebooks with Evernote's - for (int i=0; i 0 && (enNote.isActive() == false || enNote.getDeleted() > 0)) { + updateSequenceNumber = noteStore.expungeSearch(authToken, expunged.get(i).guid); + conn.getSyncTable().setLastSequenceDate(sequenceDate); + conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber); + } + } catch (EDAMUserException e) { + logger.log(logger.LOW, "EDAM User Excepton in syncExpunged: " +expunged.get(i).guid); // This can happen if we try to delete a deleted note + } catch (EDAMSystemException e) { + logger.log(logger.LOW, "EDAM System Excepton in syncExpunged: "+expunged.get(i).guid); + logger.log(logger.LOW, e.getStackTrace()); + error=true; + } catch (EDAMNotFoundException e) { + logger.log(logger.LOW, "EDAM Not Found Excepton in syncExpunged: "+expunged.get(i).guid); + } catch (TException e) { + logger.log(logger.LOW, "EDAM TExcepton in syncExpunged: "+expunged.get(i).guid); + logger.log(logger.LOW, e.getStackTrace()); + error=true; + } + } + if (!error) + conn.getDeletedTable().expungeAllDeletedRecords(); + + logger.log(logger.HIGH, "Leaving SyncRunner.syncExpunged"); + + } + private void syncDeletedNotes(Client noteStore) { + if (syncDeletedContent) + return; + logger.log(logger.HIGH, "Entering SyncRunner.syncDeletedNotes"); + status.message.emit(tr("Synchronizing deleted notes.")); + + List notes = conn.getNoteTable().getDirty(); + // Sync the local notebooks with Evernote's + for (int i=0; i 0 && (enNote.isActive() == false || enNote.getDeleted() > 0)) { // Check that the note is valid. if (enNote.isActive() == true || enNote.getDeleted() == 0) { conn.getNoteTable().deleteNote(enNote.getGuid()); enNote = conn.getNoteTable().getNote(enNote.getGuid(), false, false, false, false, false); } - if (syncDeletedContent) { - logger.log(logger.EXTREME, "Deleted note found & synch content selected"); - Note delNote = conn.getNoteTable().getNote(enNote.getGuid(), true, true, true, true, true); - delNote = getNoteContent(delNote); - delNote = noteStore.updateNote(authToken, delNote); - enNote.setUpdateSequenceNum(delNote.getUpdateSequenceNum()); - conn.getNoteTable().updateNoteSequence(enNote.getGuid(), enNote.getUpdateSequenceNum()); - } else { - logger.log(logger.EXTREME, "Deleted note found & sync content not selected"); - int usn = noteStore.deleteNote(authToken, enNote.getGuid()); - enNote.setUpdateSequenceNum(usn); - conn.getNoteTable().updateNoteSequence(enNote.getGuid(), enNote.getUpdateSequenceNum()); - } - logger.log(logger.EXTREME, "Resetting deleted dirty flag"); - conn.getNoteTable().resetDirtyFlag(enNote.getGuid()); - updateSequenceNumber = enNote.getUpdateSequenceNum(); - logger.log(logger.EXTREME, "Saving sequence number"); - conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber); - } - } catch (EDAMUserException e) { + if (syncDeletedContent) { + logger.log(logger.EXTREME, "Deleted note found & synch content selected"); + Note delNote = conn.getNoteTable().getNote(enNote.getGuid(), true, true, true, true, true); + delNote = getNoteContent(delNote); + delNote = noteStore.updateNote(authToken, delNote); + enNote.setUpdateSequenceNum(delNote.getUpdateSequenceNum()); + conn.getNoteTable().updateNoteSequence(enNote.getGuid(), enNote.getUpdateSequenceNum()); + } else { + logger.log(logger.EXTREME, "Deleted note found & sync content not selected"); + int usn = noteStore.deleteNote(authToken, enNote.getGuid()); + enNote.setUpdateSequenceNum(usn); + conn.getNoteTable().updateNoteSequence(enNote.getGuid(), enNote.getUpdateSequenceNum()); + } + logger.log(logger.EXTREME, "Resetting deleted dirty flag"); + conn.getNoteTable().resetDirtyFlag(enNote.getGuid()); + updateSequenceNumber = enNote.getUpdateSequenceNum(); + logger.log(logger.EXTREME, "Saving sequence number"); + conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber); + } + } catch (EDAMUserException e) { logger.log(logger.LOW, "*** EDAM User Excepton syncLocalNotes "+e); - //status.message.emit("Error sending local note: " +e.getParameter()); - //logger.log(logger.LOW, e.toString()); - //error = true; - } catch (EDAMSystemException e) { - logger.log(logger.LOW, "*** EDAM System Excepton syncLocalNotes "+e); - status.message.emit(tr("Error: ") +e); - logger.log(logger.LOW, e.toString()); - error = true; - } catch (EDAMNotFoundException e) { + //status.message.emit("Error sending local note: " +e.getParameter()); + //logger.log(logger.LOW, e.toString()); + //error = true; + } catch (EDAMSystemException e) { + logger.log(logger.LOW, "*** EDAM System Excepton syncLocalNotes "+e); + status.message.emit(tr("Error: ") +e); + logger.log(logger.LOW, e.toString()); + error = true; + } catch (EDAMNotFoundException e) { logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalNotes " +e); - //status.message.emit("Error deleting local note: " +e +" - Continuing"); - //logger.log(logger.LOW, e.toString()); - //error = true; - } catch (TException e) { - logger.log(logger.LOW, "*** EDAM TExcepton syncLocalNotes "+e); - status.message.emit(tr("Error sending local note: ") +e); - logger.log(logger.LOW, e.toString()); - error = true; - } - } - } - // Sync notes with Evernote - private void syncLocalNotes() { - logger.log(logger.HIGH, "Entering SyncRunner.syncNotes"); - logger.log(logger.LOW, "Dirty local notes found: " +new Integer(conn.getNoteTable().getDirtyCount()).toString()); - status.message.emit(tr("Sending local notes.")); - - List notes = conn.getNoteTable().getDirty(); - // Sync the local notebooks with Evernote's - for (int i=0; i 0) { - logger.log(logger.EXTREME, "Active dirty note found - non new - " +enNote.getGuid()); - logger.log(logger.EXTREME, "Fetching note content"); - enNote = getNoteContent(enNote); - logger.log(logger.MEDIUM, "Updating note : "+ enNote.getGuid() +" " +enNote.getTitle()+""); - enNote = noteStore.updateNote(token, enNote); - } else { - logger.log(logger.EXTREME, "Active dirty found - new note " +enNote.getGuid()); - String oldGuid = enNote.getGuid(); - logger.log(logger.MEDIUM, "Fetching note content"); - enNote = getNoteContent(enNote); - logger.log(logger.MEDIUM, "Creating note : "+ enNote.getGuid() +" " +enNote.getTitle()+""); - enNote = noteStore.createNote(token, enNote); - logger.log(logger.MEDIUM, "New note Guid : "+ enNote.getGuid() +" " +enNote.getTitle()+""); - noteSignal.guidChanged.emit(oldGuid, enNote.getGuid()); - conn.getNoteTable().updateNoteGuid(oldGuid, enNote.getGuid()); - } - updateSequenceNumber = enNote.getUpdateSequenceNum(); - logger.log(logger.EXTREME, "Saving note"); - conn.getNoteTable().updateNoteSequence(enNote.getGuid(), enNote.getUpdateSequenceNum()); - List rl = enNote.getResources(); - logger.log(logger.EXTREME, "Getting note resources"); - for (int j=0; j remoteList = new ArrayList(); - try { - logger.log(logger.EXTREME, "Getting remote notebooks to compare with local"); - remoteList = noteStore.listNotebooks(authToken); - } catch (EDAMUserException e1) { - logger.log(logger.LOW, "*** EDAM User Excepton syncLocalNotebooks getting remote Notebook List"); - status.message.emit(tr("Error: ") +e1); - logger.log(logger.LOW, e1.toString()); - error = true; - } catch (EDAMSystemException e1) { - logger.log(logger.LOW, "*** EDAM System Excepton syncLocalNotebooks getting remote Notebook List"); - status.message.emit(tr("Error: ") +e1); - logger.log(logger.LOW, e1.toString()); - error = true; - } catch (TException e1) { - logger.log(logger.LOW, "*** EDAM Transaction Excepton syncLocalNotebooks getting remote Notebook List"); - status.message.emit(tr("Error: ") +e1); - logger.log(logger.LOW, e1.toString()); - error = true; - } - logger.log(logger.EXTREME, "Getting local dirty notebooks"); - List notebooks = conn.getNotebookTable().getDirty(); - int sequence; - // Sync the local notebooks with Evernote's - for (int i=0; i 0) { - logger.log(logger.EXTREME, "Existing notebook is dirty"); - sequence = noteStore.updateNotebook(authToken, enNotebook); - } else { - logger.log(logger.EXTREME, "New dirty notebook found"); - String oldGuid = enNotebook.getGuid(); - boolean found = false; - - // Look for a notebook with the same name. If one is found, we don't need - // to create another one - logger.log(logger.EXTREME, "Looking for matching notebook name"); - for (int k=0; k remoteList = new ArrayList(); - status.message.emit(tr("Sending local tags.")); - - try { - logger.log(logger.EXTREME, "Getting remote tags to compare names with the local tags"); - remoteList = noteStore.listTags(authToken); - } catch (EDAMUserException e1) { - logger.log(logger.LOW, "*** EDAM User Excepton syncLocalTags getting remote Tag List"); - status.message.emit(tr("Error: ") +e1); - logger.log(logger.LOW, e1.toString()); - error = true; - } catch (EDAMSystemException e1) { - logger.log(logger.LOW, "*** EDAM System Excepton syncLocalTags getting remote Tag List"); - status.message.emit(tr("Error: ") +e1); - logger.log(logger.LOW, e1.toString()); - error = true; - } catch (TException e1) { - logger.log(logger.LOW, "*** EDAM Transaction Excepton syncLocalTags getting remote Tag List"); - status.message.emit(tr("Error: ") +e1); - logger.log(logger.LOW, e1.toString()); - error = true; - } - - int sequence; - - if (badTagSync == null) - badTagSync = new HashMap(); - else - badTagSync.clear(); - - Tag enTag = findNextTag(); - - // This is a hack. Sometimes this function goes flookey and goes into a - // perpetual loop. This causes NeverNote to flood Evernote's servers. - // This is a safety valve to prevent unlimited loops. - int maxCount = conn.getTagTable().getDirty().size()+10; - int loopCount = 0; - - while(enTag!=null && loopCount < maxCount) { - loopCount++; -// if (authRefreshNeeded) -// if (!refreshConnection()) -// return; - - try { - if (enTag.getUpdateSequenceNum() > 0) { - logger.log(logger.EXTREME, "Updating tag"); - sequence = noteStore.updateTag(authToken, enTag); - } else { - - // Look for a tag with the same name. If one is found, we don't need - // to create another one - logger.log(logger.EXTREME, "New tag. Comparing with remote names"); - boolean found = false; - String oldGuid = enTag.getGuid(); - for (int k=0; k list = conn.getLinkedNotebookTable().getDirtyGuids(); - for (int i=0; i remoteList = new ArrayList(); - status.message.emit(tr("Sending saved searches.")); - - logger.log(logger.EXTREME, "Getting saved searches to compare with local"); - try { - remoteList = noteStore.listSearches(authToken); - } catch (EDAMUserException e1) { - logger.log(logger.LOW, "*** EDAM User Excepton syncLocalTags getting remote saved search List"); - status.message.emit(tr("Error: ") +e1); - logger.log(logger.LOW, e1.toString()); - error = true; - } catch (EDAMSystemException e1) { - logger.log(logger.LOW, "*** EDAM System Excepton syncLocalTags getting remote saved search List"); - status.message.emit(tr("Error: ") +e1); - logger.log(logger.LOW, e1.toString()); - error = true; - } catch (TException e1) { - logger.log(logger.LOW, "*** EDAM Transaction Excepton syncLocalTags getting remote saved search List"); - status.message.emit(tr("Error: ") +e1); - logger.log(logger.LOW, e1.toString()); - error = true; - } - - List searches = conn.getSavedSearchTable().getDirty(); - int sequence; - // Sync the local notebooks with Evernote's - logger.log(logger.EXTREME, "Beginning to send saved searches"); - for (int i=0; i 0) - sequence = noteStore.updateSearch(authToken, enSearch); - else { - logger.log(logger.EXTREME, "New saved search found."); - // Look for a tag with the same name. If one is found, we don't need - // to create another one - boolean found = false; - logger.log(logger.EXTREME, "Matching remote saved search names with local"); - for (int k=0; k dirtyNotes = conn.getNoteTable().getDirty(); + //status.message.emit("Error deleting local note: " +e +" - Continuing"); + //logger.log(logger.LOW, e.toString()); + //error = true; + } catch (TException e) { + logger.log(logger.LOW, "*** EDAM TExcepton syncLocalNotes "+e); + status.message.emit(tr("Error sending local note: ") +e); + logger.log(logger.LOW, e.toString()); + error = true; + } + } + } + // Sync notes with Evernote + private void syncLocalNotes() { + logger.log(logger.HIGH, "Entering SyncRunner.syncNotes"); + logger.log(logger.LOW, "Dirty local notes found: " +new Integer(conn.getNoteTable().getDirtyCount()).toString()); + status.message.emit(tr("Sending local notes.")); + + List notes = conn.getNoteTable().getDirty(); + // Sync the local notebooks with Evernote's + for (int i=0; i 0) { + logger.log(logger.EXTREME, "Active dirty note found - non new - " +enNote.getGuid()); + logger.log(logger.EXTREME, "Fetching note content"); + enNote = getNoteContent(enNote); + logger.log(logger.MEDIUM, "Updating note : "+ enNote.getGuid() +" " +enNote.getTitle()+""); + enNote = noteStore.updateNote(token, enNote); + } else { + logger.log(logger.EXTREME, "Active dirty found - new note " +enNote.getGuid()); + String oldGuid = enNote.getGuid(); + logger.log(logger.MEDIUM, "Fetching note content"); + enNote = getNoteContent(enNote); + logger.log(logger.MEDIUM, "Creating note : "+ enNote.getGuid() +" " +enNote.getTitle()+""); + enNote = noteStore.createNote(token, enNote); + logger.log(logger.MEDIUM, "New note Guid : "+ enNote.getGuid() +" " +enNote.getTitle()+""); + noteSignal.guidChanged.emit(oldGuid, enNote.getGuid()); + conn.getNoteTable().updateNoteGuid(oldGuid, enNote.getGuid()); + } + updateSequenceNumber = enNote.getUpdateSequenceNum(); + logger.log(logger.EXTREME, "Saving note"); + conn.getNoteTable().updateNoteSequence(enNote.getGuid(), enNote.getUpdateSequenceNum()); + List rl = enNote.getResources(); + logger.log(logger.EXTREME, "Getting note resources"); + for (int j=0; j remoteList = new ArrayList(); + try { + logger.log(logger.EXTREME, "Getting remote notebooks to compare with local"); + remoteList = noteStore.listNotebooks(authToken); + } catch (EDAMUserException e1) { + logger.log(logger.LOW, "*** EDAM User Excepton syncLocalNotebooks getting remote Notebook List"); + status.message.emit(tr("Error: ") +e1); + logger.log(logger.LOW, e1.toString()); + error = true; + } catch (EDAMSystemException e1) { + logger.log(logger.LOW, "*** EDAM System Excepton syncLocalNotebooks getting remote Notebook List"); + status.message.emit(tr("Error: ") +e1); + logger.log(logger.LOW, e1.toString()); + error = true; + } catch (TException e1) { + logger.log(logger.LOW, "*** EDAM Transaction Excepton syncLocalNotebooks getting remote Notebook List"); + status.message.emit(tr("Error: ") +e1); + logger.log(logger.LOW, e1.toString()); + error = true; + } + logger.log(logger.EXTREME, "Getting local dirty notebooks"); + List notebooks = conn.getNotebookTable().getDirty(); + int sequence; + // Sync the local notebooks with Evernote's + for (int i=0; i 0) { + logger.log(logger.EXTREME, "Existing notebook is dirty"); + sequence = noteStore.updateNotebook(authToken, enNotebook); + } else { + logger.log(logger.EXTREME, "New dirty notebook found"); + String oldGuid = enNotebook.getGuid(); + boolean found = false; + + // Look for a notebook with the same name. If one is found, we don't need + // to create another one + logger.log(logger.EXTREME, "Looking for matching notebook name"); + for (int k=0; k remoteList = new ArrayList(); + status.message.emit(tr("Sending local tags.")); + + try { + logger.log(logger.EXTREME, "Getting remote tags to compare names with the local tags"); + remoteList = noteStore.listTags(authToken); + } catch (EDAMUserException e1) { + logger.log(logger.LOW, "*** EDAM User Excepton syncLocalTags getting remote Tag List"); + status.message.emit(tr("Error: ") +e1); + logger.log(logger.LOW, e1.toString()); + error = true; + } catch (EDAMSystemException e1) { + logger.log(logger.LOW, "*** EDAM System Excepton syncLocalTags getting remote Tag List"); + status.message.emit(tr("Error: ") +e1); + logger.log(logger.LOW, e1.toString()); + error = true; + } catch (TException e1) { + logger.log(logger.LOW, "*** EDAM Transaction Excepton syncLocalTags getting remote Tag List"); + status.message.emit(tr("Error: ") +e1); + logger.log(logger.LOW, e1.toString()); + error = true; + } + + int sequence; + + if (badTagSync == null) + badTagSync = new HashMap(); + else + badTagSync.clear(); + + Tag enTag = findNextTag(); + + // This is a hack. Sometimes this function goes flookey and goes into a + // perpetual loop. This causes NeverNote to flood Evernote's servers. + // This is a safety valve to prevent unlimited loops. + int maxCount = conn.getTagTable().getDirty().size()+10; + int loopCount = 0; + + while(enTag!=null && loopCount < maxCount) { + loopCount++; +// if (authRefreshNeeded) +// if (!refreshConnection()) +// return; + + try { + if (enTag.getUpdateSequenceNum() > 0) { + logger.log(logger.EXTREME, "Updating tag"); + sequence = noteStore.updateTag(authToken, enTag); + } else { + + // Look for a tag with the same name. If one is found, we don't need + // to create another one + logger.log(logger.EXTREME, "New tag. Comparing with remote names"); + boolean found = false; + String oldGuid = enTag.getGuid(); + for (int k=0; k list = conn.getLinkedNotebookTable().getDirtyGuids(); + for (int i=0; i remoteList = new ArrayList(); + status.message.emit(tr("Sending saved searches.")); + + logger.log(logger.EXTREME, "Getting saved searches to compare with local"); + try { + remoteList = noteStore.listSearches(authToken); + } catch (EDAMUserException e1) { + logger.log(logger.LOW, "*** EDAM User Excepton syncLocalTags getting remote saved search List"); + status.message.emit(tr("Error: ") +e1); + logger.log(logger.LOW, e1.toString()); + error = true; + } catch (EDAMSystemException e1) { + logger.log(logger.LOW, "*** EDAM System Excepton syncLocalTags getting remote saved search List"); + status.message.emit(tr("Error: ") +e1); + logger.log(logger.LOW, e1.toString()); + error = true; + } catch (TException e1) { + logger.log(logger.LOW, "*** EDAM Transaction Excepton syncLocalTags getting remote saved search List"); + status.message.emit(tr("Error: ") +e1); + logger.log(logger.LOW, e1.toString()); + error = true; + } + + List searches = conn.getSavedSearchTable().getDirty(); + int sequence; + // Sync the local notebooks with Evernote's + logger.log(logger.EXTREME, "Beginning to send saved searches"); + for (int i=0; i 0) + sequence = noteStore.updateSearch(authToken, enSearch); + else { + logger.log(logger.EXTREME, "New saved search found."); + // Look for a tag with the same name. If one is found, we don't need + // to create another one + boolean found = false; + logger.log(logger.EXTREME, "Matching remote saved search names with local"); + for (int k=0; k dirtyNotes = conn.getNoteTable().getDirty(); dirtyNoteGuids = new ArrayList(); - for (int i=0; i 0 && keepRunning) { - logger.log(logger.EXTREME, "emitting sequence number to main thread"); - updateSequenceNumber = chunk.getChunkHighUSN(); - conn.getSyncTable().setLastSequenceDate(chunk.getCurrentTime()); - conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber); -// conn.commitTransaction(); - } - - - if (more) { - long pct = chunk.getChunkHighUSN() * 100; - conn.getSyncTable().setLastSequenceDate(chunk.getCurrentTime()); - pct = pct/evernoteUpdateCount; - status.message.emit(tr("Downloading ") +new Long(pct).toString()+tr("% complete.")); - } -// conn.commitTransaction(); - } - logger.log(logger.HIGH, "Leaving SyncRunner.syncRemoteToLocal"); - } - // Sync expunged notes - private void syncExpungedNotes(SyncChunk chunk) { - // Do the local deletes - logger.log(logger.EXTREME, "Doing local deletes"); - List guid = chunk.getExpungedNotes(); - if (guid != null) { - for (int i=0; i 0 && keepRunning) { + logger.log(logger.EXTREME, "emitting sequence number to main thread"); + updateSequenceNumber = chunk.getChunkHighUSN(); + conn.getSyncTable().setLastSequenceDate(chunk.getCurrentTime()); + conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber); +// conn.commitTransaction(); + } + + + if (more) { + long pct = chunk.getChunkHighUSN() * 100; + conn.getSyncTable().setLastSequenceDate(chunk.getCurrentTime()); + pct = pct/evernoteUpdateCount; + status.message.emit(tr("Downloading ") +new Long(pct).toString()+tr("% complete.")); + } +// conn.commitTransaction(); + } + logger.log(logger.HIGH, "Leaving SyncRunner.syncRemoteToLocal"); + } + // Sync expunged notes + private void syncExpungedNotes(SyncChunk chunk) { + // Do the local deletes + logger.log(logger.EXTREME, "Doing local deletes"); + List guid = chunk.getExpungedNotes(); + if (guid != null) { + for (int i=0; i tags) { + logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteTags"); + if (tags != null) { + for (int i=0; i searches) { + logger.log(logger.EXTREME, "Entering SyncRunner.syncSavedSearches"); + if (searches != null) { + for (int i=0; i books) { + logger.log(logger.EXTREME, "Entering SyncRunner.syncLinkedNotebooks"); + if (books != null) { + for (int i=0; i notebooks) { + logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteNotebooks"); + if (notebooks != null) { + for (int i=0; i 0) { +// conn.getSharedNotebookTable().expungeNotebookByGuid(notebooks.get(i).getGuid(), false); +// for (int j=0; j books = noteStore.getSharedNotebookByAuth(authToken); +// } + // Sync remote Resources + private void syncRemoteResources(Client noteStore, List resource) { + logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteResources"); + if (resource != null) { + for (int i=0; i note, boolean fullSync, String token) { - } - // Sync remote tags - private void syncRemoteTags(List tags) { - logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteTags"); - if (tags != null) { - for (int i=0; i searches) { - logger.log(logger.EXTREME, "Entering SyncRunner.syncSavedSearches"); - if (searches != null) { - for (int i=0; i books) { - logger.log(logger.EXTREME, "Entering SyncRunner.syncLinkedNotebooks"); - if (books != null) { - for (int i=0; i notebooks) { - logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteNotebooks"); - if (notebooks != null) { - for (int i=0; i 0) { -// conn.getSharedNotebookTable().expungeNotebookByGuid(notebooks.get(i).getGuid(), false); -// for (int j=0; j books = noteStore.getSharedNotebookByAuth(authToken); -// } - // Sync remote Resources - private void syncRemoteResources(Client noteStore, List resource) { - logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteResources"); - if (resource != null) { - for (int i=0; i note, boolean fullSync, String token) { - - if (note != null) { + if (note != null) { logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteNotes"); logger.log(logger.LOW, "Local Dirty Notes: "); @@ -1278,127 +1285,127 @@ public class SyncRunner extends QObject implements Runnable { } logger.log(logger.LOW, "---"); - for (int i=0; i books = conn.getNotebookTable().getAllLocal(); - String notebookGuid = null; - for (int i=0; i>> 4) & 0x0F; - int two_halfs = 0; - do { - if ((0 <= halfbyte) && (halfbyte <= 9)) - buf.append((char) ('0' + halfbyte)); - else - buf.append((char) ('a' + (halfbyte - 10))); - halfbyte = element & 0x0F; - } while(two_halfs++ < 1); - } - return buf.toString(); - } - - - - //******************************************************* - //* Find dirty tags, which do not have newly created parents - //******************************************************* - private Tag findNextTag() { - logger.log(logger.HIGH, "Entering SyncRunner.findNextTag"); - Tag nextTag = null; - List tags = conn.getTagTable().getDirty(); - - // Find the parent. If the parent has a sequence > 0 then it is a good - // parent. - for (int i=0; i 0) { - logger.log(logger.HIGH, "Leaving SyncRunner.findNextTag - tag found"); - return tags.get(i); - } - } - } - - logger.log(logger.HIGH, "Leaving SyncRunner.findNextTag - no tags returned"); - return nextTag; - } - - - // Connect to Evernote - public boolean enConnect() { - try { - userStoreTrans = new THttpClient(userStoreUrl); - userStoreTrans.setCustomHeader("User-Agent", userAgent); - } catch (TTransportException e) { - QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Transport Excepton", e.getLocalizedMessage()); - mb.exec(); - e.printStackTrace(); - } - userStoreProt = new TBinaryProtocol(userStoreTrans); - userStore = new UserStore.Client(userStoreProt, userStoreProt); - syncSignal.saveUserStore.emit(userStore); - try { - //authResult = userStore.authenticate(username, password, consumerKey, consumerSecret); - user = userStore.getUser(authToken); - } catch (EDAMUserException e) { - QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Error", "Invalid Authorization"); - mb.exec(); - isConnected = false; - return false; - } catch (EDAMSystemException e) { - QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "EDAM System Excepton", e.getLocalizedMessage()); - mb.exec(); - e.printStackTrace(); - isConnected = false; - } catch (TException e) { - QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Transport Excepton", e.getLocalizedMessage()); - mb.exec(); - e.printStackTrace(); - isConnected = false; - } - - boolean versionOk = false; - try { - versionOk = userStore.checkVersion("NixNote", - com.evernote.edam.userstore.Constants.EDAM_VERSION_MAJOR, - com.evernote.edam.userstore.Constants.EDAM_VERSION_MINOR); - } catch (TException e) { - e.printStackTrace(); - isConnected = false; - } - if (!versionOk) { - System.err.println("Incomatible EDAM client protocol version"); - isConnected = false; - } - //if (authResult != null) { - //user = authResult.getUser(); - //authToken = authResult.getAuthenticationToken(); + return false; + return true; + } + + private void moveConflictingNote(String guid) { + logger.log(logger.EXTREME, "Conflicting change found for note " +guid); + List books = conn.getNotebookTable().getAllLocal(); + String notebookGuid = null; + for (int i=0; i>> 4) & 0x0F; + int two_halfs = 0; + do { + if ((0 <= halfbyte) && (halfbyte <= 9)) + buf.append((char) ('0' + halfbyte)); + else + buf.append((char) ('a' + (halfbyte - 10))); + halfbyte = element & 0x0F; + } while(two_halfs++ < 1); + } + return buf.toString(); + } + + + + //******************************************************* + //* Find dirty tags, which do not have newly created parents + //******************************************************* + private Tag findNextTag() { + logger.log(logger.HIGH, "Entering SyncRunner.findNextTag"); + Tag nextTag = null; + List tags = conn.getTagTable().getDirty(); + + // Find the parent. If the parent has a sequence > 0 then it is a good + // parent. + for (int i=0; i 0) { + logger.log(logger.HIGH, "Leaving SyncRunner.findNextTag - tag found"); + return tags.get(i); + } + } + } + + logger.log(logger.HIGH, "Leaving SyncRunner.findNextTag - no tags returned"); + return nextTag; + } + + + // Connect to Evernote + public boolean enConnect() { + try { + userStoreTrans = new THttpClient(userStoreUrl); + userStoreTrans.setCustomHeader("User-Agent", userAgent); + } catch (TTransportException e) { + QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Transport Excepton", e.getLocalizedMessage()); + mb.exec(); + e.printStackTrace(); + } + userStoreProt = new TBinaryProtocol(userStoreTrans); + userStore = new UserStore.Client(userStoreProt, userStoreProt); + syncSignal.saveUserStore.emit(userStore); + try { + //authResult = userStore.authenticate(username, password, consumerKey, consumerSecret); + user = userStore.getUser(authToken); + } catch (EDAMUserException e) { + QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Error", "Invalid Authorization"); + mb.exec(); + isConnected = false; + return false; + } catch (EDAMSystemException e) { + QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "EDAM System Excepton", e.getLocalizedMessage()); + mb.exec(); + e.printStackTrace(); + isConnected = false; + } catch (TException e) { + QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Transport Excepton", e.getLocalizedMessage()); + mb.exec(); + e.printStackTrace(); + isConnected = false; + } + + boolean versionOk = false; + try { + versionOk = userStore.checkVersion("NeighborNote", + com.evernote.edam.userstore.Constants.EDAM_VERSION_MAJOR, + com.evernote.edam.userstore.Constants.EDAM_VERSION_MINOR); + } catch (TException e) { + e.printStackTrace(); + isConnected = false; + } + if (!versionOk) { + System.err.println("Incomatible EDAM client protocol version"); + isConnected = false; + } + //if (authResult != null) { + //user = authResult.getUser(); + //authToken = authResult.getAuthenticationToken(); if (user == null || noteStoreUrlBase == null) { logger.log(logger.LOW, "Error retrieving user information. Aborting."); System.err.println("Error retrieving user information."); @@ -1592,545 +1599,545 @@ public class SyncRunner extends QObject implements Runnable { return false; } - noteStoreUrl = noteStoreUrlBase + user.getShardId(); - syncSignal.saveAuthToken.emit(authToken); - syncSignal.saveNoteStore.emit(localNoteStore); - - - try { - noteStoreTrans = new THttpClient(noteStoreUrl); - noteStoreTrans.setCustomHeader("User-Agent", userAgent); - } catch (TTransportException e) { - QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Transport Excepton", e.getLocalizedMessage()); - mb.exec(); - e.printStackTrace(); - isConnected = false; - } - noteStoreProt = new TBinaryProtocol(noteStoreTrans); - localNoteStore = - new NoteStore.Client(noteStoreProt, noteStoreProt); - isConnected = true; - //authTimeRemaining = authResult.getExpiration() - authResult.getCurrentTime(); - //authRefreshTime = authTimeRemaining / 2; - //} - - // Get user information - try { - User user = userStore.getUser(authToken); - syncSignal.saveUserInformation.emit(user); - } catch (EDAMUserException e1) { - e1.printStackTrace(); - } catch (EDAMSystemException e1) { - e1.printStackTrace(); - } catch (TException e1) { - e1.printStackTrace(); - } - - return isConnected; - } - // Disconnect from the database - public void enDisconnect() { - isConnected = false; - } - - /* - // Refresh the connection - private synchronized boolean refreshConnection() { - - logger.log(logger.EXTREME, "Entering SyncRunner.refreshConnection()"); -// Calendar cal = Calendar.getInstance(); - - // If we are not connected let's get out of here - if (!isConnected) - return false; - - // If we fail too many times, then let's give up. - if (failedRefreshes >=5) { - logger.log(logger.EXTREME, "Refresh attempts have failed. Disconnecting."); - isConnected = false; - status.message.emit(tr("Unable to synchronize - Authentication failed")); - return false; - } - - // If this is the first time through, then we need to set this -// if (authRefreshTime == 0 || cal.getTimeInMillis() > authRefreshTime) -// authRefreshTime = cal.getTimeInMillis(); - - // // Default to checking again in 5 min. This in case we fail. - // authRefreshTime = authRefreshTime +(5*60*1000); - - // Try to get a new token - AuthenticationResult newAuth = null; - logger.log(logger.EXTREME, "Beginning to try authentication refresh"); - try { - if (userStore != null && authToken != null) - newAuth = userStore.refreshAuthentication(authToken); - else - return false; - logger.log(logger.EXTREME, "UserStore.refreshAuthentication has succeeded."); - } catch (EDAMUserException e) { - e.printStackTrace(); - syncSignal.authRefreshComplete.emit(false); - failedRefreshes++; - return false; - } catch (EDAMSystemException e) { - e.printStackTrace(); - syncSignal.authRefreshComplete.emit(false); - failedRefreshes++; - return false; - } catch (TException e) { - e.printStackTrace(); - syncSignal.authRefreshComplete.emit(false); - failedRefreshes++; - return false; - } - - // If we didn't get a good auth, then we've failed - if (newAuth == null) { - failedRefreshes++; - status.message.emit(tr("Unable to synchronize - Authentication failed")); - logger.log(logger.EXTREME, "Authentication failure #" +failedRefreshes); - status.message.emit(tr("Unable to synchronize - Authentication failed")); - syncSignal.authRefreshComplete.emit(false); - return false; - } - - // We got a good token. Now we need to setup the time to renew it. - logger.log(logger.EXTREME, "Saving authentication tokens"); - authResult = newAuth; - authToken = new String(newAuth.getAuthenticationToken()); -// authTimeRemaining = authResult.getExpiration() - authResult.getCurrentTime(); -// authRefreshTime = cal.getTimeInMillis() + (authTimeRemaining/4); - failedRefreshes=0; - syncSignal.authRefreshComplete.emit(true); - authRefreshNeeded = false; - - // This should never happen, but if it does we consider this a faild attempt. -// if (authTimeRemaining <= 0) { -// failedRefreshes++; -// syncSignal.authRefreshComplete.emit(false); -// } - - return true; - } - - */ - - public synchronized boolean addWork(String request) { - if (workQueue.offer(request)) - return true; - return false; - } - - private Note getNoteContent(Note n) { - QTextCodec codec = QTextCodec.codecForLocale(); - codec = QTextCodec.codecForName("UTF-8"); - n.setContent(codec.toUnicode(new QByteArray(n.getContent()))); - return n; - } - - - - //********************************************************* - //* Special download instructions. Used for DB upgrades - //********************************************************* - private void downloadAllSharedNotebooks(Client noteStore) { - try { - List books = noteStore.listSharedNotebooks(authToken); - logger.log(logger.LOW, "Shared notebooks found = " +books.size()); - for (int i=0; i books = noteStore.listNotebooks(authToken); - logger.log(logger.LOW, "Shared notebooks found = " +books.size()); - for (int i=0; i books = noteStore.listLinkedNotebooks(authToken); - logger.log(logger.LOW, "Linked notebooks found = " +books.size()); - for (int i=0; i nvps = new ArrayList (); - nvps.add(new BasicNameValuePair("auth", authToken)); - - try { - post.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8)); - } catch (UnsupportedEncodingException e1) { - e1.printStackTrace(); - } - try { - HttpResponse response = http.execute(post); - HttpEntity resEntity = response.getEntity(); - InputStream is = resEntity.getContent(); - QByteArray data = writeToFile(is); - conn.getInkImagesTable().saveImage(guid, slice, data); - } catch (ClientProtocolException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - - slice++; - } - http.getConnectionManager().shutdown(); - noteSignal.noteChanged.emit(r.getNoteGuid(), null); // Signal to ivalidate note cache - } - - - public QByteArray writeToFile(InputStream iStream) throws IOException { - - File temp = File.createTempFile("nn-inknote-temp", ".png"); - - // Save InputStream to the file. - BufferedOutputStream fOut = null; - try { - fOut = new BufferedOutputStream(new FileOutputStream(temp)); - byte[] buffer = new byte[32 * 1024]; - int bytesRead = 0; - while ((bytesRead = iStream.read(buffer)) != -1) { - fOut.write(buffer, 0, bytesRead); - } - } - finally { - iStream.close(); - fOut.close(); - } - QFile tempFile = new QFile(temp.getAbsoluteFile().toString()); - tempFile.open(OpenModeFlag.ReadOnly); - QByteArray data = tempFile.readAll(); - tempFile.close(); - tempFile.remove(); - return data; - } - - - //****************************************** - //* Begin syncing shared notebooks - //****************************************** - private void syncLinkedNotebooks() { - logger.log(logger.MEDIUM, "Authenticating linked Notebooks"); - status.message.emit(tr("Synchronizing shared notebooks.")); - List books = conn.getLinkedNotebookTable().getAll(); - - errorSharedNotebooks.clear(); - - for (int i=0; i lastSequenceNumber) { - logger.log(logger.EXTREME, "Remote changes found"); - if (lastSyncDate < linkedSyncState.getFullSyncBefore()) { - lastSequenceNumber = 0; - } - logger.log(logger.EXTREME, "Calling syncLinkedNotebook for " +books.get(i).getShareName()); - syncLinkedNotebook(linkedNoteStore, books.get(i), - lastSequenceNumber, linkedSyncState.getUpdateCount(), authToken); - } - - // Synchronize local changes - syncLocalLinkedNoteChanges(linkedNoteStore, books.get(i)); - - } catch (EDAMUserException e) { - e.printStackTrace(); - } catch (EDAMNotFoundException e) { - status.message.emit(tr("Error synchronizing \" " + - books.get(i).getShareName()+"\". Please verify you still have access to that shared notebook.")); - errorSharedNotebooks.add(books.get(i).getGuid()); - errorSharedNotebooksIgnored.put(books.get(i).getGuid(), books.get(i).getGuid()); - logger.log(logger.LOW, "Error synchronizing shared notebook. EDAMNotFound: "+e.getMessage()); - logger.log(logger.LOW, e.getStackTrace()); - error = true; - e.printStackTrace(); - } catch (EDAMSystemException e) { - error = true; - logger.log(logger.LOW, "System error authenticating against shared notebook. "+ - "Key: "+books.get(i).getShareKey() +" Error:" +e.getMessage()); - e.printStackTrace(); - } catch (TException e) { - error = true; - e.printStackTrace(); - } - } - - // Cleanup tags - conn.getTagTable().removeUnusedLinkedTags(); - conn.getTagTable().cleanupTags(); - tagSignal.listChanged.emit(); - return; - } - - - //************************************************************** - //* Linked notebook contents (from someone else's account) - //************************************************************* - private void syncLinkedNotebook(Client linkedNoteStore, LinkedNotebook book, int usn, int highSequence, String token) { - logger.log(logger.EXTREME, "Entering syncLinkedNotebook"); - if (ignoreLinkedNotebooks.contains(book.getGuid())) - return; - List dirtyNotes = conn.getNoteTable().getDirtyLinkedNotes(); - if (dirtyNoteGuids == null) + noteStoreUrl = noteStoreUrlBase + user.getShardId(); + syncSignal.saveAuthToken.emit(authToken); + syncSignal.saveNoteStore.emit(localNoteStore); + + + try { + noteStoreTrans = new THttpClient(noteStoreUrl); + noteStoreTrans.setCustomHeader("User-Agent", userAgent); + } catch (TTransportException e) { + QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Transport Excepton", e.getLocalizedMessage()); + mb.exec(); + e.printStackTrace(); + isConnected = false; + } + noteStoreProt = new TBinaryProtocol(noteStoreTrans); + localNoteStore = + new NoteStore.Client(noteStoreProt, noteStoreProt); + isConnected = true; + //authTimeRemaining = authResult.getExpiration() - authResult.getCurrentTime(); + //authRefreshTime = authTimeRemaining / 2; + //} + + // Get user information + try { + User user = userStore.getUser(authToken); + syncSignal.saveUserInformation.emit(user); + } catch (EDAMUserException e1) { + e1.printStackTrace(); + } catch (EDAMSystemException e1) { + e1.printStackTrace(); + } catch (TException e1) { + e1.printStackTrace(); + } + + return isConnected; + } + // Disconnect from the database + public void enDisconnect() { + isConnected = false; + } + + /* + // Refresh the connection + private synchronized boolean refreshConnection() { + + logger.log(logger.EXTREME, "Entering SyncRunner.refreshConnection()"); +// Calendar cal = Calendar.getInstance(); + + // If we are not connected let's get out of here + if (!isConnected) + return false; + + // If we fail too many times, then let's give up. + if (failedRefreshes >=5) { + logger.log(logger.EXTREME, "Refresh attempts have failed. Disconnecting."); + isConnected = false; + status.message.emit(tr("Unable to synchronize - Authentication failed")); + return false; + } + + // If this is the first time through, then we need to set this +// if (authRefreshTime == 0 || cal.getTimeInMillis() > authRefreshTime) +// authRefreshTime = cal.getTimeInMillis(); + + // // Default to checking again in 5 min. This in case we fail. + // authRefreshTime = authRefreshTime +(5*60*1000); + + // Try to get a new token + AuthenticationResult newAuth = null; + logger.log(logger.EXTREME, "Beginning to try authentication refresh"); + try { + if (userStore != null && authToken != null) + newAuth = userStore.refreshAuthentication(authToken); + else + return false; + logger.log(logger.EXTREME, "UserStore.refreshAuthentication has succeeded."); + } catch (EDAMUserException e) { + e.printStackTrace(); + syncSignal.authRefreshComplete.emit(false); + failedRefreshes++; + return false; + } catch (EDAMSystemException e) { + e.printStackTrace(); + syncSignal.authRefreshComplete.emit(false); + failedRefreshes++; + return false; + } catch (TException e) { + e.printStackTrace(); + syncSignal.authRefreshComplete.emit(false); + failedRefreshes++; + return false; + } + + // If we didn't get a good auth, then we've failed + if (newAuth == null) { + failedRefreshes++; + status.message.emit(tr("Unable to synchronize - Authentication failed")); + logger.log(logger.EXTREME, "Authentication failure #" +failedRefreshes); + status.message.emit(tr("Unable to synchronize - Authentication failed")); + syncSignal.authRefreshComplete.emit(false); + return false; + } + + // We got a good token. Now we need to setup the time to renew it. + logger.log(logger.EXTREME, "Saving authentication tokens"); + authResult = newAuth; + authToken = new String(newAuth.getAuthenticationToken()); +// authTimeRemaining = authResult.getExpiration() - authResult.getCurrentTime(); +// authRefreshTime = cal.getTimeInMillis() + (authTimeRemaining/4); + failedRefreshes=0; + syncSignal.authRefreshComplete.emit(true); + authRefreshNeeded = false; + + // This should never happen, but if it does we consider this a faild attempt. +// if (authTimeRemaining <= 0) { +// failedRefreshes++; +// syncSignal.authRefreshComplete.emit(false); +// } + + return true; + } + + */ + + public synchronized boolean addWork(String request) { + if (workQueue.offer(request)) + return true; + return false; + } + + private Note getNoteContent(Note n) { + QTextCodec codec = QTextCodec.codecForLocale(); + codec = QTextCodec.codecForName("UTF-8"); + n.setContent(codec.toUnicode(new QByteArray(n.getContent()))); + return n; + } + + + + //********************************************************* + //* Special download instructions. Used for DB upgrades + //********************************************************* + private void downloadAllSharedNotebooks(Client noteStore) { + try { + List books = noteStore.listSharedNotebooks(authToken); + logger.log(logger.LOW, "Shared notebooks found = " +books.size()); + for (int i=0; i books = noteStore.listNotebooks(authToken); + logger.log(logger.LOW, "Shared notebooks found = " +books.size()); + for (int i=0; i books = noteStore.listLinkedNotebooks(authToken); + logger.log(logger.LOW, "Linked notebooks found = " +books.size()); + for (int i=0; i nvps = new ArrayList (); + nvps.add(new BasicNameValuePair("auth", authToken)); + + try { + post.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8)); + } catch (UnsupportedEncodingException e1) { + e1.printStackTrace(); + } + try { + HttpResponse response = http.execute(post); + HttpEntity resEntity = response.getEntity(); + InputStream is = resEntity.getContent(); + QByteArray data = writeToFile(is); + conn.getInkImagesTable().saveImage(guid, slice, data); + } catch (ClientProtocolException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + + slice++; + } + http.getConnectionManager().shutdown(); + noteSignal.noteChanged.emit(r.getNoteGuid(), null); // Signal to ivalidate note cache + } + + + public QByteArray writeToFile(InputStream iStream) throws IOException { + + File temp = File.createTempFile("nn-inknote-temp", ".png"); + + // Save InputStream to the file. + BufferedOutputStream fOut = null; + try { + fOut = new BufferedOutputStream(new FileOutputStream(temp)); + byte[] buffer = new byte[32 * 1024]; + int bytesRead = 0; + while ((bytesRead = iStream.read(buffer)) != -1) { + fOut.write(buffer, 0, bytesRead); + } + } + finally { + iStream.close(); + fOut.close(); + } + QFile tempFile = new QFile(temp.getAbsoluteFile().toString()); + tempFile.open(OpenModeFlag.ReadOnly); + QByteArray data = tempFile.readAll(); + tempFile.close(); + tempFile.remove(); + return data; + } + + + //****************************************** + //* Begin syncing shared notebooks + //****************************************** + private void syncLinkedNotebooks() { + logger.log(logger.MEDIUM, "Authenticating linked Notebooks"); + status.message.emit(tr("Synchronizing shared notebooks.")); + List books = conn.getLinkedNotebookTable().getAll(); + + errorSharedNotebooks.clear(); + + for (int i=0; i lastSequenceNumber) { + logger.log(logger.EXTREME, "Remote changes found"); + if (lastSyncDate < linkedSyncState.getFullSyncBefore()) { + lastSequenceNumber = 0; + } + logger.log(logger.EXTREME, "Calling syncLinkedNotebook for " +books.get(i).getShareName()); + syncLinkedNotebook(linkedNoteStore, books.get(i), + lastSequenceNumber, linkedSyncState.getUpdateCount(), authToken); + } + + // Synchronize local changes + syncLocalLinkedNoteChanges(linkedNoteStore, books.get(i)); + + } catch (EDAMUserException e) { + e.printStackTrace(); + } catch (EDAMNotFoundException e) { + status.message.emit(tr("Error synchronizing \" " + + books.get(i).getShareName()+"\". Please verify you still have access to that shared notebook.")); + errorSharedNotebooks.add(books.get(i).getGuid()); + errorSharedNotebooksIgnored.put(books.get(i).getGuid(), books.get(i).getGuid()); + logger.log(logger.LOW, "Error synchronizing shared notebook. EDAMNotFound: "+e.getMessage()); + logger.log(logger.LOW, e.getStackTrace()); + error = true; + e.printStackTrace(); + } catch (EDAMSystemException e) { + error = true; + logger.log(logger.LOW, "System error authenticating against shared notebook. "+ + "Key: "+books.get(i).getShareKey() +" Error:" +e.getMessage()); + e.printStackTrace(); + } catch (TException e) { + error = true; + e.printStackTrace(); + } + } + + // Cleanup tags + conn.getTagTable().removeUnusedLinkedTags(); + conn.getTagTable().cleanupTags(); + tagSignal.listChanged.emit(); + return; + } + + + //************************************************************** + //* Linked notebook contents (from someone else's account) + //************************************************************* + private void syncLinkedNotebook(Client linkedNoteStore, LinkedNotebook book, int usn, int highSequence, String token) { + logger.log(logger.EXTREME, "Entering syncLinkedNotebook"); + if (ignoreLinkedNotebooks.contains(book.getGuid())) + return; + List dirtyNotes = conn.getNoteTable().getDirtyLinkedNotes(); + if (dirtyNoteGuids == null) dirtyNoteGuids = new ArrayList(); - - for (int i=0; i tags, String notebookGuid) { - logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteTags"); - if (tags != null) { - for (int i=0; i notebooks, boolean readOnly, LinkedNotebook linked) { - logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteNotebooks"); - if (notebooks != null) { - for (int i=0; i newNotes, String token) { - if (newNotes == null) - return; - for (int i=0; i notes = conn.getNoteTable().getDirtyLinked(notebookGuid); - logger.log(logger.EXTREME, "Number of changes found: " +notes.size()); - for (int i=0; i tags, String notebookGuid) { + logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteTags"); + if (tags != null) { + for (int i=0; i notebooks, boolean readOnly, LinkedNotebook linked) { + logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteNotebooks"); + if (notebooks != null) { + for (int i=0; i newNotes, String token) { + if (newNotes == null) + return; + for (int i=0; i notes = conn.getNoteTable().getDirtyLinked(notebookGuid); + logger.log(logger.EXTREME, "Number of changes found: " +notes.size()); + for (int i=0; i workQueue; - private static int MAX_QUEUED_WAITING = 1000; - public QMutex mutex; - - - - public ThumbnailRunner(String logname, String u, String i, String r, String uid, String pswd, String cpswd) { - logger = new ApplicationLogger(logname); - conn = new DatabaseConnection(logger, u, i, r, uid, pswd, cpswd, 300); - noteSignal = new NoteSignal(); - guid = null; - keepRunning = true; - mutex = new QMutex(); - workQueue=new LinkedBlockingQueue(MAX_QUEUED_WAITING); - } - - - @Override - public void run() { - thread().setPriority(Thread.MIN_PRIORITY); - - logger.log(logger.MEDIUM, "Starting thumbnail thread "); - while (keepRunning) { - try { - interrupt = false; - String work = workQueue.take(); - if (work.startsWith("GENERATE")) { - work = work.replace("GENERATE ", ""); - guid = work; - generateThumbnail(); - } - if (work.startsWith("SCAN")) { - if (conn.getNoteTable().getThumbnailNeededCount() > 1) - scanDatabase(); - } - if (work.startsWith("IMAGE")) { - work = work.replace("IMAGE ", ""); - guid = work; - processImage(); - } - if (work.startsWith("STOP")) { - logger.log(logger.MEDIUM, "Stopping thumbail thread"); - keepRunning = false; - } - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - conn.dbShutdown(); - } - - - private void processImage() { - boolean abort = true; - if (abort) - return; - mutex.lock(); - logger.log(logger.EXTREME, "Image found "+guid); - - logger.log(logger.EXTREME, "Getting image"); - QPixmap image = new QPixmap(); - if (!image.load(Global.getFileManager().getResDirPath()+"thumbnail-"+guid+".png")) { - logger.log(logger.EXTREME, "Failure to reload image. Aborting."); - mutex.unlock(); - return; - } - - - logger.log(logger.EXTREME, "Opening buffer"); - QBuffer buffer = new QBuffer(); - if (!buffer.open(QIODevice.OpenModeFlag.WriteOnly)) { - logger.log(logger.EXTREME, "Failure to open buffer. Aborting."); - mutex.unlock(); - return; - } - - logger.log(logger.EXTREME, "Filling buffer"); - if (!image.save(buffer, "PNG")) { - logger.log(logger.EXTREME, "Failure to write to buffer. Aborting."); - mutex.unlock(); - return; - } - buffer.close(); - - logger.log(logger.EXTREME, "Updating database"); - QByteArray b = new QBuffer(buffer).buffer(); - conn.getNoteTable().setThumbnail(guid, b); - conn.getNoteTable().setThumbnailNeeded(guid, false); - mutex.unlock(); - } - - - - private void scanDatabase() { - // If there is already work in the queue, that takes priority - logger.log(logger.HIGH, "Scanning database for notes needing thumbnail"); - if (workQueue.size() > 0) - return; - - // Find a few records that need thumbnails - List guids = conn.getNoteTable().findThumbnailsNeeded(); - logger.log(logger.HIGH, guids.size() +" records returned"); - for (int i=0; i tempFiles = new ArrayList(); - Note currentNote = conn.getNoteTable().getNote(guid,true,true,false,true,false); - NoteFormatter formatter = new NoteFormatter(logger, conn, tempFiles); - currentNote = conn.getNoteTable().getNote(guid, true, true, false, true, false); - formatter.setNote(currentNote, true); - formatter.setHighlight(null); - js.append(""); - js.append(""); - js.append(""); - js.append(""); - js.append(""); - js.append(""); - js.append(formatter.rebuildNoteHTML()); - js.append(""); - js.replace("", ""); - js.replace("", ""); - js.replace("", ""); - int zoom = 1; - if (currentNote != null && currentNote.getContent() != null) { - String content = currentNote.getContent(); - zoom = Global.calculateThumbnailZoom(content); - } - logger.log(logger.HIGH, "Thumbnail file ready"); - noteSignal.thumbnailPageReady.emit(guid, js, zoom); - } - - - - -} +/* + * This file is part of NixNote + * Copyright 2009 Randy Baumgarte + * + * This file may be licensed under the terms of of the + * GNU General Public License Version 2 (the ``GPL''). + * + * Software distributed under the License is distributed + * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the GPL for the specific language + * governing rights and limitations. + * + * You should have received a copy of the GPL along with this + * program. If not, go to http://www.gnu.org/licenses/gpl.html + * or write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * +*/ + +package cx.fbn.nevernote.threads; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.LinkedBlockingQueue; + +import com.evernote.edam.type.Note; +import com.trolltech.qt.core.QBuffer; +import com.trolltech.qt.core.QByteArray; +import com.trolltech.qt.core.QIODevice; +import com.trolltech.qt.core.QMutex; +import com.trolltech.qt.core.QObject; +import com.trolltech.qt.core.QTemporaryFile; +import com.trolltech.qt.gui.QPixmap; + +import cx.fbn.nevernote.Global; +import cx.fbn.nevernote.signals.NoteSignal; +import cx.fbn.nevernote.sql.DatabaseConnection; +import cx.fbn.nevernote.utilities.ApplicationLogger; +import cx.fbn.nevernote.xml.NoteFormatter; + + +/* + * + * @author Randy Baumgarte + * + * Thumbnail Overview: + * + * How thumbnails are generated is a bit odd. The problem is that + * process of creating the thumbnail involves actually creating an HTML + * version of the note & all of its resources. That is very CPU intensive + * so we try to do it in a separate thread. Unfortunately, the QWebPage class + * which actually creates the thumbnail must be in the main GUI thread. + * This is the odd way I've tried to get around the problem. + * + * First, the thumbail thread finds a note which needs a thumbnail. This + * can be done by either scanning the database or specifically being told + * a note needs a new thumbnail. + * + * When a note is found, this thread will read the database and write out + * the resources and create an HTML version of the note. It then signals + * the main GUI thread that a note is ready. + * + * Next, the main GUI thread will process the signal received from the + * thumbnail thread. The GUI thread will create a QWebPage (via the + * Thumbnailer class) and will render the image. The image is written to + * the database to be used in the thumbnail view. + * + */ +public class ThumbnailRunner extends QObject implements Runnable { + + private final ApplicationLogger logger; + private String guid; + public NoteSignal noteSignal; + private boolean keepRunning; + public boolean interrupt; + private final DatabaseConnection conn; + private volatile LinkedBlockingQueue workQueue; + private static int MAX_QUEUED_WAITING = 1000; + public QMutex mutex; + + + // ICHANGED String bを追加 + public ThumbnailRunner(String logname, String u, String i, String r, String b, String uid, String pswd, String cpswd) { + logger = new ApplicationLogger(logname); + // ICHANGED bを追加 + conn = new DatabaseConnection(logger, u, i, r, b, uid, pswd, cpswd, 300); + noteSignal = new NoteSignal(); + guid = null; + keepRunning = true; + mutex = new QMutex(); + workQueue=new LinkedBlockingQueue(MAX_QUEUED_WAITING); + } + + + @Override + public void run() { + thread().setPriority(Thread.MIN_PRIORITY); + + logger.log(logger.MEDIUM, "Starting thumbnail thread "); + while (keepRunning) { + try { + interrupt = false; + String work = workQueue.take(); + if (work.startsWith("GENERATE")) { + work = work.replace("GENERATE ", ""); + guid = work; + generateThumbnail(); + } + if (work.startsWith("SCAN")) { + if (conn.getNoteTable().getThumbnailNeededCount() > 1) + scanDatabase(); + } + if (work.startsWith("IMAGE")) { + work = work.replace("IMAGE ", ""); + guid = work; + processImage(); + } + if (work.startsWith("STOP")) { + logger.log(logger.MEDIUM, "Stopping thumbail thread"); + keepRunning = false; + } + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + conn.dbShutdown(); + } + + + private void processImage() { + boolean abort = true; + if (abort) + return; + mutex.lock(); + logger.log(logger.EXTREME, "Image found "+guid); + + logger.log(logger.EXTREME, "Getting image"); + QPixmap image = new QPixmap(); + if (!image.load(Global.getFileManager().getResDirPath()+"thumbnail-"+guid+".png")) { + logger.log(logger.EXTREME, "Failure to reload image. Aborting."); + mutex.unlock(); + return; + } + + + logger.log(logger.EXTREME, "Opening buffer"); + QBuffer buffer = new QBuffer(); + if (!buffer.open(QIODevice.OpenModeFlag.WriteOnly)) { + logger.log(logger.EXTREME, "Failure to open buffer. Aborting."); + mutex.unlock(); + return; + } + + logger.log(logger.EXTREME, "Filling buffer"); + if (!image.save(buffer, "PNG")) { + logger.log(logger.EXTREME, "Failure to write to buffer. Aborting."); + mutex.unlock(); + return; + } + buffer.close(); + + logger.log(logger.EXTREME, "Updating database"); + QByteArray b = new QBuffer(buffer).buffer(); + conn.getNoteTable().setThumbnail(guid, b); + conn.getNoteTable().setThumbnailNeeded(guid, false); + mutex.unlock(); + } + + + + private void scanDatabase() { + // If there is already work in the queue, that takes priority + logger.log(logger.HIGH, "Scanning database for notes needing thumbnail"); + if (workQueue.size() > 0) + return; + + // Find a few records that need thumbnails + List guids = conn.getNoteTable().findThumbnailsNeeded(); + logger.log(logger.HIGH, guids.size() +" records returned"); + for (int i=0; i tempFiles = new ArrayList(); + Note currentNote = conn.getNoteTable().getNote(guid,true,true,false,true,false); + NoteFormatter formatter = new NoteFormatter(logger, conn, tempFiles); + currentNote = conn.getNoteTable().getNote(guid, true, true, false, true, false); + formatter.setNote(currentNote, true); + formatter.setHighlight(null); + js.append(""); + js.append(""); + js.append(""); + js.append(""); + js.append(""); + js.append(""); + js.append(formatter.rebuildNoteHTML()); + js.append(""); + js.replace("", ""); + js.replace("", ""); + js.replace("", ""); + int zoom = 1; + if (currentNote != null && currentNote.getContent() != null) { + String content = currentNote.getContent(); + zoom = Global.calculateThumbnailZoom(content); + } + logger.log(logger.HIGH, "Thumbnail file ready"); + noteSignal.thumbnailPageReady.emit(guid, js, zoom); + } + + + + +} diff --git a/src/cx/fbn/nevernote/utilities/ListManager.java b/src/cx/fbn/nevernote/utilities/ListManager.java index 864ec58..7927a33 100644 --- a/src/cx/fbn/nevernote/utilities/ListManager.java +++ b/src/cx/fbn/nevernote/utilities/ListManager.java @@ -1,1281 +1,1295 @@ -/* - * This file is part of NixNote - * Copyright 2009 Randy Baumgarte - * - * This file may be licensed under the terms of of the - * GNU General Public License Version 2 (the ``GPL''). - * - * Software distributed under the License is distributed - * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either - * express or implied. See the GPL for the specific language - * governing rights and limitations. - * - * You should have received a copy of the GPL along with this - * program. If not, go to http://www.gnu.org/licenses/gpl.html - * or write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * -*/ - -package cx.fbn.nevernote.utilities; - -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collections; -import java.util.Comparator; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.List; -import java.util.Vector; - -import com.evernote.edam.type.LinkedNotebook; -import com.evernote.edam.type.Note; -import com.evernote.edam.type.Notebook; -import com.evernote.edam.type.SavedSearch; -import com.evernote.edam.type.Tag; -import com.trolltech.qt.QThread; -import com.trolltech.qt.core.QDateTime; -import com.trolltech.qt.gui.QImage; -import com.trolltech.qt.gui.QPixmap; -import com.trolltech.qt.sql.QSqlQuery; -import com.trolltech.qt.xml.QDomAttr; -import com.trolltech.qt.xml.QDomDocument; -import com.trolltech.qt.xml.QDomElement; -import com.trolltech.qt.xml.QDomNodeList; - -import cx.fbn.nevernote.Global; -import cx.fbn.nevernote.evernote.NoteMetadata; -import cx.fbn.nevernote.filters.EnSearch; -import cx.fbn.nevernote.filters.NotebookCounter; -import cx.fbn.nevernote.filters.TagCounter; -import cx.fbn.nevernote.gui.NoteTableModel; -import cx.fbn.nevernote.signals.NotebookSignal; -import cx.fbn.nevernote.signals.StatusSignal; -import cx.fbn.nevernote.signals.TagSignal; -import cx.fbn.nevernote.signals.ThreadSignal; -import cx.fbn.nevernote.signals.TrashSignal; -import cx.fbn.nevernote.sql.DatabaseConnection; -import cx.fbn.nevernote.threads.CounterRunner; -import cx.fbn.nevernote.threads.SaveRunner; - - -public class ListManager { - - - private final ApplicationLogger logger; - DatabaseConnection conn; - QSqlQuery deleteWords; - QSqlQuery insertWords; - - private List tagIndex; - private List notebookIndex; - private List archiveNotebookIndex; - private List localNotebookIndex; - private List linkedNotebookIndex; - - private List searchIndex; - - private List selectedNotebooks; - private final NoteTableModel noteModel; - - - private List selectedTags; - private String selectedSearch; - ThreadSignal signals; - public StatusSignal status; - private final CounterRunner notebookCounterRunner; - private final QThread notebookThread; - private final CounterRunner tagCounterRunner; - private final QThread tagThread; - - private final CounterRunner trashCounterRunner; - private final QThread trashThread; - public TrashSignal trashSignal; - - private List notebookCounter; // count of displayed notes in each notebook - private List tagCounter; // count of displayed notes for each tag - - private EnSearch enSearch; - private boolean enSearchChanged; - public HashMap wordMap; - public TagSignal tagSignal; - public NotebookSignal notebookSignal; - public boolean refreshCounters; // Used to control when to recount lists - private int trashCount; - public SaveRunner saveRunner; // Thread used to save content. Used because the xml conversion is slowwwww - QThread saveThread; - -// private final HashMap thumbnailList; - - // Constructor - public ListManager(DatabaseConnection d, ApplicationLogger l) { - conn = d; - logger = l; - - conn.getTagTable().cleanupTags(); - status = new StatusSignal(); - signals = new ThreadSignal(); - - // setup index locks - enSearchChanged = false; - - // Setup arrays - noteModel = new NoteTableModel(this); - selectedTags = new ArrayList(); - - notebookCounter = new ArrayList(); - tagCounter = new ArrayList(); - selectedNotebooks = new ArrayList(); - - reloadIndexes(); - - notebookSignal = new NotebookSignal(); - notebookCounterRunner = new CounterRunner("notebook_counter.log", CounterRunner.NOTEBOOK, - Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(), - Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword); - notebookCounterRunner.setNoteIndex(getNoteIndex()); - notebookCounterRunner.notebookSignal.countsChanged.connect(this, "setNotebookCounter(List)"); - notebookThread = new QThread(notebookCounterRunner, "Notebook Counter Thread"); - notebookThread.start(); - - tagSignal = new TagSignal(); - tagCounterRunner = new CounterRunner("tag_counter.log", CounterRunner.TAG, - Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(), - Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword); - tagCounterRunner.setNoteIndex(getNoteIndex()); - tagCounterRunner.tagSignal.countsChanged.connect(this, "setTagCounter(List)"); - tagThread = new QThread(tagCounterRunner, "Tag Counter Thread"); - tagThread.start(); - - trashSignal = new TrashSignal(); - trashCounterRunner = new CounterRunner("trash_counter.log", CounterRunner.TRASH, - Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(), - Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword); - trashCounterRunner.trashSignal.countChanged.connect(this, "trashSignalReceiver(Integer)"); - trashThread = new QThread(trashCounterRunner, "Trash Counter Thread"); - trashThread.start(); -// reloadTrashCount(); - - wordMap = new HashMap(); - tagSignal = new TagSignal(); - - logger.log(logger.EXTREME, "Setting save thread"); - saveRunner = new SaveRunner("saveRunner.log", - Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(), - Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword); - saveThread = new QThread(saveRunner, "Save Runner Thread"); - saveThread.start(); - -// thumbnailList = conn.getNoteTable().getThumbnails(); -// thumbnailList = new HashMap(); - - linkedNotebookIndex = conn.getLinkedNotebookTable().getAll(); - loadNoteTitleColors(); - refreshCounters = true; - refreshCounters(); - - } - - public void stop() { - saveRunner.addWork("stop", ""); - tagCounterRunner.release(CounterRunner.EXIT); - notebookCounterRunner.release(CounterRunner.EXIT); - trashCounterRunner.release(CounterRunner.EXIT); - - logger.log(logger.MEDIUM, "Waiting for notebookCounterThread to stop"); - try { - notebookThread.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - logger.log(logger.MEDIUM, "Waiting for tagCounterThread to stop"); - try { - tagThread.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - logger.log(logger.MEDIUM, "Waiting for trashThread to stop"); - try { - trashThread.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - - logger.log(logger.MEDIUM, "Waiting for saveThread to stop"); - try { - saveThread.join(0); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - } - - //*************************************************************** - //*************************************************************** - //* Refresh lists after a db sync - //*************************************************************** - //*************************************************************** - public void refreshLists(Note n, boolean dirty, String content) { - if (dirty) { -// conn.getNoteTable().updateNoteContent(n.getGuid(), n.getContent()); - saveRunner.addWork(n.getGuid(), content); - conn.getNoteTable().updateNoteTitle(n.getGuid(), n.getTitle()); - } - - setSavedSearchIndex(conn.getSavedSearchTable().getAll()); - setTagIndex(conn.getTagTable().getAll()); - setNotebookIndex(conn.getNotebookTable().getAll()); - - List local = conn.getNotebookTable().getAllLocal(); - localNotebookIndex = new ArrayList(); - for (int i=0; i noteTags = conn.getNoteTable().noteTagsTable.getAllNoteTags(); - for (int i=0; i tags = new ArrayList(); - List names = new ArrayList(); - for (int j=0; j local = conn.getNotebookTable().getAllLocal(); - localNotebookIndex = new ArrayList(); - for (int i=0; i noteTags = conn.getNoteTable().noteTagsTable.getAllNoteTags(); - for (int i=0; i tags = new ArrayList(); - List names = new ArrayList(); - for (int j=0; j getSelectedNotebooks() { - return selectedNotebooks; - } - // Set the current selected notebook(s) - public void setSelectedNotebooks(List s) { - if (s == null) - s = new ArrayList(); - selectedNotebooks = s; - } - - - //*************************************************************** - //*************************************************************** - //** These functions deal with setting & retrieving the master lists - //*************************************************************** - //*************************************************************** - // Get the note table model - public NoteTableModel getNoteTableModel() { - return noteModel; - } - // save the saved search index - private void setSavedSearchIndex(List t) { - searchIndex = t; - } - // Retrieve the Tag index - public List getSavedSearchIndex() { - return searchIndex; - - } - // save the tag index - private void setTagIndex(List t) { - tagIndex = t; - } - // Retrieve the Tag index - public List getTagIndex() { - return tagIndex; - } - private void setNotebookIndex(List t) { - notebookIndex = t; - } - private void setArchiveNotebookIndex(List t) { - archiveNotebookIndex = t; - } - // Retrieve the Notebook index - public List getNotebookIndex() { - return notebookIndex; - - } - public List getLinkedNotebookIndex() { - return linkedNotebookIndex; - } - public List getArchiveNotebookIndex() { - return archiveNotebookIndex; - } - // Save the current note list - private void setNoteIndex(List n) { - noteModel.setNoteIndex(n); - refreshNoteMetadata(); - } - public void refreshNoteMetadata() { - noteModel.setNoteMetadata(conn.getNoteTable().getNotesMetaInformation()); - } - // Update a note's meta data - public void updateNoteMetadata(NoteMetadata meta) { - noteModel.metaData.remove(meta); - noteModel.metaData.put(meta.getGuid(), meta); - conn.getNoteTable().updateNoteMetadata(meta); - } - // Get the note index - public synchronized List getNoteIndex() { - return noteModel.getNoteIndex(); - } - // Save the count of notes per notebook - public void setNotebookCounter(List n) { - notebookCounter = n; - notebookSignal.refreshNotebookTreeCounts.emit(getNotebookIndex(), notebookCounter); - } - public List getNotebookCounter() { - return notebookCounter; - } - // Save the count of notes for each tag - public void setTagCounter(List n) { - tagCounter = n; - tagSignal.refreshTagTreeCounts.emit(tagCounter); - } - public List getTagCounter() { - return tagCounter; - } - public List getLocalNotebooks() { - return localNotebookIndex; - } - -// public void setUnsynchronizedNotes(List l) { -// noteModel.setUnsynchronizedNotes(l); -// } - // Return a count of items in the trash - public int getTrashCount() { - return trashCount; - } - // get the EnSearch variable - public EnSearch getEnSearch() { - return enSearch; - } - public List getMasterNoteIndex() { - return noteModel.getMasterNoteIndex(); - } - // Thumbnails -// public HashMap getThumbnails() { -// return thumbnailList; -// } - public HashMap getNoteMetadata() { - return noteModel.metaData; - } - public QImage getThumbnail(String guid) { -// if (getThumbnails().containsKey(guid)) -// return getThumbnails().get(guid); - - QImage img = new QImage(); - img = QImage.fromData(conn.getNoteTable().getThumbnail(guid)); - if (img == null || img.isNull()) - return null; - //getThumbnails().put(guid, img); - return img; - } - public QPixmap getThumbnailPixmap(String guid) { -// if (getThumbnails().containsKey(guid)) -// return getThumbnails().get(guid); - - QPixmap img = new QPixmap(); - img.loadFromData(conn.getNoteTable().getThumbnail(guid)); - if (img == null || img.isNull()) - return null; - //getThumbnails().put(guid, img); - return img; - } - //*************************************************************** - //*************************************************************** - //** These functions deal with setting & retrieving filters - //*************************************************************** - //*************************************************************** - public void setEnSearch(String t) { - enSearch = new EnSearch(conn,logger, t, getTagIndex(), Global.getRecognitionWeight()); - enSearchChanged = true; - } - // Save search tags - public void setSelectedTags(List selectedTags) { - this.selectedTags = selectedTags; - } - // Save seleceted search - public void setSelectedSavedSearch(String s) { - this.selectedSearch = s; - } - // Get search tags - public List getSelectedTags() { - return selectedTags; - } - // Get saved search - public String getSelectedSearch() { - return selectedSearch; - } - - - - - //*************************************************************** - //*************************************************************** - //** Note functions - //*************************************************************** - //*************************************************************** - // Save Note Tags +/* + * This file is part of NixNote + * Copyright 2009 Randy Baumgarte + * + * This file may be licensed under the terms of of the + * GNU General Public License Version 2 (the ``GPL''). + * + * Software distributed under the License is distributed + * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the GPL for the specific language + * governing rights and limitations. + * + * You should have received a copy of the GPL along with this + * program. If not, go to http://www.gnu.org/licenses/gpl.html + * or write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * +*/ + +package cx.fbn.nevernote.utilities; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.Comparator; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.List; +import java.util.Vector; + +import com.evernote.edam.type.LinkedNotebook; +import com.evernote.edam.type.Note; +import com.evernote.edam.type.Notebook; +import com.evernote.edam.type.SavedSearch; +import com.evernote.edam.type.Tag; +import com.trolltech.qt.QThread; +import com.trolltech.qt.core.QDateTime; +import com.trolltech.qt.gui.QImage; +import com.trolltech.qt.gui.QPixmap; +import com.trolltech.qt.sql.QSqlQuery; +import com.trolltech.qt.xml.QDomAttr; +import com.trolltech.qt.xml.QDomDocument; +import com.trolltech.qt.xml.QDomElement; +import com.trolltech.qt.xml.QDomNodeList; + +import cx.fbn.nevernote.Global; +import cx.fbn.nevernote.evernote.NoteMetadata; +import cx.fbn.nevernote.filters.EnSearch; +import cx.fbn.nevernote.filters.NotebookCounter; +import cx.fbn.nevernote.filters.TagCounter; +import cx.fbn.nevernote.gui.NoteTableModel; +import cx.fbn.nevernote.signals.NotebookSignal; +import cx.fbn.nevernote.signals.StatusSignal; +import cx.fbn.nevernote.signals.TagSignal; +import cx.fbn.nevernote.signals.ThreadSignal; +import cx.fbn.nevernote.signals.TrashSignal; +import cx.fbn.nevernote.sql.DatabaseConnection; +import cx.fbn.nevernote.threads.CounterRunner; +import cx.fbn.nevernote.threads.SaveRunner; + + +public class ListManager { + + + private final ApplicationLogger logger; + DatabaseConnection conn; + QSqlQuery deleteWords; + QSqlQuery insertWords; + + private List tagIndex; + private List notebookIndex; + private List archiveNotebookIndex; + private List localNotebookIndex; + private List linkedNotebookIndex; + + private List searchIndex; + + private List selectedNotebooks; + private final NoteTableModel noteModel; + + + private List selectedTags; + private String selectedSearch; + ThreadSignal signals; + public StatusSignal status; + private final CounterRunner notebookCounterRunner; + private final QThread notebookThread; + private final CounterRunner tagCounterRunner; + private final QThread tagThread; + + private final CounterRunner trashCounterRunner; + private final QThread trashThread; + public TrashSignal trashSignal; + + private List notebookCounter; // count of displayed notes in each notebook + private List tagCounter; // count of displayed notes for each tag + + private EnSearch enSearch; + private boolean enSearchChanged; + public HashMap wordMap; + public TagSignal tagSignal; + public NotebookSignal notebookSignal; + public boolean refreshCounters; // Used to control when to recount lists + private int trashCount; + public SaveRunner saveRunner; // Thread used to save content. Used because the xml conversion is slowwwww + QThread saveThread; + +// private final HashMap thumbnailList; + + // Constructor + public ListManager(DatabaseConnection d, ApplicationLogger l) { + conn = d; + logger = l; + + conn.getTagTable().cleanupTags(); + status = new StatusSignal(); + signals = new ThreadSignal(); + + // setup index locks + enSearchChanged = false; + + // Setup arrays + noteModel = new NoteTableModel(this); + selectedTags = new ArrayList(); + + notebookCounter = new ArrayList(); + tagCounter = new ArrayList(); + selectedNotebooks = new ArrayList(); + + reloadIndexes(); + + notebookSignal = new NotebookSignal(); + // ICHANGED Global.getBehaviorDatabaseUrl()を追加 + notebookCounterRunner = new CounterRunner("notebook_counter.log", CounterRunner.NOTEBOOK, + Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(), Global.getBehaviorDatabaseUrl(), + Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword); + notebookCounterRunner.setNoteIndex(getNoteIndex()); + notebookCounterRunner.notebookSignal.countsChanged.connect(this, "setNotebookCounter(List)"); + notebookThread = new QThread(notebookCounterRunner, "Notebook Counter Thread"); + notebookThread.start(); + + tagSignal = new TagSignal(); + // ICHANGED Global.getBehaviorDatabaseUrl()を追加 + tagCounterRunner = new CounterRunner("tag_counter.log", CounterRunner.TAG, + Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(), Global.getBehaviorDatabaseUrl(), + Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword); + tagCounterRunner.setNoteIndex(getNoteIndex()); + tagCounterRunner.tagSignal.countsChanged.connect(this, "setTagCounter(List)"); + tagThread = new QThread(tagCounterRunner, "Tag Counter Thread"); + tagThread.start(); + + trashSignal = new TrashSignal(); + // ICHANGED Global.getBehaviorDatabaseUrl()を追加 + trashCounterRunner = new CounterRunner("trash_counter.log", CounterRunner.TRASH, + Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(), Global.getBehaviorDatabaseUrl(), + Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword); + trashCounterRunner.trashSignal.countChanged.connect(this, "trashSignalReceiver(Integer)"); + trashThread = new QThread(trashCounterRunner, "Trash Counter Thread"); + trashThread.start(); +// reloadTrashCount(); + + wordMap = new HashMap(); + tagSignal = new TagSignal(); + + logger.log(logger.EXTREME, "Setting save thread"); + // ICHANGED Global.getBehaviorDatabaseUrl()を追加 + saveRunner = new SaveRunner("saveRunner.log", + Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(), Global.getBehaviorDatabaseUrl(), + Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword); + saveThread = new QThread(saveRunner, "Save Runner Thread"); + saveThread.start(); + +// thumbnailList = conn.getNoteTable().getThumbnails(); +// thumbnailList = new HashMap(); + + linkedNotebookIndex = conn.getLinkedNotebookTable().getAll(); + loadNoteTitleColors(); + refreshCounters = true; + refreshCounters(); + + } + + public void stop() { + saveRunner.addWork("stop", ""); + tagCounterRunner.release(CounterRunner.EXIT); + notebookCounterRunner.release(CounterRunner.EXIT); + trashCounterRunner.release(CounterRunner.EXIT); + + logger.log(logger.MEDIUM, "Waiting for notebookCounterThread to stop"); + try { + notebookThread.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + logger.log(logger.MEDIUM, "Waiting for tagCounterThread to stop"); + try { + tagThread.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + logger.log(logger.MEDIUM, "Waiting for trashThread to stop"); + try { + trashThread.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + + logger.log(logger.MEDIUM, "Waiting for saveThread to stop"); + try { + saveThread.join(0); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + } + + //*************************************************************** + //*************************************************************** + //* Refresh lists after a db sync + //*************************************************************** + //*************************************************************** + public void refreshLists(Note n, boolean dirty, String content) { + if (dirty) { +// conn.getNoteTable().updateNoteContent(n.getGuid(), n.getContent()); + saveRunner.addWork(n.getGuid(), content); + conn.getNoteTable().updateNoteTitle(n.getGuid(), n.getTitle()); + } + + setSavedSearchIndex(conn.getSavedSearchTable().getAll()); + setTagIndex(conn.getTagTable().getAll()); + setNotebookIndex(conn.getNotebookTable().getAll()); + + List local = conn.getNotebookTable().getAllLocal(); + localNotebookIndex = new ArrayList(); + for (int i=0; i noteTags = conn.getNoteTable().noteTagsTable.getAllNoteTags(); + for (int i=0; i tags = new ArrayList(); + List names = new ArrayList(); + for (int j=0; j local = conn.getNotebookTable().getAllLocal(); + localNotebookIndex = new ArrayList(); + for (int i=0; i noteTags = conn.getNoteTable().noteTagsTable.getAllNoteTags(); + for (int i=0; i tags = new ArrayList(); + List names = new ArrayList(); + for (int j=0; j getSelectedNotebooks() { + return selectedNotebooks; + } + // Set the current selected notebook(s) + public void setSelectedNotebooks(List s) { + if (s == null) + s = new ArrayList(); + selectedNotebooks = s; + } + + + //*************************************************************** + //*************************************************************** + //** These functions deal with setting & retrieving the master lists + //*************************************************************** + //*************************************************************** + // Get the note table model + public NoteTableModel getNoteTableModel() { + return noteModel; + } + // save the saved search index + private void setSavedSearchIndex(List t) { + searchIndex = t; + } + // Retrieve the Tag index + public List getSavedSearchIndex() { + return searchIndex; + + } + // save the tag index + private void setTagIndex(List t) { + tagIndex = t; + } + // Retrieve the Tag index + public List getTagIndex() { + return tagIndex; + } + private void setNotebookIndex(List t) { + notebookIndex = t; + } + private void setArchiveNotebookIndex(List t) { + archiveNotebookIndex = t; + } + // Retrieve the Notebook index + public List getNotebookIndex() { + return notebookIndex; + + } + public List getLinkedNotebookIndex() { + return linkedNotebookIndex; + } + public List getArchiveNotebookIndex() { + return archiveNotebookIndex; + } + // Save the current note list + private void setNoteIndex(List n) { + noteModel.setNoteIndex(n); + refreshNoteMetadata(); + } + public void refreshNoteMetadata() { + noteModel.setNoteMetadata(conn.getNoteTable().getNotesMetaInformation()); + } + // Update a note's meta data + public void updateNoteMetadata(NoteMetadata meta) { + noteModel.metaData.remove(meta); + noteModel.metaData.put(meta.getGuid(), meta); + conn.getNoteTable().updateNoteMetadata(meta); + } + // Get the note index + public synchronized List getNoteIndex() { + return noteModel.getNoteIndex(); + } + // Save the count of notes per notebook + public void setNotebookCounter(List n) { + notebookCounter = n; + notebookSignal.refreshNotebookTreeCounts.emit(getNotebookIndex(), notebookCounter); + } + public List getNotebookCounter() { + return notebookCounter; + } + // Save the count of notes for each tag + public void setTagCounter(List n) { + tagCounter = n; + tagSignal.refreshTagTreeCounts.emit(tagCounter); + } + public List getTagCounter() { + return tagCounter; + } + public List getLocalNotebooks() { + return localNotebookIndex; + } + +// public void setUnsynchronizedNotes(List l) { +// noteModel.setUnsynchronizedNotes(l); +// } + // Return a count of items in the trash + public int getTrashCount() { + return trashCount; + } + // get the EnSearch variable + public EnSearch getEnSearch() { + return enSearch; + } + public List getMasterNoteIndex() { + return noteModel.getMasterNoteIndex(); + } + // Thumbnails +// public HashMap getThumbnails() { +// return thumbnailList; +// } + public HashMap getNoteMetadata() { + return noteModel.metaData; + } + public QImage getThumbnail(String guid) { +// if (getThumbnails().containsKey(guid)) +// return getThumbnails().get(guid); + + QImage img = new QImage(); + img = QImage.fromData(conn.getNoteTable().getThumbnail(guid)); + if (img == null || img.isNull()) + return null; + //getThumbnails().put(guid, img); + return img; + } + public QPixmap getThumbnailPixmap(String guid) { +// if (getThumbnails().containsKey(guid)) +// return getThumbnails().get(guid); + + QPixmap img = new QPixmap(); + img.loadFromData(conn.getNoteTable().getThumbnail(guid)); + if (img == null || img.isNull()) + return null; + //getThumbnails().put(guid, img); + return img; + } + //*************************************************************** + //*************************************************************** + //** These functions deal with setting & retrieving filters + //*************************************************************** + //*************************************************************** + public void setEnSearch(String t) { + enSearch = new EnSearch(conn,logger, t, getTagIndex(), Global.getRecognitionWeight()); + enSearchChanged = true; + } + // Save search tags + public void setSelectedTags(List selectedTags) { + this.selectedTags = selectedTags; + } + // Save seleceted search + public void setSelectedSavedSearch(String s) { + this.selectedSearch = s; + } + // Get search tags + public List getSelectedTags() { + return selectedTags; + } + // Get saved search + public String getSelectedSearch() { + return selectedSearch; + } + + + + + //*************************************************************** + //*************************************************************** + //** Note functions + //*************************************************************** + //*************************************************************** + // Save Note Tags public void saveNoteTags(String noteGuid, List tags, boolean isDirty) { - logger.log(logger.HIGH, "Entering ListManager.saveNoteTags"); - String tagName; - conn.getNoteTable().noteTagsTable.deleteNoteTag(noteGuid); - List tagGuids = new ArrayList(); - boolean newTagCreated = false; - - for (int i=0; i tagGuids = new ArrayList(); + boolean newTagCreated = false; + + for (int i=0; i=0; i--) { - if (!getMasterNoteIndex().get(i).isActive()) { - getMasterNoteIndex().remove(i); - } - } - - for (int i=getNoteIndex().size()-1; i>=0; i--) { - if (!getNoteIndex().get(i).isActive()) { - getNoteIndex().remove(i); - } - } - - conn.getNoteTable().expungeAllDeletedNotes(); - reloadTrashCount(); - } - // The trash counter thread has produced a result - @SuppressWarnings("unused") - private void trashSignalReceiver(Integer i) { - trashCount = i; - trashSignal.countChanged.emit(i); - } - // Update note contents - public void updateNoteContent(String guid, String content) { - logger.log(logger.HIGH, "Entering ListManager.updateNoteContent"); -// EnmlConverter enml = new EnmlConverter(logger); -// String text = enml.convert(guid, content); - - // Update the list tables -/* for (int i=0; i elements = Global.invalidElements; - for (int i=0; i attributes = Global.invalidAttributes.get(key); - for (int i=0; i findAllChildren(String guid) { - List tags = new ArrayList(); - return findAllChildrenRecursive(guid, tags); - } - public List findAllChildrenRecursive(String guid, List tags) { - - // Start looping through the tags. If we find a tag which has a parent that - // matches guid, then we add it to the list of tags & search for its children. - for (int i=0; i noteTags) { - boolean returnValue = false; - List children = findAllChildren(guid); - for (int i=0; i matches; - if (enSearchChanged || getMasterNoteIndex() == null) - matches = enSearch.matchWords(); - else - matches = getMasterNoteIndex(); - - if (matches == null) - matches = getMasterNoteIndex(); - - setNoteIndex(new ArrayList()); - for (int i=0; i index) { - logger.log(logger.EXTREME, "Entering ListManager.countNotebookResults()"); - notebookCounterRunner.abortCount = true; - if (!Global.mimicEvernoteInterface) - notebookCounterRunner.setNoteIndex(index); - else - notebookCounterRunner.setNoteIndex(getMasterNoteIndex()); - notebookCounterRunner.release(CounterRunner.NOTEBOOK); - logger.log(logger.EXTREME, "Leaving ListManager.countNotebookResults()"); - } - public void countTagResults(List index) { - logger.log(logger.EXTREME, "Entering ListManager.countTagResults"); - trashCounterRunner.abortCount = true; - if (!Global.tagBehavior().equalsIgnoreCase("DoNothing")) - tagCounterRunner.setNoteIndex(index); - else - tagCounterRunner.setNoteIndex(getMasterNoteIndex()); - tagCounterRunner.release(CounterRunner.TAG); - logger.log(logger.EXTREME, "Leaving ListManager.countTagResults()"); - } - // Update the count of items in the trash - public void reloadTrashCount() { - logger.log(logger.EXTREME, "Entering ListManager.reloadTrashCount"); - trashCounterRunner.abortCount = true; - trashCounterRunner.setNoteIndex(getMasterNoteIndex()); - trashCounterRunner.release(CounterRunner.TRASH); - logger.log(logger.EXTREME, "Leaving ListManager.reloadTrashCount"); - } - - private boolean filterByNotebook(String guid) { - boolean good = false; - if (selectedNotebooks.size() == 0) - good = true; - if (!good && selectedNotebooks.contains(guid)) - good = true; - - for (int i=0; i noteTags) { - // If either the note has no tags or there are - // no selected tags, then any note is good. - if (noteTags == null || selectedTags == null) - return true; - - // If there are no tags selected, then any note is good - if (selectedTags.size() == 0) - return true; - - // If ALL tags must be matched, then check ALL note tags, - // otherwise we match on any criteria. - if (!Global.anyTagSelectionMatch()) { - for (int i=0; i scanNoteForResources(Note n) { - logger.log(logger.HIGH, "Entering ListManager.scanNoteForResources"); - logger.log(logger.EXTREME, "Note guid: " +n.getGuid()); - QDomDocument doc = new QDomDocument(); - QDomDocument.Result result = doc.setContent(n.getContent()); - if (!result.success) { - logger.log(logger.MEDIUM, "Parse error when scanning note for resources."); - logger.log(logger.MEDIUM, "Note guid: " +n.getGuid()); - return null; - } - - List returnArray = new ArrayList(); - QDomNodeList anchors = doc.elementsByTagName("en-media"); - for (int i=0; i v = new Vector(); - List guids = n.getTagGuids(); - - if (guids == null) - return ""; - - for (int i=0; i comparator = Collections.reverseOrder(); - Collections.sort(v,comparator); - Collections.reverse(v); - - for (int i = 0; i0) - buffer.append(", "); - buffer.append(v.get(i)); - } - - return buffer.toString(); - } - // Get a tag name when given a tag guid - public String getTagNameByGuid(String guid) { - for (int i=0; i=0; i--) { + if (!getMasterNoteIndex().get(i).isActive()) { + getMasterNoteIndex().remove(i); + } + } + + for (int i=getNoteIndex().size()-1; i>=0; i--) { + if (!getNoteIndex().get(i).isActive()) { + getNoteIndex().remove(i); + } + } + + conn.getNoteTable().expungeAllDeletedNotes(); + reloadTrashCount(); + } + // The trash counter thread has produced a result + @SuppressWarnings("unused") + private void trashSignalReceiver(Integer i) { + trashCount = i; + trashSignal.countChanged.emit(i); + } + // Update note contents + public void updateNoteContent(String guid, String content) { + logger.log(logger.HIGH, "Entering ListManager.updateNoteContent"); +// EnmlConverter enml = new EnmlConverter(logger); +// String text = enml.convert(guid, content); + + // Update the list tables +/* for (int i=0; i elements = Global.invalidElements; + for (int i=0; i attributes = Global.invalidAttributes.get(key); + for (int i=0; i findAllChildren(String guid) { + List tags = new ArrayList(); + return findAllChildrenRecursive(guid, tags); + } + public List findAllChildrenRecursive(String guid, List tags) { + + // Start looping through the tags. If we find a tag which has a parent that + // matches guid, then we add it to the list of tags & search for its children. + for (int i=0; i noteTags) { + boolean returnValue = false; + List children = findAllChildren(guid); + for (int i=0; i matches; + if (enSearchChanged || getMasterNoteIndex() == null) + matches = enSearch.matchWords(); + else + matches = getMasterNoteIndex(); + + if (matches == null) + matches = getMasterNoteIndex(); + + setNoteIndex(new ArrayList()); + for (int i=0; i index) { + logger.log(logger.EXTREME, "Entering ListManager.countNotebookResults()"); + notebookCounterRunner.abortCount = true; + if (!Global.mimicEvernoteInterface) + notebookCounterRunner.setNoteIndex(index); + else + notebookCounterRunner.setNoteIndex(getMasterNoteIndex()); + notebookCounterRunner.release(CounterRunner.NOTEBOOK); + logger.log(logger.EXTREME, "Leaving ListManager.countNotebookResults()"); + } + public void countTagResults(List index) { + logger.log(logger.EXTREME, "Entering ListManager.countTagResults"); + trashCounterRunner.abortCount = true; + if (!Global.tagBehavior().equalsIgnoreCase("DoNothing")) + tagCounterRunner.setNoteIndex(index); + else + tagCounterRunner.setNoteIndex(getMasterNoteIndex()); + tagCounterRunner.release(CounterRunner.TAG); + logger.log(logger.EXTREME, "Leaving ListManager.countTagResults()"); + } + // Update the count of items in the trash + public void reloadTrashCount() { + logger.log(logger.EXTREME, "Entering ListManager.reloadTrashCount"); + trashCounterRunner.abortCount = true; + trashCounterRunner.setNoteIndex(getMasterNoteIndex()); + trashCounterRunner.release(CounterRunner.TRASH); + logger.log(logger.EXTREME, "Leaving ListManager.reloadTrashCount"); + } + + private boolean filterByNotebook(String guid) { + boolean good = false; + if (selectedNotebooks.size() == 0) + good = true; + if (!good && selectedNotebooks.contains(guid)) + good = true; + + for (int i=0; i noteTags) { + // If either the note has no tags or there are + // no selected tags, then any note is good. + if (noteTags == null || selectedTags == null) + return true; + + // If there are no tags selected, then any note is good + if (selectedTags.size() == 0) + return true; + + // If ALL tags must be matched, then check ALL note tags, + // otherwise we match on any criteria. + if (!Global.anyTagSelectionMatch()) { + for (int i=0; i scanNoteForResources(Note n) { + logger.log(logger.HIGH, "Entering ListManager.scanNoteForResources"); + logger.log(logger.EXTREME, "Note guid: " +n.getGuid()); + QDomDocument doc = new QDomDocument(); + QDomDocument.Result result = doc.setContent(n.getContent()); + if (!result.success) { + logger.log(logger.MEDIUM, "Parse error when scanning note for resources."); + logger.log(logger.MEDIUM, "Note guid: " +n.getGuid()); + return null; + } + + List returnArray = new ArrayList(); + QDomNodeList anchors = doc.elementsByTagName("en-media"); + for (int i=0; i v = new Vector(); + List guids = n.getTagGuids(); + + if (guids == null) + return ""; + + for (int i=0; i comparator = Collections.reverseOrder(); + Collections.sort(v,comparator); + Collections.reverse(v); + + for (int i = 0; i0) + buffer.append(", "); + buffer.append(v.get(i)); + } + + return buffer.toString(); + } + // Get a tag name when given a tag guid + public String getTagNameByGuid(String guid) { + for (int i=0; i