--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+ <classpathentry kind="src" path="src"/>\r
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>\r
+ <classpathentry kind="lib" path="D:/NeverNote/lib/PDFRenderer.jar"/>\r
+ <classpathentry kind="lib" path="D:/Nevernote-prod/lib/h2-1.2.136.jar"/>\r
+ <classpathentry kind="lib" path="D:/NeverNote/lib/evernote-api-1.15.jar"/>\r
+ <classpathentry kind="lib" path="D:/NeverNote/lib/libthrift.jar"/>\r
+ <classpathentry kind="lib" path="D:/NeverNote/lib/log4j-1.2.14.jar"/>\r
+ <classpathentry kind="lib" path="D:/qtjambi-win32-lgpl-4.5.0_01/qtjambi-4.5.0_01.jar"/>\r
+ <classpathentry kind="lib" path="D:/qtjambi-win32-lgpl-4.5.0_01/qtjambi-win32-msvc2005-4.5.0_01.jar"/>\r
+ <classpathentry kind="output" path="bin"/>\r
+</classpath>\r
--- /dev/null
+bin
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+ <name>NeverNote</name>\r
+ <comment></comment>\r
+ <projects>\r
+ </projects>\r
+ <buildSpec>\r
+ <buildCommand>\r
+ <name>com.trolltech.qtjambi.juicBuilder</name>\r
+ <arguments>\r
+ </arguments>\r
+ </buildCommand>\r
+ <buildCommand>\r
+ <name>org.eclipse.jdt.core.javabuilder</name>\r
+ <arguments>\r
+ </arguments>\r
+ </buildCommand>\r
+ </buildSpec>\r
+ <natures>\r
+ <nature>org.eclipse.jdt.core.javanature</nature>\r
+ </natures>\r
+</projectDescription>\r
--- /dev/null
+#Mon Feb 01 13:37:03 EST 2010\r
+eclipse.preferences.version=1\r
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true\r
+sp_cleanup.add_default_serial_version_id=true\r
+sp_cleanup.add_generated_serial_version_id=false\r
+sp_cleanup.add_missing_annotations=true\r
+sp_cleanup.add_missing_deprecated_annotations=true\r
+sp_cleanup.add_missing_methods=false\r
+sp_cleanup.add_missing_nls_tags=false\r
+sp_cleanup.add_missing_override_annotations=true\r
+sp_cleanup.add_serial_version_id=false\r
+sp_cleanup.always_use_blocks=true\r
+sp_cleanup.always_use_parentheses_in_expressions=false\r
+sp_cleanup.always_use_this_for_non_static_field_access=false\r
+sp_cleanup.always_use_this_for_non_static_method_access=false\r
+sp_cleanup.convert_to_enhanced_for_loop=true\r
+sp_cleanup.correct_indentation=false\r
+sp_cleanup.format_source_code=false\r
+sp_cleanup.format_source_code_changes_only=false\r
+sp_cleanup.make_local_variable_final=false\r
+sp_cleanup.make_parameters_final=false\r
+sp_cleanup.make_private_fields_final=true\r
+sp_cleanup.make_type_abstract_if_missing_method=false\r
+sp_cleanup.make_variable_declarations_final=true\r
+sp_cleanup.never_use_blocks=false\r
+sp_cleanup.never_use_parentheses_in_expressions=true\r
+sp_cleanup.on_save_use_additional_actions=true\r
+sp_cleanup.organize_imports=true\r
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false\r
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true\r
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true\r
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=false\r
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false\r
+sp_cleanup.remove_private_constructors=true\r
+sp_cleanup.remove_trailing_whitespaces=false\r
+sp_cleanup.remove_trailing_whitespaces_all=true\r
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=false\r
+sp_cleanup.remove_unnecessary_casts=true\r
+sp_cleanup.remove_unnecessary_nls_tags=false\r
+sp_cleanup.remove_unused_imports=false\r
+sp_cleanup.remove_unused_local_variables=false\r
+sp_cleanup.remove_unused_private_fields=true\r
+sp_cleanup.remove_unused_private_members=false\r
+sp_cleanup.remove_unused_private_methods=true\r
+sp_cleanup.remove_unused_private_types=true\r
+sp_cleanup.sort_members=false\r
+sp_cleanup.sort_members_all=false\r
+sp_cleanup.use_blocks=false\r
+sp_cleanup.use_blocks_only_for_return_and_throw=false\r
+sp_cleanup.use_parentheses_in_expressions=false\r
+sp_cleanup.use_this_for_non_static_field_access=false\r
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true\r
+sp_cleanup.use_this_for_non_static_method_access=false\r
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true\r
--- /dev/null
+#Thu Aug 06 07:27:30 EDT 2009\r
+eclipse.preferences.version=1\r
+org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+ <classpathentry kind="lib" path="D:/qtjambi-win32-lgpl-4.5.0_01/qtjambi-4.5.0_01.jar">\r
+ <attributes>\r
+ <attribute name="javadoc_location" value="file:D:/qtjambi-win32-lgpl-4.5.0_01/doc/html"/>\r
+ </attributes>\r
+ </classpathentry>\r
+ <classpathentry kind="lib" path="D:/qtjambi-win32-lgpl-4.5.0_01/qtjambi-win32-msvc2005-4.5.0_01.jar">\r
+ <attributes>\r
+ <attribute name="javadoc_location" value="file:D:/qtjambi-win32-lgpl-4.5.0_01/doc/html"/>\r
+ </attributes>\r
+ </classpathentry>\r
+ <classpathentry kind="src" path="src"/>\r
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>\r
+ <classpathentry kind="var" path="JAMBI_LOCATION"/>\r
+ <classpathentry kind="lib" path="D:/NeverNote/lib/log4j-1.2.14.jar"/>\r
+ <classpathentry kind="lib" path="D:/NeverNote/lib/libthrift.jar"/>\r
+ <classpathentry kind="lib" path="D:/NeverNote/lib/evernote-api-1.15.jar"/>\r
+ <classpathentry kind="output" path="bin"/>\r
+</classpath>\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+ <name>NeverNote 0.80</name>\r
+ <comment></comment>\r
+ <projects>\r
+ </projects>\r
+ <buildSpec>\r
+ <buildCommand>\r
+ <name>com.trolltech.qtjambi.juicBuilder</name>\r
+ <arguments>\r
+ </arguments>\r
+ </buildCommand>\r
+ <buildCommand>\r
+ <name>org.eclipse.jdt.core.javabuilder</name>\r
+ <arguments>\r
+ </arguments>\r
+ </buildCommand>\r
+ </buildSpec>\r
+ <natures>\r
+ <nature>org.eclipse.jdt.core.javanature</nature>\r
+ </natures>\r
+</projectDescription>\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.spell.engine;\r
+\r
+import java.security.AccessControlException;\r
+\r
+\r
+/**\r
+ * The various settings used to control how a spell checker works are read from here.\r
+ * Includes the COST_* constants that decide how to figure the cost of converting one word to\r
+ * another in the EditDistance class.\r
+ * <p/>\r
+ * Also includes SPELL_* constants that control how misspellings are detected, for example, how to handle\r
+ * mixed-case words, etc.\r
+ *\r
+ * @author aim4min\r
+ * @see EditDistance\r
+ */\r
+public abstract class Configuration {\r
+\r
+ /** used by EditDistance: the cost of having to remove a character <br/>(integer greater than 0) */\r
+ public static final String COST_REMOVE_CHAR = "EDIT_DEL1";\r
+\r
+ /** used by EditDistance: the cost of having to insert a character <br/>(integer greater than 0)*/\r
+ public static final String COST_INSERT_CHAR = "EDIT_DEL2";\r
+\r
+ /**\r
+ * used by EditDistance: the cost of having to swap two adjoining characters\r
+ * for the swap value to ever be used, it should be smaller than the COST_REMOVE_CHAR or COST_INSERT_CHAR values\r
+ * <br/>(integer greater than 0)\r
+ */\r
+ public static final String COST_SWAP_CHARS = "EDIT_SWAP";\r
+\r
+ /**\r
+ * used by EditDistance: the cost of having to change case, for example, from i to I.\r
+ * <br/>(integer greater than 0)\r
+ */\r
+ public static final String COST_CHANGE_CASE = "EDIT_CASE";\r
+\r
+ /**\r
+ * used by EditDistance: the cost of having to substitute one character for another\r
+ * for the sub value to ever be used, it should be smaller than the COST_REMOVE_CHAR or COST_INSERT_CHAR values\r
+ * <br/>(integer greater than 0)\r
+ */\r
+ public static final String COST_SUBST_CHARS = "EDIT_SUB";\r
+\r
+// public static final String EDIT_SIMILAR = "EDIT_SIMILAR"; //DMV: these does not seem to be used at all\r
+// public static final String EDIT_MIN = "EDIT_MIN";\r
+// public static final String EDIT_MAX = "EDIT_MAX";\r
+\r
+ /** the maximum cost of suggested spelling. Any suggestions that cost more are thrown away\r
+ * <br/> integer greater than 1)\r
+ */\r
+ public static final String SPELL_THRESHOLD = "SPELL_THRESHOLD";\r
+\r
+ /** words that are all upper case are not spell checked, example: "CIA" <br/>(boolean) */\r
+ public static final String SPELL_IGNOREUPPERCASE = "SPELL_IGNOREUPPERCASE";\r
+ /** words that have mixed case are not spell checked, example: "SpellChecker"<br/>(boolean) */\r
+ public static final String SPELL_IGNOREMIXEDCASE = "SPELL_IGNOREMIXEDCASE";\r
+ /** words that look like an Internet address are not spell checked, example: "http://www.google.com" <br/>(boolean)*/\r
+ public static final String SPELL_IGNOREINTERNETADDRESSES = "SPELL_IGNOREINTERNETADDRESS";\r
+ /** words that have digits in them are not spell checked, example: "mach5" <br/>(boolean) */\r
+ public static final String SPELL_IGNOREDIGITWORDS = "SPELL_IGNOREDIGITWORDS";\r
+ /** I don't know what this does. It doesn't seem to be used <br/>(boolean) */\r
+ public static final String SPELL_IGNOREMULTIPLEWORDS = "SPELL_IGNOREMULTIPLEWORDS";\r
+ /** the first word of a sentence is expected to start with an upper case letter <br/>(boolean) */\r
+ public static final String SPELL_IGNORESENTENCECAPITALIZATION = "SPELL_IGNORESENTENCECAPTILIZATION";\r
+\r
+ /**\r
+ * Gets one of the integer constants\r
+ * @param key one of the integer constants defined in this class\r
+ * @return int value of the setting\r
+ */\r
+ public abstract int getInteger(String key);\r
+\r
+ /**\r
+ * Gets one of the boolean constants\r
+ * @param key one of the boolean constants defined in this class\r
+ * @return boolean value of the setting\r
+ */\r
+ public abstract boolean getBoolean(String key);\r
+\r
+ /**\r
+ * Sets one of the integer constants\r
+ * @param key one of the integer constants defined in this class\r
+ * @param value new integer value of the constant\r
+ */\r
+ public abstract void setInteger(String key, int value);\r
+\r
+ /**\r
+ * Sets one of the boolean constants\r
+ * @param key one of the boolean constants defined in this class\r
+ * @param value new boolean value of this setting\r
+ */\r
+ public abstract void setBoolean(String key, boolean value);\r
+\r
+ /**\r
+ * gets a new default Configuration\r
+ * @return Configuration\r
+ */\r
+ public static final Configuration getConfiguration() {\r
+ try {\r
+ String config = System.getProperty("jazzy.config"); // added by bd\r
+ if (config != null && config.length() > 0)\r
+ return getConfiguration(config);\r
+ } catch (AccessControlException e) {\r
+ e.printStackTrace();\r
+ } \r
+ return getConfiguration(null);\r
+ }\r
+\r
+ /**\r
+ * Returns a new instance of a Configuration class\r
+ * @param className - the class to return, must be based on Configuration\r
+ * @return Configuration\r
+ */\r
+ public static final Configuration getConfiguration(String className) {\r
+\r
+ Configuration result;\r
+\r
+ if (className != null && className.length() > 0) {\r
+ try {\r
+ result = (Configuration) Class.forName(className).newInstance();\r
+ } catch (InstantiationException e) {\r
+ result = new PropertyConfiguration();\r
+ } catch (IllegalAccessException e) {\r
+ result = new PropertyConfiguration();\r
+ } catch (ClassNotFoundException e) {\r
+ result = new PropertyConfiguration();\r
+ }\r
+ } else {\r
+ result = new PropertyConfiguration();\r
+ }\r
+ return result;\r
+ }\r
+}\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.spell.engine;\r
+\r
+\r
+/**\r
+ * A phonetic encoding algorithm that takes an English word and computes a phonetic version of it. This\r
+ * allows for phonetic matches in a spell checker. This class is a port of the C++ DoubleMetaphone() class,\r
+ * which was intended to return two possible phonetic translations for certain words, although the Java version\r
+ * only seems to be concerned with one, making the "double" part erroneous.\r
+ * <br>\r
+ * source code for the original C++ can be found\r
+ * here: <a href="http://aspell.sourceforge.net/metaphone/"/>http://aspell.sourceforge.net/metaphone/</a>\r
+ * DoubleMetaphone does some processing, such as uppercasing, on the input string first to normalize it. Then, to\r
+ * create the key, the function traverses the input string in a while loop, sending successive characters into a giant\r
+ * switch statement. Before determining the appropriate pronunciation, the algorithm considers the context\r
+ * surrounding each character within the input string.\r
+ * <p>\r
+ * Things that were changed:\r
+ * <br/>The alternate flag could be set to true but was never checked so why bother with it. REMOVED\r
+ * <br/>Why was this class serializable?\r
+ * <br/>The primary, in, length and last variables could be initialized and local to the\r
+ * process method and references passed around the appropriate methods. As such there are\r
+ * no class variables and this class becomes firstly threadsafe and secondly could be static final.\r
+ * <br/>The function call SlavoGermaic was called repeatedly in the process function, it is now only called once.\r
+ *\r
+ */\r
+public class DoubleMeta implements Transformator {\r
+\r
+ /**\r
+ * The replace list is used in the getSuggestions method.\r
+ * All of the letters in the misspelled word are replaced with the characters from\r
+ * this list to try and generate more suggestions, which implies l*n tries,\r
+ * if l is the size of the string, and n is the size of this list.\r
+ *\r
+ * In addition to that, each of these letters is added to the misspelled word.\r
+ */\r
+ private static char[] replaceList = {'A', 'B', 'X', 'S', 'K', 'J', 'T', 'F', 'H', 'L', 'M', 'N', 'P', 'R', '0'};\r
+\r
+\r
+ private static final String[] myList = {"GN", "KN", "PN", "WR", "PS", ""};\r
+ private static final String[] list1 = {"ACH", ""};\r
+ private static final String[] list2 = {"BACHER", "MACHER", ""};\r
+ private static final String[] list3 = {"CAESAR", ""};\r
+ private static final String[] list4 = {"CHIA", ""};\r
+ private static final String[] list5 = {"CH", ""};\r
+ private static final String[] list6 = {"CHAE", ""};\r
+ private static final String[] list7 = {"HARAC", "HARIS", ""};\r
+ private static final String[] list8 = {"HOR", "HYM", "HIA", "HEM", ""};\r
+ private static final String[] list9 = {"CHORE", ""};\r
+ private static final String[] list10 = {"VAN ", "VON ", ""};\r
+ private static final String[] list11 = {"SCH", ""};\r
+ private static final String[] list12 = {"ORCHES", "ARCHIT", "ORCHID", ""};\r
+ private static final String[] list13 = {"T", "S", ""};\r
+ private static final String[] list14 = {"A", "O", "U", "E", ""};\r
+ private static final String[] list15 = {"L", "R", "N", "M", "B", "H", "F", "V", "W", " ", ""};\r
+ private static final String[] list16 = {"MC", ""};\r
+ private static final String[] list17 = {"CZ", ""};\r
+ private static final String[] list18 = {"WICZ", ""};\r
+ private static final String[] list19 = {"CIA", ""};\r
+ private static final String[] list20 = {"CC", ""};\r
+ private static final String[] list21 = {"I", "E", "H", ""};\r
+ private static final String[] list22 = {"HU", ""};\r
+ private static final String[] list23 = {"UCCEE", "UCCES", ""};\r
+ private static final String[] list24 = {"CK", "CG", "CQ", ""};\r
+ private static final String[] list25 = {"CI", "CE", "CY", ""};\r
+// DMV: used by the orininal code which returned two phonetic code, but not the current code\r
+// private static final String[] list26 = {\r
+// "CIO", "CIE", "CIA", ""\r
+// };\r
+ private static final String[] list27 = {" C", " Q", " G", ""};\r
+ private static final String[] list28 = {"C", "K", "Q", ""};\r
+ private static final String[] list29 = {"CE", "CI", ""};\r
+ private static final String[] list30 = {"DG", ""};\r
+ private static final String[] list31 = {"I", "E", "Y", ""};\r
+ private static final String[] list32 = {"DT", "DD", ""};\r
+ private static final String[] list33 = {"B", "H", "D", ""};\r
+ private static final String[] list34 = {"B", "H", "D", ""};\r
+ private static final String[] list35 = {"B", "H", ""};\r
+ private static final String[] list36 = {"C", "G", "L", "R", "T", ""};\r
+ private static final String[] list37 = {"EY", ""};\r
+ private static final String[] list38 = {"LI", ""};\r
+ private static final String[] list39 = {"ES", "EP", "EB", "EL", "EY", "IB", "IL", "IN", "IE", "EI", "ER", ""};\r
+ private static final String[] list40 = {"ER", ""};\r
+ private static final String[] list41 = {"DANGER", "RANGER", "MANGER", ""};\r
+ private static final String[] list42 = {"E", "I", ""};\r
+ private static final String[] list43 = {"RGY", "OGY", ""};\r
+ private static final String[] list44 = {"E", "I", "Y", ""};\r
+ private static final String[] list45 = {"AGGI", "OGGI", ""};\r
+ private static final String[] list46 = {"VAN ", "VON ", ""};\r
+ private static final String[] list47 = {"SCH", ""};\r
+ private static final String[] list48 = {"ET", ""};\r
+\r
+// DMV: used by the orininal code which returned two phonetic code, but not the current code\r
+// private static final String[] list49 = {\r
+// "IER ", ""\r
+// };\r
+ private static final String[] list50 = {"JOSE", ""};\r
+ private static final String[] list51 = {"SAN ", ""};\r
+ private static final String[] list52 = {"SAN ", ""};\r
+ private static final String[] list53 = {"JOSE", ""};\r
+ private static final String[] list54 = {"L", "T", "K", "S", "N", "M", "B", "Z", ""};\r
+ private static final String[] list55 = {"S", "K", "L", ""};\r
+ private static final String[] list56 = {"ILLO", "ILLA", "ALLE", ""};\r
+ private static final String[] list57 = {"AS", "OS", ""};\r
+ private static final String[] list58 = {"A", "O", ""};\r
+ private static final String[] list59 = {"ALLE", ""};\r
+ private static final String[] list60 = {"UMB", ""};\r
+ private static final String[] list61 = {"ER", ""};\r
+ private static final String[] list62 = {"P", "B", ""};\r
+ private static final String[] list63 = {"IE", ""};\r
+ private static final String[] list64 = {"ME", "MA", ""};\r
+ private static final String[] list65 = {"ISL", "YSL", ""};\r
+ private static final String[] list66 = {"SUGAR", ""};\r
+ private static final String[] list67 = {"SH", ""};\r
+ private static final String[] list68 = {"HEIM", "HOEK", "HOLM", "HOLZ", ""};\r
+ private static final String[] list69 = {"SIO", "SIA", ""};\r
+ private static final String[] list70 = {"SIAN", ""};\r
+ private static final String[] list71 = {"M", "N", "L", "W", ""};\r
+ private static final String[] list72 = {"Z", ""};\r
+ private static final String[] list73 = {"Z", ""};\r
+ private static final String[] list74 = {"SC", ""};\r
+ private static final String[] list75 = {"OO", "ER", "EN", "UY", "ED", "EM", ""};\r
+ private static final String[] list76 = {"ER", "EN", ""};\r
+ private static final String[] list77 = {"I", "E", "Y", ""};\r
+ private static final String[] list78 = {"AI", "OI", ""};\r
+ private static final String[] list79 = {"S", "Z", ""};\r
+ private static final String[] list80 = {"TION", ""};\r
+ private static final String[] list81 = {"TIA", "TCH", ""};\r
+ private static final String[] list82 = {"TH", ""};\r
+ private static final String[] list83 = {"TTH", ""};\r
+ private static final String[] list84 = {"OM", "AM", ""};\r
+ private static final String[] list85 = {"VAN ", "VON ", ""};\r
+ private static final String[] list86 = {"SCH", ""};\r
+ private static final String[] list87 = {"T", "D", ""};\r
+ private static final String[] list88 = {"WR", ""};\r
+ private static final String[] list89 = {"WH", ""};\r
+ private static final String[] list90 = {"EWSKI", "EWSKY", "OWSKI", "OWSKY", ""};\r
+ private static final String[] list91 = {"SCH", ""};\r
+ private static final String[] list92 = {"WICZ", "WITZ", ""};\r
+ private static final String[] list93 = {"IAU", "EAU", ""};\r
+ private static final String[] list94 = {"AU", "OU", ""};\r
+ private static final String[] list95 = {"C", "X", ""};\r
+\r
+// DMV: used by the orininal code which returned two phonetic code, but not the current code\r
+// private static final String[] list96 = {\r
+// "ZO", "ZI", "ZA", ""\r
+// };\r
+\r
+ /**\r
+ * put your documentation comment here\r
+ * @return\r
+ */\r
+ private final static boolean SlavoGermanic(String in) {\r
+ if ((in.indexOf("W") > -1) || (in.indexOf("K") > -1) || (in.indexOf("CZ") > -1) || (in.indexOf("WITZ") > -1))\r
+ return true;\r
+ return false;\r
+ }\r
+\r
+ /**\r
+ * put your documentation comment here\r
+ * @param main\r
+ */\r
+ private final static void MetaphAdd(StringBuffer primary, String main) {\r
+ if (main != null) {\r
+ primary.append(main);\r
+ }\r
+ }\r
+\r
+ private final static void MetaphAdd(StringBuffer primary, char main) {\r
+ primary.append(main);\r
+ }\r
+\r
+ /**\r
+ * put your documentation comment here\r
+ * @param at\r
+ * @return\r
+ */\r
+ private final static boolean isVowel(String in, int at, int length) {\r
+ if ((at < 0) || (at >= length))\r
+ return false;\r
+ char it = in.charAt(at);\r
+ if ((it == 'A') || (it == 'E') || (it == 'I') || (it == 'O') || (it == 'U') || (it == 'Y'))\r
+ return true;\r
+ return false;\r
+ }\r
+\r
+ /**\r
+ * put your documentation comment here\r
+ * @param string\r
+ * @param start\r
+ * @param length\r
+ * @param list\r
+ * @return\r
+ */\r
+ private final static boolean stringAt(String string, int start, int length, String[] list) {\r
+ if ((start < 0) || (start >= string.length()) || list.length == 0)\r
+ return false;\r
+ String substr = string.substring(start, start + length);\r
+ for (int i = 0; i < list.length; i++) {\r
+ if (list[i].equals(substr))\r
+ return true;\r
+ }\r
+ return false;\r
+ }\r
+\r
+ /**\r
+ * Take the given word, and return the best phonetic hash for it.\r
+ * Vowels are minimized as much as possible, and consenants\r
+ * that have similiar sounds are converted to the same consenant\r
+ * for example, 'v' and 'f' are both converted to 'f'\r
+ * @param word the texte to transform\r
+ * @return the result of the phonetic transformation\r
+ */\r
+ public final String transform(String word) {\r
+ StringBuffer primary = new StringBuffer(word.length() + 5);\r
+ String in = word.toUpperCase() + " ";\r
+ int current = 0;\r
+ int length = in.length();\r
+ if (length < 1)\r
+ return "";\r
+ int last = length - 1;\r
+ boolean isSlavoGermaic = SlavoGermanic(in);\r
+ if (stringAt(in, 0, 2, myList))\r
+ current += 1;\r
+ if (in.charAt(0) == 'X') {\r
+ MetaphAdd(primary, 'S');\r
+ current += 1;\r
+ }\r
+ while (current < length) {\r
+ switch (in.charAt(current)) {\r
+ case 'A':\r
+ case 'E':\r
+ case 'I':\r
+ case 'O':\r
+ case 'U':\r
+ case 'Y':\r
+ if (current == 0)\r
+ MetaphAdd(primary, 'A');\r
+ current += 1;\r
+ break;\r
+ case 'B':\r
+ MetaphAdd(primary, 'P');\r
+ if (in.charAt(current + 1) == 'B')\r
+ current += 2;\r
+ else\r
+ current += 1;\r
+ break;\r
+ case '\u00C7':\r
+ MetaphAdd(primary, 'S');\r
+ current += 1;\r
+ break;\r
+ case 'C':\r
+ if ((current > 1) && !isVowel(in, current - 2, length) && stringAt(in, (current - 1), 3, list1) && (in.charAt(current + 2) != 'I') && (in.charAt(current + 2) != 'E') || stringAt(in, (current - 2), 6, list2)) {\r
+ MetaphAdd(primary, 'K');\r
+ current += 2;\r
+ break;\r
+ }\r
+ if ((current == 0) && stringAt(in, current, 6, list3)) {\r
+ MetaphAdd(primary, 'S');\r
+ current += 2;\r
+ break;\r
+ }\r
+ if (stringAt(in, current, 4, list4)) {\r
+ MetaphAdd(primary, 'K');\r
+ current += 2;\r
+ break;\r
+ }\r
+ if (stringAt(in, current, 2, list5)) {\r
+ if ((current > 0) && stringAt(in, current, 4, list6)) {\r
+ MetaphAdd(primary, 'K');\r
+ current += 2;\r
+ break;\r
+ }\r
+ if ((current == 0) && stringAt(in, (current + 1), 5, list7) || stringAt(in, current + 1, 3, list8) && !stringAt(in, 0, 5, list9)) {\r
+ MetaphAdd(primary, 'K');\r
+ current += 2;\r
+ break;\r
+ }\r
+ if (stringAt(in, 0, 4, list10) || stringAt(in, 0, 3, list11) || stringAt(in, current - 2, 6, list12) || stringAt(in, current + 2, 1, list13) || (stringAt(in, current - 1, 1, list14) || (current == 0)) && stringAt(in, current + 2, 1, list15)) {\r
+ MetaphAdd(primary, 'K');\r
+ } else {\r
+ if (current > 0) {\r
+ if (stringAt(in, 0, 2, list16))\r
+ MetaphAdd(primary, 'K');\r
+ else\r
+ MetaphAdd(primary, 'X');\r
+ } else {\r
+ MetaphAdd(primary, 'X');\r
+ }\r
+ }\r
+ current += 2;\r
+ break;\r
+ }\r
+ if (stringAt(in, current, 2, list17) && !stringAt(in, current, 4, list18)) {\r
+ MetaphAdd(primary, 'S');\r
+ current += 2;\r
+ break;\r
+ }\r
+ if (stringAt(in, current, 2, list19)) {\r
+ MetaphAdd(primary, 'X');\r
+ current += 2;\r
+ break;\r
+ }\r
+ if (stringAt(in, current, 2, list20) && !((current == 1) && in.charAt(0) == 'M')) {\r
+ if (stringAt(in, current + 2, 1, list21) && !stringAt(in, current + 2, 2, list22)) {\r
+ if (((current == 1) && (in.charAt(current - 1) == 'A')) || stringAt(in, (current - 1), 5, list23))\r
+ MetaphAdd(primary, "KS");\r
+ else\r
+ MetaphAdd(primary, 'X');\r
+ current += 3;\r
+ break;\r
+ } else {\r
+ MetaphAdd(primary, 'K');\r
+ current += 2;\r
+ break;\r
+ }\r
+ }\r
+ if (stringAt(in, current, 2, list24)) {\r
+ MetaphAdd(primary, 'K');\r
+ current += 2;\r
+ break;\r
+ } else if (stringAt(in, current, 2, list25)) {\r
+ MetaphAdd(primary, 'S');\r
+ current += 2;\r
+ break;\r
+ }\r
+\r
+ MetaphAdd(primary, 'K');\r
+ if (stringAt(in, current + 1, 2, list27))\r
+ current += 3;\r
+ else if (stringAt(in, current + 1, 1, list28) && !stringAt(in, current + 1, 2, list29))\r
+ current += 2;\r
+ else\r
+ current += 1;\r
+ break;\r
+ case 'D':\r
+ if (stringAt(in, current, 2, list30)) {\r
+ if (stringAt(in, current + 2, 1, list31)) {\r
+ MetaphAdd(primary, 'J');\r
+ current += 3;\r
+ break;\r
+ } else {\r
+ MetaphAdd(primary, "TK");\r
+ current += 2;\r
+ break;\r
+ }\r
+ }\r
+ MetaphAdd(primary, 'T');\r
+ if (stringAt(in, current, 2, list32)) {\r
+ current += 2;\r
+ } else {\r
+ current += 1;\r
+ }\r
+ break;\r
+ case 'F':\r
+ if (in.charAt(current + 1) == 'F')\r
+ current += 2;\r
+ else\r
+ current += 1;\r
+ MetaphAdd(primary, 'F');\r
+ break;\r
+ case 'G':\r
+ if (in.charAt(current + 1) == 'H') {\r
+ if ((current > 0) && !isVowel(in, current - 1, length)) {\r
+ MetaphAdd(primary, 'K');\r
+ current += 2;\r
+ break;\r
+ }\r
+ if (current < 3) {\r
+ if (current == 0) {\r
+ if (in.charAt(current + 2) == 'I')\r
+ MetaphAdd(primary, 'J');\r
+ else\r
+ MetaphAdd(primary, 'K');\r
+ current += 2;\r
+ break;\r
+ }\r
+ }\r
+ if ((current > 1) && stringAt(in, current - 2, 1, list33) || ((current > 2) && stringAt(in, current - 3, 1, list34)) || ((current > 3) && stringAt(in, current - 4, 1, list35))) {\r
+ current += 2;\r
+ break;\r
+ } else {\r
+ if ((current > 2) && (in.charAt(current - 1) == 'U') && stringAt(in, current - 3, 1, list36)) {\r
+ MetaphAdd(primary, 'F');\r
+ } else {\r
+ if ((current > 0) && (in.charAt(current - 1) != 'I'))\r
+ MetaphAdd(primary, 'K');\r
+ }\r
+ current += 2;\r
+ break;\r
+ }\r
+ }\r
+ if (in.charAt(current + 1) == 'N') {\r
+ if ((current == 1) && isVowel(in, 0, length) && !isSlavoGermaic) {\r
+ MetaphAdd(primary, "KN");\r
+ } else {\r
+ if (!stringAt(in, current + 2, 2, list37) && (in.charAt(current + 1) != 'Y') && !isSlavoGermaic) {\r
+ MetaphAdd(primary, "N");\r
+ } else {\r
+ MetaphAdd(primary, "KN");\r
+ }\r
+ }\r
+ current += 2;\r
+ break;\r
+ }\r
+ if (stringAt(in, current + 1, 2, list38) && !isSlavoGermaic) {\r
+ MetaphAdd(primary, "KL");\r
+ current += 2;\r
+ break;\r
+ }\r
+ if ((current == 0) && ((in.charAt(current + 1) == 'Y') || stringAt(in, current + 1, 2, list39))) {\r
+ MetaphAdd(primary, 'K');\r
+ current += 2;\r
+ break;\r
+ }\r
+ if ((stringAt(in, current + 1, 2, list40) || (in.charAt(current + 1) == 'Y')) && !stringAt(in, 0, 6, list41) && !stringAt(in, current - 1, 1, list42) && !stringAt(in, current - 1, 3, list43)) {\r
+ MetaphAdd(primary, 'K');\r
+ current += 2;\r
+ break;\r
+ }\r
+ if (stringAt(in, current + 1, 1, list44) || stringAt(in, current - 1, 4, list45)) {\r
+ if (stringAt(in, 0, 4, list46) || stringAt(in, 0, 3, list47) || stringAt(in, current + 1, 2, list48)) {\r
+ MetaphAdd(primary, 'K');\r
+ } else {\r
+ MetaphAdd(primary, 'J');\r
+ }\r
+ current += 2;\r
+ break;\r
+ }\r
+ if (in.charAt(current + 1) == 'G')\r
+ current += 2;\r
+ else\r
+ current += 1;\r
+ MetaphAdd(primary, 'K');\r
+ break;\r
+ case 'H':\r
+ if (((current == 0) || isVowel(in, current - 1, length)) && isVowel(in, current + 1, length)) {\r
+ MetaphAdd(primary, 'H');\r
+ current += 2;\r
+ } else {\r
+ current += 1;\r
+ }\r
+ break;\r
+ case 'J':\r
+ if (stringAt(in, current, 4, list50) || stringAt(in, 0, 4, list51)) {\r
+ if ((current == 0) && (in.charAt(current + 4) == ' ') || stringAt(in, 0, 4, list52)) {\r
+ MetaphAdd(primary, 'H');\r
+ } else {\r
+ MetaphAdd(primary, 'J');\r
+ }\r
+ current += 1;\r
+ break;\r
+ }\r
+ if ((current == 0) && !stringAt(in, current, 4, list53)) {\r
+ MetaphAdd(primary, 'J');\r
+ } else {\r
+ if (isVowel(in, current - 1, length) && !isSlavoGermaic && ((in.charAt(current + 1) == 'A') || in.charAt(current + 1) == 'O')) {\r
+ MetaphAdd(primary, 'J');\r
+ } else {\r
+ if (current == last) {\r
+ MetaphAdd(primary, 'J');\r
+ } else {\r
+ if (!stringAt(in, current + 1, 1, list54) && !stringAt(in, current - 1, 1, list55)) {\r
+ MetaphAdd(primary, 'J');\r
+ }\r
+ }\r
+ }\r
+ }\r
+ if (in.charAt(current + 1) == 'J')\r
+ current += 2;\r
+ else\r
+ current += 1;\r
+ break;\r
+ case 'K':\r
+ if (in.charAt(current + 1) == 'K')\r
+ current += 2;\r
+ else\r
+ current += 1;\r
+ MetaphAdd(primary, 'K');\r
+ break;\r
+ case 'L':\r
+ if (in.charAt(current + 1) == 'L') {\r
+ if (((current == (length - 3)) && stringAt(in, current - 1, 4, list56)) || ((stringAt(in, last - 1, 2, list57) || stringAt(in, last, 1, list58)) && stringAt(in, current - 1, 4, list59))) {\r
+ MetaphAdd(primary, 'L');\r
+ current += 2;\r
+ break;\r
+ }\r
+ current += 2;\r
+ } else\r
+ current += 1;\r
+ MetaphAdd(primary, 'L');\r
+ break;\r
+ case 'M':\r
+ if ((stringAt(in, current - 1, 3, list60) && (((current + 1) == last) || stringAt(in, current + 2, 2, list61))) || (in.charAt(current + 1) == 'M'))\r
+ current += 2;\r
+ else\r
+ current += 1;\r
+ MetaphAdd(primary, 'M');\r
+ break;\r
+ case 'N':\r
+ if (in.charAt(current + 1) == 'N')\r
+ current += 2;\r
+ else\r
+ current += 1;\r
+ MetaphAdd(primary, 'N');\r
+ break;\r
+ case '\u00D1':\r
+ current += 1;\r
+ MetaphAdd(primary, 'N');\r
+ break;\r
+ case 'P':\r
+ if (in.charAt(current + 1) == 'N') {\r
+ MetaphAdd(primary, 'F');\r
+ current += 2;\r
+ break;\r
+ }\r
+ if (stringAt(in, current + 1, 1, list62))\r
+ current += 2;\r
+ else\r
+ current += 1;\r
+ MetaphAdd(primary, 'P');\r
+ break;\r
+ case 'Q':\r
+ if (in.charAt(current + 1) == 'Q')\r
+ current += 2;\r
+ else\r
+ current += 1;\r
+ MetaphAdd(primary, 'K');\r
+ break;\r
+ case 'R':\r
+ if ((current == last) && !isSlavoGermaic && stringAt(in, current - 2, 2, list63) && !stringAt(in, current - 4, 2, list64)) {\r
+// MetaphAdd(primary, "");\r
+ } else\r
+ MetaphAdd(primary, 'R');\r
+ if (in.charAt(current + 1) == 'R')\r
+ current += 2;\r
+ else\r
+ current += 1;\r
+ break;\r
+ case 'S':\r
+ if (stringAt(in, current - 1, 3, list65)) {\r
+ current += 1;\r
+ break;\r
+ }\r
+ if ((current == 0) && stringAt(in, current, 5, list66)) {\r
+ MetaphAdd(primary, 'X');\r
+ current += 1;\r
+ break;\r
+ }\r
+ if (stringAt(in, current, 2, list67)) {\r
+ if (stringAt(in, current + 1, 4, list68))\r
+ MetaphAdd(primary, 'S');\r
+ else\r
+ MetaphAdd(primary, 'X');\r
+ current += 2;\r
+ break;\r
+ }\r
+ if (stringAt(in, current, 3, list69) || stringAt(in, current, 4, list70)) {\r
+ MetaphAdd(primary, 'S');\r
+ current += 3;\r
+ break;\r
+ }\r
+ if (((current == 0) && stringAt(in, current + 1, 1, list71)) || stringAt(in, current + 1, 1, list72)) {\r
+ MetaphAdd(primary, 'S');\r
+ if (stringAt(in, current + 1, 1, list73))\r
+ current += 2;\r
+ else\r
+ current += 1;\r
+ break;\r
+ }\r
+ if (stringAt(in, current, 2, list74)) {\r
+ if (in.charAt(current + 2) == 'H')\r
+ if (stringAt(in, current + 3, 2, list75)) {\r
+ if (stringAt(in, current + 3, 2, list76)) {\r
+ MetaphAdd(primary, "X");\r
+ } else {\r
+ MetaphAdd(primary, "SK");\r
+ }\r
+ current += 3;\r
+ break;\r
+ } else {\r
+ MetaphAdd(primary, 'X');\r
+ current += 3;\r
+ break;\r
+ }\r
+ if (stringAt(in, current + 2, 1, list77)) {\r
+ MetaphAdd(primary, 'S');\r
+ current += 3;\r
+ break;\r
+ }\r
+ MetaphAdd(primary, "SK");\r
+ current += 3;\r
+ break;\r
+ }\r
+ if ((current == last) && stringAt(in, current - 2, 2, list78)) {\r
+ //MetaphAdd(primary, "");\r
+ } else\r
+ MetaphAdd(primary, 'S');\r
+ if (stringAt(in, current + 1, 1, list79))\r
+ current += 2;\r
+ else\r
+ current += 1;\r
+ break;\r
+ case 'T':\r
+ if (stringAt(in, current, 4, list80)) {\r
+ MetaphAdd(primary, 'X');\r
+ current += 3;\r
+ break;\r
+ }\r
+ if (stringAt(in, current, 3, list81)) {\r
+ MetaphAdd(primary, 'X');\r
+ current += 3;\r
+ break;\r
+ }\r
+ if (stringAt(in, current, 2, list82) || stringAt(in, current, 3, list83)) {\r
+ if (stringAt(in, (current + 2), 2, list84) || stringAt(in, 0, 4, list85) || stringAt(in, 0, 3, list86)) {\r
+ MetaphAdd(primary, 'T');\r
+ } else {\r
+ MetaphAdd(primary, '0');\r
+ }\r
+ current += 2;\r
+ break;\r
+ }\r
+ if (stringAt(in, current + 1, 1, list87)) {\r
+ current += 2;\r
+ } else\r
+ current += 1;\r
+ MetaphAdd(primary, 'T');\r
+ break;\r
+ case 'V':\r
+ if (in.charAt(current + 1) == 'V')\r
+ current += 2;\r
+ else\r
+ current += 1;\r
+ MetaphAdd(primary, 'F');\r
+ break;\r
+ case 'W':\r
+ if (stringAt(in, current, 2, list88)) {\r
+ MetaphAdd(primary, 'R');\r
+ current += 2;\r
+ break;\r
+ }\r
+ if ((current == 0) && (isVowel(in, current + 1, length) || stringAt(in, current, 2, list89))) {\r
+ MetaphAdd(primary, 'A');\r
+ }\r
+ if (((current == last) && isVowel(in, current - 1, length)) || stringAt(in, current - 1, 5, list90) || stringAt(in, 0, 3, list91)) {\r
+ MetaphAdd(primary, 'F');\r
+ current += 1;\r
+ break;\r
+ }\r
+ if (stringAt(in, current, 4, list92)) {\r
+ MetaphAdd(primary, "TS");\r
+ current += 4;\r
+ break;\r
+ }\r
+ current += 1;\r
+ break;\r
+ case 'X':\r
+ if (!((current == last) && (stringAt(in, current - 3, 3, list93) || stringAt(in, current - 2, 2, list94))))\r
+ MetaphAdd(primary, "KS");\r
+ if (stringAt(in, current + 1, 1, list95))\r
+ current += 2;\r
+ else\r
+ current += 1;\r
+ break;\r
+ case 'Z':\r
+ if (in.charAt(current + 1) == 'H') {\r
+ MetaphAdd(primary, 'J');\r
+ current += 2;\r
+ break;\r
+ } else {\r
+ MetaphAdd(primary, 'S');\r
+ }\r
+ if (in.charAt(current + 1) == 'Z')\r
+ current += 2;\r
+ else\r
+ current += 1;\r
+ break;\r
+ default:\r
+ current += 1;\r
+ }\r
+ }\r
+ return primary.toString();\r
+ }\r
+\r
+ /**\r
+ * @see com.swabunga.spell.engine.Transformator#getReplaceList()\r
+ */\r
+ public char[] getReplaceList() {\r
+ return replaceList;\r
+ }\r
+}\r
+\r
+\r
+\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.spell.engine;\r
+\r
+import java.io.BufferedReader;\r
+import java.io.InputStreamReader;\r
+\r
+/**\r
+ * This class is based on Levenshtein Distance algorithms, and it calculates how similar two words are.\r
+ * If the words are identical, then the distance is 0. The more that the words have in common, the lower the distance value.\r
+ * The distance value is based on how many operations it takes to get from one word to the other. Possible operations are\r
+ * swapping characters, adding a character, deleting a character, and substituting a character.\r
+ * The resulting distance is the sum of these operations weighted by their cost, which can be set in the Configuration object.\r
+ * When there are multiple ways to convert one word into the other, the lowest cost distance is returned.\r
+ * <br/>\r
+ * Another way to think about this: what are the cheapest operations that would have to be done on the "original" word to end up\r
+ * with the "similar" word? Each operation has a cost, and these are added up to get the distance.\r
+ * <br/>\r
+ *\r
+ * @see com.swabunga.spell.engine.Configuration#COST_REMOVE_CHAR\r
+ * @see com.swabunga.spell.engine.Configuration#COST_INSERT_CHAR\r
+ * @see com.swabunga.spell.engine.Configuration#COST_SUBST_CHARS\r
+ * @see com.swabunga.spell.engine.Configuration#COST_SWAP_CHARS\r
+ *\r
+ */\r
+\r
+public class EditDistance {\r
+\r
+ /**\r
+ * Fetches the spell engine configuration properties.\r
+ */\r
+ public static Configuration config = Configuration.getConfiguration();\r
+\r
+ /**\r
+ * get the weights for each possible operation\r
+ */\r
+ static final int costOfDeletingSourceCharacter = config.getInteger(Configuration.COST_REMOVE_CHAR);\r
+ static final int costOfInsertingSourceCharacter = config.getInteger(Configuration.COST_INSERT_CHAR);\r
+ static final int costOfSubstitutingLetters = config.getInteger(Configuration.COST_SUBST_CHARS);\r
+ static final int costOfSwappingLetters = config.getInteger(Configuration.COST_SWAP_CHARS);\r
+ static final int costOfChangingCase = config.getInteger(Configuration.COST_CHANGE_CASE); \r
+\r
+ /**\r
+ * Evaluates the distance between two words.\r
+ * \r
+ * @param word One word to evaluates\r
+ * @param similar The other word to evaluates\r
+ * @return a number representing how easy or complex it is to transform on\r
+ * word into a similar one.\r
+ */\r
+ public static final int getDistance(String word, String similar) {\r
+ return getDistance(word,similar,null);\r
+ } \r
+ \r
+ /**\r
+ * Evaluates the distance between two words.\r
+ * \r
+ * @param word One word to evaluates\r
+ * @param similar The other word to evaluates\r
+ * @return a number representing how easy or complex it is to transform on\r
+ * word into a similar one.\r
+ */\r
+ public static final int getDistance(String word, String similar, int[][] matrix) {\r
+ /* JMH Again, there is no need to have a global class matrix variable\r
+ * in this class. I have removed it and made the getDistance static final\r
+ * DMV: I refactored this method to make it more efficient, more readable, and simpler.\r
+ * I also fixed a bug with how the distance was being calculated. You could get wrong\r
+ * distances if you compared ("abc" to "ab") depending on what you had setup your\r
+ * COST_REMOVE_CHAR and EDIT_INSERTION_COST values to - that is now fixed.\r
+ * WRS: I added a distance for case comparison, so a misspelling of "i" would be closer to "I" than\r
+ * to "a".\r
+ */\r
+\r
+ //Allocate memory outside of the loops. \r
+ int i;\r
+ int j;\r
+ int costOfSubst;\r
+ int costOfSwap;\r
+ int costOfDelete;\r
+ int costOfInsertion;\r
+ int costOfCaseChange;\r
+ \r
+ boolean isSwap;\r
+ char sourceChar = 0;\r
+ char otherChar = 0;\r
+ \r
+ int a_size = word.length() + 1;\r
+ int b_size = similar.length() + 1;\r
+ \r
+ \r
+ //Only allocate new memory if we need a bigger matrix. \r
+ if (matrix == null || matrix.length < a_size || matrix[0].length < b_size)\r
+ matrix = new int[a_size][b_size];\r
+ \r
+ matrix[0][0] = 0;\r
+\r
+ for (i = 1; i != a_size; ++i)\r
+ matrix[i][0] = matrix[i - 1][0] + costOfInsertingSourceCharacter; //initialize the first column\r
+\r
+ for (j = 1; j != b_size; ++j)\r
+ matrix[0][j] = matrix[0][j - 1] + costOfDeletingSourceCharacter; //initalize the first row\r
+\r
+ for (i = 1; i != a_size; ++i) {\r
+ sourceChar = word.charAt(i-1);\r
+ for (j = 1; j != b_size; ++j) {\r
+\r
+ otherChar = similar.charAt(j-1);\r
+ if (sourceChar == otherChar) {\r
+ matrix[i][j] = matrix[i - 1][j - 1]; //no change required, so just carry the current cost up\r
+ continue;\r
+ }\r
+\r
+ costOfSubst = costOfSubstitutingLetters + matrix[i - 1][j - 1];\r
+ //if needed, add up the cost of doing a swap\r
+ costOfSwap = Integer.MAX_VALUE;\r
+\r
+ isSwap = (i != 1) && (j != 1) && sourceChar == similar.charAt(j - 2) && word.charAt(i - 2) == otherChar;\r
+ if (isSwap)\r
+ costOfSwap = costOfSwappingLetters + matrix[i - 2][j - 2];\r
+\r
+ costOfDelete = costOfDeletingSourceCharacter + matrix[i][j - 1];\r
+ costOfInsertion = costOfInsertingSourceCharacter + matrix[i - 1][j];\r
+\r
+ costOfCaseChange = Integer.MAX_VALUE;\r
+ \r
+ if (equalIgnoreCase(sourceChar, otherChar))\r
+ costOfCaseChange = costOfChangingCase + matrix[i - 1][j - 1];\r
+ \r
+ matrix[i][j] = minimum(costOfSubst, costOfSwap, costOfDelete, costOfInsertion, costOfCaseChange);\r
+ }\r
+ }\r
+\r
+ return matrix[a_size - 1][b_size - 1];\r
+ }\r
+\r
+ /**\r
+ * checks to see if the two charactors are equal ignoring case. \r
+ * @param ch1\r
+ * @param ch2\r
+ * @return boolean\r
+ */\r
+ private static boolean equalIgnoreCase(char ch1, char ch2) {\r
+ if (ch1 == ch2)\r
+ {\r
+ return true;\r
+ }\r
+ else\r
+ {\r
+ return (Character.toLowerCase(ch1) == Character.toLowerCase(ch2));\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * For debugging, this creates a string that represents the matrix. To read the matrix, look at any square. That is the cost to get from\r
+ * the partial letters along the top to the partial letters along the side.\r
+ * @param src - the source string that the matrix columns are based on\r
+ * @param dest - the dest string that the matrix rows are based on\r
+ * @param matrix - a two dimensional array of costs (distances)\r
+ * @return String\r
+ */\r
+ @SuppressWarnings("unused")\r
+static private String dumpMatrix(String src, String dest, int matrix[][]) {\r
+ StringBuffer s = new StringBuffer("");\r
+\r
+ int cols = matrix.length -1;\r
+ int rows = matrix[0].length -1;\r
+\r
+ for (int i = 0; i < cols + 1; i++) {\r
+ for (int j = 0; j < rows + 1; j++) {\r
+ if (i == 0 && j == 0) {\r
+ s.append("\n ");\r
+ continue;\r
+\r
+ }\r
+ if (i == 0) {\r
+ s.append("| ");\r
+ s.append(dest.charAt(j - 1));\r
+ continue;\r
+ }\r
+ if (j == 0) {\r
+ s.append(src.charAt(i - 1));\r
+ continue;\r
+ }\r
+ String num = Integer.toString(matrix[i - 1][j - 1]);\r
+ int padding = 4 - num.length();\r
+ s.append("|");\r
+ for (int k = 0; k < padding; k++)\r
+ s.append(' ');\r
+ s.append(num);\r
+ }\r
+ s.append('\n');\r
+ }\r
+ return s.toString();\r
+\r
+ }\r
+\r
+\r
+ static private int minimum(int a, int b, int c, int d, int e) {\r
+ int mi = a;\r
+ if (b < mi)\r
+ mi = b;\r
+ if (c < mi)\r
+ mi = c;\r
+ if (d < mi)\r
+ mi = d;\r
+ if (e < mi)\r
+ mi = e;\r
+\r
+ return mi;\r
+ }\r
+\r
+ /**\r
+ * For testing edit distances\r
+ * @param args an array of two strings we want to evaluate their distances.\r
+ * @throws java.lang.Exception when problems occurs during reading args.\r
+ */\r
+ public static void main(String[] args) throws Exception {\r
+ BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));\r
+ int[][] matrix = new int[0][0]; \r
+ while (true) {\r
+\r
+ String input1 = stdin.readLine();\r
+ if (input1 == null || input1.length() == 0)\r
+ break;\r
+\r
+ String input2 = stdin.readLine();\r
+ if (input2 == null || input2.length() == 0)\r
+ break;\r
+\r
+ System.out.println(EditDistance.getDistance(input1, input2,matrix));\r
+ }\r
+ System.out.println("done");\r
+ }\r
+}\r
+\r
+\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.spell.engine;\r
+\r
+import java.io.BufferedReader;\r
+import java.io.File;\r
+import java.io.FileNotFoundException;\r
+import java.io.FileReader;\r
+import java.io.FileWriter;\r
+import java.io.IOException;\r
+import java.util.HashMap;\r
+import java.util.LinkedList;\r
+import java.util.List;\r
+import java.util.Vector;\r
+\r
+/**\r
+ * The SpellDictionary class holds the instance of the dictionary.\r
+ * <p>\r
+ * This class is thread safe. Derived classes should ensure that this preserved.\r
+ * </p>\r
+ * <p>\r
+ * There are many open source dictionary files. For just a few see:\r
+ * http://wordlist.sourceforge.net/\r
+ * </p>\r
+ * <p>\r
+ * This dictionary class reads words one per line. Make sure that your word list\r
+ * is formatted in this way (most are).\r
+ * </p>\r
+ */\r
+public class GenericSpellDictionary extends SpellDictionaryASpell {\r
+\r
+//tech_monkey: the alphabet / replace list stuff has been moved into the Transformator classes,\r
+//since they are so closely tied to how the phonetic transformations are done.\r
+// /**\r
+// * This replace list is used if no phonetic file is supplied or it doesn't\r
+// * contain the alphabet.\r
+// */\r
+// protected static final char[] englishAlphabet =\r
+\r
+\r
+ /** A field indicating the initial hash map capacity (16KB) for the main\r
+ * dictionary hash map. Interested to see what the performance of a\r
+ * smaller initial capacity is like.\r
+ */\r
+ private final static int INITIAL_CAPACITY = 16 * 1024;\r
+\r
+ /**\r
+ * The hashmap that contains the word dictionary. The map is hashed on the doublemeta\r
+ * code. The map entry contains a LinkedList of words that have the same double meta code.\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+protected HashMap mainDictionary = new HashMap(INITIAL_CAPACITY);\r
+\r
+ /** Holds the dictionary file for appending*/\r
+ private File dictFile = null;\r
+\r
+\r
+ /**\r
+ * Dictionary constructor that uses the DoubleMeta class with the\r
+ * English alphabet.\r
+ * @param wordList The file containing dictionary as a words list.\r
+ * @throws java.io.FileNotFoundException when the words list file could not \r
+ * be located on the system.\r
+ * @throws java.io.IOException when problems occurs while reading the words \r
+ * list file\r
+ */\r
+ public GenericSpellDictionary(File wordList) throws FileNotFoundException, IOException {\r
+ this(wordList, (File) null);\r
+ }\r
+\r
+ /**\r
+ * Dictionary constructor that uses an aspell phonetic file to\r
+ * build the transformation table.\r
+ * If phonetic is null, then DoubleMeta is used with the English alphabet\r
+ * @param wordList The file containing dictionary as a words list.\r
+ * @param phonetic The file containing the phonetic transformation \r
+ * information.\r
+ * @throws java.io.FileNotFoundException when the words list or phonetic \r
+ * file could not be located on the system\r
+ * @throws java.io.IOException when problems occurs while reading the \r
+ * words list or phonetic file\r
+ */\r
+ public GenericSpellDictionary(File wordList, File phonetic) throws FileNotFoundException, IOException {\r
+\r
+ super(phonetic);\r
+ dictFile = wordList;\r
+ createDictionary(new BufferedReader(new FileReader(wordList)));\r
+ }\r
+\r
+\r
+ /**\r
+ * Add a word permanently to the dictionary (and the dictionary file).\r
+ * <p>This needs to be made thread safe (synchronized)</p>\r
+ * @param word The word to add to the dictionary\r
+ */\r
+ public void addWord(String word) {\r
+ putWord(word);\r
+ if (dictFile == null)\r
+ return;\r
+ try {\r
+ FileWriter w = new FileWriter(dictFile.toString(), true);\r
+ // Open with append.\r
+ w.write(word);\r
+ w.write("\n");\r
+ w.close();\r
+ } catch (IOException ex) {\r
+ System.out.println("Error writing to dictionary file");\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Constructs the dictionary from a word list file.\r
+ * <p>\r
+ * Each word in the reader should be on a separate line.\r
+ * <p>\r
+ * This is a very slow function. On my machine it takes quite a while to\r
+ * load the data in. I suspect that we could speed this up quite allot.\r
+ */\r
+ protected void createDictionary(BufferedReader in) throws IOException {\r
+ String line = "";\r
+ while (line != null) {\r
+ line = in.readLine();\r
+ if (line != null) {\r
+ line = new String(line.toCharArray());\r
+ putWord(line);\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Allocates a word in the dictionary\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+protected void putWord(String word) {\r
+ String code = getCode(word);\r
+ LinkedList list = (LinkedList) mainDictionary.get(code);\r
+ if (list != null) {\r
+ list.add(word);\r
+ } else {\r
+ list = new LinkedList();\r
+ list.add(word);\r
+ mainDictionary.put(code, list);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Returns a list of strings (words) for the code.\r
+ * @param code The phonetic code we want to find words for\r
+ * @return the list of words having the same phonetic code\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+@Override\r
+public List getWords(String code) {\r
+ //Check the main dictionary.\r
+ List mainDictResult = (List) mainDictionary.get(code);\r
+ if (mainDictResult == null)\r
+ return new Vector();\r
+ return mainDictResult;\r
+ }\r
+\r
+ /**\r
+ * Returns true if the word is correctly spelled against the current word list.\r
+ * @param word The word to checked in the dictionary\r
+ * @return indication if the word is in the dictionary\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+@Override\r
+public boolean isCorrect(String word) {\r
+ List possible = getWords(getCode(word));\r
+ if (possible.contains(word))\r
+ return true;\r
+ //JMH should we always try the lowercase version. If I dont then capitalised\r
+ //words are always returned as incorrect.\r
+ else if (possible.contains(word.toLowerCase()))\r
+ return true;\r
+ return false;\r
+ }\r
+}\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.spell.engine;\r
+\r
+import java.io.BufferedReader;\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.FileReader;\r
+import java.io.IOException;\r
+import java.io.InputStreamReader;\r
+import java.io.Reader;\r
+import java.util.HashMap;\r
+import java.util.Vector;\r
+\r
+import com.swabunga.util.StringUtility;\r
+\r
+/**\r
+ * A Generic implementation of a transformator takes an \r
+ * <a href="http://aspell.net/man-html/Phonetic-Code.html">\r
+ * aspell phonetics file</a> and constructs some sort of transformation \r
+ * table using the inner class TransformationRule.\r
+ * </p>\r
+ * Basically, each transformation rule represent a line in the phonetic file.\r
+ * One line contains two groups of characters separated by white space(s).\r
+ * The first group is the <em>match expression</em>. \r
+ * The <em>match expression</em> describe letters to associate with a syllable.\r
+ * The second group is the <em>replacement expression</em> giving the phonetic \r
+ * equivalent of the <em>match expression</em>.\r
+ *\r
+ * @see SpellDictionaryASpell SpellDictionaryASpell for information on getting\r
+ * phonetic files for aspell.\r
+ *\r
+ * @author Robert Gustavsson (robert@lindesign.se)\r
+ */\r
+public class GenericTransformator implements Transformator {\r
+\r
+\r
+ /**\r
+ * This replace list is used if no phonetic file is supplied or it doesn't\r
+ * contain the alphabet.\r
+ */\r
+ private static final char[] defaultEnglishAlphabet = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};\r
+\r
+ /**\r
+ * The alphabet start marker.\r
+ * @see GenericTransformator#KEYWORD_ALPHBET KEYWORD_ALPHBET\r
+ */\r
+ public static final char ALPHABET_START = '[';\r
+ /**\r
+ * The alphabet end marker.\r
+ * @see GenericTransformator#KEYWORD_ALPHBET KEYWORD_ALPHBET\r
+ */\r
+ public static final char ALPHABET_END = ']';\r
+ /**\r
+ * Phonetic file keyword indicating that a different alphabet is used \r
+ * for this language. The keyword must be followed an\r
+ * {@link GenericTransformator#ALPHABET_START ALPHABET_START} marker, \r
+ * a list of characters defining the alphabet and a\r
+ * {@link GenericTransformator#ALPHABET_END ALPHABET_END} marker.\r
+ */\r
+ public static final String KEYWORD_ALPHBET = "alphabet";\r
+ /**\r
+ * Phonetic file lines starting with the keywords are skipped. \r
+ * The key words are: version, followup, collapse_result.\r
+ * Comments, starting with '#', are also skipped to the end of line.\r
+ */\r
+ public static final String[] IGNORED_KEYWORDS = {"version", "followup", "collapse_result"};\r
+\r
+ /**\r
+ * Start a group of characters which can be appended to the match expression\r
+ * of the phonetic file.\r
+ */\r
+ public static final char STARTMULTI = '(';\r
+ /**\r
+ * End a group of characters which can be appended to the match expression\r
+ * of the phonetic file.\r
+ */\r
+ public static final char ENDMULTI = ')';\r
+ /**\r
+ * During phonetic transformation of a word each numeric character is\r
+ * replaced by this DIGITCODE.\r
+ */\r
+ public static final String DIGITCODE = "0";\r
+ /**\r
+ * Phonetic file character code indicating that the replace expression\r
+ * is empty.\r
+ */\r
+ public static final String REPLACEVOID = "_";\r
+\r
+ private Object[] ruleArray = null;\r
+ private char[] alphabetString = defaultEnglishAlphabet;\r
+\r
+ /**\r
+ * Construct a transformation table from the phonetic file\r
+ * @param phonetic the phonetic file as specified in aspell\r
+ * @throws java.io.IOException indicates a problem while reading\r
+ * the phonetic file\r
+ */\r
+ public GenericTransformator(File phonetic) throws IOException {\r
+ buildRules(new BufferedReader(new FileReader(phonetic)));\r
+ alphabetString = washAlphabetIntoReplaceList(getReplaceList());\r
+\r
+ }\r
+\r
+ /**\r
+ * Construct a transformation table from the phonetic file\r
+ * @param phonetic the phonetic file as specified in aspell\r
+ * @param encoding the character set required\r
+ * @throws java.io.IOException indicates a problem while reading\r
+ * the phonetic file\r
+ */\r
+ public GenericTransformator(File phonetic, String encoding) throws IOException {\r
+ buildRules(new BufferedReader(new InputStreamReader(new FileInputStream(phonetic), encoding)));\r
+ alphabetString = washAlphabetIntoReplaceList(getReplaceList());\r
+ }\r
+\r
+ /**\r
+ * Construct a transformation table from the phonetic file\r
+ * @param phonetic the phonetic file as specified in aspell. The file is\r
+ * supplied as a reader.\r
+ * @throws java.io.IOException indicates a problem while reading\r
+ * the phonetic information\r
+ */\r
+ public GenericTransformator(Reader phonetic) throws IOException {\r
+ buildRules(new BufferedReader(phonetic));\r
+ alphabetString = washAlphabetIntoReplaceList(getReplaceList());\r
+ }\r
+\r
+ /**\r
+ * Goes through an alphabet and makes sure that only one of those letters\r
+ * that are coded equally will be in the replace list.\r
+ * In other words, it removes any letters in the alphabet\r
+ * that are redundant phonetically.\r
+ *\r
+ * This is done to improve speed in the getSuggestion method.\r
+ *\r
+ * @param alphabet The complete alphabet to wash.\r
+ * @return The washed alphabet to be used as replace list.\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+private char[] washAlphabetIntoReplaceList(char[] alphabet) {\r
+\r
+ HashMap letters = new HashMap(alphabet.length);\r
+\r
+ for (char element : alphabet) {\r
+ String tmp = String.valueOf(element);\r
+ String code = transform(tmp);\r
+ if (!letters.containsKey(code)) {\r
+ letters.put(code, new Character(element));\r
+ }\r
+ }\r
+\r
+ Object[] tmpCharacters = letters.values().toArray();\r
+ char[] washedArray = new char[tmpCharacters.length];\r
+\r
+ for (int i = 0; i < tmpCharacters.length; i++) {\r
+ washedArray[i] = ((Character) tmpCharacters[i]).charValue();\r
+ }\r
+\r
+ return washedArray;\r
+ }\r
+\r
+\r
+ /**\r
+ * Takes out all single character replacements and put them in a char array.\r
+ * This array can later be used for adding or changing letters in getSuggestion().\r
+ * @return char[] An array of chars with replacements characters\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+public char[] getCodeReplaceList() {\r
+ char[] replacements;\r
+ TransformationRule rule;\r
+ Vector tmp = new Vector();\r
+\r
+ if (ruleArray == null)\r
+ return null;\r
+ for (Object element : ruleArray) {\r
+ rule = (TransformationRule) element;\r
+ if (rule.getReplaceExp().length() == 1)\r
+ tmp.addElement(rule.getReplaceExp());\r
+ }\r
+ replacements = new char[tmp.size()];\r
+ for (int i = 0; i < tmp.size(); i++) {\r
+ replacements[i] = ((String) tmp.elementAt(i)).charAt(0);\r
+ }\r
+ return replacements;\r
+ }\r
+\r
+ /**\r
+ * Builds up an char array with the chars in the alphabet of the language as it was read from the\r
+ * alphabet tag in the phonetic file.\r
+ * @return char[] An array of chars representing the alphabet or null if no alphabet was available.\r
+ */\r
+ public char[] getReplaceList() {\r
+ return alphabetString;\r
+ }\r
+\r
+ /**\r
+ * Builds the phonetic code of the word.\r
+ * @param word the word to transform\r
+ * @return the phonetic transformation of the word\r
+ */\r
+ public String transform(String word) {\r
+\r
+ if (ruleArray == null)\r
+ return null;\r
+\r
+ TransformationRule rule;\r
+ StringBuffer str = new StringBuffer(word.toUpperCase());\r
+ int strLength = str.length();\r
+ int startPos = 0, add = 1;\r
+\r
+ while (startPos < strLength) {\r
+\r
+ add = 1;\r
+ if (Character.isDigit(str.charAt(startPos))) {\r
+ StringUtility.replace(str, startPos, startPos + DIGITCODE.length(), DIGITCODE);\r
+ startPos += add;\r
+ continue;\r
+ }\r
+\r
+ for (Object element : ruleArray) {\r
+ //System.out.println("Testing rule#:"+i);\r
+ rule = (TransformationRule) element;\r
+ if (rule.startsWithExp() && startPos > 0)\r
+ continue;\r
+ if (startPos + rule.lengthOfMatch() > strLength) {\r
+ continue;\r
+ }\r
+ if (rule.isMatching(str, startPos)) {\r
+ String replaceExp = rule.getReplaceExp();\r
+\r
+ add = replaceExp.length();\r
+ StringUtility.replace(str, startPos, startPos + rule.getTakeOut(), replaceExp);\r
+ strLength -= rule.getTakeOut();\r
+ strLength += add;\r
+ //System.out.println("Replacing with rule#:"+i+" add="+add);\r
+ break;\r
+ }\r
+ }\r
+ startPos += add;\r
+ }\r
+ //System.out.println(word);\r
+ //System.out.println(str.toString());\r
+ return str.toString();\r
+ }\r
+\r
+ // Used to build up the transformastion table.\r
+ @SuppressWarnings("unchecked")\r
+private void buildRules(BufferedReader in) throws IOException {\r
+ String read = null;\r
+ Vector ruleList = new Vector();\r
+ while ((read = in.readLine()) != null) {\r
+ buildRule(realTrimmer(read), ruleList);\r
+ }\r
+ ruleArray = new TransformationRule[ruleList.size()];\r
+ ruleList.copyInto(ruleArray);\r
+ }\r
+\r
+ // Here is where the real work of reading the phonetics file is done.\r
+ @SuppressWarnings("unchecked")\r
+private void buildRule(String str, Vector ruleList) {\r
+ if (str.length() < 1)\r
+ return;\r
+ for (String element : IGNORED_KEYWORDS) {\r
+ if (str.startsWith(element))\r
+ return;\r
+ }\r
+\r
+ // A different alphabet is used for this language, will be read into\r
+ // the alphabetString variable.\r
+ if (str.startsWith(KEYWORD_ALPHBET)) {\r
+ int start = str.indexOf(ALPHABET_START);\r
+ int end = str.lastIndexOf(ALPHABET_END);\r
+ if (end != -1 && start != -1) {\r
+ alphabetString = str.substring(++start, end).toCharArray();\r
+ }\r
+ return;\r
+ }\r
+\r
+ // str contains two groups of characters separated by white space(s).\r
+ // The fisrt group is the "match expression". The second group is the \r
+ // "replacement expression" giving the phonetic equivalent of the \r
+ // "match expression".\r
+ TransformationRule rule = null;\r
+ StringBuffer matchExp = new StringBuffer();\r
+ StringBuffer replaceExp = new StringBuffer();\r
+ boolean start = false,\r
+ end = false;\r
+ int takeOutPart = 0,\r
+ matchLength = 0;\r
+ boolean match = true,\r
+ inMulti = false;\r
+ for (int i = 0; i < str.length(); i++) {\r
+ if (Character.isWhitespace(str.charAt(i))) {\r
+ match = false;\r
+ } else {\r
+ if (match) {\r
+ if (!isReservedChar(str.charAt(i))) {\r
+ matchExp.append(str.charAt(i));\r
+ if (!inMulti) {\r
+ takeOutPart++;\r
+ matchLength++;\r
+ }\r
+ if (str.charAt(i) == STARTMULTI || str.charAt(i) == ENDMULTI)\r
+ inMulti = !inMulti;\r
+ }\r
+ if (str.charAt(i) == '-')\r
+ takeOutPart--;\r
+ if (str.charAt(i) == '^')\r
+ start = true;\r
+ if (str.charAt(i) == '$')\r
+ end = true;\r
+ } else {\r
+ replaceExp.append(str.charAt(i));\r
+ }\r
+ }\r
+ }\r
+ if (replaceExp.toString().equals(REPLACEVOID)) {\r
+ replaceExp = new StringBuffer("");\r
+ //System.out.println("Changing _ to \"\" for "+matchExp.toString());\r
+ }\r
+ rule = new TransformationRule(matchExp.toString(), replaceExp.toString(), takeOutPart, matchLength, start, end);\r
+ //System.out.println(rule.toString());\r
+ ruleList.addElement(rule);\r
+ }\r
+\r
+ // Chars with special meaning to aspell. Not everyone is implemented here.\r
+ private boolean isReservedChar(char ch) {\r
+ if (ch == '<' || ch == '>' || ch == '^' || ch == '$' || ch == '-' || Character.isDigit(ch))\r
+ return true;\r
+ return false;\r
+ }\r
+\r
+ // Trims off everything we don't care about.\r
+ private String realTrimmer(String row) {\r
+ int pos = row.indexOf('#');\r
+ if (pos != -1) {\r
+ row = row.substring(0, pos);\r
+ }\r
+ return row.trim();\r
+ }\r
+\r
+ // Inner Classes\r
+ /*\r
+ * Holds the match string and the replace string and all the rule attributes.\r
+ * Is responsible for indicating matches.\r
+ */\r
+ private class TransformationRule {\r
+\r
+ private final String replace;\r
+ private final char[] match;\r
+ // takeOut=number of chars to replace;\r
+ // matchLength=length of matching string counting multies as one.\r
+ private final int takeOut, matchLength;\r
+ private final boolean start, end;\r
+\r
+ // Construktor\r
+ public TransformationRule(String match, String replace, int takeout, int matchLength, boolean start, boolean end) {\r
+ this.match = match.toCharArray();\r
+ this.replace = replace;\r
+ this.takeOut = takeout;\r
+ this.matchLength = matchLength;\r
+ this.start = start;\r
+ this.end = end;\r
+ }\r
+\r
+ /*\r
+ * Returns true if word from pos and forward matches the match string.\r
+ * Precondition: wordPos+matchLength<word.length()\r
+ */\r
+ public boolean isMatching(StringBuffer word, int wordPos) {\r
+ boolean matching = true, inMulti = false, multiMatch = false;\r
+ char matchCh;\r
+\r
+ for (char element : match) {\r
+ matchCh = element;\r
+ if (matchCh == STARTMULTI || matchCh == ENDMULTI) {\r
+ inMulti = !inMulti;\r
+ if (!inMulti)\r
+ matching = matching & multiMatch;\r
+ else\r
+ multiMatch = false;\r
+ } else {\r
+ if (matchCh != word.charAt(wordPos)) {\r
+ if (inMulti)\r
+ multiMatch = multiMatch | false;\r
+ else\r
+ matching = false;\r
+ } else {\r
+ if (inMulti)\r
+ multiMatch = multiMatch | true;\r
+ else\r
+ matching = true;\r
+ }\r
+ if (!inMulti)\r
+ wordPos++;\r
+ if (!matching)\r
+ break;\r
+ }\r
+ }\r
+ if (end && wordPos != word.length())\r
+ matching = false;\r
+ return matching;\r
+ }\r
+\r
+ public String getReplaceExp() {\r
+ return replace;\r
+ }\r
+\r
+ public int getTakeOut() {\r
+ return takeOut;\r
+ }\r
+\r
+ public boolean startsWithExp() {\r
+ return start;\r
+ }\r
+\r
+ public int lengthOfMatch() {\r
+ return matchLength;\r
+ }\r
+\r
+ // Just for debugging purposes.\r
+ @Override\r
+ public String toString() {\r
+ return "Match:" + String.valueOf(match) + " Replace:" + replace + " TakeOut:" + takeOut + " MatchLength:" + matchLength + " Start:" + start + " End:" + end;\r
+ }\r
+\r
+ }\r
+}\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.spell.engine;\r
+\r
+import java.io.*;\r
+import java.net.URL;\r
+import java.util.Properties;\r
+\r
+\r
+/**\r
+ * Implementation class to read the properties controlling the spell engine. \r
+ * The properties are read form the <code>configuration.properties</code> file.\r
+ *\r
+ * @author aim4min\r
+ */\r
+public class PropertyConfiguration extends Configuration {\r
+\r
+ /**\r
+ * The persistent set of properties supported by the spell engine\r
+ */\r
+ public Properties prop;\r
+ /**\r
+ * The name of the file containing spell engine properties\r
+ */\r
+ public URL filename;\r
+\r
+ /**\r
+ * Constructs and loads spell engine properties configuration.\r
+ */\r
+ public PropertyConfiguration() {\r
+ prop = new Properties();\r
+ try {\r
+ filename = getClass().getClassLoader().getResource("com/swabunga/spell/engine/configuration.properties");\r
+ InputStream in = filename.openStream();\r
+ prop.load(in);\r
+ } catch (Exception e) {\r
+ System.out.println("Could not load Properties file :\n" + e);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * @see com.swabunga.spell.engine.Configuration#getBoolean(String)\r
+ */\r
+ public boolean getBoolean(String key) {\r
+ return new Boolean(prop.getProperty(key)).booleanValue();\r
+ }\r
+\r
+ /**\r
+ * @see com.swabunga.spell.engine.Configuration#getInteger(String)\r
+ */\r
+ public int getInteger(String key) {\r
+ return new Integer(prop.getProperty(key)).intValue();\r
+ }\r
+\r
+ /**\r
+ * @see com.swabunga.spell.engine.Configuration#setBoolean(String, boolean)\r
+ */\r
+ public void setBoolean(String key, boolean value) {\r
+ String string = null;\r
+ if (value)\r
+ string = "true";\r
+ else\r
+ string = "false";\r
+\r
+ prop.setProperty(key, string);\r
+ save();\r
+ }\r
+\r
+ /**\r
+ * @see com.swabunga.spell.engine.Configuration#setInteger(String, int)\r
+ */\r
+ public void setInteger(String key, int value) {\r
+ prop.setProperty(key, Integer.toString(value));\r
+ save();\r
+ }\r
+\r
+ /**\r
+ * Writes the property list (key and element pairs) in the \r
+ * PropertyConfiguration file.\r
+ */\r
+ public void save() {\r
+ try {\r
+ File file = new File(filename.getFile());\r
+ FileOutputStream fout = new FileOutputStream(file);\r
+ prop.store(fout, "HEADER");\r
+ } catch (FileNotFoundException e) {\r
+ } catch (IOException e) {\r
+ }\r
+ }\r
+\r
+}\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.spell.engine;\r
+\r
+import java.util.List;\r
+\r
+/**\r
+ * An interface for all dictionary implementations. It defines the most basic\r
+ * operations on a dictionary: adding words, checking if a word is correct, and getting a list\r
+ * of suggestions for misspelled words.\r
+ */\r
+public interface SpellDictionary {\r
+\r
+ /**\r
+ * Add a word permanently to the dictionary.\r
+ * @param word The word to add to the dictionary\r
+ */\r
+ public void addWord(String word);\r
+\r
+ /**\r
+ * Evaluates if the word is correctly spelled against the dictionary.\r
+ * @param word The word to verify if it's spelling is OK.\r
+ * @return Indicates if the word is present in the dictionary.\r
+ */\r
+ public boolean isCorrect(String word);\r
+\r
+ /**\r
+ * Returns a list of Word objects that are the suggestions to any word.\r
+ * If the word is correctly spelled, then this method\r
+ * could return just that one word, or it could still return a list\r
+ * of words with similar spellings.\r
+ * <br/>\r
+ * Each suggested word has a score, which is an integer\r
+ * that represents how different the suggested word is from the sourceWord.\r
+ * If the words are the exactly the same, then the score is 0.\r
+ * You can get the dictionary to only return the most similar words by setting\r
+ * an appropriately low threshold value.\r
+ * If you set the threshold value too low, you may get no suggestions for a given word.\r
+ * <p>\r
+ * This method is only needed to provide backward compatibility. \r
+ * @see #getSuggestions(String, int, int[][])\r
+ * \r
+ * @param sourceWord the string that we want to get a list of spelling suggestions for\r
+ * @param scoreThreshold Any words that have score less than this number are returned.\r
+ * @return List a List of suggested words\r
+ * @see com.swabunga.spell.engine.Word\r
+ * \r
+ */\r
+ @SuppressWarnings("unchecked")\r
+public List getSuggestions(String sourceWord, int scoreThreshold);\r
+\r
+ /**\r
+ * Returns a list of Word objects that are the suggestions to any word.\r
+ * If the word is correctly spelled, then this method\r
+ * could return just that one word, or it could still return a list\r
+ * of words with similar spellings.\r
+ * <br/>\r
+ * Each suggested word has a score, which is an integer\r
+ * that represents how different the suggested word is from the sourceWord.\r
+ * If the words are the exactly the same, then the score is 0.\r
+ * You can get the dictionary to only return the most similar words by setting\r
+ * an appropriately low threshold value.\r
+ * If you set the threshold value too low, you may get no suggestions for a given word.\r
+ * <p>\r
+ * @param sourceWord the string that we want to get a list of spelling suggestions for\r
+ * @param scoreThreshold Any words that have score less than this number are returned.\r
+ * @param Two dimensional int array used to calculate edit distance. Allocating \r
+ * this memory outside of the function will greatly improve efficiency. \r
+ * @return List a List of suggested words\r
+ * @see com.swabunga.spell.engine.Word\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+public List getSuggestions(String sourceWord, int scoreThreshold , int[][] matrix);\r
+\r
+}\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+/* Created by bgalbs on Jan 30, 2003 at 11:45:25 PM */\r
+package com.swabunga.spell.engine;\r
+\r
+import java.io.File;\r
+import java.io.IOException;\r
+import java.io.Reader;\r
+import java.security.InvalidParameterException;\r
+import java.util.Collections;\r
+import java.util.Enumeration;\r
+import java.util.Hashtable;\r
+import java.util.Iterator;\r
+import java.util.LinkedList;\r
+import java.util.List;\r
+import java.util.Vector;\r
+\r
+/**\r
+ * Container for various methods that any <code>SpellDictionary</code> will use.\r
+ * This class is based on the original Jazzy aspell port.\r
+ * <p/>\r
+ * Derived classes will need words list files as spell checking reference. \r
+ * Words list file is a dictionary with one word per line. There are many \r
+ * open source dictionary files, see: \r
+ * <a href="http://wordlist.sourceforge.net/">\r
+ * http://wordlist.sourceforge.net/</a>\r
+ * <p/>\r
+ * You can choose words lists form <a href="http://aspell.net/">aspell</a> \r
+ * many differents languages dictionaries. To grab some, install \r
+ * <code>aspell</code> and the dictionaries you require. Then run aspell \r
+ * specifying the name of the dictionary and the words list file to dump it \r
+ * into, for example:\r
+ * <pre>\r
+ * aspell --master=fr-40 dump master > fr-40.txt\r
+ * </pre>\r
+ * Note: the number following the language is the size indicator. A bigger\r
+ * number gives a more extensive language coverage. Size 40 is more than \r
+ * adequate for many usages.\r
+ * <p/>\r
+ * For some languages, Aspell can also supply you with the phonetic file. \r
+ * On Windows, go into aspell <code>data</code> directory and copy the \r
+ * phonetic file corresponding to your language, for example the \r
+ * <code>fr_phonet.dat</code> for the <code>fr</code> language. The phonetic\r
+ * file should be in directory <code>/usr/share/aspell</code> on Unix.\r
+ *\r
+ * @see GenericTransformator GenericTransformator for information on \r
+ * phonetic files.\r
+ */\r
+public abstract class SpellDictionaryASpell implements SpellDictionary {\r
+\r
+\r
+ /** The reference to a Transformator, used to transform a word into it's phonetic code. */\r
+ protected Transformator tf;\r
+\r
+ /**\r
+ * Constructs a new SpellDictionaryASpell\r
+ * @param phonetic The file to use for phonetic transformation of the \r
+ * words list. If <code>phonetic</code> is null, the the transformation\r
+ * uses {@link DoubleMeta} transformation.\r
+ * @throws java.io.IOException indicates problems reading the phonetic \r
+ * information\r
+ */\r
+ public SpellDictionaryASpell(File phonetic) throws IOException {\r
+ if (phonetic == null)\r
+ tf = new DoubleMeta();\r
+ else\r
+ tf = new GenericTransformator(phonetic);\r
+ }\r
+\r
+ /**\r
+ * Constructs a new SpellDictionaryASpell\r
+ * @param phonetic The file to use for phonetic transformation of the \r
+ * words list. If <code>phonetic</code> is null, the the transformation\r
+ * uses {@link DoubleMeta} transformation.\r
+ * @param encoding Uses the character set encoding specified\r
+ * @throws java.io.IOException indicates problems reading the phonetic \r
+ * information\r
+ */\r
+ public SpellDictionaryASpell(File phonetic, String encoding) throws IOException {\r
+ if (phonetic == null)\r
+ tf = new DoubleMeta();\r
+ else\r
+ tf = new GenericTransformator(phonetic, encoding);\r
+ }\r
+\r
+ /**\r
+ * Constructs a new SpellDictionaryASpell\r
+ * @param phonetic The Reader to use for phonetic transformation of the \r
+ * words list. If <code>phonetic</code> is null, the the transformation\r
+ * uses {@link DoubleMeta} transformation.\r
+ * @throws java.io.IOException indicates problems reading the phonetic \r
+ * information\r
+ */\r
+ public SpellDictionaryASpell(Reader phonetic) throws IOException {\r
+ if (phonetic == null)\r
+ tf = new DoubleMeta();\r
+ else\r
+ tf = new GenericTransformator(phonetic);\r
+ }\r
+\r
+ /**\r
+ * Returns a list of Word objects that are the suggestions to an\r
+ * incorrect word. \r
+ * <p>\r
+ * This method is only needed to provide backward compatibility.\r
+ * @see #getSuggestions(String, int, int[][])\r
+ * @param word Suggestions for given misspelt word\r
+ * @param threshold The lower boundary of similarity to misspelt word\r
+ * @return Vector a List of suggestions\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+public List getSuggestions(String word, int threshold) {\r
+ \r
+ return getSuggestions(word,threshold,null);\r
+ \r
+ }\r
+\r
+ /**\r
+ * Returns a list of Word objects that are the suggestions to an\r
+ * incorrect word.\r
+ * <p>\r
+ * @param word Suggestions for given misspelt word\r
+ * @param threshold The lower boundary of similarity to misspelt word\r
+ * @param matrix Two dimensional int array used to calculate\r
+ * edit distance. Allocating this memory outside of the function will greatly improve efficiency. \r
+ * @return Vector a List of suggestions\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+public List getSuggestions(String word, int threshold, int[][] matrix) {\r
+\r
+ int i;\r
+ int j;\r
+ \r
+ if(matrix == null)\r
+ matrix = new int[0][0];\r
+ \r
+ Hashtable nearmisscodes = new Hashtable();\r
+ String code = getCode(word);\r
+\r
+ // add all words that have the same phonetics\r
+ nearmisscodes.put(code, code);\r
+ Vector phoneticList = getWordsFromCode(word, nearmisscodes);\r
+\r
+ // do some tranformations to pick up more results\r
+ //interchange\r
+ nearmisscodes = new Hashtable();\r
+ char[] charArray = word.toCharArray();\r
+ char a;\r
+ char b ;\r
+ \r
+ for (i = 0; i < word.length() - 1; i++) {\r
+ a = charArray[i];\r
+ b = charArray[i + 1];\r
+ charArray[i] = b;\r
+ charArray[i + 1] = a;\r
+ String s = getCode(new String(charArray));\r
+ nearmisscodes.put(s, s);\r
+ charArray[i] = a;\r
+ charArray[i + 1] = b;\r
+ }\r
+\r
+ char[] replacelist = tf.getReplaceList();\r
+\r
+ //change\r
+ charArray = word.toCharArray();\r
+ char original; \r
+ for (i = 0; i < word.length(); i++) {\r
+ original = charArray[i];\r
+ for (j = 0; j < replacelist.length; j++) {\r
+ charArray[i] = replacelist[j];\r
+ String s = getCode(new String(charArray));\r
+ nearmisscodes.put(s, s);\r
+ }\r
+ charArray[i] = original;\r
+ }\r
+\r
+ //add\r
+ charArray = (word += " ").toCharArray();\r
+ int iy = charArray.length - 1;\r
+ while (true) {\r
+ for (j = 0; j < replacelist.length; j++) {\r
+ charArray[iy] = replacelist[j];\r
+ String s = getCode(new String(charArray));\r
+ nearmisscodes.put(s, s);\r
+ }\r
+ if (iy == 0)\r
+ break;\r
+ charArray[iy] = charArray[iy - 1];\r
+ --iy;\r
+ }\r
+\r
+ //delete\r
+ word = word.trim();\r
+ charArray = word.toCharArray();\r
+ char[] charArray2 = new char[charArray.length - 1];\r
+ for (int ix = 0; ix < charArray2.length; ix++) {\r
+ charArray2[ix] = charArray[ix];\r
+ }\r
+ \r
+ a = charArray[charArray.length - 1];\r
+ int ii = charArray2.length;\r
+ while (true) {\r
+ String s = getCode(new String(charArray));\r
+ nearmisscodes.put(s, s);\r
+ if (ii == 0)\r
+ break;\r
+ b = a;\r
+ a = charArray2[ii - 1];\r
+ charArray2[ii - 1] = b;\r
+ --ii;\r
+ }\r
+\r
+ nearmisscodes.remove(code); //already accounted for in phoneticList\r
+\r
+ Vector wordlist = getWordsFromCode(word, nearmisscodes);\r
+\r
+ if (wordlist.size() == 0 && phoneticList.size() == 0)\r
+ addBestGuess(word, phoneticList, matrix);\r
+\r
+\r
+ // We sort a Vector at the end instead of maintaining a\r
+ // continously sorted TreeSet because everytime you add a collection\r
+ // to a treeset it has to be resorted. It's better to do this operation\r
+ // once at the end.\r
+\r
+ Collections.sort(phoneticList, new Word()); //always sort phonetic matches along the top\r
+ Collections.sort(wordlist, new Word()); //the non-phonetic matches can be listed below\r
+\r
+ phoneticList.addAll(wordlist);\r
+ return phoneticList;\r
+ }\r
+\r
+ /**\r
+ * When we don't come up with any suggestions (probably because the threshold was too strict),\r
+ * then pick the best guesses from the those words that have the same phonetic code.\r
+ * <p>\r
+ * This method is only needed to provide backward compatibility.\r
+ * @see addBestGuess(String word, Vector wordList, int[][] matrix)\r
+ * @param word - the word we are trying spell correct\r
+ * @param wordList - the linked list that will get the best guess\r
+ */\r
+ @SuppressWarnings({ "unused", "unchecked" })\r
+private void addBestGuess(String word, Vector wordList) {\r
+ addBestGuess(word,wordList,null);\r
+ }\r
+ \r
+ /**\r
+ * When we don't come up with any suggestions (probably because the threshold was too strict),\r
+ * then pick the best guesses from the those words that have the same phonetic code.\r
+ * @param word - the word we are trying spell correct\r
+ * @param Two dimensional array of int used to calculate \r
+ * edit distance. Allocating this memory outside of the function will greatly improve efficiency. \r
+ * @param wordList - the linked list that will get the best guess\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+private void addBestGuess(String word, Vector wordList, int[][] matrix) {\r
+ if(matrix == null)\r
+ matrix = new int[0][0];\r
+ \r
+ if (wordList.size() != 0)\r
+ throw new InvalidParameterException("the wordList vector must be empty");\r
+\r
+ int bestScore = Integer.MAX_VALUE;\r
+ \r
+ String code = getCode(word);\r
+ List simwordlist = getWords(code);\r
+\r
+ LinkedList candidates = new LinkedList();\r
+\r
+ for (Iterator j = simwordlist.iterator(); j.hasNext();) {\r
+ String similar = (String) j.next();\r
+ int distance = EditDistance.getDistance(word, similar, matrix);\r
+ if (distance <= bestScore) {\r
+ bestScore = distance;\r
+ Word goodGuess = new Word(similar, distance);\r
+ candidates.add(goodGuess);\r
+ }\r
+ }\r
+\r
+ //now, only pull out the guesses that had the best score\r
+ for (Iterator iter = candidates.iterator(); iter.hasNext();) {\r
+ Word candidate = (Word) iter.next();\r
+ if (candidate.getCost() == bestScore)\r
+ wordList.add(candidate);\r
+ }\r
+\r
+ }\r
+\r
+ @SuppressWarnings("unchecked")\r
+private Vector getWordsFromCode(String word, Hashtable codes) {\r
+ Configuration config = Configuration.getConfiguration();\r
+ Vector result = new Vector();\r
+ int[][] matrix = new int[0][0]; \r
+ final int configDistance = config.getInteger(Configuration.SPELL_THRESHOLD);\r
+\r
+ for (Enumeration i = codes.keys(); i.hasMoreElements();) {\r
+ String code = (String) i.nextElement();\r
+\r
+ List simwordlist = getWords(code);\r
+ for (Iterator iter = simwordlist.iterator(); iter.hasNext();) {\r
+ String similar = (String) iter.next();\r
+ int distance = EditDistance.getDistance(word, similar, matrix);\r
+ if (distance < configDistance) {\r
+ Word w = new Word(similar, distance);\r
+ result.addElement(w);\r
+ }\r
+ }\r
+ }\r
+ return result;\r
+ }\r
+\r
+ /**\r
+ * Returns the phonetic code representing the word.\r
+ * @param word The word we want the phonetic code.\r
+ * @return The value of the phonetic code for the word.\r
+ */\r
+ public String getCode(String word) {\r
+ return tf.transform(word);\r
+ }\r
+\r
+ /**\r
+ * Returns a list of words that have the same phonetic code.\r
+ * @param phoneticCode The phonetic code common to the list of words\r
+ * @return A list of words having the same phonetic code\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+protected abstract List getWords(String phoneticCode);\r
+\r
+ /**\r
+ * Returns true if the word is correctly spelled against the current word list.\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+public boolean isCorrect(String word) {\r
+ List possible = getWords(getCode(word));\r
+ if (possible.contains(word))\r
+ return true;\r
+ //JMH should we always try the lowercase version. If I dont then capitalised\r
+ //words are always returned as incorrect.\r
+ else if (possible.contains(word.toLowerCase()))\r
+ return true;\r
+ return false;\r
+ }\r
+}\r
--- /dev/null
+/*\rJazzy - a Java library for Spell Checking\rCopyright (C) 2001 Mindaugas Idzelis\rFull text of license can be found in LICENSE.txt\r\rThis library is free software; you can redistribute it and/or\rmodify it under the terms of the GNU Lesser General Public\rLicense as published by the Free Software Foundation; either\rversion 2.1 of the License, or (at your option) any later version.\r\rThis library is distributed in the hope that it will be useful,\rbut WITHOUT ANY WARRANTY; without even the implied warranty of\rMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\rLesser General Public License for more details.\r\rYou should have received a copy of the GNU Lesser General Public\rLicense along with this library; if not, write to the Free Software\rFoundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r*/\rpackage com.swabunga.spell.engine;\r\rimport java.io.File;\rimport java.io.FileInputStream;\rimport java.io.FileNotFoundException;\rimport java.io.FileOutputStream;\rimport java.io.IOException;\rimport java.io.ObjectInputStream;\rimport java.io.ObjectOutputStream;\rimport java.io.Serializable;\rimport java.util.HashMap;\rimport java.util.Iterator;\rimport java.util.List;\r\r/**\r * Yet another <code>SpellDictionary</code> this one is based on Damien Guillaume's\r * Diskbased dictionary but adds a cache to try to improve abit on performance.\r *\r * @author Robert Gustavsson\r * @version 0.01\r */\r\rpublic class SpellDictionaryCachedDichoDisk extends SpellDictionaryDichoDisk {\r \r // Only used for testing to measure the effectiveness of the cache.\r static public int hits=0;\r static public int codes=0;\r\r public static final String JAZZY_DIR=".jazzy";\r public static final String PRE_CACHE_FILE_EXT=".pre";\r\r private static int MAX_CACHED=10000;\r\r @SuppressWarnings("unchecked")\r private final HashMap suggestionCache=new HashMap(MAX_CACHED);\r private String preCacheFileName;\r private String preCacheDir;\r\r /**\r * Dictionary Convienence Constructor.\r */\r public SpellDictionaryCachedDichoDisk(File wordList)\r throws FileNotFoundException, IOException {\r super(wordList);\r loadPreCache(wordList);\r }\r \r /**\r * Dictionary Convienence Constructor.\r */\r public SpellDictionaryCachedDichoDisk(File wordList, String encoding)\r throws FileNotFoundException, IOException {\r super(wordList, encoding);\r loadPreCache(wordList);\r }\r\r /**\r * Dictionary constructor that uses an aspell phonetic file to\r * build the transformation table.\r */\r\r public SpellDictionaryCachedDichoDisk(File wordList, File phonetic)\r throws FileNotFoundException, IOException {\r super(wordList, phonetic);\r loadPreCache(wordList);\r }\r\r /**\r * Dictionary constructor that uses an aspell phonetic file to\r * build the transformation table.\r */\r public SpellDictionaryCachedDichoDisk(File wordList, File phonetic, String encoding)\r throws FileNotFoundException, IOException {\r super(wordList, phonetic, encoding);\r loadPreCache(wordList);\r }\r\r /**\r * Add a word permanantly to the dictionary (and the dictionary file).\r * <i>not implemented !</i>\r */\r @Override\r public void addWord(String word) {\r System.err.println("error: addWord is not implemented for SpellDictionaryCachedDichoDisk");\r }\r\r /**\r * Clears the cache.\r */\r public void clearCache(){\r suggestionCache.clear();\r }\r\r /**\r * Returns a list of strings (words) for the code.\r */\r @Override\r @SuppressWarnings("unchecked")\r public List getWords(String code) {\r List list;\r codes++;\r if(suggestionCache.containsKey(code)){\r hits++;\r list=getCachedList(code);\r return list;\r }\r list=super.getWords(code);\r addToCache(code,list);\r \r return list;\r }\r /**\r * This method returns the cached suggestionlist and also moves the code to\r * the top of the codeRefQueue to indicate this code has resentlly been\r * referenced.\r */\r @SuppressWarnings("unchecked")\r private List getCachedList(String code){\r CacheObject obj=(CacheObject)suggestionCache.get(code);\r obj.setRefTime();\r return obj.getSuggestionList();\r }\r\r /**\r * Adds a code and it's suggestion list to the cache.\r */\r @SuppressWarnings("unchecked")\r private void addToCache(String code, List l){\r String c=null;\r String lowestCode=null;\r long lowestTime=Long.MAX_VALUE;\r Iterator it;\r CacheObject obj;\r\r if(suggestionCache.size()>=MAX_CACHED){\r it=suggestionCache.keySet().iterator();\r while(it.hasNext()){\r c=(String)it.next();\r obj=(CacheObject)suggestionCache.get(c);\r if(obj.getRefTime()==0){\r lowestCode=c;\r break;\r }\r if(lowestTime>obj.getRefTime()){\r lowestCode=c;\r lowestTime=obj.getRefTime();\r }\r }\r suggestionCache.remove(lowestCode);\r } \r suggestionCache.put(code,new CacheObject(l));\r }\r\r /**\r * Load the cache from file. The cach file has the same name as the \r * dico file with the .pre extension added.\r */\r @SuppressWarnings("unchecked")\r private void loadPreCache(File dicoFile)throws IOException{\r String code;\r List suggestions;\r long size,\r time;\r File preFile;\r ObjectInputStream in;\r\r preCacheDir=System.getProperty("user.home")+"/"+JAZZY_DIR;\r preCacheFileName=preCacheDir+"/"+dicoFile.getName()+PRE_CACHE_FILE_EXT;\r //System.out.println(preCacheFileName);\r preFile=new File(preCacheFileName);\r if(!preFile.exists()){\r System.err.println("No precache file");\r return;\r }\r //System.out.println("Precaching...");\r in=new ObjectInputStream(new FileInputStream(preFile));\r try{\r size=in.readLong();\r for(int i=0;i<size;i++){\r code=(String)in.readObject();\r time=in.readLong();\r suggestions=(List)in.readObject();\r suggestionCache.put(code,new CacheObject(suggestions,time));\r }\r }catch(ClassNotFoundException ex){\r System.out.println(ex.getMessage());\r }\r in.close();\r }\r\r /**\r * Saves the current cache to file.\r */\r @SuppressWarnings("unchecked")\r public void saveCache() throws IOException{\r String code;\r CacheObject obj;\r File preFile,\r preDir;\r ObjectOutputStream out;\r Iterator it;\r\r if(preCacheFileName==null || preCacheDir==null){\r System.err.println("Precache filename has not been set.");\r return;\r }\r //System.out.println("Saving cache to precache file...");\r preDir=new File(preCacheDir);\r if(!preDir.exists())\r preDir.mkdir();\r preFile=new File(preCacheFileName);\r out=new ObjectOutputStream(new FileOutputStream(preFile));\r it=suggestionCache.keySet().iterator();\r out.writeLong(suggestionCache.size());\r while(it.hasNext()){\r code=(String)it.next();\r obj=(CacheObject)suggestionCache.get(code);\r out.writeObject(code);\r out.writeLong(obj.getRefTime());\r out.writeObject(obj.getSuggestionList());\r }\r out.close();\r }\r\r // INNER CLASSES\r // ------------------------------------------------------------------------\r @SuppressWarnings("serial")\r private class CacheObject implements Serializable{\r \r @SuppressWarnings("unchecked")\r private List suggestions=null;\r private long refTime=0;\r\r @SuppressWarnings("unchecked")\r public CacheObject(List list){\r this.suggestions=list;\r }\r\r @SuppressWarnings("unchecked")\r public CacheObject(List list, long time){\r this.suggestions=list;\r this.refTime=time;\r }\r \r @SuppressWarnings("unchecked")\r public List getSuggestionList(){\r return suggestions;\r }\r\r public void setRefTime(){\r refTime=System.currentTimeMillis();\r }\r\r public long getRefTime(){\r return refTime;\r }\r }\r}\r
\ No newline at end of file
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.spell.engine;\r
+\r
+import java.io.EOFException;\r
+import java.io.File;\r
+import java.io.FileNotFoundException;\r
+import java.io.IOException;\r
+import java.io.RandomAccessFile;\r
+import java.util.LinkedList;\r
+import java.util.List;\r
+\r
+/**\r
+ * Another implementation of <code>SpellDictionary</code> that doesn't cache any words in memory. Avoids the huge\r
+ * footprint of <code>SpellDictionaryHashMap</code> at the cost of relatively minor latency. A future version\r
+ * of this class that implements some caching strategies might be a good idea in the future, if there's any\r
+ * demand for it.\r
+ *\r
+ * This implementation requires a special dictionary file, with "code*word" lines sorted by code.\r
+ * It's using a dichotomy algorithm to search for words in the dictionary\r
+ *\r
+ * @author Damien Guillaume\r
+ * @version 0.1\r
+ */\r
+public class SpellDictionaryDichoDisk extends SpellDictionaryASpell {\r
+\r
+ /** Holds the dictionary file for reading*/\r
+ private RandomAccessFile dictFile = null;\r
+\r
+ /** dictionary and phonetic file encoding */\r
+ private String encoding = null;\r
+\r
+ /**\r
+ * Dictionary convenience Constructor.\r
+ * @param wordList The file containing the words list for the dictionary\r
+ * @throws java.io.FileNotFoundException indicates problems locating the\r
+ * words list file on the system\r
+ * @throws java.io.IOException indicates problems reading the words list\r
+ * file\r
+ */\r
+ public SpellDictionaryDichoDisk(File wordList)\r
+ throws FileNotFoundException, IOException {\r
+ super((File) null);\r
+ dictFile = new RandomAccessFile(wordList, "r");\r
+ }\r
+\r
+ /**\r
+ * Dictionary convenience Constructor.\r
+ * @param wordList The file containing the words list for the dictionary\r
+ * @param encoding Uses the character set encoding specified\r
+ * @throws java.io.FileNotFoundException indicates problems locating the\r
+ * words list file on the system\r
+ * @throws java.io.IOException indicates problems reading the words list\r
+ * file\r
+ */\r
+ public SpellDictionaryDichoDisk(File wordList, String encoding)\r
+ throws FileNotFoundException, IOException {\r
+ super((File) null);\r
+ this.encoding = encoding;\r
+ dictFile = new RandomAccessFile(wordList, "r");\r
+ }\r
+\r
+ /**\r
+ * Dictionary constructor that uses an aspell phonetic file to\r
+ * build the transformation table.\r
+ * @param wordList The file containing the words list for the dictionary\r
+ * @param phonetic The file to use for phonetic transformation of the \r
+ * wordlist.\r
+ * @throws java.io.FileNotFoundException indicates problems locating the\r
+ * file on the system\r
+ * @throws java.io.IOException indicates problems reading the words list\r
+ * file\r
+ */\r
+ public SpellDictionaryDichoDisk(File wordList, File phonetic)\r
+ throws FileNotFoundException, IOException {\r
+ super(phonetic);\r
+ dictFile = new RandomAccessFile(wordList, "r");\r
+ }\r
+ \r
+ /**\r
+ * Dictionary constructor that uses an aspell phonetic file to\r
+ * build the transformation table.\r
+ * @param wordList The file containing the words list for the dictionary\r
+ * @param phonetic The file to use for phonetic transformation of the \r
+ * wordlist.\r
+ * @param encoding Uses the character set encoding specified\r
+ * @throws java.io.FileNotFoundException indicates problems locating the\r
+ * file on the system\r
+ * @throws java.io.IOException indicates problems reading the words list\r
+ * file\r
+ */\r
+ public SpellDictionaryDichoDisk(File wordList, File phonetic, String encoding)\r
+ throws FileNotFoundException, IOException {\r
+ super(phonetic, encoding);\r
+ this.encoding = encoding;\r
+ dictFile = new RandomAccessFile(wordList, "r");\r
+ }\r
+ \r
+ /**\r
+ * Add a word permanently to the dictionary (and the dictionary file).\r
+ * <i>not implemented !</i>\r
+ * @param word The word to add.\r
+ */\r
+ public void addWord(String word) {\r
+ System.err.println("error: addWord is not implemented for SpellDictionaryDichoDisk");\r
+ }\r
+\r
+ /**\r
+ * Search the dictionary file for the words corresponding to the code\r
+ * within positions p1 - p2\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+private LinkedList dichoFind(String code, long p1, long p2) throws IOException {\r
+ //System.out.println("dichoFind("+code+","+p1+","+p2+")");\r
+ long pm = (p1 + p2) / 2;\r
+ dictFile.seek(pm);\r
+ String l;\r
+ if (encoding == null)\r
+ l = dictFile.readLine();\r
+ else\r
+ l = dictReadLine();\r
+ pm = dictFile.getFilePointer();\r
+ if (encoding == null)\r
+ l = dictFile.readLine();\r
+ else\r
+ l = dictReadLine();\r
+ long pm2 = dictFile.getFilePointer();\r
+ if (pm2 >= p2)\r
+ return(seqFind(code, p1, p2));\r
+ int istar = l.indexOf('*');\r
+ if (istar == -1)\r
+ throw new IOException("bad format: no * !");\r
+ String testcode = l.substring(0, istar);\r
+ int comp = code.compareTo(testcode);\r
+ if (comp < 0)\r
+ return(dichoFind(code, p1, pm-1));\r
+ else if (comp > 0)\r
+ return(dichoFind(code, pm2, p2));\r
+ else {\r
+ LinkedList l1 = dichoFind(code, p1, pm-1);\r
+ LinkedList l2 = dichoFind(code, pm2, p2);\r
+ String word = l.substring(istar+1);\r
+ l1.add(word);\r
+ l1.addAll(l2);\r
+ return(l1);\r
+ }\r
+ }\r
+ \r
+ @SuppressWarnings("unchecked")\r
+private LinkedList seqFind(String code, long p1, long p2) throws IOException {\r
+ //System.out.println("seqFind("+code+","+p1+","+p2+")");\r
+ LinkedList list = new LinkedList();\r
+ dictFile.seek(p1);\r
+ while (dictFile.getFilePointer() < p2) {\r
+ String l;\r
+ if (encoding == null)\r
+ l = dictFile.readLine();\r
+ else\r
+ l = dictReadLine();\r
+ int istar = l.indexOf('*');\r
+ if (istar == -1)\r
+ throw new IOException("bad format: no * !");\r
+ String testcode = l.substring(0, istar);\r
+ if (testcode.equals(code)) {\r
+ String word = l.substring(istar+1);\r
+ list.add(word);\r
+ }\r
+ }\r
+ return(list);\r
+ }\r
+ \r
+ /**\r
+ * Read a line of dictFile with a specific encoding\r
+ */\r
+ private String dictReadLine() throws IOException {\r
+ int max = 255;\r
+ byte b=0;\r
+ byte[] buf = new byte[max];\r
+ int i=0;\r
+ try {\r
+ for (; b != '\n' && b != '\r' && i<max-1; i++) {\r
+ b = dictFile.readByte();\r
+ buf[i] = b;\r
+ }\r
+ } catch (EOFException ex) {\r
+ }\r
+ if (i == 0)\r
+ return("");\r
+ String s = new String(buf, 0, i-1, encoding);\r
+ return(s);\r
+ }\r
+ \r
+ /**\r
+ * Returns a list of strings (words) for the code.\r
+ * @param code The phonetic code common to the list of words\r
+ * @return A list of words having the same phonetic code\r
+ */\r
+ @Override\r
+@SuppressWarnings("unchecked")\r
+public List getWords(String code) {\r
+ //System.out.println("getWords("+code+")");\r
+ LinkedList list;\r
+ try {\r
+ list = dichoFind(code, 0, dictFile.length()-1);\r
+ //System.out.println(list);\r
+ } catch (IOException ex) {\r
+ System.err.println("IOException: " + ex.getMessage());\r
+ list = new LinkedList();\r
+ }\r
+ return list;\r
+ }\r
+\r
+}\r
+\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+/* Created by bgalbs on Jan 30, 2003 at 11:38:39 PM */\r
+package com.swabunga.spell.engine;\r
+\r
+import java.io.BufferedOutputStream;\r
+import java.io.BufferedReader;\r
+import java.io.BufferedWriter;\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.FileNotFoundException;\r
+import java.io.FileOutputStream;\r
+import java.io.FileReader;\r
+import java.io.FileWriter;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.util.ArrayList;\r
+import java.util.Collections;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.StringTokenizer;\r
+import java.util.Vector;\r
+\r
+/**\r
+ * An implementation of <code>SpellDictionary</code> that doesn't cache any words in memory. Avoids the huge\r
+ * footprint of <code>SpellDictionaryHashMap</code> at the cost of relatively minor latency. A future version\r
+ * of this class that implements some caching strategies might be a good idea in the future, if there's any\r
+ * demand for it.\r
+ * <p>\r
+ * This class makes use of the "classic" Java IO library (java.io). However, it could probably benefit from\r
+ * the new IO APIs (java.nio) and it is anticipated that a future version of this class, probably called\r
+ * <code>SpellDictionaryDiskNIO</code> will appear at some point.\r
+ *\r
+ * @author Ben Galbraith (ben@galbraiths.org)\r
+ * @version 0.1\r
+ * @since 0.5\r
+ */\r
+public class SpellDictionaryDisk extends SpellDictionaryASpell {\r
+ private final static String DIRECTORY_WORDS = "words";\r
+ private final static String DIRECTORY_DB = "db";\r
+ private final static String FILE_CONTENTS = "contents";\r
+ private final static String FILE_DB = "words.db";\r
+ private final static String FILE_INDEX = "words.idx";\r
+\r
+ /* maximum number of words an index entry can represent */\r
+ private final static int INDEX_SIZE_MAX = 200;\r
+\r
+ private final File base;\r
+ private final File words;\r
+ private final File db;\r
+ @SuppressWarnings("unchecked")\r
+private Map index;\r
+ /**\r
+ * The flag indicating if the initial preparation or loading of the on \r
+ * disk dictionary is complete.\r
+ */\r
+ protected boolean ready;\r
+\r
+ /* used at time of creation of index to speed up determining the number of words per index entry */\r
+ @SuppressWarnings("unchecked")\r
+private List indexCodeCache = null;\r
+\r
+ /**\r
+ * Construct a spell dictionary on disk. \r
+ * The spell dictionary is created from words list(s) contained in file(s).\r
+ * A words list file is a file with one word per line. Words list files are\r
+ * located in a <code>base/words</code> dictionary where <code>base</code> \r
+ * is the path to <code>words</code> dictionary. The on disk spell \r
+ * dictionary is created in <code>base/db</code> dictionary and contains \r
+ * files:\r
+ * <ul>\r
+ * <li><code>contents</code> list the words files used for spelling.</li>\r
+ * <li><code>words.db</code> the content of words files organized as\r
+ * a <em>database</em> of words.</li>\r
+ * <li><code>words.idx</code> an index file to the <code>words.db</code>\r
+ * file content.</li>\r
+ * </ul>\r
+ * The <code>contents</code> file has a list of \r
+ * <code>filename, size</code> indicating the name and length of each files\r
+ * in the <code>base/words</code> dictionary. If one of theses files was \r
+ * changed, added or deleted before the call to the constructor, the process \r
+ * of producing new or updated <code>words.db</code> and \r
+ * <code>words.idx</code> files is started again.\r
+ * <p/>\r
+ * The spellchecking process is then worked upon the <code>words.db</code>\r
+ * and <code>words.idx</code> files.\r
+ * <p/>\r
+ * \r
+ * NOTE: Do *not* create two instances of this class pointing to the same <code>base</code> unless\r
+ * you are sure that a new dictionary does not have to be created. In the future, some sort of\r
+ * external locking mechanism may be created that handles this scenario gracefully.\r
+ * \r
+ * @param base the base directory in which <code>SpellDictionaryDisk</code> can expect to find\r
+ * its necessary files.\r
+ * @param phonetic the phonetic file used by the spellchecker.\r
+ * @param block if a new word db needs to be created, there can be a considerable delay before\r
+ * the constructor returns. If block is true, this method will block while the db is created\r
+ * and return when done. If block is false, this method will create a thread to create the new\r
+ * dictionary and return immediately.\r
+ * @throws java.io.FileNotFoundException indicates problems locating the\r
+ * files on the system\r
+ * @throws java.io.IOException indicates problems reading the files\r
+ */\r
+ public SpellDictionaryDisk(File base, File phonetic, boolean block) throws FileNotFoundException, IOException {\r
+ super(phonetic);\r
+ this.ready = false;\r
+\r
+ this.base = base;\r
+ this.words = new File(base, DIRECTORY_WORDS);\r
+ this.db = new File(base, DIRECTORY_DB);\r
+\r
+ if (!this.base.exists()) throw new FileNotFoundException("Couldn't find required path '" + this.base + "'");\r
+ if (!this.words.exists()) throw new FileNotFoundException("Couldn't find required path '" + this.words + "'");\r
+ if (!this.db.exists()) db.mkdirs();\r
+\r
+ if (newDictionaryFiles()) {\r
+ if (block) {\r
+ buildNewDictionaryDatabase();\r
+ loadIndex();\r
+ ready = true;\r
+ } else {\r
+ Thread t = new Thread() {\r
+ @Override\r
+ public void run() {\r
+ try {\r
+ buildNewDictionaryDatabase();\r
+ loadIndex();\r
+ ready = true;\r
+ } catch (Exception e) {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+ };\r
+ t.start();\r
+ }\r
+ } else {\r
+ loadIndex();\r
+ ready = true;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Builds the file words database file and the contents file for the on\r
+ * disk dictionary.\r
+ */\r
+ protected void buildNewDictionaryDatabase() throws FileNotFoundException, IOException {\r
+ /* combine all dictionary files into one sorted file */\r
+ File sortedFile = buildSortedFile();\r
+\r
+ /* create the db for the sorted file */\r
+ buildCodeDb(sortedFile);\r
+ sortedFile.delete();\r
+\r
+ /* build contents file */\r
+ buildContentsFile();\r
+ }\r
+\r
+ /**\r
+ * Adds another word to the dictionary. <em>This method is not yet implemented\r
+ * for this class</em>.\r
+ * @param word The word to add.\r
+ */\r
+ public void addWord(String word) {\r
+ throw new UnsupportedOperationException("addWord not yet implemented (sorry)");\r
+ }\r
+\r
+ /**\r
+ * Returns a list of words that have the same phonetic code.\r
+ * @param code The phonetic code common to the list of words\r
+ * @return A list of words having the same phonetic code\r
+ */\r
+ @Override\r
+@SuppressWarnings("unchecked")\r
+public List getWords(String code) {\r
+ Vector words = new Vector();\r
+\r
+ int[] posLen = getStartPosAndLen(code);\r
+ if (posLen != null) {\r
+ try {\r
+ InputStream input = new FileInputStream(new File(db, FILE_DB));\r
+ input.skip(posLen[0]);\r
+ byte[] bytes = new byte[posLen[1]];\r
+ input.read(bytes, 0, posLen[1]);\r
+ input.close();\r
+\r
+ String data = new String(bytes);\r
+ String[] lines = split(data, "\n");\r
+ for (String line : lines) {\r
+ String[] s = split(line, ",");\r
+ if (s[0].equals(code)) words.addElement(s[1]);\r
+ }\r
+ } catch (Exception e) {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+\r
+ return words;\r
+ }\r
+\r
+ /**\r
+ * Indicates if the initial preparation or loading of the on disk dictionary\r
+ * is complete.\r
+ * @return the indication that the dictionary initial setup is done.\r
+ */\r
+ public boolean isReady() {\r
+ return ready;\r
+ }\r
+\r
+ @SuppressWarnings("unchecked")\r
+private boolean newDictionaryFiles() throws FileNotFoundException, IOException {\r
+ /* load in contents file, which indicates the files and sizes of the last db build */\r
+ List contents = new ArrayList();\r
+ File c = new File(db, FILE_CONTENTS);\r
+ if (c.exists()) {\r
+ BufferedReader reader = null;\r
+ try {\r
+ reader = new BufferedReader(new FileReader(c));\r
+ String line;\r
+ while ((line = reader.readLine()) != null) {\r
+ // format of file should be [filename],[size]\r
+ String[] s = split(line, ",");\r
+ contents.add(new FileSize(s[0], Integer.parseInt(s[1])));\r
+ }\r
+ } catch (FileNotFoundException e) {\r
+ throw e;\r
+ } catch (IOException e) {\r
+ throw e;\r
+ } finally {\r
+ if (reader != null) reader.close();\r
+ }\r
+ }\r
+\r
+ /* compare this to the actual directory */\r
+ boolean changed = false;\r
+ File[] wordFiles = words.listFiles();\r
+ if (contents.size() != wordFiles.length) {\r
+ // if the size of the contents list and the number of word files are different, it\r
+ // means we've definitely got to reindex\r
+ changed = true;\r
+ } else {\r
+ // check and make sure that all the word files haven't changed on us\r
+ for (File wordFile : wordFiles) {\r
+ FileSize fs = new FileSize(wordFile.getName(), wordFile.length());\r
+ if (!contents.contains(fs)) {\r
+ changed = true;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ return changed;\r
+ }\r
+\r
+ @SuppressWarnings("unchecked")\r
+private File buildSortedFile() throws FileNotFoundException, IOException {\r
+ List w = new ArrayList();\r
+\r
+ /*\r
+ * read every single word into the list. eeek. if this causes problems,\r
+ * we may wish to explore disk-based sorting or more efficient memory-based storage\r
+ */\r
+ File[] wordFiles = words.listFiles();\r
+ for (File wordFile : wordFiles) {\r
+ BufferedReader r = new BufferedReader(new FileReader(wordFile));\r
+ String word;\r
+ while ((word = r.readLine()) != null) {\r
+ if (!word.equals("")) {\r
+ w.add(word.trim());\r
+ }\r
+ }\r
+ r.close();\r
+ }\r
+\r
+ Collections.sort(w);\r
+\r
+ // FIXME - error handling for running out of disk space would be nice.\r
+ File file = File.createTempFile("jazzy", "sorted");\r
+ BufferedWriter writer = new BufferedWriter(new FileWriter(file));\r
+ String prev = null;\r
+ for (int i = 0; i < w.size(); i++) {\r
+ String word = (String) w.get(i);\r
+ if (prev == null || !prev.equals(word)) {\r
+ writer.write(word);\r
+ writer.newLine();\r
+ }\r
+ prev = word;\r
+ }\r
+ writer.close();\r
+\r
+ return file;\r
+ }\r
+\r
+ @SuppressWarnings("unchecked")\r
+private void buildCodeDb(File sortedWords) throws FileNotFoundException, IOException {\r
+ List codeList = new ArrayList();\r
+\r
+ BufferedReader reader = new BufferedReader(new FileReader(sortedWords));\r
+ String word;\r
+ while ((word = reader.readLine()) != null) {\r
+ codeList.add(new CodeWord(this.getCode(word), word));\r
+ }\r
+ reader.close();\r
+\r
+ Collections.sort(codeList);\r
+\r
+ List index = new ArrayList();\r
+\r
+ BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(new File(db, FILE_DB)));\r
+ String currentCode = null;\r
+ int currentPosition = 0;\r
+ int currentLength = 0;\r
+ for (int i = 0; i < codeList.size(); i++) {\r
+ CodeWord cw = (CodeWord) codeList.get(i);\r
+ String thisCode = cw.getCode();\r
+// if (thisCode.length() > 3) thisCode = thisCode.substring(0, 3);\r
+ thisCode = getIndexCode(thisCode, codeList);\r
+ String toWrite = cw.getCode() + "," + cw.getWord() + "\n";\r
+ byte[] bytes = toWrite.getBytes();\r
+\r
+ if (currentCode == null) currentCode = thisCode;\r
+ if (!currentCode.equals(thisCode)) {\r
+ index.add(new Object[]{currentCode, new int[]{currentPosition, currentLength}});\r
+ currentPosition += currentLength;\r
+ currentLength = bytes.length;\r
+ currentCode = thisCode;\r
+ } else {\r
+ currentLength += bytes.length;\r
+ }\r
+ out.write(bytes);\r
+ }\r
+ out.close();\r
+\r
+ // Output the last iteration\r
+ if (currentCode != null && currentPosition != 0 && currentLength != 0)\r
+ index.add(new Object[]{currentCode, new int[]{currentPosition, currentLength}});\r
+\r
+ BufferedWriter writer = new BufferedWriter(new FileWriter(new File(db, FILE_INDEX)));\r
+ for (int i = 0; i < index.size(); i++) {\r
+ Object[] o = (Object[]) index.get(i);\r
+ writer.write(o[0].toString());\r
+ writer.write(",");\r
+ writer.write(String.valueOf(((int[]) o[1])[0]));\r
+ writer.write(",");\r
+ writer.write(String.valueOf(((int[]) o[1])[1]));\r
+ writer.newLine();\r
+ }\r
+ writer.close();\r
+ }\r
+\r
+ private void buildContentsFile() throws IOException {\r
+ File[] wordFiles = words.listFiles();\r
+ if (wordFiles.length > 0) {\r
+ BufferedWriter writer = new BufferedWriter(new FileWriter(new File(db, FILE_CONTENTS)));\r
+ for (File wordFile : wordFiles) {\r
+ writer.write(wordFile.getName());\r
+ writer.write(",");\r
+ writer.write(String.valueOf(wordFile.length()));\r
+ writer.newLine();\r
+ }\r
+ writer.close();\r
+ } else {\r
+ new File(db, FILE_CONTENTS).delete();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Loads the index file from disk. The index file accelerates words lookup\r
+ * into the dictionary db file.\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+protected void loadIndex() throws IOException {\r
+ index = new HashMap();\r
+ File idx = new File(db, FILE_INDEX);\r
+ BufferedReader reader = new BufferedReader(new FileReader(idx));\r
+ String line;\r
+ while ((line = reader.readLine()) != null) {\r
+ String[] fields = split(line, ",");\r
+ index.put(fields[0], new int[]{Integer.parseInt(fields[1]), Integer.parseInt(fields[2])});\r
+ }\r
+ reader.close();\r
+ }\r
+\r
+ private int[] getStartPosAndLen(String code) {\r
+ while (code.length() > 0) {\r
+ int[] posLen = (int[]) index.get(code);\r
+ if (posLen == null) {\r
+ code = code.substring(0, code.length() - 1);\r
+ } else {\r
+ return posLen;\r
+ }\r
+ }\r
+ return null;\r
+ }\r
+\r
+ @SuppressWarnings("unchecked")\r
+private String getIndexCode(String code, List codes) {\r
+ if (indexCodeCache == null) indexCodeCache = new ArrayList();\r
+\r
+ if (code.length() <= 1) return code;\r
+\r
+ for (int i = 0; i < indexCodeCache.size(); i++) {\r
+ String c = (String) indexCodeCache.get(i);\r
+ if (code.startsWith(c)) return c;\r
+ }\r
+\r
+ int foundSize = -1;\r
+ boolean cacheable = false;\r
+ for (int z = 1; z < code.length(); z++) {\r
+ String thisCode = code.substring(0, z);\r
+ int count = 0;\r
+ for (int i = 0; i < codes.size();) {\r
+ if (i == 0) {\r
+ i = Collections.binarySearch(codes, new CodeWord(thisCode, ""));\r
+ if (i < 0) i = 0;\r
+ }\r
+\r
+ CodeWord cw = (CodeWord) codes.get(i);\r
+ if (cw.getCode().startsWith(thisCode)) {\r
+ count++;\r
+ if (count > INDEX_SIZE_MAX) break;\r
+ } else if (cw.getCode().compareTo(thisCode) > 0) break;\r
+ i++;\r
+ }\r
+ if (count <= INDEX_SIZE_MAX) {\r
+ cacheable = true;\r
+ foundSize = z;\r
+ break;\r
+ }\r
+ }\r
+\r
+ String newCode = (foundSize == -1) ? code : code.substring(0, foundSize);\r
+ if (cacheable) indexCodeCache.add(newCode);\r
+ return newCode;\r
+ }\r
+\r
+ private static String[] split(String input, String delimiter) {\r
+ StringTokenizer st = new StringTokenizer(input, delimiter);\r
+ int count = st.countTokens();\r
+ String[] out = new String[count];\r
+\r
+ for (int i = 0; i < count; i++) {\r
+ out[i] = st.nextToken();\r
+ }\r
+\r
+ return out;\r
+ }\r
+\r
+ @SuppressWarnings("unchecked")\r
+private class CodeWord implements Comparable {\r
+ private final String code;\r
+ private final String word;\r
+\r
+ public CodeWord(String code, String word) {\r
+ this.code = code;\r
+ this.word = word;\r
+ }\r
+\r
+ public String getCode() {\r
+ return code;\r
+ }\r
+\r
+ public String getWord() {\r
+ return word;\r
+ }\r
+\r
+ @Override\r
+ public boolean equals(Object o) {\r
+ if (this == o) return true;\r
+ if (!(o instanceof CodeWord)) return false;\r
+\r
+ final CodeWord codeWord = (CodeWord) o;\r
+\r
+ if (!word.equals(codeWord.word)) return false;\r
+\r
+ return true;\r
+ }\r
+\r
+ @Override\r
+ public int hashCode() {\r
+ return word.hashCode();\r
+ }\r
+\r
+ public int compareTo(Object o) {\r
+ return code.compareTo(((CodeWord) o).getCode());\r
+ }\r
+ }\r
+\r
+ private class FileSize {\r
+ private final String filename;\r
+ private final long size;\r
+\r
+ public FileSize(String filename, long size) {\r
+ this.filename = filename;\r
+ this.size = size;\r
+ }\r
+\r
+ @SuppressWarnings("unused")\r
+ public String getFilename() {\r
+ return filename;\r
+ }\r
+\r
+ @SuppressWarnings("unused")\r
+ public long getSize() {\r
+ return size;\r
+ }\r
+\r
+ @Override\r
+ public boolean equals(Object o) {\r
+ if (this == o) return true;\r
+ if (!(o instanceof FileSize)) return false;\r
+\r
+ final FileSize fileSize = (FileSize) o;\r
+\r
+ if (size != fileSize.size) return false;\r
+ if (!filename.equals(fileSize.filename)) return false;\r
+\r
+ return true;\r
+ }\r
+\r
+ @Override\r
+ public int hashCode() {\r
+ int result;\r
+ result = filename.hashCode();\r
+ result = (int) (29 * result + size);\r
+ return result;\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+/*\r
+ * put your module comment here\r
+ * formatted with JxBeauty (c) johann.langhofer@nextra.at\r
+ */\r
+\r
+package com.swabunga.spell.engine;\r
+\r
+import java.io.BufferedReader;\r
+import java.io.File;\r
+import java.io.FileNotFoundException;\r
+import java.io.FileReader;\r
+import java.io.FileWriter;\r
+import java.io.IOException;\r
+import java.io.Reader;\r
+import java.util.Hashtable;\r
+import java.util.List;\r
+import java.util.Vector;\r
+\r
+/**\r
+ * The SpellDictionaryHashMap holds the dictionary\r
+ * <p/>\r
+ * This class is thread safe. Derived classes should ensure that this preserved.\r
+ * <p/>\r
+ * There are many open source dictionary files. For just a few see:\r
+ * http://wordlist.sourceforge.net/\r
+ * <p/>\r
+ * This dictionary class reads words one per line. Make sure that your word list\r
+ * is formatted in this way (most are).\r
+ * <p/>\r
+ * Note that you must create the dictionary with a word list for the added\r
+ * words to persist.\r
+ */\r
+public class SpellDictionaryHashMap extends SpellDictionaryASpell {\r
+ /** A field indicating the initial hash map capacity (16KB) for the main\r
+ * dictionary hash map. Interested to see what the performance of a\r
+ * smaller initial capacity is like.\r
+ */\r
+ private final static int INITIAL_CAPACITY = 16 * 1024;\r
+\r
+ /**\r
+ * The hashmap that contains the word dictionary. The map is hashed on the doublemeta\r
+ * code. The map entry contains a LinkedList of words that have the same double meta code.\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+protected Hashtable mainDictionary = new Hashtable(INITIAL_CAPACITY);\r
+\r
+ /** Holds the dictionary file for appending*/\r
+ private File dictFile = null;\r
+\r
+ /**\r
+ * Dictionary Constructor.\r
+ * @throws java.io.IOException indicates a problem with the file system\r
+ */\r
+ public SpellDictionaryHashMap() throws IOException {\r
+ super((File) null);\r
+ }\r
+\r
+ /**\r
+ * Dictionary Constructor.\r
+ * @param wordList The file containing the words list for the dictionary\r
+ * @throws java.io.IOException indicates problems reading the words list\r
+ * file\r
+ */\r
+ public SpellDictionaryHashMap(Reader wordList) throws IOException {\r
+ super((File) null);\r
+ createDictionary(new BufferedReader(wordList));\r
+ }\r
+\r
+ /**\r
+ * Dictionary convenience Constructor.\r
+ * @param wordList The file containing the words list for the dictionary\r
+ * @throws java.io.FileNotFoundException indicates problems locating the\r
+ * words list file on the system\r
+ * @throws java.io.IOException indicates problems reading the words list\r
+ * file\r
+ */\r
+ public SpellDictionaryHashMap(File wordList) throws FileNotFoundException, IOException {\r
+ this(new FileReader(wordList));\r
+ dictFile = wordList;\r
+ }\r
+\r
+ /**\r
+ * Dictionary constructor that uses an aspell phonetic file to\r
+ * build the transformation table.\r
+ * @param wordList The file containing the words list for the dictionary\r
+ * @param phonetic The file to use for phonetic transformation of the \r
+ * wordlist.\r
+ * @throws java.io.FileNotFoundException indicates problems locating the\r
+ * file on the system\r
+ * @throws java.io.IOException indicates problems reading the words list\r
+ * file\r
+ */\r
+ public SpellDictionaryHashMap(File wordList, File phonetic) throws FileNotFoundException, IOException {\r
+ super(phonetic);\r
+ dictFile = wordList;\r
+ createDictionary(new BufferedReader(new FileReader(wordList)));\r
+ }\r
+\r
+ /**\r
+ * Dictionary constructor that uses an aspell phonetic file to\r
+ * build the transformation table. Encoding is used for phonetic file only; \r
+ * default encoding is used for wordList\r
+ * @param wordList The file containing the words list for the dictionary\r
+ * @param phonetic The file to use for phonetic transformation of the \r
+ * wordlist.\r
+ * @param phoneticEncoding Uses the character set encoding specified\r
+ * @throws java.io.FileNotFoundException indicates problems locating the\r
+ * file on the system\r
+ * @throws java.io.IOException indicates problems reading the words list\r
+ * or phonetic information\r
+ */\r
+ public SpellDictionaryHashMap(File wordList, File phonetic, String phoneticEncoding) throws FileNotFoundException, IOException {\r
+ super(phonetic, phoneticEncoding);\r
+ dictFile = wordList;\r
+ createDictionary(new BufferedReader(new FileReader(wordList)));\r
+ }\r
+\r
+ /**\r
+ * Dictionary constructor that uses an aspell phonetic file to\r
+ * build the transformation table.\r
+ * @param wordList The file containing the words list for the dictionary\r
+ * @param phonetic The reader to use for phonetic transformation of the \r
+ * wordlist.\r
+ * @throws java.io.IOException indicates problems reading the words list\r
+ * or phonetic information\r
+ */\r
+ public SpellDictionaryHashMap(Reader wordList, Reader phonetic) throws IOException {\r
+ super(phonetic);\r
+ dictFile = null;\r
+ createDictionary(new BufferedReader(wordList));\r
+ }\r
+\r
+ /**\r
+ * Add words from a file to existing dictionary hashmap.\r
+ * This function can be called as many times as needed to\r
+ * build the internal word list. Duplicates are not added.\r
+ * <p>\r
+ * Note that adding a dictionary does not affect the target\r
+ * dictionary file for the addWord method. That is, addWord() continues\r
+ * to make additions to the dictionary file specified in createDictionary()\r
+ * <P>\r
+ * @param wordList a File object that contains the words, on word per line.\r
+ * @throws FileNotFoundException\r
+ * @throws IOException\r
+ */\r
+ public void addDictionary(File wordList) throws FileNotFoundException, IOException {\r
+ addDictionaryHelper(new BufferedReader(new FileReader(wordList)));\r
+ }\r
+\r
+ /**\r
+ * Add words from a Reader to existing dictionary hashmap.\r
+ * This function can be called as many times as needed to\r
+ * build the internal word list. Duplicates are not added.\r
+ * <p>\r
+ * Note that adding a dictionary does not affect the target\r
+ * dictionary file for the addWord method. That is, addWord() continues\r
+ * to make additions to the dictionary file specified in createDictionary()\r
+ * <P>\r
+ * @param wordList a Reader object that contains the words, on word per line.\r
+ * @throws IOException\r
+ */\r
+ public void addDictionary(Reader wordList) throws IOException {\r
+ addDictionaryHelper(new BufferedReader(wordList));\r
+ }\r
+\r
+ /**\r
+ * Add a word permanently to the dictionary (and the dictionary file).\r
+ * <p>This needs to be made thread safe (synchronized)</p>\r
+ */\r
+ public void addWord(String word) {\r
+ putWord(word);\r
+ if (dictFile == null)\r
+ return;\r
+ try {\r
+ FileWriter w = new FileWriter(dictFile.toString(), true);\r
+ // Open with append.\r
+ w.write(word);\r
+ w.write("\n");\r
+ w.close();\r
+ } catch (IOException ex) {\r
+ System.out.println("Error writing to dictionary file");\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Constructs the dictionary from a word list file.\r
+ * <p>\r
+ * Each word in the reader should be on a separate line.\r
+ * <p>\r
+ * This is a very slow function. On my machine it takes quite a while to\r
+ * load the data in. I suspect that we could speed this up quite allot.\r
+ */\r
+ protected void createDictionary(BufferedReader in) throws IOException {\r
+ String line = "";\r
+ while (line != null) {\r
+ line = in.readLine();\r
+ if (line != null && line.length() > 0) {\r
+ line = new String(line.toCharArray());\r
+ putWord(line);\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Adds to the existing dictionary from a word list file. If the word\r
+ * already exists in the dictionary, a new entry is not added.\r
+ * <p>\r
+ * Each word in the reader should be on a separate line.\r
+ * <p>\r
+ * Note: for whatever reason that I haven't yet looked into, the phonetic codes\r
+ * for a particular word map to a vector of words rather than a hash table.\r
+ * This is a drag since in order to check for duplicates you have to iterate\r
+ * through all the words that use the phonetic code.\r
+ * If the vector-based implementation is important, it may be better\r
+ * to subclass for the cases where duplicates are bad.\r
+ */\r
+ protected void addDictionaryHelper(BufferedReader in) throws IOException {\r
+\r
+ String line = "";\r
+ while (line != null) {\r
+ line = in.readLine();\r
+ if (line != null && line.length() > 0) {\r
+ line = new String(line.toCharArray());\r
+ putWordUnique(line);\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Allocates a word in the dictionary\r
+ * @param word The word to add\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+protected void putWord(String word) {\r
+ String code = getCode(word);\r
+ Vector list = (Vector) mainDictionary.get(code);\r
+ if (list != null) {\r
+ list.addElement(word);\r
+ } else {\r
+ list = new Vector();\r
+ list.addElement(word);\r
+ mainDictionary.put(code, list);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Allocates a word, if it is not already present in the dictionary. A word\r
+ * with a different case is considered the same.\r
+ * @param word The word to add\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+protected void putWordUnique(String word) {\r
+\r
+ String code = getCode(word);\r
+ Vector list = (Vector) mainDictionary.get(code);\r
+\r
+ if (list != null) {\r
+\r
+ boolean isAlready = false;\r
+\r
+ for (int i = 0; i < list.size(); i++) {\r
+\r
+ if (word.equalsIgnoreCase((String) list.elementAt(i))) {\r
+ isAlready = true;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (!isAlready)\r
+ list.addElement(word);\r
+\r
+ } else {\r
+\r
+ list = new Vector();\r
+ list.addElement(word);\r
+ mainDictionary.put(code, list);\r
+\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Returns a list of strings (words) for the code.\r
+ */\r
+ @Override\r
+@SuppressWarnings("unchecked")\r
+public List getWords(String code) {\r
+ //Check the main dictionary.\r
+ Vector mainDictResult = (Vector) mainDictionary.get(code);\r
+ if (mainDictResult == null)\r
+ return new Vector();\r
+ return mainDictResult;\r
+ }\r
+\r
+ /**\r
+ * Returns true if the word is correctly spelled against the current word list.\r
+ */\r
+ @Override\r
+@SuppressWarnings("unchecked")\r
+public boolean isCorrect(String word) {\r
+ List possible = getWords(getCode(word));\r
+ if (possible.contains(word))\r
+ return true;\r
+ //JMH should we always try the lowercase version. If I dont then capitalised\r
+ //words are always returned as incorrect.\r
+ else if (possible.contains(word.toLowerCase()))\r
+ return true;\r
+ return false;\r
+ }\r
+}\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.spell.engine;\r
+\r
+/**\r
+ * An interface for all Transformators - which take a dictionary word and converts into its\r
+ * phonetic hash. These phonetic hashes are useful for determining what other words are\r
+ * similar to it, and then list those words as suggestions.\r
+ *\r
+ * @author Robert Gustavsson (robert@lindesign.se)\r
+ */\r
+public interface Transformator {\r
+\r
+ /**\r
+ * Take the given word, and return the best phonetic hash for it.\r
+ * @param word the word to transform\r
+ * @return the phonetic transformation of the word\r
+ */\r
+ public String transform(String word);\r
+\r
+ /**\r
+ * gets the list of characters that should be swapped in to the misspelled word\r
+ * in order to try to find more suggestions.\r
+ * In general, this list represents all of the unique phonetic characters\r
+ * for this Transformator.\r
+ * <p/>\r
+ * The replace list is used in the getSuggestions method.\r
+ * All of the letters in the misspelled word are replaced with the characters from\r
+ * this list to try and generate more suggestions, which implies l*n tries,\r
+ * if l is the size of the string, and n is the size of this list.\r
+ * <p/>\r
+ * In addition to that, each of these letters is added to the misspelled word.\r
+ * <p/>\r
+ * @return char[] misspelled words should try replacing with these characters to get more suggestions\r
+ */\r
+ public char[] getReplaceList();\r
+}\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.spell.engine;\r
+\r
+import java.util.Comparator;\r
+\r
+/**\r
+ * The Word object holds information for one suggested spelling.\r
+ * It contains both the suggested word string and the distance cost, which represents how different the suggested\r
+ * word is from the misspelling.\r
+ * <p>This class is now immutable.\r
+ * </p>\r
+ */\r
+@SuppressWarnings("unchecked")\r
+public class Word implements Comparator {\r
+ private String word;\r
+ private final int score;\r
+\r
+ /**\r
+ * Constructs a new Word.\r
+ * @param word The text of a word.\r
+ * @param score The word's distance cost\r
+ */\r
+ public Word(String word, int score) {\r
+ this.word = word;\r
+ this.score = score;\r
+ }\r
+\r
+ /**\r
+ * Constructs a new Word.\r
+ */\r
+ public Word() {\r
+ this.word = "";\r
+ this.score = 0;\r
+ }\r
+\r
+ /**\r
+ * Compares two words, mostly for the purpose of sorting words.\r
+ * @param o1 the first word\r
+ * @param o2 the second word\r
+ * @return -1 if the first word is more similar to the misspelled word\r
+ * <br>1 if the second word is more similar to the misspelled word\r
+ * <br>0 if both words are equally similar\r
+ *\r
+ */\r
+ public int compare(Object o1, Object o2) {\r
+ if (((Word) o1).getCost() < ((Word) o2).getCost()) return -1;\r
+ if (((Word) o1).getCost() == ((Word) o2).getCost()) return 0;\r
+ return 1;\r
+ }\r
+\r
+ /**\r
+ * Indicates if this word is equal to another one.\r
+ * @param o The other word to compare\r
+ * @return The indication of equality\r
+ */\r
+ @Override\r
+public boolean equals(Object o) {\r
+ if (o instanceof Word) // added by bd\r
+ return(((Word)o).getWord().equals(getWord()));\r
+ return false;\r
+ }\r
+ \r
+ /**\r
+ * gets suggested spelling\r
+ * @return the actual text of the suggest spelling\r
+ */\r
+ public String getWord() {\r
+ return word;\r
+ }\r
+\r
+ /**\r
+ * sets suggested spelling\r
+ * @param word The text to set for suggestd spelling\r
+ */\r
+ public void setWord(String word) {\r
+ this.word = word;\r
+ }\r
+\r
+ /**\r
+ * A cost measures how close a match this word was to the original word\r
+ * @return 0 if an exact match. Higher numbers are worse matches.\r
+ * @see EditDistance\r
+ */\r
+ public int getCost() {\r
+ return score;\r
+ }\r
+\r
+ /**\r
+ * returns the suggested spelling\r
+ * @return The word's text \r
+ */\r
+ @Override\r
+public String toString() {\r
+ return word;\r
+ }\r
+}\r
+\r
--- /dev/null
+EDIT_DEL1=95\r
+EDIT_DEL2=95\r
+EDIT_SWAP=90\r
+EDIT_SUB=100\r
+EDIT_CASE=10\r
+\r
+#DMV: the following commented out settings do not seem to be used at all\r
+#EDIT_SIMILAR=10\r
+#EDIT_MIN=90\r
+#EDIT_MAX=100\r
+\r
+SPELL_THRESHOLD=140\r
+SPELL_IGNOREUPPERCASE=true\r
+SPELL_IGNOREMIXEDCASE=false\r
+SPELL_IGNOREINTERNETADDRESS=true\r
+SPELL_IGNOREDIGITWORDS=true\r
+SPELL_IGNOREMULTIPLEWORDS=false\r
+SPELL_IGNORESENTENCECAPTILIZATION=true\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.spell.event;\r
+\r
+import java.text.BreakIterator;\r
+\r
+/**\r
+ * Defines common methods and behaviour for the various word finding\r
+ * subclasses.\r
+ *\r
+ * @author Anthony Roy (ajr@antroy.co.uk)\r
+ */\r
+public abstract class AbstractWordFinder implements WordFinder {\r
+\r
+ //~ Instance/static variables .............................................\r
+\r
+ /** The word being analyzed */\r
+ protected Word currentWord;\r
+ /** The word following the current one */\r
+ protected Word nextWord;\r
+ /** Indicate if the current word starts a new sentence */\r
+ protected boolean startsSentence;\r
+ /** Holds the text to analyze */\r
+ protected String text;\r
+ /** An iterator to work through the sentence */\r
+ protected BreakIterator sentenceIterator;\r
+\r
+ //~ Constructors ..........................................................\r
+\r
+ /**\r
+ * Creates a new AbstractWordFinder object.\r
+ *\r
+ * @param inText the String to iterate through.\r
+ */\r
+ public AbstractWordFinder(String inText) {\r
+ text = inText;\r
+ setup();\r
+ }\r
+\r
+ /**\r
+ * Creates a new default AbstractWordFinder object.\r
+ */\r
+ public AbstractWordFinder() {\r
+ text = "";\r
+ setup();\r
+ }\r
+ //~ Methods ...............................................................\r
+\r
+ /**\r
+ * This method scans the text from the end of the last word, and returns\r
+ * a new Word object corresponding to the next word.\r
+ *\r
+ * @return the following word.\r
+ */\r
+ public abstract Word next();\r
+\r
+ /**\r
+ * Return the text being searched. May have changed since first set\r
+ * through calls to replace.\r
+ *\r
+ * @return the text being searched.\r
+ */\r
+ public String getText() {\r
+\r
+ return text;\r
+ }\r
+ \r
+ /**\r
+ * Defines the text to search.\r
+ * @param newText The text to be analyzed\r
+ */\r
+ public void setText(String newText) {\r
+ text = newText;\r
+ setup();\r
+ }\r
+\r
+ /**\r
+ * Returns the current word in the iteration .\r
+ *\r
+ * @return the current word.\r
+ * @throws WordNotFoundException current word has not yet been set.\r
+ */\r
+ public Word current() {\r
+\r
+ if (currentWord == null) {\r
+ throw new WordNotFoundException("No Words in current String");\r
+ }\r
+\r
+ return currentWord;\r
+ }\r
+\r
+ /**\r
+ * Indicates if there is some more word to analyze\r
+ * @return true if there are further words in the string.\r
+ */\r
+ public boolean hasNext() {\r
+\r
+ return nextWord != null;\r
+\r
+ }\r
+\r
+ /**\r
+ * Replace the current word in the search with a replacement string.\r
+ *\r
+ * @param newWord the replacement string.\r
+ * @throws WordNotFoundException current word has not yet been set.\r
+ */\r
+ public void replace(String newWord) {\r
+\r
+ if (currentWord == null) {\r
+ throw new WordNotFoundException("No Words in current String");\r
+ }\r
+\r
+ StringBuffer sb = new StringBuffer(text.substring(0, currentWord.getStart()));\r
+ sb.append(newWord);\r
+ sb.append(text.substring(currentWord.getEnd()));\r
+ int diff = newWord.length() - currentWord.getText().length();\r
+ currentWord.setText(newWord);\r
+ /* Added Conditional to ensure a NullPointerException is avoided (11 Feb 2003) */\r
+ if (nextWord != null) {\r
+ nextWord.setStart(nextWord.getStart() + diff);\r
+ }\r
+ text = sb.toString();\r
+\r
+ sentenceIterator.setText(text);\r
+ int start = currentWord.getStart();\r
+ sentenceIterator.following(start);\r
+ startsSentence = sentenceIterator.current() == start;\r
+\r
+ }\r
+\r
+ /**\r
+ * @return true if the current word starts a new sentence.\r
+ * @throws WordNotFoundException current word has not yet been set.\r
+ */\r
+ public boolean startsSentence() {\r
+\r
+ if (currentWord == null) {\r
+ throw new WordNotFoundException("No Words in current String");\r
+ }\r
+\r
+ return startsSentence;\r
+ }\r
+\r
+ /**\r
+ * Return the text being searched. May have changed since first set\r
+ * through calls to replace.\r
+ *\r
+ * @return the text being searched.\r
+ */\r
+ public String toString() {\r
+\r
+ return text;\r
+ }\r
+\r
+ /**\r
+ * Adjusts the sentence iterator and the startSentence flag according to the\r
+ * currentWord.\r
+ * @param wd the wd parameter is not presently used.\r
+ */\r
+ protected void setSentenceIterator(Word wd) {\r
+ int current = sentenceIterator.current();\r
+\r
+ if (current == currentWord.getStart())\r
+ startsSentence = true;\r
+ else {\r
+ startsSentence = false;\r
+\r
+ if (currentWord.getEnd() > current) {\r
+ sentenceIterator.next();\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Indicates if the character at the specified position is acceptable as\r
+ * part of a word. To be acceptable, the character need to be a letter\r
+ * or a digit. It is also acceptable if the character is one of ''', '@',\r
+ * '.' or '_' and is preceded and followed by letter or digit.\r
+ * @param posn The character position to analyze.\r
+ * @return true if the character is a letter or digit\r
+ */\r
+ //Added more intelligent character recognition (11 Feb '03)\r
+ protected boolean isWordChar(int posn) {\r
+ boolean out = false;\r
+\r
+ char curr = text.charAt(posn);\r
+\r
+ if ((posn == 0) || (posn == text.length() - 1)) {\r
+ return Character.isLetterOrDigit(curr);\r
+ }\r
+\r
+ char prev = text.charAt(posn - 1);\r
+ char next = text.charAt(posn + 1);\r
+\r
+\r
+ switch (curr) {\r
+ case '\'':\r
+ case '@':\r
+ case '.':\r
+ case '_':\r
+ out = (Character.isLetterOrDigit(prev) && Character.isLetterOrDigit(next));\r
+ break;\r
+ default :\r
+ out = Character.isLetterOrDigit(curr);\r
+ }\r
+\r
+ return out;\r
+ }\r
+\r
+ /**\r
+ * Indicates if the character at the specified character is acceptable as\r
+ * part of a word. To be acceptable, the character need to be a letter\r
+ * or a digit or a ' (an apostrophe).\r
+ * @param c The character to evaluates if it can be part of a word\r
+ * @return true if the character is a letter, digit or a ' (an apostrophe).\r
+ */\r
+ protected boolean isWordChar(char c) {\r
+ boolean out = false;\r
+\r
+ if (Character.isLetterOrDigit(c) || (c == '\'')) {\r
+ out = true;\r
+ }\r
+\r
+ return out;\r
+ }\r
+\r
+ /**\r
+ * Ignores or skip over text starting from the index position specified \r
+ * if it contains the <code>startIgnore</code>, and until the \r
+ * first non letter or digit character is encountered or end of text is \r
+ * detected.\r
+ * @param index The start position in text.\r
+ * @param startIgnore The character that should be at <code>index</code> \r
+ * position to start skipping through.\r
+ * @return The index position pointing after the skipped characters or the\r
+ * original index if the ignore condition could not be met.\r
+ */\r
+ protected int ignore(int index, char startIgnore) {\r
+ return ignore(index, new Character(startIgnore), null);\r
+ }\r
+\r
+ /**\r
+ * Ignores or skip over text starting from the index position specified \r
+ * if it contains the <code>startIgnore</code>, and until the \r
+ * <code>endIgnore</code> character is encountered or end of text is \r
+ * detected.\r
+ * @param index The start position in text.\r
+ * @param startIgnore The character that should be at <code>index</code> \r
+ * position to start skipping through.\r
+ * @param endIgnore The character which mark the end of skipping through. If\r
+ * the value of endIgnore is <code>null</code>, skipping characters stop\r
+ * at first non letter or digit character.\r
+ * @return The index position pointing after the skipped characters or the\r
+ * original index if the ignore condition could not be met.\r
+ */\r
+ protected int ignore(int index, char startIgnore, char endIgnore) {\r
+ return ignore(index, new Character(startIgnore), new Character(endIgnore));\r
+ }\r
+\r
+ /**\r
+ * Ignores or skip over text starting from the index position specified \r
+ * if it contains the <code>startIgnore</code>, and until the \r
+ * <code>endIgnore</code> character is encountered or end of text is \r
+ * detected.\r
+ * @param index The start position in text.\r
+ * @param startIgnore The character that should be at <code>index</code> \r
+ * position to start skipping through.\r
+ * @param endIgnore The character which mark the end of skipping through. If\r
+ * the value of endIgnore is <code>null</code>, skipping characters stop\r
+ * at first non letter or digit character.\r
+ * @return The index position pointing after the skipped characters or the\r
+ * original index if the ignore condition could not be met.\r
+ */\r
+ protected int ignore(int index, Character startIgnore, Character endIgnore) {\r
+ int newIndex = index;\r
+\r
+ if (newIndex < text.length()) {\r
+ Character curChar = new Character(text.charAt(newIndex));\r
+\r
+ if (curChar.equals(startIgnore)) {\r
+ newIndex++;\r
+ while (newIndex < text.length()) {\r
+ curChar = new Character(text.charAt(newIndex));\r
+ if (endIgnore != null && curChar.equals(endIgnore)){\r
+ newIndex++;\r
+ break;\r
+ } else if (endIgnore == null && !Character.isLetterOrDigit(curChar.charValue())){\r
+ break;\r
+ }\r
+ newIndex++;\r
+ }\r
+ }\r
+ }\r
+\r
+ return newIndex;\r
+ }\r
+\r
+ /**\r
+ * Ignores or skip over text starting from the index position specified \r
+ * if it contains the <code>startIgnore</code> string, and until the \r
+ * <code>endIgnore</code> string is encountered or end of text is \r
+ * detected.\r
+ * @param index The start position in text.\r
+ * @param startIgnore The string that should be at <code>index</code> \r
+ * position to start skipping through.\r
+ * @param endIgnore The string which mark the end of skipping through.\r
+ * @return The index position pointing after the skipped characters or the\r
+ * original index if the ignore condition could not be met.\r
+ */\r
+ protected int ignore(int index, String startIgnore, String endIgnore) {\r
+\r
+ //{{{\r
+ int newIndex = index;\r
+ int len = text.length();\r
+ int slen = startIgnore.length();\r
+ int elen = endIgnore.length();\r
+\r
+ if (!((newIndex + slen) >= len)) {\r
+ String seg = text.substring(newIndex, newIndex + slen);\r
+\r
+ // System.out.println(seg + ":" + seg.length()+ ":" + startIgnore + ":" + slen);\r
+ if (seg.equals(startIgnore)) {\r
+ newIndex += slen;\r
+ cycle: while (true) {\r
+\r
+ if (newIndex == (text.length() - elen)) {\r
+\r
+ break cycle;\r
+ }\r
+\r
+ String ss = text.substring(newIndex, newIndex + elen);\r
+\r
+ if (ss.equals(endIgnore)) {\r
+ newIndex += elen;\r
+\r
+ break cycle;\r
+ } else {\r
+ newIndex++;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ return newIndex;\r
+ } //}}}\r
+\r
+ /**\r
+ * Initializes the sentenseIterator\r
+ */\r
+ protected void init() {\r
+ sentenceIterator = BreakIterator.getSentenceInstance();\r
+ sentenceIterator.setText(text);\r
+ }\r
+ \r
+ /**\r
+ * Defines the starting positions for text analysis\r
+ */\r
+ private void setup() {\r
+ currentWord = new Word("", 0);\r
+ nextWord = new Word("", 0);\r
+ startsSentence = true;\r
+\r
+ init();\r
+\r
+ try {\r
+ next();\r
+ } catch (WordNotFoundException e) {\r
+ currentWord = null;\r
+ nextWord = null;\r
+ }\r
+ }\r
+\r
+ \r
+}\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.spell.event;\r
+\r
+import java.text.BreakIterator;\r
+\r
+\r
+/**\r
+ * This class tokenizes a input string.\r
+ *\r
+ * <p>\r
+ * It also allows for the string to be mutated. The result after the spell\r
+ * checking is completed is available to the call to getFinalText\r
+ * </p>\r
+ *\r
+ * @author Jason Height(jheight@chariot.net.au)\r
+ * @author Anthony Roy (ajr@antroy.co.uk)\r
+ */\r
+public abstract class AbstractWordTokenizer implements WordTokenizer {\r
+\r
+ //~ Instance/static variables ...............................................\r
+\r
+ /** The word being analyzed */\r
+ protected Word currentWord;\r
+ /** The word finder used to filter out words which are non pertinent to\r
+ * spell checking */\r
+ protected WordFinder finder;\r
+ /** An iterator to work through the sentence */\r
+ protected BreakIterator sentenceIterator;\r
+\r
+ /** The cumulative word count that have been processed */\r
+ protected int wordCount = 0;\r
+\r
+ //~ Constructors ............................................................\r
+\r
+ /**\r
+ * Creates a new AbstractWordTokenizer object.\r
+ *\r
+ * @param text the text to process.\r
+ */\r
+ public AbstractWordTokenizer(String text) {\r
+ this(new DefaultWordFinder(text));\r
+ }\r
+\r
+ /**\r
+ * Creates a new AbstractWordTokenizer object.\r
+ *\r
+ * @param wf the custom WordFinder to use in searching for words.\r
+ */\r
+ public AbstractWordTokenizer(WordFinder wf) {\r
+ this.finder = wf;\r
+ }\r
+\r
+ //~ Methods .................................................................\r
+\r
+ /**\r
+ * Returns the current number of words that have been processed\r
+ *\r
+ * @return number of words so far iterated.\r
+ */\r
+ public int getCurrentWordCount() {\r
+\r
+ return wordCount;\r
+ }\r
+\r
+ /**\r
+ * Returns the end of the current word in the text\r
+ *\r
+ * @return index in string of the end of the current word.\r
+ * @throws WordNotFoundException current word has not yet been set.\r
+ */\r
+ public int getCurrentWordEnd() {\r
+\r
+ if (currentWord == null) {\r
+ throw new WordNotFoundException("No Words in current String");\r
+ }\r
+\r
+ return currentWord.getEnd();\r
+ }\r
+\r
+ /**\r
+ * Returns the index of the start of the current word in the text\r
+ *\r
+ * @return index in string of the start of the current word.\r
+ * @throws WordNotFoundException current word has not yet been set.\r
+ */\r
+ public int getCurrentWordPosition() {\r
+\r
+ if (currentWord == null) {\r
+ throw new WordNotFoundException("No Words in current String");\r
+ }\r
+\r
+ return currentWord.getStart();\r
+ }\r
+\r
+ /**\r
+ * Returns true if there are more words that can be processed in the string\r
+ *\r
+ * @return true if there are further words in the text.\r
+ */\r
+ public boolean hasMoreWords() {\r
+\r
+ return finder.hasNext();\r
+ }\r
+\r
+ /**\r
+ * Returns searches for the next word in the text, and returns that word.\r
+ *\r
+ * @return the string representing the current word.\r
+ * @throws WordNotFoundException search string contains no more words.\r
+ */\r
+ public String nextWord() {\r
+ currentWord = finder.next();\r
+\r
+ return currentWord.getText();\r
+ }\r
+\r
+ /**\r
+ * Replaces the current word token\r
+ *\r
+ * @param newWord replacement word.\r
+ * @throws WordNotFoundException current word has not yet been set.\r
+ */\r
+ public abstract void replaceWord(String newWord);\r
+\r
+ /**\r
+ * Returns the current text that is being tokenized (includes any changes\r
+ * that have been made)\r
+ *\r
+ * @return the text being tokenized.\r
+ */\r
+ public String getContext() {\r
+\r
+ return finder.toString();\r
+ }\r
+\r
+ /**\r
+ * returns true if the current word is at the start of a sentence\r
+ *\r
+ * @return true if the current word starts a sentence.\r
+ * @throws WordNotFoundException current word has not yet been set.\r
+ */\r
+ public boolean isNewSentence() {\r
+\r
+ return finder.startsSentence();\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.spell.event;\r
+\r
+import java.util.List;\r
+\r
+/** This event is fired off by the SpellChecker and is passed to the\r
+ * registered SpellCheckListeners\r
+ *\r
+ * @author Jason Height (jheight@chariot.net.au)\r
+ */\r
+class BasicSpellCheckEvent implements SpellCheckEvent {\r
+\r
+ /**The list holding the suggested Word objects for the misspelt word*/\r
+ @SuppressWarnings("unchecked")\r
+private final List suggestions;\r
+ /**The misspelt word*/\r
+ private final String invalidWord;\r
+ /**The action to be done when the event returns*/\r
+ private short action = INITIAL;\r
+ /**Contains the word to be replaced if the action is REPLACE or REPLACEALL*/\r
+ private String replaceWord = null;\r
+\r
+ @SuppressWarnings("unused")\r
+private final String context;\r
+ private final int startPosition;\r
+\r
+\r
+ /**Constructs the SpellCheckEvent\r
+ * @param invalidWord The word that is misspelt\r
+ * @param suggestions A list of Word objects that are suggested to replace the currently misspelt word\r
+ * @param tokenizer The reference to the tokenizer that caused this\r
+ * event to fire.\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+public BasicSpellCheckEvent(String invalidWord, List suggestions, WordTokenizer tokenizer) {\r
+ this.invalidWord = invalidWord;\r
+ this.suggestions = suggestions;\r
+ this.context = tokenizer.getContext();\r
+ this.startPosition = tokenizer.getCurrentWordPosition();\r
+ }\r
+\r
+ /** Returns the list of suggested Word objects\r
+ * @return A list of words phonetically close to the misspelt word\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+public List getSuggestions() {\r
+ return suggestions;\r
+ }\r
+\r
+ /** Returns the currently misspelt word\r
+ * @return The text misspelt\r
+ */\r
+ public String getInvalidWord() {\r
+ return invalidWord;\r
+ }\r
+\r
+ /** Returns the context in which the misspelt word is used\r
+ * @return The text containing the context\r
+ */\r
+ public String getWordContext() {\r
+ //JMH TBD\r
+ return null;\r
+ }\r
+\r
+ /** Returns the start position of the misspelt word in the context\r
+ * @return The position of the word\r
+ */\r
+ public int getWordContextPosition() {\r
+ return startPosition;\r
+ }\r
+\r
+ /** Returns the action type the user has to handle\r
+ * @return The type of action the event is carrying\r
+ */\r
+ public short getAction() {\r
+ return action;\r
+ }\r
+\r
+ /** Returns the text to replace\r
+ * @return the text of the word to replace\r
+ */\r
+ public String getReplaceWord() {\r
+ return replaceWord;\r
+ }\r
+\r
+ /** Set the action to replace the currently misspelt word with the new word\r
+ * @param newWord The word to replace the currently misspelt word\r
+ * @param replaceAll If set to true, the SpellChecker will replace all\r
+ * further occurrences of the misspelt word without firing a SpellCheckEvent.\r
+ */\r
+ public void replaceWord(String newWord, boolean replaceAll) {\r
+ if (action != INITIAL)\r
+ throw new IllegalStateException("The action can can only be set once");\r
+ if (replaceAll)\r
+ action = REPLACEALL;\r
+ else\r
+ action = REPLACE;\r
+ replaceWord = newWord;\r
+ }\r
+\r
+ /**\r
+ * Set the action it ignore the currently misspelt word.\r
+ * @param ignoreAll If set to true, the SpellChecker will replace all\r
+ * further occurrences of the misspelt word without firing a SpellCheckEvent.\r
+ */\r
+ public void ignoreWord(boolean ignoreAll) {\r
+ if (action != INITIAL)\r
+ throw new IllegalStateException("The action can can only be set once");\r
+ if (ignoreAll)\r
+ action = IGNOREALL;\r
+ else\r
+ action = IGNORE;\r
+ }\r
+\r
+ /** Set the action to add a new word into the dictionary. This will also replace the\r
+ * currently misspelt word.\r
+ * @param newWord The new word to add to the dictionary.\r
+ */\r
+ public void addToDictionary(String newWord) {\r
+ if (action != INITIAL)\r
+ throw new IllegalStateException("The action can can only be set once");\r
+ action = ADDTODICT;\r
+ replaceWord = newWord;\r
+ }\r
+\r
+ /** Set the action to terminate processing of the spellchecker.\r
+ */\r
+ public void cancel() {\r
+ if (action != INITIAL)\r
+ throw new IllegalStateException("The action can can only be set once");\r
+ action = CANCEL;\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.spell.event;\r
+\r
+/**\r
+ * A basic word finder, which searches text for sequences of letters.\r
+ * \r
+ * @author Anthony Roy (ajr@antroy.co.uk)\r
+ */\r
+public class DefaultWordFinder extends AbstractWordFinder {\r
+\r
+ //~ Instance/static variables ...............................................\r
+\r
+ //~ Constructors ............................................................\r
+\r
+ /**\r
+ * Creates a new DefaultWordFinder object.\r
+ * \r
+ * @param inText the String to search\r
+ */\r
+ public DefaultWordFinder(String inText) {\r
+ super(inText);\r
+ }\r
+\r
+ /**\r
+ * Creates a new DefaultWordFinder object.\r
+ */\r
+ public DefaultWordFinder() {\r
+ super();\r
+ }\r
+\r
+ //~ Methods .................................................................\r
+\r
+ /**\r
+ * This method scans the text from the end of the last word, and returns a\r
+ * new Word object corresponding to the next word.\r
+ * \r
+ * @return the next word.\r
+ * @throws WordNotFoundException search string contains no more words.\r
+ */\r
+ public Word next() {\r
+ if (nextWord == null) {\r
+ throw new WordNotFoundException("No more words found.");\r
+ }\r
+ currentWord.copy(nextWord);\r
+ setSentenceIterator(currentWord);\r
+\r
+ int i = currentWord.getEnd();\r
+ boolean finished = false;\r
+\r
+ while (i < text.length() && !finished) {\r
+ if (isWordChar(i)) {\r
+ nextWord.setStart(i);\r
+ int end = getNextWordEnd(text, i);\r
+ nextWord.setText(text.substring(i, end));\r
+ finished = true;\r
+ }\r
+ i++;\r
+ }\r
+ if (!finished)\r
+ nextWord = null;\r
+\r
+ return currentWord;\r
+ }\r
+\r
+ /**\r
+ * Returns the position in the string <em>after</em> the end of the next word.\r
+ * Note that this return value should not be used as an index into the string\r
+ * without checking first that it is in range, since it is possible for the\r
+ * value <code>text.length()</code> to be returned by this method.\r
+ */\r
+ private int getNextWordEnd(String text, int startPos) {\r
+ // If we're dealing with a possible 'internet word' we need to provide\r
+ // some special handling\r
+ if (SpellChecker.isINETWord(text.substring(startPos))) {\r
+ for (int i = startPos; i < text.length(); i++) {\r
+ char ch = text.charAt(i);\r
+ if (Character.isLetterOrDigit(ch))\r
+ continue;\r
+\r
+ if (ch == '\r' || ch == '\n')\r
+ return i;\r
+ // Chop off any characters that might be enclosing the 'internet word'. eg ',",),]\r
+ if (Character.isSpaceChar(ch))\r
+ if (i > 0 && Character.isLetterOrDigit(text.charAt(i - 1)))\r
+ return i;\r
+ else\r
+ return i - 1;\r
+ }\r
+ return text.length();\r
+ } else {\r
+ for (int i = startPos; i < text.length(); i++) {\r
+ if (!isWordChar(i))\r
+ return i;\r
+ }\r
+ return text.length();\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.spell.event;\r
+\r
+\r
+import java.text.BreakIterator;\r
+\r
+import javax.swing.text.AttributeSet;\r
+import javax.swing.text.BadLocationException;\r
+import javax.swing.text.Document;\r
+import javax.swing.text.Segment;\r
+import javax.swing.text.StyledDocument;\r
+\r
+\r
+/** This class tokenizes a swing document model. It also allows for the\r
+ * document model to be changed when corrections occur.\r
+ *\r
+ * @author Jason Height (jheight@chariot.net.au)\r
+ */\r
+public class DocumentWordTokenizer implements WordTokenizer {\r
+ /** Holds the start character position of the current word*/\r
+ private int currentWordPos = 0;\r
+ /** Holds the end character position of the current word*/\r
+ private int currentWordEnd = 0;\r
+ /** Holds the start character position of the next word*/\r
+ private int nextWordPos = -1;\r
+ /** The actual text that is being tokenized*/\r
+ private final Document document;\r
+ /** The character iterator over the document*/\r
+ private final Segment text;\r
+ /** The cumulative word count that have been processed*/\r
+ private int wordCount = 0;\r
+ /** Flag indicating if there are any more tokens (words) left*/\r
+ private boolean moreTokens = true;\r
+ /** Is this a special case where the currentWordStart, currntWordEnd and\r
+ * nextWordPos have already been calculated. (see nextWord)\r
+ */\r
+ private boolean first = true;\r
+ private final BreakIterator sentenceIterator;\r
+ private boolean startsSentence = true;\r
+\r
+ /**\r
+ * Creates a new DocumentWordTokenizer to work on a document\r
+ * @param document The document to spell check\r
+ */\r
+ public DocumentWordTokenizer(Document document) {\r
+ this.document = document;\r
+ //Create a text segment over the entire document\r
+ text = new Segment();\r
+ sentenceIterator = BreakIterator.getSentenceInstance();\r
+ try {\r
+ document.getText(0, document.getLength(), text);\r
+ sentenceIterator.setText(text);\r
+ currentWordPos = getNextWordStart(text, 0);\r
+ //If the current word pos is -1 then the string was all white space\r
+ if (currentWordPos != -1) {\r
+ currentWordEnd = getNextWordEnd(text, currentWordPos);\r
+ nextWordPos = getNextWordStart(text, currentWordEnd);\r
+ } else {\r
+ moreTokens = false;\r
+ }\r
+ } catch (BadLocationException ex) {\r
+ moreTokens = false;\r
+ }\r
+ }\r
+\r
+ /** This helper method will return the start character of the next\r
+ * word in the buffer from the start position\r
+ */\r
+ private static int getNextWordStart(Segment text, int startPos) {\r
+ if (startPos <= text.getEndIndex())\r
+ for (char ch = text.setIndex(startPos); ch != Segment.DONE; ch = text.next()) {\r
+ if (Character.isLetterOrDigit(ch)) {\r
+ return text.getIndex();\r
+ }\r
+ }\r
+ return -1;\r
+ }\r
+\r
+ /** This helper method will return the end of the next word in the buffer.\r
+ *\r
+ */\r
+ private static int getNextWordEnd(Segment text, int startPos) {\r
+ for (char ch = text.setIndex(startPos); ch != Segment.DONE; ch = text.next()) {\r
+ if (!Character.isLetterOrDigit(ch)) {\r
+ if (ch == '-' || ch == '\'') { // handle ' and - inside words\r
+ char ch2 = text.next();\r
+ text.previous();\r
+ if (ch2 != Segment.DONE && Character.isLetterOrDigit(ch2))\r
+ continue;\r
+ }\r
+ return text.getIndex();\r
+ }\r
+ }\r
+ return text.getEndIndex();\r
+ }\r
+\r
+ /**\r
+ * Indicates if there are more words left\r
+ * @return true if more words can be found in the text.\r
+ */\r
+ public boolean hasMoreWords() {\r
+ return moreTokens;\r
+ }\r
+ \r
+ /**\r
+ * Sets the current word position at the start of the word containing\r
+ * the char at position pos. This way a call to nextWord() will return\r
+ * this word.\r
+ * \r
+ * @param pos position in the word we want to set as current.\r
+ */\r
+ public void posStartFullWordFrom(int pos){\r
+ currentWordPos=text.getBeginIndex();\r
+ if(pos>text.getEndIndex())\r
+ pos=text.getEndIndex();\r
+ for (char ch = text.setIndex(pos); ch != Segment.DONE; ch = text.previous()) {\r
+ if (!Character.isLetterOrDigit(ch)) {\r
+ if (ch == '-' || ch == '\'') { // handle ' and - inside words\r
+ char ch2 = text.previous();\r
+ text.next();\r
+ if (ch2 != Segment.DONE && Character.isLetterOrDigit(ch2))\r
+ continue;\r
+ }\r
+ currentWordPos=text.getIndex()+1;\r
+ break;\r
+ }\r
+ }\r
+ //System.out.println("CurPos:"+currentWordPos);\r
+ if(currentWordPos==0)\r
+ first=true;\r
+ moreTokens=true;\r
+ currentWordEnd = getNextWordEnd(text, currentWordPos);\r
+ nextWordPos = getNextWordStart(text, currentWordEnd + 1);\r
+ }\r
+\r
+ /**\r
+ * Returns the number of word tokens that have been processed thus far\r
+ * @return the number of words found so far.\r
+ */\r
+ public int getCurrentWordPosition() {\r
+ return currentWordPos;\r
+ }\r
+\r
+ /**\r
+ * Returns an index representing the end location of the current word in the text.\r
+ * @return index of the end of the current word in the text.\r
+ */\r
+ public int getCurrentWordEnd() {\r
+ return currentWordEnd;\r
+ }\r
+\r
+ /**\r
+ * This returns the next word in the iteration. Note that any implementation should return\r
+ * the current word, and then replace the current word with the next word found in the\r
+ * input text (if one exists).\r
+ * @return the next word in the iteration.\r
+ */\r
+ public String nextWord() {\r
+ if (!first) {\r
+ currentWordPos = nextWordPos;\r
+ currentWordEnd = getNextWordEnd(text, currentWordPos);\r
+ nextWordPos = getNextWordStart(text, currentWordEnd + 1);\r
+ }\r
+ int current = sentenceIterator.current();\r
+ if (current == currentWordPos)\r
+ startsSentence = true;\r
+ else {\r
+ startsSentence = false;\r
+ if (currentWordEnd > current)\r
+ sentenceIterator.next();\r
+ }\r
+ //The nextWordPos has already been populated\r
+ String word = null;\r
+ try {\r
+ word = document.getText(currentWordPos, currentWordEnd - currentWordPos);\r
+ } catch (BadLocationException ex) {\r
+ moreTokens = false;\r
+ }\r
+ wordCount++;\r
+ first = false;\r
+ if (nextWordPos == -1)\r
+ moreTokens = false;\r
+ return word;\r
+ }\r
+\r
+ /**\r
+ * Returns the number of word tokens that have been processed thus far\r
+ * @return the number of words found so far.\r
+ */\r
+ public int getCurrentWordCount() {\r
+ return wordCount;\r
+ }\r
+\r
+ /** Replaces the current word token\r
+ * @param newWord The new word to replace the misspelt one\r
+ */\r
+ public void replaceWord(String newWord) {\r
+ @SuppressWarnings("unused")\r
+ AttributeSet attr=null;\r
+ if (currentWordPos != -1) {\r
+ try {\r
+ if(document instanceof StyledDocument)\r
+ attr=((StyledDocument)document).getCharacterElement(currentWordPos).getAttributes();\r
+ document.remove(currentWordPos, currentWordEnd - currentWordPos);\r
+ document.insertString(currentWordPos, newWord, null);\r
+ //Need to reset the segment\r
+ document.getText(0, document.getLength(), text);\r
+ } catch (BadLocationException ex) {\r
+ throw new RuntimeException(ex.getMessage());\r
+ }\r
+ //Position after the newly replaced word(s)\r
+ first = true;\r
+ currentWordPos = getNextWordStart(text, currentWordPos + newWord.length());\r
+ if (currentWordPos != -1) {\r
+ currentWordEnd = getNextWordEnd(text, currentWordPos);\r
+ nextWordPos = getNextWordStart(text, currentWordEnd);\r
+ sentenceIterator.setText(text);\r
+ sentenceIterator.following(currentWordPos);\r
+ } else\r
+ moreTokens = false;\r
+ }\r
+ }\r
+\r
+ /** Returns the current text that is being tokenized (includes any changes\r
+ * that have been made)\r
+ * @return The text, including changes.\r
+ */\r
+ public String getContext() {\r
+ return text.toString();\r
+ }\r
+\r
+ /** Indicates if the current word is at the start of a sentence\r
+ * @return true if the current word is at the start of a sentence\r
+ */\r
+ public boolean isNewSentence() {\r
+ // BreakIterator doesn't work when the first word in a sentence is not capitalised,\r
+ // but we need to check for capitalisation\r
+ if (startsSentence || currentWordPos < 2)\r
+ return(true);\r
+ \r
+ String textBefore = null;\r
+ try {\r
+ textBefore = document.getText(currentWordPos-2, 2);\r
+ } catch (BadLocationException ex) {\r
+ return(false);\r
+ }\r
+ return(textBefore != null && ".".equals(textBefore.trim()));\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.spell.event;\r
+\r
+import java.io.BufferedReader;\r
+import java.io.File;\r
+import java.io.FileReader;\r
+import java.io.IOException;\r
+\r
+\r
+/**\r
+ * This class tokenizes a input file.\r
+ *\r
+ * <p>\r
+ * Any takers to do this efficiently?? doesn't need to replace any words to\r
+ * start with. I need this to get an idea of how quick the spell checker is.\r
+ * </p>\r
+ */\r
+public class FileWordTokenizer extends AbstractWordTokenizer {\r
+\r
+ //~ Instance/static variables ...............................................\r
+\r
+// private File inFile;\r
+\r
+ //~ Constructors ............................................................\r
+\r
+ /**\r
+ * Creates a new FileWordTokenizer object.\r
+ *\r
+ * @param inputFile the file to work upon\r
+ */\r
+ public FileWordTokenizer(File inputFile) {\r
+ super(stringValue(inputFile));\r
+ }\r
+\r
+ /**\r
+ * Creates a new FileWordTokenizer object and associate a WordFinder to it's\r
+ * processing.\r
+ *\r
+ * @param inputFile the file to word upon.\r
+ * @param finder the specialize processing for words.\r
+ */\r
+ public FileWordTokenizer(File inputFile, WordFinder finder) {\r
+ super(finder);\r
+ finder.setText(stringValue(inputFile));\r
+ }\r
+ //~ Methods .................................................................\r
+\r
+ /**\r
+ * Replaces the current word token\r
+ *\r
+ * @param s the new string\r
+ * @throws WordNotFoundException current word not yet set.\r
+ */\r
+ @Override\r
+public void replaceWord(String s) {\r
+ }\r
+\r
+ private static String stringValue(File inFile) {\r
+ @SuppressWarnings("unused")\r
+ File stringFile = inFile;\r
+ StringBuffer out = new StringBuffer("");\r
+\r
+ try{\r
+ BufferedReader in = new BufferedReader(new FileReader(inFile));\r
+ char[] c = new char[100];\r
+ int count;\r
+ while ((count = in.read(c, 0, c.length)) != -1){\r
+ out.append(c,0,count);\r
+ }\r
+ in.close();\r
+ } catch(IOException e){\r
+ System.err.println("File input error trying to open " + inFile.toString() + " : " + e);\r
+ }\r
+ return out.toString();\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.spell.event;\r
+\r
+\r
+/**\r
+ * A word finder Java source files, which searches text for sequences of \r
+ * letters formated as Java comments.\r
+ *\r
+ * @author Anthony Roy (ajr@antroy.co.uk)\r
+ */\r
+public class JavaWordFinder extends AbstractWordFinder {\r
+\r
+ //~ Instance/static variables ...............................................\r
+\r
+ private boolean inComment;\r
+\r
+ //~ Constructors ............................................................\r
+\r
+ /**\r
+ * Creates a new JavaWordFinder object.\r
+ *\r
+ * @param inText the String to search\r
+ */\r
+ public JavaWordFinder(String inText) {\r
+ super(inText);\r
+ }\r
+\r
+ /**\r
+ * Creates a new JavaWordFinder object.\r
+ */\r
+ public JavaWordFinder() {\r
+ super();\r
+ }\r
+\r
+ //~ Methods .................................................................\r
+\r
+\r
+ /**\r
+ * This method scans the text from the end of the last word, and returns a\r
+ * new Word object corresponding to the next word.\r
+ *\r
+ * @return the next word.\r
+ * @throws WordNotFoundException search string contains no more words.\r
+ */\r
+ @Override\r
+public Word next() {\r
+\r
+ if (nextWord == null) {\r
+ throw new WordNotFoundException("No more words found.");\r
+ }\r
+\r
+ currentWord.copy(nextWord);\r
+\r
+ @SuppressWarnings("unused")\r
+ int current = sentenceIterator.current();\r
+ setSentenceIterator(currentWord);\r
+\r
+ int i = currentWord.getEnd();\r
+ boolean finished = false;\r
+ boolean started = false;\r
+\r
+ search:\r
+ while (i < text.length() && !finished) {\r
+\r
+ i = ignore(i, '@');\r
+ i = ignore(i, "<code>", "</code>");\r
+ i = ignore(i, "<CODE>", "</CODE>");\r
+ i = ignore(i, '<', '>');\r
+\r
+ if (i >= text.length()) break search;\r
+\r
+ char currentLetter = text.charAt(i);\r
+ if (inComment) {\r
+ //Reset on new line.\r
+ if (currentLetter == '\n') {\r
+ inComment = false;\r
+ i++;\r
+ continue search;\r
+ } else if (!isWordChar(i)) {\r
+ i++;\r
+ continue search;\r
+ }\r
+ //Find words.\r
+ while (i < text.length() - 1) {\r
+ if (!started && isWordChar(i)) {\r
+ nextWord.setStart(i);\r
+ started = true;\r
+ } else if (started && !isWordChar(i)) {\r
+ nextWord.setText(text.substring(nextWord.getStart(), i));\r
+ finished = true;\r
+ break search;\r
+ }\r
+\r
+ currentLetter = text.charAt(++i);\r
+ }\r
+ } else if (currentLetter == '*') {\r
+ inComment = true;\r
+ i++;\r
+ } else {\r
+ i++;\r
+ }\r
+ }\r
+\r
+ if (!started) {\r
+ nextWord = null;\r
+ } else if (!finished) {\r
+ nextWord.setText(text.substring(nextWord.getStart(), i));\r
+ }\r
+\r
+ return currentWord;\r
+ }\r
+\r
+ /**\r
+ * Initializes this word finder\r
+ */\r
+\r
+ @Override\r
+protected void init() {\r
+// sentenceIterator = BreakIterator.getSentenceInstance();\r
+// sentenceIterator.setText(text);\r
+ super.init();\r
+ inComment = false;\r
+ }\r
+}\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.spell.event;\r
+\r
+import java.util.List;\r
+\r
+/**\r
+ * This event is fired off by the SpellChecker and is passed to the\r
+ * registered SpellCheckListeners\r
+ * <p/>\r
+ * As far as I know, we will only require one implementation of the SpellCheckEvent\r
+ * (BasicSpellCheckEvent) but I have defined this interface just in case. The\r
+ * BasicSpellCheckEvent implementation is currently package private.\r
+ *\r
+ * @author Jason Height (jheight@chariot.net.au)\r
+ */\r
+public interface SpellCheckEvent {\r
+ /** Field indicating that the incorrect word should be ignored*/\r
+ public static final short IGNORE = 0;\r
+ /** Field indicating that the incorrect word should be ignored forever*/\r
+ public static final short IGNOREALL = 1;\r
+ /** Field indicating that the incorrect word should be replaced*/\r
+ public static final short REPLACE = 2;\r
+ /** Field indicating that the incorrect word should be replaced always*/\r
+ public static final short REPLACEALL = 3;\r
+ /** Field indicating that the incorrect word should be added to the dictionary*/\r
+ public static final short ADDTODICT = 4;\r
+ /** Field indicating that the spell checking should be terminated*/\r
+ public static final short CANCEL = 5;\r
+ /** Initial case for the action */\r
+ public static final short INITIAL = -1;\r
+\r
+ /** Returns the list of suggested Word objects\r
+ * @return A list of words phonetically close to the misspelt word\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+public List getSuggestions();\r
+\r
+ /** Returns the currently misspelt word\r
+ * @return The text misspelt\r
+ */\r
+ public String getInvalidWord();\r
+\r
+ /** Returns the context in which the misspelt word is used\r
+ * @return The text containing the context\r
+ */\r
+ public String getWordContext();\r
+\r
+ /** Returns the start position of the misspelt word in the context\r
+ * @return The position of the word\r
+ */\r
+ public int getWordContextPosition();\r
+\r
+ /** Returns the action type the user has to handle\r
+ * @return The type of action the event is carrying\r
+ */\r
+ public short getAction();\r
+\r
+ /** Returns the text to replace\r
+ * @return the text of the word to replace\r
+ */\r
+ public String getReplaceWord();\r
+\r
+ /** Set the action to replace the currently misspelt word with the new word\r
+ * @param newWord The word to replace the currently misspelt word\r
+ * @param replaceAll If set to true, the SpellChecker will replace all\r
+ * further occurrences of the misspelt word without firing a SpellCheckEvent.\r
+ */\r
+ public void replaceWord(String newWord, boolean replaceAll);\r
+\r
+ /** Set the action it ignore the currently misspelt word.\r
+ * @param ignoreAll If set to true, the SpellChecker will replace all\r
+ * further occurrences of the misspelt word without firing a SpellCheckEvent.\r
+ */\r
+ public void ignoreWord(boolean ignoreAll);\r
+\r
+ /** Set the action to add a new word into the dictionary. This will also replace the\r
+ * currently misspelt word.\r
+ *@param newWord The new word to add\r
+ */\r
+ public void addToDictionary(String newWord);\r
+\r
+ /** Set the action to terminate processing of the spell checker.\r
+ */\r
+ public void cancel();\r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.spell.event;\r
+\r
+import java.util.EventListener;\r
+\r
+/**\r
+ * This is the event based listener interface.\r
+ *\r
+ * @author Jason Height (jheight@chariot.net.au)\r
+ */\r
+public interface SpellCheckListener extends EventListener {\r
+ \r
+ /**\r
+ * Propagates the spelling errors to listeners.\r
+ * @param event The event to handle\r
+ */\r
+ public void spellingError(SpellCheckEvent event);\r
+}\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.spell.event;\r
+\r
+import java.io.IOException;\r
+import java.util.ArrayList;\r
+import java.util.Enumeration;\r
+import java.util.HashMap;\r
+import java.util.Hashtable;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Vector;\r
+\r
+import com.swabunga.spell.engine.Configuration;\r
+import com.swabunga.spell.engine.SpellDictionary;\r
+import com.swabunga.spell.engine.SpellDictionaryHashMap;\r
+import com.swabunga.spell.engine.Word;\r
+import com.swabunga.util.VectorUtility;\r
+\r
+\r
+/**\r
+ * This is the main class for spell checking (using the new event based spell\r
+ * checking). \r
+ * <p/>\r
+ * By default, the class makes a user dictionary to accumulate added words.\r
+ * Since this user directory has no file assign to persist added words, they\r
+ * will be retained for the duration of the spell checker instance.\r
+ * If you set a user dictionary like \r
+ * {@link com.swabunga.spell.engine.SpellDictionaryHashMap SpellDictionaryHashMap}\r
+ * to persist the added word, the user dictionary will have the possibility to\r
+ * grow and be available across differents invocations of the spell checker.\r
+ *\r
+ * @author Jason Height (jheight@chariot.net.au)\r
+ * 19 June 2002\r
+ */\r
+public class SpellChecker {\r
+ /** Flag indicating that the Spell Check completed without any errors present*/\r
+ public static final int SPELLCHECK_OK = -1;\r
+ /** Flag indicating that the Spell Check completed due to user cancellation*/\r
+ public static final int SPELLCHECK_CANCEL = -2;\r
+\r
+ @SuppressWarnings("unchecked")\r
+private final Vector eventListeners = new Vector();\r
+ @SuppressWarnings("unchecked")\r
+private final Vector dictionaries = new Vector();\r
+ private SpellDictionary userdictionary;\r
+\r
+ private final Configuration config = Configuration.getConfiguration();\r
+\r
+ /**This variable holds all of the words that are to be always ignored */\r
+ @SuppressWarnings("unchecked")\r
+private Vector ignoredWords = new Vector();\r
+ @SuppressWarnings("unchecked")\r
+private Hashtable autoReplaceWords = new Hashtable();\r
+ \r
+ // added caching - bd\r
+ // For cached operation a separate user dictionary is required\r
+ @SuppressWarnings("unchecked")\r
+private Map cache;\r
+ private int threshold = 0;\r
+ private int cacheSize = 0;\r
+ \r
+\r
+ /**\r
+ * Constructs the SpellChecker.\r
+ */\r
+ public SpellChecker() {\r
+ try {\r
+ userdictionary = new SpellDictionaryHashMap();\r
+ } catch (IOException e) {\r
+ throw new RuntimeException("this exception should never happen because we are using null phonetic file");\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Constructs the SpellChecker. The default threshold is used\r
+ *\r
+ * @param dictionary The dictionary used for looking up words.\r
+ */\r
+ public SpellChecker(SpellDictionary dictionary) {\r
+ this();\r
+ addDictionary(dictionary);\r
+ }\r
+\r
+\r
+ /**\r
+ * Constructs the SpellChecker with a threshold\r
+ *\r
+ * @param dictionary the dictionary used for looking up words.\r
+ * @param threshold the cost value above which any suggestions are \r
+ * thrown away\r
+ */\r
+ public SpellChecker(SpellDictionary dictionary, int threshold) {\r
+ this(dictionary);\r
+ config.setInteger(Configuration.SPELL_THRESHOLD, threshold);\r
+ }\r
+\r
+ /**\r
+ * Accumulates a dictionary at the end of the dictionaries list used\r
+ * for looking up words. Adding a dictionary give the flexibility to\r
+ * assign the base language dictionary, then a more technical, then...\r
+ *\r
+ * @param dictionary the dictionary to add at the end of the dictionary list.\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+public void addDictionary(SpellDictionary dictionary) {\r
+ if (dictionary == null) {\r
+ throw new IllegalArgumentException("dictionary must be non-null");\r
+ }\r
+ this.dictionaries.addElement(dictionary);\r
+ }\r
+\r
+ /**\r
+ * Registers the user dictionary to which words are added.\r
+ *\r
+ * @param dictionary the dictionary to use when the user specify a new word\r
+ * to add.\r
+ */\r
+ public void setUserDictionary(SpellDictionary dictionary) {\r
+ userdictionary = dictionary;\r
+ }\r
+\r
+ /**\r
+ * Supply the instance of the configuration holding the spell checking engine\r
+ * parameters.\r
+ *\r
+ * @return Current Configuration\r
+ */\r
+ public Configuration getConfiguration() {\r
+ return config;\r
+ }\r
+\r
+ /**\r
+ * Adds a SpellCheckListener to the listeners list.\r
+ *\r
+ * @param listener The feature to be added to the SpellCheckListener attribute\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+public void addSpellCheckListener(SpellCheckListener listener) {\r
+ eventListeners.addElement(listener);\r
+ }\r
+\r
+\r
+ /**\r
+ * Removes a SpellCheckListener from the listeners list.\r
+ *\r
+ * @param listener The listener to be removed from the listeners list.\r
+ */\r
+ public void removeSpellCheckListener(SpellCheckListener listener) {\r
+ eventListeners.removeElement(listener);\r
+ }\r
+\r
+\r
+ /**\r
+ * Fires off a spell check event to the listeners.\r
+ *\r
+ * @param event The event that need to be processed by the spell checking\r
+ * system.\r
+ */\r
+ protected void fireSpellCheckEvent(SpellCheckEvent event) {\r
+ for (int i = eventListeners.size() - 1; i >= 0; i--) {\r
+ ((SpellCheckListener) eventListeners.elementAt(i)).spellingError(event);\r
+ }\r
+ }\r
+\r
+\r
+ /**\r
+ * This method clears the words that are currently being remembered as\r
+ * <code>Ignore All</code> words and <code>Replace All</code> words.\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+public void reset() {\r
+ ignoredWords = new Vector();\r
+ autoReplaceWords = new Hashtable();\r
+ }\r
+\r
+\r
+ /**\r
+ * Checks the text string.\r
+ * <p>\r
+ * Returns the corrected string.\r
+ *\r
+ * @param text The text that need to be spelled checked\r
+ * @return The text after spell checking\r
+ * @deprecated use checkSpelling(WordTokenizer)\r
+ */\r
+ @Deprecated\r
+public String checkString(String text) {\r
+ StringWordTokenizer tokens = new StringWordTokenizer(text);\r
+ checkSpelling(tokens);\r
+ return tokens.getContext();\r
+ }\r
+\r
+\r
+ /**\r
+ * Verifies if the word that is being spell checked contains at least a\r
+ * digit.\r
+ * Returns true if this word contains a digit.\r
+ *\r
+ * @param word The word to analyze for digit.\r
+ * @return true if the word contains at least a digit.\r
+ */\r
+ private final static boolean isDigitWord(String word) {\r
+ for (int i = word.length() - 1; i >= 0; i--) {\r
+ if (Character.isDigit(word.charAt(i))) {\r
+ return true;\r
+ }\r
+ }\r
+ return false;\r
+ }\r
+\r
+\r
+ /**\r
+ * Verifies if the word that is being spell checked contains an Internet \r
+ * address. The method look for typical protocol or the habitual string \r
+ * in the word:\r
+ * <ul>\r
+ * <li>http://</li>\r
+ * <li>ftp://</li>\r
+ * <li>https://</li>\r
+ * <li>ftps://</li>\r
+ * <li>www.</li>\r
+ * </ul>\r
+ *\r
+ * One limitation is that this method cannot currently recognize email\r
+ * addresses. Since the 'word' that is passed in, may in fact contain\r
+ * the rest of the document to be checked, it is not (yet!) a good\r
+ * idea to scan for the @ character.\r
+ *\r
+ * @param word The word to analyze for an Internet address.\r
+ * @return true if this word looks like an Internet address.\r
+ */\r
+ public final static boolean isINETWord(String word) {\r
+ String lowerCaseWord = word.toLowerCase();\r
+ return lowerCaseWord.startsWith("http://") ||\r
+ lowerCaseWord.startsWith("www.") ||\r
+ lowerCaseWord.startsWith("ftp://") ||\r
+ lowerCaseWord.startsWith("https://") ||\r
+ lowerCaseWord.startsWith("ftps://");\r
+ }\r
+\r
+\r
+ /**\r
+ * Verifies if the word that is being spell checked contains all\r
+ * uppercases characters.\r
+ *\r
+ * @param word The word to analyze for uppercases characters\r
+ * @return true if this word contains all upper case characters\r
+ */\r
+ private final static boolean isUpperCaseWord(String word) {\r
+ for (int i = word.length() - 1; i >= 0; i--) {\r
+ if (Character.isLowerCase(word.charAt(i))) {\r
+ return false;\r
+ }\r
+ }\r
+ return true;\r
+ }\r
+\r
+\r
+ /**\r
+ * Verifies if the word that is being spell checked contains lower and\r
+ * upper cased characters. Note that a phrase beginning with an upper cased\r
+ * character is not considered a mixed case word.\r
+ *\r
+ * @param word The word to analyze for mixed cases characters\r
+ * @param startsSentence True if this word is at the start of a sentence\r
+ * @return true if this word contains mixed case characters\r
+ */\r
+ private final static boolean isMixedCaseWord(String word, boolean startsSentence) {\r
+ int strLen = word.length();\r
+ boolean isUpper = Character.isUpperCase(word.charAt(0));\r
+ //Ignore the first character if this word starts the sentence and the first\r
+ //character was upper cased, since this is normal behaviour\r
+ if ((startsSentence) && isUpper && (strLen > 1))\r
+ isUpper = Character.isUpperCase(word.charAt(1));\r
+ if (isUpper) {\r
+ for (int i = word.length() - 1; i > 0; i--) {\r
+ if (Character.isLowerCase(word.charAt(i))) {\r
+ return true;\r
+ }\r
+ }\r
+ } else {\r
+ for (int i = word.length() - 1; i > 0; i--) {\r
+ if (Character.isUpperCase(word.charAt(i))) {\r
+ return true;\r
+ }\r
+ }\r
+ }\r
+ return false;\r
+ }\r
+\r
+\r
+ /**\r
+ * This method will fire the spell check event and then handle the event\r
+ * action that has been selected by the user.\r
+ *\r
+ * @param tokenizer Description of the Parameter\r
+ * @param event The event to handle\r
+ * @return Returns true if the event action is to cancel the current spell checking, false if the spell checking should continue\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+protected boolean fireAndHandleEvent(WordTokenizer tokenizer, SpellCheckEvent event) {\r
+ fireSpellCheckEvent(event);\r
+ String word = event.getInvalidWord();\r
+ //Work out what to do in response to the event.\r
+ switch (event.getAction()) {\r
+ case SpellCheckEvent.INITIAL:\r
+ break;\r
+ case SpellCheckEvent.IGNORE:\r
+ break;\r
+ case SpellCheckEvent.IGNOREALL:\r
+ ignoreAll(word);\r
+ break;\r
+ case SpellCheckEvent.REPLACE:\r
+ tokenizer.replaceWord(event.getReplaceWord());\r
+ break;\r
+ case SpellCheckEvent.REPLACEALL:\r
+ String replaceAllWord = event.getReplaceWord();\r
+ if (!autoReplaceWords.containsKey(word)) {\r
+ autoReplaceWords.put(word, replaceAllWord);\r
+ }\r
+ tokenizer.replaceWord(replaceAllWord);\r
+ break;\r
+ case SpellCheckEvent.ADDTODICT:\r
+ String addWord = event.getReplaceWord();\r
+ if (!addWord.equals(word))\r
+ tokenizer.replaceWord(addWord);\r
+ userdictionary.addWord(addWord);\r
+ break;\r
+ case SpellCheckEvent.CANCEL:\r
+ return true;\r
+ default:\r
+ throw new IllegalArgumentException("Unhandled case.");\r
+ }\r
+ return false;\r
+ }\r
+\r
+ /**\r
+ * Adds a word to the list of ignored words\r
+ * @param word The text of the word to ignore\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+public void ignoreAll(String word) {\r
+ if (!ignoredWords.contains(word)) {\r
+ ignoredWords.addElement(word);\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * Adds a word to the user dictionary\r
+ * @param word The text of the word to add\r
+ */\r
+ public void addToDictionary(String word) {\r
+ if (!userdictionary.isCorrect(word))\r
+ userdictionary.addWord(word);\r
+ }\r
+ \r
+ /**\r
+ * Indicates if a word is in the list of ignored words\r
+ * @param word The text of the word check\r
+ */\r
+ public boolean isIgnored(String word){\r
+ return ignoredWords.contains(word);\r
+ }\r
+ \r
+ /**\r
+ * Verifies if the word to analyze is contained in dictionaries. The order \r
+ * of dictionary lookup is:\r
+ * <ul>\r
+ * <li>The default user dictionary or the one set through \r
+ * {@link SpellChecker#setUserDictionary}</li>\r
+ * <li>The dictionary specified at construction time, if any.</li>\r
+ * <li>Any dictionary in the order they were added through \r
+ * {@link SpellChecker#addDictionary}</li>\r
+ * </ul>\r
+ *\r
+ * @param word The word to verify that it's spelling is known.\r
+ * @return true if the word is in a dictionary.\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+public boolean isCorrect(String word) {\r
+ if (userdictionary.isCorrect(word)) return true;\r
+ for (Enumeration e = dictionaries.elements(); e.hasMoreElements();) {\r
+ SpellDictionary dictionary = (SpellDictionary) e.nextElement();\r
+ if (dictionary.isCorrect(word)) return true;\r
+ }\r
+ return false;\r
+ }\r
+\r
+ /**\r
+ * Produces a list of suggested word after looking for suggestions in various\r
+ * dictionaries. The order of dictionary lookup is:\r
+ * <ul>\r
+ * <li>The default user dictionary or the one set through \r
+ * {@link SpellChecker#setUserDictionary}</li>\r
+ * <li>The dictionary specified at construction time, if any.</li>\r
+ * <li>Any dictionary in the order they were added through \r
+ * {@link SpellChecker#addDictionary}</li>\r
+ * </ul>\r
+ *\r
+ * @param word The word for which we want to gather suggestions\r
+ * @param threshold the cost value above which any suggestions are \r
+ * thrown away\r
+ * @return the list of words suggested\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+public List getSuggestions(String word, int threshold) {\r
+ if (this.threshold != threshold && cache != null) {\r
+ this.threshold = threshold;\r
+ cache.clear();\r
+ }\r
+ \r
+ ArrayList suggestions = null;\r
+ \r
+ if (cache != null)\r
+ suggestions = (ArrayList) cache.get(word);\r
+\r
+ if (suggestions == null) {\r
+ suggestions = new ArrayList(50);\r
+ \r
+ for (Enumeration e = dictionaries.elements(); e.hasMoreElements();) {\r
+ SpellDictionary dictionary = (SpellDictionary) e.nextElement();\r
+ \r
+ if (dictionary != userdictionary)\r
+ VectorUtility.addAll(suggestions, dictionary.getSuggestions(word, threshold), false);\r
+ }\r
+\r
+ if (cache != null && cache.size() < cacheSize)\r
+ cache.put(word, suggestions);\r
+ }\r
+ \r
+ VectorUtility.addAll(suggestions, userdictionary.getSuggestions(word, threshold), false);\r
+ suggestions.trimToSize();\r
+ \r
+ return suggestions;\r
+ }\r
+\r
+ /**\r
+ * Activates a cache with the maximum number of entries set to 300\r
+ */\r
+ public void setCache() {\r
+ setCache(300);\r
+ }\r
+\r
+ /**\r
+ * Activates a cache with specified size\r
+ * @param size - max. number of cache entries (0 to disable chache)\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+public void setCache(int size) {\r
+ cacheSize = size;\r
+ if (size == 0)\r
+ cache = null;\r
+ else\r
+ cache = new HashMap((size + 2) / 3 * 4);\r
+ }\r
+\r
+ /**\r
+ * This method is called to check the spelling of the words that are returned\r
+ * by the WordTokenizer.\r
+ * <p/>\r
+ * For each invalid word the action listeners will be informed with a new \r
+ * SpellCheckEvent.<p>\r
+ *\r
+ * @param tokenizer The media containing the text to analyze.\r
+ * @return Either SPELLCHECK_OK, SPELLCHECK_CANCEL or the number of errors found. The number of errors are those that\r
+ * are found BEFORE any corrections are made.\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+public final int checkSpelling(WordTokenizer tokenizer) {\r
+ int errors = 0;\r
+ boolean terminated = false;\r
+ //Keep track of the previous word\r
+// String previousWord = null;\r
+ while (tokenizer.hasMoreWords() && !terminated) {\r
+ String word = tokenizer.nextWord();\r
+ //Check the spelling of the word\r
+ if (!isCorrect(word)) {\r
+ if ((config.getBoolean(Configuration.SPELL_IGNOREMIXEDCASE) && isMixedCaseWord(word, tokenizer.isNewSentence())) ||\r
+ (config.getBoolean(Configuration.SPELL_IGNOREUPPERCASE) && isUpperCaseWord(word)) ||\r
+ (config.getBoolean(Configuration.SPELL_IGNOREDIGITWORDS) && isDigitWord(word)) ||\r
+ (config.getBoolean(Configuration.SPELL_IGNOREINTERNETADDRESSES) && isINETWord(word))) {\r
+ //Null event. Since we are ignoring this word due\r
+ //to one of the above cases.\r
+ } else {\r
+ //We cant ignore this misspelt word\r
+ //For this invalid word are we ignoring the misspelling?\r
+ if (!isIgnored(word)) {\r
+ errors++;\r
+ //Is this word being automagically replaced\r
+ if (autoReplaceWords.containsKey(word)) {\r
+ tokenizer.replaceWord((String) autoReplaceWords.get(word));\r
+ } else {\r
+ //JMH Need to somehow capitalise the suggestions if\r
+ //ignoreSentenceCapitalisation is not set to true\r
+ //Fire the event.\r
+ List suggestions = getSuggestions(word, config.getInteger(Configuration.SPELL_THRESHOLD));\r
+ if (capitalizeSuggestions(word, tokenizer))\r
+ suggestions = makeSuggestionsCapitalized(suggestions);\r
+ SpellCheckEvent event = new BasicSpellCheckEvent(word, suggestions, tokenizer);\r
+ terminated = fireAndHandleEvent(tokenizer, event);\r
+ }\r
+ }\r
+ }\r
+ } else {\r
+ //This is a correctly spelt word. However perform some extra checks\r
+ /*\r
+ * JMH TBD //Check for multiple words\r
+ * if (!ignoreMultipleWords &&) {\r
+ * }\r
+ */\r
+ //Check for capitalisation\r
+ if (isSupposedToBeCapitalized(word, tokenizer)) {\r
+ errors++;\r
+ StringBuffer buf = new StringBuffer(word);\r
+ buf.setCharAt(0, Character.toUpperCase(word.charAt(0)));\r
+ Vector suggestion = new Vector();\r
+ suggestion.addElement(new Word(buf.toString(), 0));\r
+ SpellCheckEvent event = new BasicSpellCheckEvent(word, suggestion, tokenizer);\r
+ terminated = fireAndHandleEvent(tokenizer, event);\r
+ }\r
+ }\r
+ }\r
+ if (terminated)\r
+ return SPELLCHECK_CANCEL;\r
+ else if (errors == 0)\r
+ return SPELLCHECK_OK;\r
+ else\r
+ return errors;\r
+ }\r
+ \r
+ \r
+ @SuppressWarnings("unchecked")\r
+private List makeSuggestionsCapitalized(List suggestions) {\r
+ Iterator iterator = suggestions.iterator();\r
+ while(iterator.hasNext()) {\r
+ Word word = (Word)iterator.next();\r
+ String suggestion = word.getWord();\r
+ StringBuffer stringBuffer = new StringBuffer(suggestion);\r
+ stringBuffer.setCharAt(0, Character.toUpperCase(suggestion.charAt(0)));\r
+ word.setWord(stringBuffer.toString());\r
+ }\r
+ return suggestions;\r
+ }\r
+\r
+ \r
+ private boolean isSupposedToBeCapitalized(String word, WordTokenizer wordTokenizer) {\r
+ boolean configCapitalize = !config.getBoolean(Configuration.SPELL_IGNORESENTENCECAPITALIZATION);\r
+ return configCapitalize && wordTokenizer.isNewSentence() && Character.isLowerCase(word.charAt(0));\r
+ } \r
+\r
+ private boolean capitalizeSuggestions(String word, WordTokenizer wordTokenizer) {\r
+ // if SPELL_IGNORESENTENCECAPITALIZATION and the initial word is capitalized, suggestions should also be capitalized\r
+ // if !SPELL_IGNORESENTENCECAPITALIZATION, capitalize suggestions only for the first word in a sentence\r
+ boolean configCapitalize = !config.getBoolean(Configuration.SPELL_IGNORESENTENCECAPITALIZATION);\r
+ boolean uppercase = Character.isUpperCase(word.charAt(0));\r
+ return (configCapitalize && wordTokenizer.isNewSentence()) || (!configCapitalize && uppercase);\r
+ }\r
+}\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.spell.event;\r
+\r
+\r
+/**\r
+ * This class tokenizes a input string.\r
+ *\r
+ * <p>\r
+ * It also allows for the string to be altered by calls to replaceWord(). The result after the spell\r
+ * checking is completed is available to the call to getContext.\r
+ * </p>\r
+ *\r
+ * @author Jason Height (jheight@chariot.net.au)\r
+ * @author Anthony Roy (ajr@antroy.co.uk)\r
+ */\r
+public class StringWordTokenizer extends AbstractWordTokenizer {\r
+\r
+ //~ Constructors ............................................................\r
+\r
+ /**\r
+ * Creates a new StringWordTokenizer object.\r
+ *\r
+ * @param s the string to tokenize.\r
+ */\r
+ public StringWordTokenizer(String s) {\r
+ super(s);\r
+ }\r
+\r
+ /**\r
+ * Creates a new StringWordTokenizer object.\r
+ *\r
+ * @param wf the custom WordFinder to use in tokenizing. Note\r
+ * that the string to tokenize will be encapsulated within the WordFinder.\r
+ */\r
+ public StringWordTokenizer(WordFinder wf) {\r
+ super(wf);\r
+ }\r
+\r
+ /**\r
+ * Creates a new StringWordTokenizer object.\r
+ * @param s the string to work on\r
+ * @param finder the custom WordFinder to use in tokenizing. Note\r
+ * that the string to tokenize will be encapsulated within the WordFinder.\r
+ */\r
+ public StringWordTokenizer(String s, WordFinder finder) {\r
+ super(finder);\r
+ finder.setText(s);\r
+ }\r
+\r
+ \r
+ //~ Methods .................................................................\r
+\r
+ /**\r
+ *\r
+ * @deprecated use getContext() instead as per the WordTokenizer\r
+ * interface specification.\r
+ * @return the final text.\r
+ */\r
+ public String getFinalText() {\r
+\r
+ return getContext();\r
+ }\r
+\r
+ /**\r
+ * Replace the current word in the iteration with the String s.\r
+ *\r
+ * @param s the String to replace the current word.\r
+ * @throws WordNotFoundException current word not yet set.\r
+ */\r
+ public void replaceWord(String s) {\r
+ finder.replace(s);\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+//{{{ package and imports\r
+//:folding=explicit:\r
+package com.swabunga.spell.event;\r
+\r
+import java.util.Collection;\r
+import java.util.HashSet;\r
+\r
+/**\r
+ * A word finder for TeX and LaTeX documents, which searches text for\r
+ * sequences of letters, but ignores any commands and environments as well\r
+ * as Math environments.\r
+ *\r
+ * @author Anthony Roy (ajr@antroy.co.uk)\r
+ */\r
+\r
+//}}}\r
+\r
+public class TeXWordFinder extends AbstractWordFinder {\r
+\r
+//{{{ ~ Instance/static variables ...............................................\r
+\r
+ @SuppressWarnings("unused")\r
+private boolean IGNORE_COMMENTS = true;\r
+ @SuppressWarnings("unchecked")\r
+private final HashSet user_defined_ignores = new HashSet();\r
+ @SuppressWarnings("unused")\r
+private int regex_user_defined_ignores = STRING_EXPR;\r
+ /**\r
+ * A type where string expressions are used to define expression to ignore\r
+ */\r
+ public static final int STRING_EXPR = 0;\r
+ /**\r
+ * A type where regular expressions are used to define expression to ignore\r
+ */\r
+ public static final int REG_EXPR = 1;\r
+// public static final int GLOB_EXPR = 2;\r
+//}}}\r
+//{{{ ~ Constructors ............................................................\r
+\r
+ /**\r
+ * Creates a new DefaultWordFinder object.\r
+ *\r
+ * @param inText the text to search.\r
+ */\r
+ public TeXWordFinder(String inText) {\r
+ super(inText);\r
+ }\r
+ \r
+ /**\r
+ * Creates a new DefaultWordFinder object.\r
+ */\r
+ public TeXWordFinder() {\r
+ super();\r
+ }\r
+//}}}\r
+//{{{ ~ Methods .................................................................\r
+\r
+ /**\r
+ * This method scans the text from the end of the last word, and returns a\r
+ * new Word object corresponding to the next word.\r
+ *\r
+ * @return the next word.\r
+ * @throws WordNotFoundException search string contains no more words.\r
+ */\r
+ @Override\r
+public Word next() {\r
+//{{{\r
+\r
+ if (!hasNext())//currentWord == null)\r
+ throw new WordNotFoundException("No more words found.");\r
+\r
+ currentWord.copy(nextWord);\r
+ setSentenceIterator(currentWord);\r
+\r
+\r
+ int i = currentWord.getEnd();\r
+ boolean finished = false;\r
+ boolean started = false;\r
+\r
+ search:\r
+ while (i < text.length() && !finished) {\r
+\r
+//{{{ Find words.\r
+ if (!started && isWordChar(i)) {\r
+ nextWord.setStart(i++);\r
+ started = true;\r
+ continue search;\r
+ } else if (started) {\r
+ if (isWordChar(i)) {\r
+ i++;\r
+ continue search;\r
+ } else {\r
+ nextWord.setText(text.substring(nextWord.getStart(), i));\r
+ finished = true;\r
+ break search;\r
+ }\r
+ } //}}}\r
+// Ignores should be in order of importance and then specificity.\r
+ int j = i;\r
+// Ignore Comments:\r
+ j = ignore(j, '%', '\n');\r
+ \r
+// Ignore Maths:\r
+ j = ignore(j, "$$", "$$");\r
+ j = ignore(j, '$', '$');\r
+ \r
+// Ignore user defined.\r
+ j = ignoreUserDefined(j);\r
+ \r
+// Ignore certain command parameters.\r
+ j = ignore(j, "\\newcommand", "}");\r
+ j = ignore(j, "\\documentclass", "}");\r
+ j = ignore(j, "\\usepackage", "}");\r
+ j = ignore(j, "\\newcounter{", "}");\r
+ j = ignore(j, "\\setcounter{", "}");\r
+ j = ignore(j, "\\addtocounter{", "}");\r
+ j = ignore(j, "\\value{", "}");\r
+ j = ignore(j, "\\arabic{", "}");\r
+ j = ignore(j, "\\usecounter{", "}");\r
+ j = ignore(j, "\\newenvironment", "}");\r
+ j = ignore(j, "\\setlength", "}");\r
+ j = ignore(j, "\\setkeys", "}");\r
+ \r
+// Ignore environment names.\r
+ j = ignore(j, "\\begin{", "}");\r
+ j = ignore(j, "\\end{", "}"); \r
+ if (i != j){\r
+ i = j;\r
+ continue search;\r
+ }\r
+ \r
+// Ignore commands.\r
+ j = ignore(j, '\\');\r
+ \r
+ if (i != j){\r
+ i = j;\r
+ continue search;\r
+ }\r
+ i++;\r
+ }\r
+\r
+ if (!started) {\r
+ nextWord = null;\r
+ } else if (!finished) {\r
+ nextWord.setText(text.substring(nextWord.getStart(), i));\r
+ }\r
+\r
+ return currentWord;\r
+ }\r
+//}}}\r
+ /**\r
+ * This method is used to import a user defined set of either strings or regular expressions to ignore.\r
+ * @param expressions a collection of Objects whose toString() value should be the expression. Typically String objects.\r
+ * @param regex is an integer specifying the type of expression to use. e.g. REG_EXPR, STRING_EXPR.\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+public void addUserDefinedIgnores(Collection expressions, int regex){\r
+ user_defined_ignores.addAll(expressions);\r
+ regex_user_defined_ignores = regex;\r
+ }\r
+\r
+ private int ignoreUserDefined(int i){\r
+ return i;\r
+ }\r
+ \r
+ /**\r
+ * Define if comments contents are ignored during spell checking\r
+ * @param ignore an indication if comments content is to be ignored\r
+ */\r
+ public void setIgnoreComments(boolean ignore) {\r
+ IGNORE_COMMENTS = ignore;\r
+ }\r
+//}}}\r
+}\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.spell.event;\r
+\r
+/**\r
+ * Offers basic methods to manipulate a text string representing a word.\r
+ */\r
+public class Word {\r
+\r
+ //~ Instance/static variables ...............................................\r
+\r
+ private int end;\r
+ private int start;\r
+ private String text;\r
+\r
+ //~ Constructors ............................................................\r
+\r
+ /**\r
+ * Creates a new Word object.\r
+ *\r
+ * @param text the String representing the word.\r
+ * @param start the start index of the word.\r
+ */\r
+ public Word(String text, int start) {\r
+ this.text = text;\r
+ this.start = start;\r
+ setEnd();\r
+ }\r
+\r
+ /**\r
+ * Creates a new Word object by cloning an existing Word object.\r
+ *\r
+ * @param w the word object to clone.\r
+ */\r
+ public Word(Word w) {\r
+ this.copy(w);\r
+ }\r
+\r
+ //~ Methods .................................................................\r
+\r
+ /**\r
+ * Evaluate the end of word position.\r
+ * @return the end index of the word.\r
+ */\r
+ public int getEnd() {\r
+\r
+ return end;\r
+ }\r
+\r
+ /**\r
+ * Set the start index of the word.\r
+ *\r
+ * @param s the start index.\r
+ */\r
+ public void setStart(int s) {\r
+ start = s;\r
+ setEnd();\r
+ }\r
+\r
+ /**\r
+ * Evaluate the start of word position.\r
+ * @return the start index.\r
+ */\r
+ public int getStart() {\r
+\r
+ return start;\r
+ }\r
+\r
+ /**\r
+ * Set the text to a new string value.\r
+ *\r
+ * @param s the new text\r
+ */\r
+ public void setText(String s) {\r
+ text = s;\r
+ setEnd();\r
+ }\r
+\r
+ /**\r
+ * Supply the text string representing the word\r
+ * @return the String representing the word.\r
+ */\r
+ public String getText() {\r
+\r
+ return text;\r
+ }\r
+\r
+ /**\r
+ * Sets the value of this Word to be a copy of another.\r
+ *\r
+ * @param w the Word to copy.\r
+ */\r
+ public void copy(Word w) {\r
+ text = w.toString();\r
+ start = w.getStart();\r
+ setEnd();\r
+ }\r
+\r
+ /**\r
+ * Evaluate the length of the word.\r
+ * @return the length of the word.\r
+ */\r
+ public int length() {\r
+\r
+ return text.length();\r
+ }\r
+\r
+ /**\r
+ * Supply the text representing the word.\r
+ * @return the text representing the word.\r
+ */\r
+ public String toString() {\r
+\r
+ return text;\r
+ }\r
+\r
+ /**\r
+ * Set the end index of the word.\r
+ *\r
+ */\r
+ private void setEnd() {\r
+ end = start + text.length();\r
+ }\r
+}\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.spell.event;\r
+\r
+/**\r
+ * <p>An interface for objects which take a String as input, and iterates through\r
+ * the words in the string.\r
+ * </P>\r
+ *\r
+ * <P>\r
+ * When the object is instantiated, and before the first call to <CODE>next()</CODE> is made,\r
+ * the following methods should throw a <CODE>WordNotFoundException</CODE>:<br>\r
+ * <CODE>current()</CODE>,\r
+ * <CODE>startsSentence()</CODE> and <CODE>replace()</CODE>.\r
+ * </P>\r
+ *\r
+ * <P>A call to <CODE>next()</CODE> when <CODE>hasMoreWords()</CODE> returns false\r
+ * should throw a <CODE>WordNotFoundException</CODE>.</P>\r
+ * @author Jason Height (jheight@chariot.net.au)\r
+ */\r
+\r
+public interface WordFinder {\r
+\r
+ //~ Methods .................................................................\r
+\r
+ /**\r
+ * This method returns the text through which the WordFinder is iterating.\r
+ * The text may have been modified through calls to replace().\r
+ *\r
+ * @return the (possibly modified) text being searched.\r
+ */\r
+ public String getText();\r
+\r
+ /**\r
+ * This method resets the text through which the WordFinder iterates.\r
+ * It must also re-initialize the WordFinder.\r
+ *\r
+ * @param newText the new text to search.\r
+ */\r
+ public void setText(String newText);\r
+\r
+ /**\r
+ * This method should return the Word object representing the current word\r
+ * in the iteration.\r
+ * This method should not affect the state of the WordFinder object.\r
+ *\r
+ * @return the current Word object.\r
+ * @throws WordNotFoundException current word has not yet been set.\r
+ */\r
+ public Word current();\r
+\r
+ /**\r
+ * Tests the finder to see if any more words are available.\r
+ *\r
+ * @return true if more words are available.\r
+ */\r
+ public boolean hasNext();\r
+\r
+ /**\r
+ * This method should return the Word object representing the next word\r
+ * in the iteration (the first word if next() has not yet been called.)\r
+ *\r
+ * @return the next Word in the iteration.\r
+ * @throws WordNotFoundException search string contains no more words.\r
+ */\r
+ public Word next();\r
+\r
+ /**\r
+ * This method should replace the current Word object with a Word object\r
+ * representing the String newWord.\r
+ *\r
+ * @param newWord the word to replace the current word with.\r
+ * @throws WordNotFoundException current word has not yet been set.\r
+ */\r
+ public void replace(String newWord);\r
+\r
+ /**\r
+ * Indicates if the current word starts a new sentence.\r
+ * @return true if the current word starts a new sentence.\r
+ * @throws WordNotFoundException current word has not yet been set.\r
+ */\r
+ public boolean startsSentence();\r
+\r
+ // public void setText();\r
+}\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.spell.event;\r
+\r
+/**\r
+ * An exception to indicate that there not enough words as expected.\r
+ */\r
+@SuppressWarnings("serial")\r
+public class WordNotFoundException extends RuntimeException {\r
+\r
+ //~ Constructors ............................................................\r
+\r
+ /**\r
+ * Creates a new WordNotFoundException object.\r
+ */\r
+ public WordNotFoundException() {\r
+ super();\r
+ }\r
+\r
+ /**\r
+ * Creates a new WordNotFoundException object.\r
+ *\r
+ * @param s a message.\r
+ */\r
+ public WordNotFoundException(String s) {\r
+ super(s);\r
+ }\r
+}\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.spell.event;\r
+\r
+/**\r
+ * <p>An interface for objects which take a text-based media as input, and iterate through\r
+ * the words in the text stored in that media. Examples of such media could be Strings,\r
+ * Documents, Files, TextComponents etc.\r
+ * </P>\r
+ *\r
+ * <P>\r
+ * When the object is instantiated, and before the first call to <CODE>next()</CODE> is made,\r
+ * the following methods should throw a <CODE>WordNotFoundException</CODE>:<br>\r
+ * <CODE>getCurrentWordEnd()</CODE>, <CODE>getCurrentWordPosition()</CODE>,\r
+ * <CODE>isNewSentence()</CODE> and <CODE>replaceWord()</CODE>.\r
+ * </P>\r
+ *\r
+ * <P>A call to <CODE>next()</CODE> when <CODE>hasMoreWords()</CODE> returns false\r
+ * should throw a <CODE>WordNotFoundException</CODE>.</P>\r
+ * @author Jason Height (jheight@chariot.net.au)\r
+ */\r
+public interface WordTokenizer {\r
+\r
+ //~ Methods .................................................................\r
+\r
+ /**\r
+ * Returns the context text that is being tokenized (should include any\r
+ * changes that have been made).\r
+ * @return the text being searched.\r
+ */\r
+ public String getContext();\r
+\r
+ /**\r
+ * Returns the number of word tokens that have been processed thus far\r
+ * @return the number of words found so far.\r
+ */\r
+ public int getCurrentWordCount();\r
+\r
+ /**\r
+ * Returns an index representing the end location of the current word in the text.\r
+ * @return index of the end of the current word in the text.\r
+ * @throws WordNotFoundException current word has not yet been set.\r
+ */\r
+ public int getCurrentWordEnd();\r
+\r
+ /**\r
+ * Returns an index representing the start location of the current word in the text.\r
+ * @return index of the start of the current word in the text.\r
+ * @throws WordNotFoundException current word has not yet been set.\r
+ */\r
+ public int getCurrentWordPosition();\r
+\r
+ /**\r
+ * Returns true if the current word is at the start of a sentence\r
+ * @return true if the current word starts a sentence.\r
+ * @throws WordNotFoundException current word has not yet been set.\r
+ */\r
+ public boolean isNewSentence();\r
+\r
+ /**\r
+ * Indicates if there are more words left\r
+ * @return true if more words can be found in the text.\r
+ */\r
+ public boolean hasMoreWords();\r
+\r
+ /**\r
+ * This returns the next word in the iteration. Note that any implementation should return\r
+ * the current word, and then replace the current word with the next word found in the\r
+ * input text (if one exists).\r
+ * @return the next word in the iteration.\r
+ * @throws WordNotFoundException search string contains no more words.\r
+ */\r
+ public String nextWord();\r
+\r
+ /**\r
+ * Replaces the current word token\r
+ *\r
+ * <p/>\r
+ * When a word is replaced care should be taken that the WordTokenizer\r
+ * repositions itself such that the words that were added aren't rechecked.\r
+ * Of course this is not mandatory, maybe there is a case when an\r
+ * application doesn't need to do this.\r
+ * <p/>\r
+ * @param newWord the string which should replace the current word.\r
+ * @throws WordNotFoundException current word has not yet been set.\r
+ */\r
+ public void replaceWord(String newWord);\r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+//:folding=indent:\r
+package com.swabunga.spell.event;\r
+\r
+\r
+/**\r
+ * A word finder for XML or HTML documents, which searches text for sequences\r
+ * of letters, but ignores the text inside any tags.\r
+ *\r
+ * @author Anthony Roy (ajr@antroy.co.uk)\r
+ */\r
+public class XMLWordFinder extends AbstractWordFinder {\r
+\r
+ //~ Instance/static variables ...............................................\r
+\r
+ //~ Constructors ............................................................\r
+\r
+ /**\r
+ * Creates a new DefaultWordFinder object.\r
+ *\r
+ * @param inText the text to search.\r
+ */\r
+ public XMLWordFinder(String inText) {\r
+ super(inText);\r
+ }\r
+\r
+ //~ Methods .................................................................\r
+\r
+ /**\r
+ * This method scans the text from the end of the last word, and returns a\r
+ * new Word object corresponding to the next word.\r
+ *\r
+ * @return the next word.\r
+ * @throws WordNotFoundException search string contains no more words.\r
+ */\r
+ public Word next() {\r
+\r
+ if (currentWord == null)\r
+ throw new WordNotFoundException("No more words found.");\r
+\r
+ currentWord.copy(nextWord);\r
+\r
+ setSentenceIterator(currentWord);\r
+\r
+ int i = currentWord.getEnd();\r
+ boolean finished = false;\r
+ boolean started = false;\r
+\r
+ search: /* Find words. */\r
+ while (i < text.length() && !finished) {\r
+ if (!started && isWordChar(i)) {\r
+ nextWord.setStart(i++);\r
+ started = true;\r
+ continue search;\r
+ } else if (started) {\r
+ if (isWordChar(i)) {\r
+ i++;\r
+ continue search;\r
+ } else {\r
+ nextWord.setText(text.substring(nextWord.getStart(), i));\r
+ finished = true;\r
+ break search;\r
+ }\r
+ }\r
+\r
+ //Ignore things inside tags.\r
+ int i2 = ignore(i, '<', '>');\r
+ i = (i2 == i ? i + 1 : i2);\r
+ }\r
+\r
+ if (!started) {\r
+ nextWord = null;\r
+ } else if (!finished) {\r
+ nextWord.setText(text.substring(nextWord.getStart(), i));\r
+ }\r
+\r
+ return currentWord;\r
+ }\r
+}\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.spell.swing.autospell;\r
+\r
+import java.awt.Point;\r
+import java.awt.event.ActionEvent;\r
+import java.awt.event.ActionListener;\r
+import java.awt.event.MouseAdapter;\r
+import java.awt.event.MouseEvent;\r
+import java.util.ResourceBundle;\r
+\r
+import javax.swing.JEditorPane;\r
+import javax.swing.JMenuItem;\r
+import javax.swing.JPopupMenu;\r
+import javax.swing.SwingUtilities;\r
+import javax.swing.event.DocumentEvent;\r
+import javax.swing.event.DocumentListener;\r
+import javax.swing.text.AttributeSet;\r
+import javax.swing.text.Document;\r
+import javax.swing.text.Element;\r
+import javax.swing.text.Segment;\r
+import javax.swing.text.SimpleAttributeSet;\r
+import javax.swing.text.StyledDocument;\r
+\r
+import com.swabunga.spell.engine.Configuration;\r
+import com.swabunga.spell.event.DocumentWordTokenizer;\r
+import com.swabunga.spell.event.SpellChecker;\r
+\r
+/**\r
+ * This class handles the actual autospelling by implementing some listeners\r
+ * on the spellchecked JEditorPane and Document.\r
+ * \r
+ * @author Robert Gustavsson (robert@lindesign.se)\r
+ *\r
+ */\r
+public class AutoSpellCheckHandler extends MouseAdapter implements DocumentListener, \r
+ AutoSpellConstants{\r
+\r
+ private SpellChecker sCheck=null;\r
+ private final Configuration config = Configuration.getConfiguration();\r
+ private ResourceBundle messages=null;\r
+ \r
+ public AutoSpellCheckHandler(SpellChecker sc){\r
+ sCheck=sc;\r
+ }\r
+ \r
+ public AutoSpellCheckHandler(SpellChecker sc, ResourceBundle rs){\r
+ this(sc);\r
+ messages=rs;\r
+ }\r
+ \r
+ public void addJEditorPane(JEditorPane pane){\r
+ StyledDocument doc=(StyledDocument)pane.getDocument();\r
+ markupSpelling(doc, 0, doc.getLength()-1);\r
+ doc.addDocumentListener(this);\r
+ pane.addMouseListener(this);\r
+ }\r
+ \r
+ public void removeJEditorPane(JEditorPane pane){\r
+ Document doc=pane.getDocument();\r
+ pane.removeMouseListener(this);\r
+ doc.removeDocumentListener(this);\r
+ }\r
+ \r
+ private void markupSpelling(StyledDocument doc, int start, int end){\r
+ int wordStart=-1,\r
+ wordEnd=-1;\r
+ String word;\r
+ DocumentWordTokenizer docTok;\r
+ @SuppressWarnings("unused")\r
+ Segment seg=new Segment();\r
+ \r
+ docTok=new DocumentWordTokenizer(doc);\r
+ if(start>0){\r
+ docTok.posStartFullWordFrom(start);\r
+ }\r
+ \r
+ while(docTok.hasMoreWords() && docTok.getCurrentWordPosition()<=end){\r
+ word=docTok.nextWord();\r
+ wordStart=docTok.getCurrentWordPosition();\r
+ \r
+ // Mark non word parts (spaces) as correct\r
+ if(wordEnd!=-1){\r
+ //System.out.println("Space:"+wordEnd+","+wordStart);\r
+ markAsCorrect(doc, wordEnd, wordStart);\r
+ }\r
+ wordEnd=docTok.getCurrentWordEnd();\r
+ \r
+ if(wordEnd>doc.getLength())\r
+ wordEnd=doc.getLength()-1;\r
+ if(wordStart>=wordEnd)\r
+ continue;\r
+ //System.out.println("Word:"+wordStart+","+wordEnd);\r
+ if(sCheck.isCorrect(word) || sCheck.isIgnored(word)){\r
+ markAsCorrect(doc, wordStart, wordEnd);\r
+ }else{\r
+ markAsMisspelled(doc, wordStart, wordEnd);\r
+ }\r
+ }\r
+ // Mark the rest (if any) as correct.\r
+ if(wordEnd<end && wordEnd!=-1){\r
+ //System.out.println("End:"+wordEnd+","+end);\r
+ markAsCorrect(doc, wordEnd, end);\r
+ }\r
+ }\r
+ \r
+ private void markAsMisspelled(StyledDocument doc, int start, int end){\r
+ SimpleAttributeSet attr;\r
+ attr=new SimpleAttributeSet();\r
+ attr.addAttribute(wordMisspelled, wordMisspelledTrue);\r
+ doc.setCharacterAttributes(start, end-start, attr, false);\r
+ }\r
+ \r
+ private void markAsCorrect(StyledDocument doc, int start, int end){\r
+ SimpleAttributeSet attr;\r
+ attr=new SimpleAttributeSet(doc.getCharacterElement((start+end)/2).getAttributes());\r
+ attr.removeAttribute(wordMisspelled);\r
+ if(end>=start)\r
+ doc.setCharacterAttributes(start, end-start, attr, true);\r
+ }\r
+ \r
+ private void handleDocumentChange(DocumentEvent evt){\r
+ Element curElem,\r
+ parElem;\r
+ StyledDocument doc;\r
+ int start,\r
+ end;\r
+ \r
+ if(evt.getDocument() instanceof StyledDocument){\r
+ doc=(StyledDocument)evt.getDocument();\r
+ curElem=doc.getCharacterElement(evt.getOffset());\r
+ parElem=curElem.getParentElement();\r
+ if(parElem!=null){\r
+ start=parElem.getStartOffset();\r
+ end=parElem.getEndOffset();\r
+ }else{\r
+ start=curElem.getStartOffset();\r
+ end=curElem.getEndOffset();\r
+ }\r
+ //System.out.println("curElem: "+curElem.getStartOffset()+", "+curElem.getEndOffset());\r
+ //System.out.println("parElem: "+parElem.getStartOffset()+", "+parElem.getEndOffset());\r
+ //System.out.println("change: "+start+", "+end);\r
+ markupSpelling(doc,start, end);\r
+ } \r
+ }\r
+ \r
+ @SuppressWarnings("unchecked")\r
+ private void showSuggestionPopup(JEditorPane pane, Point p){\r
+ StyledDocument doc;\r
+ JMenuItem item;\r
+ AttributeSet attr;\r
+ int pos = pane.viewToModel(p);\r
+ DocumentWordTokenizer docTok;\r
+ String word;\r
+ java.util.List suggestions;\r
+ JPopupMenu popup;\r
+ ReplaceListener repList;\r
+ \r
+ if (pos >= 0) {\r
+ doc=(StyledDocument)pane.getDocument();\r
+ attr=doc.getCharacterElement(pos).getAttributes();\r
+ if(attr.containsAttribute(wordMisspelled, wordMisspelledTrue)){\r
+ docTok=new DocumentWordTokenizer(doc);\r
+ docTok.posStartFullWordFrom(pos);\r
+ word=docTok.nextWord();\r
+ suggestions=sCheck.getSuggestions(word, config.getInteger(Configuration.SPELL_THRESHOLD));\r
+ \r
+ popup=new JPopupMenu();\r
+ repList=new ReplaceListener(docTok);\r
+ for(int i=0;i<suggestions.size();i++) {\r
+ com.swabunga.spell.engine.Word w = (com.swabunga.spell.engine.Word) suggestions.get(i);\r
+ item = new JMenuItem(w.getWord());\r
+ item.setActionCommand(w.getWord());\r
+ item.addActionListener(repList);\r
+ popup.add(item);\r
+ }\r
+ popup.addSeparator();\r
+ item = new JMenuItem();\r
+ if(messages!=null)\r
+ item.setText(messages.getString("IGNOREALL"));\r
+ else\r
+ item.setText("Ignore All");\r
+ item.setActionCommand(word);\r
+ item.addActionListener(new IgnoreAllListener(doc));\r
+ popup.add(item);\r
+ item = new JMenuItem();\r
+ if(messages!=null)\r
+ item.setText(messages.getString("ADD"));\r
+ else\r
+ item.setText("Add word to wordlist");\r
+ item.setActionCommand(word);\r
+ item.addActionListener(new AddToDictListener(doc));\r
+ popup.add(item);\r
+ popup.show(pane, p.x, p.y); \r
+ }\r
+ }\r
+ }\r
+ \r
+ // DocumentListener implementation\r
+ // ------------------------------------------------------------------\r
+ public void changedUpdate(DocumentEvent evt){\r
+ }\r
+ \r
+ public void insertUpdate(DocumentEvent evt){\r
+ Runnable r=new SpellCheckChange(evt);\r
+ SwingUtilities.invokeLater(r);\r
+ }\r
+ \r
+ public void removeUpdate(DocumentEvent evt){\r
+ Runnable r=new SpellCheckChange(evt);\r
+ SwingUtilities.invokeLater(r);\r
+ }\r
+ \r
+ // MouseListener implementation\r
+ // ------------------------------------------------------------------\r
+ @Override\r
+ public void mouseReleased(MouseEvent evt){\r
+ JEditorPane pane;\r
+ if(!(evt.getComponent() instanceof JEditorPane))\r
+ return;\r
+ \r
+ if(evt.isPopupTrigger()){\r
+ pane=(JEditorPane)evt.getComponent();\r
+ if(pane.isEditable())\r
+ showSuggestionPopup(pane, new Point(evt.getX(), evt.getY()));\r
+ }\r
+ }\r
+ \r
+ // INNER CLASSES\r
+ // ------------------------------------------------------------------\r
+ private class SpellCheckChange implements Runnable{\r
+ \r
+ private final DocumentEvent evt;\r
+ \r
+ public SpellCheckChange(DocumentEvent evt){\r
+ this.evt=evt;\r
+ }\r
+ \r
+ public void run(){\r
+ handleDocumentChange(evt);\r
+ }\r
+ \r
+ }\r
+ \r
+ private class ReplaceListener implements ActionListener{\r
+ \r
+ DocumentWordTokenizer tok;\r
+ \r
+ public ReplaceListener(DocumentWordTokenizer tok){\r
+ this.tok=tok;\r
+ }\r
+ \r
+ public void actionPerformed(ActionEvent evt){\r
+ tok.replaceWord(evt.getActionCommand());\r
+ }\r
+ }\r
+ \r
+ private class AddToDictListener implements ActionListener{\r
+ \r
+ private final StyledDocument doc;\r
+ \r
+ public AddToDictListener(StyledDocument doc){\r
+ this.doc=doc;\r
+ }\r
+ \r
+ public void actionPerformed(ActionEvent evt){\r
+ sCheck.addToDictionary(evt.getActionCommand());\r
+ Runnable r=new MarkUpSpellingAll(doc);\r
+ SwingUtilities.invokeLater(r);\r
+ }\r
+ }\r
+ \r
+ private class IgnoreAllListener implements ActionListener{\r
+ \r
+ private final StyledDocument doc;\r
+ \r
+ public IgnoreAllListener(StyledDocument doc){\r
+ this.doc=doc;\r
+ }\r
+ \r
+ public void actionPerformed(ActionEvent evt){\r
+ sCheck.ignoreAll(evt.getActionCommand());\r
+ Runnable r=new MarkUpSpellingAll(doc);\r
+ SwingUtilities.invokeLater(r);\r
+ }\r
+ }\r
+ \r
+ private class MarkUpSpellingAll implements Runnable{\r
+ \r
+ private final StyledDocument doc;\r
+ \r
+ public MarkUpSpellingAll(StyledDocument doc){\r
+ this.doc=doc;\r
+ }\r
+ \r
+ public void run(){\r
+ markupSpelling(doc,0,doc.getLength());\r
+ }\r
+ }\r
+ \r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.spell.swing.autospell;\r
+\r
+/**\r
+ * Just some constants used by autospell.\r
+ * \r
+ * @author Robert Gustavsson (robert@lindesign.se)\r
+ */\r
+public interface AutoSpellConstants {\r
+\r
+ public static final String wordMisspelled="misspelled";\r
+ public static final Boolean wordMisspelledTrue=new Boolean(true);\r
+ \r
+}\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+/*\r
+ * Created on 2004-apr-23\r
+ *\r
+ * To change the template for this generated file go to\r
+ * Window - Preferences - Java - Code Generation - Code and Comments\r
+ */\r
+package com.swabunga.spell.swing.autospell;\r
+\r
+import java.awt.event.ActionEvent;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.OutputStream;\r
+import java.io.Reader;\r
+import java.io.Writer;\r
+\r
+import javax.swing.AbstractAction;\r
+import javax.swing.Action;\r
+import javax.swing.JEditorPane;\r
+import javax.swing.JTextPane;\r
+import javax.swing.text.BadLocationException;\r
+import javax.swing.text.Caret;\r
+import javax.swing.text.Document;\r
+import javax.swing.text.Element;\r
+import javax.swing.text.MutableAttributeSet;\r
+import javax.swing.text.SimpleAttributeSet;\r
+import javax.swing.text.StyledDocument;\r
+import javax.swing.text.StyledEditorKit;\r
+import javax.swing.text.ViewFactory;\r
+\r
+/**\r
+ * This editorkit just forwards all method calls to the original EditorKit\r
+ * for all method but getAction where it also adds a "MarkAsMisspelled" action \r
+ * and getViewFactory where we return our own ViewFactory (Based on the original).\r
+ * \r
+ * @author Robert Gustavsson (robert@lindesign.se)\r
+ *\r
+ */\r
+@SuppressWarnings("serial")\r
+public class AutoSpellEditorKit extends StyledEditorKit implements AutoSpellConstants{\r
+\r
+ private StyledEditorKit editorKit=null;\r
+ private JEditorPane pane=null;\r
+ \r
+ public AutoSpellEditorKit(StyledEditorKit editorKit){\r
+ this.editorKit=editorKit;\r
+ }\r
+ \r
+ public StyledEditorKit getStyledEditorKit(){\r
+ return editorKit;\r
+ }\r
+ \r
+ @Override\r
+ public Object clone(){\r
+ return new AutoSpellEditorKit(editorKit);\r
+ }\r
+ \r
+ @Override\r
+ public void deinstall(JEditorPane c){\r
+ editorKit.deinstall(c);\r
+ pane=null;\r
+ }\r
+ \r
+ @Override\r
+ public Element getCharacterAttributeRun(){\r
+ return editorKit.getCharacterAttributeRun();\r
+ }\r
+ \r
+ @Override\r
+ public MutableAttributeSet getInputAttributes(){\r
+ return editorKit.getInputAttributes();\r
+ }\r
+ \r
+ @Override\r
+ public void install(JEditorPane c){\r
+ editorKit.install(c);\r
+ pane=c;\r
+ }\r
+ \r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.EditorKit#getContentType()\r
+ */\r
+ @Override\r
+ public String getContentType() {\r
+ return editorKit.getContentType();\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.EditorKit#getActions()\r
+ */\r
+ @Override\r
+ public Action[] getActions() {\r
+ Action[] actions=new Action[editorKit.getActions().length+1];\r
+ \r
+ for(int i=0;i<editorKit.getActions().length;i++){\r
+ actions[i]=editorKit.getActions()[i];\r
+ }\r
+ actions[actions.length-1]=new SpellCheckAction();\r
+ return actions;\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.EditorKit#createCaret()\r
+ */\r
+ @Override\r
+ public Caret createCaret() {\r
+ return editorKit.createCaret();\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.EditorKit#createDefaultDocument()\r
+ */\r
+ @Override\r
+ public Document createDefaultDocument() {\r
+ return editorKit.createDefaultDocument();\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.EditorKit#getViewFactory()\r
+ */\r
+ @Override\r
+ public ViewFactory getViewFactory() {\r
+ return new AutoSpellViewFactory(editorKit.getViewFactory());\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.EditorKit#read(java.io.InputStream, javax.swing.text.Document, int)\r
+ */\r
+ @Override\r
+ public void read(InputStream in, Document doc, int pos)\r
+ throws IOException, BadLocationException {\r
+ \r
+ editorKit.read(in, doc, pos);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.EditorKit#write(java.io.OutputStream, javax.swing.text.Document, int, int)\r
+ */\r
+ @Override\r
+ public void write(OutputStream out, Document doc, int pos, int len)\r
+ throws IOException, BadLocationException {\r
+ \r
+ editorKit.write(out, doc, pos, len);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.EditorKit#read(java.io.Reader, javax.swing.text.Document, int)\r
+ */\r
+ @Override\r
+ public void read(Reader in, Document doc, int pos)\r
+ throws IOException, BadLocationException {\r
+ \r
+ editorKit.read(in, doc, pos);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.EditorKit#write(java.io.Writer, javax.swing.text.Document, int, int)\r
+ */\r
+ @Override\r
+ public void write(Writer out, Document doc, int pos, int len)\r
+ throws IOException, BadLocationException {\r
+ \r
+ editorKit.write(out, doc, pos, len);\r
+ }\r
+\r
+ // INNER CLASSES\r
+ // ------------------------------------------------------------------\r
+ private class SpellCheckAction extends AbstractAction{\r
+ \r
+ public SpellCheckAction(){\r
+ super("Mark as misspelled");\r
+ }\r
+ \r
+ public void actionPerformed(ActionEvent evt){\r
+ SimpleAttributeSet attr;\r
+ int pos=pane.getCaretPosition();\r
+ if(pos<0)\r
+ return;\r
+ attr=new SimpleAttributeSet(((StyledDocument)pane.getDocument()).getCharacterElement(pos).getAttributes());\r
+ attr.addAttribute(wordMisspelled, wordMisspelledTrue);\r
+ ((JTextPane)pane).setCharacterAttributes(attr,false);\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+/*\r
+ * Created on 2004-apr-23\r
+ *\r
+ * To change the template for this generated file go to\r
+ * Window - Preferences - Java - Code Generation - Code and Comments\r
+ */\r
+package com.swabunga.spell.swing.autospell;\r
+\r
+import java.awt.Color;\r
+import java.awt.Container;\r
+import java.awt.Graphics;\r
+import java.awt.Rectangle;\r
+import java.awt.Shape;\r
+\r
+import javax.swing.event.DocumentEvent;\r
+import javax.swing.text.AttributeSet;\r
+import javax.swing.text.BadLocationException;\r
+import javax.swing.text.Document;\r
+import javax.swing.text.Element;\r
+import javax.swing.text.View;\r
+import javax.swing.text.ViewFactory;\r
+import javax.swing.text.Position.Bias;\r
+\r
+/**\r
+ * This View just forward all calls to the original view but also paints\r
+ * the waved line if the Elements is marked as misspelled.\r
+ * \r
+ * @author Robert Gustavsson (robert@lindesign.se)\r
+ */\r
+public class AutoSpellView extends View implements AutoSpellConstants{\r
+\r
+ private View view=null;\r
+ private final int[] wavePoints=new int[10];\r
+ \r
+ public AutoSpellView(View view){\r
+ super(view.getElement());\r
+ this.view=view;\r
+ for(int i=0;i<wavePoints.length;i++){\r
+ wavePoints[i]=(int)Math.round(Math.cos(2*i*(2*Math.PI/wavePoints.length)));\r
+ }\r
+ }\r
+ \r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#append(javax.swing.text.View)\r
+ */\r
+ @Override\r
+ public void append(View arg0) {\r
+ view.append(arg0);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#breakView(int, int, float, float)\r
+ */\r
+ @Override\r
+ public View breakView(int arg0, int arg1, float arg2, float arg3) {\r
+ return view.breakView(arg0, arg1, arg2, arg3);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#changedUpdate(javax.swing.event.DocumentEvent, java.awt.Shape, javax.swing.text.ViewFactory)\r
+ */\r
+ @Override\r
+ public void changedUpdate(\r
+ DocumentEvent arg0,\r
+ Shape arg1,\r
+ ViewFactory arg2) {\r
+ view.changedUpdate(arg0, arg1, arg2);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#createFragment(int, int)\r
+ */\r
+ @Override\r
+ public View createFragment(int arg0, int arg1) {\r
+ return view.createFragment(arg0, arg1);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see java.lang.Object#equals(java.lang.Object)\r
+ */\r
+ @Override\r
+ public boolean equals(Object arg0) {\r
+ return view.equals(arg0);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#getAlignment(int)\r
+ */\r
+ @Override\r
+ public float getAlignment(int arg0) {\r
+ return view.getAlignment(arg0);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#getAttributes()\r
+ */\r
+ @Override\r
+ public AttributeSet getAttributes() {\r
+ return view.getAttributes();\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#getBreakWeight(int, float, float)\r
+ */\r
+ @Override\r
+ public int getBreakWeight(int arg0, float arg1, float arg2) {\r
+ return view.getBreakWeight(arg0, arg1, arg2);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#getChildAllocation(int, java.awt.Shape)\r
+ */\r
+ @Override\r
+ public Shape getChildAllocation(int arg0, Shape arg1) {\r
+ return view.getChildAllocation(arg0, arg1);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#getContainer()\r
+ */\r
+ @Override\r
+ public Container getContainer() {\r
+ return view.getContainer();\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#getDocument()\r
+ */\r
+ @Override\r
+ public Document getDocument() {\r
+ return view.getDocument();\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#getElement()\r
+ */\r
+ @Override\r
+ public Element getElement() {\r
+ return view.getElement();\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#getEndOffset()\r
+ */\r
+ @Override\r
+ public int getEndOffset() {\r
+ return view.getEndOffset();\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#getGraphics()\r
+ */\r
+ @Override\r
+ public Graphics getGraphics() {\r
+ return view.getGraphics();\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#getMaximumSpan(int)\r
+ */\r
+ @Override\r
+ public float getMaximumSpan(int arg0) {\r
+ return view.getMaximumSpan(arg0);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#getMinimumSpan(int)\r
+ */\r
+ @Override\r
+ public float getMinimumSpan(int arg0) {\r
+ return view.getMinimumSpan(arg0);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#getNextVisualPositionFrom(int, javax.swing.text.Position.Bias, java.awt.Shape, int, javax.swing.text.Position.Bias[])\r
+ */\r
+ @Override\r
+ public int getNextVisualPositionFrom(\r
+ int arg0,\r
+ Bias arg1,\r
+ Shape arg2,\r
+ int arg3,\r
+ Bias[] arg4)\r
+ throws BadLocationException {\r
+ return view.getNextVisualPositionFrom(arg0, arg1, arg2, arg3, arg4);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#getParent()\r
+ */\r
+ @Override\r
+ public View getParent() {\r
+ return view.getParent();\r
+ }\r
+\r
+ /**\r
+ * @param arg0\r
+ * @return\r
+ */\r
+ @Override\r
+ public float getPreferredSpan(int arg0) {\r
+ return view.getPreferredSpan(arg0);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#getResizeWeight(int)\r
+ */\r
+ @Override\r
+ public int getResizeWeight(int arg0) {\r
+ return view.getResizeWeight(arg0);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#getStartOffset()\r
+ */\r
+ @Override\r
+ public int getStartOffset() {\r
+ return view.getStartOffset();\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#getToolTipText(float, float, java.awt.Shape)\r
+ */\r
+ @Override\r
+ public String getToolTipText(float arg0, float arg1, Shape arg2) {\r
+ return view.getToolTipText(arg0, arg1, arg2);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#getView(int)\r
+ */\r
+ @Override\r
+ public View getView(int arg0) {\r
+ return view.getView(arg0);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#getViewCount()\r
+ */\r
+ @Override\r
+ public int getViewCount() {\r
+ return view.getViewCount();\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#getViewFactory()\r
+ */\r
+ @Override\r
+ public ViewFactory getViewFactory() {\r
+ return view.getViewFactory();\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#getViewIndex(float, float, java.awt.Shape)\r
+ */\r
+ @Override\r
+ public int getViewIndex(float arg0, float arg1, Shape arg2) {\r
+ return view.getViewIndex(arg0, arg1, arg2);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#getViewIndex(int, javax.swing.text.Position.Bias)\r
+ */\r
+ @Override\r
+ public int getViewIndex(int arg0, Bias arg1) {\r
+ return view.getViewIndex(arg0, arg1);\r
+ }\r
+\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#insert(int, javax.swing.text.View)\r
+ */\r
+ @Override\r
+ public void insert(int arg0, View arg1) {\r
+ view.insert(arg0, arg1);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#insertUpdate(javax.swing.event.DocumentEvent, java.awt.Shape, javax.swing.text.ViewFactory)\r
+ */\r
+ @Override\r
+ public void insertUpdate(DocumentEvent arg0, Shape arg1, ViewFactory arg2) {\r
+ view.insertUpdate(arg0, arg1, arg2);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#isVisible()\r
+ */\r
+ @Override\r
+ public boolean isVisible() {\r
+ return view.isVisible();\r
+ }\r
+\r
+ /*public Shape modelToView(int arg0, Shape arg1)\r
+ throws BadLocationException {\r
+ return view.modelToView(arg0, arg1);\r
+ }*/\r
+\r
+ /**\r
+ * @param arg0\r
+ * @param arg1\r
+ * @param arg2\r
+ * @return\r
+ * @throws javax.swing.text.BadLocationException\r
+ */\r
+ @Override\r
+ public Shape modelToView(int arg0, Shape arg1, Bias arg2)\r
+ throws BadLocationException {\r
+ return view.modelToView(arg0, arg1, arg2);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#modelToView(int, javax.swing.text.Position.Bias, int, javax.swing.text.Position.Bias, java.awt.Shape)\r
+ */\r
+ @Override\r
+ public Shape modelToView(int arg0, Bias arg1, int arg2, Bias arg3, Shape arg4)\r
+ throws BadLocationException {\r
+ return view.modelToView(arg0, arg1, arg2, arg3, arg4);\r
+ }\r
+\r
+ /**\r
+ * @param arg0\r
+ * @param arg1\r
+ */\r
+ @Override\r
+ public void paint(Graphics arg0, Shape arg1) {\r
+ Graphics g=arg0;\r
+ Rectangle r;\r
+ @SuppressWarnings("unused")\r
+ Color c;\r
+ view.paint(arg0, arg1);\r
+ if(getAttributes().containsAttribute(wordMisspelled, wordMisspelledTrue)){\r
+ r=arg1.getBounds();\r
+ c=g.getColor();\r
+ g.setColor(Color.red);\r
+ for(int x=r.x;x<r.x+r.width;x++){\r
+ g.drawLine(x,r.y+r.height-2-wavePoints[x%wavePoints.length],x,r.y+r.height-2-wavePoints[x%wavePoints.length]);\r
+ }\r
+ //g.setColor(c);\r
+ }\r
+ \r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#preferenceChanged(javax.swing.text.View, boolean, boolean)\r
+ */\r
+ @Override\r
+ public void preferenceChanged(View arg0, boolean arg1, boolean arg2) {\r
+ view.preferenceChanged(arg0, arg1, arg2);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#remove(int)\r
+ */\r
+ @Override\r
+ public void remove(int arg0) {\r
+ view.remove(arg0);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#removeAll()\r
+ */\r
+ @Override\r
+ public void removeAll() {\r
+ view.removeAll();\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#removeUpdate(javax.swing.event.DocumentEvent, java.awt.Shape, javax.swing.text.ViewFactory)\r
+ */\r
+ @Override\r
+ public void removeUpdate(\r
+ DocumentEvent arg0,\r
+ Shape arg1,\r
+ ViewFactory arg2) {\r
+ view.removeUpdate(arg0, arg1, arg2);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#replace(int, int, javax.swing.text.View[])\r
+ */\r
+ @Override\r
+ public void replace(int arg0, int arg1, View[] arg2) {\r
+ view.replace(arg0, arg1, arg2);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#setParent(javax.swing.text.View)\r
+ */\r
+ @Override\r
+ public void setParent(View arg0) {\r
+ view.setParent(arg0);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.View#setSize(float, float)\r
+ */\r
+ @Override\r
+ public void setSize(float arg0, float arg1) {\r
+ view.setSize(arg0, arg1);\r
+ }\r
+\r
+ /*public int viewToModel(float arg0, float arg1, Shape arg2) {\r
+ return view.viewToModel(arg0, arg1, arg2);\r
+ }*/\r
+\r
+ /**\r
+ * @param arg0\r
+ * @param arg1\r
+ * @param arg2\r
+ * @param arg3\r
+ * @return\r
+ */\r
+ @Override\r
+ public int viewToModel(float arg0, float arg1, Shape arg2, Bias[] arg3) {\r
+ return view.viewToModel(arg0, arg1, arg2, arg3);\r
+ }\r
+\r
+}\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+/*\r
+ * Created on 2004-apr-23\r
+ *\r
+ * To change the template for this generated file go to\r
+ * Window - Preferences - Java - Code Generation - Code and Comments\r
+ */\r
+package com.swabunga.spell.swing.autospell;\r
+\r
+import javax.swing.text.Element;\r
+import javax.swing.text.View;\r
+import javax.swing.text.ViewFactory;\r
+\r
+/**\r
+ * Gets the views from the original ViewFactory and but all of them in a\r
+ * AutoSpellView to support the waved line style. (Maybe this should only\r
+ * be done for elements actually marked as misspelled, maybe...)\r
+ * \r
+ * @author Robert Gustavsson (robert@lindesign.se)\r
+ */\r
+public class AutoSpellViewFactory implements ViewFactory{\r
+\r
+ private ViewFactory viewFactory=null;\r
+ \r
+ public AutoSpellViewFactory(ViewFactory wf){\r
+ viewFactory=wf;\r
+ }\r
+ \r
+ /* (non-Javadoc)\r
+ * @see javax.swing.text.ViewFactory#create(javax.swing.text.Element)\r
+ */\r
+ public View create(Element arg0) {\r
+ View view=viewFactory.create(arg0);\r
+ return new AutoSpellView(view);\r
+ }\r
+}\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.util;\r
+\r
+public class StringUtility {\r
+ public static StringBuffer replace(StringBuffer buf, int start, int end, String text) {\r
+ int len = text.length();\r
+ char[] ch = new char[buf.length() + len - (end - start)];\r
+ buf.getChars(0, start, ch, 0);\r
+ text.getChars(0, len, ch, start);\r
+ buf.getChars(end, buf.length(), ch, start + len);\r
+ buf.setLength(0);\r
+ buf.append(ch);\r
+ return buf;\r
+ }\r
+\r
+ public static void main(String[] args) {\r
+ System.out.println(StringUtility.replace(new StringBuffer(args[0]), Integer.parseInt(args[2]), Integer.parseInt(args[3]), args[1]));\r
+ }\r
+}\r
--- /dev/null
+/*\r
+Jazzy - a Java library for Spell Checking\r
+Copyright (C) 2001 Mindaugas Idzelis\r
+Full text of license can be found in LICENSE.txt\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+*/\r
+package com.swabunga.util;\r
+\r
+import java.util.Iterator;\r
+import java.util.List;\r
+\r
+public class VectorUtility {\r
+ @SuppressWarnings("unchecked")\r
+public static List addAll(List dest, List src) {\r
+ return addAll(dest, src, true);\r
+ }\r
+\r
+ @SuppressWarnings("unchecked")\r
+public static List addAll(List dest, List src, boolean allow_duplicates) {\r
+ for (Iterator e = src.iterator(); e.hasNext();) {\r
+ Object o = e.next();\r
+ if (allow_duplicates || !dest.contains(o))\r
+ dest.add(o);\r
+ }\r
+ return dest;\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote;\r
+\r
+\r
+//import java.io.ByteArrayOutputStream;\r
+import java.io.File;\r
+import java.io.PrintStream;\r
+import java.text.SimpleDateFormat;\r
+import java.util.ArrayList;\r
+import java.util.Calendar;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.concurrent.ArrayBlockingQueue;\r
+\r
+import com.evernote.edam.type.Accounting;\r
+import com.evernote.edam.type.PrivilegeLevel;\r
+import com.evernote.edam.type.User;\r
+import com.evernote.edam.type.UserAttributes;\r
+import com.trolltech.qt.core.QByteArray;\r
+import com.trolltech.qt.core.QMutex;\r
+import com.trolltech.qt.core.QSettings;\r
+import com.trolltech.qt.gui.QPalette;\r
+\r
+import cx.fbn.nevernote.gui.ContainsAttributeFilterTable;\r
+import cx.fbn.nevernote.gui.DateAttributeFilterTable;\r
+import cx.fbn.nevernote.gui.ShortcutKeys;\r
+import cx.fbn.nevernote.signals.DBRunnerSignal;\r
+import cx.fbn.nevernote.threads.DBRunner;\r
+import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+\r
+public class Global {\r
+ public static String version = "0.88";\r
+ public static String username = ""; \r
+ public static String password = ""; \r
+\r
+ public static DBRunner dbRunner; // Database thread\r
+ public static DBRunnerSignal dbRunnerSignal; // Signals to the database runner\r
+ public static QMutex dbrunnerWorkLock; // mutex lock for work queue\r
+ \r
+\r
+ public static int mainThreadId=0;\r
+ private static ArrayBlockingQueue<Boolean> mainThreadWaiter = new ArrayBlockingQueue<Boolean>(1);\r
+ \r
+ public static int syncThreadId=1;\r
+ private static ArrayBlockingQueue<Boolean> syncThreadWaiter = new ArrayBlockingQueue<Boolean>(1);\r
+ \r
+ public static int tagCounterThreadId=2;\r
+ private static ArrayBlockingQueue<Boolean> tagCounterThreadWaiter = new ArrayBlockingQueue<Boolean>(1);\r
+ \r
+ public static int trashCounterThreadId=3; // This should always be the highest thread ID\r
+ private static ArrayBlockingQueue<Boolean> trashCounterThreadWaiter = new ArrayBlockingQueue<Boolean>(1);\r
+\r
+ public static int indexThreadId=4; // Thread for indexing words\r
+ private static ArrayBlockingQueue<Boolean> indexThreadWaiter = new ArrayBlockingQueue<Boolean>(1);\r
+\r
+ public static int saveThreadId=5; // Thread used for processing data to saving content\r
+ private static ArrayBlockingQueue<Boolean> saveThreadWaiter = new ArrayBlockingQueue<Boolean>(1);\r
+\r
+ public static int notebookCounterThreadId=6; // Notebook Thread\r
+ private static ArrayBlockingQueue<Boolean> notebookCounterThreadWaiter = new ArrayBlockingQueue<Boolean>(1);\r
+\r
+ public static int indexThread03Id=7; // unused\r
+ private static ArrayBlockingQueue<Boolean> indexThread03ThreadWaiter = new ArrayBlockingQueue<Boolean>(1);\r
+\r
+ public static int indexThread04Id=8; // unused\r
+ private static ArrayBlockingQueue<Boolean> indexThread04ThreadWaiter = new ArrayBlockingQueue<Boolean>(1);\r
+ \r
+ public static int dbThreadId=9; // This should always be the highest thread ID\r
+ \r
+ \r
+ public static HashMap<String,String> passwordSafe = new HashMap<String, String>();\r
+ public static List<String> passwordRemember = new ArrayList<String>();\r
+ public static String currentNotebookGuid;\r
+ public static User user; \r
+ public static long authTimeRemaining;\r
+ public static long authRefreshTime;\r
+ public static long failedRefreshes = 0;\r
+ public static String currentDir;\r
+ public static boolean keepRunning;\r
+ \r
+ public static String userStoreUrl;\r
+ public static String noteStoreUrl;\r
+ public static String noteStoreUrlBase;\r
+ \r
+ public static int noteTableCreationPosition = 0;\r
+ public static int noteTableTitlePosition = 1;\r
+ public static int noteTableTagPosition = 2;\r
+ public static int noteTableNotebookPosition = 3;\r
+ public static int noteTableChangedPosition = 4;\r
+ public static int noteTableGuidPosition = 5;\r
+ public static int noteTableAuthorPosition = 6;\r
+ public static int noteTableSourceUrlPosition = 7;\r
+ public static int noteTableSubjectDatePosition = 8;\r
+ public static int noteTableSynchronizedPosition = 9;\r
+ public static int noteTableColumnCount = 10;\r
+ public static Integer cryptCounter = 0;\r
+ \r
+ public static int minimumWordCount = 2;\r
+ private static String wordRegex;\r
+ public static boolean enableCarriageReturnFix = false;\r
+ \r
+ public static String name = null;\r
+ public static QSettings settings;\r
+ public static boolean isConnected;\r
+ public static boolean showDeleted = false;\r
+ public static boolean disableUploads = false;\r
+ public static int messageLevel;\r
+ public static String tagDelimeter = ",";\r
+ public static String attachmentNameDelimeter = "------";\r
+ \r
+ public static String databaseName = new String("NeverNote");\r
+ public static String indexDatabaseName = new String("IndexDatabase.db");\r
+ public static DateAttributeFilterTable createdSinceFilter;\r
+ public static DateAttributeFilterTable createdBeforeFilter;\r
+ public static DateAttributeFilterTable changedSinceFilter;\r
+ public static DateAttributeFilterTable changedBeforeFilter;\r
+ public static ContainsAttributeFilterTable containsFilter;\r
+// public static DBLock dbLock;\r
+// public static DBLock indexLock;\r
+ public static ApplicationLogger logger;\r
+ PrintStream stdoutStream;\r
+ public static QPalette originalPalette;\r
+ public static ShortcutKeys shortcutKeys;\r
+ public static boolean disableViewing = false;\r
+ \r
+ public static List<String> invalidElements = new ArrayList<String>();\r
+ public static HashMap<String, ArrayList<String>> invalidAttributes = new HashMap<String, ArrayList<String>>();\r
+ public static boolean mimicEvernoteInterface;\r
+ public static HashMap<String,String> resourceMap;\r
+ public static String cipherPassword = "";\r
+ \r
+ static Calendar startTraceTime;\r
+ static Calendar intervalTraceTime;\r
+ \r
+ // Do initial setup \r
+ public static void setup() {\r
+ if (name == null)\r
+ name = "NeverNote";\r
+ settings = new QSettings("fbn.cx", name);\r
+ currentDir = getDirectoryPath();\r
+ getServer();\r
+ settings.beginGroup("General");\r
+ String regex = (String) settings.value("regex", "[,\\s]+");\r
+ setWordRegex(regex);\r
+ String wordString = settings.value("wordLength", "4").toString();\r
+ Integer wordLen = new Integer(wordString);\r
+ Global.minimumWordCount = wordLen;\r
+ settings.endGroup();\r
+ settings.beginGroup("Debug");\r
+ String msglevel = (String) settings.value("messageLevel", "Low");\r
+ settings.endGroup();\r
+ messageLevel = 1;\r
+ setMessageLevel(msglevel);\r
+ keepRunning = true;\r
+ disableUploads = disableUploads();\r
+ enableCarriageReturnFix = enableCarriageReturnFix();\r
+// dbLock = new DBLock();\r
+// indexLock = new DBLock();\r
+ logger = new ApplicationLogger("global.log");\r
+ shortcutKeys = new ShortcutKeys();\r
+ dbrunnerWorkLock = new QMutex();\r
+ mimicEvernoteInterface = getMimicEvernoteInterface();\r
+ resourceMap = new HashMap<String,String>();\r
+ \r
+ }\r
+ public static void setName(String n) {\r
+ if (!n.trim().equals("")) {\r
+ name = "NeverNote-"+n;\r
+ }\r
+ }\r
+ public static String getDirectoryPath() {\r
+ if (currentDir == null) {\r
+ currentDir = System.getProperty("user.dir");\r
+ }\r
+ if (!currentDir.substring(currentDir.length()-1).equals(File.separator)) {\r
+ currentDir = currentDir+File.separator;\r
+ }\r
+ return currentDir;\r
+ }\r
+ public static void setDirectoryPath(String path) {\r
+ if (path.trim().equals(""))\r
+ path = System.getProperty("user.dir");\r
+ if (!path.substring(path.length()-1).equals(File.separator)) \r
+ path = path+File.separator;\r
+ currentDir = path;\r
+ }\r
+ public static String getWordRegex() {\r
+ return wordRegex;\r
+ }\r
+ public static void setWordRegex(String r) {\r
+ wordRegex = r;\r
+ }\r
+ public static void setMessageLevel(String msglevel) {\r
+ if (msglevel.equalsIgnoreCase("low")) \r
+ messageLevel = 1;\r
+ if (msglevel.equalsIgnoreCase("medium")) \r
+ messageLevel = 2;\r
+ if (msglevel.equalsIgnoreCase("high")) \r
+ messageLevel = 3;\r
+ if (msglevel.equalsIgnoreCase("extreme")) \r
+ messageLevel = 4;\r
+ settings.beginGroup("Debug");\r
+ settings.setValue("messageLevel", msglevel);\r
+ settings.endGroup(); \r
+ }\r
+\r
+ public static void saveUserInformation(User user) {\r
+ settings.beginGroup("User");\r
+ settings.setValue("id", user.getId());\r
+ settings.setValue("username", user.getUsername());\r
+ settings.setValue("email", user.getEmail());\r
+ settings.setValue("name", user.getName());\r
+ settings.setValue("timezone", user.getTimezone());\r
+ settings.setValue("privilege", user.getPrivilege().getValue());\r
+ settings.setValue("created", user.getCreated());\r
+ settings.setValue("updated", user.getUpdated());\r
+ settings.setValue("deleted", user.getDeleted());\r
+ settings.endGroup();\r
+ isPremium();\r
+ if (user.getAttributes()!=null)\r
+ saveUserAttributes(user.getAttributes());\r
+ if (user.getAccounting()!=null)\r
+ saveUserAccounting(user.getAccounting());\r
+\r
+ }\r
+ public static void saveUserAttributes(UserAttributes attrib) {\r
+ settings.beginGroup("UserAttributes");\r
+ settings.setValue("defaultLocationName", attrib.getDefaultLocationName());\r
+ settings.setValue("defaultLatitude", attrib.getDefaultLocationName());\r
+ settings.setValue("defaultLongitude", attrib.getDefaultLocationName());\r
+ settings.setValue("incomingEmailAddress", attrib.getIncomingEmailAddress());\r
+ settings.endGroup();\r
+ }\r
+ public static UserAttributes getUserAttributes() {\r
+ settings.beginGroup("UserAttributes");\r
+ UserAttributes attrib = new UserAttributes();\r
+ attrib.setDefaultLocationName((String)settings.value("defaultLocationName",""));\r
+ attrib.setDefaultLatitudeIsSet(false);\r
+ attrib.setDefaultLongitudeIsSet(false);\r
+ attrib.setIncomingEmailAddress((String)settings.value("incomingEmailAddress", ""));\r
+ settings.endGroup();\r
+ return attrib;\r
+ }\r
+ public static void saveUserAccounting(Accounting acc) {\r
+ settings.beginGroup("UserAccounting");\r
+ settings.setValue("uploadLimit", acc.getUploadLimit());\r
+ settings.setValue("uploadLimitEnd", acc.getUploadLimitEnd());\r
+ settings.setValue("uploadLimitNextMonth", acc.getUploadLimitNextMonth());\r
+ settings.setValue("premiumServiceStart", acc.getPremiumServiceStart());\r
+ settings.setValue("nextPaymentDue", acc.getNextPaymentDue());\r
+ settings.setValue("uploadAmount", acc.getUpdated());\r
+ settings.endGroup();\r
+ }\r
+ public static long getUploadLimitEnd() {\r
+ Long limit;\r
+ settings.beginGroup("UserAccounting");\r
+ \r
+ // Upload limit\r
+ try {\r
+ String val = (String)settings.value("uploadLimitEnd", "0");\r
+ limit = new Long(val.trim());\r
+ } catch (Exception e) {\r
+ try {\r
+ limit = (Long)settings.value("uploadLimitEnd", 0);\r
+ } catch (Exception e1) {\r
+ limit = new Long(0);\r
+ }\r
+ }\r
+ \r
+ // return value\r
+ settings.endGroup();\r
+ return limit;\r
+ }\r
+ public static void saveUploadAmount(long amount) {\r
+ settings.beginGroup("UserAccounting");\r
+ settings.setValue("uploadAmount", amount);\r
+ settings.endGroup();\r
+ }\r
+ public static long getUploadAmount() {\r
+ long amt=0;\r
+ settings.beginGroup("UserAccounting");\r
+ try {\r
+ String num = (String)settings.value("uploadAmount", "0");\r
+ amt = new Long(num.trim());\r
+ } catch (Exception e) {\r
+ try {\r
+ amt = (Integer)settings.value("uploadAmount", 0);\r
+ } catch (Exception e1) {\r
+ amt = 0;\r
+ }\r
+ }\r
+ settings.endGroup();\r
+ return amt;\r
+ }\r
+ public static void saveEvernoteUpdateCount(long amount) {\r
+ settings.beginGroup("UserAccounting");\r
+ settings.setValue("updateCount", amount);\r
+ settings.endGroup();\r
+ }\r
+ public static long getEvernoteUpdateCount() {\r
+ long amt;\r
+ settings.beginGroup("UserAccounting");\r
+ try {\r
+ String num = (String)settings.value("updateCount", new Long(0).toString());\r
+ amt = new Long(num.trim());\r
+ } catch (java.lang.ClassCastException e) {\r
+ amt = 0;\r
+ }\r
+ settings.endGroup();\r
+ return amt;\r
+ }\r
+ public static boolean isPremium() {\r
+ int level;\r
+ settings.beginGroup("User");\r
+ try {\r
+ String num = (String)settings.value("privilege", "1");\r
+ level = new Integer(num.trim());\r
+ } catch (java.lang.ClassCastException e) {\r
+ try {\r
+ level = (Integer)settings.value("privilege", 1);\r
+ } catch (Exception e1) {\r
+ level = 1;\r
+ }\r
+ }\r
+ settings.endGroup();\r
+ PrivilegeLevel userLevel = PrivilegeLevel.findByValue(level);\r
+ if (userLevel == PrivilegeLevel.NORMAL)\r
+ return false;\r
+ return true;\r
+ \r
+ }\r
+ public static long getUploadLimit() {\r
+ settings.beginGroup("UserAccounting");\r
+ long limit;\r
+ try {\r
+ String num = (String)settings.value("uploadLimit", new Long(0).toString());\r
+ limit = new Long(num.trim());\r
+ } catch (java.lang.ClassCastException e) {\r
+ limit = 0;\r
+ }\r
+ settings.endGroup();\r
+ return limit;\r
+ }\r
+ public static boolean showTrayIcon() {\r
+ settings.beginGroup("General");\r
+ String max = (String) settings.value("showTrayIcon", "true");\r
+ settings.endGroup();\r
+ if (!max.equalsIgnoreCase("true"))\r
+ return false;\r
+ return true; \r
+ }\r
+ public static void setShowTrayIcon(boolean val) {\r
+ settings.beginGroup("General");\r
+ if (val)\r
+ settings.setValue("showTrayIcon", "true");\r
+ else\r
+ settings.setValue("showTrayIcon", "false");\r
+ settings.endGroup();\r
+ }\r
+ public static boolean wasWindowMaximized() {\r
+ settings.beginGroup("General");\r
+ String max = (String) settings.value("isMaximized", "true");\r
+ settings.endGroup();\r
+ if (!max.equalsIgnoreCase("true"))\r
+ return false;\r
+ return true; \r
+ }\r
+ public static void saveWindowMaximized(boolean isMax) {\r
+ settings.beginGroup("General");\r
+ if (isMax)\r
+ settings.setValue("isMaximized", "true");\r
+ else\r
+ settings.setValue("isMaximized", "false");\r
+ settings.endGroup();\r
+ }\r
+ public static String getLastViewedNoteGuid() {\r
+ settings.beginGroup("General");\r
+ String guid = (String) settings.value("lastViewedNote", "");\r
+ settings.endGroup();\r
+ return guid; \r
+ }\r
+ public static void saveCurrentNoteGuid(String guid) {\r
+ settings.beginGroup("General");\r
+ if (guid != null)\r
+ settings.setValue("lastViewedNote", guid);\r
+ else\r
+ settings.setValue("lastViewedNote", "");\r
+ settings.endGroup();\r
+ }\r
+ public static void setSortColumn(int i) {\r
+ settings.beginGroup("General");\r
+ settings.setValue("sortColumn", i);\r
+ settings.endGroup();\r
+ }\r
+ public static int getSortColumn() {;\r
+ settings.beginGroup("General");\r
+ int order; \r
+ try {\r
+ String val = settings.value("sortColumn", new Integer(0)).toString();\r
+ order = new Integer(val.trim());\r
+ } catch (Exception e) {\r
+ try {\r
+ order = (Integer)settings.value("sortColumn", 0);\r
+ } catch (Exception e1) {\r
+ order = 0;\r
+ }\r
+ }\r
+ \r
+ settings.endGroup();\r
+ return order;\r
+ }\r
+ public static void setSortOrder(int i) {\r
+ settings.beginGroup("General");\r
+ settings.setValue("sortOrder", i);\r
+ settings.endGroup();\r
+ }\r
+ public static int getSortOrder() {\r
+ settings.beginGroup("General");\r
+ int order; \r
+ try {\r
+ String val = settings.value("sortOrder", new Integer(0)).toString();\r
+ order = new Integer(val.trim());\r
+ } catch (Exception e) {\r
+ try {\r
+ order = (Integer)settings.value("sortOrder", 0);\r
+ } catch (Exception e1) {\r
+ order = 0;\r
+ }\r
+ }\r
+ \r
+ settings.endGroup();\r
+ return order;\r
+ }\r
+ public static boolean automaticLogin() {\r
+ settings.beginGroup("General");\r
+ String text = (String)settings.value("automaticLogin", "false");\r
+ settings.endGroup();\r
+ if (text.equalsIgnoreCase("true"))\r
+ return true;\r
+ else\r
+ return false; \r
+ }\r
+ public static void setAutomaticLogin(boolean val) {\r
+ settings.beginGroup("General");\r
+ if (val)\r
+ settings.setValue("automaticLogin", "true");\r
+ else\r
+ settings.setValue("automaticLogin", "false");\r
+ settings.endGroup();\r
+ }\r
+ public static boolean rememberPassword() {\r
+ settings.beginGroup("General");\r
+ String text = (String)settings.value("rememberPassword", "false");\r
+ settings.endGroup();\r
+ if (text.equalsIgnoreCase("true"))\r
+ return true;\r
+ else\r
+ return false; \r
+ }\r
+ public static void setRememberPassword(boolean val) {\r
+ settings.beginGroup("General");\r
+ if (val)\r
+ settings.setValue("rememberPassword", "true");\r
+ else\r
+ settings.setValue("rememberPassword", "false");\r
+ settings.endGroup();\r
+ }\r
+ public static void setServer(String server) {\r
+ settings.beginGroup("General");\r
+ settings.setValue("server", server);\r
+ settings.endGroup(); \r
+ }\r
+ public static String getServer() {\r
+ settings.beginGroup("General");\r
+ String text = (String)settings.value("server", "www.evernote.com");\r
+ if (text.equals("www.evernote.com")) {\r
+ userStoreUrl = "https://www.evernote.com/edam/user";\r
+ noteStoreUrlBase = "www.evernote.com/edam/note/"; \r
+ } else {\r
+ userStoreUrl = "https://sandbox.evernote.com/edam/user";\r
+ noteStoreUrlBase = "sandbox.evernote.com/edam/note/";\r
+ }\r
+ settings.endGroup();\r
+ if (isPremium())\r
+ noteStoreUrlBase = "https://" + noteStoreUrlBase;\r
+ else\r
+ noteStoreUrlBase = "http://" + noteStoreUrlBase;\r
+ return text;\r
+ }\r
+ public static boolean disableUploads() {\r
+ settings.beginGroup("General");\r
+ String text = (String)settings.value("disableUploads", "false");\r
+ settings.endGroup();\r
+ if (text.equalsIgnoreCase("true"))\r
+ return true;\r
+ else\r
+ return false;\r
+ }\r
+ public static void setDisableUploads(boolean val) {\r
+ settings.beginGroup("General");\r
+ if (val)\r
+ settings.setValue("disableUploads", "true");\r
+ else\r
+ settings.setValue("disableUploads", "false");\r
+ settings.endGroup();\r
+ disableUploads = val;\r
+ }\r
+ public static boolean pdfPreview() {\r
+ settings.beginGroup("General");\r
+ String text = (String)settings.value("pdfPreview", "true");\r
+ settings.endGroup();\r
+ if (text.equalsIgnoreCase("true"))\r
+ return true;\r
+ else\r
+ return false;\r
+ }\r
+ public static void setPdfPreview(boolean val) {\r
+ settings.beginGroup("General");\r
+ if (val)\r
+ settings.setValue("pdfPreview", "true");\r
+ else\r
+ settings.setValue("pdfPreview", "false");\r
+ settings.endGroup();\r
+ }\r
+ public static void setMinimumWordLength(int len) {\r
+ settings.beginGroup("General");\r
+ settings.setValue("minimumWordLength", len);\r
+ settings.endGroup(); \r
+ }\r
+ public static int getMinimumWordLength() {\r
+ settings.beginGroup("General");\r
+ Integer len = 4;\r
+ try {\r
+ String val = (String)settings.value("minimumWordLength", "4");\r
+ len = new Integer(val);\r
+ } catch (Exception e) {\r
+ try {\r
+ len = (Integer)settings.value("minimumWordLength", 4);\r
+ } catch (Exception e1) {\r
+ len = 4;\r
+ }\r
+ }\r
+ settings.endGroup();\r
+ return len;\r
+ \r
+ }\r
+ public static void setRecognitionWeight(int len) {\r
+ settings.beginGroup("General");\r
+ settings.setValue("recognitionWeight", len);\r
+ settings.endGroup(); \r
+ }\r
+ public static int getRecognitionWeight() {\r
+ settings.beginGroup("General");\r
+ Integer len;\r
+ try {\r
+ len = (Integer)settings.value("recognitionWeight", 80);\r
+ } catch (Exception e) {\r
+ len = 80;\r
+ }\r
+ settings.endGroup();\r
+ return len;\r
+ }\r
+ public static String getMessageLevel() {\r
+ settings.beginGroup("Debug");\r
+ String text = (String)settings.value("messageLevel", "Low");\r
+ settings.endGroup();\r
+ return text;\r
+ }\r
+ public static void setDateFormat(String format) {\r
+ settings.beginGroup("General");\r
+ settings.setValue("dateFormat", format);\r
+ settings.endGroup(); \r
+ }\r
+ public static String getDateFormat() {\r
+ settings.beginGroup("General");\r
+ String text = (String)settings.value("dateFormat", "MM/dd/yyyy");\r
+ settings.endGroup();\r
+ return text;\r
+ }\r
+ public static void setTimeFormat(String format) {\r
+ settings.beginGroup("General");\r
+ settings.setValue("timeFormat", format);\r
+ settings.endGroup(); \r
+ }\r
+ public static String getTimeFormat() {\r
+ settings.beginGroup("General");\r
+ String text = (String)settings.value("timeFormat", "HH:mm:ss");\r
+ settings.endGroup();\r
+ return text;\r
+ }\r
+ public static String getSyncInterval() {\r
+ settings.beginGroup("General");\r
+ String text = (String)settings.value("syncInterval", "15 minutes");\r
+ settings.endGroup();\r
+ return text; \r
+ }\r
+ public static void setSyncInterval(String format) {\r
+ settings.beginGroup("General");\r
+ settings.setValue("syncInterval", format);\r
+ settings.endGroup(); \r
+ }\r
+ public static void setColumnWidth(String col, int width) {\r
+ settings.beginGroup("ColumnWidths");\r
+ settings.setValue(col, width);\r
+ settings.endGroup();\r
+ }\r
+ public static int getColumnWidth(String col) {\r
+ settings.beginGroup("ColumnWidths");\r
+ Integer width;\r
+ try {\r
+ String val = (String)settings.value(col, "0");\r
+ width = new Integer(val.trim());\r
+ } catch (Exception e) {\r
+ try {\r
+ width = (Integer)settings.value(col, 0);\r
+ } catch (Exception e1) {\r
+ width = 0;\r
+ }\r
+ }\r
+ settings.endGroup();\r
+ return width;\r
+ }\r
+ public static void setColumnPosition(String col, int width) {\r
+ settings.beginGroup("ColumnPosition");\r
+ settings.setValue(col, width);\r
+ settings.endGroup();\r
+ }\r
+ public static int getColumnPosition(String col) {\r
+ settings.beginGroup("ColumnPosition");\r
+ Integer width;\r
+ try {\r
+ String val = (String)settings.value(col, "-1");\r
+ width = new Integer(val.trim());\r
+ } catch (Exception e) {\r
+ try {\r
+ width = (Integer)settings.value(col, 0);\r
+ } catch (Exception e1) {\r
+ width = 0;\r
+ }\r
+ }\r
+ settings.endGroup();\r
+ return width;\r
+ }\r
+ public static boolean verifyDelete() {\r
+ settings.beginGroup("General");\r
+ String text = (String)settings.value("verifyDelete", "true");\r
+ settings.endGroup();\r
+ if (text.equalsIgnoreCase("true"))\r
+ return true;\r
+ else\r
+ return false; \r
+ }\r
+ public static void setVerifyDelete(boolean val) {\r
+ settings.beginGroup("General");\r
+ if (val)\r
+ settings.setValue("verifyDelete", "true");\r
+ else\r
+ settings.setValue("verifyDelete", "false");\r
+ settings.endGroup();\r
+ }\r
+ public static boolean synchronizeDeletedContent() {\r
+ settings.beginGroup("General");\r
+ String text = (String)settings.value("syncDeletedContent", "false");\r
+ settings.endGroup();\r
+ if (text.equalsIgnoreCase("true"))\r
+ return true;\r
+ else\r
+ return false; \r
+ }\r
+ public static void setSynchronizeDeletedContent(boolean val) {\r
+ settings.beginGroup("General");\r
+ if (val)\r
+ settings.setValue("syncDeletedContent", "true");\r
+ else\r
+ settings.setValue("syncDeletedContent", "false");\r
+ settings.endGroup();\r
+ }\r
+ public static boolean isWindowVisible(String window) {\r
+ settings.beginGroup("WindowsVisible");\r
+ String text = (String)settings.value(window, "true");\r
+ settings.endGroup();\r
+ if (text.equalsIgnoreCase("true"))\r
+ return true;\r
+ else\r
+ return false; \r
+ }\r
+ public static void saveWindowVisible(String window, boolean val) {\r
+ settings.beginGroup("WindowsVisible");\r
+ if (val)\r
+ settings.setValue(window, "true");\r
+ else\r
+ settings.setValue(window, "false");\r
+ settings.endGroup();\r
+ }\r
+ public static boolean isColumnVisible(String window) {\r
+ settings.beginGroup("ColumnsVisible");\r
+ String text = (String)settings.value(window, "true");\r
+ settings.endGroup();\r
+ if (text.equalsIgnoreCase("true"))\r
+ return true;\r
+ else\r
+ return false; \r
+ }\r
+ public static void saveColumnVisible(String column, boolean val) {\r
+ settings.beginGroup("ColumnsVisible");\r
+ if (val)\r
+ settings.setValue(column, "true");\r
+ else\r
+ settings.setValue(column, "false");\r
+ settings.endGroup();\r
+ }\r
+ public static boolean isEditorButtonVisible(String window) {\r
+ settings.beginGroup("EditorButtonsVisible");\r
+ String text = (String)settings.value(window, "true");\r
+ settings.endGroup();\r
+ if (text.equalsIgnoreCase("true"))\r
+ return true;\r
+ else\r
+ return false; \r
+ }\r
+ public static void saveEditorButtonsVisible(String column, boolean val) {\r
+ settings.beginGroup("EditorButtonsVisible");\r
+ if (val)\r
+ settings.setValue(column, "true");\r
+ else\r
+ settings.setValue(column, "false");\r
+ settings.endGroup();\r
+ }\r
+ public static boolean enableCarriageReturnFix() {\r
+ settings.beginGroup("Debug");\r
+ String text = (String)settings.value("enableCarriageReturnFix", "false");\r
+ settings.endGroup();\r
+ if (text.equalsIgnoreCase("true"))\r
+ return true;\r
+ else\r
+ return false; \r
+ }\r
+ public static void saveCarriageReturnFix(boolean val) {\r
+ settings.beginGroup("Debug");\r
+ if (val)\r
+ settings.setValue("enableCarriageReturnFix", "true");\r
+ else\r
+ settings.setValue("enableCarriageReturnFix", "false");\r
+ settings.endGroup();\r
+ }\r
+ public static void setIndexThreads(int val) {\r
+ settings.beginGroup("General");\r
+ settings.setValue("indexThreads", val);\r
+ settings.endGroup();\r
+ }\r
+ public static int getIndexThreads() {\r
+ settings.beginGroup("General");\r
+ Integer threads;\r
+ try {\r
+ String val = (String)settings.value("indexThreads", "1");\r
+ threads = new Integer(val.trim());\r
+ } catch (Exception e) {\r
+ try {\r
+ threads = (Integer)settings.value("indexThreads", 1);\r
+ } catch (Exception e1) {\r
+ threads = 1;\r
+ }\r
+ }\r
+ settings.endGroup();\r
+ threads = 1;\r
+ return threads;\r
+ }\r
+ public static void setZoomFactor(double val) {\r
+ settings.beginGroup("General");\r
+ settings.setValue("zoomFactor", val);\r
+ settings.endGroup();\r
+ }\r
+ public static double getZoomFactor() {\r
+ settings.beginGroup("General");\r
+ Double threads;\r
+ try {\r
+ String val = (String)settings.value("zoomFactor", "1.0");\r
+ threads = new Double(val.trim());\r
+ } catch (Exception e) {\r
+ try {\r
+ threads = (Double)settings.value("zoomFactor", 1.0);\r
+ } catch (Exception e1) {\r
+ threads = new Double(1);\r
+ }\r
+ }\r
+ settings.endGroup();\r
+ return threads;\r
+ }\r
+ public static void setTextSizeMultiplier(double val) {\r
+ settings.beginGroup("General");\r
+ settings.setValue("textMultiplier", val);\r
+ settings.endGroup();\r
+ }\r
+ public static double getTextSizeMultiplier() {\r
+ settings.beginGroup("General");\r
+ Double threads;\r
+ try {\r
+ String val = (String)settings.value("textMultiplier", "1");\r
+ threads = new Double(val.trim());\r
+ } catch (Exception e) {\r
+ try {\r
+ threads = (Double)settings.value("textMultiplier", 1);\r
+ } catch (Exception e1) {\r
+ threads = new Double(1);\r
+ }\r
+ }\r
+ settings.endGroup();\r
+ return threads;\r
+ }\r
+\r
+ public static boolean getMimicEvernoteInterface() {\r
+ settings.beginGroup("General");\r
+ String text = (String)settings.value("mimicEvernoteInterface", "true");\r
+ settings.endGroup();\r
+ if (text.equalsIgnoreCase("true"))\r
+ return true;\r
+ else\r
+ return false;\r
+ }\r
+ public static void setMimicEvernoteInterface(boolean value) {\r
+ settings.beginGroup("General");\r
+ if (value)\r
+ settings.setValue("mimicEvernoteInterface", "true");\r
+ else\r
+ settings.setValue("mimicEvernoteInterface", "false"); \r
+ settings.endGroup();\r
+ }\r
+ \r
+ public static boolean synchronizeOnClose() {\r
+ settings.beginGroup("General");\r
+ String text = (String)settings.value("synchronizeOnClose", "false");\r
+ settings.endGroup();\r
+ if (text.equalsIgnoreCase("true"))\r
+ return true;\r
+ else\r
+ return false;\r
+ }\r
+ public static void setSynchronizeOnClose(boolean val) {\r
+ settings.beginGroup("General");\r
+ if (val)\r
+ settings.setValue("synchronizeOnClose", "true");\r
+ else\r
+ settings.setValue("synchronizeOnClose", "false");\r
+ settings.endGroup();\r
+ }\r
+ public static void setDatabaseVersion(String version) {\r
+ settings.beginGroup("General");\r
+ settings.setValue("databaseVersion", version);\r
+ settings.endGroup();\r
+ }\r
+ public static String getDatabaseVersion() {\r
+ settings.beginGroup("General");\r
+ String val = (String)settings.value("databaseVersion", "0.70");\r
+ settings.endGroup();\r
+ return val;\r
+ }\r
+ public static String getDatabaseUrl() {\r
+ settings.beginGroup("General");\r
+ String val = (String)settings.value("DatabaseURL", "");\r
+ settings.endGroup();\r
+ if (val.equals(""))\r
+ val = "jdbc:h2:"+Global.getDirectoryPath() +File.separator +"db" +File.separator +Global.databaseName;\r
+ return val;\r
+ }\r
+ public static String getDatabaseUserid() {\r
+ settings.beginGroup("General");\r
+ String val = (String)settings.value("databaseUserid", "");\r
+ settings.endGroup();\r
+ return val;\r
+ }\r
+ public static String getDatabaseUserPassword() {\r
+ settings.beginGroup("General");\r
+ String val = (String)settings.value("databaseUserPassword", "");\r
+ settings.endGroup();\r
+ return val;\r
+ }\r
+ public static void setStyle(String style) {\r
+ settings.beginGroup("General");\r
+ settings.setValue("style", style);\r
+ settings.endGroup();\r
+ }\r
+ public static String getStyle() {\r
+ settings.beginGroup("General");\r
+ String val = (String)settings.value("style", "");\r
+ settings.endGroup();\r
+ return val;\r
+ }\r
+ public static boolean useStandardPalette() {\r
+ settings.beginGroup("General");\r
+ String text = (String)settings.value("standardPalette", "true");\r
+ settings.endGroup();\r
+ if (text.equalsIgnoreCase("true"))\r
+ return true;\r
+ else\r
+ return false;\r
+ }\r
+ public static void setStandardPalette(boolean val) {\r
+ settings.beginGroup("General");\r
+ if (val)\r
+ settings.setValue("standardPalette", "true");\r
+ else\r
+ settings.setValue("standardPalette", "false");\r
+ settings.endGroup();\r
+ }\r
+ \r
+ public static void dbWait() {\r
+ // Global.dbThreadWait.wait(Global.dbThreadWaitMutex);\r
+ }\r
+ public static void dbContinue() {\r
+// Global.dbThreadWait.wakeAll();\r
+ }\r
+ public static synchronized void dbClientWait(int id) {\r
+ if (id == mainThreadId) {\r
+ try {mainThreadWaiter.take(); } catch (InterruptedException e) {e.printStackTrace();}\r
+ }\r
+ if (id == syncThreadId) {\r
+ try {syncThreadWaiter.take();} catch (InterruptedException e) {e.printStackTrace();}\r
+ }\r
+ if (id == tagCounterThreadId) {\r
+ try {tagCounterThreadWaiter.take();} catch (InterruptedException e) {e.printStackTrace();}\r
+ }\r
+ if (id == trashCounterThreadId) {\r
+ try {trashCounterThreadWaiter.take();} catch (InterruptedException e) {e.printStackTrace();}\r
+ }\r
+ if (id == indexThreadId) {\r
+ try {indexThreadWaiter.take();} catch (InterruptedException e) {e.printStackTrace();}\r
+ }\r
+ if (id == saveThreadId) {\r
+ try {saveThreadWaiter.take();} catch (InterruptedException e) {e.printStackTrace();}\r
+ }\r
+ if (id == notebookCounterThreadId) {\r
+ try {notebookCounterThreadWaiter.take();} catch (InterruptedException e) {e.printStackTrace();}\r
+ }\r
+ if (id == indexThread03Id) {\r
+ try {indexThread03ThreadWaiter.take();} catch (InterruptedException e) {e.printStackTrace();}\r
+ }\r
+ if (id == indexThread04Id) {\r
+ try {indexThread04ThreadWaiter.take();} catch (InterruptedException e) {e.printStackTrace();}\r
+ }\r
+ }\r
+ public static void dbClientContinue(int id) {\r
+ if (id == mainThreadId) {\r
+ try { mainThreadWaiter.put(true); } catch (InterruptedException e) { e.printStackTrace();}\r
+ }\r
+ if (id == syncThreadId) {\r
+ try { syncThreadWaiter.put(true); } catch (InterruptedException e) { e.printStackTrace();}\r
+ }\r
+ if (id == tagCounterThreadId) { \r
+ try { tagCounterThreadWaiter.put(true); } catch (InterruptedException e) { e.printStackTrace();}\r
+ }\r
+ if (id == trashCounterThreadId) { \r
+ try { trashCounterThreadWaiter.put(true); } catch (InterruptedException e) { e.printStackTrace();}\r
+ }\r
+ if (id == indexThreadId) { \r
+ try { indexThreadWaiter.put(true); } catch (InterruptedException e) { e.printStackTrace();}\r
+ }\r
+ if (id == saveThreadId) { \r
+ try { saveThreadWaiter.put(true); } catch (InterruptedException e) { e.printStackTrace();}\r
+ }\r
+ if (id == notebookCounterThreadId) { \r
+ try { notebookCounterThreadWaiter.put(true); } catch (InterruptedException e) { e.printStackTrace();}\r
+ }\r
+ if (id == indexThread03Id) { \r
+ try { indexThread03ThreadWaiter.put(true); } catch (InterruptedException e) { e.printStackTrace();}\r
+ }\r
+ if (id == indexThread04Id) { \r
+ try { indexThread04ThreadWaiter.put(true); } catch (InterruptedException e) { e.printStackTrace();}\r
+ }\r
+ }\r
+ \r
+ public static void saveState(String name, QByteArray state) {\r
+ settings.beginGroup("SaveState");\r
+ settings.setValue(name, state);\r
+ settings.endGroup();\r
+ }\r
+ \r
+ public static QByteArray restoreState(String name) {\r
+ settings.beginGroup("SaveState");\r
+ QByteArray state = (QByteArray)settings.value(name);\r
+ settings.endGroup();\r
+ return state;\r
+ }\r
+ public static void saveGeometry(String name, QByteArray state) {\r
+ settings.beginGroup("SaveGeometry");\r
+ settings.setValue(name, state);\r
+ settings.endGroup();\r
+ }\r
+ \r
+ public static QByteArray restoreGeometry(String name) {\r
+ settings.beginGroup("SaveGeometry");\r
+ QByteArray state = (QByteArray)settings.value(name);\r
+ settings.endGroup();\r
+ return state;\r
+ }\r
+ \r
+ public static void setAutoSaveInterval(int interval) {\r
+ settings.beginGroup("General");\r
+ settings.setValue("autoSaveInterval", interval);\r
+ settings.endGroup();\r
+ }\r
+ public static int getAutoSaveInterval() {\r
+ settings.beginGroup("General");\r
+ Integer value;\r
+ try {\r
+ String val = (String)settings.value("autoSaveInterval", "5");\r
+ value = new Integer(val.trim());\r
+ } catch (Exception e) {\r
+ try {\r
+ value = (Integer)settings.value("autoSaveInterval", 5);\r
+ } catch (Exception e1) {\r
+ value = 0;\r
+ }\r
+ }\r
+ settings.endGroup();\r
+ return value;\r
+ }\r
+ \r
+ // Add invalid attributes\r
+ public static void addInvalidAttribute(String element, String attribute) {\r
+ \r
+ List<String> attributes = invalidAttributes.get(element);\r
+ if (attributes != null) {\r
+ for (int i=0; i<attributes.size(); i++)\r
+ if (attribute.equalsIgnoreCase(attributes.get(i))) {\r
+ return;\r
+ }\r
+ }\r
+ \r
+ ArrayList<String> attributeList;\r
+ if (!invalidAttributes.containsKey(element)) {\r
+ attributeList = new ArrayList<String>();\r
+ attributeList.add(attribute);\r
+ invalidAttributes.put(element, attributeList);\r
+ }\r
+ else {\r
+ attributeList = invalidAttributes.get(element);\r
+ attributeList.add(attribute);\r
+ invalidAttributes.put(element,attributeList);\r
+ }\r
+ }\r
+\r
+ \r
+ // Add invalid attributes\r
+ public static void addInvalidElement(String element) {\r
+ for (int i=0; i<invalidElements.size(); i++) {\r
+ if (element.equalsIgnoreCase(invalidElements.get(i)))\r
+ return;\r
+ }\r
+ invalidElements.add(element);\r
+ }\r
+ \r
+ // Convert a byte array to a hex string\r
+ public static String byteArrayToHexString(byte data[]) {\r
+ StringBuffer buf = new StringBuffer();\r
+ for (byte element : data) {\r
+ int halfbyte = (element >>> 4) & 0x0F;\r
+ int two_halfs = 0;\r
+ do {\r
+ if ((0 <= halfbyte) && (halfbyte <= 9))\r
+ buf.append((char) ('0' + halfbyte));\r
+ else\r
+ buf.append((char) ('a' + (halfbyte - 10)));\r
+ halfbyte = element & 0x0F;\r
+ } while(two_halfs++ < 1);\r
+ }\r
+ return buf.toString(); \r
+ }\r
+\r
+ \r
+ // What to do with inactive tags?\r
+ public static String tagBehavior() {\r
+ settings.beginGroup("General");\r
+ String text = (String)settings.value("tagBehavior", "DoNothing");\r
+ settings.endGroup();\r
+ return text;\r
+ }\r
+ // What to do with inactive tags?\r
+ public static void setTagBehavior(String value) {\r
+ settings.beginGroup("General");\r
+ settings.setValue("tagBehavior", value);\r
+ settings.endGroup();\r
+ }\r
+\r
+ \r
+ // Print date/time. Used mainly for performance tracing\r
+ public static void trace(boolean resetInterval) {\r
+ String fmt = "MM/dd/yy HH:mm:ss.SSSSSS";\r
+ String dateTimeFormat = new String(fmt);\r
+ SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);\r
+ Calendar cal = Calendar.getInstance();\r
+ if (intervalTraceTime == null) \r
+ intervalTraceTime = Calendar.getInstance();\r
+ if (startTraceTime == null)\r
+ startTraceTime = Calendar.getInstance();\r
+ \r
+ float interval = (cal.getTimeInMillis() - intervalTraceTime.getTimeInMillis());\r
+ float total = (cal.getTimeInMillis() - startTraceTime.getTimeInMillis());\r
+ \r
+// if (interval > 00.0) {\r
+ StackTraceElement[] exceptions = Thread.currentThread().getStackTrace();\r
+ System.out.println("------------------------------------------");\r
+\r
+ System.out.println("Date/Time " +simple.format(cal.getTime()));\r
+ System.out.format("Interval Time: %-10.6f%n", interval);\r
+ System.out.format("Total Time: %-10.6f%n", total);\r
+ for (int i=2; i<5 && i<exceptions.length; i++) {\r
+ System.out.println(exceptions[i]);\r
+ }\r
+// }\r
+ if (resetInterval)\r
+ intervalTraceTime = cal;\r
+ }\r
+ public static void traceReset() {\r
+ intervalTraceTime = null;\r
+ startTraceTime = null;\r
+ }\r
+\r
+}\r
+\r
--- /dev/null
+/*
+ * This file is part of NeverNote
+ * 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.awt.Desktop;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.List;
+import java.util.SortedMap;
+import java.util.Vector;
+
+import org.apache.thrift.TException;
+
+import com.evernote.edam.error.EDAMNotFoundException;
+import com.evernote.edam.error.EDAMSystemException;
+import com.evernote.edam.error.EDAMUserException;
+import com.evernote.edam.notestore.NoteFilter;
+import com.evernote.edam.notestore.NoteVersionId;
+import com.evernote.edam.type.Data;
+import com.evernote.edam.type.Note;
+import com.evernote.edam.type.NoteAttributes;
+import com.evernote.edam.type.Notebook;
+import com.evernote.edam.type.QueryFormat;
+import com.evernote.edam.type.Resource;
+import com.evernote.edam.type.SavedSearch;
+import com.evernote.edam.type.Tag;
+import com.evernote.edam.type.User;
+import com.trolltech.qt.QThread;
+import com.trolltech.qt.core.QByteArray;
+import com.trolltech.qt.core.QDataStream;
+import com.trolltech.qt.core.QDateTime;
+import com.trolltech.qt.core.QDir;
+import com.trolltech.qt.core.QFile;
+import com.trolltech.qt.core.QFileInfo;
+import com.trolltech.qt.core.QFileSystemWatcher;
+import com.trolltech.qt.core.QIODevice;
+import com.trolltech.qt.core.QIODevice.OpenModeFlag;
+import com.trolltech.qt.core.QModelIndex;
+import com.trolltech.qt.core.QSize;
+import com.trolltech.qt.core.QTemporaryFile;
+import com.trolltech.qt.core.QTextCodec;
+import com.trolltech.qt.core.QThreadPool;
+import com.trolltech.qt.core.QTimer;
+import com.trolltech.qt.core.QUrl;
+import com.trolltech.qt.core.Qt;
+import com.trolltech.qt.core.Qt.SortOrder;
+import com.trolltech.qt.core.Qt.WidgetAttribute;
+import com.trolltech.qt.gui.QAbstractItemView;
+import com.trolltech.qt.gui.QAbstractItemView.ScrollHint;
+import com.trolltech.qt.gui.QAction;
+import com.trolltech.qt.gui.QApplication;
+import com.trolltech.qt.gui.QCloseEvent;
+import com.trolltech.qt.gui.QColor;
+import com.trolltech.qt.gui.QComboBox;
+import com.trolltech.qt.gui.QComboBox.InsertPolicy;
+import com.trolltech.qt.gui.QCursor;
+import com.trolltech.qt.gui.QDesktopServices;
+import com.trolltech.qt.gui.QDialog;
+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.QGridLayout;
+import com.trolltech.qt.gui.QHBoxLayout;
+import com.trolltech.qt.gui.QIcon;
+import com.trolltech.qt.gui.QImage;
+import com.trolltech.qt.gui.QLabel;
+import com.trolltech.qt.gui.QListWidget;
+import com.trolltech.qt.gui.QMainWindow;
+import com.trolltech.qt.gui.QMenu;
+import com.trolltech.qt.gui.QMessageBox;
+import com.trolltech.qt.gui.QMessageBox.StandardButton;
+import com.trolltech.qt.gui.QPixmap;
+import com.trolltech.qt.gui.QPrintDialog;
+import com.trolltech.qt.gui.QPrinter;
+import com.trolltech.qt.gui.QProgressBar;
+import com.trolltech.qt.gui.QSizePolicy;
+import com.trolltech.qt.gui.QSizePolicy.Policy;
+import com.trolltech.qt.gui.QSpinBox;
+import com.trolltech.qt.gui.QSplashScreen;
+import com.trolltech.qt.gui.QSplitter;
+import com.trolltech.qt.gui.QStatusBar;
+import com.trolltech.qt.gui.QSystemTrayIcon;
+import com.trolltech.qt.gui.QTableWidgetItem;
+import com.trolltech.qt.gui.QTextEdit;
+import com.trolltech.qt.gui.QToolBar;
+import com.trolltech.qt.gui.QTreeWidgetItem;
+import com.trolltech.qt.webkit.QWebPage.WebAction;
+import com.trolltech.qt.webkit.QWebSettings;
+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.dialog.AccountDialog;
+import cx.fbn.nevernote.dialog.ConfigDialog;
+import cx.fbn.nevernote.dialog.DatabaseLoginDialog;
+import cx.fbn.nevernote.dialog.DatabaseStatus;
+import cx.fbn.nevernote.dialog.FindDialog;
+import cx.fbn.nevernote.dialog.LoginDialog;
+import cx.fbn.nevernote.dialog.NotebookArchive;
+import cx.fbn.nevernote.dialog.NotebookEdit;
+import cx.fbn.nevernote.dialog.OnlineNoteHistory;
+import cx.fbn.nevernote.dialog.SavedSearchEdit;
+import cx.fbn.nevernote.dialog.TagEdit;
+import cx.fbn.nevernote.dialog.ThumbnailViewer;
+import cx.fbn.nevernote.dialog.WatchFolder;
+import cx.fbn.nevernote.filters.EnSearch;
+import cx.fbn.nevernote.gui.AttributeTreeWidget;
+import cx.fbn.nevernote.gui.BrowserWindow;
+import cx.fbn.nevernote.gui.DateAttributeFilterTable;
+import cx.fbn.nevernote.gui.MainMenuBar;
+import cx.fbn.nevernote.gui.NotebookTreeWidget;
+import cx.fbn.nevernote.gui.PDFPreview;
+import cx.fbn.nevernote.gui.SavedSearchTreeWidget;
+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.signals.DBRunnerSignal;
+import cx.fbn.nevernote.sql.DatabaseConnection;
+import cx.fbn.nevernote.sql.runners.WatchFolderRecord;
+import cx.fbn.nevernote.threads.DBRunner;
+import cx.fbn.nevernote.threads.IndexRunner;
+import cx.fbn.nevernote.threads.SyncRunner;
+import cx.fbn.nevernote.utilities.AESEncrypter;
+import cx.fbn.nevernote.utilities.ApplicationLogger;
+import cx.fbn.nevernote.utilities.FileImporter;
+import cx.fbn.nevernote.utilities.ListManager;
+import cx.fbn.nevernote.utilities.SyncTimes;
+import cx.fbn.nevernote.xml.ExportData;
+import cx.fbn.nevernote.xml.ImportData;
+import cx.fbn.nevernote.xml.XMLInsertHilight;
+
+
+public class NeverNote extends QMainWindow{
+
+ QStatusBar statusBar; // Application status bar
+
+ DatabaseConnection conn;
+
+ MainMenuBar menuBar; // Main menu bar
+ FindDialog find; // Text search in note dialog
+ List<String> emitLog; // Messages displayed in the status bar;
+ QSystemTrayIcon trayIcon; // little tray icon
+ QMenu trayMenu; // System tray menu
+ QAction trayExitAction; // Exit the application
+ QAction trayShowAction; // toggle the show/hide action
+ QAction trayAddNoteAction; // Add a note from the system tray
+
+ NotebookTreeWidget notebookTree; // List of notebooks
+ AttributeTreeWidget attributeTree; // List of note attributes
+ TagTreeWidget tagTree; // list of user created tags
+ SavedSearchTreeWidget savedSearchTree; // list of saved searches
+ TrashTreeWidget trashTree; // Trashcan
+ TableView noteTableView; // List of notes (the widget).
+
+ public BrowserWindow browserWindow; // Window containing browser & labels
+ QToolBar toolBar; // The tool bar under the menu
+// QLineEdit searchField; // The search filter bar on the toolbar
+ QComboBox searchField; // search filter bar on the toolbar;
+ boolean searchPerformed = false; // Search was done?
+ QProgressBar quotaBar; // The current quota usage
+
+ ApplicationLogger logger;
+ List<String> selectedNotebookGUIDs; // List of notebook GUIDs
+ List<String> selectedTagGUIDs; // List of selected tag GUIDs
+ List<String> selectedNoteGUIDs; // List of selected notes
+ String selectedSavedSearchGUID; // Currently selected saved searches
+
+ NoteFilter filter; // Note filter
+ String currentNoteGuid; // GUID of the current note
+ Note currentNote; // The currently viewed note
+ boolean noteDirty; // Has the note been changed?
+ boolean inkNote; // if this is an ink note, it is read only
+
+ QThread dbThread; // Thread to handle DB communication
+ ListManager listManager; // DB runnable task
+
+ List<QTemporaryFile> tempFiles; // Array of temporary files;
+
+ QTimer indexTimer; // timer to start the index thread
+ IndexRunner indexRunner; // thread to index notes
+ QThread indexThread;
+
+ QTimer syncTimer; // Sync on an interval
+ QTimer syncDelayTimer; // Sync delay to free up database
+ SyncRunner syncRunner; // thread to do a sync.
+ QThread syncThread;
+ QTimer saveTimer; // Timer to save note contents
+
+ QTimer authTimer; // Refresh authentication
+ QTimer externalFileSaveTimer; // Save files altered externally
+ List<String> externalFiles; // External files to save later
+ List<String> importFilesKeep; // Auto-import files to save later
+ List<String> importFilesDelete; // Auto-import files to save later
+
+ int indexTime; // how often to try and index
+ boolean indexRunning; // Is indexing running?
+ boolean indexDisabled; // Is indexing disabled?
+
+ int syncThreadsReady; // number of sync threads that are free
+ int syncTime; // Sync interval
+ boolean syncRunning; // Is sync running?
+ boolean automaticSync; // do sync automatically?
+ QTreeWidgetItem attributeTreeSelected;
+
+ QAction prevButton; // Go to the previous item viewed
+ QAction nextButton; // Go to the next item in the history
+ QAction downButton; // Go to the next item in the list
+ QAction upButton; // Go to the prev. item in the list;
+ QAction synchronizeButton; // Synchronize with Evernote
+ List<QIcon> synchronizeAnimation; // Synchronize movie
+ QTimer synchronizeAnimationTimer; // Timer to change animation button
+ int synchronizeFrame; // Current frame being viewed
+ QAction printButton; // Print Button
+ QAction tagButton; // Tag edit button
+ QAction attributeButton; // Attribute information button
+ QAction emailButton; // Email button
+ QAction deleteButton; // Delete button
+ QAction newButton; // new Note Button;
+ QSpinBox zoomSpinner; // Zoom zoom
+ QAction searchClearButton; // Clear the search field
+
+ QSplitter mainLeftRightSplitter; // main splitter for left/right side
+ QSplitter leftSplitter1; // first left hand splitter
+ QSplitter browserIndexSplitter; // splitter between note index & note text
+
+ QFileSystemWatcher importKeepWatcher; // Watch & keep auto-import
+ QFileSystemWatcher importDeleteWatcher; // Watch & Delete auto-import
+ List<String> importedFiles; // History of imported files (so we don't import twice)
+
+ OnlineNoteHistory historyWindow; // online history window
+ List<NoteVersionId> versions; // history versions
+
+ QTimer threadMonitorTimer; // Timer to watch threads.
+ int dbThreadDeadCount=0; // number of consecutive dead times for the db thread
+ int syncThreadDeadCount=0; // number of consecutive dead times for the sync thread
+ int indexThreadDeadCount=0; // number of consecutive dead times for the index thread
+ int notebookThreadDeadCount=0; // number of consecutive dead times for the notebook thread
+ int tagDeadCount=0; // number of consecutive dead times for the tag thread
+ int trashDeadCount=0; // number of consecutive dead times for the trash thread
+ int saveThreadDeadCount=0; // number of consecutive dead times for the save thread
+
+ HashMap<String, String> noteCache; // Cash of note content
+ List<String> historyGuids; // GUIDs of previously viewed items
+ int historyPosition; // Position within the viewed items
+ boolean fromHistory; // Is this from the history queue?
+ String trashNoteGuid; // Guid to restore / set into or out of trash to save position
+ Thumbnailer preview; // generate preview image
+ ThumbnailViewer thumbnailViewer; // View preview thumbnail;
+
+ String iconPath = new String("classpath:cx/fbn/nevernote/icons/");
+
+
+ //***************************************************************
+ //***************************************************************
+ //** Constructor & main entry point
+ //***************************************************************
+ //***************************************************************
+ // Application Constructor
+ public NeverNote() {
+
+ if (!lockApplication()) {
+ System.exit(0);
+ }
+ thread().setPriority(Thread.MAX_PRIORITY);
+
+ logger = new ApplicationLogger("nevernote.log");
+ logger.log(logger.HIGH, tr("Starting Application"));
+ conn = new DatabaseConnection(logger, Global.mainThreadId);
+ conn.dbSetup();
+
+ logger.log(logger.EXTREME, tr("Creating index connection"));
+ logger.log(logger.EXTREME, tr("Building DB thread"));
+ Global.dbRunnerSignal = new DBRunnerSignal();
+ if (Global.getDatabaseUrl().toUpperCase().indexOf("CIPHER=") > -1) {
+ boolean goodCheck = false;
+ while (!goodCheck) {
+ DatabaseLoginDialog dialog = new DatabaseLoginDialog();
+ dialog.exec();
+ if (!dialog.okPressed())
+ System.exit(0);
+ Global.cipherPassword = dialog.getPassword();
+ goodCheck = databaseCheck(Global.getDatabaseUrl(), Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
+ }
+ }
+ Global.dbRunner = new DBRunner(Global.getDatabaseUrl(), Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
+ logger.log(logger.EXTREME, tr("Starting DB thread"));
+ dbThread = new QThread(Global.dbRunner, "Database Thread");
+ dbThread.start();
+ logger.log(logger.EXTREME, tr("DB Thread has started"));
+ Global.dbRunnerSignal.start.emit();
+ logger.log(logger.EXTREME, tr("Setting main thread DB connection"));
+ logger.log(logger.EXTREME, tr("main DB thread setup complete."));
+ conn.checkDatabaseVersion();
+
+ // Start building the invalid XML tables
+ Global.invalidElements = conn.getInvalidXMLTable().getInvalidElements();
+ List<String> elements = conn.getInvalidXMLTable().getInvalidAttributeElements();
+
+ for (int i=0; i<elements.size(); i++) {
+ Global.invalidAttributes.put(elements.get(i), conn.getInvalidXMLTable().getInvalidAttributes(elements.get(i)));
+ }
+
+ logger.log(logger.EXTREME, tr("Starting GUI build"));
+ Global.originalPalette = QApplication.palette();
+ QApplication.setStyle(Global.getStyle());
+ if (Global.useStandardPalette())
+ QApplication.setPalette(QApplication.style().standardPalette());
+ setWindowTitle("NeverNote");
+
+ mainLeftRightSplitter = new QSplitter();
+ setCentralWidget(mainLeftRightSplitter);
+ leftSplitter1 = new QSplitter();
+ leftSplitter1.setOrientation(Qt.Orientation.Vertical);
+
+ browserIndexSplitter = new QSplitter();
+ browserIndexSplitter.setOrientation(Qt.Orientation.Vertical);
+
+ //* Setup threads & thread timers
+ int indexRunnerCount = Global.getIndexThreads();
+ indexRunnerCount = 1;
+ QThreadPool.globalInstance().setMaxThreadCount(indexRunnerCount+5); // increase max thread count
+
+ logger.log(logger.EXTREME, tr("Building list manager"));
+ listManager = new ListManager(conn, logger, Global.mainThreadId);
+
+ logger.log(logger.EXTREME, tr("Building index runners & timers"));
+ indexRunner = new IndexRunner("indexRunner.log");
+ indexThread = new QThread(indexRunner, "Index Thread");
+ indexThread.start();
+
+ synchronizeAnimationTimer = new QTimer();
+ synchronizeAnimationTimer.timeout.connect(this, "updateSyncButton()");
+
+ indexTimer = new QTimer();
+ indexTime = 1000*60*5; // look for unindexed every 5 minutes
+// indexTime = 1000*5;
+ indexTimer.start(indexTime); // Start indexing timer
+ indexTimer.timeout.connect(this, "indexTimer()");
+ indexDisabled = false;
+ indexRunning = false;
+
+ logger.log(logger.EXTREME, tr("Setting sync thread & timers"));
+ syncThreadsReady=1;
+ syncRunner = new SyncRunner("syncRunner.log");
+ syncTime = new SyncTimes().timeValue(Global.getSyncInterval());
+ syncTimer = new QTimer();
+ syncTimer.timeout.connect(this, "syncTimer()");
+ syncRunner.status.message.connect(this, "setMessage(String)");
+ syncRunner.syncSignal.finished.connect(this, "syncThreadComplete(Boolean)");
+ syncRunner.syncSignal.errorDisconnect.connect(this, "remoteErrorDisconnect()");
+ syncRunning = false;
+ if (syncTime > 0) {
+ automaticSync = true;
+ syncTimer.start(syncTime*60*1000);
+ } else {
+ automaticSync = false;
+ syncTimer.stop();
+ }
+ syncRunner.setEvernoteUpdateCount(Global.getEvernoteUpdateCount());
+ syncThread = new QThread(syncRunner, "Synchronization Thread");
+ syncThread.start();
+
+
+ logger.log(logger.EXTREME, tr("Starting authentication timer"));
+ authTimer = new QTimer();
+ authTimer.timeout.connect(this, "authTimer()");
+ authTimer.start(1000*60*15);
+ syncRunner.syncSignal.authRefreshComplete.connect(this, "authRefreshComplete(boolean)");
+
+ logger.log(logger.EXTREME, tr("Setting save note timer"));
+ saveTimer = new QTimer();
+ saveTimer.timeout.connect(this, "saveNote()");
+ if (Global.getAutoSaveInterval() > 0) {
+ saveTimer.setInterval(1000*60*Global.getAutoSaveInterval());
+// saveTimer.setInterval(1000*10); // auto save every 20 seconds;
+ saveTimer.start();
+ }
+
+// Global.trace();
+ logger.log(logger.EXTREME, tr("Starting external file monitor timer"));
+ externalFileSaveTimer = new QTimer();
+ externalFileSaveTimer.timeout.connect(this, "externalFileEditedSaver()");
+ externalFileSaveTimer.setInterval(1000*5); // save every 5 seconds;
+ externalFiles = new ArrayList<String>();
+ importFilesDelete = new ArrayList<String>();
+ importFilesKeep = new ArrayList<String>();
+ externalFileSaveTimer.start();
+
+ notebookTree = new NotebookTreeWidget();
+ attributeTree = new AttributeTreeWidget();
+ tagTree = new TagTreeWidget(conn);
+ savedSearchTree = new SavedSearchTreeWidget();
+ trashTree = new TrashTreeWidget();
+ noteTableView = new TableView(logger);
+
+ QGridLayout leftGrid = new QGridLayout();
+ leftSplitter1.setLayout(leftGrid);
+ leftGrid.addWidget(notebookTree, 1, 1);
+ leftGrid.addWidget(tagTree,2,1);
+ leftGrid.addWidget(attributeTree,3,1);
+ leftGrid.addWidget(savedSearchTree,4,1);
+ leftGrid.addWidget(trashTree, 5, 1);
+
+ // Setup the browser window
+ noteCache = new HashMap<String,String>();
+ browserWindow = new BrowserWindow(conn);
+
+ browserIndexSplitter.addWidget(noteTableView);
+ browserIndexSplitter.addWidget(browserWindow);
+
+ mainLeftRightSplitter.addWidget(leftSplitter1);
+ mainLeftRightSplitter.addWidget(browserIndexSplitter);
+
+ searchField = new QComboBox();
+ searchField.setEditable(true);
+ searchField.activatedIndex.connect(this, "searchFieldChanged()");
+ searchField.setDuplicatesEnabled(false);
+ searchField.editTextChanged.connect(this,"searchFieldTextChanged(String)");
+
+ quotaBar = new QProgressBar();
+
+ // Setup the thumbnail viewer
+ thumbnailViewer = new ThumbnailViewer();
+ thumbnailViewer.upArrow.connect(this, "upAction()");
+ thumbnailViewer.downArrow.connect(this, "downAction()");
+ thumbnailViewer.leftArrow.connect(this, "nextViewedAction()");
+ thumbnailViewer.rightArrow.connect(this, "previousViewedAction()");
+
+ listManager.loadNotesIndex();
+ initializeNotebookTree();
+ initializeTagTree();
+ initializeSavedSearchTree();
+ attributeTree.itemClicked.connect(this, "attributeTreeClicked(QTreeWidgetItem, Integer)");
+ attributeTreeSelected = null;
+ initializeNoteTable();
+
+ selectedNoteGUIDs = new ArrayList<String>();
+ statusBar = new QStatusBar();
+ setStatusBar(statusBar);
+ menuBar = new MainMenuBar(this);
+ emitLog = new ArrayList<String>();
+
+ tagTree.setDeleteAction(menuBar.tagDeleteAction);
+ tagTree.setEditAction(menuBar.tagEditAction);
+ tagTree.setAddAction(menuBar.tagAddAction);
+ tagTree.setVisible(Global.isWindowVisible("tagTree"));
+ tagTree.noteSignal.tagsAdded.connect(this, "tagsAdded(String, String)");
+ menuBar.hideTags.setChecked(Global.isWindowVisible("tagTree"));
+ listManager.tagSignal.listChanged.connect(this, "reloadTagTree()");
+
+ notebookTree.setDeleteAction(menuBar.notebookDeleteAction);
+ notebookTree.setEditAction(menuBar.notebookEditAction);
+ notebookTree.setAddAction(menuBar.notebookAddAction);
+ notebookTree.setVisible(Global.isWindowVisible("notebookTree"));
+ notebookTree.noteSignal.notebookChanged.connect(this, "updateNoteNotebook(String, String)");
+ menuBar.hideNotebooks.setChecked(Global.isWindowVisible("notebookTree"));
+
+ savedSearchTree.setAddAction(menuBar.savedSearchAddAction);
+ savedSearchTree.setEditAction(menuBar.savedSearchEditAction);
+ savedSearchTree.setDeleteAction(menuBar.savedSearchDeleteAction);
+ savedSearchTree.itemSelectionChanged.connect(this, "updateSavedSearchSelection()");
+ savedSearchTree.setVisible(Global.isWindowVisible("savedSearchTree"));
+ menuBar.hideSavedSearches.setChecked(Global.isWindowVisible("savedSearchTree"));
+
+ noteTableView.setAddAction(menuBar.noteAdd);
+ noteTableView.setDeleteAction(menuBar.noteDelete);
+ noteTableView.setRestoreAction(menuBar.noteRestoreAction);
+ noteTableView.setNoteDuplicateAction(menuBar.noteDuplicateAction);
+ noteTableView.setNoteHistoryAction(menuBar.noteOnlineHistoryAction);
+ noteTableView.noteSignal.titleColorChanged.connect(this, "titleColorChanged(Integer)");
+ noteTableView.setMergeNotesAction(menuBar.noteMergeAction);
+ noteTableView.rowChanged.connect(this, "scrollToGuid(String)");
+ noteTableView.resetViewport.connect(this, "scrollToCurrentGuid()");
+ noteTableView.doubleClicked.connect(this, "listDoubleClick()");
+ listManager.trashSignal.countChanged.connect(trashTree, "updateCounts(Integer)");
+ trashTree.load();
+ trashTree.itemSelectionChanged.connect(this, "trashTreeSelection()");
+ trashTree.setEmptyAction(menuBar.emptyTrashAction);
+ trashTree.setVisible(Global.isWindowVisible("trashTree"));
+ menuBar.hideTrash.setChecked(Global.isWindowVisible("trashTree"));
+ trashTree.updateCounts(listManager.getTrashCount());
+
+ attributeTree.setVisible(Global.isWindowVisible("attributeTree"));
+ menuBar.hideAttributes.setChecked(Global.isWindowVisible("attributeTree"));
+
+ noteTableView.setVisible(Global.isWindowVisible("noteList"));
+ menuBar.hideNoteList.setChecked(Global.isWindowVisible("noteList"));
+
+ if (!Global.isWindowVisible("editorButtonBar"))
+ toggleEditorButtonBar();
+ if (!Global.isWindowVisible("leftPanel"))
+ menuBar.hideLeftSide.setChecked(true);
+
+ setMenuBar(menuBar);
+ setupToolBar();
+ find = new FindDialog();
+ find.getOkButton().clicked.connect(this, "doFindText()");
+
+ // Setup the tray icon menu bar
+ trayShowAction = new QAction("Show/Hide", this);
+ trayExitAction = new QAction("Exit", this);
+ trayAddNoteAction = new QAction("Add Note", this);
+
+ trayExitAction.triggered.connect(this, "close()");
+ trayAddNoteAction.triggered.connect(this, "addNote()");
+ trayShowAction.triggered.connect(this, "trayToggleVisible()");
+
+ trayMenu = new QMenu(this);
+ trayMenu.addAction(trayAddNoteAction);
+ trayMenu.addAction(trayShowAction);
+ trayMenu.addAction(trayExitAction);
+
+
+ trayIcon = new QSystemTrayIcon(this);
+ trayIcon.setToolTip("NeverNote");
+ trayIcon.setContextMenu(trayMenu);
+ trayIcon.activated.connect(this, "trayActivated(com.trolltech.qt.gui.QSystemTrayIcon$ActivationReason)");
+
+ currentNoteGuid="";
+ currentNoteGuid = Global.getLastViewedNoteGuid();
+ historyGuids = new ArrayList<String>();
+ historyPosition = 0;
+ fromHistory = false;
+ noteDirty = false;
+ if (!currentNoteGuid.trim().equals("")) {
+ currentNote = conn.getNoteTable().getNote(currentNoteGuid, true,true,false,false,true);
+ }
+
+ noteIndexUpdated(true);
+ showColumns();
+ menuBar.showEditorBar.setChecked(Global.isWindowVisible("editorButtonBar"));
+ if (menuBar.showEditorBar.isChecked())
+ showEditorButtons();
+ tagIndexUpdated(true);
+ savedSearchIndexUpdated();
+ notebookIndexUpdated();
+ updateQuotaBar();
+ setupSyncSignalListeners();
+ setupBrowserSignalListeners();
+ setupIndexListeners();
+
+
+ tagTree.tagSignal.listChanged.connect(this, "tagIndexUpdated()");
+ tagTree.showAllTags(true);
+
+ QIcon appIcon = new QIcon(iconPath+"nevernote.png");
+ setWindowIcon(appIcon);
+ trayIcon.setIcon(appIcon);
+ if (Global.showTrayIcon())
+ trayIcon.show();
+ else
+ trayIcon.hide();
+
+ scrollToGuid(currentNoteGuid);
+ if (Global.automaticLogin()) {
+ remoteConnect();
+ if (Global.isConnected)
+ syncTimer();
+ }
+ setupFolderImports();
+
+ loadStyleSheet();
+ restoreWindowState();
+
+ if (Global.mimicEvernoteInterface) {
+ notebookTree.selectGuid("");
+ }
+
+ threadMonitorTimer = new QTimer();
+ threadMonitorTimer.timeout.connect(this, "threadMonitorCheck()");
+ threadMonitorTimer.start(1000*10); // Check for threads every 10 seconds;
+
+ historyGuids.add(currentNoteGuid);
+ historyPosition = 1;
+
+ int sortCol = Global.getSortColumn();
+ int sortOrder = Global.getSortOrder();
+ noteTableView.sortByColumn(sortCol, SortOrder.resolve(sortOrder));
+ }
+
+
+ // Main entry point
+ public static void main(String[] args) {
+ QApplication.initialize(args);
+ QPixmap pixmap = new QPixmap("classpath:cx/fbn/nevernote/icons/splash_logo.png");
+ QSplashScreen splash = new QSplashScreen(pixmap);
+
+ for (String arg : args) {
+ String lower = arg.toLowerCase();
+ if (lower.startsWith("--name="))
+ Global.setName(arg.substring(arg.indexOf('=')+1));
+ if (lower.startsWith("--home="))
+ Global.currentDir = arg.substring(arg.indexOf('=')+1);
+ if (lower.startsWith("--disable-viewing"))
+ Global.disableViewing = true;
+ }
+ Global.setup();
+ boolean showSplash = Global.isWindowVisible("SplashScreen");
+ if (showSplash)
+ splash.show();
+ NeverNote application = new NeverNote();
+ application.setAttribute(WidgetAttribute.WA_DeleteOnClose, true);
+ if (Global.wasWindowMaximized())
+ application.showMaximized();
+ else
+ application.show();
+ if (showSplash)
+ splash.finish(application);
+ QApplication.exec();
+ System.out.println("Goodbye.");
+ QApplication.exit();
+ }
+ // Exit point
+ @Override
+ public void closeEvent(QCloseEvent event) {
+ logger.log(logger.HIGH, "Entering NeverNote.closeEvent");
+ waitCursor(true);
+
+ if (currentNote!= null & browserWindow!=null) {
+ if (!currentNote.getTitle().equals(browserWindow.getTitle()))
+ conn.getNoteTable().updateNoteTitle(currentNote.getGuid(), browserWindow.getTitle());
+ }
+ saveNote();
+ setMessage("Beginning shutdown.");
+
+ externalFileEditedSaver();
+ if (Global.isConnected && Global.synchronizeOnClose()) {
+ setMessage("Performing synchronization before closing.");
+ syncRunner.addWork("SYNC");
+ }
+ setMessage("Closing Program.");
+ threadMonitorTimer.stop();
+
+ syncRunner.addWork("STOP");
+ indexRunner.addWork("STOP");
+ saveNote();
+ listManager.stop();
+ saveWindowState();
+
+ if (tempFiles != null)
+ tempFiles.clear();
+
+ browserWindow.noteSignal.tagsChanged.disconnect();
+ browserWindow.noteSignal.titleChanged.disconnect();
+ browserWindow.noteSignal.noteChanged.disconnect();
+ browserWindow.noteSignal.notebookChanged.disconnect();
+ browserWindow.noteSignal.createdDateChanged.disconnect();
+ browserWindow.noteSignal.alteredDateChanged.disconnect();
+ syncRunner.searchSignal.listChanged.disconnect();
+ syncRunner.tagSignal.listChanged.disconnect();
+ syncRunner.notebookSignal.listChanged.disconnect();
+ syncRunner.noteIndexSignal.listChanged.disconnect();
+
+
+ int position = noteTableView.header.visualIndex(Global.noteTableCreationPosition);
+ Global.setColumnPosition("noteTableCreationPosition", position);
+ position = noteTableView.header.visualIndex(Global.noteTableTagPosition);
+ Global.setColumnPosition("noteTableTagPosition", position);
+ position = noteTableView.header.visualIndex(Global.noteTableNotebookPosition);
+ Global.setColumnPosition("noteTableNotebookPosition", position);
+ position = noteTableView.header.visualIndex(Global.noteTableChangedPosition);
+ Global.setColumnPosition("noteTableChangedPosition", position);
+ position = noteTableView.header.visualIndex(Global.noteTableAuthorPosition);
+ Global.setColumnPosition("noteTableAuthorPosition", position);
+ position = noteTableView.header.visualIndex(Global.noteTableSourceUrlPosition);
+ Global.setColumnPosition("noteTableSourceUrlPosition", position);
+ position = noteTableView.header.visualIndex(Global.noteTableSubjectDatePosition);
+ Global.setColumnPosition("noteTableSubjectDatePosition", position);
+ position = noteTableView.header.visualIndex(Global.noteTableTitlePosition);
+ Global.setColumnPosition("noteTableTitlePosition", position);
+ position = noteTableView.header.visualIndex(Global.noteTableSynchronizedPosition);
+ Global.setColumnPosition("noteTableSynchronizedPosition", position);
+
+ saveNoteIndexWidth();
+
+ int width = notebookTree.columnWidth(0);
+ Global.setColumnWidth("notebookTreeName", width);
+ width = tagTree.columnWidth(0);
+ Global.setColumnWidth("tagTreeName", width);
+
+ Global.saveWindowMaximized(isMaximized());
+ Global.saveCurrentNoteGuid(currentNoteGuid);
+
+ int sortCol = noteTableView.proxyModel.sortColumn();
+ int sortOrder = noteTableView.proxyModel.sortOrder().value();
+ Global.setSortColumn(sortCol);
+ Global.setSortOrder(sortOrder);
+
+ hide();
+ trayIcon.hide();
+ Global.keepRunning = false;
+ try {
+ logger.log(logger.MEDIUM, "Waiting for indexThread to stop");
+ indexRunner.thread().join(50);
+ logger.log(logger.MEDIUM, "Index thread has stopped");
+ } catch (InterruptedException e1) {
+ e1.printStackTrace();
+ }
+ if (!syncRunner.isIdle()) {
+ try {
+ logger.log(logger.MEDIUM, "Waiting for syncThread to stop");
+ syncThread.join();
+ logger.log(logger.MEDIUM, "Sync thread has stopped");
+ } catch (InterruptedException e1) {
+ e1.printStackTrace();
+ }
+ }
+
+ logger.log(logger.EXTREME, "Shutting down database");
+ conn.dbShutdown();
+ logger.log(logger.EXTREME, "Waiting for DB thread to terminate");
+ try {
+ dbThread.join();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ logger.log(logger.EXTREME, "DB Thread has terminated");
+ unlockApplication();
+ logger.log(logger.HIGH, "Leaving NeverNote.closeEvent");
+ }
+
+ public void setMessage(String s) {
+ logger.log(logger.HIGH, "Entering NeverNote.setMessage");
+ logger.log(logger.HIGH, "Message: " +s);
+ statusBar.showMessage(s);
+ emitLog.add(s);
+ logger.log(logger.HIGH, "Leaving NeverNote.setMessage");
+ }
+
+ private void waitCursor(boolean wait) {
+ if (wait)
+ QApplication.setOverrideCursor(new QCursor(Qt.CursorShape.WaitCursor));
+ else
+ QApplication.restoreOverrideCursor();
+ }
+
+ private void setupIndexListeners() {
+ indexRunner.noteSignal.noteIndexed.connect(this, "indexThreadComplete(String)");
+ indexRunner.resourceSignal.resourceIndexed.connect(this, "indexThreadComplete(String)");
+// indexRunner.threadSignal.indexNeeded.connect(listManager, "setIndexNeeded(String, String, Boolean)");
+ }
+ private void setupSyncSignalListeners() {
+ syncRunner.tagSignal.listChanged.connect(this, "tagIndexUpdated()");
+ syncRunner.searchSignal.listChanged.connect(this, "savedSearchIndexUpdated()");
+ syncRunner.notebookSignal.listChanged.connect(this, "notebookIndexUpdated()");
+ syncRunner.noteIndexSignal.listChanged.connect(this, "noteIndexUpdated(boolean)");
+ syncRunner.noteSignal.quotaChanged.connect(this, "updateQuotaBar()");
+
+// syncRunner.syncSignal.setSequenceDate.connect(this,"setSequenceDate(long)");
+ syncRunner.syncSignal.saveUploadAmount.connect(this,"saveUploadAmount(long)");
+// syncRunner.syncSignal.setUpdateSequenceNumber.connect(this,"setUpdateSequenceNumber(int)");
+ syncRunner.syncSignal.saveUserInformation.connect(this,"saveUserInformation(User)");
+ syncRunner.syncSignal.saveEvernoteUpdateCount.connect(this,"saveEvernoteUpdateCount(int)");
+
+ syncRunner.noteSignal.guidChanged.connect(this, "noteGuidChanged(String, String)");
+ syncRunner.noteSignal.noteChanged.connect(this, "invalidateNoteCache(String, String)");
+ syncRunner.resourceSignal.resourceGuidChanged.connect(this, "noteResourceGuidChanged(String,String,String)");
+
+ syncRunner.syncSignal.refreshLists.connect(this, "refreshLists()");
+ }
+
+ private void setupBrowserSignalListeners() {
+
+ browserWindow.fileWatcher.fileChanged.connect(this, "externalFileEdited(String)");
+ browserWindow.noteSignal.tagsChanged.connect(this, "updateNoteTags(String, List)");
+ browserWindow.noteSignal.tagsChanged.connect(this, "updateListTags(String, List)");
+ browserWindow.noteSignal.noteChanged.connect(this, "invalidateNoteCache(String, String)");
+ browserWindow.noteSignal.noteChanged.connect(this, "setNoteDirty()");
+ browserWindow.noteSignal.titleChanged.connect(listManager, "updateNoteTitle(String, String)");
+ browserWindow.noteSignal.titleChanged.connect(this, "updateListTitle(String, String)");
+ browserWindow.noteSignal.notebookChanged.connect(this, "updateNoteNotebook(String, String)");
+ browserWindow.noteSignal.createdDateChanged.connect(listManager, "updateNoteCreatedDate(String, QDateTime)");
+ browserWindow.noteSignal.createdDateChanged.connect(this, "updateListDateCreated(String, QDateTime)");
+ browserWindow.noteSignal.alteredDateChanged.connect(listManager, "updateNoteAlteredDate(String, QDateTime)");
+ browserWindow.noteSignal.alteredDateChanged.connect(this, "updateListDateChanged(String, QDateTime)");
+ browserWindow.noteSignal.subjectDateChanged.connect(listManager, "updateNoteSubjectDate(String, QDateTime)");
+ browserWindow.noteSignal.subjectDateChanged.connect(this, "updateListDateSubject(String, QDateTime)");
+ browserWindow.noteSignal.authorChanged.connect(listManager, "updateNoteAuthor(String, String)");
+ browserWindow.noteSignal.authorChanged.connect(this, "updateListAuthor(String, String)");
+ browserWindow.noteSignal.sourceUrlChanged.connect(listManager, "updateNoteSourceUrl(String, String)");
+ browserWindow.noteSignal.sourceUrlChanged.connect(this, "updateListSourceUrl(String, String)");
+ browserWindow.focusLost.connect(this, "saveNote()");
+ browserWindow.resourceSignal.contentChanged.connect(this, "externalFileEdited(String)");
+// browserWindow.resourceSignal.externalFileEdit.connect(this, "saveResourceLater(String, String)");
+ }
+ private boolean lockApplication() {
+
+ String fileName = Global.currentDir +"db" +File.separator +"NeverNote.lock.db";
+// QFile.remove(fileName);
+ if (QFile.exists(fileName)) {
+ QMessageBox.question(this, "Lock File Detected",
+ "While starting I've found a database lock file.\n" +
+ "to prevent multiple instances from accessing the database \n"+
+ "at the same time. Please stop any other program, or (if you\n" +
+ "are sure nothing else is using the database) remove the file\n" +
+ fileName +".");
+ return false;
+
+ }
+ return true;
+/* String fileName = Global.currentDir +"nevernote.lock";
+
+
+ if (QFile.exists(fileName)) {
+ if (QMessageBox.question(this, "Confirmation",
+ "While starting I've found a lock file. This file is used to prevent multiple "+
+ "instances of this program running at once. If NeverNote has crashed this " +
+ "is just a file that wasn't cleaned up and you can safely, "+
+ "continue, but if there is another instance of this running you are " +
+ "running the risk of creating problems.\n\n" +
+ "Are you sure you want to continue?",
+ QMessageBox.StandardButton.Yes,
+ QMessageBox.StandardButton.No)==StandardButton.No.value()) {
+ return false;
+ }
+ }
+
+ QFile file = new QFile(fileName);
+ file.open(OpenModeFlag.WriteOnly);
+ file.write(new QByteArray("This file is used to prevent multiple instances " +
+ "of NeverNote running more than once. " +
+ "It should be deleted when NeverNote ends"));
+ file.close();
+ return true;
+*/
+ }
+ private void unlockApplication() {
+ String fileName = Global.currentDir +"nevernote.lock";
+ if (QFile.exists(fileName)) {
+ QFile.remove(fileName);
+ }
+ }
+
+
+ //***************************************************************
+ //***************************************************************
+ //* Settings and look & feel
+ //***************************************************************
+ //***************************************************************
+ @SuppressWarnings("unused")
+ private void settings() {
+ logger.log(logger.HIGH, "Entering NeverNote.settings");
+ ConfigDialog settings = new ConfigDialog(this);
+ String dateFormat = Global.getDateFormat();
+ String timeFormat = Global.getTimeFormat();
+
+ settings.exec();
+ if (Global.showTrayIcon())
+ trayIcon.show();
+ else
+ trayIcon.hide();
+ showColumns();
+ if (menuBar.showEditorBar.isChecked())
+ showEditorButtons();
+
+ // Reset the save timer
+ if (Global.getAutoSaveInterval() > 0)
+ saveTimer.setInterval(1000*60*Global.getAutoSaveInterval());
+ else
+ saveTimer.stop();
+
+ // This is a hack to force a reload of the index in case the date or time changed.
+// if (!dateFormat.equals(Global.getDateFormat()) ||
+// !timeFormat.equals(Global.getTimeFormat())) {
+ noteCache.clear();
+ noteIndexUpdated(true);
+// }
+
+ logger.log(logger.HIGH, "Leaving NeverNote.settings");
+ }
+ // Restore things to the way they were
+ private void restoreWindowState() {
+ // We need to name things or this doesn't work.
+ setObjectName("NeverNote");
+ mainLeftRightSplitter.setObjectName("mainLeftRightSplitter");
+ browserIndexSplitter.setObjectName("browserIndexSplitter");
+ leftSplitter1.setObjectName("leftSplitter1");
+
+ // Restore the actual positions.
+ restoreGeometry(Global.restoreGeometry(objectName()));
+ mainLeftRightSplitter.restoreState(Global.restoreState(mainLeftRightSplitter.objectName()));
+ browserIndexSplitter.restoreState(Global.restoreState(browserIndexSplitter.objectName()));
+ leftSplitter1.restoreState(Global.restoreState(leftSplitter1.objectName()));
+
+ }
+ // Save window positions for the next start
+ private void saveWindowState() {
+ Global.saveGeometry(objectName(), saveGeometry());
+ Global.saveState(mainLeftRightSplitter.objectName(), mainLeftRightSplitter.saveState());
+ Global.saveState(browserIndexSplitter.objectName(), browserIndexSplitter.saveState());
+ Global.saveState(leftSplitter1.objectName(), leftSplitter1.saveState());
+ }
+ // Load the style sheet
+ private void loadStyleSheet() {
+ String fileName = Global.currentDir +"qss"+System.getProperty("file.separator")+ "default.qss";
+ QFile file = new QFile(fileName);
+ file.open(OpenModeFlag.ReadOnly);
+ String styleSheet = file.readAll().toString();
+ file.close();
+ setStyleSheet(styleSheet);
+ }
+ // Save column widths for the next time
+ private void saveNoteIndexWidth() {
+ int width;
+ width = noteTableView.getColumnWidth(Global.noteTableCreationPosition);
+ Global.setColumnWidth("noteTableCreationPosition", width);
+ width = noteTableView.getColumnWidth(Global.noteTableChangedPosition);
+ Global.setColumnWidth("noteTableChangedPosition", width);
+ width = noteTableView.getColumnWidth(Global.noteTableGuidPosition);
+ Global.setColumnWidth("noteTableGuidPosition", width);
+ width = noteTableView.getColumnWidth(Global.noteTableNotebookPosition);
+ Global.setColumnWidth("noteTableNotebookPosition", width);
+ width = noteTableView.getColumnWidth(Global.noteTableTagPosition);
+ Global.setColumnWidth("noteTableTagPosition", width);
+ width = noteTableView.getColumnWidth(Global.noteTableTitlePosition);
+ Global.setColumnWidth("noteTableTitlePosition", width);
+ width = noteTableView.getColumnWidth(Global.noteTableSourceUrlPosition);
+ Global.setColumnWidth("noteTableSourceUrlPosition", width);
+ width = noteTableView.getColumnWidth(Global.noteTableAuthorPosition);
+ Global.setColumnWidth("noteTableAuthorPosition", width);
+ width = noteTableView.getColumnWidth(Global.noteTableSubjectDatePosition);
+ Global.setColumnWidth("noteTableSubjectDatePosition", width);
+ width = noteTableView.getColumnWidth(Global.noteTableSynchronizedPosition);
+ Global.setColumnWidth("noteTableSynchronizedPosition", width);
+ }
+
+
+ //***************************************************************
+ //***************************************************************
+ //** These functions deal with Notebook menu items
+ //***************************************************************
+ //***************************************************************
+ // Setup the tree containing the user's notebooks.
+ private void initializeNotebookTree() {
+ logger.log(logger.HIGH, "Entering NeverNote.initializeNotebookTree");
+ notebookTree.itemSelectionChanged.connect(this, "notebookTreeSelection()");
+ listManager.notebookSignal.refreshNotebookTreeCounts.connect(notebookTree, "updateCounts(List, List)");
+ // notebookTree.resize(Global.getSize("notebookTree"));
+ logger.log(logger.HIGH, "Leaving NeverNote.initializeNotebookTree");
+ }
+ // Listener when a notebook is selected
+ @SuppressWarnings("unused")
+ private void notebookTreeSelection() {
+ logger.log(logger.HIGH, "Entering NeverNote.notebookTreeSelection");
+
+ clearTrashFilter();
+ clearAttributeFilter();
+ clearSavedSearchFilter();
+ if (Global.mimicEvernoteInterface) {
+ clearTagFilter();
+ searchField.clear();
+ }
+
+ menuBar.noteRestoreAction.setVisible(false);
+ menuBar.notebookEditAction.setEnabled(true);
+ menuBar.notebookDeleteAction.setEnabled(true);
+ List<QTreeWidgetItem> selections = notebookTree.selectedItems();
+ QTreeWidgetItem currentSelection;
+ selectedNotebookGUIDs.clear();
+ if (!Global.mimicEvernoteInterface) {
+ for (int i=0; i<selections.size(); i++) {
+ currentSelection = selections.get(i);
+ selectedNotebookGUIDs.add(currentSelection.text(2));
+ }
+
+
+ // There is the potential for no notebooks to be selected if this
+ // happens then we make it look like all notebooks were selecetd.
+ // If that happens, just select the "all notebooks"
+ selections = notebookTree.selectedItems();
+ if (selections.size()==0) {
+ selectedNotebookGUIDs.clear();
+ menuBar.notebookEditAction.setEnabled(false);
+ menuBar.notebookDeleteAction.setEnabled(false);
+ }
+ } else {
+ String guid = "";
+ if (selections.size() > 0)
+ guid = (selections.get(0).text(2));
+ if (!guid.equals(""))
+ selectedNotebookGUIDs.add(guid);
+ }
+ listManager.setSelectedNotebooks(selectedNotebookGUIDs);
+ listManager.loadNotesIndex();
+ noteIndexUpdated(false);
+ logger.log(logger.HIGH, "Leaving NeverNote.notebookTreeSelection");
+
+ }
+ private void clearNotebookFilter() {
+ notebookTree.blockSignals(true);
+ notebookTree.clearSelection();
+ menuBar.noteRestoreAction.setVisible(false);
+ menuBar.notebookEditAction.setEnabled(false);
+ menuBar.notebookDeleteAction.setEnabled(false);
+ selectedNotebookGUIDs.clear();
+ listManager.setSelectedNotebooks(selectedNotebookGUIDs);
+ notebookTree.blockSignals(false);
+ }
+ // Triggered when the notebook DB has been updated
+ private void notebookIndexUpdated() {
+ logger.log(logger.HIGH, "Entering NeverNote.notebookIndexUpdated");
+ if (selectedNotebookGUIDs == null)
+ selectedNotebookGUIDs = new ArrayList<String>();
+ List<Notebook> books = conn.getNotebookTable().getAll();
+ for (int i=books.size()-1; i>=0; i--) {
+ for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
+ if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(books.get(i).getGuid())) {
+ books.remove(i);
+ j=listManager.getArchiveNotebookIndex().size();
+ }
+ }
+ }
+
+
+ listManager.countNotebookResults(listManager.getNoteIndex());
+ notebookTree.blockSignals(true);
+ notebookTree.load(books, listManager.getLocalNotebooks());
+ for (int i=selectedNotebookGUIDs.size()-1; i>=0; i--) {
+ boolean found = notebookTree.selectGuid(selectedNotebookGUIDs.get(i));
+ if (!found)
+ selectedNotebookGUIDs.remove(i);
+ }
+ notebookTree.blockSignals(false);
+
+ logger.log(logger.HIGH, "Leaving NeverNote.notebookIndexUpdated");
+ }
+ // Show/Hide note information
+ private void toggleNotebookWindow() {
+ logger.log(logger.HIGH, "Entering NeverNote.toggleNotebookWindow");
+ if (notebookTree.isVisible())
+ notebookTree.hide();
+ else
+ notebookTree.show();
+ menuBar.hideNotebooks.setChecked(notebookTree.isVisible());
+ Global.saveWindowVisible("notebookTree", notebookTree.isVisible());
+ logger.log(logger.HIGH, "Leaving NeverNote.toggleNotebookWindow");
+ }
+ // Add a new notebook
+ @SuppressWarnings("unused")
+ private void addNotebook() {
+ logger.log(logger.HIGH, "Inside NeverNote.addNotebook");
+ NotebookEdit edit = new NotebookEdit();
+ edit.setNotebooks(listManager.getNotebookIndex());
+ edit.exec();
+
+ if (!edit.okPressed())
+ return;
+
+ Calendar currentTime = new GregorianCalendar();
+ Long l = new Long(currentTime.getTimeInMillis());
+ String randint = new String(Long.toString(l));
+
+ Notebook newBook = new Notebook();
+ newBook.setUpdateSequenceNum(0);
+ newBook.setGuid(randint);
+ newBook.setName(edit.getNotebook());
+ newBook.setServiceCreated(new Date().getTime());
+ newBook.setServiceUpdated(new Date().getTime());
+ newBook.setDefaultNotebook(false);
+ newBook.setPublished(false);
+
+ listManager.getNotebookIndex().add(newBook);
+ if (edit.isLocal())
+ listManager.getLocalNotebooks().add(newBook.getGuid());
+ conn.getNotebookTable().addNotebook(newBook, true, edit.isLocal());
+ notebookIndexUpdated();
+ listManager.countNotebookResults(listManager.getNoteIndex());
+// notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
+ logger.log(logger.HIGH, "Leaving NeverNote.addNotebook");
+ }
+ // Edit an existing notebook
+ @SuppressWarnings("unused")
+ private void editNotebook() {
+ logger.log(logger.HIGH, "Entering NeverNote.editNotebook");
+ NotebookEdit edit = new NotebookEdit();
+ edit.setTitle("Edit Notebook");
+ edit.setLocalCheckboxEnabled(false);
+ List<QTreeWidgetItem> selections = notebookTree.selectedItems();
+ QTreeWidgetItem currentSelection;
+ currentSelection = selections.get(0);
+ edit.setNotebook(currentSelection.text(0));
+ edit.setNotebooks(listManager.getNotebookIndex());
+ edit.exec();
+
+ if (!edit.okPressed())
+ return;
+
+ String guid = currentSelection.text(2);
+ updateListNotebookName(currentSelection.text(0), edit.getNotebook());
+ currentSelection.setText(0, edit.getNotebook());
+
+ for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
+ if (listManager.getNotebookIndex().get(i).getGuid().equals(guid)) {
+ listManager.getNotebookIndex().get(i).setName(edit.getNotebook());
+ conn.getNotebookTable().updateNotebook(listManager.getNotebookIndex().get(i), true);
+ i=listManager.getNotebookIndex().size();
+ }
+ }
+
+ // Build a list of non-closed notebooks
+ List<Notebook> nbooks = new ArrayList<Notebook>();
+ for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
+ boolean found=false;
+ for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
+ if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid()))
+ found = true;
+ }
+ if (!found)
+ nbooks.add(listManager.getNotebookIndex().get(i));
+ }
+
+ browserWindow.setNotebookList(nbooks);
+ logger.log(logger.HIGH, "Leaving NeverNote.editNotebook");
+ }
+ // Delete an existing notebook
+ @SuppressWarnings("unused")
+ private void deleteNotebook() {
+ logger.log(logger.HIGH, "Entering NeverNote.deleteNotebook");
+ boolean assigned = false;
+ // Check if any notes have this notebook
+ List<QTreeWidgetItem> selections = notebookTree.selectedItems();
+ for (int i=0; i<selections.size(); i++) {
+ QTreeWidgetItem currentSelection;
+ currentSelection = selections.get(i);
+ String guid = currentSelection.text(2);
+ for (int j=0; j<listManager.getNoteIndex().size(); j++) {
+ String noteGuid = listManager.getNoteIndex().get(j).getNotebookGuid();
+ if (noteGuid.equals(guid)) {
+ assigned = true;
+ j=listManager.getNoteIndex().size();
+ i=selections.size();
+ }
+ }
+ }
+ if (assigned) {
+ QMessageBox.information(this, "Unable to Delete", "Some of the selected notebook(s) contain notes.\n"+
+ "Please delete the notes or move them to another notebook before deleting any notebooks.");
+ return;
+ }
+
+ if (conn.getNotebookTable().getAll().size() == 1) {
+ QMessageBox.information(this, "Unable to Delete", "You must have at least one notebook.");
+ return;
+ }
+
+ // If all notebooks are clear, verify the delete
+ if (QMessageBox.question(this, "Confirmation", "Delete the selected notebooks?",
+ QMessageBox.StandardButton.Yes,
+ QMessageBox.StandardButton.No)==StandardButton.No.value()) {
+ return;
+ }
+
+ // If confirmed, delete the notebook
+ for (int i=selections.size()-1; i>=0; i--) {
+ QTreeWidgetItem currentSelection;
+ currentSelection = selections.get(i);
+ String guid = currentSelection.text(2);
+ conn.getNotebookTable().expungeNotebook(guid, true);
+ listManager.deleteNotebook(guid);
+ }
+// for (int i=<dbRunner.getLocalNotebooks().size()-1; i>=0; i--) {
+ // if (dbRunner.getLocalNotebooks().get(i).equals(arg0))
+ // }
+ notebookTree.load(listManager.getNotebookIndex(), listManager.getLocalNotebooks());
+ listManager.countNotebookResults(listManager.getNoteIndex());
+// notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
+ logger.log(logger.HIGH, "Entering NeverNote.deleteNotebook");
+ }
+ // A note's notebook has been updated
+ @SuppressWarnings("unused")
+ private void updateNoteNotebook(String guid, String notebookGuid) {
+
+ // Update the list manager
+ listManager.updateNoteNotebook(guid, notebookGuid);
+ listManager.countNotebookResults(listManager.getNoteIndex());
+// notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
+
+ // Find the name of the notebook
+ String notebookName = null;
+ for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
+ if (listManager.getNotebookIndex().get(i).getGuid().equals(notebookGuid)) {
+ notebookName = listManager.getNotebookIndex().get(i).getName();
+ i=listManager.getNotebookIndex().size();
+ }
+ }
+
+ // If we found the name, update the browser window
+ if (notebookName != null) {
+ updateListNoteNotebook(guid, notebookName);
+ if (guid.equals(currentNoteGuid)) {
+ int pos = browserWindow.notebookBox.findText(notebookName);
+ if (pos >=0)
+ browserWindow.notebookBox.setCurrentIndex(pos);
+ }
+ }
+
+ // If we're dealing with the current note, then we need to be sure and update the notebook there
+ if (guid.equals(currentNoteGuid)) {
+ if (currentNote != null) {
+ currentNote.setNotebookGuid(notebookGuid);
+ }
+ }
+ }
+ // Open/close notebooks
+ @SuppressWarnings("unused")
+ private void closeNotebooks() {
+ NotebookArchive na = new NotebookArchive(listManager.getNotebookIndex(), listManager.getArchiveNotebookIndex());
+ na.exec();
+ if (!na.okClicked())
+ return;
+
+ waitCursor(true);
+ listManager.getArchiveNotebookIndex().clear();
+
+ for (int i=na.getClosedBookList().count()-1; i>=0; i--) {
+ String text = na.getClosedBookList().takeItem(i).text();
+ for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
+ if (listManager.getNotebookIndex().get(j).getName().equalsIgnoreCase(text)) {
+ Notebook n = listManager.getNotebookIndex().get(j);
+ conn.getNotebookTable().setArchived(n.getGuid(),true);
+ listManager.getArchiveNotebookIndex().add(n);
+ j=listManager.getNotebookIndex().size();
+ }
+ }
+ }
+
+ for (int i=na.getOpenBookList().count()-1; i>=0; i--) {
+ String text = na.getOpenBookList().takeItem(i).text();
+ for (int j=0; j<listManager.getNotebookIndex().size(); j++) {
+ if (listManager.getNotebookIndex().get(j).getName().equalsIgnoreCase(text)) {
+ Notebook n = listManager.getNotebookIndex().get(j);
+ conn.getNotebookTable().setArchived(n.getGuid(),false);
+ j=listManager.getNotebookIndex().size();
+ }
+ }
+ }
+
+ listManager.loadNotesIndex();
+ notebookIndexUpdated();
+ noteIndexUpdated(true);
+// noteIndexUpdated(false);
+
+ // Build a list of non-closed notebooks
+ List<Notebook> nbooks = new ArrayList<Notebook>();
+ for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
+ boolean found=false;
+ for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
+ if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid()))
+ found = true;
+ }
+ if (!found)
+ nbooks.add(listManager.getNotebookIndex().get(i));
+ }
+ waitCursor(false);
+ browserWindow.setNotebookList(nbooks);
+ }
+
+
+
+
+
+ //***************************************************************
+ //***************************************************************
+ //** These functions deal with Tag menu items
+ //***************************************************************
+ //***************************************************************
+ // Add a new notebook
+ @SuppressWarnings("unused")
+ private void addTag() {
+ logger.log(logger.HIGH, "Inside NeverNote.addTag");
+ TagEdit edit = new TagEdit();
+ edit.setTagList(listManager.getTagIndex());
+ edit.exec();
+
+ if (!edit.okPressed())
+ return;
+
+ Calendar currentTime = new GregorianCalendar();
+ Long l = new Long(currentTime.getTimeInMillis());
+ String randint = new String(Long.toString(l));
+
+ Tag newTag = new Tag();
+ newTag.setUpdateSequenceNum(0);
+ newTag.setGuid(randint);
+ newTag.setName(edit.getTag());
+ conn.getTagTable().addTag(newTag, true);
+ listManager.getTagIndex().add(newTag);
+ reloadTagTree();
+
+ logger.log(logger.HIGH, "Leaving NeverNote.addTag");
+ }
+ private void reloadTagTree() {
+ logger.log(logger.HIGH, "Entering NeverNote.reloadTagTree");
+ tagIndexUpdated(false);
+ boolean filter = false;
+ listManager.countTagResults(listManager.getNoteIndex());
+ if (notebookTree.selectedItems().size() > 0
+ && !notebookTree.selectedItems().get(0).text(0).equalsIgnoreCase("All Notebooks"))
+ filter = true;
+ if (tagTree.selectedItems().size() > 0)
+ filter = true;
+ tagTree.showAllTags(!filter);
+ logger.log(logger.HIGH, "Leaving NeverNote.reloadTagTree");
+ }
+ // Edit an existing tag
+ @SuppressWarnings("unused")
+ private void editTag() {
+ logger.log(logger.HIGH, "Entering NeverNote.editTag");
+ TagEdit edit = new TagEdit();
+ edit.setTitle("Edit Tag");
+ List<QTreeWidgetItem> selections = tagTree.selectedItems();
+ QTreeWidgetItem currentSelection;
+ currentSelection = selections.get(0);
+ edit.setTag(currentSelection.text(0));
+ edit.setTagList(listManager.getTagIndex());
+ edit.exec();
+
+ if (!edit.okPressed())
+ return;
+
+ String guid = currentSelection.text(2);
+ currentSelection.setText(0,edit.getTag());
+
+ for (int i=0; i<listManager.getTagIndex().size(); i++) {
+ if (listManager.getTagIndex().get(i).getGuid().equals(guid)) {
+ listManager.getTagIndex().get(i).setName(edit.getTag());
+ conn.getTagTable().updateTag(listManager.getTagIndex().get(i), true);
+ updateListTagName(guid);
+ if (currentNote != null && currentNote.getTagGuids().contains(guid))
+ browserWindow.setTag(getTagNamesForNote(currentNote));
+ logger.log(logger.HIGH, "Leaving NeverNote.editTag");
+ return;
+ }
+ }
+ browserWindow.setTag(getTagNamesForNote(currentNote));
+ logger.log(logger.HIGH, "Leaving NeverNote.editTag...");
+ }
+ // Delete an existing tag
+ @SuppressWarnings("unused")
+ private void deleteTag() {
+ logger.log(logger.HIGH, "Entering NeverNote.deleteTag");
+
+ if (QMessageBox.question(this, "Confirmation", "Delete the selected tags?",
+ QMessageBox.StandardButton.Yes,
+ QMessageBox.StandardButton.No)==StandardButton.No.value()) {
+ return;
+ }
+
+ List<QTreeWidgetItem> selections = tagTree.selectedItems();
+ for (int i=selections.size()-1; i>=0; i--) {
+ QTreeWidgetItem currentSelection;
+ currentSelection = selections.get(i);
+ removeTagItem(currentSelection.text(2));
+ }
+ tagIndexUpdated(true);
+ listManager.countTagResults(listManager.getNoteIndex());
+// tagTree.updateCounts(listManager.getTagCounter());
+ logger.log(logger.HIGH, "Leaving NeverNote.deleteTag");
+ }
+ // Remove a tag tree item. Go recursively down & remove the children too
+ private void removeTagItem(String guid) {
+ for (int j=listManager.getTagIndex().size()-1; j>=0; j--) {
+ String parent = listManager.getTagIndex().get(j).getParentGuid();
+ if (parent != null && parent.equals(guid)) {
+ //Remove this tag's children
+ removeTagItem(listManager.getTagIndex().get(j).getGuid());
+ }
+ }
+ //Now, remove this tag
+ removeListTagName(guid);
+ conn.getTagTable().expungeTag(guid, true);
+ for (int a=0; a<listManager.getTagIndex().size(); a++) {
+ if (listManager.getTagIndex().get(a).getGuid().equals(guid)) {
+ listManager.getTagIndex().remove(a);
+ return;
+ }
+ }
+ }
+ // Setup the tree containing the user's tags
+ private void initializeTagTree() {
+ logger.log(logger.HIGH, "Entering NeverNote.initializeTagTree");
+ tagTree.itemSelectionChanged.connect(this, "tagTreeSelection()");
+ listManager.tagSignal.refreshTagTreeCounts.connect(tagTree, "updateCounts(List)");
+ logger.log(logger.HIGH, "Leaving NeverNote.initializeTagTree");
+ }
+ // Listener when a tag is selected
+ @SuppressWarnings("unused")
+ private void tagTreeSelection() {
+ logger.log(logger.HIGH, "Entering NeverNote.tagTreeSelection");
+
+ List<QTreeWidgetItem> x = tagTree.selectedItems();
+ for (int i=0; i<x.size(); i++) {
+ }
+
+ clearTrashFilter();
+ clearAttributeFilter();
+ clearSavedSearchFilter();
+
+ menuBar.noteRestoreAction.setVisible(false);
+
+ List<QTreeWidgetItem> selections = tagTree.selectedItems();
+ QTreeWidgetItem currentSelection;
+ selectedTagGUIDs.clear();
+ for (int i=0; i<selections.size(); i++) {
+ currentSelection = selections.get(i);
+ selectedTagGUIDs.add(currentSelection.text(2));
+ }
+ if (selections.size() > 0) {
+ menuBar.tagEditAction.setEnabled(true);
+ menuBar.tagDeleteAction.setEnabled(true);
+ }
+ else {
+ menuBar.tagEditAction.setEnabled(false);
+ menuBar.tagDeleteAction.setEnabled(false);
+ }
+ listManager.setSelectedTags(selectedTagGUIDs);
+ listManager.loadNotesIndex();
+ noteIndexUpdated(false);
+ logger.log(logger.HIGH, "Leaving NeverNote.tagTreeSelection");
+ }
+ // trigger the tag index to be refreshed
+ @SuppressWarnings("unused")
+ private void tagIndexUpdated() {
+ tagIndexUpdated(true);
+ }
+ private void tagIndexUpdated(boolean reload) {
+ logger.log(logger.HIGH, "Entering NeverNote.tagIndexUpdated");
+ if (selectedTagGUIDs == null)
+ selectedTagGUIDs = new ArrayList<String>();
+// selectedTagGUIDs.clear(); // clear out old entries
+
+ tagTree.blockSignals(true);
+ if (reload)
+ tagTree.load(listManager.getTagIndex());
+ for (int i=selectedTagGUIDs.size()-1; i>=0; i--) {
+ boolean found = tagTree.selectGuid(selectedTagGUIDs.get(i));
+ if (!found)
+ selectedTagGUIDs.remove(i);
+ }
+ tagTree.blockSignals(false);
+
+ browserWindow.setTag(getTagNamesForNote(currentNote));
+ logger.log(logger.HIGH, "Leaving NeverNote.tagIndexUpdated");
+ }
+ // Show/Hide note information
+ private void toggleTagWindow() {
+ logger.log(logger.HIGH, "Entering NeverNote.toggleTagWindow");
+ if (tagTree.isVisible())
+ tagTree.hide();
+ else
+ tagTree.show();
+ menuBar.hideTags.setChecked(tagTree.isVisible());
+ Global.saveWindowVisible("tagTree", tagTree.isVisible());
+ logger.log(logger.HIGH, "Leaving NeverNote.toggleTagWindow");
+ }
+ // A note's tags have been updated
+ @SuppressWarnings("unused")
+ private void updateNoteTags(String guid, List<String> tags) {
+ listManager.saveNoteTags(guid, tags);
+ listManager.countTagResults(listManager.getNoteIndex());
+ StringBuffer names = new StringBuffer("");
+ for (int i=0; i<tags.size(); i++) {
+ names = names.append(tags.get(i));
+ if (i<tags.size()-1) {
+ names.append(Global.tagDelimeter + " ");
+ }
+ }
+ browserWindow.setTag(names.toString());
+ noteDirty = true;
+// tagTree.updateCounts(listManager.getTagCounter());
+ }
+ // Get a string containing all tag names for a note
+ private String getTagNamesForNote(Note n) {
+ logger.log(logger.HIGH, "Entering NeverNote.getTagNamesForNote");
+ if (n==null || n.getGuid() == null || n.getGuid().equals(""))
+ return "";
+ StringBuffer buffer = new StringBuffer(100);
+ Vector<String> v = new Vector<String>();
+ List<String> guids = n.getTagGuids();
+
+ if (guids == null)
+ return "";
+
+ for (int i=0; i<guids.size(); i++) {
+ v.add(listManager.getTagNameByGuid(guids.get(i)));
+ }
+ Comparator<String> comparator = Collections.reverseOrder();
+ Collections.sort(v,comparator);
+ Collections.reverse(v);
+
+ for (int i = 0; i<v.size(); i++) {
+ if (i>0)
+ buffer.append(", ");
+ buffer.append(v.get(i));
+ }
+
+ logger.log(logger.HIGH, "Leaving NeverNote.getTagNamesForNote");
+ return buffer.toString();
+ }
+ // Tags were added via dropping notes from the note list
+ @SuppressWarnings("unused")
+ private void tagsAdded(String noteGuid, String tagGuid) {
+ String tagName = null;
+ for (int i=0; i<listManager.getTagIndex().size(); i++) {
+ if (listManager.getTagIndex().get(i).getGuid().equals(tagGuid)) {
+ tagName = listManager.getTagIndex().get(i).getName();
+ i=listManager.getTagIndex().size();
+ }
+ }
+ if (tagName == null)
+ return;
+
+ for (int i=0; i<noteTableView.model.rowCount(); i++) {
+ QModelIndex modelIndex = noteTableView.model.index(i, Global.noteTableGuidPosition);
+ if (modelIndex != null) {
+ SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+ String titleGuid = (String)ix.values().toArray()[0];
+ if (titleGuid.equals(noteGuid)) {
+ String text = (String)noteTableView.model.data(i, Global.noteTableTagPosition);
+ if (!text.trim().equals(""))
+ text = text + Global.tagDelimeter + " " +tagName;
+ else
+ text = tagName;
+ noteTableView.model.setData(i, Global.noteTableTagPosition, text);
+ noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
+ if (noteGuid.equals(currentNoteGuid))
+ browserWindow.setTag(text);
+ i=noteTableView.model.rowCount();
+ }
+ }
+ }
+ }
+ private void clearTagFilter() {
+ tagTree.blockSignals(true);
+ tagTree.clearSelection();
+ menuBar.noteRestoreAction.setVisible(false);
+ menuBar.tagEditAction.setEnabled(false);
+ menuBar.tagDeleteAction.setEnabled(false);
+ selectedTagGUIDs.clear();
+ listManager.setSelectedTags(selectedTagGUIDs);
+ tagTree.blockSignals(false);
+ }
+
+
+ //***************************************************************
+ //***************************************************************
+ //** These functions deal with Saved Search menu items
+ //***************************************************************
+ //***************************************************************
+ // Add a new notebook
+ @SuppressWarnings("unused")
+ private void addSavedSearch() {
+ logger.log(logger.HIGH, "Inside NeverNote.addSavedSearch");
+ SavedSearchEdit edit = new SavedSearchEdit();
+ edit.setSearchList(listManager.getSavedSearchIndex());
+ edit.exec();
+
+ if (!edit.okPressed())
+ return;
+
+ Calendar currentTime = new GregorianCalendar();
+ Long l = new Long(currentTime.getTimeInMillis());
+ String randint = new String(Long.toString(l));
+
+ SavedSearch search = new SavedSearch();
+ search.setUpdateSequenceNum(0);
+ search.setGuid(randint);
+ search.setName(edit.getName());
+ search.setQuery(edit.getQuery());
+ search.setFormat(QueryFormat.USER);
+ listManager.getSavedSearchIndex().add(search);
+ conn.getSavedSearchTable().addSavedSearch(search, true);
+ savedSearchIndexUpdated();
+ logger.log(logger.HIGH, "Leaving NeverNote.addSavedSearch");
+ }
+ // Edit an existing tag
+ @SuppressWarnings("unused")
+ private void editSavedSearch() {
+ logger.log(logger.HIGH, "Entering NeverNote.editSavedSearch");
+ SavedSearchEdit edit = new SavedSearchEdit();
+ edit.setTitle("Edit Search");
+ List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
+ QTreeWidgetItem currentSelection;
+ currentSelection = selections.get(0);
+ String guid = currentSelection.text(1);
+ SavedSearch s = conn.getSavedSearchTable().getSavedSearch(guid);
+ edit.setName(currentSelection.text(0));
+ edit.setQuery(s.getQuery());
+ edit.setSearchList(listManager.getSavedSearchIndex());
+ edit.exec();
+
+ if (!edit.okPressed())
+ return;
+
+ List<SavedSearch> list = listManager.getSavedSearchIndex();
+ SavedSearch search = null;
+ boolean found = false;
+ for (int i=0; i<list.size(); i++) {
+ search = list.get(i);
+ if (search.getGuid().equals(guid)) {
+ i=list.size();
+ found = true;
+ }
+ }
+ if (!found)
+ return;
+ search.setName(edit.getName());
+ search.setQuery(edit.getQuery());
+ conn.getSavedSearchTable().updateSavedSearch(search, true);
+ savedSearchIndexUpdated();
+ logger.log(logger.HIGH, "Leaving NeverNote.editSavedSearch");
+ }
+ // Delete an existing tag
+ @SuppressWarnings("unused")
+ private void deleteSavedSearch() {
+ logger.log(logger.HIGH, "Entering NeverNote.deleteSavedSearch");
+
+ if (QMessageBox.question(this, "Confirmation", "Delete the selected search?",
+ QMessageBox.StandardButton.Yes,
+ QMessageBox.StandardButton.No)==StandardButton.No.value()) {
+ return;
+ }
+
+ List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
+ for (int i=selections.size()-1; i>=0; i--) {
+ QTreeWidgetItem currentSelection;
+ currentSelection = selections.get(i);
+ for (int j=0; j<listManager.getSavedSearchIndex().size(); j++) {
+ if (listManager.getSavedSearchIndex().get(j).getGuid().equals(currentSelection.text(1))) {
+ conn.getSavedSearchTable().expungeSavedSearch(listManager.getSavedSearchIndex().get(j).getGuid(), true);
+ listManager.getSavedSearchIndex().remove(j);
+ j=listManager.getSavedSearchIndex().size()+1;
+ }
+ }
+ selections.remove(i);
+ }
+ savedSearchIndexUpdated();
+ logger.log(logger.HIGH, "Leaving NeverNote.deleteSavedSearch");
+ }
+ // Setup the tree containing the user's tags
+ private void initializeSavedSearchTree() {
+ logger.log(logger.HIGH, "Entering NeverNote.initializeSavedSearchTree");
+ savedSearchTree.itemSelectionChanged.connect(this, "savedSearchTreeSelection()");
+ logger.log(logger.HIGH, "Leaving NeverNote.initializeSavedSearchTree");
+ }
+ // Listener when a tag is selected
+ @SuppressWarnings("unused")
+ private void savedSearchTreeSelection() {
+ logger.log(logger.HIGH, "Entering NeverNote.savedSearchTreeSelection");
+
+ clearNotebookFilter();
+ clearTagFilter();
+ clearTrashFilter();
+ clearAttributeFilter();
+
+ String currentGuid = selectedSavedSearchGUID;
+ menuBar.savedSearchEditAction.setEnabled(true);
+ menuBar.savedSearchDeleteAction.setEnabled(true);
+ List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
+ QTreeWidgetItem currentSelection;
+ selectedSavedSearchGUID = "";
+ for (int i=0; i<selections.size(); i++) {
+ currentSelection = selections.get(i);
+ if (currentSelection.text(1).equals(currentGuid)) {
+ currentSelection.setSelected(false);
+ } else {
+ selectedSavedSearchGUID = currentSelection.text(1);
+ }
+// i = selections.size() +1;
+ }
+
+ // There is the potential for no notebooks to be selected if this
+ // happens then we make it look like all notebooks were selecetd.
+ // If that happens, just select the "all notebooks"
+ if (selections.size()==0) {
+ clearSavedSearchFilter();
+ }
+ listManager.setSelectedSavedSearch(selectedSavedSearchGUID);
+
+ logger.log(logger.HIGH, "Leaving NeverNote.savedSearchTreeSelection");
+ }
+ private void clearSavedSearchFilter() {
+ menuBar.savedSearchEditAction.setEnabled(false);
+ menuBar.savedSearchDeleteAction.setEnabled(false);
+ savedSearchTree.blockSignals(true);
+ savedSearchTree.clearSelection();
+ savedSearchTree.blockSignals(false);
+ selectedSavedSearchGUID = "";
+ searchField.setEditText("");
+ searchPerformed = false;
+ listManager.setSelectedSavedSearch(selectedSavedSearchGUID);
+ }
+ // trigger the tag index to be refreshed
+ private void savedSearchIndexUpdated() {
+ if (selectedSavedSearchGUID == null)
+ selectedSavedSearchGUID = new String();
+ savedSearchTree.blockSignals(true);
+ savedSearchTree.load(listManager.getSavedSearchIndex());
+ savedSearchTree.selectGuid(selectedSavedSearchGUID);
+ savedSearchTree.blockSignals(false);
+ }
+ // trigger when the saved search selection changes
+ @SuppressWarnings("unused")
+ private void updateSavedSearchSelection() {
+ logger.log(logger.HIGH, "Entering NeverNote.updateSavedSearchSelection()");
+
+ menuBar.savedSearchEditAction.setEnabled(true);
+ menuBar.savedSearchDeleteAction.setEnabled(true);
+ List<QTreeWidgetItem> selections = savedSearchTree.selectedItems();
+
+ if (selections.size() > 0) {
+ menuBar.savedSearchEditAction.setEnabled(true);
+ menuBar.savedSearchDeleteAction.setEnabled(true);
+ selectedSavedSearchGUID = selections.get(0).text(1);
+ SavedSearch s = conn.getSavedSearchTable().getSavedSearch(selectedSavedSearchGUID);
+ searchField.setEditText(s.getQuery());
+ } else {
+ menuBar.savedSearchEditAction.setEnabled(false);
+ menuBar.savedSearchDeleteAction.setEnabled(false);
+ selectedSavedSearchGUID = "";
+ searchField.setEditText("");
+ }
+ searchFieldChanged();
+
+ logger.log(logger.HIGH, "Leaving NeverNote.updateSavedSearchSelection()");
+
+
+ }
+ // Show/Hide note information
+ private void toggleSavedSearchWindow() {
+ logger.log(logger.HIGH, "Entering NeverNote.toggleSavedSearchWindow");
+ if (savedSearchTree.isVisible())
+ savedSearchTree.hide();
+ else
+ savedSearchTree.show();
+ menuBar.hideSavedSearches.setChecked(savedSearchTree.isVisible());
+
+ Global.saveWindowVisible("savedSearchTree", savedSearchTree.isVisible());
+ logger.log(logger.HIGH, "Leaving NeverNote.toggleSavedSearchWindow");
+ }
+
+
+
+
+ //***************************************************************
+ //***************************************************************
+ //** These functions deal with Help menu & tool menu items
+ //***************************************************************
+ //***************************************************************
+ // Show database status
+ @SuppressWarnings("unused")
+ private void databaseStatus() {
+ waitCursor(true);
+ int dirty = conn.getNoteTable().getDirtyCount();
+ int unindexed = conn.getNoteTable().getUnindexedCount();
+ DatabaseStatus status = new DatabaseStatus();
+ status.setUnsynchronized(dirty);
+ status.setUnindexed(unindexed);
+ status.setNoteCount(conn.getNoteTable().getNoteCount());
+ status.setNotebookCount(listManager.getNotebookIndex().size());
+ status.setSavedSearchCount(listManager.getSavedSearchIndex().size());
+ status.setTagCount(listManager.getTagIndex().size());
+ status.setResourceCount(conn.getNoteTable().noteResourceTable.getResourceCount());
+ status.setWordCount(conn.getWordsTable().getWordCount());
+ waitCursor(false);
+ status.exec();
+ }
+ // Compact the database
+ @SuppressWarnings("unused")
+ private void compactDatabase() {
+ logger.log(logger.HIGH, "Entering NeverNote.compactDatabase");
+ if (QMessageBox.question(this, "Confirmation", "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 NeverNote 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;
+ }
+ setMessage("Compacting database.");
+ waitCursor(true);
+ listManager.compactDatabase();
+ waitCursor(false);
+ setMessage("Database compact is complete.");
+ logger.log(logger.HIGH, "Leaving NeverNote.compactDatabase");
+ }
+ @SuppressWarnings("unused")
+ private void accountInformation() {
+ logger.log(logger.HIGH, "Entering NeverNote.accountInformation");
+ AccountDialog dialog = new AccountDialog();
+ dialog.show();
+ logger.log(logger.HIGH, "Leaving NeverNote.accountInformation");
+ }
+ @SuppressWarnings("unused")
+ private void releaseNotes() {
+ logger.log(logger.HIGH, "Entering NeverNote.releaseNotes");
+ QDialog dialog = new QDialog(this);
+ QHBoxLayout layout = new QHBoxLayout();
+ QTextEdit textBox = new QTextEdit();
+ layout.addWidget(textBox);
+ textBox.setReadOnly(true);
+ QFile file = new QFile(Global.getDirectoryPath()+"release.txt");
+ if (!file.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly,
+ QIODevice.OpenModeFlag.Text)))
+ return;
+ textBox.setText(file.readAll().toString());
+ file.close();
+ dialog.setWindowTitle("Release Notes");
+ dialog.setLayout(layout);
+ dialog.show();
+ logger.log(logger.HIGH, "Leaving NeverNote.releaseNotes");
+ }
+ // Called when user picks Log from the help menu
+ @SuppressWarnings("unused")
+ private void logger() {
+ logger.log(logger.HIGH, "Entering NeverNote.logger");
+ QDialog dialog = new QDialog(this);
+ QHBoxLayout layout = new QHBoxLayout();
+ QListWidget textBox = new QListWidget();
+ layout.addWidget(textBox);
+ textBox.addItems(emitLog);
+
+ dialog.setLayout(layout);
+ dialog.setWindowTitle("Mesasge Log");
+ dialog.show();
+ logger.log(logger.HIGH, "Leaving NeverNote.logger");
+ }
+ // Menu option "help/about" was selected
+ @SuppressWarnings("unused")
+ private void about() {
+ logger.log(logger.HIGH, "Entering NeverNote.about");
+ QMessageBox.about(this,
+ tr("About NeverNote"),
+ tr("<h4><center><b>NeverNote</b></center></h4><hr><center>Version "+Global.version+"<hr></center>Evernote"
+ +" Generic client.<br><br>"
+ +"Licensed under GPL v2. <br><hr><br>"
+ +"Evernote is copyright 2001-2010 by Evernote Corporation<br>"
+ +"Jambi and QT are the licensed trademark of Nokia Corporation<br>"
+ +"PDFRenderer is licened under the LGPL<br>"
+ +"Jazzy is licened under the LGPL<br>"
+ +"Java is a registered trademark of Sun Microsystems.<br><hr>"));
+ logger.log(logger.HIGH, "Leaving NeverNote.about");
+ }
+ // Hide the entire left hand side
+ @SuppressWarnings("unused")
+ private void toggleLeftSide() {
+ boolean hidden;
+
+ hidden = !menuBar.hideLeftSide.isChecked();
+ menuBar.hideLeftSide.setChecked(!hidden);
+
+ if (notebookTree.isVisible() != hidden)
+ toggleNotebookWindow();
+ if (savedSearchTree.isVisible() != hidden)
+ toggleSavedSearchWindow();
+ if (tagTree.isVisible() != hidden)
+ toggleTagWindow();
+ if (attributeTree.isVisible() != hidden)
+ toggleAttributesWindow();
+ if (trashTree.isVisible() != hidden)
+ toggleTrashWindow();
+
+ Global.saveWindowVisible("leftPanel", hidden);
+
+ }
+
+
+ //***************************************************************
+ //***************************************************************
+ //** These functions deal with the Toolbar
+ //***************************************************************
+ //***************************************************************
+ // Text in the search bar has been cleared
+ private void searchFieldCleared() {
+ searchField.setEditText("");
+ saveNoteIndexWidth();
+ }
+ // text in the search bar changed. We only use this to tell if it was cleared,
+ // otherwise we trigger off searchFieldChanged.
+ @SuppressWarnings("unused")
+ private void searchFieldTextChanged(String text) {
+ if (text.trim().equals("")) {
+ searchFieldCleared();
+ if (searchPerformed) {
+ noteCache.clear();
+ listManager.setEnSearch("");
+///// listManager.clearNoteIndexSearch();
+ //noteIndexUpdated(true);
+ listManager.loadNotesIndex();
+ refreshEvernoteNote(true);
+ noteIndexUpdated(false);
+ }
+ searchPerformed = false;
+ }
+ }
+ // Text in the toolbar has changed
+ private void searchFieldChanged() {
+ logger.log(logger.HIGH, "Entering NeverNote.searchFieldChanged");
+ noteCache.clear();
+ saveNoteIndexWidth();
+ String text = searchField.currentText();
+ listManager.setEnSearch(text.trim());
+ listManager.loadNotesIndex();
+//--->>> noteIndexUpdated(true);
+ noteIndexUpdated(false);
+ refreshEvernoteNote(true);
+ searchPerformed = true;
+ logger.log(logger.HIGH, "Leaving NeverNote.searchFieldChanged");
+ }
+ // Build the window tool bar
+ private void setupToolBar() {
+ logger.log(logger.HIGH, "Entering NeverNote.setupToolBar");
+ toolBar = addToolBar(tr("toolBar"));
+
+ prevButton = toolBar.addAction("Previous");
+ QIcon prevIcon = new QIcon(iconPath+"back.png");
+ prevButton.setIcon(prevIcon);
+ prevButton.triggered.connect(this, "previousViewedAction()");
+
+ nextButton = toolBar.addAction("Next");
+ QIcon nextIcon = new QIcon(iconPath+"forward.png");
+ nextButton.setIcon(nextIcon);
+ nextButton.triggered.connect(this, "nextViewedAction()");
+
+ upButton = toolBar.addAction("Up");
+ QIcon upIcon = new QIcon(iconPath+"up.png");
+ upButton.setIcon(upIcon);
+ upButton.triggered.connect(this, "upAction()");
+
+ downButton = toolBar.addAction("Down");
+ QIcon downIcon = new QIcon(iconPath+"down.png");
+ downButton.setIcon(downIcon);
+ downButton.triggered.connect(this, "downAction()");
+
+ synchronizeButton = toolBar.addAction("Synchronize");
+ synchronizeAnimation = new ArrayList<QIcon>();
+ synchronizeAnimation.add(new QIcon(iconPath+"synchronize-0.png"));
+ synchronizeAnimation.add(new QIcon(iconPath+"synchronize-1.png"));
+ synchronizeAnimation.add(new QIcon(iconPath+"synchronize-2.png"));
+ synchronizeAnimation.add(new QIcon(iconPath+"synchronize-3.png"));
+ synchronizeButton.setIcon(synchronizeAnimation.get(0));
+ synchronizeFrame = 0;
+ synchronizeButton.triggered.connect(this, "evernoteSync()");
+
+ printButton = toolBar.addAction("Print");
+ QIcon printIcon = new QIcon(iconPath+"print.png");
+ printButton.setIcon(printIcon);
+ printButton.triggered.connect(this, "printNote()");
+
+ tagButton = toolBar.addAction("Tag");
+ QIcon tagIcon = new QIcon(iconPath+"tag.png");
+ tagButton.setIcon(tagIcon);
+ tagButton.triggered.connect(browserWindow, "modifyTags()");
+
+ attributeButton = toolBar.addAction("Attributes");
+ QIcon attributeIcon = new QIcon(iconPath+"attribute.png");
+ attributeButton.setIcon(attributeIcon);
+ attributeButton.triggered.connect(this, "toggleNoteInformation()");
+
+ emailButton = toolBar.addAction("Email");
+ QIcon emailIcon = new QIcon(iconPath+"email.png");
+ emailButton.setIcon(emailIcon);
+ emailButton.triggered.connect(this, "emailNote()");
+
+ deleteButton = toolBar.addAction("Delete");
+ QIcon deleteIcon = new QIcon(iconPath+"delete.png");
+ deleteButton.setIcon(deleteIcon);
+ deleteButton.triggered.connect(this, "deleteNote()");
+
+ newButton = toolBar.addAction("New");
+ QIcon newIcon = new QIcon(iconPath+"new.png");
+ newButton.triggered.connect(this, "addNote()");
+ newButton.setIcon(newIcon);
+ toolBar.addSeparator();
+ toolBar.addWidget(new QLabel("Quota:"));
+ toolBar.addWidget(quotaBar);
+ //quotaBar.setSizePolicy(Policy.Minimum, Policy.Minimum);
+ updateQuotaBar();
+
+ // Setup the zoom
+ zoomSpinner = new QSpinBox();
+ zoomSpinner.setMinimum(10);
+ zoomSpinner.setMaximum(1000);
+ zoomSpinner.setAccelerated(true);
+ zoomSpinner.setSingleStep(10);
+ zoomSpinner.setValue(100);
+ zoomSpinner.valueChanged.connect(this, "zoomChanged()");
+ toolBar.addWidget(new QLabel("Zoom"));
+ toolBar.addWidget(zoomSpinner);
+
+ //toolBar.addWidget(new QLabel(" "));
+ toolBar.addSeparator();
+ toolBar.addWidget(new QLabel(" Search:"));
+ toolBar.addWidget(searchField);
+ QSizePolicy sizePolicy = new QSizePolicy();
+ sizePolicy.setHorizontalPolicy(Policy.MinimumExpanding);
+ searchField.setSizePolicy(sizePolicy);
+ searchField.setInsertPolicy(InsertPolicy.InsertAtTop);
+
+ searchClearButton = toolBar.addAction("Search Clear");
+ QIcon searchClearIcon = new QIcon(iconPath+"searchclear.png");
+ searchClearButton.setIcon(searchClearIcon);
+ searchClearButton.triggered.connect(this, "searchFieldCleared()");
+
+ logger.log(logger.HIGH, "Leaving NeverNote.setupToolBar");
+ }
+ // Update the sychronize button picture
+ @SuppressWarnings("unused")
+ private void updateSyncButton() {
+ synchronizeFrame++;
+ if (synchronizeFrame == 4)
+ synchronizeFrame = 0;
+ synchronizeButton.setIcon(synchronizeAnimation.get(synchronizeFrame));
+ }
+ // Synchronize with Evernote
+ @SuppressWarnings("unused")
+ private void evernoteSync() {
+ logger.log(logger.HIGH, "Entering NeverNote.evernoteSync");
+ if (!Global.isConnected)
+ remoteConnect();
+ if (Global.isConnected)
+ synchronizeAnimationTimer.start(200);
+ syncTimer();
+ logger.log(logger.HIGH, "Leaving NeverNote.evernoteSync");
+ }
+ private void updateQuotaBar() {
+ long limit = Global.getUploadLimit();
+ long amount = Global.getUploadAmount();
+ if (amount>0 && limit>0) {
+ int percent =(int)(amount*100/limit);
+ quotaBar.setValue(percent);
+ } else
+ quotaBar.setValue(0);
+ }
+ // Zoom changed
+ @SuppressWarnings("unused")
+ private void zoomChanged() {
+ browserWindow.getBrowser().setZoomFactor(new Double(zoomSpinner.value())/100);
+ }
+
+ //****************************************************************
+ //****************************************************************
+ //* System Tray functions
+ //****************************************************************
+ //****************************************************************
+ private void trayToggleVisible() {
+ if (isVisible()) {
+ hide();
+ } else {
+ show();
+ raise();
+ }
+ }
+ @SuppressWarnings("unused")
+ private void trayActivated(QSystemTrayIcon.ActivationReason reason) {
+ if (reason == QSystemTrayIcon.ActivationReason.DoubleClick) {
+ String name = QSystemTrayIcon.MessageIcon.resolve(reason.value()).name();
+ trayToggleVisible();
+ }
+ }
+
+
+ //***************************************************************
+ //***************************************************************
+ //** These functions deal with the trash tree
+ //***************************************************************
+ //***************************************************************
+ // Setup the tree containing the trash.
+ @SuppressWarnings("unused")
+ private void trashTreeSelection() {
+ logger.log(logger.HIGH, "Entering NeverNote.trashTreeSelection");
+
+ clearNotebookFilter();
+ clearTagFilter();
+ clearAttributeFilter();
+ clearSavedSearchFilter();
+
+ String tempGuid = currentNoteGuid;
+
+// currentNoteGuid = "";
+ currentNote = new Note();
+ selectedNoteGUIDs.clear();
+ listManager.getSelectedNotebooks().clear();
+ listManager.getSelectedTags().clear();
+ listManager.setSelectedSavedSearch("");
+ browserWindow.clear();
+
+ // toggle the add buttons
+ newButton.setEnabled(!newButton.isEnabled());
+ menuBar.noteAdd.setEnabled(newButton.isEnabled());
+ menuBar.noteAdd.setVisible(true);
+
+ List<QTreeWidgetItem> selections = trashTree.selectedItems();
+ if (selections.size() == 0) {
+ currentNoteGuid = trashNoteGuid;
+ trashNoteGuid = tempGuid;
+ Global.showDeleted = false;
+ menuBar.noteRestoreAction.setEnabled(false);
+ menuBar.noteRestoreAction.setVisible(false);
+ }
+ else {
+ currentNoteGuid = trashNoteGuid;
+ trashNoteGuid = tempGuid;
+ menuBar.noteRestoreAction.setEnabled(true);
+ menuBar.noteRestoreAction.setVisible(true);
+ Global.showDeleted = true;
+ }
+ listManager.loadNotesIndex();
+ noteIndexUpdated(false);
+//// browserWindow.setEnabled(newButton.isEnabled());
+ browserWindow.setReadOnly(!newButton.isEnabled());
+ logger.log(logger.HIGH, "Leaving NeverNote.trashTreeSelection");
+ }
+ // Empty the trash file
+ @SuppressWarnings("unused")
+ private void emptyTrash() {
+// browserWindow.clear();
+ listManager.emptyTrash();
+ if (trashTree.selectedItems().size() > 0) {
+ listManager.getSelectedNotebooks().clear();
+ listManager.getSelectedTags().clear();
+ listManager.setSelectedSavedSearch("");
+ newButton.setEnabled(!newButton.isEnabled());
+ menuBar.noteAdd.setEnabled(newButton.isEnabled());
+ menuBar.noteAdd.setVisible(true);
+ browserWindow.clear();
+
+ clearTagFilter();
+ clearNotebookFilter();
+ clearSavedSearchFilter();
+ clearAttributeFilter();
+
+ Global.showDeleted = false;
+ menuBar.noteRestoreAction.setEnabled(false);
+ menuBar.noteRestoreAction.setVisible(false);
+
+ listManager.loadNotesIndex();
+//--->>> noteIndexUpdated(true);
+ noteIndexUpdated(false);
+ }
+ }
+ // Show/Hide trash window
+ private void toggleTrashWindow() {
+ logger.log(logger.HIGH, "Entering NeverNote.toggleTrashWindow");
+ if (trashTree.isVisible())
+ trashTree.hide();
+ else
+ trashTree.show();
+ menuBar.hideTrash.setChecked(trashTree.isVisible());
+
+ Global.saveWindowVisible("trashTree", trashTree.isVisible());
+ logger.log(logger.HIGH, "Leaving NeverNote.trashWindow");
+ }
+ private void clearTrashFilter() {
+ Global.showDeleted = false;
+ newButton.setEnabled(true);
+ menuBar.noteAdd.setEnabled(true);
+ menuBar.noteAdd.setVisible(true);
+ trashTree.blockSignals(true);
+ trashTree.clearSelection();
+ trashTree.blockSignals(false);
+
+ }
+
+
+ //***************************************************************
+ //***************************************************************
+ //** These functions deal with connection settings
+ //***************************************************************
+ //***************************************************************
+ // SyncRunner had a problem and things are disconnected
+ @SuppressWarnings("unused")
+ private void remoteErrorDisconnect() {
+ menuBar.connectAction.setText("Connect");
+ menuBar.connectAction.setToolTip("Connect to Evernote");
+ menuBar.synchronizeAction.setEnabled(false);
+ synchronizeAnimationTimer.stop();
+ return;
+ }
+ // Do a manual connect/disconnect
+ private void remoteConnect() {
+ logger.log(logger.HIGH, "Entering NeverNote.remoteConnect");
+
+ if (Global.isConnected) {
+ Global.isConnected = false;
+ syncRunner.enDisconnect();
+ setupConnectMenuOptions();
+ setupOnlineMenu();
+ return;
+ }
+
+ AESEncrypter aes = new AESEncrypter();
+ try {
+ aes.decrypt(new FileInputStream(Global.getDirectoryPath()+"secure.txt"));
+ } catch (FileNotFoundException e) {
+ // File not found, so we'll just get empty strings anyway.
+ }
+ String userid = aes.getUserid();
+ String password = aes.getPassword();
+ if (!userid.equals("") && !password.equals("")) {
+ Global.username = userid;
+ Global.password = password;
+ }
+
+ // Show the login dialog box
+ if (!Global.automaticLogin() || userid.equals("")|| password.equals("")) {
+ LoginDialog login = new LoginDialog();
+ login.exec();
+
+ if (!login.okPressed()) {
+ return;
+ }
+
+ Global.username = login.getUserid();
+ Global.password = login.getPassword();
+ }
+ syncRunner.username = Global.username;
+ syncRunner.password = Global.password;
+ syncRunner.userStoreUrl = Global.userStoreUrl;
+ syncRunner.noteStoreUrl = Global.noteStoreUrl;
+ syncRunner.noteStoreUrlBase = Global.noteStoreUrlBase;
+ syncRunner.enConnect();
+ Global.isConnected = syncRunner.isConnected;
+ setupOnlineMenu();
+ setupConnectMenuOptions();
+ logger.log(logger.HIGH, "Leaving NeverNote.remoteConnect");
+ }
+ private void setupConnectMenuOptions() {
+ logger.log(logger.HIGH, "entering NeverNote.setupConnectMenuOptions");
+ if (!Global.isConnected) {
+ menuBar.connectAction.setText("Connect");
+ menuBar.connectAction.setToolTip("Connect to Evernote");
+ menuBar.synchronizeAction.setEnabled(false);
+ } else {
+ menuBar.connectAction.setText("Disconnect");
+ menuBar.connectAction.setToolTip("Disconnect from Evernote");
+ menuBar.synchronizeAction.setEnabled(true);
+ }
+ logger.log(logger.HIGH, "Leaving NeverNote.setupConnectionMenuOptions");
+ }
+
+
+
+ //***************************************************************
+ //***************************************************************
+ //** These functions deal with the GUI Attribute tree
+ //***************************************************************
+ //***************************************************************
+ @SuppressWarnings("unused")
+ private void attributeTreeClicked(QTreeWidgetItem item, Integer integer) {
+
+ clearTagFilter();
+ clearNotebookFilter();
+ clearTrashFilter();
+ clearSavedSearchFilter();
+
+ if (attributeTreeSelected == null || item.nativeId() != attributeTreeSelected.nativeId()) {
+ if (item.childCount() > 0) {
+ item.setSelected(false);
+ } else {
+ Global.createdBeforeFilter.reset();
+ Global.createdSinceFilter.reset();
+ Global.changedBeforeFilter.reset();
+ Global.changedSinceFilter.reset();
+ Global.containsFilter.reset();
+ attributeTreeSelected = item;
+ DateAttributeFilterTable f = null;
+ f = findDateAttributeFilterTable(item.parent());
+ if (f!=null)
+ f.select(item.text(0));
+ else {
+ String text = item.text(0);
+ Global.containsFilter.select(text);
+ }
+ }
+ listManager.loadNotesIndex();
+ noteIndexUpdated(false);
+ return;
+ }
+ attributeTreeSelected = null;
+ item.setSelected(false);
+ Global.createdBeforeFilter.reset();
+ Global.createdSinceFilter.reset();
+ Global.changedBeforeFilter.reset();
+ Global.changedSinceFilter.reset();
+ Global.containsFilter.reset();
+ listManager.loadNotesIndex();
+ noteIndexUpdated(false);
+ }
+ // This determines what attribute filter we need, depending upon the selection
+ private DateAttributeFilterTable findDateAttributeFilterTable(QTreeWidgetItem w) {
+ if (w.parent() != null && w.childCount() > 0) {
+ QTreeWidgetItem parent = w.parent();
+ if (parent.text(0).equalsIgnoreCase("created") &&
+ w.text(0).equalsIgnoreCase("since"))
+ return Global.createdSinceFilter;
+ if (parent.text(0).equalsIgnoreCase("created") &&
+ w.text(0).equalsIgnoreCase("before"))
+ return Global.createdBeforeFilter;
+ if (parent.text(0).equalsIgnoreCase("last modified") &&
+ w.text(0).equalsIgnoreCase("since"))
+ return Global.changedSinceFilter;
+ if (parent.text(0).equalsIgnoreCase("last modified") &&
+ w.text(0).equalsIgnoreCase("before"))
+ return Global.changedBeforeFilter;
+ }
+ return null;
+ }
+ // Show/Hide attribute search window
+ private void toggleAttributesWindow() {
+ logger.log(logger.HIGH, "Entering NeverNote.toggleAttributesWindow");
+ if (attributeTree.isVisible())
+ attributeTree.hide();
+ else
+ attributeTree.show();
+ menuBar.hideAttributes.setChecked(attributeTree.isVisible());
+
+ Global.saveWindowVisible("attributeTree", attributeTree.isVisible());
+ logger.log(logger.HIGH, "Leaving NeverNote.toggleAttributeWindow");
+ }
+ private void clearAttributeFilter() {
+ Global.createdBeforeFilter.reset();
+ Global.createdSinceFilter.reset();
+ Global.changedBeforeFilter.reset();
+ Global.changedSinceFilter.reset();
+ Global.containsFilter.reset();
+ attributeTreeSelected = null;
+ attributeTree.blockSignals(true);
+ attributeTree.clearSelection();
+ attributeTree.blockSignals(false);
+ }
+
+
+ //***************************************************************
+ //***************************************************************
+ //** These functions deal with the GUI Note index table
+ //***************************************************************
+ //***************************************************************
+ // Initialize the note list table
+ private void initializeNoteTable() {
+ logger.log(logger.HIGH, "Entering NeverNote.initializeNoteTable");
+ noteTableView.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection);
+ noteTableView.selectionModel().selectionChanged.connect(this, "noteTableSelection()");
+ logger.log(logger.HIGH, "Leaving NeverNote.initializeNoteTable");
+ }
+ // Show/Hide trash window
+ @SuppressWarnings("unused")
+ private void toggleNoteListWindow() {
+ logger.log(logger.HIGH, "Entering NeverNote.toggleNoteListWindow");
+ if (noteTableView.isVisible())
+ noteTableView.hide();
+ else
+ noteTableView.show();
+ menuBar.hideNoteList.setChecked(noteTableView.isVisible());
+
+ Global.saveWindowVisible("noteList", noteTableView.isVisible());
+ logger.log(logger.HIGH, "Leaving NeverNote.toggleNoteListWindow");
+ }
+ // Handle the event that a user selects a note from the table
+ @SuppressWarnings("unused")
+ private void noteTableSelection() {
+ logger.log(logger.HIGH, "Entering NeverNote.noteTableSelection");
+ saveNote();
+ if (historyGuids.size() == 0) {
+ historyGuids.add(currentNoteGuid);
+ historyPosition = 1;
+ }
+ noteTableView.showColumn(Global.noteTableGuidPosition);
+
+ List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
+ noteTableView.hideColumn(Global.noteTableGuidPosition);
+
+ if (selections.size() > 0) {
+ QModelIndex index;
+ menuBar.noteDuplicateAction.setEnabled(true);
+ menuBar.noteOnlineHistoryAction.setEnabled(true);
+ menuBar.noteMergeAction.setEnabled(true);
+ selectedNoteGUIDs.clear();
+ if (selections.size() != 1 || Global.showDeleted) {
+ menuBar.noteDuplicateAction.setEnabled(false);
+ }
+ if (selections.size() != 1 || !Global.isConnected) {
+ menuBar.noteOnlineHistoryAction.setEnabled(false);
+ }
+ if (selections.size() == 1) {
+ menuBar.noteMergeAction.setEnabled(false);
+ }
+ for (int i=0; i<selections.size(); i++) {
+ int row = selections.get(i).row();
+ if (row == 0)
+ upButton.setEnabled(false);
+ else
+ upButton.setEnabled(true);
+ if (row < noteTableView.model.rowCount()-1)
+ downButton.setEnabled(true);
+ else
+ downButton.setEnabled(false);
+ index = noteTableView.proxyModel.index(row, Global.noteTableGuidPosition);
+ SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
+ currentNoteGuid = (String)ix.values().toArray()[0];
+ selectedNoteGUIDs.add(currentNoteGuid);
+ }
+ }
+
+ 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;
+ scrollToGuid(currentNoteGuid);
+ refreshEvernoteNote(true);
+ logger.log(logger.HIGH, "Leaving NeverNote.noteTableSelection");
+ }
+ // Trigger a refresh when the note db has been updated
+ private void noteIndexUpdated(boolean reload) {
+ logger.log(logger.HIGH, "Entering NeverNote.noteIndexUpdated");
+ Global.traceReset();
+ saveNote();
+ refreshEvernoteNoteList();
+ logger.log(logger.HIGH, "Calling note table reload in NeverNote.noteIndexUpdated() - "+reload);
+ noteTableView.load(listManager, reload);
+ scrollToGuid(currentNoteGuid);
+ logger.log(logger.HIGH, "Leaving NeverNote.noteIndexUpdated");
+ }
+ // Called when the list of notes is updated
+ private void refreshEvernoteNoteList() {
+ logger.log(logger.HIGH, "Entering NeverNote.refreshEvernoteNoteList");
+ browserWindow.setDisabled(false);
+ if (selectedNoteGUIDs == null)
+ selectedNoteGUIDs = new ArrayList<String>();
+ selectedNoteGUIDs.clear(); // clear out old entries
+
+ String saveCurrentNoteGuid = new String();
+ String tempNoteGuid = new String();
+
+ historyGuids.clear();
+ historyPosition = 0;
+ prevButton.setEnabled(false);
+ nextButton.setEnabled(false);
+
+ if (currentNoteGuid == null)
+ currentNoteGuid = new String();
+
+ for (Note note : listManager.getNoteIndex()) {
+ tempNoteGuid = note.getGuid();
+ if (currentNoteGuid.equals(tempNoteGuid)) {
+ saveCurrentNoteGuid = new String(tempNoteGuid);
+ }
+ }
+
+ if (listManager.getNoteIndex().size() == 0) {
+ currentNoteGuid = "";
+ currentNote = null;
+ browserWindow.clear();
+ browserWindow.setDisabled(true);
+ }
+
+ if (saveCurrentNoteGuid.equals("") && listManager.getNoteIndex().size() >0) {
+ currentNoteGuid = listManager.getNoteIndex().get(listManager.getNoteIndex().size()-1).getGuid();
+ currentNote = listManager.getNoteIndex().get(listManager.getNoteIndex().size()-1);
+ refreshEvernoteNote(true);
+ } else {
+ refreshEvernoteNote(false);
+ }
+ reloadTagTree();
+
+ logger.log(logger.HIGH, "Leaving NeverNote.refreshEvernoteNoteList");
+ }
+ // 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<noteTableView.model().rowCount(); i++) {
+ QModelIndex modelIndex = noteTableView.model().index(i, Global.noteTableGuidPosition);
+ if (modelIndex != null) {
+ SortedMap<Integer, Object> 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<noteTableView.model().rowCount(); i++) {
+ QModelIndex modelIndex = noteTableView.model().index(i, Global.noteTableGuidPosition);
+ if (modelIndex != null) {
+ SortedMap<Integer, Object> 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")
+ private void upAction() {
+ List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
+ int row = selections.get(0).row();
+ if (row > 0) {
+ noteTableView.selectRow(row-1);
+ }
+ }
+ // Called when the down arrow is clicked
+ @SuppressWarnings("unused")
+ private void downAction() {
+ List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
+ int row = selections.get(0).row();
+ int max = noteTableView.model.rowCount();
+ if (row < max-1) {
+ noteTableView.selectRow(row+1);
+ }
+ }
+ // Update a tag string for a specific note in the list
+ @SuppressWarnings("unused")
+ private void updateListTags(String guid, List<String> tags) {
+ logger.log(logger.HIGH, "Entering NeverNote.updateListTags");
+ StringBuffer tagBuffer = new StringBuffer();
+ for (int i=0; i<tags.size(); i++) {
+ tagBuffer.append(tags.get(i));
+ if (i<tags.size()-1)
+ tagBuffer.append(", ");
+ }
+
+ for (int i=0; i<noteTableView.model.rowCount(); i++) {
+ QModelIndex modelIndex = noteTableView.model.index(i, Global.noteTableGuidPosition);
+ if (modelIndex != null) {
+ SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+ String tableGuid = (String)ix.values().toArray()[0];
+ if (tableGuid.equals(guid)) {
+ noteTableView.model.setData(i, Global.noteTableTagPosition,tagBuffer.toString());
+ noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
+ return;
+ }
+ }
+ }
+ logger.log(logger.HIGH, "Leaving NeverNote.updateListTags");
+ }
+ // Update a title for a specific note in the list
+ @SuppressWarnings("unused")
+ private void updateListTitle(String guid, String title) {
+ logger.log(logger.HIGH, "Entering NeverNote.updateListTitle");
+
+ for (int i=0; i<noteTableView.model.rowCount(); i++) {
+ //QModelIndex modelIndex = noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
+ QModelIndex modelIndex = noteTableView.model.index(i, Global.noteTableGuidPosition);
+ if (modelIndex != null) {
+// SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(modelIndex);
+ SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+ String tableGuid = (String)ix.values().toArray()[0];
+ if (tableGuid.equals(guid)) {
+ noteTableView.model.setData(i, Global.noteTableTitlePosition,title);
+ noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
+ return;
+ }
+ }
+ }
+ logger.log(logger.HIGH, "Leaving NeverNote.updateListTitle");
+ }
+ // Update a title for a specific note in the list
+ @SuppressWarnings("unused")
+ private void updateListAuthor(String guid, String author) {
+ logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
+
+ for (int i=0; i<noteTableView.model.rowCount(); i++) {
+ //QModelIndex modelIndex = noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
+ QModelIndex modelIndex = noteTableView.model.index(i, Global.noteTableGuidPosition);
+ if (modelIndex != null) {
+// SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(modelIndex);
+ SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+ String tableGuid = (String)ix.values().toArray()[0];
+ if (tableGuid.equals(guid)) {
+ noteTableView.model.setData(i, Global.noteTableAuthorPosition,author);
+ noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
+ return;
+ }
+ }
+ }
+ logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
+ }
+ private void updateListNoteNotebook(String guid, String notebook) {
+ logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
+
+ for (int i=0; i<noteTableView.model.rowCount(); i++) {
+ //QModelIndex modelIndex = noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
+ QModelIndex modelIndex = noteTableView.model.index(i, Global.noteTableGuidPosition);
+ if (modelIndex != null) {
+// SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(modelIndex);
+ SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+ String tableGuid = (String)ix.values().toArray()[0];
+ if (tableGuid.equals(guid)) {
+ noteTableView.model.setData(i, Global.noteTableNotebookPosition,notebook);
+ noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
+ return;
+ }
+ }
+ }
+ logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
+ }
+ // Update a title for a specific note in the list
+ @SuppressWarnings("unused")
+ private void updateListSourceUrl(String guid, String url) {
+ logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
+
+ for (int i=0; i<noteTableView.model.rowCount(); i++) {
+ //QModelIndex modelIndex = noteTableView.proxyModel.index(i, Global.noteTableGuidPosition);
+ QModelIndex modelIndex = noteTableView.model.index(i, Global.noteTableGuidPosition);
+ if (modelIndex != null) {
+// SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(modelIndex);
+ SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+ String tableGuid = (String)ix.values().toArray()[0];
+ if (tableGuid.equals(guid)) {
+ noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
+ noteTableView.model.setData(i, Global.noteTableSourceUrlPosition,url);
+ return;
+ }
+ }
+ }
+ logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
+ }
+ private void updateListGuid(String oldGuid, String newGuid) {
+ logger.log(logger.HIGH, "Entering NeverNote.updateListTitle");
+
+ for (int i=0; i<noteTableView.model.rowCount(); i++) {
+ QModelIndex modelIndex = noteTableView.model.index(i, Global.noteTableGuidPosition);
+ if (modelIndex != null) {
+ SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+ String tableGuid = (String)ix.values().toArray()[0];
+ if (tableGuid.equals(oldGuid)) {
+ noteTableView.model.setData(i, Global.noteTableGuidPosition,newGuid);
+ //noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
+ return;
+ }
+ }
+ }
+ logger.log(logger.HIGH, "Leaving NeverNote.updateListTitle");
+ }
+ private void updateListTagName(String guid) {
+ logger.log(logger.HIGH, "Entering NeverNote.updateTagName");
+
+ for (int j=0; j<listManager.getNoteIndex().size(); j++) {
+ if (listManager.getNoteIndex().get(j).getTagGuids().contains(guid)) {
+ String newName = listManager.getTagNamesForNote(listManager.getNoteIndex().get(j));
+
+ for (int i=0; i<noteTableView.model.rowCount(); i++) {
+ QModelIndex modelIndex = noteTableView.model.index(i, Global.noteTableGuidPosition);
+ if (modelIndex != null) {
+ SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+ String noteGuid = (String)ix.values().toArray()[0];
+ if (noteGuid.equalsIgnoreCase(listManager.getNoteIndex().get(j).getGuid())) {
+ noteTableView.model.setData(i, Global.noteTableTagPosition, newName);
+ //noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
+ i=noteTableView.model.rowCount();
+ }
+ }
+ }
+ }
+ }
+ logger.log(logger.HIGH, "Leaving NeverNote.updateListNotebook");
+ }
+ private void removeListTagName(String guid) {
+ logger.log(logger.HIGH, "Entering NeverNote.updateTagName");
+
+ for (int j=0; j<listManager.getNoteIndex().size(); j++) {
+ if (listManager.getNoteIndex().get(j).getTagGuids().contains(guid)) {
+ for (int i=listManager.getNoteIndex().get(j).getTagGuids().size()-1; i>=0; i--) {
+ if (listManager.getNoteIndex().get(j).getTagGuids().get(i).equals(guid))
+ listManager.getNoteIndex().get(j).getTagGuids().remove(i);
+ }
+
+ String newName = listManager.getTagNamesForNote(listManager.getNoteIndex().get(j));
+ for (int i=0; i<noteTableView.model.rowCount(); i++) {
+ QModelIndex modelIndex = noteTableView.model.index(i, Global.noteTableGuidPosition);
+ if (modelIndex != null) {
+ SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+ String noteGuid = (String)ix.values().toArray()[0];
+ if (noteGuid.equalsIgnoreCase(listManager.getNoteIndex().get(j).getGuid())) {
+ noteTableView.model.setData(i, Global.noteTableTagPosition, newName);
+// noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
+ i=noteTableView.model.rowCount();
+ }
+ }
+ }
+ }
+ }
+ logger.log(logger.HIGH, "Leaving NeverNote.updateListNotebook");
+ }
+ private void updateListNotebookName(String oldName, String newName) {
+ logger.log(logger.HIGH, "Entering NeverNote.updateListNotebookName");
+
+ for (int i=0; i<noteTableView.model.rowCount(); i++) {
+ QModelIndex modelIndex = noteTableView.model.index(i, Global.noteTableNotebookPosition);
+ if (modelIndex != null) {
+ SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+ String tableName = (String)ix.values().toArray()[0];
+ if (tableName.equalsIgnoreCase(oldName)) {
+// noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
+ noteTableView.model.setData(i, Global.noteTableNotebookPosition, newName);
+ }
+ }
+ }
+ logger.log(logger.HIGH, "Leaving NeverNote.updateListNotebookName");
+ }
+ @SuppressWarnings("unused")
+ private void updateListDateCreated(String guid, QDateTime date) {
+ logger.log(logger.HIGH, "Entering NeverNote.updateListDateCreated");
+
+ for (int i=0; i<noteTableView.model.rowCount(); i++) {
+ QModelIndex modelIndex = noteTableView.model.index(i, Global.noteTableGuidPosition);
+ if (modelIndex != null) {
+ SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+ String tableGuid = (String)ix.values().toArray()[0];
+ if (tableGuid.equals(guid)) {
+ noteTableView.model.setData(i, Global.noteTableCreationPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
+ return;
+ }
+ }
+ }
+ logger.log(logger.HIGH, "Leaving NeverNote.updateListDateCreated");
+ }
+ @SuppressWarnings("unused")
+ private void updateListDateSubject(String guid, QDateTime date) {
+ logger.log(logger.HIGH, "Entering NeverNote.updateListDateSubject");
+
+ for (int i=0; i<noteTableView.model.rowCount(); i++) {
+ QModelIndex modelIndex = noteTableView.model.index(i, Global.noteTableGuidPosition);
+ if (modelIndex != null) {
+ SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+ String tableGuid = (String)ix.values().toArray()[0];
+ if (tableGuid.equals(guid)) {
+ noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
+ noteTableView.model.setData(i, Global.noteTableSubjectDatePosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
+ return;
+ }
+ }
+ }
+ logger.log(logger.HIGH, "Leaving NeverNote.updateListDateCreated");
+ }
+ @SuppressWarnings("unused")
+ private void updateListDateChanged(String guid, QDateTime date) {
+ logger.log(logger.HIGH, "Entering NeverNote.updateListDateChanged");
+
+ for (int i=0; i<noteTableView.model.rowCount(); i++) {
+ QModelIndex modelIndex = noteTableView.model.index(i, Global.noteTableGuidPosition);
+ if (modelIndex != null) {
+ SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+ String tableGuid = (String)ix.values().toArray()[0];
+ if (tableGuid.equals(guid)) {
+ noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
+ noteTableView.model.setData(i, Global.noteTableChangedPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
+ return;
+ }
+ }
+ }
+ logger.log(logger.HIGH, "Leaving NeverNote.updateListDateChanged");
+ }
+ private void updateListDateChanged() {
+ logger.log(logger.HIGH, "Entering NeverNote.updateListDateChanged");
+ QDateTime date = new QDateTime(QDateTime.currentDateTime());
+ for (int i=0; i<noteTableView.model.rowCount(); i++) {
+ QModelIndex modelIndex = noteTableView.model.index(i, Global.noteTableGuidPosition);
+ if (modelIndex != null) {
+ SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+ String tableGuid = (String)ix.values().toArray()[0];
+ if (tableGuid.equals(currentNoteGuid)) {
+ noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
+ noteTableView.model.setData(i, Global.noteTableChangedPosition, date.toString(Global.getDateFormat()+" " +Global.getTimeFormat()));
+ return;
+ }
+ }
+ }
+ logger.log(logger.HIGH, "Leaving NeverNote.updateListDateChanged");
+ }
+ // Redo scroll
+ @SuppressWarnings("unused")
+ private void scrollToCurrentGuid() {
+ //scrollToGuid(currentNoteGuid);
+ List<QModelIndex> selections = noteTableView.selectionModel().selectedRows();
+ if (selections.size() == 0)
+ return;
+ QModelIndex index = selections.get(0);
+ int row = selections.get(0).row();
+ String guid = (String)index.model().index(row, Global.noteTableGuidPosition).data();
+ scrollToGuid(guid);
+ }
+ // Scroll to a particular index item
+ private void scrollToGuid(String guid) {
+ if (currentNote == null || guid == null)
+ return;
+ if (currentNote.isActive() && Global.showDeleted) {
+ for (int i=0; i<listManager.getNoteIndex().size(); i++) {
+ if (!listManager.getNoteIndex().get(i).isActive()) {
+ currentNote = listManager.getNoteIndex().get(i);
+ currentNoteGuid = currentNote.getGuid();
+ i = listManager.getNoteIndex().size();
+ }
+ }
+ }
+
+ if (!currentNote.isActive() && !Global.showDeleted) {
+ for (int i=0; i<listManager.getNoteIndex().size(); i++) {
+ if (listManager.getNoteIndex().get(i).isActive()) {
+ currentNote = listManager.getNoteIndex().get(i);
+ currentNoteGuid = currentNote.getGuid();
+ i = listManager.getNoteIndex().size();
+ }
+ }
+ }
+
+ QModelIndex index;
+ for (int i=0; i<noteTableView.model().rowCount(); i++) {
+ index = noteTableView.model().index(i, Global.noteTableGuidPosition);
+ if (currentNoteGuid.equals(index.data())) {
+// noteTableView.setCurrentIndex(index);
+ noteTableView.selectRow(i);
+ noteTableView.scrollTo(index, ScrollHint.EnsureVisible); // This should work, but it doesn't
+ i=noteTableView.model.rowCount();
+ }
+ }
+ }
+ // Show/Hide columns
+ private void showColumns() {
+ noteTableView.setColumnHidden(Global.noteTableCreationPosition, !Global.isColumnVisible("dateCreated"));
+ noteTableView.setColumnHidden(Global.noteTableChangedPosition, !Global.isColumnVisible("dateChanged"));
+ noteTableView.setColumnHidden(Global.noteTableSubjectDatePosition, !Global.isColumnVisible("dateSubject"));
+ noteTableView.setColumnHidden(Global.noteTableAuthorPosition, !Global.isColumnVisible("author"));
+ noteTableView.setColumnHidden(Global.noteTableSourceUrlPosition, !Global.isColumnVisible("sourceUrl"));
+ noteTableView.setColumnHidden(Global.noteTableTagPosition, !Global.isColumnVisible("tags"));
+ noteTableView.setColumnHidden(Global.noteTableNotebookPosition, !Global.isColumnVisible("notebook"));
+ noteTableView.setColumnHidden(Global.noteTableSynchronizedPosition, !Global.isColumnVisible("synchronized"));
+ }
+ // Open a separate window
+ @SuppressWarnings("unused")
+ private void listDoubleClick() {
+
+ }
+ // Title color has changed
+ @SuppressWarnings("unused")
+ private void titleColorChanged(Integer color) {
+ logger.log(logger.HIGH, "Entering NeverNote.updateListAuthor");
+
+ QColor backgroundColor = new QColor();
+ QColor foregroundColor = new QColor(QColor.black);
+ backgroundColor.setRgb(color);
+
+ if (backgroundColor.rgb() == QColor.black.rgb() || backgroundColor.rgb() == QColor.blue.rgb())
+ foregroundColor.setRgb(QColor.white.rgb());
+
+ if (selectedNoteGUIDs.size() == 0)
+ selectedNoteGUIDs.add(currentNoteGuid);
+
+ for (int j=0; j<selectedNoteGUIDs.size(); j++) {
+ for (int i=0; i<noteTableView.model.rowCount(); i++) {
+ QModelIndex modelIndex = noteTableView.model.index(i, Global.noteTableGuidPosition);
+ if (modelIndex != null) {
+ SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+ String tableGuid = (String)ix.values().toArray()[0];
+ if (tableGuid.equals(selectedNoteGUIDs.get(j))) {
+ for (int k=0; k<Global.noteTableColumnCount; k++) {
+ noteTableView.model.setData(i, k, backgroundColor, Qt.ItemDataRole.BackgroundRole);
+ noteTableView.model.setData(i, k, foregroundColor, Qt.ItemDataRole.ForegroundRole);
+ listManager.updateNoteTitleColor(selectedNoteGUIDs.get(j), backgroundColor.rgb());
+ }
+ i=noteTableView.model.rowCount();
+ }
+ }
+ }
+ }
+ logger.log(logger.HIGH, "Leaving NeverNote.updateListAuthor");
+ }
+
+
+ //***************************************************************
+ //***************************************************************
+ //** These functions deal with Note specific things
+ //***************************************************************
+ //***************************************************************
+ @SuppressWarnings("unused")
+ private void setNoteDirty() {
+ logger.log(logger.EXTREME, "Entering NeverNote.setNoteDirty()");
+ noteDirty = true;
+
+ listManager.getUnsynchronizedNotes().add(currentNoteGuid);
+ for (int i=0; i<noteTableView.model.rowCount(); i++) {
+ QModelIndex modelIndex = noteTableView.model.index(i, Global.noteTableGuidPosition);
+ if (modelIndex != null) {
+ SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+ String tableGuid = (String)ix.values().toArray()[0];
+ if (tableGuid.equals(currentNoteGuid)) {
+ noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, "false");
+ return;
+ }
+ }
+ }
+ logger.log(logger.EXTREME, "Leaving NeverNote.setNoteDirty()");
+ }
+ private void saveNote() {
+ logger.log(logger.EXTREME, "Inside NeverNote.saveNote()");
+ if (noteDirty) {
+ logger.log(logger.EXTREME, "Note is dirty.");
+ waitCursor(true);
+
+ preview = new Thumbnailer(currentNoteGuid, new QSize(1024,768));
+ preview.finished.connect(this, "saveThumbnail(String)");
+ preview.setContent(browserWindow.getContent());
+
+ logger.log(logger.EXTREME, "Saving to cache");
+ QTextCodec codec = QTextCodec.codecForLocale();
+// QTextDecoder decoder = codec.makeDecoder();
+ codec = QTextCodec.codecForName("UTF-8");
+ QByteArray unicode = codec.fromUnicode(browserWindow.getContent());
+ noteCache.put(currentNoteGuid, unicode.toString());
+
+ logger.log(logger.EXTREME, "updating list manager");
+ listManager.updateNoteContent(currentNoteGuid, browserWindow.getContent());
+ logger.log(logger.EXTREME, "Updating title");
+ listManager.updateNoteTitle(currentNoteGuid, browserWindow.getTitle());
+ updateListDateChanged();
+
+ logger.log(logger.EXTREME, "Looking through note index for refreshed note");
+ for (int i=0; i<listManager.getNoteIndex().size(); i++) {
+ if (listManager.getNoteIndex().get(i).getGuid().equals(currentNoteGuid)) {
+ currentNote = listManager.getNoteIndex().get(i);
+ i = listManager.getNoteIndex().size();
+ }
+ }
+ noteDirty = false;
+ waitCursor(false);
+ }
+ }
+ // Get a note from Evernote (and put it in the browser)
+ private void refreshEvernoteNote(boolean reload) {
+ logger.log(logger.HIGH, "Entering NeverNote.refreshEvernoteNote");
+ if (Global.disableViewing) {
+ browserWindow.setEnabled(false);
+ return;
+ }
+ inkNote = false;
+ if (!Global.showDeleted)
+ browserWindow.setReadOnly(false);
+ Global.cryptCounter =0;
+ if (currentNoteGuid.equals("")) {
+ browserWindow.setReadOnly(true);
+ return;
+ }
+ if (!reload)
+ return;
+
+ waitCursor(true);
+ browserWindow.loadingData(true);
+
+ currentNote = conn.getNoteTable().getNote(currentNoteGuid, true,true,false,false,true);
+ if (currentNote == null)
+ return;
+
+ if (!noteCache.containsKey(currentNoteGuid) || conn.getNoteTable().isThumbnailNeeded(currentNoteGuid)) {
+ QByteArray js = new QByteArray();
+ // We need to prepend the note with <HEAD></HEAD> or encoded characters are ugly
+ js.append("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">");
+ js.append("<style type=\"text/css\">en-crypt-temp { border-style:solid; border-color:blue; padding:0.5mm 0.5mm 0.5mm 0.5mm; }</style>");
+ js.append("<style type=\"text/css\">en-hilight { background-color: rgb(255,255,0) }</style>");
+ js.append("<style type=\"text/css\">en-spell { text-decoration: none; border-bottom: dotted 1px #cc0000; }</style>");
+ js.append("</head>");
+ js.append(rebuildNoteHTML(currentNoteGuid, currentNote.getContent()));
+ js.append("</HTML>");
+ js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml.dtd'>", "");
+ js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml2.dtd'>", "");
+ js.replace("<?xml version='1.0' encoding='UTF-8'?>", "");
+ browserWindow.getBrowser().setContent(js);
+ noteCache.put(currentNoteGuid, js.toString());
+ if (conn.getNoteTable().isThumbnailNeeded(currentNoteGuid)) {
+ preview = new Thumbnailer(currentNoteGuid, new QSize(1024,768));
+ preview.finished.connect(this, "saveThumbnail(String)");
+ preview.setContent(js.toString());
+ }
+ } else {
+ logger.log(logger.HIGH, "Note content is being pulled from the cache");
+ String cachedContent = modifyCachedTodoTags(noteCache.get(currentNoteGuid));
+ browserWindow.getBrowser().setContent(new QByteArray(cachedContent));
+ }
+
+ browserWindow.getBrowser().page().setContentEditable(!inkNote); // We don't allow editing of ink notes
+ browserWindow.setNote(currentNote);
+
+ // Build a list of non-closed notebooks
+ List<Notebook> nbooks = new ArrayList<Notebook>();
+ for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
+ boolean found=false;
+ for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
+ if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid()))
+ found = true;
+ }
+ if (!found)
+ nbooks.add(listManager.getNotebookIndex().get(i));
+ }
+
+ browserWindow.setNotebookList(nbooks);
+ browserWindow.setTitle(currentNote.getTitle());
+ browserWindow.setTag(getTagNamesForNote(currentNote));
+ browserWindow.setAuthor(currentNote.getAttributes().getAuthor());
+
+ browserWindow.setAltered(currentNote.getUpdated());
+ browserWindow.setCreation(currentNote.getCreated());
+ if (currentNote.getAttributes().getSubjectDate() > 0)
+ browserWindow.setSubjectDate(currentNote.getAttributes().getSubjectDate());
+ else
+ browserWindow.setSubjectDate(currentNote.getCreated());
+ browserWindow.setUrl(currentNote.getAttributes().getSourceURL());
+ browserWindow.setAllTags(listManager.getTagIndex());
+ browserWindow.setCurrentTags(currentNote.getTagNames());
+ noteDirty = false;
+ scrollToGuid(currentNoteGuid);
+
+ browserWindow.loadingData(false);
+ if (thumbnailViewer.isActiveWindow())
+ thumbnailView();
+ waitCursor(false);
+ logger.log(logger.HIGH, "Leaving NeverNote.refreshEvernoteNote");
+ }
+ // Save a generated thumbnail
+ @SuppressWarnings("unused")
+ private void saveThumbnail(String guid) {
+ QFile tFile = new QFile(Global.currentDir+"res/thumbnail-"+guid+".png");
+ tFile.open(OpenModeFlag.ReadOnly);
+ QByteArray imgBytes = tFile.readAll();
+ tFile.close();
+ conn.getNoteTable().setThumbnail(guid, imgBytes);
+ conn.getNoteTable().setThumbnailNeeded(guid, false);
+ thumbnailViewer.setThumbnail(QImage.fromData(imgBytes));
+ if (thumbnailViewer.isVisible())
+ thumbnailViewer.showFullScreen();
+
+ /*
+ QByteArray img2 = new QByteArray(conn.getNoteTable().getThumbnail(guid));
+ QFile file = new QFile(Global.currentDir+"res/aaaa.png");
+ file.open(OpenModeFlag.WriteOnly);
+ file.write(img2);
+ file.close();
+ */
+ }
+ // Show/Hide note information
+ @SuppressWarnings("unused")
+ private void toggleNoteInformation() {
+ logger.log(logger.HIGH, "Entering NeverNote.toggleNoteInformation");
+ browserWindow.toggleInformation();
+ menuBar.noteAttributes.setChecked(browserWindow.isExtended());
+ logger.log(logger.HIGH, "Leaving NeverNote.toggleNoteInformation");
+ }
+ // Listener triggered when a print button is pressed
+ @SuppressWarnings("unused")
+ private void printNote() {
+ logger.log(logger.HIGH, "Entering NeverNote.printNote");
+
+ QPrintDialog dialog = new QPrintDialog();
+ if (dialog.exec() == QDialog.DialogCode.Accepted.value()) {
+ QPrinter printer = dialog.printer();
+ browserWindow.getBrowser().print(printer);
+ }
+ logger.log(logger.HIGH, "Leaving NeverNote.printNote");
+
+ }
+ // Listener triggered when the email button is pressed
+ @SuppressWarnings("unused")
+ private void emailNote() {
+ logger.log(logger.HIGH, "Entering NeverNote.emailNote");
+
+ if (Desktop.isDesktopSupported()) {
+ Desktop desktop = Desktop.getDesktop();
+
+ String text2 = browserWindow.getContentsToEmail();
+ QUrl url = new QUrl("mailto:");
+ url.addQueryItem("subject", currentNote.getTitle());
+ url.addQueryItem("body", QUrl.toPercentEncoding(text2).toString());
+ QDesktopServices.openUrl(url);
+ }
+/*
+
+ if (desktop.isSupported(Desktop.Action.MAIL)) {
+ URI uriMailTo = null;
+ try {
+ //String text = browserWindow.getBrowser().page().currentFrame().toPlainText();
+ String text = browserWindow.getContentsToEmail();
+ //text = "<b>" +text +"</b>";
+ uriMailTo = new URI("mailto", "&SUBJECT="+currentNote.getTitle()
+ +"&BODY=" +text, null);
+ uriMailTo = new URI("mailto", "&SUBJECT="+currentNote.getTitle()
+ +"&ATTACHMENT=d:/test.pdf", null);
+ desktop.mail(uriMailTo);
+ } catch (URISyntaxException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ }
+ */
+ logger.log(logger.HIGH, "Leaving NeverNote.emailNote");
+ }
+ // Reindex all notes
+ @SuppressWarnings("unused")
+ private void fullReindex() {
+ logger.log(logger.HIGH, "Entering NeverNote.fullReindex");
+ // If we are deleting non-trash notes
+ if (currentNote.getDeleted() == 0) {
+ if (QMessageBox.question(this, "Confirmation", "This will cause all notes & attachments to be reindexed, "+
+ "but please be aware that depending upon the size of your database updating all these records " +
+ "can be time consuming and NeverNote 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;
+ }
+ }
+ waitCursor(true);
+ setMessage("Marking notes for reindex.");
+ conn.getNoteTable().reindexAllNotes();
+ conn.getNoteTable().noteResourceTable.reindexAll();
+ setMessage("Database will be reindexed.");
+ waitCursor(false);
+ logger.log(logger.HIGH, "Leaving NeverNote.fullRefresh");
+ }
+ // Listener when a user wants to reindex a specific note
+ @SuppressWarnings("unused")
+ private void reindexNote() {
+ logger.log(logger.HIGH, "Entering NeverNote.reindexNote");
+ for (int i=0; i<selectedNoteGUIDs.size(); i++) {
+ conn.getNoteTable().setIndexNeeded(selectedNoteGUIDs.get(i), true);
+ }
+ if (selectedNotebookGUIDs.size() > 1)
+ setMessage("Notes will be reindexed.");
+ else
+ setMessage("Note will be reindexed.");
+ logger.log(logger.HIGH, "Leaving NeverNote.reindexNote");
+ }
+ // Delete the note
+ @SuppressWarnings("unused")
+ private void deleteNote() {
+ logger.log(logger.HIGH, "Entering NeverNote.deleteNote");
+ if (currentNote == null)
+ return;
+ if (currentNoteGuid.equals(""))
+ return;
+
+ // If we are deleting non-trash notes
+ if (currentNote.isActive()) {
+ if (Global.verifyDelete()) {
+ if (QMessageBox.question(this, "Confirmation", "Delete selected note(s)?",
+ QMessageBox.StandardButton.Yes,
+ QMessageBox.StandardButton.No)==StandardButton.No.value() && Global.verifyDelete() == true) {
+ return;
+ }
+ }
+ if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
+ selectedNoteGUIDs.add(currentNoteGuid);
+ for (int i=0; i<selectedNoteGUIDs.size(); i++) {
+ listManager.deleteNote(selectedNoteGUIDs.get(i));
+ }
+ } else {
+ // If we are deleting from the trash.
+ if (Global.verifyDelete()) {
+ if (QMessageBox.question(this, "Confirmation", "Permanently delete selected note(s)?",
+ QMessageBox.StandardButton.Yes,
+ QMessageBox.StandardButton.No)==StandardButton.No.value()) {
+ return;
+ }
+ }
+ if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
+ selectedNoteGUIDs.add(currentNoteGuid);
+ for (int i=selectedNoteGUIDs.size()-1; i>=0; i--) {
+ for (int j=noteTableView.model.rowCount()-1; j>=0; j--) {
+ QModelIndex modelIndex = noteTableView.model.index(j, Global.noteTableGuidPosition);
+ if (modelIndex != null) {
+ SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+ String tableGuid = (String)ix.values().toArray()[0];
+ if (tableGuid.equals(selectedNoteGUIDs.get(i))) {
+ noteTableView.model.removeRow(j);
+ j=-1;
+ }
+ }
+ }
+ listManager.expungeNote(selectedNoteGUIDs.get(i));
+ }
+ }
+ currentNoteGuid = "";
+ listManager.loadNotesIndex();
+ noteIndexUpdated(false);
+ refreshEvernoteNote(true);
+ scrollToGuid(currentNoteGuid);
+ logger.log(logger.HIGH, "Leaving NeverNote.deleteNote");
+ }
+ // Add a new note
+ @SuppressWarnings("unused")
+ private void addNote() {
+ logger.log(logger.HIGH, "Inside NeverNote.addNote");
+// browserWindow.setEnabled(true);
+ browserWindow.setReadOnly(false);
+ saveNote();
+ Calendar currentTime = new GregorianCalendar();
+ String noteString = new String("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+ "<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">\n" +
+ "<en-note>\n<br clear=\"none\" /></en-note>");
+
+ Long l = new Long(currentTime.getTimeInMillis());
+ String randint = new String(Long.toString(l));
+
+ // Find a notebook. We first look for a selected notebook (the "All Notebooks" one doesn't count).
+ // Then we look
+ // for the first non-archived notebook. Finally, if nothing else we
+ // pick the first notebook in the list.
+ String notebook = null;
+ listManager.getNotebookIndex().get(0).getGuid();
+ List<QTreeWidgetItem> selectedNotebook = notebookTree.selectedItems();
+ if (selectedNotebook.size() > 0 && !selectedNotebook.get(0).text(0).equalsIgnoreCase("All Notebooks")) {
+ QTreeWidgetItem currentSelectedNotebook = selectedNotebook.get(0);
+ notebook = currentSelectedNotebook.text(2);
+ } else {
+ boolean found = false;
+ List<Notebook> goodNotebooks = new ArrayList<Notebook>();
+ for (int i=0; i<listManager.getNotebookIndex().size(); i++) {
+ boolean match = false;
+ for (int j=0; j<listManager.getArchiveNotebookIndex().size(); j++) {
+ if (listManager.getArchiveNotebookIndex().get(j).getGuid().equals(listManager.getNotebookIndex().get(i).getGuid())) {
+ match = true;
+ j = listManager.getArchiveNotebookIndex().size();
+ }
+ }
+ if (!match)
+ goodNotebooks.add(listManager.getNotebookIndex().get(i).deepCopy());
+ }
+ // Now we have a list of good notebooks, so we can look for the default
+ found = false;
+ for (int i=0; i<goodNotebooks.size(); i++) {
+ if (goodNotebooks.get(i).isDefaultNotebook()) {
+ notebook = goodNotebooks.get(i).getGuid();
+ found = true;
+ i = goodNotebooks.size();
+ }
+ }
+
+ if (goodNotebooks.size() > 0 && !found)
+ notebook = goodNotebooks.get(0).getGuid();
+
+ if (notebook==null)
+ notebook = listManager.getNotebookIndex().get(0).getGuid();
+ }
+
+ Note newNote = new Note();
+ newNote.setUpdateSequenceNum(0);
+ newNote.setGuid(randint);
+ newNote.setNotebookGuid(notebook);
+ newNote.setTitle("");
+ newNote.setContent(noteString);
+ newNote.setDeleted(0);
+ newNote.setCreated(System.currentTimeMillis());
+ newNote.setUpdated(System.currentTimeMillis());
+ newNote.setActive(true);
+ NoteAttributes na = new NoteAttributes();
+ na.setLatitude(0.0);
+ na.setLongitude(0.0);
+ na.setAltitude(0.0);
+ newNote.setAttributes(new NoteAttributes());
+ conn.getNoteTable().addNote(newNote, true);
+ listManager.getUnsynchronizedNotes().add(newNote.getGuid());
+ noteTableView.insertRow(listManager, newNote, true, -1);
+
+ currentNote = newNote;
+ currentNoteGuid = currentNote.getGuid();
+ listManager.addNote(newNote);
+ refreshEvernoteNote(true);
+ listManager.countNotebookResults(listManager.getNoteIndex());
+ browserWindow.titleLabel.setFocus();
+ browserWindow.titleLabel.selectAll();
+// notebookTree.updateCounts(listManager.getNotebookIndex(), listManager.getNotebookCounter());
+ logger.log(logger.HIGH, "Leaving NeverNote.addNote");
+ }
+ // Restore a note from the trash;
+ @SuppressWarnings("unused")
+ private void restoreNote() {
+ waitCursor(true);
+ if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
+ selectedNoteGUIDs.add(currentNoteGuid);
+ for (int i=0; i<selectedNoteGUIDs.size(); i++) {
+ listManager.restoreNote(selectedNoteGUIDs.get(i));
+ }
+ currentNoteGuid = "";
+ listManager.loadNotesIndex();
+ noteIndexUpdated(false);
+ waitCursor(false);
+ }
+ // Search a note for specific txt
+ @SuppressWarnings("unused")
+ private void findText() {
+ find.show();
+ find.setFocusOnTextField();
+ }
+ @SuppressWarnings("unused")
+ private void doFindText() {
+ browserWindow.getBrowser().page().findText(find.getText(), find.getFlags());
+ find.setFocus();
+ }
+ // Signal received that note content has changed. Normally we just need the guid to remove
+ // it from the cache.
+ @SuppressWarnings("unused")
+ private void invalidateNoteCache(String guid, String content) {
+ String v = noteCache.remove(guid);
+ if (content != null) {
+ v = noteCache.put(guid, content);
+ }
+ }
+ // Signal received that a note guid has changed
+ @SuppressWarnings("unused")
+ private void noteGuidChanged(String oldGuid, String newGuid) {
+ if (noteCache.containsKey(oldGuid)) {
+ String cache = noteCache.get(oldGuid);
+ noteCache.put(newGuid, cache);
+ noteCache.remove(oldGuid);
+ }
+ listManager.updateNoteGuid(oldGuid, newGuid, false);
+ if (currentNoteGuid.equals(oldGuid)) {
+ if (currentNote != null)
+ currentNote.setGuid(newGuid);
+ currentNoteGuid = newGuid;
+ }
+ for (int i=0; i<listManager.getNoteIndex().size(); i++) {
+ if (listManager.getNoteIndex().get(i).getGuid().equals(newGuid)) {
+ noteTableView.proxyModel.addGuid(newGuid);
+ i=listManager.getNoteIndex().size();
+ }
+ }
+ updateListGuid(oldGuid, newGuid);
+ }
+ // Toggle the note editor button bar
+ private void toggleEditorButtonBar() {
+ if (browserWindow.buttonsVisible) {
+ browserWindow.hideButtons();
+ menuBar.showEditorBar.setChecked(browserWindow.buttonsVisible);
+// Global.saveWindowVisible("editorButtonBar", browserWindow.buttonsVisible);
+ } else {
+ browserWindow.buttonsVisible = true;
+ showEditorButtons();
+ }
+ Global.saveWindowVisible("editorButtonBar", browserWindow.buttonsVisible);
+ }
+ // Show editor buttons
+ private void showEditorButtons() {
+ browserWindow.undoButton.setVisible(false);
+ browserWindow.redoButton.setVisible(false);
+ browserWindow.cutButton.setVisible(false);
+ browserWindow.copyButton.setVisible(false);
+ browserWindow.pasteButton.setVisible(false);
+ browserWindow.strikethroughButton.setVisible(false);
+ browserWindow.underlineButton.setVisible(false);
+ browserWindow.boldButton.setVisible(false);
+ browserWindow.italicButton.setVisible(false);
+ browserWindow.hlineButton.setVisible(false);
+ browserWindow.indentButton.setVisible(false);
+ browserWindow.outdentButton.setVisible(false);
+ browserWindow.fontList.setVisible(false);
+ browserWindow.fontSize.setVisible(false);
+ browserWindow.fontColor.setVisible(false);
+ browserWindow.fontHilight.setVisible(false);
+ browserWindow.leftAlignButton.setVisible(false);
+ browserWindow.centerAlignButton.setVisible(false);
+ browserWindow.rightAlignButton.setVisible(false);
+ browserWindow.indentButton.setVisible(false);
+ browserWindow.outdentButton.setVisible(false);
+
+ browserWindow.undoButton.setVisible(Global.isEditorButtonVisible("undo"));
+ browserWindow.redoButton.setVisible(Global.isEditorButtonVisible("redo"));
+ browserWindow.cutButton.setVisible(Global.isEditorButtonVisible("cut"));
+ browserWindow.copyButton.setVisible(Global.isEditorButtonVisible("copy"));
+ browserWindow.pasteButton.setVisible(Global.isEditorButtonVisible("paste"));
+ browserWindow.strikethroughButton.setVisible(Global.isEditorButtonVisible("strikethrough"));
+ browserWindow.underlineButton.setVisible(Global.isEditorButtonVisible("underline"));
+ browserWindow.boldButton.setVisible(Global.isEditorButtonVisible("bold"));
+ browserWindow.italicButton.setVisible(Global.isEditorButtonVisible("italic"));
+ browserWindow.hlineButton.setVisible(Global.isEditorButtonVisible("hline"));
+ browserWindow.indentButton.setVisible(Global.isEditorButtonVisible("indent"));
+ browserWindow.outdentButton.setVisible(Global.isEditorButtonVisible("outdent"));
+ browserWindow.bulletListButton.setVisible(Global.isEditorButtonVisible("bulletList"));
+ browserWindow.numberListButton.setVisible(Global.isEditorButtonVisible("numberList"));
+ browserWindow.fontList.setVisible(Global.isEditorButtonVisible("font"));
+ browserWindow.fontSize.setVisible(Global.isEditorButtonVisible("fontSize"));
+ browserWindow.fontColor.setVisible(Global.isEditorButtonVisible("fontColor"));
+ browserWindow.fontHilight.setVisible(Global.isEditorButtonVisible("fontHilight"));
+ browserWindow.leftAlignButton.setVisible(Global.isEditorButtonVisible("alignLeft"));
+ browserWindow.centerAlignButton.setVisible(Global.isEditorButtonVisible("alignCenter"));
+ browserWindow.rightAlignButton.setVisible(Global.isEditorButtonVisible("alignRight"));
+ }
+ private void duplicateNote(String guid) {
+
+ Calendar currentTime = new GregorianCalendar();
+ Long l = new Long(currentTime.getTimeInMillis());
+ String newGuid = new String(Long.toString(l));
+
+ Note oldNote = conn.getNoteTable().getNote(guid, true, true, false, false, false);
+ Note newNote = oldNote.deepCopy();
+ newNote.setGuid(newGuid);
+ List<Resource> resList = conn.getNoteTable().noteResourceTable.getNoteResources(guid, true);
+ oldNote.setResources(resList);
+ duplicateNote(oldNote);
+ }
+ private void duplicateNote(Note oldNote) {
+ waitCursor(true);
+ // Now that we have a good notebook guid, we need to move the conflicting note
+ // to the local notebook
+ Calendar currentTime = new GregorianCalendar();
+ Long l = new Long(currentTime.getTimeInMillis());
+ String newGuid = new String(Long.toString(l));
+
+ Note newNote = oldNote.deepCopy();
+ newNote.setUpdateSequenceNum(0);
+ newNote.setGuid(newGuid);
+ newNote.setDeleted(0);
+ newNote.setActive(true);
+ List<Resource> resList = oldNote.getResources();
+ if (resList == null)
+ resList = new ArrayList<Resource>();
+ long prevGuid = 0;
+ for (int i=0; i<resList.size(); i++) {
+ l = prevGuid;
+ while (l == prevGuid) {
+ currentTime = new GregorianCalendar();
+ l = new Long(currentTime.getTimeInMillis());
+ }
+ prevGuid = l;
+ String newResGuid = new String(Long.toString(l));
+ resList.get(i).setNoteGuid(newGuid);
+ resList.get(i).setGuid(newResGuid);
+ resList.get(i).setUpdateSequenceNum(0);
+ resList.get(i).setActive(true);
+ conn.getNoteTable().noteResourceTable.saveNoteResource(new Resource(resList.get(i).deepCopy()), true);
+ }
+ newNote.setResources(resList);
+ listManager.addNote(newNote);
+ conn.getNoteTable().addNote(newNote, true);
+ listManager.getUnsynchronizedNotes().add(newNote.getGuid());
+ noteTableView.insertRow(listManager, newNote, true, -1);
+ listManager.countNotebookResults(listManager.getNoteIndex());
+ waitCursor(false);
+ }
+ // Merge notes
+ @SuppressWarnings("unused")
+ private void mergeNotes() {
+ logger.log(logger.HIGH, "Merging notes");
+ waitCursor(true);
+ saveNote();
+ String masterGuid = null;
+ List<String> sources = new ArrayList<String>();
+ QModelIndex index;
+ for (int i=0; i<noteTableView.selectionModel().selectedRows().size(); i++) {
+ int r = noteTableView.selectionModel().selectedRows().get(i).row();
+ index = noteTableView.proxyModel.index(r, Global.noteTableGuidPosition);
+ SortedMap<Integer, Object> ix = noteTableView.proxyModel.itemData(index);
+ if (i == 0)
+ masterGuid = (String)ix.values().toArray()[0];
+ else
+ sources.add((String)ix.values().toArray()[0]);
+ }
+
+ logger.log(logger.EXTREME, "Master guid=" +masterGuid);
+ logger.log(logger.EXTREME, "Children count: "+sources.size());
+ mergeNoteContents(masterGuid, sources);
+ currentNoteGuid = masterGuid;
+ noteIndexUpdated(false);
+ refreshEvernoteNote(true);
+ waitCursor(false);
+ }
+ private void mergeNoteContents(String targetGuid, List<String> sources) {
+ Note target = conn.getNoteTable().getNote(targetGuid, true, false, false, false, false);
+ String newContent = target.getContent();
+ newContent = newContent.replace("</en-note>", "<br></br>");
+
+ for (int i=0; i<sources.size(); i++) {
+ Note source = conn.getNoteTable().getNote(sources.get(i), true, true, false, false, false);
+ if (source.isSetTitle()) {
+ newContent = newContent +("<table bgcolor=\"lightgrey\"><tr><td><font size=\"6\"><b>" +source.getTitle() +"</b></font></td></tr></table>");
+ }
+ String sourceContent = source.getContent();
+ logger.log(logger.EXTREME, "Merging contents into note");
+ logger.log(logger.EXTREME, sourceContent);
+ logger.log(logger.EXTREME, "End of content");
+ int startOfNote = sourceContent.indexOf("<en-note>");
+ sourceContent = sourceContent.substring(startOfNote+9);
+ int endOfNote = sourceContent.indexOf("</en-note>");
+ sourceContent = sourceContent.substring(0,endOfNote);
+ newContent = newContent + sourceContent;
+ logger.log(logger.EXTREME, "New note content");
+ logger.log(logger.EXTREME, newContent);
+ logger.log(logger.EXTREME, "End of content");
+ for (int j=0; j<source.getResourcesSize(); j++) {
+ logger.log(logger.EXTREME, "Reassigning resource: "+source.getResources().get(j).getGuid());
+ Resource r = source.getResources().get(j);
+ Resource newRes = conn.getNoteTable().noteResourceTable.getNoteResource(r.getGuid(), true);
+
+ Calendar currentTime = new GregorianCalendar();
+ Long l = new Long(currentTime.getTimeInMillis());
+
+ long prevGuid = 0;
+ l = prevGuid;
+ while (l == prevGuid) {
+ currentTime = new GregorianCalendar();
+ l = new Long(currentTime.getTimeInMillis());
+ }
+ String newResGuid = new String(Long.toString(l));
+ newRes.setNoteGuid(targetGuid);
+ newRes.setGuid(newResGuid);
+ newRes.setUpdateSequenceNum(0);
+ newRes.setActive(true);
+ conn.getNoteTable().noteResourceTable.saveNoteResource(newRes, true);
+ }
+ }
+ logger.log(logger.EXTREME, "Updating note");
+ conn.getNoteTable().updateNoteContent(targetGuid, newContent +"</en-note>");
+ for (int i=0; i<sources.size(); i++) {
+ logger.log(logger.EXTREME, "Deleting note " +sources.get(i));
+ listManager.deleteNote(sources.get(i));
+ }
+ logger.log(logger.EXTREME, "Exiting merge note");
+ }
+ // A resource within a note has had a guid change
+ @SuppressWarnings("unused")
+ private void noteResourceGuidChanged(String noteGuid, String oldGuid, String newGuid) {
+ if (!oldGuid.equals(newGuid))
+ Global.resourceMap.put(oldGuid, newGuid);
+ }
+ // View a thumbnail of the note
+ public void thumbnailView() {
+
+ String thumbnailName = Global.currentDir+"res/thumbnail-"+currentNoteGuid+".png";
+ QFile thumbnail = new QFile(thumbnailName);
+ if (!thumbnail.exists()) {
+
+ QImage img = new QImage();
+ img.loadFromData(conn.getNoteTable().getThumbnail(currentNoteGuid));
+ thumbnailViewer.setThumbnail(img);
+ } else
+ thumbnailViewer.setThumbnail(thumbnailName);
+ if (!thumbnailViewer.isVisible())
+ thumbnailViewer.showFullScreen();
+ }
+
+ //**********************************************************
+ //**********************************************************
+ //* Online user actions
+ //**********************************************************
+ //**********************************************************
+ private void setupOnlineMenu() {
+ if (!Global.isConnected) {
+ menuBar.noteOnlineHistoryAction.setEnabled(false);
+ return;
+ } else {
+ menuBar.noteOnlineHistoryAction.setEnabled(true);
+ }
+ }
+ @SuppressWarnings("unused")
+ private void viewNoteHistory() {
+ if (currentNoteGuid == null || currentNoteGuid.equals(""))
+ return;
+ if (currentNote.getUpdateSequenceNum() == 0) {
+ setMessage("Note has never been synchronized.");
+ QMessageBox.information(this, "Error", "This note has never been sent to Evernote, so there is no history.");
+ return;
+ }
+
+ setMessage("Getting Note History");
+ waitCursor(true);
+ Note currentOnlineNote = null;
+ versions = null;
+ try {
+ if (Global.isPremium())
+ versions = syncRunner.noteStore.listNoteVersions(syncRunner.authToken, currentNoteGuid);
+ else
+ versions = new ArrayList<NoteVersionId>();
+ currentOnlineNote = syncRunner.noteStore.getNote(syncRunner.authToken, currentNoteGuid, true, true, false, false);
+ } catch (EDAMUserException e) {
+ setMessage("EDAMUserException: " +e.getMessage());
+ return;
+ } catch (EDAMSystemException e) {
+ setMessage("EDAMSystemException: " +e.getMessage());
+ return;
+ } catch (EDAMNotFoundException e) {
+ setMessage("Note not found on server.");
+ QMessageBox.information(this, "Error", "This note could not be found on Evernote's servers.");
+ return;
+ } catch (TException e) {
+ setMessage("EDAMTransactionException: " +e.getMessage());
+ return;
+ }
+
+ // If we've gotten this far, we have a good note.
+ if (historyWindow == null) {
+ historyWindow = new OnlineNoteHistory(conn);
+ historyWindow.historyCombo.activated.connect(this, "reloadHistoryWindow(String)");
+ historyWindow.restoreAsNew.clicked.connect(this, "restoreHistoryNoteAsNew()");
+ historyWindow.restore.clicked.connect(this, "restoreHistoryNote()");
+ } else {
+ historyWindow.historyCombo.clear();
+ }
+ boolean isDirty = conn.getNoteTable().isNoteDirty(currentNoteGuid);
+ if (currentNote.getUpdateSequenceNum() != currentOnlineNote.getUpdateSequenceNum())
+ isDirty = true;
+ historyWindow.setCurrent(isDirty);
+
+ loadHistoryWindowContent(currentOnlineNote);
+ historyWindow.load(versions);
+ setMessage("History retrieved");
+ waitCursor(false);
+ historyWindow.exec();
+ }
+ private Note reloadHistoryWindow(String selection) {
+ waitCursor(true);
+ String fmt = Global.getDateFormat() + " " + Global.getTimeFormat();
+ String dateTimeFormat = new String(fmt);
+ SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);
+ int index = -1;
+ int usn = 0;
+
+ for (int i=0; i<versions.size(); i++) {
+ StringBuilder versionDate = new StringBuilder(simple.format(versions.get(i).getServiceUpdated()));
+ if (versionDate.toString().equals(selection))
+ index = i;
+ }
+
+ if (index > -1 || selection.indexOf("Current") > -1) {
+ Note historyNote = null;
+ try {
+ if (index > -1) {
+ usn = versions.get(index).getUpdateSequenceNum();
+ historyNote = syncRunner.noteStore.getNoteVersion(syncRunner.authToken, currentNoteGuid, usn, true, true, true);
+ } else
+ historyNote = syncRunner.noteStore.getNote(syncRunner.authToken, currentNoteGuid, true,true,true,true);
+ } catch (EDAMUserException e) {
+ setMessage("EDAMUserException: " +e.getMessage());
+ waitCursor(false);
+ return null;
+ } catch (EDAMSystemException e) {
+ setMessage("EDAMSystemException: " +e.getMessage());
+ waitCursor(false);
+ return null;
+ } catch (EDAMNotFoundException e) {
+ setMessage("EDAMNotFoundException: " +e.getMessage());
+ waitCursor(false);
+ return null;
+ } catch (TException e) {
+ setMessage("EDAMTransactionException: " +e.getMessage());
+ waitCursor(false);
+ return null;
+ }
+
+ waitCursor(false);
+ if (historyNote != null)
+ historyWindow.setContent(historyNote);
+ return historyNote;
+ }
+ waitCursor(false);
+ return null;
+ }
+ private void loadHistoryWindowContent(Note note) {
+ note.setUpdateSequenceNum(0);
+ historyWindow.setContent(note);
+ }
+ @SuppressWarnings("unused")
+ private void restoreHistoryNoteAsNew() {
+ setMessage("Restoring as new note.");
+ duplicateNote(reloadHistoryWindow(historyWindow.historyCombo.currentText()));
+ setMessage("Note has been restored as a new note.");
+ }
+ @SuppressWarnings("unused")
+ private void restoreHistoryNote() {
+ setMessage("Restoring note.");
+ Note n = reloadHistoryWindow(historyWindow.historyCombo.currentText());
+ conn.getNoteTable().expungeNote(n.getGuid(), true, false);
+ n.setActive(true);
+ n.setDeleted(0);
+ for (int i=0; i<n.getResourcesSize(); i++) {
+ n.getResources().get(i).setActive(true);
+ conn.getNoteTable().noteResourceTable.saveNoteResource(n.getResources().get(i), true);
+ }
+ listManager.addNote(n);
+ conn.getNoteTable().addNote(n, true);
+ refreshEvernoteNote(true);
+ setMessage("Note has been restored.");
+ }
+
+
+
+ //**********************************************************
+ //**********************************************************
+ //* XML Modifying methods
+ //**********************************************************
+ //**********************************************************
+ // find the appropriate icon for an attachment
+ private String findIcon(String appl) {
+ logger.log(logger.HIGH, "Entering NeverNote.findIcon");
+ appl = appl.toLowerCase();
+ File f = new File(Global.getDirectoryPath()+"images"+File.separator +appl +".png");
+ if (f.exists())
+ return appl+".png";
+ logger.log(logger.HIGH, "Leaving NeverNote.findIcon");
+ return "attachment.png";
+ }
+ // Modify the en-media tag into an attachment
+ private void modifyApplicationTags(QDomDocument doc, QDomElement docElem, QDomElement enmedia, QDomAttr hash, String appl) {
+ logger.log(logger.HIGH, "Entering NeverNote.modifyApplicationTags");
+ if (appl.equalsIgnoreCase("vnd.evernote.ink"))
+ inkNote = true;
+ String resGuid = conn.getNoteTable().noteResourceTable.getNoteResourceGuidByHashHex(currentNote.getGuid(), hash.value());
+ Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(resGuid, false);
+ if (r == null || r.getData() == null)
+ resourceErrorMessage();
+ if (r!= null) {
+ if (r.getData()!=null) {
+ // Did we get a generic applicaiton? Then look at the file name to
+ // try and find a good application type for the icon
+ if (appl.equalsIgnoreCase("octet-stream")) {
+ if (r.getAttributes() != null && r.getAttributes().getFileName() != null) {
+ String fn = r.getAttributes().getFileName();
+ int pos = fn.lastIndexOf(".");
+ if (pos > -1) {
+ appl = fn.substring(pos+1);
+ }
+ }
+ }
+
+ String fileDetails = null;
+ if (r.getAttributes() != null && r.getAttributes().getFileName() != null && !r.getAttributes().getFileName().equals(""))
+ fileDetails = r.getAttributes().getFileName();
+ String contextFileName;
+ String pathPrefix = Global.currentDir;
+ pathPrefix = Global.getDirectoryPath()+"res/";
+ if (fileDetails != null && !fileDetails.equals("")) {
+ enmedia.setAttribute("href", "nnres://" +r.getGuid() +Global.attachmentNameDelimeter +fileDetails);
+ contextFileName = Global.currentDir +"res/" +r.getGuid() +Global.attachmentNameDelimeter +fileDetails;
+ } else {
+ enmedia.setAttribute("href", "nnres://" +r.getGuid() +Global.attachmentNameDelimeter +appl);
+ contextFileName = pathPrefix+r.getGuid() +Global.attachmentNameDelimeter +appl;
+ }
+ contextFileName = contextFileName.replace("\\", "/");
+ enmedia.setAttribute("onContextMenu", "window.jambi.resourceContextMenu('" +contextFileName +"');");
+ if (fileDetails == null || fileDetails.equals(""))
+ fileDetails = "";
+ enmedia.setAttribute("en-tag", "en-media");
+ enmedia.setAttribute("guid", r.getGuid());
+ enmedia.setTagName("a");
+ QDomElement newText = doc.createElement("img");
+ boolean goodPreview = false;
+ String filePath = "";
+ if (appl.equalsIgnoreCase("pdf") && Global.pdfPreview()) {
+ String fileName;
+ Resource res = conn.getNoteTable().noteResourceTable.getNoteResource(r.getGuid(), true);
+ if (res.getAttributes() != null &&
+ res.getAttributes().getFileName() != null &&
+ !res.getAttributes().getFileName().trim().equals(""))
+ fileName = res.getGuid()+Global.attachmentNameDelimeter+res.getAttributes().getFileName();
+ else
+ fileName = res.getGuid()+".pdf";
+ QFile file = new QFile(Global.getDirectoryPath() +"res/"+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(res.getGuid(), true);
+ QByteArray binData = new QByteArray(resBinary.getData().getBody());
+ resBinary = null;
+ out.writeBytes(binData.toByteArray());
+ file.close();
+ PDFPreview pdfPreview = new PDFPreview();
+ goodPreview = pdfPreview.setupPreview(file.fileName(), appl,0);
+ if (goodPreview) {
+ QDomElement span = doc.createElement("span");
+ QDomElement table = doc.createElement("table");
+ span.setAttribute("pdfNavigationTable", "true");
+ QDomElement tr = doc.createElement("tr");
+ QDomElement td = doc.createElement("td");
+ QDomElement left = doc.createElement("img");
+ left.setAttribute("onMouseDown", "window.jambi.nextPage('" +file.fileName() +"')");
+ left.setAttribute("onMouseDown", "window.jambi.nextPage('" +file.fileName() +"')");
+ left.setAttribute("onMouseOver", "style.cursor='hand'");
+ QDomElement right = doc.createElement("img");
+ right.setAttribute("onMouseDown", "window.jambi.nextPage('" +file.fileName() +"')");
+ left.setAttribute("onMouseDown", "window.jambi.previousPage('" +file.fileName() +"')");
+ left.setAttribute("src", Global.currentDir+"images/small_left.png");
+ right.setAttribute("src", Global.currentDir+"images/small_right.png");
+ right.setAttribute("onMouseOver", "style.cursor='hand'");
+
+ table.appendChild(tr);
+ tr.appendChild(td);
+ td.appendChild(left);
+ td.appendChild(right);
+ span.appendChild(table);
+ enmedia.parentNode().insertBefore(span, enmedia);
+ }
+ filePath = fileName+".png";
+ }
+ String icon = findIcon(appl);
+ if (icon.equals("attachment.png"))
+ icon = findIcon(fileDetails.substring(fileDetails.indexOf(".")+1));
+ newText.setAttribute("src", Global.getDirectoryPath()+"images"+File.separator +icon);
+ if (goodPreview) {
+ newText.setAttribute("src", Global.getDirectoryPath()+"res/"+filePath);
+ newText.setAttribute("style", "border-style:solid; border-color:green; padding:0.5mm 0.5mm 0.5mm 0.5mm;");
+ }
+ newText.setAttribute("title", fileDetails);
+ enmedia.removeChild(enmedia.firstChild());
+
+ enmedia.appendChild(newText);
+ }
+ }
+ logger.log(logger.HIGH, "Leaving NeverNote.modifyApplicationTags");
+ }
+ // Modify the en-to tag into an input field
+ private void modifyTodoTags(QDomElement todo) {
+ logger.log(logger.HIGH, "Entering NeverNote.modifyTodoTags");
+ todo.setAttribute("type", "checkbox");
+ String checked = todo.attribute("checked");
+ todo.removeAttribute("checked");
+ if (checked.equalsIgnoreCase("true"))
+ todo.setAttribute("checked", "");
+ else
+ todo.setAttribute("unchecked","");
+ todo.setAttribute("value", checked);
+ todo.setAttribute("onClick", "value=checked;window.jambi.contentChanged(); ");
+ todo.setTagName("input");
+ logger.log(logger.HIGH, "Leaving NeverNote.modifyTodoTags");
+ }
+ // Modify any cached todo tags that may have changed
+ private String modifyCachedTodoTags(String note) {
+ logger.log(logger.HIGH, "Entering NeverNote.modifyCachedTodoTags");
+ StringBuffer html = new StringBuffer(note);
+ for (int i=html.indexOf("<input", 0); i>-1; i=html.indexOf("<input", i)) {
+ int endPos =html.indexOf(">",i+1);
+ String input = html.substring(i,endPos);
+ if (input.indexOf("value=\"true\"") > 0)
+ input = input.replace("unchecked=\"\"", "checked=\"\"");
+ else
+ input = input.replace("checked=\"\"", "unchecked=\"\"");
+ html.replace(i, endPos, input);
+ i++;
+ }
+ logger.log(logger.HIGH, "Leaving NeverNote.modifyCachedTodoTags");
+ return html.toString();
+ }
+ // Modify the en-media tag into an image tag so it can be displayed.
+ private void modifyImageTags(QDomElement docElem, QDomElement enmedia, QDomAttr hash) {
+ logger.log(logger.HIGH, "Entering NeverNote.modifyImageTags");
+ String type = enmedia.attribute("type");
+ if (type.startsWith("image/"))
+ type = "."+type.substring(6);
+ else
+ type="";
+
+ String resGuid = conn.getNoteTable().noteResourceTable.getNoteResourceGuidByHashHex(currentNoteGuid, hash.value());
+ QFile tfile = new QFile(Global.getDirectoryPath()+"res"+File.separator +resGuid+type);
+ if (!tfile.exists()) {
+ Resource r = null;
+ if (resGuid != null)
+ r = conn.getNoteTable().noteResourceTable.getNoteResource(resGuid,true);
+ if (r==null || r.getData() == null || r.getData().getBody().length == 0)
+ resourceErrorMessage();
+ if (r!= null && r.getData() != null && r.getData().getBody().length > 0) {
+ tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));
+ QByteArray binData = new QByteArray(r.getData().getBody());
+ tfile.write(binData);
+ tfile.close();
+ enmedia.setAttribute("src", QUrl.fromLocalFile(tfile.fileName()).toString());
+ enmedia.setAttribute("en-tag", "en-media");
+ enmedia.setNodeValue("");
+ enmedia.setAttribute("guid", r.getGuid());
+ enmedia.setTagName("img");
+ }
+ }
+ enmedia.setAttribute("src", QUrl.fromLocalFile(tfile.fileName()).toString());
+ enmedia.setAttribute("en-tag", "en-media");
+ enmedia.setAttribute("onContextMenu", "window.jambi.imageContextMenu('" +tfile.fileName() +"');");
+ enmedia.setNodeValue("");
+ enmedia.setAttribute("guid", resGuid);
+ enmedia.setTagName("img");
+
+ logger.log(logger.HIGH, "Leaving NeverNote.modifyImageTags");
+ }
+ // Modify tags from Evernote specific things to XHTML tags.
+ private QDomDocument modifyTags(QDomDocument doc) {
+ logger.log(logger.HIGH, "Entering NeverNote.modifyTags");
+ if (tempFiles == null)
+ tempFiles = new ArrayList<QTemporaryFile>();
+ tempFiles.clear();
+ QDomElement docElem = doc.documentElement();
+
+ // Modify en-media tags
+ QDomNodeList anchors = docElem.elementsByTagName("en-media");
+ int enMediaCount = anchors.length();
+ for (int i=enMediaCount-1; i>=0; i--) {
+ QDomElement enmedia = anchors.at(i).toElement();
+ if (enmedia.hasAttribute("type")) {
+ QDomAttr attr = enmedia.attributeNode("type");
+ QDomAttr hash = enmedia.attributeNode("hash");
+ String[] type = attr.nodeValue().split("/");
+ String appl = type[1];
+
+ if (type[0] != null) {
+ if (type[0].equals("image")) {
+ modifyImageTags(docElem, enmedia, hash);
+ }
+ if (!type[0].equals("image")) {
+ modifyApplicationTags(doc, docElem, enmedia, hash, appl);
+ }
+ }
+ }
+ }
+
+ // Modify todo tags
+ anchors = docElem.elementsByTagName("en-todo");
+ int enTodoCount = anchors.length();
+ for (int i=enTodoCount-1; i>=0; i--) {
+ QDomElement enmedia = anchors.at(i).toElement();
+ modifyTodoTags(enmedia);
+ }
+
+ // Modify en-crypt tags
+ anchors = docElem.elementsByTagName("en-crypt");
+ int enCryptLen = anchors.length();
+ for (int i=enCryptLen-1; i>=0; i--) {
+ QDomElement enmedia = anchors.at(i).toElement();
+ enmedia.setAttribute("contentEditable","false");
+ enmedia.setAttribute("src", Global.getDirectoryPath()+"images/encrypt.png");
+ enmedia.setAttribute("en-tag","en-crypt");
+ enmedia.setAttribute("alt", enmedia.text());
+ Global.cryptCounter++;
+ enmedia.setAttribute("id", "crypt"+Global.cryptCounter.toString());
+ String encryptedText = enmedia.text();
+
+ // If the encryption string contains crlf at the end, remove them because they mess up the javascript.
+ if (encryptedText.endsWith("\n"))
+ encryptedText = encryptedText.substring(0,encryptedText.length()-1);
+ if (encryptedText.endsWith("\r"))
+ encryptedText = encryptedText.substring(0,encryptedText.length()-1);
+
+ // Add the commands
+ String hint = enmedia.attribute("hint");
+ hint = hint.replace("'","'");
+ enmedia.setAttribute("onClick", "window.jambi.decryptText('crypt"+Global.cryptCounter.toString()+"', '"+encryptedText+"', '"+hint+"');");
+ enmedia.setAttribute("onMouseOver", "style.cursor='hand'");
+ enmedia.setTagName("img");
+ enmedia.removeChild(enmedia.firstChild()); // Remove the actual encrypted text
+ }
+
+ logger.log(logger.HIGH, "Leaving NeverNote.modifyTags");
+ return doc;
+ }
+ // Rebuild the note HTML to something usable
+ private String rebuildNoteHTML(String noteGuid, String note) {
+ logger.log(logger.HIGH, "Entering NeverNote.rebuildNoteHTML");
+ logger.log(logger.EXTREME, "Note guid: " +noteGuid);
+ logger.log(logger.EXTREME, "Note Text:" +note);
+ QDomDocument doc = new QDomDocument();
+ QDomDocument.Result result = doc.setContent(note);
+ if (!result.success) {
+ logger.log(logger.MEDIUM, tr("Parse error when rebuilding HTML"));
+ logger.log(logger.MEDIUM, tr("Note guid: " +noteGuid));
+ logger.log(logger.EXTREME, tr("Start of unmodified note HTML"));
+ logger.log(logger.EXTREME, note);
+ logger.log(logger.EXTREME, tr("End of unmodified note HTML"));
+ return note;
+ }
+
+ if (tempFiles == null)
+ tempFiles = new ArrayList<QTemporaryFile>();
+ tempFiles.clear();
+
+ doc = modifyTags(doc);
+ doc = addHilight(doc);
+ QDomElement docElem = doc.documentElement();
+ docElem.setTagName("Body");
+// docElem.setAttribute("bgcolor", "green");
+ logger.log(logger.EXTREME, "Rebuilt HTML:");
+ logger.log(logger.EXTREME, doc.toString());
+ logger.log(logger.HIGH, "Leaving NeverNote.rebuildNoteHTML");
+ // Fix the stupid problem where inserting an <img> tag after an <a> tag (which is done
+ // to get the <en-media> application tag to work properly) causes spaces to be inserted
+ // between the <a> & <img>. This messes things up later. This is an ugly hack.
+ StringBuffer html = new StringBuffer(doc.toString());
+ for (int i=html.indexOf("<a en-tag=\"en-media\" ", 0); i>-1; i=html.indexOf("<a en-tag=\"en-media\" ", i)) {
+ i=html.indexOf(">\n",i+1);
+ int z = html.indexOf("<img",i);
+ for (int j=z-1; j>i; j--)
+ html.deleteCharAt(j);
+ i=html.indexOf("/>", z+1);
+ z = html.indexOf("</a>",i);
+ for (int j=z-1; j>i+1; j--)
+ html.deleteCharAt(j);
+ }
+ return html.toString();
+ }
+ // Scan and do hilighting of words
+ private QDomDocument addHilight(QDomDocument doc) {
+ EnSearch e = listManager.getEnSearch();
+ if (e.hilightWords == null || e.hilightWords.size() == 0)
+ return doc;
+ XMLInsertHilight hilight = new XMLInsertHilight(doc, listManager.getEnSearch().hilightWords);
+ return hilight.getDoc();
+ }
+
+ // An error has happended fetching a resource. let the user know
+ private void resourceErrorMessage() {
+ if (inkNote)
+ return;
+ QMessageBox.information(this, tr("DOUGH!!!"), tr("Well, this is embarrassing."+
+ "\n\nSome attachments or images for this note appear to be missing from my database.\n"+
+ "In a perfect world this wouldn't happen, but it has.\n" +
+ "It is embarasing when a program like me, designed to save all your\n"+
+ "precious data, has a problem finding data.\n\n" +
+ "I guess life isn't fair, but I'll survive. Somehow...\n\n" +
+ "In the mean time, I'm not going to let you make changes to this note.\n" +
+ "Don't get angry. I'm doing it to prevent you from messing up\n"+
+ "this note on the Evernote servers. Sorry."+
+ "\n\nP.S. You might want to re-synchronize to see if it corrects this problem.\nWho knows, you might get lucky."));
+ inkNote = true;
+//// browserWindow.setEnabled(false);
+ browserWindow.setReadOnly(true);
+ }
+
+
+
+
+ //**********************************************************
+ //**********************************************************
+ //* Timer functions
+ //**********************************************************
+ //**********************************************************
+ // We should now do a sync with Evernote
+ private void syncTimer() {
+ logger.log(logger.EXTREME, "Entering NeverNote.syncTimer()");
+ syncRunner.syncNeeded = true;
+ syncRunner.disableUploads = Global.disableUploads;
+ syncStart();
+ logger.log(logger.EXTREME, "Leaving NeverNote.syncTimer()");
+ }
+ private void syncStart() {
+ logger.log(logger.EXTREME, "Entering NeverNote.syncStart()");
+ saveNote();
+ if (!syncRunning && Global.isConnected) {
+ syncRunner.setConnected(true);
+ syncRunner.setKeepRunning(Global.keepRunning);
+ syncRunner.syncDeletedContent = Global.synchronizeDeletedContent();
+
+ if (syncThreadsReady > 0) {
+ saveNoteIndexWidth();
+ if (syncRunner.addWork("SYNC")) {
+ syncRunning = true;
+ syncRunner.syncNeeded = true;
+ syncThreadsReady--;
+ }
+ }
+ }
+ logger.log(logger.EXTREME, "Leaving NeverNote.syncStart");
+ }
+ @SuppressWarnings("unused")
+ private void syncThreadComplete(Boolean refreshNeeded) {
+ setMessage("Finalizing Synchronization");
+ syncThreadsReady++;
+ syncRunning = false;
+ syncRunner.syncNeeded = false;
+ synchronizeAnimationTimer.stop();
+ noteIndexUpdated(true);
+ synchronizeButton.setIcon(synchronizeAnimation.get(0));
+ saveNote();
+// noteTableView.selectionModel().selectionChanged.disconnect(this, "noteTableSelection()");
+ noteTableView.selectionModel().blockSignals(true);
+ scrollToGuid(currentNoteGuid);
+ noteTableView.selectionModel().blockSignals(false);
+// noteTableView.selectionModel().selectionChanged.connect(this, "noteTableSelection()");
+// indexRunner.setKeepRunning(Global.keepRunning);
+
+ // Reload the unindexed table If the dbthread is dead, we are probably shutting down.
+ if (!dbThread.isAlive())
+ return;
+ listManager.setUnsynchronizedNotes(conn.getNoteTable().getUnsynchronizedGUIDs());
+ for (int i=0; i<noteTableView.model.rowCount(); i++) {
+ QModelIndex modelIndex = noteTableView.model.index(i, Global.noteTableGuidPosition);
+ if (modelIndex != null) {
+ SortedMap<Integer, Object> ix = noteTableView.model.itemData(modelIndex);
+ String tableGuid = (String)ix.values().toArray()[0];
+ String synch = "true";
+ for (int j=0; j<listManager.getUnsynchronizedNotes().size(); j++) {
+ if (listManager.getUnsynchronizedNotes().get(j).equalsIgnoreCase(tableGuid)) {
+ synch = "false";
+ j = listManager.getUnsynchronizedNotes().size();
+ }
+ }
+ noteTableView.model.setData(i, Global.noteTableSynchronizedPosition, synch);
+ }
+ }
+ refreshEvernoteNote(false);
+ scrollToGuid(currentNoteGuid);
+ setMessage("Synchronization Complete");
+ logger.log(logger.MEDIUM, "Sync complete.");
+ }
+// public void setSequenceDate(long t) {
+// Global.setSequenceDate(t);
+// }
+ public void saveUploadAmount(long t) {
+ Global.saveUploadAmount(t);
+ }
+// public void setUpdateSequenceNumber(int t) {
+// Global.setUpdateSequenceNumber(t);
+// }
+ public void saveUserInformation(User user) {
+ Global.saveUserInformation(user);
+ }
+ public void saveEvernoteUpdateCount(int i) {
+ Global.saveEvernoteUpdateCount(i);
+ }
+ public void refreshLists() {
+ logger.log(logger.EXTREME, "Entering NeverNote.refreshLists");
+ updateQuotaBar();
+ listManager.refreshLists(currentNote, noteDirty, browserWindow.getContent());
+ tagIndexUpdated(true);
+ notebookIndexUpdated();
+ savedSearchIndexUpdated();
+ listManager.loadNotesIndex();
+
+ noteTableView.selectionModel().blockSignals(true);
+ noteIndexUpdated(true);
+ noteTableView.selectionModel().blockSignals(false);
+ logger.log(logger.EXTREME, "Leaving NeverNote.refreshLists");
+ }
+
+
+ @SuppressWarnings("unused")
+ private void authTimer() {
+ Calendar cal = Calendar.getInstance();
+
+ // If we are not connected let's get out of here
+ if (!Global.isConnected)
+ return;
+
+ // If this is the first time through, then we need to set this
+ // if (syncRunner.authRefreshTime == 0 || cal.getTimeInMillis() > syncRunner.authRefreshTime)
+// syncRunner.authRefreshTime = cal.getTimeInMillis();
+
+// long now = new Date().getTime();
+// if (now > Global.authRefreshTime && Global.isConnected) {
+ syncRunner.authRefreshNeeded = true;
+ syncStart();
+// }
+ }
+ @SuppressWarnings("unused")
+ private void authRefreshComplete(boolean goodSync) {
+ logger.log(logger.EXTREME, "Entering NeverNote.authRefreshComplete");
+ Global.isConnected = syncRunner.isConnected;
+ if (goodSync) {
+// authTimer.start((int)syncRunner.authTimeRemaining/4);
+ authTimer.start(1000*60*15);
+ logger.log(logger.LOW, "Authentication token has been renewed");
+// setMessage("Authentication token has been renewed.");
+ } else {
+ authTimer.start(1000*60*5);
+ logger.log(logger.LOW, "Authentication token renew has failed - retry in 5 minutes.");
+// setMessage("Authentication token renew has failed - retry in 5 minutes.");
+ }
+ logger.log(logger.EXTREME, "Leaving NeverNote.authRefreshComplete");
+ }
+
+
+ @SuppressWarnings("unused")
+ private synchronized void indexTimer() {
+ logger.log(logger.EXTREME, "Index timer activated. Sync running="+syncRunning);
+ if (syncRunning)
+ return;
+ // Look for any unindexed notes. We only refresh occasionally
+ // and do one at a time to keep overhead down.
+ if (!indexDisabled && indexRunner.getWorkQueueSize() == 0) {
+ List<String> notes = conn.getNoteTable().getNextUnindexed(1);
+ String unindexedNote = null;
+ if (notes.size() > 0)
+ unindexedNote = notes.get(0);
+ if (unindexedNote != null && Global.keepRunning) {
+ indexNoteContent(unindexedNote);
+ }
+ if (notes.size()>0) {
+ indexTimer.setInterval(100);
+ return;
+ }
+ List<String> unindexedResources = conn.getNoteTable().noteResourceTable.getNextUnindexed(1);
+ if (unindexedResources.size() > 0 && indexRunner.getWorkQueueSize() == 0) {
+ String unindexedResource = unindexedResources.get(0);
+ if (unindexedResource != null && Global.keepRunning) {
+ indexNoteResource(unindexedResource);
+ }
+ }
+ if (unindexedResources.size() > 0) {
+ indexTimer.setInterval(100);
+ return;
+ } else {
+ indexTimer.setInterval(indexTime);
+ }
+ if (indexRunning) {
+ setMessage("Index completed.");
+ logger.log(logger.LOW, "Indexing has completed.");
+ indexRunning = false;
+ indexTimer.setInterval(indexTime);
+ }
+ }
+ logger.log(logger.EXTREME, "Leaving neverNote index timer");
+ }
+ private synchronized void indexNoteContent(String unindexedNote) {
+ logger.log(logger.EXTREME, "Entering NeverNote.indexNoteContent()");
+ logger.log(logger.MEDIUM, "Unindexed Note found: "+unindexedNote);
+ indexRunner.setIndexType(indexRunner.CONTENT);
+ indexRunner.addWork("CONTENT "+unindexedNote);
+ if (!indexRunning) {
+ setMessage("Indexing notes.");
+ logger.log(logger.LOW, "Beginning to index note contents.");
+ indexRunning = true;
+ }
+ logger.log(logger.EXTREME, "Leaving NeverNote.indexNoteContent()");
+ }
+ private synchronized void indexNoteResource(String unindexedResource) {
+ logger.log(logger.EXTREME, "Leaving NeverNote.indexNoteResource()");
+ indexRunner.addWork(new String("RESOURCE "+unindexedResource));
+ if (!indexRunning) {
+ setMessage("Indexing notes.");
+ indexRunning = true;
+ }
+ logger.log(logger.EXTREME, "Leaving NeverNote.indexNoteResource()");
+ }
+ @SuppressWarnings("unused")
+ private void indexThreadComplete(String guid) {
+ logger.log(logger.MEDIUM, "Index complete for "+guid);
+ }
+ @SuppressWarnings("unused")
+ private synchronized void toggleNoteIndexing() {
+ logger.log(logger.HIGH, "Entering NeverNote.toggleIndexing");
+ indexDisabled = !indexDisabled;
+ if (!indexDisabled)
+ setMessage("Indexing is now enabled.");
+ else
+ setMessage("Indexing is now disabled.");
+ menuBar.disableIndexing.setChecked(indexDisabled);
+ logger.log(logger.HIGH, "Leaving NeverNote.toggleIndexing");
+ }
+
+ @SuppressWarnings("unused")
+ private void threadMonitorCheck() {
+ int MAX=3;
+
+
+ boolean alive;
+ alive = listManager.threadCheck(Global.tagCounterThreadId);
+ if (!alive) {
+ tagDeadCount++;
+ if (tagDeadCount > MAX)
+ QMessageBox.information(this, "A thread his died.", "It appears as the tag counter thread has died. I recommend "+
+ "checking stopping NeverNote, saving the logs for later viewing, and restarting. Sorry.");
+ } else
+ tagDeadCount=0;
+
+ alive = listManager.threadCheck(Global.notebookCounterThreadId);
+ if (!alive) {
+ notebookThreadDeadCount++;
+ QMessageBox.information(this, "A thread his died.", "It appears as the notebook counter thread has died. I recommend "+
+ "checking stopping NeverNote, saving the logs for later viewing, and restarting. Sorry.");
+ } else
+ notebookThreadDeadCount=0;
+
+ alive = listManager.threadCheck(Global.trashCounterThreadId);
+ if (!alive) {
+ trashDeadCount++;
+ QMessageBox.information(this, "A thread his died.", "It appears as the trash counter thread has died. I recommend "+
+ "checking stopping NeverNote, saving the logs for later viewing, and restarting. Sorry.");
+ } else
+ trashDeadCount = 0;
+
+ alive = listManager.threadCheck(Global.saveThreadId);
+ if (!alive) {
+ saveThreadDeadCount++;
+ QMessageBox.information(this, "A thread his died.", "It appears as the note saver thread has died. I recommend "+
+ "checking stopping NeverNote, saving the logs for later viewing, and restarting. Sorry.");
+ } else
+ saveThreadDeadCount=0;
+
+ if (!dbThread.isAlive()) {
+ dbThreadDeadCount++;
+ QMessageBox.information(this, "A thread his died.", "It appears as the database thread has died. I recommend "+
+ "checking stopping NeverNote, saving the logs for later viewing, and restarting. Sorry.");
+ } else
+ dbThreadDeadCount=0;
+
+ if (!syncThread.isAlive()) {
+ syncThreadDeadCount++;
+ QMessageBox.information(this, "A thread his died.", "It appears as the synchronization thread has died. I recommend "+
+ "checking stopping NeverNote, saving the logs for later viewing, and restarting. Sorry.");
+ } else
+ syncThreadDeadCount=0;
+
+ if (!indexThread.isAlive()) {
+ indexThreadDeadCount++;
+ QMessageBox.information(this, "A thread his died.", "It appears as the index thread has died. I recommend "+
+ "checking stopping NeverNote, saving the logs for later viewing, and restarting. Sorry.");
+ } else
+ indexThreadDeadCount=0;
+
+
+ }
+
+
+
+ //**************************************************
+ //* Backup & Restore
+ //**************************************************
+ @SuppressWarnings("unused")
+ private void databaseBackup() {
+ QFileDialog fd = new QFileDialog(this);
+ fd.setFileMode(FileMode.AnyFile);
+ fd.setConfirmOverwrite(true);
+ fd.setWindowTitle("Backup Database");
+ fd.setFilter(tr("NeverNote Export (*.nnex);;All Files (*.*)"));
+ fd.setAcceptMode(AcceptMode.AcceptSave);
+ fd.setDirectory(System.getProperty("user.home"));
+ if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
+ return;
+ }
+
+
+ waitCursor(true);
+ setMessage("Backing up database");
+ saveNote();
+// conn.backupDatabase(Global.getUpdateSequenceNumber(), Global.getSequenceDate());
+
+ ExportData noteWriter = new ExportData(conn, true);
+ String fileName = fd.selectedFiles().get(0);
+
+ if (!fileName.endsWith(".nnex"))
+ fileName = fileName +".nnex";
+ noteWriter.exportData(fileName);
+ setMessage("Database backup completed.");
+
+
+ waitCursor(false);
+ }
+ @SuppressWarnings("unused")
+ private void databaseRestore() {
+ if (QMessageBox.question(this, "Confirmation",
+ "This is used to restore a database from backups.\n" +
+ "It is HIGHLY recommened that this only be used to populate\n" +
+ "an empty database. Restoring into a database that\n already has data" +
+ " can cause problems.\n\nAre you sure you want to continue?",
+ QMessageBox.StandardButton.Yes,
+ QMessageBox.StandardButton.No)==StandardButton.No.value()) {
+ return;
+ }
+
+
+ QFileDialog fd = new QFileDialog(this);
+ fd.setFileMode(FileMode.ExistingFile);
+ fd.setConfirmOverwrite(true);
+ fd.setWindowTitle("Restore Database");
+ fd.setFilter(tr("NeverNote Export (*.nnex);;All Files (*.*)"));
+ fd.setAcceptMode(AcceptMode.AcceptOpen);
+ fd.setDirectory(System.getProperty("user.home"));
+ if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
+ return;
+ }
+
+
+ waitCursor(true);
+ setMessage("Restoring database");
+ ImportData noteReader = new ImportData(conn, true);
+ noteReader.importData(fd.selectedFiles().get(0));
+
+ if (noteReader.lastError != 0) {
+ setMessage(noteReader.getErrorMessage());
+ logger.log(logger.LOW, "Restore problem: " +noteReader.lastError);
+ waitCursor(false);
+ return;
+ }
+
+ listManager.loadNoteTitleColors();
+ refreshLists();
+ refreshEvernoteNote(true);
+ setMessage("Database has been restored.");
+ waitCursor(false);
+ }
+ @SuppressWarnings("unused")
+ private void exportNotes() {
+ QFileDialog fd = new QFileDialog(this);
+ fd.setFileMode(FileMode.AnyFile);
+ fd.setConfirmOverwrite(true);
+ fd.setWindowTitle("Backup Database");
+ fd.setFilter(tr("NeverNote Export (*.nnex);;All Files (*.*)"));
+ fd.setAcceptMode(AcceptMode.AcceptSave);
+ fd.setDirectory(System.getProperty("user.home"));
+ if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
+ return;
+ }
+
+
+ waitCursor(true);
+ setMessage("Exporting Notes");
+ saveNote();
+
+ if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
+ selectedNoteGUIDs.add(currentNoteGuid);
+
+ ExportData noteWriter = new ExportData(conn, false, selectedNoteGUIDs);
+ String fileName = fd.selectedFiles().get(0);
+
+ if (!fileName.endsWith(".nnex"))
+ fileName = fileName +".nnex";
+ noteWriter.exportData(fileName);
+ setMessage("Export completed.");
+
+
+ waitCursor(false);
+
+ }
+ @SuppressWarnings("unused")
+ private void importNotes() {
+ QFileDialog fd = new QFileDialog(this);
+ fd.setFileMode(FileMode.ExistingFile);
+ fd.setConfirmOverwrite(true);
+ fd.setWindowTitle("Import Notes");
+ fd.setFilter(tr("NeverNote Export (*.nnex);;All Files (*.*)"));
+ fd.setAcceptMode(AcceptMode.AcceptOpen);
+ fd.setDirectory(System.getProperty("user.home"));
+ if (fd.exec() == 0 || fd.selectedFiles().size() == 0) {
+ return;
+ }
+
+
+ waitCursor(true);
+ setMessage("Importing Notes");
+ saveNote();
+
+ if (selectedNoteGUIDs.size() == 0 && !currentNoteGuid.equals(""))
+ selectedNoteGUIDs.add(currentNoteGuid);
+
+ ImportData noteReader = new ImportData(conn, false);
+ String fileName = fd.selectedFiles().get(0);
+
+ if (!fileName.endsWith(".nnex"))
+ fileName = fileName +".nnex";
+ if (selectedNotebookGUIDs != null && selectedNotebookGUIDs.size() > 0)
+ noteReader.setNotebookGuid(selectedNotebookGUIDs.get(0));
+ else
+ noteReader.setNotebookGuid(listManager.getNotebookIndex().get(0).getGuid());
+
+ noteReader.importData(fileName);
+
+ if (noteReader.lastError != 0) {
+ setMessage(noteReader.getErrorMessage());
+ logger.log(logger.LOW, "Import problem: " +noteReader.lastError);
+ waitCursor(false);
+ return;
+ }
+
+ listManager.loadNoteTitleColors();
+ refreshLists();
+ refreshEvernoteNote(false);
+ setMessage("Notes have been imported.");
+ waitCursor(false);
+
+ setMessage("Import completed.");
+
+
+ waitCursor(false);
+
+ }
+
+ //**************************************************
+ //* Duplicate a note
+ //**************************************************
+ @SuppressWarnings("unused")
+ private void duplicateNote() {
+ saveNote();
+ duplicateNote(currentNoteGuid);
+ }
+
+
+
+ //**************************************************
+ //* Folder Imports
+ //**************************************************
+ public void setupFolderImports() {
+ List<WatchFolderRecord> records = conn.getWatchFolderTable().getAll();
+
+ if (importKeepWatcher == null)
+ importKeepWatcher = new QFileSystemWatcher();
+ if (importDeleteWatcher == null) {
+ importDeleteWatcher = new QFileSystemWatcher();
+ for (int i=0; i<records.size(); i++) {
+ if (!records.get(i).keep)
+ folderImportDelete(records.get(i).folder);
+ }
+ }
+
+
+
+// importKeepWatcher.addPath(records.get(i).folder.replace('\\', '/'));
+ for (int i=0; i<records.size(); i++) {
+ if (records.get(i).keep)
+ importKeepWatcher.addPath(records.get(i).folder);
+ else
+ importDeleteWatcher.addPath(records.get(i).folder);
+ }
+
+ importKeepWatcher.directoryChanged.connect(this, "folderImportKeep(String)");
+ importDeleteWatcher.directoryChanged.connect(this, "folderImportDelete(String)");
+
+ // Look at the files already there so we don't import them again if a new file is created
+ if (importedFiles == null) {
+ importedFiles = new ArrayList<String>();
+ for (int j=0; j<records.size(); j++) {
+ QDir dir = new QDir(records.get(j).folder);
+ List<QFileInfo> list = dir.entryInfoList();
+ for (int k=0; k<list.size(); k++) {
+ if (list.get(k).isFile())
+ importedFiles.add(list.get(k).absoluteFilePath());
+ }
+ }
+ }
+ }
+ public void folderImport() {
+ List<WatchFolderRecord> recs = conn.getWatchFolderTable().getAll();
+ WatchFolder dialog = new WatchFolder(recs, listManager.getNotebookIndex());
+ dialog.exec();
+ if (!dialog.okClicked())
+ return;
+
+ // We have some sort of update.
+ if (importKeepWatcher.directories().size() > 0)
+ importKeepWatcher.removePaths(importKeepWatcher.directories());
+ if (importDeleteWatcher.directories().size() > 0)
+ importDeleteWatcher.removePaths(importDeleteWatcher.directories());
+
+ conn.getWatchFolderTable().expungeAll();
+ // Start building from the table
+ for (int i=0; i<dialog.table.rowCount(); i++) {
+ QTableWidgetItem item = dialog.table.item(i, 0);
+ String dir = item.text();
+ item = dialog.table.item(i, 1);
+ String notebook = item.text();
+ item = dialog.table.item(i, 2);
+ boolean keep;
+ if (item.text().equalsIgnoreCase("Keep"))
+ keep = true;
+ else
+ keep = false;
+
+ String guid = conn.getNotebookTable().findNotebookByName(notebook);
+ conn.getWatchFolderTable().addWatchFolder(dir, guid, keep, 0);
+ }
+ setupFolderImports();
+ }
+
+ public void folderImportKeep(String dirName) throws NoSuchAlgorithmException {
+
+ String whichOS = System.getProperty("os.name");
+ if (whichOS.contains("Windows"))
+ dirName = dirName.replace('/','\\');
+
+ FileImporter importer = new FileImporter(logger, conn);
+
+ QDir dir = new QDir(dirName);
+ List<QFileInfo> list = dir.entryInfoList();
+ String notebook = conn.getWatchFolderTable().getNotebook(dirName);
+
+ for (int i=0; i<list.size(); i++){
+
+ boolean redundant = false;
+ // Check if we've already imported this one or if it existed before
+ for (int j=0; j<importedFiles.size(); j++) {
+ if (importedFiles.get(j).equals(list.get(i).absoluteFilePath()))
+ redundant = true;
+ }
+
+ if (!redundant) {
+ importer.setFileInfo(list.get(i));
+ importer.setFileName(list.get(i).absoluteFilePath());
+
+
+ if (list.get(i).isFile() && importer.isValidType()) {
+
+ if (!importer.importFile()) {
+ // If we can't get to the file, it is probably locked. We'll try again later.
+ logger.log(logger.LOW, "Unable to save externally edited file. Saving for later.");
+ importFilesKeep.add(list.get(i).absoluteFilePath());
+ return;
+ }
+
+ Note newNote = importer.getNote();
+ newNote.setNotebookGuid(notebook);
+ newNote.setTitle(dir.at(i));
+ listManager.addNote(newNote);
+ conn.getNoteTable().addNote(newNote, true);
+ listManager.getUnsynchronizedNotes().add(newNote.getGuid());
+ noteTableView.insertRow(listManager, newNote, true, -1);
+ listManager.updateNoteContent(newNote.getGuid(), importer.getNoteContent());
+ listManager.countNotebookResults(listManager.getNoteIndex());
+ importedFiles.add(list.get(i).absoluteFilePath());
+ }
+ }
+ }
+
+
+ }
+
+ public void folderImportDelete(String dirName) {
+
+ String whichOS = System.getProperty("os.name");
+ if (whichOS.contains("Windows"))
+ dirName = dirName.replace('/','\\');
+
+ FileImporter importer = new FileImporter(logger, conn);
+ QDir dir = new QDir(dirName);
+ List<QFileInfo> list = dir.entryInfoList();
+ String notebook = conn.getWatchFolderTable().getNotebook(dirName);
+
+ for (int i=0; i<list.size(); i++){
+ importer.setFileInfo(list.get(i));
+ importer.setFileName(list.get(i).absoluteFilePath());
+
+ if (list.get(i).isFile() && importer.isValidType()) {
+
+ if (!importer.importFile()) {
+ // If we can't get to the file, it is probably locked. We'll try again later.
+ logger.log(logger.LOW, "Unable to save externally edited file. Saving for later.");
+ importFilesKeep.add(list.get(i).absoluteFilePath());
+ return;
+ }
+
+ Note newNote = importer.getNote();
+ newNote.setNotebookGuid(notebook);
+ newNote.setTitle(dir.at(i));
+ listManager.addNote(newNote);
+ conn.getNoteTable().addNote(newNote, true);
+ listManager.getUnsynchronizedNotes().add(newNote.getGuid());
+ noteTableView.insertRow(listManager, newNote, true, -1);
+ listManager.updateNoteContent(newNote.getGuid(), importer.getNoteContent());
+ listManager.countNotebookResults(listManager.getNoteIndex());
+ dir.remove(dir.at(i));
+ }
+ }
+ }
+
+
+ //**************************************************
+ //* External events
+ //**************************************************
+ private void externalFileEdited(String fileName) throws NoSuchAlgorithmException {
+ logger.log(logger.HIGH, "Entering exernalFileEdited");
+
+ String dPath = Global.getDirectoryPath() + "res/";
+ dPath = dPath.replace('\\', '/');
+ String name = fileName.replace(dPath, "");
+ int pos = name.lastIndexOf('.');
+ String guid = name;
+ if (pos > -1) {
+ guid = guid.substring(0,pos);
+ }
+ pos = name.lastIndexOf(Global.attachmentNameDelimeter);
+ if (pos > -1) {
+ guid = name.substring(0, pos);
+ }
+
+ QFile file = new QFile(fileName);
+ if (!file.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly))) {
+ // If we can't get to the file, it is probably locked. We'll try again later.
+ logger.log(logger.LOW, "Unable to save externally edited file. Saving for later.");
+ externalFiles.add(fileName);
+ return;
+ }
+ QByteArray binData = file.readAll();
+ file.close();
+ if (binData.size() == 0) {
+ // If we can't get to the file, it is probably locked. We'll try again later.
+ logger.log(logger.LOW, "Unable to save externally edited file. Saving for later.");
+ externalFiles.add(fileName);
+ return;
+ }
+
+ Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
+ if (r==null)
+ r = conn.getNoteTable().noteResourceTable.getNoteResource(Global.resourceMap.get(guid), true);
+ if (r == null || r.getData() == null || r.getData().getBody() == null)
+ return;
+ String oldHash = Global.byteArrayToHexString(r.getData().getBodyHash());
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ md.update(binData.toByteArray());
+ byte[] hash = md.digest();
+ String newHash = Global.byteArrayToHexString(hash);
+ if (r.getNoteGuid().equalsIgnoreCase(currentNoteGuid)) {
+ updateResourceContentHash(r.getGuid(), oldHash, newHash);
+ }
+ conn.getNoteTable().updateResourceContentHash(r.getNoteGuid(), oldHash, newHash);
+ Data data = r.getData();
+ data.setBody(binData.toByteArray());
+ data.setBodyHash(hash);
+ logger.log(logger.LOW, "externalFileEdited: " +data.getSize() +" bytes");
+ r.setData(data);
+ conn.getNoteTable().noteResourceTable.updateNoteResource(r,true);
+
+ if (r.getNoteGuid().equals(currentNoteGuid)) {
+ QWebSettings.setMaximumPagesInCache(0);
+ QWebSettings.setObjectCacheCapacities(0, 0, 0);
+ refreshEvernoteNote(true);
+ browserWindow.getBrowser().triggerPageAction(WebAction.Reload);
+ }
+
+ logger.log(logger.HIGH, "Exiting externalFielEdited");
+ }
+ // This is a timer event that tries to save any external files that were edited. This
+ // is only needed if we couldn't save a file earlier.
+ public void externalFileEditedSaver() {
+ for (int i=externalFiles.size()-1; i>=0; i--) {
+ try {
+ logger.log(logger.MEDIUM, "Trying to save " +externalFiles.get(i));
+ externalFileEdited(externalFiles.get(i));
+ externalFiles.remove(i);
+ } catch (NoSuchAlgorithmException e) {e.printStackTrace();}
+ }
+ for (int i=0; i<importFilesKeep.size(); i++) {
+ try {
+ logger.log(logger.MEDIUM, "Trying to save " +importFilesKeep.get(i));
+ folderImportKeep(importFilesKeep.get(i));
+ importFilesKeep.remove(i);
+ } catch (NoSuchAlgorithmException e) {e.printStackTrace();}
+ }
+ for (int i=0; i<importFilesDelete.size(); i++) {
+ logger.log(logger.MEDIUM, "Trying to save " +importFilesDelete.get(i));
+ folderImportDelete(importFilesDelete.get(i));
+ importFilesDelete.remove(i);
+ }
+ }
+
+
+
+
+ // If an attachment on the current note was edited, we need to update the current notes's hash
+ // 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) {
+ int position = browserWindow.getContent().indexOf("en-tag=\"en-media\" guid=\""+guid+"\" type=");
+ int endPos;
+ for (;position>-1;) {
+ endPos = browserWindow.getContent().indexOf(">", position+1);
+ String oldSegment = browserWindow.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 = browserWindow.getContent().substring(0,position) +
+ newSegment +
+ browserWindow.getContent().substring(endPos);
+ browserWindow.getBrowser().setContent(new QByteArray(content));;
+ }
+
+ position = browserWindow.getContent().indexOf("en-tag=\"en-media\" guid=\""+guid+"\" type=", position+1);
+ }
+ }
+
+
+
+
+ //*************************************************
+ //* Check database userid & passwords
+ //*************************************************
+ public boolean databaseCheck(String url,String userid, String userPassword, String cypherPassword) {
+ Connection connection;
+
+ try {
+ Class.forName("org.h2.Driver");
+ } catch (ClassNotFoundException e1) {
+ e1.printStackTrace();
+ System.exit(16);
+ }
+
+ try {
+ String passwordString = null;
+ if (cypherPassword==null || cypherPassword.trim().equals(""))
+ passwordString = userPassword;
+ else
+ passwordString = cypherPassword+" "+userPassword;
+ connection = DriverManager.getConnection(url,userid,passwordString);
+ } catch (SQLException e) {
+ return false;
+ }
+ try {
+ connection.close();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ return true;
+ }
+
+}
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.dialog;\r
+\r
+\r
+import java.text.SimpleDateFormat;\r
+\r
+import com.evernote.edam.type.UserAttributes;\r
+import com.trolltech.qt.gui.QDialog;\r
+import com.trolltech.qt.gui.QGridLayout;\r
+import com.trolltech.qt.gui.QGroupBox;\r
+import com.trolltech.qt.gui.QHBoxLayout;\r
+import com.trolltech.qt.gui.QLabel;\r
+import com.trolltech.qt.gui.QPushButton;\r
+\r
+import cx.fbn.nevernote.Global;\r
+\r
+public class AccountDialog extends QDialog {\r
+\r
+ private final QPushButton ok;\r
+ \r
+ // Constructor\r
+ public AccountDialog() {\r
+ setWindowTitle("Account Information");\r
+ QGridLayout grid = new QGridLayout();\r
+ setLayout(grid);\r
+ QLabel premium;\r
+ if (Global.isPremium())\r
+ premium = new QLabel("Premium");\r
+ else\r
+ premium = new QLabel("Free");\r
+ \r
+ Long uploadAmt = Global.getUploadAmount();\r
+ Long uploadLimit = Global.getUploadLimit();\r
+ Long uploadLimitEnd = Global.getUploadLimitEnd();\r
+ Long pct;\r
+ if (uploadLimit > 0)\r
+ pct = uploadAmt*100 / uploadLimit;\r
+ else\r
+ pct = new Long(0);\r
+ String unit = " Bytes";\r
+ \r
+ if (uploadAmt > 0) {\r
+ uploadAmt = uploadAmt/1024;\r
+ unit = " KB";\r
+ }\r
+ if (uploadAmt >= 1024) {\r
+ uploadAmt = uploadAmt / 1024;\r
+ unit = " MB";\r
+ }\r
+ if (uploadLimit > 0)\r
+ uploadLimit = uploadLimit/1024/1024;\r
+ \r
+ \r
+ String fmt = Global.getDateFormat() + " " + Global.getTimeFormat();\r
+ String dateTimeFormat = new String(fmt);\r
+ SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);\r
+ StringBuilder endDate = new StringBuilder(simple.format(uploadLimitEnd));\r
+ \r
+ QGridLayout textGrid = new QGridLayout();\r
+ QGroupBox limitGroup = new QGroupBox(tr("Account:"));\r
+ textGrid.addWidget(new QLabel("Account Type:"), 1,1);\r
+ textGrid.addWidget(premium, 1, 2);\r
+ textGrid.addWidget(new QLabel("Limit:"), 2,1);\r
+ textGrid.addWidget(new QLabel(uploadLimit.toString() +" MB"),2,2);\r
+ textGrid.addWidget(new QLabel("Uploaded In This Period:"), 3,1);\r
+ textGrid.addWidget(new QLabel(uploadAmt.toString()+unit +" ("+pct+"%)"),3,2);\r
+ textGrid.addWidget(new QLabel("Current Cycle Ends:"), 4,1);\r
+ textGrid.addWidget(new QLabel(endDate.toString()),4,2);\r
+ limitGroup.setLayout(textGrid);\r
+\r
+ grid.addWidget(limitGroup, 1, 1);\r
+\r
+ UserAttributes attrib = Global.getUserAttributes();\r
+ QGridLayout attribGrid = new QGridLayout();\r
+ QGroupBox attribGroup = new QGroupBox(tr("User Attributes"));\r
+ attribGrid.addWidget(new QLabel(tr("Incoming Email:")), 1,1);\r
+ String server = Global.getServer();\r
+ if (server.startsWith("www."))\r
+ server = server.substring(4);\r
+ attribGrid.addWidget(new QLabel(attrib.getIncomingEmailAddress()+"@"+Global.getServer()), 1,2);\r
+ attribGroup.setLayout(attribGrid);\r
+ grid.addWidget(attribGroup, 2,1);\r
+\r
+ \r
+ QHBoxLayout buttonLayout = new QHBoxLayout();\r
+ ok = new QPushButton("OK");\r
+ ok.clicked.connect(this, "okPushed()");\r
+ buttonLayout.addStretch();\r
+ buttonLayout.addWidget(ok);\r
+ buttonLayout.addStretch();\r
+ grid.addLayout(buttonLayout,3,1);\r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void okPushed() {\r
+ this.close();\r
+ }\r
+ \r
+\r
+ public QPushButton getOkButton() {\r
+ return ok;\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.dialog;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.trolltech.qt.gui.QApplication;\r
+import com.trolltech.qt.gui.QCheckBox;\r
+import com.trolltech.qt.gui.QComboBox;\r
+import com.trolltech.qt.gui.QFormLayout;\r
+import com.trolltech.qt.gui.QGroupBox;\r
+import com.trolltech.qt.gui.QHBoxLayout;\r
+import com.trolltech.qt.gui.QLabel;\r
+import com.trolltech.qt.gui.QSpinBox;\r
+import com.trolltech.qt.gui.QStyleFactory;\r
+import com.trolltech.qt.gui.QVBoxLayout;\r
+import com.trolltech.qt.gui.QWidget;\r
+\r
+import cx.fbn.nevernote.Global;\r
+\r
+public class ConfigAppearancePage extends QWidget {\r
+ private final QComboBox dateFormat;\r
+ private final QComboBox timeFormat;\r
+ private final QComboBox styleFormat;\r
+ private final QComboBox tagBehavior;\r
+ private final QCheckBox standardPalette;\r
+ private final QCheckBox showSplashScreen;\r
+ private final QCheckBox showTrayIcon;\r
+ private final QCheckBox verifyDelete;\r
+ private final QCheckBox pdfPreview;\r
+ private final QCheckBox mimicEvernote;\r
+ private final QSpinBox autoSaveInterval;\r
+ \r
+ private final List<String> tformats;\r
+ private final List<String> dformats;\r
+ \r
+ public ConfigAppearancePage(QWidget parent) {\r
+// super(parent);\r
+ \r
+ dformats = new ArrayList<String>();\r
+ tformats = new ArrayList<String>();\r
+ \r
+ dformats.add("MM/dd/yy - 12/31/09");\r
+ dformats.add("MM/dd/yyyy - 12/31/2009");\r
+ dformats.add("dd/MM/yy - 31/12/09");\r
+ dformats.add("dd/MM/yyyy - 31/12/2009");\r
+ dformats.add("yyyy/MM/dd - 2009/12/31");\r
+ dformats.add("yy/MM/dd - 9/12/31");\r
+ \r
+ tformats.add("HH:mm:ss - 2:13:01");\r
+ tformats.add("HH:mm:ss a - 2:13:01 am");\r
+ tformats.add("HH:mm - 2:13");\r
+ tformats.add("HH:mm a - 2:13 am");\r
+\r
+ \r
+ // Style sheet formats\r
+ List<String> styles = QStyleFactory.keys();\r
+ QGroupBox styleGroup = new QGroupBox(tr("GUI Style"));\r
+ styleFormat = new QComboBox(); \r
+ styleFormat.addItems(styles);\r
+ styleFormat.activated.connect(this, "styleSelected(String)");\r
+ \r
+ standardPalette = new QCheckBox();\r
+ standardPalette.setText("Use standard palette");\r
+ standardPalette.clicked.connect(this, "standardPaletteChanged()");\r
+\r
+ QFormLayout styleLayout = new QFormLayout();\r
+ styleLayout.addWidget(styleFormat);\r
+ styleLayout.addWidget(standardPalette);\r
+ \r
+ styleGroup.setLayout(styleLayout);\r
+\r
+ QGroupBox tagBehaviorGroup = new QGroupBox(tr("Tag Behavior"));\r
+ tagBehavior = new QComboBox();\r
+ tagBehavior.addItem(tr("Do nothing"));\r
+ tagBehavior.addItem(tr("Count tags & do not hide inactive"));\r
+ tagBehavior.addItem(tr("Count tags & hide inactive"));\r
+ tagBehavior.addItem(tr("Color active tags"));\r
+ \r
+ QFormLayout tagLayout = new QFormLayout();\r
+ tagLayout.addWidget(tagBehavior);\r
+ tagBehaviorGroup.setLayout(tagLayout);\r
+ \r
+ \r
+ \r
+ // Date/Time settings\r
+ QGroupBox datetimeGroup = new QGroupBox(tr("Date/Time Format"));\r
+ dateFormat = new QComboBox(); \r
+ for (int i=0; i<dformats.size(); i++) {\r
+ dateFormat.addItem(tr(dformats.get(i)));\r
+ }\r
+ \r
+ timeFormat = new QComboBox(); \r
+ for (int i=0; i<tformats.size(); i++) {\r
+ timeFormat.addItem(tr(tformats.get(i)));\r
+ }\r
+\r
+ QFormLayout formatLayout = new QFormLayout();\r
+ formatLayout.addWidget(dateFormat);\r
+ formatLayout.addWidget(timeFormat);\r
+ datetimeGroup.setLayout(formatLayout);\r
+ \r
+ mimicEvernote = new QCheckBox("Mimic Evernote Selection Behavior (Requires Restart)");\r
+ showSplashScreen = new QCheckBox("Show Splash Screen on Startup");\r
+ showTrayIcon = new QCheckBox("Show Tray Icon");\r
+ verifyDelete = new QCheckBox("Verify Deletes");\r
+ pdfPreview = new QCheckBox("Display PDF Documents Inline");\r
+ \r
+ QHBoxLayout autoSaveLayout = new QHBoxLayout();\r
+ autoSaveLayout.addWidget(new QLabel("Automatic Save Interval (in Minutes)"));\r
+ autoSaveInterval = new QSpinBox();\r
+ autoSaveLayout.addWidget(autoSaveInterval);\r
+ autoSaveInterval.setMaximum(1440);\r
+ autoSaveInterval.setMinimum(0);\r
+ \r
+ QVBoxLayout mainLayout = new QVBoxLayout();\r
+ mainLayout.addWidget(styleGroup);\r
+ mainLayout.addWidget(datetimeGroup);\r
+ mainLayout.addLayout(autoSaveLayout);\r
+ mainLayout.addWidget(tagBehaviorGroup);\r
+ mainLayout.addWidget(mimicEvernote); \r
+ mainLayout.addWidget(showTrayIcon);\r
+ mainLayout.addWidget(showSplashScreen);\r
+ mainLayout.addWidget(verifyDelete);\r
+ mainLayout.addWidget(pdfPreview);\r
+ mainLayout.addStretch(1);\r
+ setLayout(mainLayout);\r
+\r
+\r
+ }\r
+\r
+ \r
+ //*****************************************\r
+ //* date format get/set methods \r
+ //*****************************************\r
+ public void setDateFormat(String id) {\r
+ for (int i=0; i<dformats.size(); i++) {\r
+ String d = dformats.get(i);\r
+ if (d.substring(0,id.length()).equals(id))\r
+ dateFormat.setCurrentIndex(i);\r
+ }\r
+ }\r
+ public String getDateFormat() {\r
+ int i = dateFormat.currentIndex();\r
+ return dateFormat.itemText(i); \r
+ }\r
+ \r
+\r
+ \r
+ //*****************************************\r
+ //* time format get/set methods \r
+ //*****************************************\r
+ public void setTimeFormat(String id) {\r
+ for (int i=0; i<tformats.size(); i++) {\r
+ String d = tformats.get(i);\r
+ int dash = d.indexOf("-");\r
+ d = d.substring(0,dash-1);\r
+ if (d.equals(id)) {\r
+ timeFormat.setCurrentIndex(i);\r
+ return;\r
+ }\r
+ }\r
+ }\r
+ public String getTimeFormat() {\r
+ int i = timeFormat.currentIndex();\r
+ return timeFormat.itemText(i); \r
+ }\r
+\r
+ \r
+ //*****************************************\r
+ //* gui style format get/set methods \r
+ //*****************************************\r
+ public void setStyle(String id) {\r
+ for (int i=0; i<styleFormat.count(); i++) {\r
+ String d = styleFormat.itemText(i);\r
+ if (d.equals(id))\r
+ styleFormat.setCurrentIndex(i);\r
+ }\r
+ }\r
+ public String getStyle() {\r
+ int i = styleFormat.currentIndex();\r
+ return styleFormat.itemText(i); \r
+ }\r
+ \r
+ //*****************************************\r
+ //* palette style get/set methods \r
+ //*****************************************\r
+ public void setStandardPalette(boolean value) {\r
+ standardPalette.setChecked(value);\r
+ }\r
+ public boolean getStandardPalette() {\r
+ return standardPalette.isChecked(); \r
+ }\r
+ \r
+ //*******************************************\r
+ //* Show/Hide tray icon get/set\r
+ //*******************************************\r
+ public void setShowTrayIcon(boolean val) {\r
+ showTrayIcon.setChecked(val); \r
+ }\r
+ public boolean getShowTrayIcon() {\r
+ return showTrayIcon.isChecked();\r
+ }\r
+ \r
+ \r
+ //*****************************************\r
+ //* Show the splash screen on startup\r
+ //*****************************************\r
+ public void setShowSplashScreen(boolean val) {\r
+ showSplashScreen.setChecked(val);\r
+ }\r
+ public boolean getShowSplashScreen() {\r
+ return showSplashScreen.isChecked();\r
+ }\r
+ \r
+ //*******************************************\r
+ //* verify deletes get/set\r
+ //*******************************************\r
+ public void setVerifyDelete(boolean val) {\r
+ verifyDelete.setChecked(val); \r
+ }\r
+ public boolean getVerifyDelete() {\r
+ return verifyDelete.isChecked();\r
+ }\r
+ \r
+ \r
+ //*******************************************\r
+ //* Show/Hide tray icon get/set\r
+ //*******************************************\r
+ public void setPdfPreview(boolean val) {\r
+ pdfPreview.setChecked(val); \r
+ }\r
+ public boolean getPdfPreview() {\r
+ return pdfPreview.isChecked();\r
+ }\r
+\r
+ \r
+ //********************************************\r
+ //* Listeners for palette & style changes\r
+ //********************************************\r
+ \r
+ public void styleSelected(String style) {\r
+ QApplication.setStyle(style);\r
+ QApplication.setPalette(QApplication.style().standardPalette());\r
+ }\r
+ \r
+ public void standardPaletteChanged() {\r
+ if (standardPalette.isChecked())\r
+ QApplication.setPalette(QApplication.style().standardPalette());\r
+ else\r
+ QApplication.setPalette(Global.originalPalette);\r
+ \r
+ }\r
+\r
+ \r
+ //*****************************************\r
+ //* automatic save timer\r
+ //*****************************************\r
+ public void setAutoSaveInterval(int len) {\r
+ autoSaveInterval.setValue(len);\r
+ }\r
+ public int getAutoSaveInterval() {\r
+ return autoSaveInterval.value(); \r
+ }\r
+\r
+ \r
+ //*****************************************\r
+ //* Get/Set tag behavior combo box\r
+ //*****************************************\r
+ public void setTagBehavior(String value) {\r
+ for (int i=0; i<tagBehavior.count(); i++) {\r
+ String d = tagBehavior.itemText(i);\r
+ if (d.equalsIgnoreCase("Do Nothing") && value.equalsIgnoreCase("DoNothing")) {\r
+ tagBehavior.setCurrentIndex(i);\r
+ return;\r
+ }\r
+ if (d.equalsIgnoreCase("Count tags & hide inactive") && value.equalsIgnoreCase("HideInactiveCount")) {\r
+ tagBehavior.setCurrentIndex(i);\r
+ return;\r
+ }\r
+ if (d.equalsIgnoreCase("Count tags & do not hide inactive") && value.equalsIgnoreCase("NoHideInactiveCount")) {\r
+ tagBehavior.setCurrentIndex(i);\r
+ return;\r
+ }\r
+ if (d.equalsIgnoreCase("Color Active Tags") && value.equalsIgnoreCase("ColorActive")) {\r
+ tagBehavior.setCurrentIndex(i);\r
+ return;\r
+ }\r
+ }\r
+ }\r
+ public String getTagBehavior() {\r
+ int i = tagBehavior.currentIndex();\r
+ String behavior = tagBehavior.itemText(i); \r
+ if (behavior.equalsIgnoreCase("Count tags & hide inactive")) {\r
+ tagBehavior.setCurrentIndex(i);\r
+ return "HideInactiveCount";\r
+ }\r
+ if (behavior.equalsIgnoreCase("Count tags & do not hide inactive")) {\r
+ tagBehavior.setCurrentIndex(i);\r
+ return "NoHideInactiveCount";\r
+ }\r
+ if (behavior.equalsIgnoreCase("Color Active Tags")) {\r
+ tagBehavior.setCurrentIndex(i);\r
+ return "ColorActive";\r
+ }\r
+ return "DoNothing";\r
+ }\r
+\r
+ //*****************************************\r
+ //* Mimic Evernote Selection\r
+ //*****************************************\r
+ public boolean getMimicEvernote() {\r
+ return mimicEvernote.isChecked();\r
+ }\r
+ public void setMimicEvernote(boolean val) {\r
+ mimicEvernote.setChecked(val);\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.dialog;\r
+\r
+import java.util.List;\r
+\r
+import com.trolltech.qt.gui.QCheckBox;\r
+import com.trolltech.qt.gui.QComboBox;\r
+import com.trolltech.qt.gui.QFormLayout;\r
+import com.trolltech.qt.gui.QGroupBox;\r
+import com.trolltech.qt.gui.QLabel;\r
+import com.trolltech.qt.gui.QLineEdit;\r
+import com.trolltech.qt.gui.QVBoxLayout;\r
+import com.trolltech.qt.gui.QWidget;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.utilities.SyncTimes;\r
+\r
+public class ConfigConnectionPage extends QWidget {\r
+ private final QLineEdit useridEdit;\r
+ private final QLineEdit passwordEdit;\r
+ private final QCheckBox rememberPassword;\r
+ private final QCheckBox autoLogin;\r
+ private final QComboBox syncInterval;\r
+ private final SyncTimes syncTimes;\r
+ private final QCheckBox synchronizeOnClose;\r
+ private final QCheckBox synchronizeDeletedContents;\r
+ \r
+ public ConfigConnectionPage(QWidget parent) {\r
+ \r
+ // Userid settings\r
+ QGroupBox useridGroup = new QGroupBox(tr("Connection"));\r
+ QLabel useridLabel = new QLabel(tr("Userid"));\r
+ QLabel passwordLabel = new QLabel(tr("Password"));\r
+\r
+ \r
+ useridEdit = new QLineEdit();\r
+ useridEdit.setText(Global.username);\r
+ \r
+ passwordEdit = new QLineEdit();\r
+ passwordEdit.setText(Global.password);\r
+ passwordEdit.setEchoMode(QLineEdit.EchoMode.Password);\r
+ \r
+ syncInterval = new QComboBox(this);\r
+ syncTimes = new SyncTimes();\r
+ syncInterval.addItems(syncTimes.stringValues());\r
+ \r
+ rememberPassword = new QCheckBox("Remember Userid & Password");\r
+ autoLogin = new QCheckBox("Automatic Connect");\r
+ synchronizeDeletedContents = new QCheckBox("Synchronze Deleted Note Content");\r
+ synchronizeOnClose = new QCheckBox("Synchronize On Shutdown (only if connected)");\r
+ \r
+ \r
+ QFormLayout useridLayout = new QFormLayout();\r
+ useridLayout.addWidget(useridLabel);\r
+ useridLayout.addWidget(useridEdit); \r
+ useridLayout.addWidget(passwordLabel);\r
+ useridLayout.addWidget(passwordEdit);\r
+ useridLayout.addWidget(new QLabel(tr("Syncronization Interval")));\r
+ useridLayout.addWidget(syncInterval);\r
+ useridLayout.addWidget(rememberPassword);\r
+ useridLayout.addWidget(autoLogin);\r
+ useridLayout.addWidget(synchronizeOnClose);\r
+ useridLayout.addWidget(synchronizeDeletedContents);\r
+ \r
+ useridGroup.setLayout(useridLayout);\r
+ \r
+ // Add everything together\r
+ QVBoxLayout mainLayout = new QVBoxLayout();\r
+ mainLayout.addWidget(useridGroup);\r
+ mainLayout.addStretch(1);\r
+ setLayout(mainLayout);\r
+ \r
+ }\r
+\r
+ \r
+ //*****************************************\r
+ //* Userid get/set methods \r
+ //*****************************************\r
+ public void setUserid(String id) {\r
+ useridEdit.setText(id);\r
+ }\r
+ public String getUserid() {\r
+ return useridEdit.text();\r
+ }\r
+ \r
+\r
+ //*****************************************\r
+ //* Password get/set methods \r
+ //*****************************************\r
+ public void setPassword(String id) {\r
+ passwordEdit.setText(id);\r
+ }\r
+ public String getPassword() {\r
+ return passwordEdit.text();\r
+ }\r
+ \r
+\r
+ //*******************************************\r
+ //* Remember Password get/set\r
+ //*******************************************\r
+ public void setRememberPassword(boolean val) {\r
+ rememberPassword.setChecked(val);\r
+ }\r
+ public boolean getRememberPassword() {\r
+ return rememberPassword.isChecked();\r
+ }\r
+ \r
+ \r
+ \r
+ \r
+ //*******************************************\r
+ //* Automatic login get/set\r
+ //*******************************************\r
+ public void setAutomaticLogin(boolean val) {\r
+ autoLogin.setChecked(val);\r
+ }\r
+ public boolean getAutomaticLogin() {\r
+ return autoLogin.isChecked();\r
+ }\r
+\r
+ \r
+\r
+ //*****************************************\r
+ //* Synchronize Deleted Note Content\r
+ //*****************************************\r
+ public void setSyncronizeDeletedContent(boolean val) {\r
+ synchronizeDeletedContents.setChecked(val);\r
+ }\r
+ public boolean getSynchronizeDeletedContent() {\r
+ return synchronizeDeletedContents.isChecked();\r
+ }\r
+ \r
+\r
+ \r
+\r
+ \r
+ \r
+ \r
+ //*****************************************\r
+ //* Get/set synchronize on close\r
+ //*****************************************\r
+ public boolean getSynchronizeOnClose() {\r
+ return synchronizeOnClose.isChecked();\r
+ }\r
+ public void setSynchronizeOnClose(boolean val) {\r
+ synchronizeOnClose.setChecked(val);\r
+ }\r
+ \r
+ \r
+ //*****************************************\r
+ //* Get/set sync intervals\r
+ //*****************************************\r
+ public String getSyncInterval() {\r
+ int i = syncInterval.currentIndex();\r
+ return syncInterval.itemText(i); \r
+ }\r
+ public void setSyncInterval(String s) {\r
+ List<String> vals = syncTimes.stringValues();\r
+ for (int i=0; i<vals.size(); i++) {\r
+ if (vals.get(i).equalsIgnoreCase(s))\r
+ syncInterval.setCurrentIndex(i);\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.dialog;\r
+\r
+import com.trolltech.qt.gui.QCheckBox;\r
+import com.trolltech.qt.gui.QComboBox;\r
+import com.trolltech.qt.gui.QGroupBox;\r
+import com.trolltech.qt.gui.QHBoxLayout;\r
+import com.trolltech.qt.gui.QLabel;\r
+import com.trolltech.qt.gui.QTextBrowser;\r
+import com.trolltech.qt.gui.QVBoxLayout;\r
+import com.trolltech.qt.gui.QWidget;\r
+\r
+public class ConfigDebugPage extends QWidget {\r
+ \r
+ QComboBox messageCombo;\r
+ QComboBox serverCombo;\r
+ QCheckBox disableUploads;\r
+ QCheckBox carriageReturnFix;\r
+ public ConfigDebugPage(QWidget parent) {\r
+ super(parent);\r
+ // Server settings\r
+ QGroupBox serverGroup = new QGroupBox(tr("Server Configuration"));\r
+ QLabel serverLabel = new QLabel(tr("Server"));\r
+ serverCombo = new QComboBox();\r
+ serverCombo.addItem(tr("www.evernote.com"));\r
+ serverCombo.addItem(tr("sandbox.evernote.com"));\r
+ disableUploads = new QCheckBox();\r
+ disableUploads.setText("Disable uploads to server");\r
+\r
+ QHBoxLayout serverLayout = new QHBoxLayout();\r
+ serverLayout.addWidget(serverLabel);\r
+ serverLayout.addWidget(serverCombo);\r
+ serverLayout.addWidget(disableUploads);\r
+ serverGroup.setLayout(serverLayout);\r
+\r
+ QGroupBox messageGroup = new QGroupBox(tr("Debug Messages"));\r
+ QLabel messageLevelLabel = new QLabel(tr("Message Level"));\r
+ messageCombo = new QComboBox();\r
+ messageCombo.addItem(tr("Low"));\r
+ messageCombo.addItem(tr("Medium"));\r
+ messageCombo.addItem(tr("High"));\r
+ messageCombo.addItem(tr("Extreme"));\r
+ \r
+ QHBoxLayout messageLayout = new QHBoxLayout();\r
+ messageLayout.addWidget(messageLevelLabel);\r
+ messageLayout.addWidget(messageCombo);\r
+ messageLayout.setStretch(1, 100);\r
+ messageGroup.setLayout(messageLayout);\r
+ \r
+ QVBoxLayout mainLayout = new QVBoxLayout();\r
+ mainLayout.addWidget(serverGroup);\r
+ mainLayout.addWidget(messageGroup);\r
+ \r
+ QGroupBox crlfGroup = new QGroupBox(tr("Carriage Return Fix"));\r
+ String crlfMessage = new String(tr("Note: The carriage return is a test fix. If you " +\r
+ "enable it, it will do some modifications to the notes you view to try and" +\r
+ " get the carriage returns to look correct. This is due to the way that " +\r
+ "the way Evernote 3.1 Windows client is dealing with carriage returns. This fix"+\r
+ "will try and correct this problem. This fix is not permanent unless you edit a note. If" +\r
+ "you edit a note, this fix is PERMANENT and will be sent to Evernote on the next sync. I haven't" +\r
+ "had any issues with this, but please be aware of this condition."));\r
+ carriageReturnFix = new QCheckBox(this);\r
+ QHBoxLayout crlfLayout = new QHBoxLayout();\r
+ QLabel carriageReturnLabel = new QLabel("Enable Carriage Return Fix");\r
+ crlfLayout.addWidget(carriageReturnLabel);\r
+ crlfLayout.addWidget(carriageReturnFix);\r
+ crlfGroup.setLayout(crlfLayout);\r
+\r
+ QTextBrowser msg = new QTextBrowser(this);\r
+ msg.setText(crlfMessage);\r
+ mainLayout.addWidget(crlfGroup);\r
+\r
+ mainLayout.addWidget(msg);\r
+ \r
+ mainLayout.addStretch(1);\r
+ setLayout(mainLayout);\r
+ \r
+ serverCombo.activated.connect(this, "serverOptionChanged()");\r
+ }\r
+ \r
+ //******************************************\r
+ //* Message set/get\r
+ //******************************************\r
+ public void setDebugLevel(String level) {\r
+ int i = messageCombo.findText(level);\r
+ if (i>0)\r
+ messageCombo.setCurrentIndex(i);\r
+ }\r
+ public String getDebugLevel() {\r
+ int i = messageCombo.currentIndex();\r
+ return messageCombo.itemText(i);\r
+ }\r
+ public void setCarriageReturnFix(boolean val) {\r
+ carriageReturnFix.setChecked(val);\r
+ }\r
+ public boolean getCarriageReturnFix() {\r
+ return carriageReturnFix.isChecked();\r
+ }\r
+\r
+ \r
+ //******************************************\r
+ //* Server set/get\r
+ //******************************************\r
+ public void setServer(String server) {\r
+ int i = serverCombo.findText(server);\r
+ if (i>0)\r
+ serverCombo.setCurrentIndex(i);\r
+ }\r
+ public String getServer() {\r
+ int i = serverCombo.currentIndex();\r
+ return serverCombo.itemText(i);\r
+ }\r
+ @SuppressWarnings("unused")\r
+ private void serverOptionChanged() {\r
+ String text = serverCombo.currentText();\r
+ if (text.equalsIgnoreCase("www.evernote.com")) \r
+ disableUploads.setChecked(true);\r
+ }\r
+ //*****************************************\r
+ //* Disable uploads \r
+ //*****************************************\r
+ public void setDisableUploads(boolean val) {\r
+ disableUploads.setChecked(val);\r
+ }\r
+ public boolean getDisableUploads() {\r
+ return disableUploads.isChecked();\r
+ }\r
+ \r
+ \r
+\r
+\r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.dialog;\r
+\r
+import java.io.FileInputStream;\r
+import java.io.FileNotFoundException;\r
+import java.io.FileOutputStream;\r
+\r
+import com.trolltech.qt.core.QSize;\r
+import com.trolltech.qt.core.Qt.AlignmentFlag;\r
+import com.trolltech.qt.core.Qt.ItemFlag;\r
+import com.trolltech.qt.gui.QApplication;\r
+import com.trolltech.qt.gui.QDialog;\r
+import com.trolltech.qt.gui.QHBoxLayout;\r
+import com.trolltech.qt.gui.QIcon;\r
+import com.trolltech.qt.gui.QListView;\r
+import com.trolltech.qt.gui.QListWidget;\r
+import com.trolltech.qt.gui.QListWidgetItem;\r
+import com.trolltech.qt.gui.QPushButton;\r
+import com.trolltech.qt.gui.QStackedWidget;\r
+import com.trolltech.qt.gui.QVBoxLayout;\r
+import com.trolltech.qt.gui.QWidget;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.utilities.AESEncrypter;\r
+public class ConfigDialog extends QDialog {\r
+ private final QListWidget contentsWidget;\r
+ private final QStackedWidget pagesWidget;\r
+ private final ConfigConnectionPage connectionPage;\r
+ private final ConfigDebugPage debugPage;\r
+ private final ConfigAppearancePage appearancePage;\r
+ private final ConfigShowColumnsPage columnsPage;\r
+ private final ConfigIndexPage indexPage;\r
+ private final ConfigShowEditorButtonsPage editorButtonsPage;\r
+ \r
+ public ConfigDialog(QWidget parent) {\r
+ \r
+ contentsWidget = new QListWidget(this);\r
+ contentsWidget.setViewMode(QListView.ViewMode.IconMode);\r
+ contentsWidget.setIconSize(new QSize(96, 84));\r
+ contentsWidget.setMovement(QListView.Movement.Static);\r
+ contentsWidget.setMaximumWidth(128);\r
+ contentsWidget.setSpacing(12);\r
+ \r
+ pagesWidget = new QStackedWidget(this);\r
+ connectionPage = new ConfigConnectionPage(this);\r
+ appearancePage = new ConfigAppearancePage(this);\r
+ indexPage = new ConfigIndexPage(this);\r
+ debugPage = new ConfigDebugPage(this);\r
+ columnsPage = new ConfigShowColumnsPage(this);\r
+ editorButtonsPage = new ConfigShowEditorButtonsPage(this);\r
+ pagesWidget.addWidget(appearancePage);\r
+ pagesWidget.addWidget(indexPage);\r
+ pagesWidget.addWidget(connectionPage);\r
+ pagesWidget.addWidget(columnsPage);\r
+ pagesWidget.addWidget(editorButtonsPage);\r
+ pagesWidget.addWidget(debugPage);\r
+ \r
+ QPushButton cancelButton = new QPushButton(tr("Cancel"));\r
+ QPushButton okButton = new QPushButton(tr("OK"));\r
+ okButton.clicked.connect(this, "okPushed()");\r
+ cancelButton.clicked.connect(this, "close()");\r
+ \r
+ createIcons();\r
+ contentsWidget.setCurrentRow(0);\r
+ \r
+ QHBoxLayout horizontalLayout = new QHBoxLayout();\r
+ horizontalLayout.addWidget(contentsWidget);\r
+ horizontalLayout.addWidget(pagesWidget,1);\r
+ \r
+ QHBoxLayout buttonLayout = new QHBoxLayout();\r
+ buttonLayout.addStretch(1);\r
+ buttonLayout.addWidget(okButton);\r
+ buttonLayout.addWidget(cancelButton);\r
+ setWindowTitle(tr("Settings")); \r
+ \r
+ QVBoxLayout mainLayout = new QVBoxLayout();\r
+ mainLayout.addLayout(horizontalLayout);\r
+ mainLayout.addSpacing(1);\r
+ mainLayout.addLayout(buttonLayout);\r
+ setLayout(mainLayout);\r
+ \r
+ loadSettings();\r
+ }\r
+ public void okPushed() {\r
+ Global.setServer(debugPage.getServer());\r
+ AESEncrypter aes = new AESEncrypter();\r
+ aes.setUserid(connectionPage.getUserid().trim());\r
+ \r
+ if (debugPage.getDisableUploads())\r
+ Global.disableUploads = true;\r
+ else\r
+ Global.disableUploads = false;\r
+ Global.setDisableUploads(Global.disableUploads);\r
+ Global.setMimicEvernoteInterface(appearancePage.getMimicEvernote());\r
+ \r
+ if (appearancePage.getShowSplashScreen())\r
+ Global.saveWindowVisible("SplashScreen", true);\r
+ else\r
+ Global.saveWindowVisible("SplashScreen", false);\r
+ \r
+ \r
+ if (appearancePage.getPdfPreview())\r
+ Global.setPdfPreview(true);\r
+ else\r
+ Global.setPdfPreview(false);\r
+ \r
+ Global.setAutoSaveInterval(appearancePage.getAutoSaveInterval());\r
+ \r
+ Global.setAutomaticLogin(connectionPage.getAutomaticLogin());\r
+ Global.setRememberPassword(connectionPage.getRememberPassword());\r
+ if (connectionPage.getRememberPassword()) { \r
+ aes.setPassword(connectionPage.getPassword());\r
+ }\r
+ Global.setShowTrayIcon(appearancePage.getShowTrayIcon());\r
+ Global.setVerifyDelete(appearancePage.getVerifyDelete());\r
+ Global.setSynchronizeOnClose(connectionPage.getSynchronizeOnClose());\r
+ Global.setSynchronizeDeletedContent(connectionPage.getSynchronizeDeletedContent());\r
+ Global.setTagBehavior(appearancePage.getTagBehavior());\r
+ FileOutputStream out = null;\r
+ try {\r
+ out = new FileOutputStream(Global.getDirectoryPath()+"secure.txt");\r
+ } catch (FileNotFoundException e) {\r
+ // if it isn't found we'll write it.\r
+ }\r
+ if (out != null)\r
+ aes.encrypt(out);\r
+ Global.userStoreUrl = "https://"+debugPage.getServer()+"/edam/user";\r
+ Global.setWordRegex(indexPage.getRegex());\r
+ Global.setRecognitionWeight(indexPage.getRecognitionWeight());\r
+ Global.setMinimumWordLength(indexPage.getWordLength());\r
+ Global.minimumWordCount = indexPage.getWordLength(); \r
+ Global.setIndexThreads(indexPage.getIndexThreads());\r
+ Global.setMessageLevel( debugPage.getDebugLevel());\r
+ Global.saveCarriageReturnFix(debugPage.getCarriageReturnFix());\r
+ Global.enableCarriageReturnFix = debugPage.getCarriageReturnFix();\r
+ \r
+ String guiFormat = appearancePage.getStyle();\r
+ QApplication.setStyle(guiFormat);\r
+ QApplication.style().standardPalette();\r
+ Global.setStyle(guiFormat);\r
+ Global.setStandardPalette(appearancePage.getStandardPalette());\r
+ if (Global.useStandardPalette())\r
+ QApplication.setPalette(QApplication.style().standardPalette());\r
+ else\r
+ QApplication.setPalette(Global.originalPalette);\r
+ \r
+ String dateFmt = appearancePage.getDateFormat();\r
+ String timeFmt = appearancePage.getTimeFormat();\r
+ int dash = dateFmt.indexOf("-");\r
+ dateFmt = dateFmt.substring(0,dash-1);\r
+ dash = timeFmt.indexOf("-");\r
+ timeFmt = timeFmt.substring(0,dash-1);\r
+ \r
+ Global.setDateFormat(dateFmt);\r
+ Global.setTimeFormat(timeFmt);\r
+ \r
+ Global.setSyncInterval(connectionPage.getSyncInterval());\r
+ \r
+ Global.saveColumnVisible("dateCreated", columnsPage.showDateCreated());\r
+ Global.saveColumnVisible("dateChanged", columnsPage.showDateChanged());\r
+ Global.saveColumnVisible("dateSubject", columnsPage.showDateSubject());\r
+ Global.saveColumnVisible("author", columnsPage.showAuthor());\r
+ Global.saveColumnVisible("sourceUrl", columnsPage.showSourceUrl());\r
+ Global.saveColumnVisible("synchronized", columnsPage.showSynchronized());\r
+ Global.saveColumnVisible("notebook", columnsPage.showNotebook());\r
+ Global.saveColumnVisible("tags", columnsPage.showTags());\r
+ \r
+ Global.saveEditorButtonsVisible("undo", editorButtonsPage.showUndo());\r
+ Global.saveEditorButtonsVisible("redo", editorButtonsPage.showRedo());\r
+ Global.saveEditorButtonsVisible("cut", editorButtonsPage.showCut());\r
+ Global.saveEditorButtonsVisible("copy", editorButtonsPage.showCopy());\r
+ Global.saveEditorButtonsVisible("paste", editorButtonsPage.showPaste());\r
+ Global.saveEditorButtonsVisible("underline", editorButtonsPage.showUnderline());\r
+ Global.saveEditorButtonsVisible("strikethrough", editorButtonsPage.showStrikethrough());\r
+ Global.saveEditorButtonsVisible("italic", editorButtonsPage.showItalic());\r
+ Global.saveEditorButtonsVisible("bold", editorButtonsPage.showBold());\r
+ Global.saveEditorButtonsVisible("font", editorButtonsPage.showFont());\r
+ Global.saveEditorButtonsVisible("fontSize", editorButtonsPage.showFontSize());\r
+ Global.saveEditorButtonsVisible("fontColor", editorButtonsPage.showFontColor());\r
+ Global.saveEditorButtonsVisible("fontHilight", editorButtonsPage.showFontHilight());\r
+ Global.saveEditorButtonsVisible("indent", editorButtonsPage.showIndent());\r
+ Global.saveEditorButtonsVisible("outdent", editorButtonsPage.showOutdent());\r
+ Global.saveEditorButtonsVisible("numberList", editorButtonsPage.showNumberList());\r
+ Global.saveEditorButtonsVisible("bulletList", editorButtonsPage.showBulletList());\r
+ Global.saveEditorButtonsVisible("alignCenter", editorButtonsPage.showAlignCenter());\r
+ Global.saveEditorButtonsVisible("alignLeft", editorButtonsPage.showAlignLeft());\r
+ Global.saveEditorButtonsVisible("alignRight", editorButtonsPage.showAlignRight());\r
+ close();\r
+ }\r
+ @Override\r
+ public void reject() {\r
+ QApplication.setStyle(Global.getStyle());\r
+ super.reject();\r
+ }\r
+ \r
+ public ConfigDebugPage getDebugPage() {\r
+ return debugPage;\r
+ }\r
+ \r
+ \r
+ public ConfigConnectionPage getConfigPage() {\r
+ return connectionPage;\r
+ }\r
+ \r
+ public void createIcons() {\r
+ String iconPath = new String("classpath:cx/fbn/nevernote/icons/");\r
+\r
+ \r
+ QListWidgetItem formatsButton = new QListWidgetItem(contentsWidget);\r
+ formatsButton.setText(tr("Appearance"));\r
+ formatsButton.setTextAlignment(AlignmentFlag.AlignHCenter.value());\r
+ formatsButton.setFlags(ItemFlag.ItemIsSelectable, ItemFlag.ItemIsEnabled);\r
+ formatsButton.setIcon(new QIcon(iconPath+"appearance.jpg"));\r
+ \r
+ QListWidgetItem indexButton = new QListWidgetItem(contentsWidget);\r
+ indexButton.setText(tr("Indexing"));\r
+ indexButton.setTextAlignment(AlignmentFlag.AlignHCenter.value());\r
+ indexButton.setFlags(ItemFlag.ItemIsSelectable, ItemFlag.ItemIsEnabled);\r
+ indexButton.setIcon(new QIcon(iconPath+"search_config.jpg"));\r
+\r
+ QListWidgetItem configButton = new QListWidgetItem(contentsWidget);\r
+ configButton.setText(tr("Connection"));\r
+ configButton.setTextAlignment(AlignmentFlag.AlignHCenter.value());\r
+ configButton.setFlags(ItemFlag.ItemIsSelectable, ItemFlag.ItemIsEnabled);\r
+ configButton.setIcon(new QIcon(iconPath+"synchronize.png"));\r
+ \r
+ QListWidgetItem columnsButton = new QListWidgetItem(contentsWidget);\r
+ columnsButton.setText(tr("Hide Columns"));\r
+ columnsButton.setTextAlignment(AlignmentFlag.AlignHCenter.value());\r
+ columnsButton.setFlags(ItemFlag.ItemIsSelectable, ItemFlag.ItemIsEnabled);\r
+ columnsButton.setIcon(new QIcon(iconPath+"show-columns.png"));\r
+\r
+ QListWidgetItem editorButton = new QListWidgetItem(contentsWidget);\r
+ editorButton.setText(tr("Hide Edit Buttons"));\r
+ editorButton.setTextAlignment(AlignmentFlag.AlignHCenter.value());\r
+ editorButton.setFlags(ItemFlag.ItemIsSelectable, ItemFlag.ItemIsEnabled);\r
+ editorButton.setIcon(new QIcon(iconPath+"scissors.jpg"));\r
+\r
+ QListWidgetItem debugButton = new QListWidgetItem(contentsWidget);\r
+ debugButton.setText(tr("Debugging"));\r
+ debugButton.setTextAlignment(AlignmentFlag.AlignHCenter.value());\r
+ debugButton.setFlags(ItemFlag.ItemIsSelectable, ItemFlag.ItemIsEnabled);\r
+ debugButton.setIcon(new QIcon(iconPath+"debug.jpg"));\r
+ \r
+ contentsWidget.currentItemChanged.connect(this, "changePage(QListWidgetItem, QListWidgetItem)");\r
+ }\r
+ \r
+ protected void changePage(QListWidgetItem current, QListWidgetItem previous) {\r
+ pagesWidget.setCurrentIndex(contentsWidget.row(current));\r
+ }\r
+ \r
+ private void loadSettings() {\r
+ Global.originalPalette = QApplication.palette();\r
+ \r
+ debugPage.setServer(Global.getServer());\r
+ debugPage.setDisableUploads(Global.disableUploads);\r
+// if (Global.getUpdateSequenceNumber() > 0)\r
+ debugPage.serverCombo.setEnabled(false);\r
+ \r
+ if (Global.username.equalsIgnoreCase("") || Global.password.equalsIgnoreCase("")) {\r
+ AESEncrypter aes = new AESEncrypter();\r
+ try {\r
+ aes.decrypt(new FileInputStream(Global.getDirectoryPath()+"secure.txt"));\r
+ } catch (FileNotFoundException e) {\r
+ // File not found, so we'll just get empty strings anyway. \r
+ }\r
+ String userid = aes.getUserid();\r
+ String password = aes.getPassword();\r
+ if (!userid.equals("") && !password.equals("")) {\r
+ Global.username = userid;\r
+ Global.password = password;\r
+ } \r
+ }\r
+ appearancePage.setAutoSaveInterval(Global.getAutoSaveInterval());\r
+ connectionPage.setUserid(Global.username);\r
+ connectionPage.setPassword(Global.password);\r
+ connectionPage.setAutomaticLogin(Global.automaticLogin());\r
+ connectionPage.setRememberPassword(Global.rememberPassword());\r
+ appearancePage.setMimicEvernote(Global.getMimicEvernoteInterface());\r
+ appearancePage.setShowTrayIcon(Global.showTrayIcon());\r
+ connectionPage.setSynchronizeOnClose(Global.synchronizeOnClose());\r
+ connectionPage.setSyncronizeDeletedContent(Global.synchronizeDeletedContent());\r
+ appearancePage.setVerifyDelete(Global.verifyDelete());\r
+ appearancePage.setPdfPreview(Global.pdfPreview());\r
+ appearancePage.setShowSplashScreen(Global.isWindowVisible("SplashScreen"));\r
+ appearancePage.setTagBehavior(Global.tagBehavior());\r
+ \r
+ indexPage.setRegex(Global.getWordRegex());\r
+ indexPage.setWordLength(Global.getMinimumWordLength());\r
+ indexPage.setIndexThreads(Global.getIndexThreads());\r
+ connectionPage.setSyncInterval(Global.getSyncInterval());\r
+ \r
+ appearancePage.setDateFormat(Global.getDateFormat());\r
+ appearancePage.setTimeFormat(Global.getTimeFormat());\r
+ appearancePage.setStyle(Global.getStyle());\r
+ appearancePage.setStandardPalette(Global.useStandardPalette());\r
+ \r
+ columnsPage.setDateCreated(Global.isColumnVisible("dateCreated"));\r
+ columnsPage.setDateSubject(Global.isColumnVisible("dateSubject"));\r
+ columnsPage.setDateChanged(Global.isColumnVisible("dateChanged"));\r
+ columnsPage.setAuthor(Global.isColumnVisible("author"));\r
+ columnsPage.setSourceUrl(Global.isColumnVisible("sourceUrl"));\r
+ columnsPage.setTags(Global.isColumnVisible("tags"));\r
+ columnsPage.setSynchronized(Global.isColumnVisible("synchronized"));\r
+ columnsPage.setNotebook(Global.isColumnVisible("notebook"));\r
+ \r
+ editorButtonsPage.setUndo(Global.isEditorButtonVisible("undo"));\r
+ editorButtonsPage.setRedo(Global.isEditorButtonVisible("redo"));\r
+ editorButtonsPage.setCut(Global.isEditorButtonVisible("cut"));\r
+ editorButtonsPage.setCopy(Global.isEditorButtonVisible("copy"));\r
+ editorButtonsPage.setPaste(Global.isEditorButtonVisible("paste"));\r
+ editorButtonsPage.setBold(Global.isEditorButtonVisible("bold"));\r
+ editorButtonsPage.setItalic(Global.isEditorButtonVisible("italic"));\r
+ editorButtonsPage.setUnderline(Global.isEditorButtonVisible("underline"));\r
+ editorButtonsPage.setStrikethrough(Global.isEditorButtonVisible("strikethrough"));\r
+ editorButtonsPage.setIndent(Global.isEditorButtonVisible("indent"));\r
+ editorButtonsPage.setHline(Global.isEditorButtonVisible("hline"));\r
+ editorButtonsPage.setOutdent(Global.isEditorButtonVisible("outdent"));\r
+ editorButtonsPage.setBulletList(Global.isEditorButtonVisible("bulletList"));\r
+ editorButtonsPage.setNumberList(Global.isEditorButtonVisible("numberList"));\r
+ editorButtonsPage.setFont(Global.isEditorButtonVisible("font"));\r
+ editorButtonsPage.setFontSize(Global.isEditorButtonVisible("fontSize"));\r
+ editorButtonsPage.setFontColor(Global.isEditorButtonVisible("fontColor"));\r
+ editorButtonsPage.setFontHighlight(Global.isEditorButtonVisible("fontHilight"));\r
+ editorButtonsPage.setAlignLeft(Global.isEditorButtonVisible("alignLeft"));\r
+ editorButtonsPage.setAlignCenter(Global.isEditorButtonVisible("alignCenter"));\r
+ editorButtonsPage.setAlignRight(Global.isEditorButtonVisible("alignRight"));\r
+ \r
+ debugPage.setDebugLevel(Global.getMessageLevel());\r
+ debugPage.setCarriageReturnFix(Global.enableCarriageReturnFix());\r
+ \r
+ }\r
+ \r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.dialog;\r
+\r
+import com.trolltech.qt.gui.QGroupBox;\r
+import com.trolltech.qt.gui.QHBoxLayout;\r
+import com.trolltech.qt.gui.QLabel;\r
+import com.trolltech.qt.gui.QLineEdit;\r
+import com.trolltech.qt.gui.QSpinBox;\r
+import com.trolltech.qt.gui.QVBoxLayout;\r
+import com.trolltech.qt.gui.QWidget;\r
+\r
+import cx.fbn.nevernote.Global;\r
+\r
+public class ConfigIndexPage extends QWidget {\r
+\r
+ private final QSpinBox indexThreadSpinner;\r
+ private final QSpinBox lengthSpinner;\r
+ private final QSpinBox weightSpinner;\r
+ private final QLineEdit regexEdit;\r
+ \r
+ public ConfigIndexPage(QWidget parent) {\r
+// super(parent);\r
+ \r
+ indexThreadSpinner = new QSpinBox(this);\r
+ indexThreadSpinner.setMaximum(5);\r
+ indexThreadSpinner.setMinimum(1);\r
+ \r
+ // Index threads layout\r
+ QLabel threadLabel = new QLabel(tr("Maximum Threads"));\r
+ QHBoxLayout threadsLayout = new QHBoxLayout();\r
+ threadsLayout.addWidget(threadLabel);\r
+ threadsLayout.addWidget(indexThreadSpinner);\r
+ QGroupBox threadsGroup = new QGroupBox(tr("Indexing Threads (Requires Restart)"));\r
+ threadsGroup.setLayout(threadsLayout);\r
+ \r
+ threadsGroup.setVisible(false);\r
+ \r
+ \r
+ // Minimum word length\r
+ QGroupBox wordLengthGroup = new QGroupBox(tr("Word Length"));\r
+ QLabel wordLengthLabel = new QLabel(tr("Minimum Word Length"));\r
+ lengthSpinner = new QSpinBox();\r
+ lengthSpinner.setRange(3,10);\r
+ lengthSpinner.setSingleStep(1);\r
+ lengthSpinner.setValue(Global.minimumWordCount);\r
+ \r
+ QHBoxLayout wordLengthLayout = new QHBoxLayout();\r
+ wordLengthLayout.addWidget(wordLengthLabel);\r
+ wordLengthLayout.addWidget(lengthSpinner);\r
+ wordLengthGroup.setLayout(wordLengthLayout);\r
+ \r
+\r
+ // Minimum word length\r
+ QGroupBox weightGroup = new QGroupBox(tr("Recognition"));\r
+ QLabel weightLabel = new QLabel(tr("Minimum Recognition Weight"));\r
+ weightSpinner = new QSpinBox();\r
+ weightSpinner.setRange(1,100);\r
+ weightSpinner.setSingleStep(1);\r
+ weightSpinner.setValue(Global.getRecognitionWeight());\r
+\r
+ QHBoxLayout weightLayout = new QHBoxLayout();\r
+ weightLayout.addWidget(weightLabel);\r
+ weightLayout.addWidget(weightSpinner);\r
+ weightGroup.setLayout(weightLayout);\r
+ \r
+ \r
+ // Regular Expressions for word parsing\r
+ QGroupBox regexGroup = new QGroupBox(tr("Word Parse"));\r
+ QLabel regexLabel = new QLabel(tr("Regular Expression"));\r
+ regexEdit = new QLineEdit();\r
+ regexEdit.setText(Global.getWordRegex());\r
+\r
+ QHBoxLayout regexLayout = new QHBoxLayout();\r
+ regexLayout.addWidget(regexLabel);\r
+ regexLayout.addWidget(regexEdit); \r
+ regexGroup.setLayout(regexLayout);\r
+ \r
+ \r
+ QVBoxLayout mainLayout = new QVBoxLayout();\r
+ mainLayout.addWidget(threadsGroup);\r
+ mainLayout.addWidget(wordLengthGroup);\r
+ mainLayout.addWidget(weightGroup);\r
+ mainLayout.addWidget(regexGroup);\r
+ mainLayout.addStretch(1);\r
+ setLayout(mainLayout);\r
+\r
+\r
+ }\r
+ \r
+ //*****************************************\r
+ //* Word length get/set methods \r
+ //*****************************************\r
+ public void setWordLength(int len) {\r
+ lengthSpinner.setValue(len);\r
+ }\r
+ public int getWordLength() {\r
+ return lengthSpinner.value();\r
+ }\r
+\r
+ \r
+ //*****************************************\r
+ //* Recognition Weight \r
+ //*****************************************\r
+ public void setRecognitionWeight(int len) {\r
+ weightSpinner.setValue(len);\r
+ }\r
+ public int getRecognitionWeight() {\r
+ return weightSpinner.value();\r
+ }\r
+ \r
+ //*****************************************\r
+ //* Index Threads get/set methods\r
+ //*****************************************\r
+ public void setIndexThreads(int value) {\r
+ indexThreadSpinner.setValue(value);\r
+ }\r
+ public int getIndexThreads() {\r
+ return indexThreadSpinner.value();\r
+ }\r
+\r
+ \r
+ \r
+ //*****************************************\r
+ //* Regex get/set methods \r
+ //*****************************************\r
+ public void setRegex(String s) {\r
+ regexEdit.setText(s);\r
+ }\r
+ public String getRegex() {\r
+ return regexEdit.text();\r
+ }\r
+\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.dialog;\r
+\r
+import com.trolltech.qt.gui.QComboBox;\r
+import com.trolltech.qt.gui.QGroupBox;\r
+import com.trolltech.qt.gui.QHBoxLayout;\r
+import com.trolltech.qt.gui.QRadioButton;\r
+import com.trolltech.qt.gui.QVBoxLayout;\r
+import com.trolltech.qt.gui.QWidget;\r
+\r
+public class ConfigShowColumnsPage extends QWidget {\r
+ private final QRadioButton showDateCreated;\r
+ private final QRadioButton hideDateCreated;\r
+ private final QRadioButton showDateSubject;\r
+ private final QRadioButton hideDateSubject;\r
+ private final QRadioButton showDateChanged;\r
+ private final QRadioButton hideDateChanged;\r
+ private final QRadioButton showAuthor;\r
+ private final QRadioButton hideAuthor;\r
+ private final QRadioButton sourceUrlShow;\r
+ private final QRadioButton sourceUrlHide;\r
+ private final QRadioButton showTags;\r
+ private final QRadioButton hideTags;\r
+ private final QRadioButton showNotebook;\r
+ private final QRadioButton hideNotebook;\r
+ private final QRadioButton showSynchronized;\r
+ private final QRadioButton hideSynchronized;\r
+\r
+ \r
+ QComboBox messageCombo;\r
+ public ConfigShowColumnsPage(QWidget parent) {\r
+ super(parent);\r
+\r
+ // Date Created Column\r
+ QGroupBox dateCreatedGroup = new QGroupBox(tr("Date Created"));\r
+ QHBoxLayout dateCreatedLayout = new QHBoxLayout();\r
+ showDateCreated = new QRadioButton(tr("Show"));\r
+ hideDateCreated = new QRadioButton(tr("Hide"));\r
+ dateCreatedLayout.addWidget(showDateCreated);\r
+ dateCreatedLayout.addWidget(hideDateCreated);\r
+ dateCreatedLayout.setStretch(1, 100);\r
+ dateCreatedGroup.setLayout(dateCreatedLayout);\r
+\r
+\r
+ // Subject Date Column\r
+ QGroupBox dateSubjectGroup = new QGroupBox(tr("Subject Date"));\r
+ QHBoxLayout dateSubjectLayout = new QHBoxLayout();\r
+ showDateSubject = new QRadioButton(tr("Show"));\r
+ hideDateSubject = new QRadioButton(tr("Hide"));\r
+ dateSubjectLayout.addWidget(showDateSubject);\r
+ dateSubjectLayout.addWidget(hideDateSubject);\r
+ dateSubjectLayout.setStretch(1, 100);\r
+ dateSubjectGroup.setLayout(dateSubjectLayout);\r
+\r
+\r
+ // Title Column\r
+ QGroupBox sourceUrlGroup = new QGroupBox(tr("Source URL"));\r
+ QHBoxLayout sourceUrlLayout = new QHBoxLayout();\r
+ sourceUrlShow = new QRadioButton(tr("Show"));\r
+ sourceUrlHide = new QRadioButton(tr("Hide"));\r
+ sourceUrlLayout.addWidget(sourceUrlShow);\r
+ sourceUrlLayout.addWidget(sourceUrlHide);\r
+ sourceUrlLayout.setStretch(1, 100);\r
+ sourceUrlGroup.setLayout(sourceUrlLayout);\r
+\r
+ // Author Column\r
+ QGroupBox authorGroup = new QGroupBox(tr("Author"));\r
+ QHBoxLayout authorLayout = new QHBoxLayout();\r
+ showAuthor = new QRadioButton(tr("Show"));\r
+ hideAuthor = new QRadioButton(tr("Hide"));\r
+ authorLayout.addWidget(showAuthor);\r
+ authorLayout.addWidget(hideAuthor);\r
+ authorLayout.setStretch(1, 100);\r
+ authorGroup.setLayout(authorLayout);\r
+\r
+ \r
+ // Date Changed Column\r
+ QGroupBox dateChangedGroup = new QGroupBox(tr("Date Changed"));\r
+ QHBoxLayout dateChangedLayout = new QHBoxLayout();\r
+ showDateChanged = new QRadioButton(tr("Show"));\r
+ hideDateChanged = new QRadioButton(tr("Hide"));\r
+ dateChangedLayout.addWidget(showDateChanged);\r
+ dateChangedLayout.addWidget(hideDateChanged);\r
+ dateChangedLayout.setStretch(1, 100);\r
+ dateChangedGroup.setLayout(dateChangedLayout);\r
+\r
+ // Notebook Column\r
+ QGroupBox notebookGroup = new QGroupBox(tr("Notebook"));\r
+ QHBoxLayout notebookLayout = new QHBoxLayout();\r
+ showNotebook = new QRadioButton(tr("Show"));\r
+ hideNotebook = new QRadioButton(tr("Hide"));\r
+ notebookLayout.addWidget(showNotebook);\r
+ notebookLayout.addWidget(hideNotebook);\r
+ notebookLayout.setStretch(1, 100);\r
+ notebookGroup.setLayout(notebookLayout);\r
+\r
+ // Tags Column\r
+ QGroupBox tagsGroup = new QGroupBox(tr("Tags"));\r
+ QHBoxLayout tagsLayout = new QHBoxLayout();\r
+ showTags = new QRadioButton(tr("Show"));\r
+ hideTags = new QRadioButton(tr("Hide"));\r
+ tagsLayout.addWidget(showTags);\r
+ tagsLayout.addWidget(hideTags);\r
+ tagsLayout.setStretch(1, 100);\r
+ tagsGroup.setLayout(tagsLayout);\r
+\r
+ // Synchronized Column\r
+ QGroupBox synchronizedGroup = new QGroupBox(tr("Synchronized Indicator"));\r
+ QHBoxLayout syncLayout = new QHBoxLayout();\r
+ showSynchronized = new QRadioButton(tr("Show"));\r
+ hideSynchronized = new QRadioButton(tr("Hide"));\r
+ syncLayout.addWidget(showSynchronized);\r
+ syncLayout.addWidget(hideSynchronized);\r
+ syncLayout.setStretch(1, 100);\r
+ synchronizedGroup.setLayout(syncLayout);\r
+ \r
+ QVBoxLayout mainLayout = new QVBoxLayout();\r
+ mainLayout.addWidget(dateCreatedGroup);\r
+ mainLayout.addWidget(dateChangedGroup);\r
+ mainLayout.addWidget(dateSubjectGroup);\r
+ mainLayout.addWidget(notebookGroup);\r
+ mainLayout.addWidget(tagsGroup);\r
+ mainLayout.addWidget(sourceUrlGroup);\r
+ mainLayout.addWidget(authorGroup);\r
+ mainLayout.addWidget(synchronizedGroup);\r
+ mainLayout.addStretch(1);\r
+ setLayout(mainLayout);\r
+ }\r
+ \r
+ public void setDateCreated(boolean value) {\r
+ if (value)\r
+ showDateCreated.click();\r
+ else\r
+ hideDateCreated.click();\r
+ }\r
+ \r
+ public void setDateSubject(boolean value) {\r
+ if (value)\r
+ showDateSubject.click();\r
+ else\r
+ hideDateSubject.click();\r
+ }\r
+\r
+ public void setDateChanged(boolean value) {\r
+ if (value)\r
+ showDateChanged.click();\r
+ else\r
+ hideDateChanged.click();\r
+ }\r
+\r
+ public void setAuthor(boolean value) {\r
+ if (value)\r
+ showAuthor.click();\r
+ else\r
+ hideAuthor.click();\r
+ }\r
+\r
+ public void setSourceUrl(boolean value) {\r
+ if (value)\r
+ sourceUrlShow.click();\r
+ else\r
+ sourceUrlHide.click();\r
+ }\r
+ public void setNotebook(boolean value) {\r
+ if (value)\r
+ showNotebook.click();\r
+ else\r
+ hideNotebook.click();\r
+ }\r
+ public void setTags(boolean value) {\r
+ if (value)\r
+ showTags.click();\r
+ else\r
+ hideTags.click();\r
+ }\r
+ public void setSynchronized(boolean value) {\r
+ if (value)\r
+ showSynchronized.click();\r
+ else\r
+ hideSynchronized.click();\r
+ }\r
+ \r
+ public boolean showDateCreated() {\r
+ return showDateCreated.isChecked();\r
+ }\r
+ public boolean showDateChanged() {\r
+ return showDateChanged.isChecked();\r
+ }\r
+ public boolean showDateSubject() {\r
+ return showDateSubject.isChecked();\r
+ }\r
+ public boolean showAuthor() {\r
+ return showAuthor.isChecked();\r
+ }\r
+ public boolean showSourceUrl() {\r
+ return sourceUrlShow.isChecked();\r
+ }\r
+ public boolean showTags() {\r
+ return showTags.isChecked();\r
+ }\r
+ public boolean showSynchronized() {\r
+ return showSynchronized.isChecked();\r
+ }\r
+ public boolean showNotebook() {\r
+ return showNotebook.isChecked();\r
+ }\r
+\r
+\r
+\r
+\r
+\r
+\r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.dialog;\r
+\r
+import com.trolltech.qt.gui.QComboBox;\r
+import com.trolltech.qt.gui.QGridLayout;\r
+import com.trolltech.qt.gui.QGroupBox;\r
+import com.trolltech.qt.gui.QHBoxLayout;\r
+import com.trolltech.qt.gui.QRadioButton;\r
+import com.trolltech.qt.gui.QWidget;\r
+\r
+public class ConfigShowEditorButtonsPage extends QWidget {\r
+ private final QRadioButton showUndo;\r
+ private final QRadioButton hideUndo;\r
+ private final QRadioButton showRedo;\r
+ private final QRadioButton hideRedo;\r
+ private final QRadioButton showCut;\r
+ private final QRadioButton hideCut;\r
+ private final QRadioButton showCopy;\r
+ private final QRadioButton hideCopy;\r
+ private final QRadioButton showPaste;\r
+ private final QRadioButton hidePaste;\r
+ private final QRadioButton showBold;\r
+ private final QRadioButton hideBold;\r
+ private final QRadioButton showItalic;\r
+ private final QRadioButton hideItalic;\r
+ private final QRadioButton showUnderline;\r
+ private final QRadioButton hideUnderline;\r
+ private final QRadioButton showStrikethrough;\r
+ private final QRadioButton hideStrikethrough;\r
+ private final QRadioButton showHline;\r
+ private final QRadioButton hideHline;\r
+ private final QRadioButton showOutdent;\r
+ private final QRadioButton hideOutdent;\r
+ private final QRadioButton showIndent;\r
+ private final QRadioButton hideIndent;\r
+ private final QRadioButton showBulletList;\r
+ private final QRadioButton hideBulletList;\r
+ private final QRadioButton showNumberList;\r
+ private final QRadioButton hideNumberList;\r
+ private final QRadioButton showFont;\r
+ private final QRadioButton hideFont;\r
+ private final QRadioButton showFontSize;\r
+ private final QRadioButton hideFontSize;\r
+ private final QRadioButton showFontColor;\r
+ private final QRadioButton hideFontColor;\r
+ private final QRadioButton showFontHighlight;\r
+ private final QRadioButton hideFontHighlight;\r
+ private final QRadioButton showAlignLeft;\r
+ private final QRadioButton hideAlignLeft;\r
+ private final QRadioButton showAlignCenter;\r
+ private final QRadioButton hideAlignCenter;\r
+ private final QRadioButton showAlignRight;\r
+ private final QRadioButton hideAlignRight;\r
+ \r
+ QComboBox messageCombo;\r
+ public ConfigShowEditorButtonsPage(QWidget parent) {\r
+ super(parent);\r
+\r
+ // Undo Button\r
+ QGroupBox undoGroup = new QGroupBox(tr("Undo"));\r
+ QHBoxLayout undoLayout = new QHBoxLayout();\r
+ showUndo = new QRadioButton(tr("Show"));\r
+ hideUndo = new QRadioButton(tr("Hide"));\r
+ undoLayout.addWidget(showUndo);\r
+ undoLayout.addWidget(hideUndo);\r
+ undoLayout.setStretch(1, 100);\r
+ undoGroup.setLayout(undoLayout);\r
+\r
+\r
+ // Redo Button\r
+ QGroupBox redoGroup = new QGroupBox(tr("Redo"));\r
+ QHBoxLayout redoLayout = new QHBoxLayout();\r
+ showRedo = new QRadioButton(tr("Show"));\r
+ hideRedo = new QRadioButton(tr("Hide"));\r
+ redoLayout.addWidget(showRedo);\r
+ redoLayout.addWidget(hideRedo);\r
+ redoLayout.setStretch(1, 100);\r
+ redoGroup.setLayout(redoLayout);\r
+\r
+\r
+ // Paste button\r
+ QGroupBox pasteGroup = new QGroupBox(tr("Paste"));\r
+ QHBoxLayout pasteLayout = new QHBoxLayout();\r
+ showPaste = new QRadioButton(tr("Show"));\r
+ hidePaste = new QRadioButton(tr("Hide"));\r
+ pasteLayout.addWidget(showPaste);\r
+ pasteLayout.addWidget(hidePaste);\r
+ pasteLayout.setStretch(1, 100);\r
+ pasteGroup.setLayout(pasteLayout);\r
+\r
+ // Copy button\r
+ QGroupBox copyGroup = new QGroupBox(tr("Copy"));\r
+ QHBoxLayout copyLayout = new QHBoxLayout();\r
+ showCopy = new QRadioButton(tr("Show"));\r
+ hideCopy = new QRadioButton(tr("Hide"));\r
+ copyLayout.addWidget(showCopy);\r
+ copyLayout.addWidget(hideCopy);\r
+ copyLayout.setStretch(1, 100);\r
+ copyGroup.setLayout(copyLayout);\r
+\r
+ \r
+ // Cut Button\r
+ QGroupBox cutGroup = new QGroupBox(tr("Cut"));\r
+ QHBoxLayout cutLayout = new QHBoxLayout();\r
+ showCut = new QRadioButton(tr("Show"));\r
+ hideCut = new QRadioButton(tr("Hide"));\r
+ cutLayout.addWidget(showCut);\r
+ cutLayout.addWidget(hideCut);\r
+ cutLayout.setStretch(1, 100);\r
+ cutGroup.setLayout(cutLayout);\r
+\r
+ // Notebook Column\r
+ QGroupBox underlineGroup = new QGroupBox(tr("Underline"));\r
+ QHBoxLayout underlineLayout = new QHBoxLayout();\r
+ showUnderline = new QRadioButton(tr("Show"));\r
+ hideUnderline = new QRadioButton(tr("Hide"));\r
+ underlineLayout.addWidget(showUnderline);\r
+ underlineLayout.addWidget(hideUnderline);\r
+ underlineLayout.setStretch(1, 100);\r
+ underlineGroup.setLayout(underlineLayout);\r
+\r
+ // Bold Button\r
+ QGroupBox boldGroup = new QGroupBox(tr("Bold"));\r
+ QHBoxLayout boldLayout = new QHBoxLayout();\r
+ showBold = new QRadioButton(tr("Show"));\r
+ hideBold = new QRadioButton(tr("Hide"));\r
+ boldLayout.addWidget(showBold);\r
+ boldLayout.addWidget(hideBold);\r
+ boldLayout.setStretch(1, 100);\r
+ boldGroup.setLayout(boldLayout);\r
+\r
+\r
+ // Italic Button\r
+ QGroupBox italicGroup = new QGroupBox(tr("Italic"));\r
+ QHBoxLayout italicLayout = new QHBoxLayout();\r
+ showItalic = new QRadioButton(tr("Show"));\r
+ hideItalic = new QRadioButton(tr("Hide"));\r
+ italicLayout.addWidget(showItalic);\r
+ italicLayout.addWidget(hideItalic);\r
+ italicLayout.setStretch(1, 100);\r
+ italicGroup.setLayout(italicLayout);\r
+\r
+ // Strikethrough Button\r
+ QGroupBox strikethroughGroup = new QGroupBox(tr("Strikethrough"));\r
+ QHBoxLayout strikethroughLayout = new QHBoxLayout();\r
+ showStrikethrough = new QRadioButton(tr("Show"));\r
+ hideStrikethrough = new QRadioButton(tr("Hide"));\r
+ strikethroughLayout.addWidget(showStrikethrough);\r
+ strikethroughLayout.addWidget(hideStrikethrough);\r
+ strikethroughLayout.setStretch(1, 100);\r
+ strikethroughGroup.setLayout(strikethroughLayout);\r
+\r
+\r
+ // Hline Button\r
+ QGroupBox hlineGroup = new QGroupBox(tr("Horizontal Line"));\r
+ QHBoxLayout hlineLayout = new QHBoxLayout();\r
+ showHline = new QRadioButton(tr("Show"));\r
+ hideHline = new QRadioButton(tr("Hide"));\r
+ hlineLayout.addWidget(showHline);\r
+ hlineLayout.addWidget(hideHline);\r
+ hlineLayout.setStretch(1, 100);\r
+ hlineGroup.setLayout(hlineLayout);\r
+\r
+ // Outdent Button\r
+ QGroupBox outdentGroup = new QGroupBox(tr("Outdent"));\r
+ QHBoxLayout outdentLayout = new QHBoxLayout();\r
+ showOutdent = new QRadioButton(tr("Show"));\r
+ hideOutdent = new QRadioButton(tr("Hide"));\r
+ outdentLayout.addWidget(showOutdent);\r
+ outdentLayout.addWidget(hideOutdent);\r
+ outdentLayout.setStretch(1, 100);\r
+ outdentGroup.setLayout(outdentLayout);\r
+\r
+ // Indent Button\r
+ QGroupBox indentGroup = new QGroupBox(tr("Indent"));\r
+ QHBoxLayout indentLayout = new QHBoxLayout();\r
+ showIndent = new QRadioButton(tr("Show"));\r
+ hideIndent = new QRadioButton(tr("Hide"));\r
+ indentLayout.addWidget(showIndent);\r
+ indentLayout.addWidget(hideIndent);\r
+ indentLayout.setStretch(1, 100);\r
+ indentGroup.setLayout(indentLayout);\r
+\r
+ // Bullet List Button\r
+ QGroupBox bulletListGroup = new QGroupBox(tr("Bullet List"));\r
+ QHBoxLayout bulletListLayout = new QHBoxLayout();\r
+ showBulletList = new QRadioButton(tr("Show"));\r
+ hideBulletList = new QRadioButton(tr("Hide"));\r
+ bulletListLayout.addWidget(showBulletList);\r
+ bulletListLayout.addWidget(hideBulletList);\r
+ bulletListLayout.setStretch(1, 100);\r
+ bulletListGroup.setLayout(bulletListLayout);\r
+\r
+ // Number List Button\r
+ QGroupBox numberListGroup = new QGroupBox(tr("Numbered List"));\r
+ QHBoxLayout numberListLayout = new QHBoxLayout();\r
+ showNumberList = new QRadioButton(tr("Show"));\r
+ hideNumberList = new QRadioButton(tr("Hide"));\r
+ numberListLayout.addWidget(showNumberList);\r
+ numberListLayout.addWidget(hideNumberList);\r
+ numberListLayout.setStretch(1, 100);\r
+ numberListGroup.setLayout(numberListLayout);\r
+\r
+ // Font drop down list\r
+ QGroupBox fontGroup = new QGroupBox(tr("Fonts"));\r
+ QHBoxLayout fontLayout = new QHBoxLayout();\r
+ showFont = new QRadioButton(tr("Show"));\r
+ hideFont = new QRadioButton(tr("Hide"));\r
+ fontLayout.addWidget(showFont);\r
+ fontLayout.addWidget(hideFont);\r
+ fontLayout.setStretch(1, 100);\r
+ fontGroup.setLayout(fontLayout);\r
+\r
+ // Font sizes drop down list\r
+ QGroupBox fontSizeGroup = new QGroupBox(tr("Font Size"));\r
+ QHBoxLayout fontSizeLayout = new QHBoxLayout();\r
+ showFontSize = new QRadioButton(tr("Show"));\r
+ hideFontSize = new QRadioButton(tr("Hide"));\r
+ fontSizeLayout.addWidget(showFontSize);\r
+ fontSizeLayout.addWidget(hideFontSize);\r
+ fontSizeLayout.setStretch(1, 100);\r
+ fontSizeGroup.setLayout(fontSizeLayout);\r
+ \r
+ // Font color button\r
+ QGroupBox fontColorGroup = new QGroupBox(tr("Font Color"));\r
+ QHBoxLayout fontColorLayout = new QHBoxLayout();\r
+ showFontColor = new QRadioButton(tr("Show"));\r
+ hideFontColor = new QRadioButton(tr("Hide"));\r
+ fontColorLayout.addWidget(showFontColor);\r
+ fontColorLayout.addWidget(hideFontColor);\r
+ fontColorLayout.setStretch(1, 100);\r
+ fontColorGroup.setLayout(fontColorLayout);\r
+ \r
+ // highlight button\r
+ QGroupBox fontHighlightGroup = new QGroupBox(tr("Text Highlight"));\r
+ QHBoxLayout fontHighlightLayout = new QHBoxLayout();\r
+ showFontHighlight = new QRadioButton(tr("Show"));\r
+ hideFontHighlight = new QRadioButton(tr("Hide"));\r
+ fontHighlightLayout.addWidget(showFontHighlight);\r
+ fontHighlightLayout.addWidget(hideFontHighlight);\r
+ fontHighlightLayout.setStretch(1, 100);\r
+ fontHighlightGroup.setLayout(fontHighlightLayout);\r
+ \r
+ // Align Left\r
+ QGroupBox alignLeftGroup = new QGroupBox(tr("Align Left"));\r
+ QHBoxLayout alignLeftLayout = new QHBoxLayout();\r
+ showAlignLeft = new QRadioButton(tr("Show"));\r
+ hideAlignLeft = new QRadioButton(tr("Hide"));\r
+ alignLeftLayout.addWidget(showAlignLeft);\r
+ alignLeftLayout.addWidget(hideAlignLeft);\r
+ alignLeftLayout.setStretch(1, 100);\r
+ alignLeftGroup.setLayout(alignLeftLayout);\r
+ \r
+ // Align Center\r
+ QGroupBox alignCenterGroup = new QGroupBox(tr("Align Center"));\r
+ QHBoxLayout alignCenterLayout = new QHBoxLayout();\r
+ showAlignCenter = new QRadioButton(tr("Show"));\r
+ hideAlignCenter = new QRadioButton(tr("Hide"));\r
+ alignCenterLayout.addWidget(showAlignCenter);\r
+ alignCenterLayout.addWidget(hideAlignCenter);\r
+ alignCenterLayout.setStretch(1, 100);\r
+ alignCenterGroup.setLayout(alignCenterLayout);\r
+ \r
+ // Align Right\r
+ QGroupBox alignRightGroup = new QGroupBox(tr("Align Right"));\r
+ QHBoxLayout alignRightLayout = new QHBoxLayout();\r
+ showAlignRight = new QRadioButton(tr("Show"));\r
+ hideAlignRight = new QRadioButton(tr("Hide"));\r
+ alignRightLayout.addWidget(showAlignRight);\r
+ alignRightLayout.addWidget(hideAlignRight);\r
+ alignRightLayout.setStretch(1, 100);\r
+ alignRightGroup.setLayout(alignRightLayout);\r
+ \r
+ QGridLayout mainLayout = new QGridLayout();\r
+ mainLayout.addWidget(undoGroup, 0,0);\r
+ mainLayout.addWidget(redoGroup, 0,1);\r
+ mainLayout.addWidget(cutGroup, 0,2);\r
+ mainLayout.addWidget(copyGroup, 1,0);\r
+ mainLayout.addWidget(pasteGroup, 1,1);\r
+ mainLayout.addWidget(boldGroup, 1,2);\r
+ mainLayout.addWidget(italicGroup, 2,0);\r
+ mainLayout.addWidget(underlineGroup, 2,1);\r
+ mainLayout.addWidget(strikethroughGroup, 2,2);\r
+ mainLayout.addWidget(hlineGroup, 3,0);\r
+ mainLayout.addWidget(indentGroup, 3,1);\r
+ mainLayout.addWidget(outdentGroup, 3,2);\r
+ mainLayout.addWidget(bulletListGroup, 4,0);\r
+ mainLayout.addWidget(numberListGroup, 4,1);\r
+ mainLayout.addWidget(fontGroup, 5,0);\r
+ mainLayout.addWidget(fontSizeGroup, 5,1);\r
+ mainLayout.addWidget(fontColorGroup, 5,2);\r
+ mainLayout.addWidget(fontHighlightGroup, 4,2);\r
+ mainLayout.addWidget(alignLeftGroup, 6,0);\r
+ mainLayout.addWidget(alignCenterGroup, 6,1);\r
+ mainLayout.addWidget(alignRightGroup, 6,2);\r
+\r
+ mainLayout.setColumnStretch(3, 100);\r
+ mainLayout.setRowStretch(7, 100);\r
+ setLayout(mainLayout);\r
+ }\r
+ \r
+ public void setUndo(boolean value) {\r
+ if (value)\r
+ showUndo.click();\r
+ else\r
+ hideUndo.click();\r
+ }\r
+ \r
+ public void setRedo(boolean value) {\r
+ if (value)\r
+ showRedo.click();\r
+ else\r
+ hideRedo.click();\r
+ }\r
+\r
+ public void setCut(boolean value) {\r
+ if (value)\r
+ showCut.click();\r
+ else\r
+ hideCut.click();\r
+ }\r
+\r
+ public void setCopy(boolean value) {\r
+ if (value)\r
+ showCopy.click();\r
+ else\r
+ hideCopy.click();\r
+ }\r
+\r
+ public void setPaste(boolean value) {\r
+ if (value)\r
+ showPaste.click();\r
+ else\r
+ hidePaste.click();\r
+ }\r
+ public void setUnderline(boolean value) {\r
+ if (value)\r
+ showUnderline.click();\r
+ else\r
+ hideUnderline.click();\r
+ }\r
+ public void setBold(boolean value) {\r
+ if (value)\r
+ showBold.click();\r
+ else\r
+ hideBold.click();\r
+ }\r
+ public void setItalic(boolean value) {\r
+ if (value)\r
+ showItalic.click();\r
+ else\r
+ hideItalic.click();\r
+ }\r
+ public void setStrikethrough(boolean value) {\r
+ if (value)\r
+ showStrikethrough.click();\r
+ else\r
+ hideStrikethrough.click();\r
+ }\r
+ public void setHline(boolean value) {\r
+ if (value)\r
+ showHline.click();\r
+ else\r
+ hideHline.click();\r
+ }\r
+ public void setIndent(boolean value) {\r
+ if (value)\r
+ showIndent.click();\r
+ else\r
+ hideIndent.click();\r
+ }\r
+ public void setOutdent(boolean value) {\r
+ if (value)\r
+ showOutdent.click();\r
+ else\r
+ hideOutdent.click();\r
+ }\r
+ public void setBulletList(boolean value) {\r
+ if (value)\r
+ showBulletList.click();\r
+ else\r
+ hideBulletList.click();\r
+ }\r
+ public void setNumberList(boolean value) {\r
+ if (value)\r
+ showNumberList.click();\r
+ else\r
+ hideNumberList.click();\r
+ }\r
+ public void setFont(boolean value) {\r
+ if (value)\r
+ showFont.click();\r
+ else\r
+ hideFont.click();\r
+ }\r
+ public void setFontSize(boolean value) {\r
+ if (value)\r
+ showFontSize.click();\r
+ else\r
+ hideFontSize.click();\r
+ }\r
+ public void setFontColor(boolean value) {\r
+ if (value)\r
+ showFontColor.click();\r
+ else\r
+ hideFontColor.click();\r
+ }\r
+ public void setFontHighlight(boolean value) {\r
+ if (value)\r
+ showFontHighlight.click();\r
+ else\r
+ hideFontHighlight.click();\r
+ }\r
+ public void setAlignLeft(boolean value) {\r
+ if (value)\r
+ showAlignLeft.click();\r
+ else\r
+ hideAlignLeft.click();\r
+ }\r
+ public void setAlignCenter(boolean value) {\r
+ if (value)\r
+ showAlignCenter.click();\r
+ else\r
+ hideAlignCenter.click();\r
+ }\r
+ public void setAlignRight(boolean value) {\r
+ if (value)\r
+ showAlignRight.click();\r
+ else\r
+ hideAlignRight.click();\r
+ }\r
+\r
+\r
+ \r
+ public boolean showUndo() {\r
+ return showUndo.isChecked();\r
+ }\r
+ public boolean showCut() {\r
+ return showCut.isChecked();\r
+ }\r
+ public boolean showRedo() {\r
+ return showRedo.isChecked();\r
+ }\r
+ public boolean showCopy() {\r
+ return showCopy.isChecked();\r
+ }\r
+ public boolean showPaste() {\r
+ return showPaste.isChecked();\r
+ }\r
+ public boolean showBold() {\r
+ return showBold.isChecked();\r
+ }\r
+ public boolean showUnderline() {\r
+ return showUnderline.isChecked();\r
+ }\r
+ public boolean showItalic() {\r
+ return showItalic.isChecked();\r
+ }\r
+ public boolean showStrikethrough() {\r
+ return showStrikethrough.isChecked();\r
+ } \r
+ public boolean showHline() {\r
+ return showHline.isChecked();\r
+ }\r
+ public boolean showIndent() {\r
+ return showIndent.isChecked();\r
+ }\r
+ public boolean showOutdent() {\r
+ return showOutdent.isChecked();\r
+ }\r
+ public boolean showNumberList() {\r
+ return showNumberList.isChecked();\r
+ }\r
+ public boolean showBulletList() {\r
+ return showBulletList.isChecked();\r
+ }\r
+ public boolean showFont() {\r
+ return showFont.isChecked();\r
+ } \r
+ public boolean showFontSize() {\r
+ return showFontSize.isChecked();\r
+ } \r
+ public boolean showFontColor() {\r
+ return showFontColor.isChecked();\r
+ } \r
+ public boolean showFontHilight() {\r
+ return showFontHighlight.isChecked();\r
+ } \r
+ public boolean showAlignCenter() {\r
+ return showAlignCenter.isChecked();\r
+ } public \r
+ boolean showAlignLeft() {\r
+ return showAlignLeft.isChecked();\r
+ }\r
+ public boolean showAlignRight() {\r
+ return showAlignRight.isChecked();\r
+ }\r
+\r
+\r
+\r
+\r
+\r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.dialog;\r
+\r
+import com.trolltech.qt.gui.QDialog;\r
+import com.trolltech.qt.gui.QGridLayout;\r
+import com.trolltech.qt.gui.QLabel;\r
+import com.trolltech.qt.gui.QLineEdit;\r
+import com.trolltech.qt.gui.QPushButton;\r
+\r
+public class DatabaseLoginDialog extends QDialog {\r
+\r
+ private boolean okPressed;\r
+ private final QLineEdit password;\r
+ private final QPushButton ok;\r
+ \r
+ \r
+ // Constructor\r
+ public DatabaseLoginDialog() {\r
+ okPressed = false;\r
+ setWindowTitle("Database Password");\r
+ QGridLayout grid = new QGridLayout();\r
+ setLayout(grid);\r
+ QGridLayout passwordGrid = new QGridLayout();\r
+ QGridLayout buttonGrid = new QGridLayout();\r
+ \r
+ String passwordValue = "";\r
+ \r
+ password = new QLineEdit(passwordValue);\r
+ password.setEchoMode(QLineEdit.EchoMode.Password);\r
+ \r
+ password.textChanged.connect(this, "validateInput()");\r
+ \r
+ passwordGrid.addWidget(new QLabel("Password"), 2,1);\r
+ passwordGrid.addWidget(password, 2, 2);\r
+ passwordGrid.setContentsMargins(10, 10, -10, -10);\r
+ grid.addLayout(passwordGrid,1,1);\r
+ \r
+ ok = new QPushButton("OK");\r
+ ok.clicked.connect(this, "okButtonPressed()");\r
+ QPushButton cancel = new QPushButton("Cancel");\r
+ cancel.clicked.connect(this, "cancelButtonPressed()");\r
+ buttonGrid.addWidget(ok, 1, 1);\r
+ buttonGrid.addWidget(cancel, 1,2);\r
+ grid.addLayout(buttonGrid,2,1);\r
+ }\r
+ \r
+ // The OK button was pressed\r
+ @SuppressWarnings("unused")\r
+ private void okButtonPressed() {\r
+ okPressed = true;\r
+ close();\r
+ }\r
+ \r
+ // The CANCEL button was pressed\r
+ @SuppressWarnings("unused")\r
+ private void cancelButtonPressed() {\r
+ okPressed = false;\r
+ close();\r
+ }\r
+\r
+ \r
+ // Get the password \r
+ public String getPassword() {\r
+ return password.text();\r
+ }\r
+ \r
+ // Check if the OK button was pressed\r
+ public boolean okPressed() {\r
+ return okPressed;\r
+ }\r
+ \r
+ // Validate user input\r
+ public void validateInput() {\r
+ ok.setEnabled(true);\r
+ if (password.text().trim().equals("")) {\r
+ ok.setEnabled(false);\r
+ return;\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.dialog;\r
+\r
+import java.text.NumberFormat;\r
+\r
+import com.trolltech.qt.gui.QDialog;\r
+import com.trolltech.qt.gui.QGridLayout;\r
+import com.trolltech.qt.gui.QLabel;\r
+import com.trolltech.qt.gui.QPushButton;\r
+\r
+public class DatabaseStatus extends QDialog {\r
+ QLabel indexNeeded;\r
+ QLabel syncNeeded;\r
+ QLabel noteCount;\r
+ QLabel notebookCount;\r
+ QLabel tagCount;\r
+ QLabel savedSearchCount;\r
+ QLabel resourceCount;\r
+ QLabel indexCount;\r
+ private final QPushButton ok;\r
+ \r
+ // Constructor\r
+ public DatabaseStatus() {\r
+ setWindowTitle("Current Database Status");\r
+ QGridLayout grid = new QGridLayout();\r
+ setLayout(grid);\r
+ noteCount = new QLabel();\r
+ indexNeeded = new QLabel();\r
+ syncNeeded = new QLabel();\r
+ notebookCount = new QLabel();\r
+ tagCount = new QLabel();\r
+ savedSearchCount = new QLabel(); \r
+ resourceCount = new QLabel();\r
+ indexCount = new QLabel();\r
+ \r
+ grid.addWidget(new QLabel("Notebooks:"), 0,0);\r
+ grid.addWidget(notebookCount, 0,1);\r
+ \r
+ grid.addWidget(new QLabel("Tags:"), 1,0);\r
+ grid.addWidget(tagCount, 1,1);\r
+ \r
+ grid.addWidget(new QLabel("Total Notes:"), 2,0);\r
+ grid.addWidget(noteCount, 2,1);\r
+ \r
+ grid.addWidget(new QLabel("Unsynchronized Notes:"), 3,0);\r
+ grid.addWidget(syncNeeded, 3, 1);\r
+ \r
+ grid.addWidget(new QLabel("Unindexed Notes:"), 4,0);\r
+ grid.addWidget(indexNeeded, 4, 1);\r
+ \r
+ grid.addWidget(new QLabel("Attachments/Images:"), 5,0);\r
+ grid.addWidget(resourceCount, 5,1);\r
+ \r
+ grid.addWidget(new QLabel("Saved Searches:"),6,0);\r
+ grid.addWidget(savedSearchCount, 6,1);\r
+ \r
+ grid.addWidget(new QLabel("Words In Index"), 7,0);\r
+ grid.addWidget(indexCount, 7,1);\r
+ \r
+ QGridLayout buttonLayout = new QGridLayout();\r
+ ok = new QPushButton("OK");\r
+ ok.clicked.connect(this, "okPushed()");\r
+ buttonLayout.addWidget(ok, 1, 1);\r
+ grid.addLayout(buttonLayout,8,1);\r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void okPushed() {\r
+ this.close();\r
+ }\r
+ public void setUnindexed(int d) {\r
+ indexNeeded.setText(NumberFormat.getInstance().format(d));\r
+ }\r
+ public void setUnsynchronized(int d) {\r
+ syncNeeded.setText(NumberFormat.getInstance().format(d));\r
+ }\r
+ public void setNoteCount(int d) {\r
+ noteCount.setText(NumberFormat.getInstance().format(d));\r
+ }\r
+ public void setNotebookCount(int d) {\r
+ notebookCount.setText(NumberFormat.getInstance().format(d));\r
+ }\r
+ public void setTagCount(int d) {\r
+ tagCount.setText(NumberFormat.getInstance().format(d));\r
+ }\r
+ public void setSavedSearchCount(int d) {\r
+ savedSearchCount.setText(NumberFormat.getInstance().format(d));\r
+ }\r
+ public void setResourceCount(int d) {\r
+ resourceCount.setText(NumberFormat.getInstance().format(d));\r
+ }\r
+ public void setWordCount(int d) {\r
+ indexCount.setText(NumberFormat.getInstance().format(d));\r
+ }\r
+ public QPushButton getOkButton() {\r
+ return ok;\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.dialog;\r
+\r
+\r
+import com.trolltech.qt.gui.QDialog;\r
+import com.trolltech.qt.gui.QGridLayout;\r
+import com.trolltech.qt.gui.QLabel;\r
+import com.trolltech.qt.gui.QLineEdit;\r
+import com.trolltech.qt.gui.QPushButton;\r
+\r
+public class EnCryptDialog extends QDialog {\r
+\r
+ private boolean okPressed;\r
+ private final QLineEdit password;\r
+ private final QLineEdit password2;\r
+ private final QLineEdit hint;\r
+ private final QPushButton ok;\r
+ private final QLabel error;\r
+ \r
+ \r
+ // Constructor\r
+ public EnCryptDialog() {\r
+ okPressed = false;\r
+ setWindowTitle("Encrypt Text");\r
+ QGridLayout grid = new QGridLayout();\r
+ QGridLayout input = new QGridLayout();\r
+ QGridLayout msgGrid = new QGridLayout();\r
+ QGridLayout button = new QGridLayout();\r
+ setLayout(grid);\r
+ \r
+ \r
+ hint = new QLineEdit("");\r
+ password = new QLineEdit("");\r
+ password.setEchoMode(QLineEdit.EchoMode.Password);\r
+ password2 = new QLineEdit("");\r
+ password2.setEchoMode(QLineEdit.EchoMode.Password);\r
+ \r
+ \r
+ input.addWidget(new QLabel("Password"), 1,1);\r
+ input.addWidget(password, 1, 2);\r
+ input.addWidget(new QLabel("Verify"), 2,1);\r
+ input.addWidget(password2, 2, 2);\r
+ input.addWidget(new QLabel("Hint"), 3,1);\r
+ input.addWidget(hint, 3, 2);\r
+ input.setContentsMargins(10, 10, -10, -10);\r
+ grid.addLayout(input, 1,1);\r
+ \r
+ error = new QLabel();\r
+ msgGrid.addWidget(error, 1, 1);\r
+ grid.addLayout(msgGrid, 2, 1);\r
+ \r
+ ok = new QPushButton("OK");\r
+ ok.clicked.connect(this, "okButtonPressed()");\r
+ ok.setEnabled(false);\r
+ \r
+ QPushButton cancel = new QPushButton("Cancel");\r
+ cancel.clicked.connect(this, "cancelButtonPressed()");\r
+ button.addWidget(ok, 1, 1);\r
+ button.addWidget(cancel, 1,2);\r
+ grid.addLayout(button, 3, 1);\r
+ \r
+ password.textChanged.connect(this, "validateInput()");\r
+ password2.textChanged.connect(this, "validateInput()");\r
+ hint.textChanged.connect(this, "validateInput()");\r
+ \r
+ }\r
+ \r
+ // The OK button was pressed\r
+ @SuppressWarnings("unused")\r
+ private void okButtonPressed() {\r
+ okPressed = true;\r
+ close();\r
+ }\r
+ // The CANCEL button was pressed\r
+ @SuppressWarnings("unused")\r
+ private void cancelButtonPressed() {\r
+ okPressed = false;\r
+ close();\r
+ }\r
+ // Get the the validated password from the field\r
+ public String getPasswordVerify() {\r
+ return password2.text();\r
+ }\r
+ // Get the password \r
+ public String getPassword() {\r
+ return password.text();\r
+ }\r
+ // Get the password hint\r
+ public String getHint() {\r
+ return hint.text();\r
+ }\r
+ // Check if the OK button was pressed\r
+ public boolean okPressed() {\r
+ return okPressed;\r
+ }\r
+ // Check if proper input was input\r
+ @SuppressWarnings("unused")\r
+ private void validateInput() {\r
+ ok.setEnabled(false);\r
+ error.setText("");\r
+ if (password.text().length()<4) {\r
+ error.setText("Password must be at least 4 characters");\r
+ return;\r
+ }\r
+ if (!password.text().equals(password2.text())) {\r
+ error.setText("Passwords do not match");\r
+ return;\r
+ }\r
+ if (hint.text().trim().equals("")) {\r
+ error.setText("Hint must be entered");\r
+ return;\r
+ }\r
+ \r
+ ok.setEnabled(true);\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.dialog;\r
+\r
+\r
+import com.trolltech.qt.gui.QCheckBox;\r
+import com.trolltech.qt.gui.QDialog;\r
+import com.trolltech.qt.gui.QGridLayout;\r
+import com.trolltech.qt.gui.QLabel;\r
+import com.trolltech.qt.gui.QLineEdit;\r
+import com.trolltech.qt.gui.QPushButton;\r
+\r
+public class EnDecryptDialog extends QDialog {\r
+\r
+ private boolean okPressed;\r
+ private final QLineEdit password;\r
+ private final QLineEdit password2;\r
+ private final QLabel hint;\r
+ private final QPushButton ok;\r
+ private final QLabel error;\r
+ private final QCheckBox permanent;\r
+ private final QCheckBox remember;\r
+ \r
+ \r
+ // Constructor\r
+ public EnDecryptDialog() {\r
+ okPressed = false;\r
+ setWindowTitle("Decrypt Text");\r
+ QGridLayout grid = new QGridLayout();\r
+ QGridLayout input = new QGridLayout();\r
+ QGridLayout msgGrid = new QGridLayout();\r
+ QGridLayout button = new QGridLayout();\r
+ setLayout(grid);\r
+ \r
+ \r
+ hint = new QLabel("");\r
+ password = new QLineEdit("");\r
+ password.setEchoMode(QLineEdit.EchoMode.Password);\r
+ password2 = new QLineEdit("");\r
+ password2.setEchoMode(QLineEdit.EchoMode.Password);\r
+ \r
+ \r
+ input.addWidget(new QLabel("Password"), 1,1);\r
+ input.addWidget(password, 1, 2);\r
+ input.addWidget(new QLabel("Verify"), 2,1);\r
+ input.addWidget(password2, 2, 2);\r
+ \r
+ permanent = new QCheckBox();\r
+ permanent.setText("Permanently Decrypt");\r
+ input.addWidget(permanent,3,2);\r
+\r
+ remember = new QCheckBox();\r
+ remember.setText("Remember For This Session");\r
+ input.addWidget(remember,4,2);\r
+ \r
+ input.setContentsMargins(10, 10, -10, -10);\r
+ grid.addLayout(input, 1,1);\r
+ \r
+ msgGrid.addWidget(new QLabel("Hint: "), 1,1);\r
+ msgGrid.addWidget(hint, 1, 2);\r
+ msgGrid.addWidget(new QLabel(""), 1,3);\r
+ msgGrid.setColumnStretch(3, 100);\r
+ error = new QLabel();\r
+ msgGrid.addWidget(error, 2, 2);\r
+ grid.addLayout(msgGrid, 2, 1); \r
+ \r
+ ok = new QPushButton("OK");\r
+ ok.clicked.connect(this, "okButtonPressed()");\r
+ ok.setEnabled(false);\r
+ \r
+ QPushButton cancel = new QPushButton("Cancel");\r
+ cancel.clicked.connect(this, "cancelButtonPressed()");\r
+ button.addWidget(ok, 1, 1);\r
+ button.addWidget(cancel, 1,2);\r
+ grid.addLayout(button, 3, 1);\r
+ \r
+ password.textChanged.connect(this, "validateInput()");\r
+ password2.textChanged.connect(this, "validateInput()");\r
+ \r
+ }\r
+ public boolean permanentlyDecrypt() {\r
+ return permanent.isChecked();\r
+ }\r
+ // The OK button was pressed\r
+ @SuppressWarnings("unused")\r
+ private void okButtonPressed() {\r
+ okPressed = true;\r
+ close();\r
+ }\r
+ // The CANCEL button was pressed\r
+ @SuppressWarnings("unused")\r
+ private void cancelButtonPressed() {\r
+ okPressed = false;\r
+ close();\r
+ }\r
+ // Get the the validated password from the field\r
+ public String getPasswordVerify() {\r
+ return password2.text();\r
+ }\r
+ // Get the password \r
+ public String getPassword() {\r
+ return password.text();\r
+ }\r
+ // Get the password hint\r
+ public void setHint(String h) {\r
+ hint.setText(h.replace("'", "'"));\r
+ }\r
+ // Set the error message\r
+ public void setError(String e) {\r
+ error.setText(e);\r
+ }\r
+ // Check if the OK button was pressed\r
+ public boolean okPressed() {\r
+ return okPressed;\r
+ }\r
+ // Check if we should remember the password\r
+ public boolean rememberPassword() {\r
+ return remember.isChecked();\r
+ }\r
+ // Check if proper input was input\r
+ @SuppressWarnings("unused")\r
+ private void validateInput() {\r
+ ok.setEnabled(false);\r
+ error.setText("");\r
+ if (!password.text().equals(password2.text())) {\r
+ error.setText("Passwords do not match");\r
+ return;\r
+ }\r
+ \r
+ ok.setEnabled(true);\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.dialog;\r
+\r
+\r
+import com.trolltech.qt.gui.QCheckBox;\r
+import com.trolltech.qt.gui.QDialog;\r
+import com.trolltech.qt.gui.QGridLayout;\r
+import com.trolltech.qt.gui.QLabel;\r
+import com.trolltech.qt.gui.QLineEdit;\r
+import com.trolltech.qt.gui.QPushButton;\r
+import com.trolltech.qt.webkit.QWebPage;\r
+\r
+public class FindDialog extends QDialog {\r
+\r
+ private final QLineEdit text;\r
+ private final QCheckBox wrap;\r
+ private final QCheckBox forward;\r
+ private final QCheckBox backward;\r
+ private final QCheckBox caseSensitive;\r
+ private final QPushButton ok;\r
+ \r
+ // Constructor\r
+ public FindDialog() {\r
+ setWindowTitle("Find");\r
+ QGridLayout grid = new QGridLayout();\r
+ setLayout(grid);\r
+\r
+ text = new QLineEdit();\r
+ wrap = new QCheckBox();\r
+ forward = new QCheckBox();\r
+ backward = new QCheckBox();\r
+ caseSensitive = new QCheckBox();\r
+\r
+ QGridLayout textGrid = new QGridLayout();\r
+ textGrid.addWidget(new QLabel("Text"), 1,1);\r
+ textGrid.addWidget(text, 1, 2);\r
+ grid.addLayout(textGrid, 1, 1);\r
+ \r
+ QGridLayout opt = new QGridLayout();\r
+ opt.addWidget(new QLabel("Case Sensitive"), 1,1);\r
+ opt.addWidget(caseSensitive, 1, 2);\r
+ opt.addWidget(new QLabel("Forward"), 2,1);\r
+ opt.addWidget(forward, 2, 2);\r
+ opt.addWidget(new QLabel("Backward"), 3,1);\r
+ opt.addWidget(backward, 3, 2);\r
+ opt.addWidget(new QLabel("Wrap"), 4,1);\r
+ opt.addWidget(wrap, 4, 2);\r
+ opt.setContentsMargins(10, 10, -10, -10);\r
+ grid.addLayout(opt,2,1);\r
+ \r
+ forward.clicked.connect(this, "forwardClicked()");\r
+ backward.clicked.connect(this, "backwardClicked()");\r
+ \r
+ QGridLayout buttonLayout = new QGridLayout();\r
+ ok = new QPushButton("OK");\r
+ ok.clicked.connect(this, "okButtonPressed()");\r
+ QPushButton cancel = new QPushButton("Close");\r
+ cancel.clicked.connect(this, "closeButtonPressed()");\r
+ buttonLayout.addWidget(ok, 1, 1);\r
+ buttonLayout.addWidget(cancel, 1,2);\r
+ grid.addLayout(buttonLayout,3,1);\r
+ }\r
+ \r
+ \r
+ //set focus on show\r
+ public void setFocusOnTextField() {\r
+ text.setFocus();\r
+ }\r
+ \r
+ // The OK button was pressed\r
+ @SuppressWarnings("unused")\r
+ private void okButtonPressed() {\r
+// close();\r
+ }\r
+ // The CANCEL button was pressed\r
+ @SuppressWarnings("unused")\r
+ private void closeButtonPressed() {\r
+ close();\r
+ }\r
+ // Check if the OK button was pressed\r
+ public void okPressed() {\r
+ return;\r
+ }\r
+ // The forward checkbox was clicked\r
+ @SuppressWarnings("unused")\r
+ private void forwardClicked() {\r
+ backward.setChecked(false);\r
+ }\r
+ // The backward checkbox was clicked\r
+ @SuppressWarnings("unused")\r
+ private void backwardClicked() {\r
+ forward.setChecked(false);\r
+ }\r
+ // Return search flags\r
+ public QWebPage.FindFlags getFlags() {\r
+ QWebPage.FindFlags flags = new QWebPage.FindFlags();\r
+ \r
+ if (wrap.isChecked()) \r
+ flags.set(QWebPage.FindFlag.FindWrapsAroundDocument);\r
+ if (backward.isChecked()) \r
+ flags.set(QWebPage.FindFlag.FindBackward);\r
+ if (caseSensitive.isChecked()) \r
+ flags.set(QWebPage.FindFlag.FindCaseSensitively);\r
+ \r
+ return flags;\r
+ }\r
+ // Return search text\r
+ public String getText() {\r
+ return text.text();\r
+ }\r
+ public QPushButton getOkButton() {\r
+ return ok;\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.dialog;\r
+\r
+\r
+import com.trolltech.qt.core.Qt;\r
+import com.trolltech.qt.gui.QDialog;\r
+import com.trolltech.qt.gui.QGridLayout;\r
+import com.trolltech.qt.gui.QLabel;\r
+import com.trolltech.qt.gui.QLineEdit;\r
+import com.trolltech.qt.gui.QPushButton;\r
+\r
+public class InsertLinkDialog extends QDialog {\r
+\r
+ private boolean okPressed;\r
+ private final QLineEdit url;\r
+ private final QPushButton ok;\r
+ private String urlText;\r
+ \r
+ \r
+ // Constructor\r
+ public InsertLinkDialog() {\r
+ okPressed = false;\r
+ setWindowTitle("Insert Link");\r
+ QGridLayout grid = new QGridLayout();\r
+ QGridLayout input = new QGridLayout();\r
+ QGridLayout button = new QGridLayout();\r
+ setLayout(grid);\r
+ \r
+ \r
+ url = new QLineEdit("");\r
+ \r
+ input.addWidget(new QLabel("Url"), 1,1);\r
+ input.addWidget(url, 1, 2);\r
+ input.setContentsMargins(10, 10, -10, -10);\r
+ grid.addLayout(input, 1,1);\r
+ \r
+ ok = new QPushButton("OK");\r
+ ok.clicked.connect(this, "accept()");\r
+ ok.setEnabled(false);\r
+ \r
+ QPushButton cancel = new QPushButton("Cancel");\r
+ cancel.clicked.connect(this, "reject()");\r
+ button.addWidget(ok, 1, 1);\r
+ button.addWidget(cancel, 1,2);\r
+ grid.addLayout(button, 3, 1);\r
+ url.textChanged.connect(this, "validateInput()");\r
+ \r
+ setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose);\r
+ }\r
+ \r
+ // Get the password \r
+ public String getUrl() {\r
+ return urlText;\r
+ }\r
+ // Set the url\r
+ public void setUrl(String u) {\r
+ url.setText(u);\r
+ }\r
+ // Check if the OK button was pressed\r
+ public boolean okPressed() {\r
+ return okPressed;\r
+ }\r
+ // Check that we have a valid URL\r
+ @SuppressWarnings("unused")\r
+ private void validateInput() {\r
+ ok.setEnabled(true);\r
+ if (url.text().trim().equals("")) \r
+ ok.setEnabled(false);\r
+ }\r
+ \r
+ @Override\r
+ public void accept() {\r
+ if (ok.isEnabled()) {\r
+ okPressed = true;\r
+ urlText = url.text();\r
+ super.accept();\r
+ }\r
+ }\r
+ \r
+ @Override\r
+ public void reject() {\r
+ okPressed=false;\r
+ super.reject();\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.dialog;\r
+\r
+import com.trolltech.qt.gui.QDialog;\r
+import com.trolltech.qt.gui.QGridLayout;\r
+import com.trolltech.qt.gui.QLabel;\r
+import com.trolltech.qt.gui.QLineEdit;\r
+import com.trolltech.qt.gui.QPushButton;\r
+\r
+import cx.fbn.nevernote.Global;\r
+\r
+public class LoginDialog extends QDialog {\r
+\r
+ private boolean okPressed;\r
+ private final QLineEdit userid;\r
+ private final QLineEdit password;\r
+ private final QPushButton ok;\r
+ \r
+ \r
+ // Constructor\r
+ public LoginDialog() {\r
+ okPressed = false;\r
+ setWindowTitle("NeverNote Login");\r
+ QGridLayout grid = new QGridLayout();\r
+ setLayout(grid);\r
+ QGridLayout passwordGrid = new QGridLayout();\r
+ QGridLayout buttonGrid = new QGridLayout();\r
+ \r
+ String useridValue = Global.username;\r
+ String passwordValue = Global.password;\r
+ \r
+ userid = new QLineEdit(useridValue);\r
+ password = new QLineEdit(passwordValue);\r
+ password.setEchoMode(QLineEdit.EchoMode.Password);\r
+ \r
+ userid.textChanged.connect(this, "validateInput()");\r
+ password.textChanged.connect(this, "validateInput()");\r
+ \r
+ passwordGrid.addWidget(new QLabel("Userid"), 1,1);\r
+ passwordGrid.addWidget(userid, 1, 2);\r
+ passwordGrid.addWidget(new QLabel("Password"), 2,1);\r
+ passwordGrid.addWidget(password, 2, 2);\r
+ passwordGrid.setContentsMargins(10, 10, -10, -10);\r
+ grid.addLayout(passwordGrid,1,1);\r
+ \r
+ ok = new QPushButton("OK");\r
+ ok.clicked.connect(this, "okButtonPressed()");\r
+ QPushButton cancel = new QPushButton("Cancel");\r
+ cancel.clicked.connect(this, "cancelButtonPressed()");\r
+ buttonGrid.addWidget(ok, 1, 1);\r
+ buttonGrid.addWidget(cancel, 1,2);\r
+ grid.addLayout(buttonGrid,2,1);\r
+ }\r
+ \r
+ // The OK button was pressed\r
+ @SuppressWarnings("unused")\r
+ private void okButtonPressed() {\r
+ okPressed = true;\r
+ close();\r
+ }\r
+ \r
+ // The CANCEL button was pressed\r
+ @SuppressWarnings("unused")\r
+ private void cancelButtonPressed() {\r
+ okPressed = false;\r
+ close();\r
+ }\r
+ \r
+ // Get the userid from the field\r
+ public String getUserid() {\r
+ return userid.text();\r
+ }\r
+ \r
+ // Get the password \r
+ public String getPassword() {\r
+ return password.text();\r
+ }\r
+ \r
+ // Check if the OK button was pressed\r
+ public boolean okPressed() {\r
+ return okPressed;\r
+ }\r
+ \r
+ // Validate user input\r
+ public void validateInput() {\r
+ ok.setEnabled(true);\r
+ if (userid.text().trim().equals("")) {\r
+ ok.setEnabled(false);\r
+ return;\r
+ } if (password.text().trim().equals("")) {\r
+ ok.setEnabled(false);\r
+ return;\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.dialog;\r
+\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.Notebook;\r
+import com.trolltech.qt.gui.QAbstractItemView;\r
+import com.trolltech.qt.gui.QDialog;\r
+import com.trolltech.qt.gui.QHBoxLayout;\r
+import com.trolltech.qt.gui.QIcon;\r
+import com.trolltech.qt.gui.QLabel;\r
+import com.trolltech.qt.gui.QListWidget;\r
+import com.trolltech.qt.gui.QListWidgetItem;\r
+import com.trolltech.qt.gui.QPushButton;\r
+import com.trolltech.qt.gui.QSpacerItem;\r
+import com.trolltech.qt.gui.QVBoxLayout;\r
+\r
+public class NotebookArchive extends QDialog {\r
+ private final QListWidget openBookList;\r
+ private final QListWidget closedBookList;\r
+ private final QPushButton okButton;\r
+ private final QPushButton cancelButton;\r
+ private boolean okClicked;\r
+ private final QPushButton leftButton;\r
+ private final QPushButton rightButton;\r
+ private final String iconPath = new String("classpath:cx/fbn/nevernote/icons/");\r
+ \r
+ public NotebookArchive(List<Notebook> allBooks, List<Notebook> archive) {\r
+ okClicked = false;\r
+ openBookList = new QListWidget();\r
+ openBookList.setSortingEnabled(true);\r
+ openBookList.setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection);\r
+ \r
+ okButton = new QPushButton();\r
+ okButton.setText("OK");\r
+ okButton.pressed.connect(this, "onClicked()");\r
+ \r
+ cancelButton = new QPushButton();\r
+ cancelButton.setText("Cancel");\r
+ cancelButton.pressed.connect(this, "onCancel()");\r
+ \r
+ QVBoxLayout openLayout = new QVBoxLayout();\r
+ openLayout.addWidget(new QLabel("Open Notebooks"));\r
+ openLayout.addWidget(openBookList);\r
+ \r
+ rightButton = new QPushButton(this);\r
+ rightButton.setIcon(new QIcon(iconPath+"forward.png"));\r
+ leftButton = new QPushButton(this);\r
+ leftButton.setIcon(new QIcon(iconPath+"back.png"));\r
+ leftButton.setEnabled(false);\r
+ rightButton.setEnabled(false);\r
+ \r
+ QVBoxLayout middleLayout = new QVBoxLayout();\r
+ middleLayout.addSpacerItem(new QSpacerItem(1,1));\r
+ middleLayout.addWidget(rightButton);\r
+ middleLayout.addWidget(leftButton);\r
+ middleLayout.addSpacerItem(new QSpacerItem(1,1));\r
+\r
+ QVBoxLayout closeLayout = new QVBoxLayout();\r
+ closeLayout.addWidget(new QLabel("Closed Notebooks"));\r
+ closedBookList = new QListWidget();\r
+ closedBookList.setSortingEnabled(true);\r
+ closedBookList.setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection);\r
+ closeLayout.addWidget(closedBookList);\r
+\r
+ openBookList.itemSelectionChanged.connect(this, "openBookSelected()");\r
+ closedBookList.itemSelectionChanged.connect(this, "closedBookSelected()");\r
+ leftButton.clicked.connect(this, "toOpenList()");\r
+ rightButton.clicked.connect(this, "toClosedList()");\r
+ \r
+ QHBoxLayout buttonLayout = new QHBoxLayout();\r
+ buttonLayout.addStretch(1);\r
+ buttonLayout.addWidget(okButton);\r
+ buttonLayout.addWidget(cancelButton);\r
+ setWindowTitle(tr("Open/Close Notebooks"));\r
+ \r
+ QHBoxLayout upperLayout = new QHBoxLayout();\r
+ upperLayout.addLayout(openLayout);\r
+ upperLayout.addLayout(middleLayout);\r
+ upperLayout.addLayout(closeLayout);\r
+ \r
+ QVBoxLayout mainLayout = new QVBoxLayout();\r
+ mainLayout.addLayout(upperLayout);\r
+ //mainLayout.addStretch(1);\r
+ mainLayout.addSpacing(1);\r
+ mainLayout.addLayout(buttonLayout);\r
+ setLayout(mainLayout);\r
+\r
+ for (int i=0; i<allBooks.size(); i++) {\r
+ boolean found = false;\r
+ for (int j=0; j<archive.size(); j++) {\r
+ if (archive.get(j).getName().equalsIgnoreCase(allBooks.get(i).getName())) {\r
+ found = true;\r
+ j=archive.size();\r
+ }\r
+ }\r
+ if (!found) {\r
+ QListWidgetItem item = new QListWidgetItem(allBooks.get(i).getName());\r
+ item.setSelected(false);\r
+ openBookList.addItem(item);\r
+ }\r
+ }\r
+ \r
+ setWindowTitle("Open Notebooks");\r
+ for (int i=0; i<archive.size(); i++) {\r
+ QListWidgetItem item = new QListWidgetItem(archive.get(i).getName());\r
+ item.setSelected(false);\r
+ closedBookList.addItem(item);\r
+ }\r
+ openBookList.itemSelectionChanged.connect(this, "itemSelected()");\r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void toClosedList() {\r
+ List<QListWidgetItem> items = openBookList.selectedItems();\r
+ for (int i=items.size()-1; i>=0; i--) {\r
+ int row = openBookList.row(items.get(i));\r
+ openBookList.takeItem(row);\r
+ closedBookList.addItem(items.get(i).text());\r
+ }\r
+ if (openBookList.count() == 0)\r
+ okButton.setEnabled(false);\r
+ rightButton.setEnabled(false);\r
+ }\r
+ \r
+ \r
+ @SuppressWarnings("unused")\r
+ private void toOpenList() {\r
+ List<QListWidgetItem> items = closedBookList.selectedItems();\r
+ for (int i=items.size()-1; i>=0; i--) {\r
+ int row = closedBookList.row(items.get(i));\r
+ closedBookList.takeItem(row);\r
+ openBookList.addItem(items.get(i).text());\r
+ }\r
+ okButton.setEnabled(true);\r
+ leftButton.setEnabled(false);\r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void closedBookSelected() {\r
+ if (closedBookList.selectedItems().size() > 0)\r
+ leftButton.setEnabled(true);\r
+ else\r
+ leftButton.setEnabled(false);\r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void openBookSelected() {\r
+ if (openBookList.selectedItems().size() > 0)\r
+ rightButton.setEnabled(true);\r
+ else\r
+ rightButton.setEnabled(false);\r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void onClicked() {\r
+ okClicked = true;\r
+ close();\r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void onCancel() {\r
+ okClicked = false;\r
+ close();\r
+ }\r
+ \r
+ public boolean okClicked() {\r
+ return okClicked;\r
+ }\r
+ \r
+ public QListWidget getOpenBookList() {\r
+ return openBookList;\r
+ }\r
+ \r
+ public QListWidget getClosedBookList() {\r
+ return closedBookList;\r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void itemSelected() {\r
+ if (openBookList.selectedItems().size() == openBookList.count()) {\r
+ okButton.setEnabled(false);\r
+ rightButton.setEnabled(false);\r
+ return;\r
+ }\r
+ rightButton.setEnabled(true);\r
+ okButton.setEnabled(true);\r
+ }\r
+}\r
--- /dev/null
+/*
+ * This file is part of NeverNote
+ * 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;
+
+import java.util.List;
+
+import com.evernote.edam.type.Notebook;
+import com.trolltech.qt.gui.QCheckBox;
+import com.trolltech.qt.gui.QDialog;
+import com.trolltech.qt.gui.QGridLayout;
+import com.trolltech.qt.gui.QLabel;
+import com.trolltech.qt.gui.QLineEdit;
+import com.trolltech.qt.gui.QPushButton;
+
+public class NotebookEdit extends QDialog {
+ private boolean okPressed;
+ private final QLineEdit notebook;
+ private final QCheckBox localRemote;
+ private final QPushButton ok;
+ private List<Notebook> currentNotebooks;
+
+ // Constructor
+ public NotebookEdit() {
+ okPressed = false;
+ setWindowTitle("Add Notebook");
+ QGridLayout grid = new QGridLayout();
+ setLayout(grid);
+
+ QGridLayout textLayout = new QGridLayout();
+ notebook = new QLineEdit();
+ textLayout.addWidget(new QLabel("Notebook Name"), 1,1);
+ textLayout.addWidget(notebook, 1, 2);
+ textLayout.setContentsMargins(10, 10,-10, -10);
+ grid.addLayout(textLayout,1,1);
+
+ localRemote = new QCheckBox();
+ localRemote.setText("Local Notebook");
+ localRemote.setChecked(false);
+ grid.addWidget(localRemote, 2,1);
+
+ QGridLayout buttonLayout = new QGridLayout();
+ ok = new QPushButton("OK");
+ ok.clicked.connect(this, "okButtonPressed()");
+ ok.setEnabled(false);
+ QPushButton cancel = new QPushButton("Cancel");
+ cancel.clicked.connect(this, "cancelButtonPressed()");
+ notebook.textChanged.connect(this, "textChanged()");
+ buttonLayout.addWidget(ok, 1, 1);
+ buttonLayout.addWidget(cancel, 1,2);
+ grid.addLayout(buttonLayout,3,1);
+ }
+
+ // The OK button was pressed
+ @SuppressWarnings("unused")
+ private void okButtonPressed() {
+ okPressed = true;
+ close();
+ }
+
+ // The CANCEL button was pressed
+ @SuppressWarnings("unused")
+ private void cancelButtonPressed() {
+ okPressed = false;
+ close();
+ }
+
+ // Get the userid from the field
+ public String getNotebook() {
+ return notebook.text();
+ }
+
+ // Set the notebook name
+ public void setNotebook(String name) {
+ notebook.setText(name);
+ }
+
+ // Is this a local notebook?
+ public boolean isLocal() {
+ return localRemote.isChecked();
+ }
+
+ // Hide the local/remote checkbox
+ public void setLocalCheckboxEnabled(boolean visible) {
+ localRemote.setEnabled(visible);
+ }
+
+
+ // Check if the OK button was pressed
+ public boolean okPressed() {
+ return okPressed;
+ }
+
+ // Set the window title
+ public void setTitle(String s) {
+ setWindowTitle(s);
+ }
+
+ // set notebooks
+ public void setNotebooks(List<Notebook> n) {
+ currentNotebooks = n;
+ }
+
+ // Watch what text is being entered
+ @SuppressWarnings("unused")
+ private void textChanged() {
+ if (notebook.text().equals("")) {
+ ok.setEnabled(false);
+ return;
+ }
+ if (notebook.text().equalsIgnoreCase("All Notebooks")) {
+ ok.setEnabled(false);
+ return;
+ }
+ if (currentNotebooks == null) {
+ ok.setEnabled(false);
+ return;
+ }
+ for (int i=0; i<currentNotebooks.size(); i++) {
+ String s = currentNotebooks.get(i).getName();
+ if (s.equalsIgnoreCase(notebook.text())) {
+ ok.setEnabled(false);
+ return;
+ }
+ }
+ ok.setEnabled(true);
+ }
+}
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.dialog;\r
+\r
+import java.io.File;\r
+import java.text.SimpleDateFormat;\r
+import java.util.List;\r
+\r
+import com.evernote.edam.notestore.NoteVersionId;\r
+import com.evernote.edam.type.Note;\r
+import com.evernote.edam.type.Resource;\r
+import com.trolltech.qt.core.QByteArray;\r
+import com.trolltech.qt.core.QFile;\r
+import com.trolltech.qt.core.QIODevice;\r
+import com.trolltech.qt.core.Qt.ContextMenuPolicy;\r
+import com.trolltech.qt.gui.QComboBox;\r
+import com.trolltech.qt.gui.QDialog;\r
+import com.trolltech.qt.gui.QHBoxLayout;\r
+import com.trolltech.qt.gui.QLabel;\r
+import com.trolltech.qt.gui.QPushButton;\r
+import com.trolltech.qt.gui.QVBoxLayout;\r
+import com.trolltech.qt.xml.QDomAttr;\r
+import com.trolltech.qt.xml.QDomDocument;\r
+import com.trolltech.qt.xml.QDomElement;\r
+import com.trolltech.qt.xml.QDomNodeList;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.gui.BrowserWindow;\r
+import cx.fbn.nevernote.sql.DatabaseConnection;\r
+\r
+public class OnlineNoteHistory extends QDialog {\r
+ public final QPushButton restoreAsNew;\r
+ public final QPushButton restore;\r
+ private DatabaseConnection conn;\r
+ public final QComboBox historyCombo; \r
+ private final BrowserWindow browser;\r
+ \r
+ // Constructor\r
+ public OnlineNoteHistory(DatabaseConnection c) {\r
+ setWindowTitle("Online Note History");\r
+ QVBoxLayout main = new QVBoxLayout();\r
+ setLayout(main);\r
+ historyCombo = new QComboBox(this);\r
+ \r
+ QHBoxLayout comboLayout = new QHBoxLayout();\r
+ comboLayout.addWidget(new QLabel("History Date:"));\r
+ comboLayout.addWidget(historyCombo);\r
+ comboLayout.addStretch(100);\r
+ \r
+ main.addLayout(comboLayout);\r
+ \r
+ browser = new BrowserWindow(conn);\r
+ main.addWidget(browser);\r
+ browser.titleLabel.setVisible(false);\r
+ browser.notebookBox.setVisible(false);\r
+ browser.hideButtons();\r
+ browser.tagEdit.setVisible(false);\r
+ browser.tagLabel.setVisible(false);\r
+ \r
+ QHBoxLayout buttonLayout = new QHBoxLayout();\r
+ buttonLayout.addStretch(100);\r
+ restore = new QPushButton("Restore Note");\r
+ restore.clicked.connect(this, "restorePushed()");\r
+ \r
+ restoreAsNew = new QPushButton("Restore As New Note");\r
+ restoreAsNew.clicked.connect(this, "restoreAsNewPushed()");\r
+ QPushButton cancel = new QPushButton("Cancel");\r
+ cancel.clicked.connect(this, "cancelPressed()");\r
+ \r
+ buttonLayout.addWidget(restore);\r
+ buttonLayout.addWidget(restoreAsNew);\r
+ buttonLayout.addWidget(cancel);\r
+ main.addLayout(buttonLayout);\r
+ \r
+ browser.getBrowser().setContextMenuPolicy(ContextMenuPolicy.NoContextMenu);\r
+\r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void restoreAsNewPushed() {\r
+ this.close();\r
+ }\r
+ @SuppressWarnings("unused")\r
+ private void restorePushed() {\r
+ this.close();\r
+ }\r
+ @SuppressWarnings("unused")\r
+ private void cancelPressed() {\r
+ this.close();\r
+ }\r
+ \r
+ public void setCurrent(boolean isDirty) {\r
+ if (isDirty) \r
+ historyCombo.addItem(new String("Current (Non Synchronized)"));\r
+ else\r
+ historyCombo.addItem(new String("Current (Synchronized)"));\r
+ \r
+ }\r
+ \r
+ public void load(List<NoteVersionId> versions) {\r
+ String fmt = Global.getDateFormat() + " " + Global.getTimeFormat();\r
+ String dateTimeFormat = new String(fmt);\r
+ SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);\r
+ \r
+ for (int i=0; i<versions.size(); i++) {\r
+ StringBuilder versionDate = new StringBuilder(simple.format(versions.get(i).getServiceUpdated()));\r
+ historyCombo.addItem(versionDate.toString());\r
+ }\r
+ }\r
+ \r
+ public void setContent(Note currentNote) {\r
+ StringBuffer b = rebuildNoteHTML(currentNote);\r
+ StringBuffer js = new StringBuffer();\r
+\r
+ // We need to prepend the note with <HEAD></HEAD> or encoded characters are ugly \r
+ js.append("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">"); \r
+ js.append("<style type=\"text/css\">en-crypt-temp { border-style:solid; border-color:blue; padding:1mm 1mm 1mm 1mm; }</style>");\r
+ js.append("</head>");\r
+ js.append(b.toString());\r
+ js.append("</HTML>");\r
+// js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml2.dtd'>", "");\r
+// js.replace("<?xml version='1.0' encoding='UTF-8'?>", "");\r
+ \r
+ browser.setNote(currentNote);\r
+ browser.getBrowser().page().mainFrame().setHtml(js.toString());\r
+ }\r
+ \r
+ //*************************************************\r
+ //* XML Modifying Methods\r
+ //*************************************************\r
+ private StringBuffer rebuildNoteHTML(Note note) {\r
+ QDomDocument doc = new QDomDocument();\r
+ QDomDocument.Result result = doc.setContent(note.getContent());\r
+ if (!result.success) {\r
+ return new StringBuffer(note.getContent());\r
+ }\r
+ \r
+ doc = modifyTags(note, doc);\r
+ QDomElement docElem = doc.documentElement();\r
+ docElem.setTagName("Body");\r
+ \r
+ // Fix the stupid problem where inserting an <img> tag after an <a> tag (which is done\r
+ // to get the <en-media> application tag to work properly) causes spaces to be inserted\r
+ // between the <a> & <img>. This messes things up later. This is an ugly hack.\r
+ String docString = doc.toString();\r
+ StringBuffer html = new StringBuffer(docString.substring(docString.toLowerCase().indexOf("<body>")));\r
+ \r
+ for (int i=html.indexOf("<a en-tag=\"en-media\" ", 0); i>-1; i=html.indexOf("<a en-tag=\"en-media\" ", i)) {\r
+ i=html.indexOf(">\n",i+1);\r
+ int z = html.indexOf("<img",i);\r
+ for (int j=z-1; j>i; j--) \r
+ html.deleteCharAt(j);\r
+ i=html.indexOf("/>", z+1);\r
+ z = html.indexOf("</a>",i);\r
+ for (int j=z-1; j>i+1; j--) \r
+ html.deleteCharAt(j);\r
+ } \r
+ return html;\r
+ } \r
+\r
+ \r
+ \r
+ private QDomDocument modifyTags(Note note, QDomDocument doc) {\r
+ QDomElement docElem = doc.documentElement();\r
+ \r
+ // Modify en-media tags\r
+ QDomNodeList anchors = docElem.elementsByTagName("en-media");\r
+ int enMediaCount = anchors.length();\r
+ for (int i=enMediaCount-1; i>=0; i--) {\r
+ QDomElement enmedia = anchors.at(i).toElement();\r
+ if (enmedia.hasAttribute("type")) {\r
+ QDomAttr attr = enmedia.attributeNode("type");\r
+ QDomAttr hash = enmedia.attributeNode("hash");\r
+ String[] type = attr.nodeValue().split("/");\r
+ String appl = type[1];\r
+ \r
+ if (type[0] != null) {\r
+ if (type[0].equals("image")) {\r
+ modifyImageTags(note, docElem, enmedia, hash);\r
+ }\r
+ if (!type[0].equals("image")) {\r
+ modifyApplicationTags(note, doc, docElem, enmedia, hash, appl);\r
+ }\r
+// if (type[0].equals("audio")) {\r
+// modifyApplicationTags(doc, docElem, enmedia, hash, appl);\r
+// }\r
+ }\r
+ }\r
+ }\r
+ \r
+ // Modify todo tags\r
+ anchors = docElem.elementsByTagName("en-todo");\r
+ int enTodoCount = anchors.length();\r
+ for (int i=enTodoCount-1; i>=0; i--) {\r
+ QDomElement enmedia = anchors.at(i).toElement();\r
+ modifyTodoTags(enmedia);\r
+ }\r
+ \r
+ // Modify en-crypt tags\r
+ anchors = docElem.elementsByTagName("en-crypt");\r
+ int enCryptLen = anchors.length();\r
+ for (int i=enCryptLen-1; i>=0; i--) {\r
+ QDomElement enmedia = anchors.at(i).toElement();\r
+ //enmedia.setAttribute("style","display:none");\r
+ enmedia.setAttribute("contentEditable","false");\r
+ enmedia.setAttribute("src", Global.getDirectoryPath()+"images/encrypt.png");\r
+ enmedia.setAttribute("en-tag","en-crypt");\r
+ enmedia.setAttribute("alt", enmedia.text());\r
+ Global.cryptCounter++;\r
+ enmedia.setAttribute("id", "crypt"+Global.cryptCounter.toString());\r
+ String encryptedText = enmedia.text();\r
+ \r
+ // If the encryption string contains crlf at the end, remove them because they mess up the javascript.\r
+ if (encryptedText.endsWith("\n"))\r
+ encryptedText = encryptedText.substring(0,encryptedText.length()-1);\r
+ if (encryptedText.endsWith("\r"))\r
+ encryptedText = encryptedText.substring(0,encryptedText.length()-1);\r
+ \r
+ // Add the commands\r
+ enmedia.setAttribute("onClick", "window.jambi.decryptText('crypt"+Global.cryptCounter.toString()+"', '"+encryptedText+"', '"+enmedia.attribute("hint")+"');");\r
+ enmedia.setAttribute("onMouseOver", "style.cursor='hand'");\r
+ enmedia.setTagName("img");\r
+ enmedia.removeChild(enmedia.firstChild()); // Remove the actual encrypted text\r
+ }\r
+\r
+ return doc;\r
+ }\r
+ \r
+ \r
+ \r
+ \r
+ private void modifyApplicationTags(Note n, QDomDocument doc, QDomElement docElem, QDomElement enmedia, QDomAttr hash, String appl) {\r
+ \r
+ Resource r = null;\r
+ for (int i=0; i<n.getResourcesSize(); i++) {\r
+ String hashValue = hash.value();\r
+ byte res[] = n.getResources().get(i).getData().getBodyHash();\r
+ String resourceHashValue = new String(Global.byteArrayToHexString(res));\r
+ if (resourceHashValue.equalsIgnoreCase(hashValue)) {\r
+ r = n.getResources().get(i);\r
+ i=n.getResourcesSize();\r
+ }\r
+ }\r
+ \r
+ if (r!= null) {\r
+ if (r.getData()!=null) {\r
+ // Did we get a generic applicaiton? Then look at the file name to \r
+ // try and find a good application type for the icon\r
+ if (appl.equalsIgnoreCase("octet-stream")) {\r
+ if (r.getAttributes() != null && r.getAttributes().getFileName() != null) {\r
+ String fn = r.getAttributes().getFileName();\r
+ int pos = fn.indexOf(".");\r
+ if (pos > -1) {\r
+ appl = fn.substring(pos+1);\r
+ }\r
+ }\r
+ }\r
+ \r
+ String fileDetails = null;\r
+ if (r.getAttributes() != null && r.getAttributes().getFileName() != null && !r.getAttributes().getFileName().equals(""))\r
+ fileDetails = r.getAttributes().getFileName();\r
+ if (fileDetails != null && !fileDetails.equals("")) \r
+ enmedia.setAttribute("href", "nnres://" +r.getGuid()+n.getUpdateSequenceNum() +Global.attachmentNameDelimeter +fileDetails);\r
+ else\r
+ enmedia.setAttribute("href", "nnres://" +r.getGuid()+n.getUpdateSequenceNum() +Global.attachmentNameDelimeter +appl);\r
+ if (fileDetails == null || fileDetails.equals(""))\r
+ fileDetails = "";\r
+ enmedia.setAttribute("en-tag", "en-media");\r
+ enmedia.setAttribute("guid", r.getGuid());\r
+ enmedia.setTagName("a");\r
+ QDomElement newText = doc.createElement("img");\r
+ String icon = findIcon(appl);\r
+ if (icon.equals("attachment.png"))\r
+ icon = findIcon(fileDetails.substring(fileDetails.indexOf(".")+1));\r
+ newText.setAttribute("src", Global.getDirectoryPath()+"images"+File.separator +icon); \r
+ newText.setAttribute("title", fileDetails);\r
+ enmedia.removeChild(enmedia.firstChild());\r
+ enmedia.appendChild(newText);\r
+ }\r
+ }\r
+ }\r
+ // find the appropriate icon for an attachment\r
+ private String findIcon(String appl) {\r
+ appl = appl.toLowerCase();\r
+ File f = new File(Global.getDirectoryPath()+"images"+File.separator +appl +".png");\r
+ if (f.exists())\r
+ return appl+".png";\r
+ return "attachment.png";\r
+ }\r
+ \r
+ \r
+ \r
+ \r
+ \r
+ \r
+ \r
+ private void modifyTodoTags(QDomElement todo) {\r
+ todo.setAttribute("type", "checkbox");\r
+ String checked = todo.attribute("checked");\r
+ todo.removeAttribute("checked");\r
+ if (checked.equalsIgnoreCase("true"))\r
+ todo.setAttribute("checked", "");\r
+ else\r
+ todo.setAttribute("unchecked","");\r
+ todo.setAttribute("value", checked);\r
+ todo.setAttribute("onClick", "value=checked;window.jambi.contentChanged(); ");\r
+ todo.setTagName("input");\r
+ }\r
+ \r
+ \r
+ private void modifyImageTags(Note note, QDomElement docElem, QDomElement enmedia, QDomAttr hash) {\r
+ String type = enmedia.attribute("type");\r
+ if (type.startsWith("image/"))\r
+ type = "."+type.substring(6);\r
+ else\r
+ type="";\r
+ \r
+ Resource r = null;\r
+ for (int i=0; i<note.getResourcesSize(); i++) {\r
+ String hashValue = hash.value();\r
+ byte res[] = note.getResources().get(i).getData().getBodyHash();\r
+ String resourceHashValue = new String(Global.byteArrayToHexString(res));\r
+ if (hashValue.equalsIgnoreCase(resourceHashValue)) {\r
+ r = note.getResources().get(i);\r
+ i=note.getResourcesSize();\r
+ }\r
+ }\r
+ \r
+ if (r==null)\r
+ return;\r
+ \r
+ QFile tfile = new QFile(Global.getDirectoryPath()+"res"+File.separator +r.getGuid()+note.getUpdateSequenceNum()+type);\r
+ if (!tfile.exists()) {\r
+ if (r!= null && r.getData() != null && r.getData().getBody().length > 0) {\r
+ tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));\r
+ QByteArray binData = new QByteArray(r.getData().getBody());\r
+ tfile.write(binData);\r
+ tfile.close();\r
+ enmedia.setAttribute("src", tfile.fileName());\r
+ enmedia.setAttribute("en-tag", "en-media");\r
+ enmedia.setNodeValue("");\r
+ enmedia.setAttribute("guid", r.getGuid());\r
+ enmedia.setTagName("img");\r
+ }\r
+ }\r
+ enmedia.setAttribute("src", tfile.fileName());\r
+ enmedia.setAttribute("en-tag", "en-media");\r
+ enmedia.setNodeValue("");\r
+ enmedia.setAttribute("guid", r.getGuid());\r
+ enmedia.setTagName("img");\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.dialog;\r
+\r
+import com.trolltech.qt.gui.QDialog;\r
+import com.trolltech.qt.gui.QHBoxLayout;\r
+import com.trolltech.qt.gui.QImage;\r
+import com.trolltech.qt.gui.QPixmap;\r
+import com.trolltech.qt.gui.QPushButton;\r
+import com.trolltech.qt.gui.QScrollArea;\r
+import com.trolltech.qt.gui.QVBoxLayout;\r
+import com.trolltech.qt.gui.QWidget;\r
+\r
+import cx.fbn.nevernote.Global;\r
+public class PreviewDialog extends QDialog {\r
+\r
+ \r
+ public PreviewDialog(QWidget parent) {\r
+ \r
+ QWidget masterLabel = new QWidget();\r
+ \r
+ QVBoxLayout subLayout = new QVBoxLayout();\r
+ setMouseTracking(true);\r
+ \r
+ PreviewImage imageLabel = new PreviewImage(masterLabel);\r
+ imageLabel.ID = "Number 1";\r
+ QImage image = new QImage(Global.currentDir+"res/thumbnail.png");\r
+ imageLabel.setPixmap(QPixmap.fromImage(image).scaled(400, 400));\r
+ subLayout.addWidget(imageLabel);\r
+\r
+ PreviewImage imageLabel2 = new PreviewImage(masterLabel);\r
+ imageLabel2.ID = "Number 2";\r
+ QImage image2 = new QImage(Global.currentDir+"res/thumbnail.png");\r
+ imageLabel2.setPixmap(QPixmap.fromImage(image2).scaled(400,400));\r
+ subLayout.addWidget(imageLabel2);\r
+ masterLabel.setLayout(subLayout);\r
+\r
+ QScrollArea scrollArea = new QScrollArea();\r
+ scrollArea.setWidget(masterLabel);\r
+ \r
+ QPushButton okButton = new QPushButton(tr("OK"));\r
+ okButton.clicked.connect(this, "okPushed()");\r
+ ;\r
+ \r
+ QVBoxLayout verticalLayout = new QVBoxLayout();\r
+ verticalLayout.addWidget(scrollArea);\r
+ \r
+ QHBoxLayout buttonLayout = new QHBoxLayout();\r
+ buttonLayout.addStretch(1);\r
+ buttonLayout.addWidget(okButton);\r
+ setWindowTitle(tr("Note Preview")); \r
+ \r
+ QVBoxLayout mainLayout = new QVBoxLayout();\r
+ mainLayout.addLayout(verticalLayout);\r
+ mainLayout.addSpacing(1);\r
+ mainLayout.addLayout(buttonLayout);\r
+ setLayout(mainLayout);\r
+\r
+ }\r
+ public void okPushed() {\r
+\r
+ close();\r
+ }\r
+ \r
+}\r
--- /dev/null
+package cx.fbn.nevernote.dialog;\r
+\r
+import com.trolltech.qt.core.QEvent;\r
+import com.trolltech.qt.gui.QLabel;\r
+import com.trolltech.qt.gui.QMouseEvent;\r
+import com.trolltech.qt.gui.QWidget;\r
+\r
+public class PreviewImage extends QLabel {\r
+\r
+ public String ID;\r
+ \r
+ public PreviewImage(QWidget parent) {\r
+ super(parent);\r
+ setMouseTracking(true);\r
+ }\r
+ \r
+ @Override\r
+ public void enterEvent(QEvent arg__1) {\r
+ System.out.println("Entering "+ID);\r
+ }\r
+ \r
+ @Override\r
+ public void leaveEvent(QEvent arg__1) {\r
+ System.out.println("Leaving "+ID);\r
+ }\r
+ \r
+ @Override\r
+ public void mousePressEvent(QMouseEvent arg__1) {\r
+ System.out.println("Selection of " +ID);\r
+ }\r
+ \r
+}\r
--- /dev/null
+/*
+ * This file is part of NeverNote
+ * 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;
+
+import java.util.List;
+
+import com.evernote.edam.type.SavedSearch;
+import com.trolltech.qt.gui.QDialog;
+import com.trolltech.qt.gui.QGridLayout;
+import com.trolltech.qt.gui.QLabel;
+import com.trolltech.qt.gui.QLineEdit;
+import com.trolltech.qt.gui.QPushButton;
+
+public class SavedSearchEdit extends QDialog {
+ private boolean okPressed;
+ private final QLineEdit searchName;
+ private final QLineEdit query;
+ QPushButton ok;
+ List<SavedSearch> currentSearches;
+
+
+ // Constructor
+ public SavedSearchEdit() {
+ okPressed = false;
+ setWindowTitle("Add a search");
+ QGridLayout grid = new QGridLayout();
+ setLayout(grid);
+
+ QGridLayout textLayout = new QGridLayout();
+ searchName = new QLineEdit();
+ textLayout.addWidget(new QLabel("Name"), 1,1);
+ textLayout.addWidget(searchName, 1, 2);
+ query = new QLineEdit();
+ textLayout.addWidget(new QLabel("String"), 2,1);
+ textLayout.addWidget(query, 2, 2);
+ textLayout.setContentsMargins(10, 10,-10, -10);
+ grid.addLayout(textLayout, 1, 1);
+
+ QGridLayout buttonLayout = new QGridLayout();
+ ok = new QPushButton("OK");
+ ok.clicked.connect(this, "okButtonPressed()");
+ ok.setEnabled(false);
+ QPushButton cancel = new QPushButton("Cancel");
+ cancel.clicked.connect(this, "cancelButtonPressed()");
+ searchName.textChanged.connect(this, "textChanged()");
+ query.textChanged.connect(this, "textChanged()");
+ buttonLayout.addWidget(ok, 1, 1);
+ buttonLayout.addWidget(cancel, 1,2);
+ grid.addLayout(buttonLayout,2,1);
+ }
+
+ // The OK button was pressed
+ @SuppressWarnings("unused")
+ private void okButtonPressed() {
+ okPressed = true;
+ close();
+ }
+
+ // The CANCEL button was pressed
+ @SuppressWarnings("unused")
+ private void cancelButtonPressed() {
+ okPressed = false;
+ close();
+ }
+
+ // Get the name from the field
+ public String getName() {
+ return searchName.text().trim();
+ }
+
+ // Set the tag name
+ public void setName(String name) {
+ searchName.setText(name);
+ }
+ // get the query
+ public String getQuery() {
+ return query.text().trim();
+ }
+ // Set the query
+ public void setQuery(String q) {
+ query.setText(q);
+ }
+ // Check if the OK button was pressed
+ public boolean okPressed() {
+ return okPressed;
+ }
+
+ // Set the window title
+ public void setTitle(String s) {
+ setWindowTitle(s);
+ }
+ // List of existing tags
+ public void setSearchList(List<SavedSearch> t) {
+ currentSearches = t;
+ }
+ // Watch what text is being entered
+ @SuppressWarnings("unused")
+ private void textChanged() {
+ if (searchName.text().trim().equals("")) {
+ ok.setEnabled(false);
+ return;
+ }
+ if (currentSearches == null) {
+ ok.setEnabled(false);
+ return;
+ }
+ if (query.text().trim().equals("")) {
+ ok.setEnabled(false);
+ return;
+ }
+/* for (int i=0; i<currentSearches.size(); i++) {
+ String s = currentSearches.get(i).getName();
+ if (s.equalsIgnoreCase(searchName.text())) {
+ ok.setEnabled(false);
+ return;
+ }
+ } */
+ ok.setEnabled(true);
+ }
+ // Watch what text is being entered
+}
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.dialog;\r
+\r
+\r
+import com.trolltech.qt.gui.QComboBox;\r
+import com.trolltech.qt.gui.QDialog;\r
+import com.trolltech.qt.gui.QGridLayout;\r
+import com.trolltech.qt.gui.QIntValidator;\r
+import com.trolltech.qt.gui.QLabel;\r
+import com.trolltech.qt.gui.QLineEdit;\r
+import com.trolltech.qt.gui.QPushButton;\r
+import com.trolltech.qt.gui.QSpinBox;\r
+\r
+public class TableDialog extends QDialog {\r
+\r
+ private boolean okPressed;\r
+ private final QSpinBox rows;\r
+ private final QSpinBox cols;\r
+ private final QLineEdit width;\r
+ private final QPushButton ok;\r
+ private final QLabel error;\r
+ private final QIntValidator widthValidator;\r
+ private final QComboBox unit;\r
+ \r
+ \r
+ // Constructor\r
+ public TableDialog() {\r
+ okPressed = false;\r
+ setWindowTitle("Insert Table");\r
+ QGridLayout grid = new QGridLayout();\r
+ QGridLayout input = new QGridLayout();\r
+ QGridLayout msgGrid = new QGridLayout();\r
+ QGridLayout button = new QGridLayout();\r
+ setLayout(grid);\r
+ \r
+ unit = new QComboBox(this);\r
+ unit.addItem("Percent");\r
+ unit.addItem("Pixels");\r
+ \r
+ \r
+ width = new QLineEdit("80");\r
+ widthValidator = new QIntValidator(0,100, this);\r
+ width.setValidator(widthValidator);\r
+ width.textChanged.connect(this, "validateWidth()");\r
+ rows = new QSpinBox();\r
+ cols = new QSpinBox();\r
+ rows.setMaximum(30);\r
+ rows.setMinimum(1);\r
+ cols.setMaximum(30);\r
+ cols.setMinimum(1);\r
+ \r
+ unit.activated.connect(this, "unitChanged()");\r
+ \r
+ input.addWidget(new QLabel("Rows"), 1,1);\r
+ input.addWidget(rows, 1, 2);\r
+ input.addWidget(new QLabel("Columns"), 2,1);\r
+ input.addWidget(cols, 2, 2);\r
+ input.addWidget(new QLabel("Width"), 3,1);\r
+ input.addWidget(width, 3, 2);\r
+ input.addWidget(new QLabel("Unit"),4,1);\r
+ input.addWidget(unit,4,2);\r
+ input.setContentsMargins(10, 10, -10, -10);\r
+ grid.addLayout(input, 1,1);\r
+ \r
+ error = new QLabel();\r
+ msgGrid.addWidget(error, 1, 1);\r
+ grid.addLayout(msgGrid, 2, 1);\r
+ \r
+ ok = new QPushButton("OK");\r
+ ok.clicked.connect(this, "okButtonPressed()");\r
+ \r
+ QPushButton cancel = new QPushButton("Cancel");\r
+ cancel.clicked.connect(this, "cancelButtonPressed()");\r
+ button.addWidget(ok, 1, 1);\r
+ button.addWidget(cancel, 1,2);\r
+ grid.addLayout(button, 3, 1);\r
+ \r
+// width.textChanged.connect(this, "validateInput()");\r
+ \r
+ }\r
+ \r
+ // The OK button was pressed\r
+ @SuppressWarnings("unused")\r
+ private void okButtonPressed() {\r
+ okPressed = true;\r
+ close();\r
+ }\r
+ // The CANCEL button was pressed\r
+ @SuppressWarnings("unused")\r
+ private void cancelButtonPressed() {\r
+ okPressed = false;\r
+ close();\r
+ }\r
+ // Check if the OK button was pressed\r
+ public boolean okPressed() {\r
+ return okPressed;\r
+ }\r
+ // Check if proper input was input\r
+ @SuppressWarnings("unused")\r
+ private void validateInput() {\r
+ ok.setEnabled(false);\r
+ \r
+ ok.setEnabled(true);\r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void validateWidth() {\r
+ if (width.text().trim().length() == 0) {\r
+ ok.setEnabled(false);\r
+ } else\r
+ ok.setEnabled(true);\r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void unitChanged() {\r
+ if (unit.currentText().equalsIgnoreCase("percent")) {\r
+ Integer w = new Integer(width.text());\r
+ if (w > 100)\r
+ width.setText("80");\r
+ widthValidator.setTop(100);\r
+ } else {\r
+ widthValidator.setTop(32767);\r
+ }\r
+ }\r
+ \r
+ public int getRows() {\r
+ return new Integer(rows.text());\r
+ }\r
+ public int getCols() {\r
+ return new Integer(cols.text());\r
+ }\r
+ public int getWidth() {\r
+ return new Integer(width.text());\r
+ }\r
+ public boolean isPercent() {\r
+ if (unit.currentText().equalsIgnoreCase("percent"))\r
+ return true;\r
+ else\r
+ return false;\r
+ }\r
+\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.dialog;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.Tag;\r
+import com.trolltech.qt.gui.QAbstractItemView;\r
+import com.trolltech.qt.gui.QDialog;\r
+import com.trolltech.qt.gui.QHBoxLayout;\r
+import com.trolltech.qt.gui.QLineEdit;\r
+import com.trolltech.qt.gui.QListWidget;\r
+import com.trolltech.qt.gui.QListWidgetItem;\r
+import com.trolltech.qt.gui.QPushButton;\r
+import com.trolltech.qt.gui.QVBoxLayout;\r
+\r
+public class TagAssign extends QDialog {\r
+ private final QListWidget tagList;\r
+ private final QPushButton okButton;\r
+ private final QPushButton cancelButton;\r
+ private final QLineEdit newTag;\r
+ private final QPushButton newTagButton;\r
+ private boolean okClicked;\r
+ private final List<String> tags;\r
+ \r
+ public TagAssign(List<Tag> allTags, List<String> selectedTags) {\r
+ okClicked = false;\r
+ tags = new ArrayList<String>();\r
+ \r
+ tagList = new QListWidget();\r
+ tagList.setSortingEnabled(true);\r
+ tagList.setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection);\r
+ \r
+ newTag = new QLineEdit();\r
+ newTag.textChanged.connect(this, "newTagTextChanged()");\r
+ newTagButton = new QPushButton("Add");\r
+ newTagButton.setEnabled(false);\r
+ newTagButton.clicked.connect(this, "addTag()");\r
+ \r
+ QHBoxLayout addLayout = new QHBoxLayout();\r
+ addLayout.addWidget(newTag);\r
+ addLayout.setStretch(0, 10);\r
+ addLayout.addWidget(newTagButton);\r
+ \r
+ okButton = new QPushButton();\r
+ okButton.setText("OK");\r
+ okButton.pressed.connect(this, "onClicked()");\r
+ \r
+ cancelButton = new QPushButton();\r
+ cancelButton.setText("Cancel");\r
+ cancelButton.pressed.connect(this, "onCancel()");\r
+ \r
+ QHBoxLayout horizontalLayout = new QHBoxLayout();\r
+ horizontalLayout.addWidget(tagList);\r
+ \r
+ QHBoxLayout buttonLayout = new QHBoxLayout();\r
+ buttonLayout.addStretch(1);\r
+ buttonLayout.addWidget(okButton);\r
+ buttonLayout.addWidget(cancelButton);\r
+ setWindowTitle(tr("Note Tags")); \r
+ \r
+ QVBoxLayout mainLayout = new QVBoxLayout();\r
+ mainLayout.addLayout(horizontalLayout);\r
+ mainLayout.addLayout(addLayout);\r
+ //mainLayout.addStretch(1);\r
+ mainLayout.addSpacing(1);\r
+ mainLayout.addLayout(buttonLayout);\r
+ setLayout(mainLayout);\r
+ \r
+ if (allTags != null) {\r
+ for (int i=0; i<allTags.size(); i++) {\r
+ tags.add(allTags.get(i).getName());\r
+// tagList.addItem(allTags.get(i).getName());\r
+ QListWidgetItem item = new QListWidgetItem(allTags.get(i).getName());\r
+ tagList.addItem(item);\r
+ if (selectedTags != null) {\r
+ for (int j=0; j<selectedTags.size(); j++) {\r
+ String name = selectedTags.get(j);\r
+ if (name.equals(item.text())) {\r
+ item.setSelected(true);\r
+ j=selectedTags.size()+1;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ \r
+ \r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void onClicked() {\r
+ okClicked = true;\r
+ close();\r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void onCancel() {\r
+ okClicked = false;\r
+ close();\r
+ }\r
+ \r
+ public boolean okClicked() {\r
+ return okClicked;\r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void newTagTextChanged() {\r
+ if (newTag.text().equals("")) {\r
+ newTagButton.setEnabled(false);\r
+ return;\r
+ }\r
+ newTagButton.setEnabled(true);\r
+ for (int i=0; i<tags.size(); i++) {\r
+ if (tags.get(i).trim().equalsIgnoreCase(newTag.text().trim())) {\r
+ newTagButton.setEnabled(false);\r
+ return;\r
+ }\r
+ }\r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void addTag() {\r
+ String tag = newTag.text().trim();\r
+ tagList.addItem(tag);\r
+ newTag.setText("");\r
+ newTagButton.setEnabled(false);\r
+ \r
+ for (int i=0; i<tagList.count(); i++) {\r
+ QListWidgetItem item = tagList.item(i);\r
+ if (item.text().equals(tag)) {\r
+ item.setSelected(true);\r
+ return;\r
+ }\r
+ }\r
+ }\r
+ \r
+ \r
+ public QListWidget getTagList() {\r
+ return tagList;\r
+ }\r
+}\r
--- /dev/null
+/*
+ * This file is part of NeverNote
+ * 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;
+
+import java.util.List;
+
+import com.evernote.edam.type.Tag;
+import com.trolltech.qt.gui.QDialog;
+import com.trolltech.qt.gui.QGridLayout;
+import com.trolltech.qt.gui.QLabel;
+import com.trolltech.qt.gui.QLineEdit;
+import com.trolltech.qt.gui.QPushButton;
+
+public class TagEdit extends QDialog {
+ private boolean okPressed;
+ private final QLineEdit tag;
+ QPushButton ok;
+ List<Tag> currentTags;
+
+
+ // Constructor
+ public TagEdit() {
+ okPressed = false;
+ setWindowTitle("Add Tag");
+ QGridLayout grid = new QGridLayout();
+ setLayout(grid);
+
+ QGridLayout textGrid = new QGridLayout();
+ tag = new QLineEdit();
+ textGrid.addWidget(new QLabel("Tag Name"), 1,1);
+ textGrid.addWidget(tag, 1, 2);
+ textGrid.setContentsMargins(10, 10,-10, -10);
+ grid.addLayout(textGrid,1,1);
+
+ QGridLayout buttonGrid = new QGridLayout();
+ ok = new QPushButton("OK");
+ ok.clicked.connect(this, "okButtonPressed()");
+ ok.setEnabled(false);
+ QPushButton cancel = new QPushButton("Cancel");
+ cancel.clicked.connect(this, "cancelButtonPressed()");
+ tag.textChanged.connect(this, "textChanged()");
+ buttonGrid.addWidget(ok, 3, 1);
+ buttonGrid.addWidget(cancel, 3,2);
+ grid.addLayout(buttonGrid,2,1);
+ }
+
+ // The OK button was pressed
+ @SuppressWarnings("unused")
+ private void okButtonPressed() {
+ okPressed = true;
+ close();
+ }
+
+ // The CANCEL button was pressed
+ @SuppressWarnings("unused")
+ private void cancelButtonPressed() {
+ okPressed = false;
+ close();
+ }
+
+ // Get the name from the field
+ public String getTag() {
+ return tag.text();
+ }
+
+ // Set the tag name
+ public void setTag(String name) {
+ tag.setText(name);
+ }
+
+ // Check if the OK button was pressed
+ public boolean okPressed() {
+ return okPressed;
+ }
+
+ // Set the window title
+ public void setTitle(String s) {
+ setWindowTitle(s);
+ }
+ // List of existing tags
+ public void setTagList(List<Tag> t) {
+ currentTags = t;
+ }
+ // Watch what text is being entered
+ @SuppressWarnings("unused")
+ private void textChanged() {
+ if (tag.text().equals("")) {
+ ok.setEnabled(false);
+ return;
+ }
+ if (currentTags == null) {
+ ok.setEnabled(false);
+ return;
+ }
+ for (int i=0; i<currentTags.size(); i++) {
+ String s = currentTags.get(i).getName();
+ if (s.equalsIgnoreCase(tag.text())) {
+ ok.setEnabled(false);
+ return;
+ }
+ }
+ ok.setEnabled(true);
+ }
+}
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.dialog;\r
+\r
+import java.util.List;\r
+\r
+import com.trolltech.qt.core.QPoint;\r
+import com.trolltech.qt.core.QRect;\r
+import com.trolltech.qt.core.Qt;\r
+import com.trolltech.qt.core.Qt.WindowModality;\r
+import com.trolltech.qt.gui.QApplication;\r
+import com.trolltech.qt.gui.QColor;\r
+import com.trolltech.qt.gui.QDesktopWidget;\r
+import com.trolltech.qt.gui.QDialog;\r
+import com.trolltech.qt.gui.QGridLayout;\r
+import com.trolltech.qt.gui.QImage;\r
+import com.trolltech.qt.gui.QKeyEvent;\r
+import com.trolltech.qt.gui.QLabel;\r
+import com.trolltech.qt.gui.QMouseEvent;\r
+import com.trolltech.qt.gui.QPaintEvent;\r
+import com.trolltech.qt.gui.QPainter;\r
+import com.trolltech.qt.gui.QPalette;\r
+import com.trolltech.qt.gui.QPalette.ColorRole;\r
+import com.trolltech.qt.gui.QPixmap;\r
+import com.trolltech.qt.gui.QWheelEvent;\r
+public class ThumbnailViewer extends QDialog {\r
+ private String thumbnail;\r
+ private final QLabel picture;\r
+ QGridLayout grid = new QGridLayout();\r
+ public Signal0 upArrow;\r
+ public Signal0 downArrow;\r
+ public Signal0 leftArrow;\r
+ public Signal0 rightArrow;\r
+ private QImage image;\r
+ private List<String> guids;\r
+ \r
+\r
+ public ThumbnailViewer() {\r
+ this.setVisible(false);\r
+ \r
+ leftArrow = new Signal0();\r
+ rightArrow = new Signal0();\r
+ upArrow = new Signal0();\r
+ downArrow = new Signal0();\r
+\r
+\r
+ setAutoFillBackground(true);\r
+ QPalette palette = new QPalette(palette());\r
+ // Set background colour to black\r
+ palette.setColor(ColorRole.Base, QColor.black);\r
+ setPalette(palette);\r
+ \r
+ grid = new QGridLayout();\r
+ setLayout(grid);\r
+ \r
+ \r
+ picture = new QLabel();\r
+/* \r
+ QLabel left = new QLabel();\r
+ QLabel right = new QLabel();\r
+ \r
+ grid.addWidget(left, 0,0);\r
+ grid.addWidget(picture,0,1);\r
+ grid.addWidget(right, 0,2);\r
+ grid.setWidgetSpacing(1);\r
+ grid.setContentsMargins(10, 10, -10, -10);\r
+*/ \r
+ \r
+ setWindowModality(WindowModality.ApplicationModal);\r
+ setWindowFlags(Qt.WindowType.FramelessWindowHint);\r
+ setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground);\r
+// setBackgroundRole(ColorRole.Shadow);\r
+// setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose);\r
+// showFullScreen();\r
+// this.hide();\r
+\r
+ }\r
+ public void setThumbnail(String thumb) {\r
+ thumbnail = thumb;\r
+ image = new QImage(thumbnail);\r
+ picture.setPixmap(QPixmap.fromImage(image));\r
+ }\r
+ public void setThumbnail(QImage i) {\r
+ image = i;\r
+ picture.setPixmap(QPixmap.fromImage(image));\r
+ }\r
+ \r
+\r
+ @Override\r
+ public void keyPressEvent(QKeyEvent e) {\r
+ if (e.key() == Qt.Key.Key_Up.value() || e.key() == Qt.Key.Key_Right.value()) {\r
+ upArrow.emit();\r
+ }\r
+ if (e.key() == Qt.Key.Key_Down.value() || e.key() == Qt.Key.Key_Left.value()) {\r
+ downArrow.emit();\r
+ }\r
+\r
+ super.keyPressEvent(e);\r
+ }\r
+ \r
+ \r
+ @Override\r
+ public void mousePressEvent(QMouseEvent e) {\r
+ if (e.button() == Qt.MouseButton.LeftButton)\r
+ close();\r
+ }\r
+ \r
+ @Override\r
+ public void wheelEvent(QWheelEvent e) {\r
+ int numDegrees = e.delta() / 8;\r
+ int numSteps = numDegrees / 15;\r
+ \r
+ if (e.orientation().equals(Qt.Orientation.Vertical)) { \r
+ if (numSteps > 0) {\r
+ for (int i=0; i<numSteps; i++) {\r
+ upArrow.emit();\r
+ repaint();\r
+ }\r
+ }\r
+ if (numSteps < 0) {\r
+ for (int i=numSteps; i<0; i++) {\r
+ downArrow.emit();\r
+ repaint();\r
+ }\r
+ }\r
+ }\r
+ }\r
+ \r
+ @Override\r
+ public void paintEvent(QPaintEvent e) {\r
+ QDesktopWidget desktop = QApplication.desktop();\r
+ int screen = desktop.screenNumber();\r
+ this.setMaximumSize(desktop.size());\r
+ this.setMinimumSize(desktop.size());\r
+ resize(desktop.size());\r
+ \r
+ QPainter painter = new QPainter(this);\r
+ \r
+ painter.fillRect(desktop.screenGeometry(screen), QColor.black);\r
+\r
+ QRect availGeo = desktop.availableGeometry(screen);\r
+ \r
+ int x1 = (availGeo.width()/2)-(image.size().width()/2);\r
+ int y1 = (availGeo.height()/2)-(image.size().height()/2);\r
+ \r
+ painter.drawImage(new QPoint(x1,y1), image);\r
+ }\r
+\r
+\r
+ public List<String> getGuids() {\r
+ return guids;\r
+ }\r
+ public void setGuids(List<String> g) {\r
+ guids = g;\r
+ }\r
+\r
+\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.dialog;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.Notebook;\r
+import com.trolltech.qt.core.QModelIndex;\r
+import com.trolltech.qt.gui.QApplication;\r
+import com.trolltech.qt.gui.QDialog;\r
+import com.trolltech.qt.gui.QFontMetrics;\r
+import com.trolltech.qt.gui.QHBoxLayout;\r
+import com.trolltech.qt.gui.QPushButton;\r
+import com.trolltech.qt.gui.QTableWidget;\r
+import com.trolltech.qt.gui.QTableWidgetItem;\r
+import com.trolltech.qt.gui.QVBoxLayout;\r
+import com.trolltech.qt.gui.QAbstractItemView.SelectionBehavior;\r
+import com.trolltech.qt.gui.QAbstractItemView.SelectionMode;\r
+\r
+import cx.fbn.nevernote.sql.runners.WatchFolderRecord;\r
+\r
+public class WatchFolder extends QDialog {\r
+ private final QPushButton okButton;\r
+ private final QPushButton cancelButton;\r
+ private final QPushButton addButton;\r
+ private final QPushButton editButton;\r
+ private final QPushButton deleteButton;\r
+ private boolean okClicked;\r
+ public final QTableWidget table;\r
+ private final List<Notebook> notebooks;\r
+ private final List<WatchFolderRecord> records;\r
+ \r
+ public WatchFolder(List<WatchFolderRecord> w, List<Notebook> n) {\r
+ okClicked = false;\r
+ notebooks = n;\r
+ records = w;\r
+ \r
+ okButton = new QPushButton();\r
+ okButton.setText("OK");\r
+ okButton.pressed.connect(this, "onClicked()");\r
+ \r
+ cancelButton = new QPushButton();\r
+ cancelButton.setText("Cancel");\r
+ cancelButton.pressed.connect(this, "onCancel()");\r
+ \r
+ QHBoxLayout horizontalLayout = new QHBoxLayout();\r
+ QHBoxLayout buttonLayout = new QHBoxLayout();\r
+ buttonLayout.addStretch(1);\r
+ buttonLayout.addWidget(okButton);\r
+ buttonLayout.addWidget(cancelButton);\r
+ setWindowTitle(tr("Auto Import Folders")); \r
+ \r
+ table = new QTableWidget(records.size(),3);\r
+ List<String> headers = new ArrayList<String>();\r
+ headers.add("Directory");\r
+ headers.add("Target Notebook");\r
+ headers.add("Keep");\r
+ table.setHorizontalHeaderLabels(headers);\r
+ table.verticalHeader().setVisible(false);\r
+ table.setAlternatingRowColors(true);\r
+ table.setSelectionBehavior(SelectionBehavior.SelectRows);\r
+ table.setSelectionMode(SelectionMode.SingleSelection);\r
+ table.itemSelectionChanged.connect(this, "tableSelection()");\r
+ horizontalLayout.addWidget(table);\r
+ \r
+ \r
+ addButton = new QPushButton();\r
+ addButton.setText("Add");\r
+ addButton.clicked.connect(this, "addPressed()");\r
+ \r
+ editButton = new QPushButton();\r
+ editButton.setText("Edit");\r
+ editButton.setEnabled(false);\r
+ editButton.clicked.connect(this, "editPressed()");\r
+ \r
+ deleteButton = new QPushButton();\r
+ deleteButton.setText("Delete");\r
+ deleteButton.setEnabled(false);\r
+ deleteButton.clicked.connect(this, "deletePressed()");\r
+ \r
+ QVBoxLayout editLayout = new QVBoxLayout();\r
+ editLayout.addWidget(addButton);\r
+ editLayout.addWidget(editButton);\r
+ editLayout.addWidget(deleteButton);\r
+ \r
+ QHBoxLayout listLayout = new QHBoxLayout();\r
+ listLayout.addLayout(horizontalLayout);\r
+ listLayout.addLayout(editLayout);\r
+ \r
+ QVBoxLayout mainLayout = new QVBoxLayout();\r
+ mainLayout.addLayout(listLayout);\r
+ mainLayout.addSpacing(1);\r
+ mainLayout.addLayout(buttonLayout);\r
+ setLayout(mainLayout);\r
+\r
+// QTableWidgetItem dir = new QTableWidgetItem();\r
+// QTableWidgetItem book = new QTableWidgetItem();\r
+ \r
+ table.setColumnWidth(0, 160);\r
+ resize(500, 200);\r
+ load();\r
+ \r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void onClicked() {\r
+ okClicked = true;\r
+ close();\r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void onCancel() {\r
+ okClicked = false;\r
+ close();\r
+ }\r
+ \r
+ public boolean okClicked() {\r
+ return okClicked;\r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void itemSelected() {\r
+ okButton.setEnabled(true);\r
+ }\r
+ \r
+ private void load() {\r
+ for (int i=0; i<records.size(); i++) {\r
+ addRow(i, records.get(i).folder, records.get(i).notebook, records.get(i).keep);\r
+ }\r
+ }\r
+\r
+ private void addRow(int row, String folder, String notebook, boolean keepAfter) {\r
+ QFontMetrics f = QApplication.fontMetrics();\r
+ int fontHeight = f.height();\r
+\r
+ QTableWidgetItem dir = new QTableWidgetItem();\r
+ dir.setText(folder);\r
+ table.setItem(row, 0, dir);\r
+ table.setRowHeight(row, fontHeight);\r
+ dir.setToolTip(folder);\r
+ \r
+ QTableWidgetItem book = new QTableWidgetItem();\r
+ book.setText(notebook);\r
+ table.setItem(row, 1, book);\r
+ \r
+ QTableWidgetItem keep = new QTableWidgetItem();\r
+ if (keepAfter)\r
+ keep.setText("Keep");\r
+ else\r
+ keep.setText("Delete");\r
+ table.setItem(row, 2, keep);\r
+\r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void tableSelection() {\r
+ editButton.setEnabled(true);\r
+ deleteButton.setEnabled(true);\r
+ }\r
+ \r
+ \r
+ @SuppressWarnings("unused")\r
+ private void addPressed() {\r
+ WatchFolderAdd dialog = new WatchFolderAdd(null, notebooks);\r
+ dialog.exec();\r
+ if (dialog.okClicked()) {\r
+ String dir = dialog.directory.text();\r
+ String notebook = dialog.books.currentText();\r
+ \r
+ boolean keep;\r
+ if (dialog.keep.currentText().equalsIgnoreCase("keep"))\r
+ keep = true;\r
+ else\r
+ keep = false;\r
+ table.insertRow(table.rowCount());\r
+ addRow(table.rowCount()-1, dir, notebook, keep); \r
+ }\r
+ \r
+ }\r
+\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void editPressed() {\r
+ WatchFolderRecord record = new WatchFolderRecord();\r
+ QModelIndex index = table.currentIndex();\r
+ int row = index.row();\r
+ QTableWidgetItem item = table.item(row, 0);\r
+ record.folder = item.text();\r
+ item = table.item(row, 1);\r
+ record.notebook = item.text();\r
+ item = table.item(row,2);\r
+ if (item.text().equalsIgnoreCase("keep"))\r
+ record.keep = true;\r
+ else\r
+ record.keep = false;\r
+ \r
+ WatchFolderAdd dialog = new WatchFolderAdd(record, notebooks);\r
+ dialog.exec();\r
+ if (dialog.okClicked()) {\r
+ String dir = dialog.directory.text();\r
+ String notebook = dialog.books.currentText();\r
+ \r
+ boolean keep;\r
+ if (dialog.keep.currentText().equalsIgnoreCase("keep"))\r
+ keep = true;\r
+ else\r
+ keep = false;\r
+ table.removeRow(row);\r
+ table.insertRow(table.rowCount());\r
+ addRow(table.rowCount()-1, dir, notebook, keep);\r
+ WatchFolderRecord newRecord = new WatchFolderRecord();\r
+ newRecord.folder = dir;\r
+ newRecord.notebook = notebook;\r
+ newRecord.keep = keep;\r
+ records.add(newRecord);\r
+ }\r
+ \r
+ }\r
+ \r
+ \r
+ @SuppressWarnings("unused")\r
+ private void deletePressed() {\r
+ QModelIndex index = table.currentIndex();\r
+ int row = index.row();\r
+ \r
+ QTableWidgetItem dirWidget = table.item(row, 0);\r
+ String value = dirWidget.text();\r
+ table.removeRow(row);\r
+ \r
+ for (int i=0; i<records.size(); i++) {\r
+ if (value.equals(records.get(i).folder)) {\r
+ records.remove(i);\r
+ i=records.size();\r
+ }\r
+ }\r
+ \r
+ if (table.rowCount() == 0) {\r
+ editButton.setEnabled(false);\r
+ deleteButton.setEnabled(false);\r
+ } \r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.dialog;\r
+\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.Notebook;\r
+import com.trolltech.qt.gui.QComboBox;\r
+import com.trolltech.qt.gui.QDialog;\r
+import com.trolltech.qt.gui.QFileDialog;\r
+import com.trolltech.qt.gui.QGridLayout;\r
+import com.trolltech.qt.gui.QHBoxLayout;\r
+import com.trolltech.qt.gui.QLabel;\r
+import com.trolltech.qt.gui.QPushButton;\r
+import com.trolltech.qt.gui.QVBoxLayout;\r
+import com.trolltech.qt.gui.QFileDialog.FileMode;\r
+\r
+import cx.fbn.nevernote.sql.runners.WatchFolderRecord;\r
+\r
+public class WatchFolderAdd extends QDialog {\r
+ private final QPushButton okButton;\r
+ private final QPushButton cancelButton;\r
+ private boolean okClicked;\r
+ private final List<Notebook> notebooks;\r
+ private final WatchFolderRecord record;\r
+ public final QLabel directory;\r
+ public final QComboBox keep;\r
+ public final QComboBox books;\r
+ \r
+ public WatchFolderAdd(WatchFolderRecord w, List<Notebook> n) {\r
+ okClicked = false;\r
+ notebooks = n;\r
+ record = w;\r
+ \r
+ okButton = new QPushButton();\r
+ okButton.setText("OK");\r
+ okButton.pressed.connect(this, "onClicked()");\r
+ \r
+ cancelButton = new QPushButton();\r
+ cancelButton.setText("Cancel");\r
+ cancelButton.pressed.connect(this, "onCancel()");\r
+ \r
+ QPushButton folderButton = new QPushButton();\r
+ folderButton.setText("Directory");\r
+ folderButton.clicked.connect(this, "folderButtonClicked()");\r
+ \r
+ directory = new QLabel();\r
+ if (record != null)\r
+ directory.setText(record.folder);\r
+ else \r
+ directory.setText(System.getProperty("user.home"));\r
+ \r
+ keep = new QComboBox();\r
+ keep.addItem("Keep");\r
+ keep.addItem("Delete");\r
+ if (record != null) {\r
+ if (record.keep)\r
+ keep.setCurrentIndex(0);\r
+ else\r
+ keep.setCurrentIndex(1);\r
+ }\r
+ \r
+ books = new QComboBox();\r
+ for (int i=0; i<notebooks.size(); i++) {\r
+ books.addItem(notebooks.get(i).getName());\r
+ if (record != null) {\r
+ if (record.notebook.equals(notebooks.get(i).getName()))\r
+ books.setCurrentIndex(i);\r
+ }\r
+ }\r
+ \r
+ QGridLayout grid = new QGridLayout();\r
+ grid.addWidget(directory,0,1);\r
+ grid.addWidget(folderButton,0,0);\r
+ grid.addWidget(new QLabel("Notebook"),1,0);\r
+ grid.addWidget(books,1,1);\r
+ grid.addWidget(new QLabel("After Import"), 2,0);\r
+ grid.addWidget(keep,2,1);\r
+ \r
+ QHBoxLayout buttonLayout = new QHBoxLayout();\r
+ buttonLayout.addStretch(1);\r
+ buttonLayout.addWidget(okButton);\r
+ buttonLayout.addWidget(cancelButton);\r
+ setWindowTitle(tr("Add Import Folder")); \r
+ \r
+ \r
+ QVBoxLayout mainLayout = new QVBoxLayout();\r
+ mainLayout.addLayout(grid);\r
+ mainLayout.addSpacing(1);\r
+ mainLayout.addLayout(buttonLayout);\r
+ setLayout(mainLayout);\r
+ \r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void onClicked() {\r
+ okClicked = true;\r
+ close();\r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void onCancel() {\r
+ okClicked = false;\r
+ close();\r
+ }\r
+ \r
+ public boolean okClicked() {\r
+ return okClicked;\r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void itemSelected() {\r
+ okButton.setEnabled(true);\r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void folderButtonClicked() {\r
+ QFileDialog fileDialog = new QFileDialog();\r
+ fileDialog.setFileMode(FileMode.DirectoryOnly);\r
+ fileDialog.fileSelected.connect(this, "folderSelected(String)");\r
+ fileDialog.exec();\r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void folderSelected(String f) {\r
+ String whichOS = System.getProperty("os.name");\r
+ if (whichOS.contains("Windows")) \r
+ f = f.replace('/','\\');\r
+ directory.setText(f);\r
+ }\r
+ \r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+package cx.fbn.nevernote.evernote;\r
+\r
+import java.io.IOException;\r
+import java.security.InvalidAlgorithmParameterException;\r
+import java.security.InvalidKeyException;\r
+import java.security.MessageDigest;\r
+import java.security.NoSuchAlgorithmException;\r
+import java.util.zip.CRC32;\r
+\r
+import javax.crypto.BadPaddingException;\r
+import javax.crypto.Cipher;\r
+import javax.crypto.IllegalBlockSizeException;\r
+import javax.crypto.NoSuchPaddingException;\r
+import javax.crypto.spec.RC2ParameterSpec;\r
+import javax.crypto.spec.SecretKeySpec;\r
+\r
+import cx.fbn.nevernote.utilities.Base64;\r
+\r
+public class EnCrypt {\r
+\r
+ // Convert a string of text to a hex string\r
+ public static String asHex (byte buf[]) {\r
+ StringBuffer strbuf = new StringBuffer(buf.length * 2);\r
+ int i;\r
+\r
+ for (i = 0; i < buf.length; i++) {\r
+ if ((buf[i] & 0xff) < 0x10)\r
+ strbuf.append("0");\r
+\r
+ strbuf.append(Long.toString(buf[i] & 0xff, 16));\r
+ }\r
+\r
+ return strbuf.toString();\r
+ }\r
+ // Encrypte the text and return the base64 string\r
+ public String encrypt(String text, String passphrase, int keylen) {\r
+ RC2ParameterSpec parm = new RC2ParameterSpec(keylen);\r
+ MessageDigest md;\r
+ try {\r
+ int len = text.length()+4;\r
+ int mod = (len%8);\r
+ if (mod>0) {\r
+ for (; mod !=0; len++) {\r
+ mod = len%8;\r
+ }\r
+ len--;\r
+ }\r
+ len = len-4;\r
+ StringBuffer textBuffer = new StringBuffer(text);\r
+ textBuffer.setLength(len);\r
+ // Get a MD5 for the passphrase\r
+ md = MessageDigest.getInstance("MD5");\r
+ md.update(passphrase.getBytes());\r
+ \r
+ // Setup parms for the cipher\r
+ SecretKeySpec skeySpec = new SecretKeySpec(md.digest(), "RC2");\r
+ Cipher cipher = Cipher.getInstance("RC2/ECB/NoPadding");\r
+ cipher.init(Cipher.ENCRYPT_MODE, skeySpec, parm);\r
+ String encoded = crcHeader(textBuffer.toString()) +textBuffer;\r
+ byte[] d = cipher.doFinal(encoded.getBytes());\r
+ return Base64.encodeBytes(d);\r
+ } catch (NoSuchAlgorithmException e) {\r
+ e.printStackTrace();\r
+ } catch (NoSuchPaddingException e) {\r
+ e.printStackTrace();\r
+ } catch (InvalidKeyException e) {\r
+ e.printStackTrace();\r
+ } catch (InvalidAlgorithmParameterException e) {\r
+ e.printStackTrace();\r
+ } catch (IllegalBlockSizeException e) {\r
+ e.printStackTrace();\r
+ } catch (BadPaddingException e) {\r
+ e.printStackTrace();\r
+ } \r
+ \r
+ return null;\r
+ }\r
+ // Decrypt the base64 text and return the unsecure text\r
+ public String decrypt(String text, String passphrase, int keylen) {\r
+ RC2ParameterSpec parm = new RC2ParameterSpec(keylen);\r
+ MessageDigest md;\r
+ try {\r
+ // Get a MD5 for the passphrase\r
+ md = MessageDigest.getInstance("MD5");\r
+ StringBuffer p = new StringBuffer(passphrase);\r
+ md.update(p.toString().getBytes());\r
+ \r
+ // Setup parms for the cipher\r
+ SecretKeySpec skeySpec = new SecretKeySpec(md.digest(), "RC2");\r
+ Cipher cipher = Cipher.getInstance("RC2/ECB/NOPADDING");\r
+ cipher.init(Cipher.DECRYPT_MODE, skeySpec, parm);\r
+ \r
+ // Decode the encrypted text and decrypt\r
+ byte[] dString = Base64.decode(text);\r
+ byte[] d = cipher.doFinal(dString);\r
+ \r
+ // We have a result. Separate it into the 4 byte header and the decrypted text\r
+ StringBuffer buffer = new StringBuffer(new String(d));\r
+ String cryptCRC = buffer.substring(0,4);\r
+ String clearText = buffer.substring(4);\r
+ String realCRC = crcHeader(clearText);\r
+ // We need to get the real CRC of the decrypted text\r
+ if (realCRC.equalsIgnoreCase(cryptCRC)) {\r
+ int endPos = clearText.length();\r
+ for (int i=buffer.length()-1; i>=0; i--) {\r
+ if (buffer.charAt(i) == 0) \r
+ endPos--;\r
+ else\r
+ i=-1;\r
+ }\r
+ clearText = clearText.substring(0,endPos);\r
+ return clearText;\r
+ }\r
+ } catch (NoSuchAlgorithmException e) {\r
+ e.printStackTrace();\r
+ } catch (NoSuchPaddingException e) {\r
+ e.printStackTrace();\r
+ } catch (InvalidKeyException e) {\r
+ e.printStackTrace();\r
+ } catch (InvalidAlgorithmParameterException e) {\r
+ e.printStackTrace();\r
+ } catch (IllegalBlockSizeException e) {\r
+ e.printStackTrace();\r
+ } catch (BadPaddingException e) {\r
+ e.printStackTrace();\r
+ } catch (IOException e) {\r
+ // TODO Auto-generated catch block\r
+ e.printStackTrace();\r
+ } \r
+ return null;\r
+ }\r
+ // Utility function to return the CRC header of an encoded string. This is\r
+ // used to verify good decryption and put in front of a new encrypted string\r
+ private String crcHeader(String text) {\r
+ CRC32 crc = new CRC32();\r
+ crc.update(text.getBytes());\r
+ int realCRC = (int)crc.getValue();\r
+ \r
+ // The first 4 chars of the hex string will equal the first\r
+ // 4 chars of the decyphered text. If they match we have a\r
+ // good password. This is what we return\r
+ realCRC = realCRC ^ (-1);\r
+ realCRC = realCRC >>> 0;\r
+ String hexCRC = Integer.toHexString(realCRC).substring(0,4);\r
+ return hexCRC.toString().toUpperCase();\r
+\r
+ }\r
+\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+package cx.fbn.nevernote.evernote;\r
+\r
+import java.io.File;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+import cx.fbn.nevernote.xml.XMLCleanup;\r
+import cx.fbn.nevernote.xml.XMLNoteRepair;\r
+\r
+public class EnmlConverter {\r
+ private final ApplicationLogger logger;\r
+ private List<String> resources;\r
+ public boolean saveInvalidXML;\r
+ \r
+ public EnmlConverter(ApplicationLogger l) {\r
+ logger = l;\r
+// conn = c;\r
+ saveInvalidXML = false;\r
+ resources = new ArrayList<String>();\r
+ }\r
+\r
+ public List<String> getResources() {\r
+ return resources;\r
+ }\r
+ public String convert(String noteGuid, String content) {\r
+ logger.log(logger.HIGH, "Entering DBRunner.convertToEnml");\r
+ logger.log(logger.EXTREME, "Note Text:" +content);\r
+ \r
+ // Replace the en-note tags with body tags in case we came from \r
+ // someplace other than the editor (for example, if we are merging notes).\r
+ content = content.replace("<en-note>", "<body>");\r
+ content = content.replace("</en-note>", "</body>");\r
+ // Start removing stuff we don't need or want\r
+ int br = content.lastIndexOf("</body>");\r
+ if (br > 0)\r
+ content = new String(content.substring(0,br));\r
+ String newContent;\r
+ int k = content.indexOf("<body");\r
+ if (k>-1)\r
+ newContent = new String(content.substring(k));\r
+ else\r
+ newContent = "<body>"+content;\r
+\r
+ \r
+ // Check that we have a vaild header. Normally we should not\r
+ // but sometimes it seems that we can. I don't see how, but it is\r
+ // easy enough to check.\r
+ if (!newContent.startsWith("<?xml"))\r
+ newContent = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" \r
+ +"<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">\n"\r
+ +newContent \r
+ +"</body>";\r
+ \r
+\r
+ // Fix the more common XML problems that Webkit creates, but are not considered \r
+ // valid XML.\r
+ newContent = fixStupidXMLProblems(newContent);\r
+ \r
+ \r
+ // Change the contents to have enml instead of body tags or\r
+ // we'll fail validation later.\r
+ newContent = newContent.replace("<body", "<en-note");\r
+ newContent = newContent.replace("</body>", "</en-note>");\r
+ \r
+ // First pass through the data. The goal of this pass is to \r
+ // validate that we have a good XML document and to repair\r
+ // any problems found.\r
+ \r
+ XMLNoteRepair repair = new XMLNoteRepair();\r
+ logger.log(logger.HIGH, "Checking XML Structure");\r
+ newContent = repair.parse(newContent, false);\r
+ logger.log(logger.HIGH, "Check complete");\r
+ \r
+\r
+ // If the repair above returned null, then the XML is foobar.\r
+ // We are done here.\r
+ if (newContent == null) {\r
+ // Houston, we've had a problem.\r
+ logger.log(logger.LOW, "Parse error when converting to ENML");\r
+ logger.log(logger.LOW, "Start of unmodified note HTML");\r
+ logger.log(logger.LOW, content);\r
+ logger.log(logger.LOW, "End of unmodified note HTML");\r
+ logger.log(logger.LOW, "Start of modified note HTML");\r
+ logger.log(logger.LOW, newContent);\r
+ logger.log(logger.LOW, "End of modified note HTML");\r
+// logger.log(logger.LOW, result.errorMessage);\r
+// logger.log(logger.LOW, "Error Line:Column "+result.errorLine+":" +result.errorColumn);\r
+ System.exit(16);\r
+\r
+\r
+ }\r
+ \r
+ // Second pass through the data. The goal of this pass is to \r
+ // remove any things we added in NeverNote that do not match\r
+ // the ENML schema\r
+ XMLCleanup v = new XMLCleanup();\r
+ v.setValue(newContent);\r
+ logger.log(logger.HIGH, "Beginning ENML Cleanup");\r
+ v.validate();\r
+ logger.log(logger.HIGH, "Cleanup complete.");\r
+ \r
+ \r
+ \r
+ // Final pass through the data. In this one we\r
+ // remove any invalid attributes and to save the\r
+ // new resources.\r
+ logger.log(logger.EXTREME, "Rebuilt ENML:");\r
+ logger.log(logger.EXTREME, v.getValue()); \r
+ logger.log(logger.EXTREME, "End Of Rebuilt ENML:");\r
+ resources = v.getResources();\r
+\r
+ \r
+ // The XML has the dtd to validate set against Evernote's web\r
+ // address. We change it to a local one because otherwise it would\r
+ // fail if the user doesn't have internet connectivity. The local copy\r
+ // also contains the 3 other PUBLIC definitions at the beginning of the dtd.\r
+ newContent = v.getValue();\r
+ File dtdFile = new File(Global.getDirectoryPath()+"xml/enml2.dtd");\r
+ String dtd = dtdFile.toURI().toString();\r
+ newContent = newContent.replace("<!DOCTYPE en-note SYSTEM \'http://xml.evernote.com/pub/enml2.dtd'>", \r
+ "<!DOCTYPE en-note SYSTEM \"" +dtd +"\">");\r
+ \r
+ logger.log(logger.HIGH, "Validating ENML");\r
+ newContent = repair.parse(newContent, true);\r
+ logger.log(logger.HIGH, "Validation complete");\r
+ saveInvalidXML = repair.saveInvalidXML;\r
+ \r
+ // Restore the correct XML header.\r
+ newContent = newContent.replace("<!DOCTYPE en-note SYSTEM \"" +dtd +"\">", \r
+ "<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml2.dtd'>");\r
+ \r
+ \r
+ \r
+ return newContent;\r
+ }\r
+ \r
+ \r
+ // Fix XML problems that Qt can't deal with\r
+ public String fixStupidXMLProblems(String content) {\r
+ logger.log(logger.HIGH, "Entering DBRunner.fixStupidXMLProblems");\r
+\r
+ // Fix the problem that the document body isn't properly closed\r
+ String newContent = new String(content);\r
+ logger.log(logger.MEDIUM, "Inside fixStupidXMLProblems. Old content:");\r
+ logger.log(logger.MEDIUM, content);\r
+ \r
+ // Fix the problem that the img tag isn't properly closed\r
+ int endPos;\r
+ logger.log(logger.MEDIUM, "Checking img tags");\r
+ for (int i=newContent.indexOf("<img"); i>0; i = newContent.indexOf("<img",i+1)) {\r
+ endPos = newContent.indexOf(">",i+1);\r
+ String end = newContent.substring(endPos+1);\r
+ newContent = newContent.subSequence(0,endPos) +"/>"+end;\r
+ }\r
+ \r
+ // Fix the problem that the input tag isn't properly closed\r
+ logger.log(logger.MEDIUM, "Checking input tags");\r
+ for (int i=newContent.indexOf("<input"); i>0; i = newContent.indexOf("<input",i+1)) {\r
+ endPos = newContent.indexOf(">",i+1);\r
+ String end = newContent.substring(endPos+1);\r
+ newContent = newContent.subSequence(0,endPos) +"/>"+end;\r
+ }\r
+ \r
+ \r
+ // Fix the problem that the <br> tag isn't properly closed\r
+ logger.log(logger.MEDIUM, "Checking br tags");\r
+ for (int i=newContent.indexOf("<br"); i>0; i = newContent.indexOf("<br",i+1)) {\r
+ endPos = newContent.indexOf(">",i+1);\r
+ String end = newContent.substring(endPos+1);\r
+ newContent = newContent.subSequence(0,endPos) +"/>"+end;\r
+ }\r
+ \r
+ // Fix the problem that the <hr> tag isn't properly closed\r
+ logger.log(logger.MEDIUM, "Checking hr tags");\r
+ for (int i=newContent.indexOf("<hr"); i>0; i = newContent.indexOf("<hr",i+1)) {\r
+ endPos = newContent.indexOf(">",i+1);\r
+ String end = newContent.substring(endPos+1);\r
+ newContent = newContent.subSequence(0,endPos) +"/>"+end;\r
+ }\r
+ \r
+ logger.log(logger.MEDIUM, "Leaving fixStupidXMLProblems");\r
+ logger.log(logger.HIGH, "Leaving DBRunner.fixStupidXMLProblems");\r
+ return newContent.toString();\r
+ }\r
+\r
+\r
+ // Fix XML that Evernote thinks is invalid\r
+ public String fixEnXMLCrap(String note) {\r
+ int pos;\r
+ StringBuffer buffer = new StringBuffer(note);\r
+ \r
+ // change all <b/> to <b></b> because Evernote hates them if they happen in <span>\r
+ pos = buffer.indexOf("<b/>");\r
+ for (; pos>-1; ) {\r
+ buffer.replace(pos, pos+4, "<b></b>");\r
+ pos = buffer.indexOf("<b/>",pos);\r
+ }\r
+ // change all <br/> to <br></br> because Evernote hates them if they happen in <span>\r
+ pos = buffer.indexOf("<br/>");\r
+ for (; pos>-1; ) {\r
+ buffer.replace(pos, pos+5, "<br></br>");\r
+ pos = buffer.indexOf("<br/>",pos);\r
+ }\r
+ \r
+ // change all <span> elements in lists because Evernote hates them if they happen \r
+ int endPos = 0;\r
+ int spanPos;\r
+ pos = buffer.indexOf("<li>");\r
+ spanPos = buffer.indexOf("<span>");\r
+/* for (; pos>-1 && spanPos >-1;) {\r
+ endPos = buffer.indexOf("</li>",pos);\r
+ if (spanPos > pos && spanPos < endPos) {\r
+ buffer.replace(spanPos,spanPos+6,"");\r
+ spanPos = buffer.indexOf("</span>"); \r
+ buffer.replace(spanPos,spanPos+7,"");\r
+ }\r
+ pos=buffer.indexOf("<li>",pos+1);\r
+ spanPos = buffer.indexOf("<span>",spanPos);\r
+ }\r
+*/ \r
+ // Get rid of empty spans in <li> elements\r
+ pos = buffer.indexOf("<li>");\r
+ spanPos = buffer.indexOf("<span/>");\r
+ for (; pos>-1 && spanPos >-1;) {\r
+ endPos = buffer.indexOf("</li>",pos);\r
+ if (spanPos > pos && spanPos < endPos) {\r
+ buffer.replace(spanPos,spanPos+7,"");\r
+ }\r
+ pos=buffer.indexOf("<li>",pos+1);\r
+ spanPos = buffer.indexOf("<span/>",spanPos);\r
+ }\r
+ \r
+ return buffer.toString();\r
+ }\r
+ \r
+ // Fix stupid en-media problems\r
+ public String fixEnMediaCrap(String note) {\r
+ if (note == null)\r
+ return null;\r
+ \r
+ StringBuffer buffer = new StringBuffer(note);\r
+ // get rid of any </en-media> tags since they shouldn't exist.\r
+ int pos = buffer.indexOf("</en-media>");\r
+ for (; pos>-1; ) {\r
+ buffer.replace(pos, pos+11, "");\r
+ pos = buffer.indexOf("</en-media>",pos);\r
+ }\r
+ \r
+ \r
+ // Make sure we have a proper /> ending the en-media tag\r
+ pos = buffer.indexOf("<en-media");\r
+ for (; pos>-1; ) {\r
+ pos=buffer.indexOf(">", pos);\r
+ if (!buffer.substring(pos-1,pos).equals("/"))\r
+ buffer.replace(pos, pos+1, " />");\r
+ pos = buffer.indexOf("<en-media",pos);\r
+ }\r
+ \r
+ return buffer.toString();\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.filters;\r
+\r
+\r
+public class AttributeFilter {\r
+ private final String name;\r
+ private boolean set;\r
+ public AttributeFilter(String n) {\r
+ name = n;\r
+ set = false;\r
+ }\r
+ public void set(boolean b) {\r
+ set = b;\r
+ }\r
+ public boolean isSet() {\r
+ return set;\r
+ }\r
+ public String getName() {\r
+ return name;\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.filters;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.Note;\r
+import com.evernote.edam.type.Tag;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.sql.requests.EnSearchRequest;\r
+\r
+public class EnSearch {\r
+ \r
+\r
+ private List<Note> matches;\r
+ public List<String> hilightWords;\r
+ int id;\r
+ \r
+ public EnSearch(int i, String s, List<Tag> t, int len, int weight) {\r
+ id = i;\r
+ if (s == null) \r
+ return;\r
+ if (s.trim().equals(""))\r
+ return;\r
+ \r
+ matches = null;\r
+ EnSearchRequest request = new EnSearchRequest();\r
+ request.requestor_id = id;\r
+// request.type = DeletedItemRequest.Get_All;\r
+ request.string1 = s;\r
+ if (t!=null) {\r
+ request.tags = new ArrayList<Tag>();\r
+ for (int k=0; k<t.size(); k++) {\r
+ request.tags.add(t.get(k).deepCopy());\r
+ }\r
+ }\r
+ request.int1 = len;\r
+ request.int2 = weight;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ EnSearchRequest req = Global.dbRunner.enSearchResponse.get(id);\r
+ hilightWords = req.responseStrings;\r
+ matches = req.responseNotes;\r
+ }\r
+ \r
+ public List<Note> matchWords() {\r
+ return matches;\r
+ }\r
+ \r
+\r
+\r
+ \r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.filters;\r
+\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+\r
+import com.trolltech.qt.core.QAbstractItemModel;\r
+import com.trolltech.qt.core.QDateTime;\r
+import com.trolltech.qt.core.QModelIndex;\r
+import com.trolltech.qt.core.QObject;\r
+import com.trolltech.qt.gui.QSortFilterProxyModel;\r
+\r
+import cx.fbn.nevernote.Global;\r
+\r
+public class NoteSortFilterProxyModel extends QSortFilterProxyModel {\r
+ private final Map<String,String> guids;\r
+ private String dateFormat;\r
+ \r
+ public NoteSortFilterProxyModel(QObject parent) {\r
+ super(parent);\r
+ guids = new HashMap<String,String>();\r
+ dateFormat = Global.getDateFormat() + " " + Global.getTimeFormat();\r
+ setDynamicSortFilter(true);\r
+// logger = new ApplicationLogger("filter.log");\r
+ }\r
+ public void clear() {\r
+ guids.clear();\r
+ }\r
+ public void addGuid(String guid) {\r
+// if (!guids.containsKey(guid))\r
+ guids.put(guid, null);\r
+ }\r
+ public void filter() {\r
+ dateFormat = Global.getDateFormat() + " " + Global.getTimeFormat();\r
+ invalidateFilter();\r
+ }\r
+ @Override\r
+ protected boolean filterAcceptsRow(int sourceRow, QModelIndex sourceParent) {\r
+ if (guids.size() == 0)\r
+ return false;\r
+ QAbstractItemModel model = sourceModel();\r
+ QModelIndex guidIndex = sourceModel().index(sourceRow, Global.noteTableGuidPosition);\r
+ String guid = (String)model.data(guidIndex);\r
+ \r
+ if (guids.containsKey(guid))\r
+ return true;\r
+ else\r
+ return false;\r
+ }\r
+ \r
+ @Override\r
+ protected boolean lessThan(QModelIndex left, QModelIndex right) {\r
+ Object leftData = sourceModel().data(left);\r
+ Object rightData = sourceModel().data(right);\r
+ \r
+ if (sortColumn() == Global.noteTableCreationPosition || \r
+ sortColumn() == Global.noteTableChangedPosition ||\r
+ sortColumn() == Global.noteTableSubjectDatePosition) {\r
+ QDateTime leftDate = QDateTime.fromString(leftData.toString(), dateFormat);\r
+ QDateTime rightDate = QDateTime.fromString(rightData.toString(), dateFormat);\r
+ return leftDate.compareTo(rightDate) < 0;\r
+ }\r
+ if (leftData instanceof String && rightData instanceof String) {\r
+ String leftString = (String)leftData;\r
+ String rightString = (String)rightData;\r
+ return leftString.compareTo(rightString) < 0;\r
+ }\r
+ \r
+ return super.lessThan(left, right);\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.filters;\r
+\r
+public class NotebookCounter {\r
+ private String guid;\r
+ private int count;\r
+ \r
+ \r
+ public NotebookCounter() {\r
+ guid = new String("");\r
+ count = 0;\r
+ }\r
+ public NotebookCounter(NotebookCounter n) {\r
+ guid = new String(n.getGuid());\r
+ count = n.getCount();\r
+ }\r
+ public void setGuid(String g) {\r
+ guid = g;\r
+ }\r
+ public String getGuid() {\r
+ return guid;\r
+ }\r
+ public void setCount(int i) {\r
+ count = i;\r
+ }\r
+ public int getCount() {\r
+ return count;\r
+ }\r
+ \r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.filters;\r
+\r
+public class TagCounter {\r
+ private String guid;\r
+ private int count;\r
+ \r
+ \r
+ public TagCounter() {\r
+ guid = new String("");\r
+ count = 0;\r
+ }\r
+ public void setGuid(String g) {\r
+ guid = g;\r
+ }\r
+ public String getGuid() {\r
+ return guid;\r
+ }\r
+ public void setCount(int i) {\r
+ count = i;\r
+ }\r
+ public int getCount() {\r
+ return count;\r
+ }\r
+ \r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.filters;\r
+\r
+import java.util.List;\r
+\r
+import com.trolltech.qt.sql.QSqlDatabase;\r
+import com.trolltech.qt.sql.QSqlQuery;\r
+\r
+import cx.fbn.nevernote.Global;\r
+\r
+public class WordFilter {\r
+ private final List<String> wordList;\r
+ QSqlDatabase db;\r
+ \r
+ public WordFilter(QSqlDatabase d, List<String> list) {\r
+ wordList = list;\r
+ db = d;\r
+ QSqlQuery query = new QSqlQuery(db);\r
+ QSqlQuery insert = new QSqlQuery(db);\r
+ \r
+ if (wordList == null) \r
+ return;\r
+ if (wordList.size() == 0)\r
+ return;\r
+ query.exec("create temporary table guidList (guid text)");\r
+ query.clear();\r
+ query.exec("delete from guidList");\r
+ query.clear();\r
+ query.prepare("Select guid from words where word like :word and weight>=:weight");\r
+ insert.prepare("insert into guidList (guid) values (:guid)");\r
+ for (int i=0; i<wordList.size(); i++) {\r
+ query.bindValue(":word", wordList.get(i)+"%"); \r
+ query.bindValue(":weight", Global.getRecognitionWeight());\r
+ if (!query.exec()) {\r
+ Global.logger.log(Global.logger.LOW, query.lastError().toString());\r
+ } else {\r
+ while (query.next()) {\r
+ insert.bindValue(":guid", query.value(0).toString());\r
+ insert.exec();\r
+ }\r
+ }\r
+ }\r
+ query.clear();\r
+ insert.clear();\r
+ insert.finish();\r
+ query.finish();\r
+ }\r
+ \r
+ public boolean contains(String guid) {\r
+ if (wordList.size() == 0) \r
+ return true;\r
+ QSqlQuery query = new QSqlQuery(db);\r
+ query.prepare("select count(guid) from guidList where guid=:guid");\r
+ query.bindValue("guid", guid);\r
+ query.exec();\r
+ while (query.next()) {\r
+ Integer count = new Integer(query.value(0).toString());\r
+ if (count >= wordList.size()) {\r
+ query.clear();\r
+ return true;\r
+ }\r
+ }\r
+ \r
+ query.clear();\r
+ return false;\r
+ }\r
+ \r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.gui;\r
+\r
+import com.trolltech.qt.gui.QAbstractItemView;\r
+import com.trolltech.qt.gui.QIcon;\r
+import com.trolltech.qt.gui.QTreeWidget;\r
+import com.trolltech.qt.gui.QTreeWidgetItem;\r
+\r
+import cx.fbn.nevernote.Global;\r
+\r
+public class AttributeTreeWidget extends QTreeWidget {\r
+ \r
+ public AttributeTreeWidget() {\r
+ setHeaderLabel("Attributes");\r
+ setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection);\r
+ \r
+ setHeaderLabel("Attributes");\r
+ setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection);\r
+ \r
+ // Setup the first attribute tree\r
+ QTreeWidgetItem created = new QTreeWidgetItem();\r
+ created.setText(0,"Created");\r
+ addTopLevelItem(created);\r
+ // Created Since List\r
+ QTreeWidgetItem parent = created;\r
+ QTreeWidgetItem child;\r
+ child = new QTreeWidgetItem();\r
+ child.setText(0,"Since");\r
+ parent.addChild(child); \r
+ parent = child;\r
+ \r
+ Global.createdBeforeFilter = new DateAttributeFilterTable();\r
+ Global.createdSinceFilter = new DateAttributeFilterTable();\r
+ Global.changedBeforeFilter = new DateAttributeFilterTable();\r
+ Global.changedSinceFilter = new DateAttributeFilterTable();\r
+ Global.containsFilter = new ContainsAttributeFilterTable();\r
+ \r
+ Global.createdBeforeFilter.setBefore();\r
+ Global.createdBeforeFilter.setCreated();\r
+ Global.createdSinceFilter.setSince();\r
+ Global.createdSinceFilter.setCreated();\r
+ Global.changedBeforeFilter.setBefore();\r
+ Global.changedBeforeFilter.setUpdated();\r
+ Global.changedSinceFilter.setSince();\r
+ Global.changedBeforeFilter.setUpdated();\r
+ \r
+ String iconPath = new String("classpath:cx/fbn/nevernote/icons/");\r
+ QIcon icon = new QIcon(iconPath+"attribute.png");\r
+ for (int i=0; i<Global.createdSinceFilter.size(); i++) {\r
+ child = new QTreeWidgetItem();\r
+ child.setIcon(0, icon);\r
+ child.setText(0,Global.createdSinceFilter.getName(i));\r
+ parent.addChild(child);\r
+ }\r
+ \r
+ \r
+ // Created Before List\r
+ parent = created;\r
+ child = new QTreeWidgetItem();\r
+ child.setText(0,"Before");\r
+ created.addChild(child);\r
+ parent = child;\r
+ for (int i=0; i<Global.createdBeforeFilter.size(); i++) {\r
+ child = new QTreeWidgetItem();\r
+ child.setIcon(0, icon);\r
+ child.setText(0,Global.createdBeforeFilter.getName(i));\r
+ parent.addChild(child);\r
+ }\r
+ \r
+ \r
+ QTreeWidgetItem lastModified = new QTreeWidgetItem();\r
+ lastModified.setText(0,"Last Modified");\r
+ addTopLevelItem(lastModified);\r
+ \r
+ // Changed Since List\r
+ parent = lastModified;\r
+ child = new QTreeWidgetItem();\r
+ child.setText(0,"Since");\r
+ lastModified.addChild(child);\r
+ parent = child;\r
+ for (int i=0; i<Global.changedSinceFilter.size(); i++) {\r
+ child = new QTreeWidgetItem();\r
+ child.setIcon(0, icon);\r
+ child.setText(0,Global.changedSinceFilter.getName(i));\r
+ parent.addChild(child);\r
+ }\r
+ \r
+ \r
+ parent = created;\r
+ child = new QTreeWidgetItem();\r
+ child.setText(0,"Before");\r
+ lastModified.addChild(child);\r
+ parent = child;\r
+ for (int i=0; i<Global.changedBeforeFilter.size(); i++) {\r
+ child = new QTreeWidgetItem();\r
+ child.setIcon(0, icon);\r
+ child.setText(0,Global.changedBeforeFilter.getName(i));\r
+ parent.addChild(child);\r
+ }\r
+ \r
+ // Now we are into the other attributes\r
+ QTreeWidgetItem contains = new QTreeWidgetItem();\r
+ contains.setText(0,"Contains");\r
+ addTopLevelItem(contains);\r
+ child = new QTreeWidgetItem();\r
+ child.setText(0,"Images");\r
+ child.setIcon(0, icon);\r
+ contains.addChild(child);\r
+ \r
+ child = new QTreeWidgetItem();\r
+ child.setText(0,"Audio");\r
+ child.setIcon(0, icon);\r
+ contains.addChild(child);\r
+ \r
+ child = new QTreeWidgetItem();\r
+ child.setText(0,"Ink");\r
+ child.setIcon(0, icon);\r
+ contains.addChild(child);\r
+ \r
+ child = new QTreeWidgetItem();\r
+ child.setText(0,"Encrypted Text");\r
+ child.setIcon(0, icon);\r
+ contains.addChild(child);\r
+ \r
+ \r
+ child = new QTreeWidgetItem();\r
+ child.setText(0,"To-Do Items");\r
+ child.setIcon(0, icon);\r
+ contains.addChild(child);\r
+ \r
+ child = new QTreeWidgetItem();\r
+ child.setText(0,"Unfinished to-do items");\r
+ child.setIcon(0, icon);\r
+ contains.addChild(child);\r
+ \r
+ child = new QTreeWidgetItem();\r
+ child.setText(0,"Finished to-do items");\r
+ child.setIcon(0, icon);\r
+ contains.addChild(child);\r
+ \r
+ child = new QTreeWidgetItem();\r
+ child.setText(0,"Attachment");\r
+ child.setIcon(0, icon);\r
+ contains.addChild(child);\r
+ \r
+ child = new QTreeWidgetItem();\r
+ child.setText(0,"PDF");\r
+ child.setIcon(0, icon);\r
+ contains.addChild(child);\r
+ \r
+ }\r
+ \r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+ */\r
+\r
+package cx.fbn.nevernote.gui;\r
+\r
+import java.io.File;\r
+import java.net.FileNameMap;\r
+import java.net.URI;\r
+import java.net.URLConnection;\r
+import java.security.MessageDigest;\r
+import java.security.NoSuchAlgorithmException;\r
+import java.text.SimpleDateFormat;\r
+import java.util.ArrayList;\r
+import java.util.Calendar;\r
+import java.util.Date;\r
+import java.util.GregorianCalendar;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+\r
+import com.evernote.edam.limits.Constants;\r
+import com.evernote.edam.type.Data;\r
+import com.evernote.edam.type.Note;\r
+import com.evernote.edam.type.Notebook;\r
+import com.evernote.edam.type.Resource;\r
+import com.evernote.edam.type.ResourceAttributes;\r
+import com.evernote.edam.type.Tag;\r
+import com.trolltech.qt.core.QByteArray;\r
+import com.trolltech.qt.core.QDataStream;\r
+import com.trolltech.qt.core.QDateTime;\r
+import com.trolltech.qt.core.QEvent;\r
+import com.trolltech.qt.core.QFile;\r
+import com.trolltech.qt.core.QFileSystemWatcher;\r
+import com.trolltech.qt.core.QIODevice;\r
+import com.trolltech.qt.core.QMimeData;\r
+import com.trolltech.qt.core.QUrl;\r
+import com.trolltech.qt.gui.QApplication;\r
+import com.trolltech.qt.gui.QCalendarWidget;\r
+import com.trolltech.qt.gui.QClipboard;\r
+import com.trolltech.qt.gui.QColor;\r
+import com.trolltech.qt.gui.QComboBox;\r
+import com.trolltech.qt.gui.QDateEdit;\r
+import com.trolltech.qt.gui.QDesktopServices;\r
+import com.trolltech.qt.gui.QFileDialog;\r
+import com.trolltech.qt.gui.QFontDatabase;\r
+import com.trolltech.qt.gui.QFormLayout;\r
+import com.trolltech.qt.gui.QGridLayout;\r
+import com.trolltech.qt.gui.QHBoxLayout;\r
+import com.trolltech.qt.gui.QIcon;\r
+import com.trolltech.qt.gui.QImage;\r
+import com.trolltech.qt.gui.QKeySequence;\r
+import com.trolltech.qt.gui.QLabel;\r
+import com.trolltech.qt.gui.QLineEdit;\r
+import com.trolltech.qt.gui.QListWidgetItem;\r
+import com.trolltech.qt.gui.QMatrix;\r
+import com.trolltech.qt.gui.QMessageBox;\r
+import com.trolltech.qt.gui.QPushButton;\r
+import com.trolltech.qt.gui.QShortcut;\r
+import com.trolltech.qt.gui.QTimeEdit;\r
+import com.trolltech.qt.gui.QVBoxLayout;\r
+import com.trolltech.qt.gui.QWidget;\r
+import com.trolltech.qt.gui.QFileDialog.AcceptMode;\r
+import com.trolltech.qt.gui.QFileDialog.FileMode;\r
+import com.trolltech.qt.network.QNetworkRequest;\r
+import com.trolltech.qt.webkit.QWebPage;\r
+import com.trolltech.qt.webkit.QWebSettings;\r
+import com.trolltech.qt.webkit.QWebView;\r
+import com.trolltech.qt.webkit.QWebPage.WebAction;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.dialog.EnCryptDialog;\r
+import cx.fbn.nevernote.dialog.EnDecryptDialog;\r
+import cx.fbn.nevernote.dialog.InsertLinkDialog;\r
+import cx.fbn.nevernote.dialog.TableDialog;\r
+import cx.fbn.nevernote.dialog.TagAssign;\r
+import cx.fbn.nevernote.evernote.EnCrypt;\r
+import cx.fbn.nevernote.signals.NoteResourceSignal;\r
+import cx.fbn.nevernote.signals.NoteSignal;\r
+import cx.fbn.nevernote.sql.DatabaseConnection;\r
+import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+\r
+public class BrowserWindow extends QWidget {\r
+\r
+ public final QLineEdit titleLabel;\r
+ private final QLineEdit urlText;\r
+ private final QLabel authorLabel;\r
+ private final QLineEdit authorText;\r
+ public final TagLineEdit tagEdit;\r
+ public final QLabel tagLabel;\r
+ private final QLabel urlLabel;\r
+ private final QLabel alteredLabel;\r
+ private final QDateEdit alteredDate;\r
+ private final QTimeEdit alteredTime;\r
+ private final QDateEdit createdDate;\r
+ private final QTimeEdit createdTime;\r
+ private final QLabel subjectLabel;\r
+ private final QDateEdit subjectDate;\r
+ private final QTimeEdit subjectTime;\r
+ public final QComboBox notebookBox;\r
+ private final QLabel notebookLabel;\r
+ private final QLabel createdLabel;\r
+ public final QComboBox fontSize;\r
+ private boolean extendedOn;\r
+ public boolean buttonsVisible;\r
+ private final String iconPath = new String("classpath:cx/fbn/nevernote/icons/");\r
+ private final ContentView browser;\r
+ private List<Tag> allTags;\r
+ private List<String> currentTags;\r
+ public NoteSignal noteSignal;\r
+ private List<Notebook> notebookList;\r
+ private Note currentNote;\r
+ private String saveNoteTitle;\r
+ private String saveTagList;\r
+ private boolean insideList;\r
+// private String selectedText;\r
+ private final DatabaseConnection conn;\r
+ private final QCalendarWidget createdCalendarWidget;\r
+ private final QCalendarWidget alteredCalendarWidget;\r
+ private final QCalendarWidget subjectCalendarWidget;\r
+\r
+ public final QPushButton undoButton;\r
+ public final QPushButton redoButton;\r
+ public final QPushButton cutButton;\r
+ public final QPushButton copyButton;\r
+ public final QPushButton pasteButton;\r
+ public final QPushButton boldButton;\r
+ public final QPushButton underlineButton;\r
+ public final QPushButton italicButton;\r
+ public final Signal0 focusLost;\r
+ public final NoteResourceSignal resourceSignal;\r
+\r
+ public QPushButton rightAlignButton;\r
+ public QPushButton leftAlignButton;\r
+ public QPushButton centerAlignButton;\r
+\r
+ public final QPushButton strikethroughButton;\r
+ public final QPushButton hlineButton;\r
+ public final QPushButton indentButton;\r
+ public final QPushButton outdentButton;\r
+ public final QPushButton bulletListButton;\r
+ public final QPushButton numberListButton;\r
+\r
+ public final QShortcut focusTitleShortcut;\r
+ public final QShortcut focusTagShortcut;\r
+ public final QShortcut focusNoteShortcut;\r
+ public final QShortcut focusUrlShortcut;\r
+ public final QShortcut focusAuthorShortcut;\r
+ \r
+ public final QComboBox fontList;\r
+ public final QPushButton fontColor;\r
+ private final ColorMenu fontColorMenu;\r
+ public final QPushButton fontHilight;\r
+// public final ColorComboBox fontHilight;\r
+ private final ColorMenu fontHilightColorMenu;\r
+ public final QFileSystemWatcher fileWatcher;\r
+ public int cursorPosition;\r
+ private boolean forceTextPaste = false;\r
+ private String selectedFile;\r
+ private String currentHyperlink;\r
+ public boolean keepPDFNavigationHidden;\r
+ private final ApplicationLogger logger;\r
+ \r
+ private final HashMap<String,Integer> previewPageList; \r
+ \r
+ \r
+ public BrowserWindow(DatabaseConnection c) {\r
+ logger = new ApplicationLogger("browser.log");\r
+ logger.log(logger.HIGH, "Setting up browser");\r
+ \r
+ fileWatcher = new QFileSystemWatcher();\r
+// fileWatcher.fileChanged.connect(this, "fileChanged(String)");\r
+ noteSignal = new NoteSignal();\r
+ titleLabel = new QLineEdit();\r
+ titleLabel.setMaxLength(Constants.EDAM_NOTE_TITLE_LEN_MAX);\r
+ urlText = new QLineEdit();\r
+ authorText = new QLineEdit();\r
+ urlLabel = new QLabel();\r
+ authorLabel = new QLabel();\r
+ conn = c;\r
+ \r
+ focusLost = new Signal0();\r
+\r
+ tagEdit = new TagLineEdit(allTags);\r
+ tagLabel = new QLabel("Tags:");\r
+ tagEdit.focusLost.connect(this, "modifyTagsTyping()");\r
+\r
+ createdCalendarWidget = new QCalendarWidget();\r
+ createdDate = new QDateEdit();\r
+ createdDate.setDisplayFormat(Global.getDateFormat());\r
+ createdDate.setCalendarPopup(true);\r
+ createdDate.setCalendarWidget(createdCalendarWidget);\r
+ createdTime = new QTimeEdit();\r
+ createdDate.dateChanged.connect(this, "createdChanged()");\r
+ createdTime.timeChanged.connect(this, "createdChanged()");\r
+\r
+ alteredCalendarWidget = new QCalendarWidget();\r
+ alteredDate = new QDateEdit();\r
+ alteredDate.setDisplayFormat(Global.getDateFormat());\r
+ alteredDate.setCalendarPopup(true);\r
+ alteredDate.setCalendarWidget(alteredCalendarWidget);\r
+ alteredTime = new QTimeEdit();\r
+ alteredLabel = new QLabel("Altered:");\r
+ alteredDate.dateChanged.connect(this, "alteredChanged()");\r
+ alteredTime.timeChanged.connect(this, "alteredChanged()");\r
+\r
+ subjectCalendarWidget = new QCalendarWidget();\r
+ subjectDate = new QDateEdit();\r
+ subjectDate.setDisplayFormat(Global.getDateFormat());\r
+ subjectDate.setCalendarPopup(true);\r
+ subjectDate.setCalendarWidget(subjectCalendarWidget);\r
+ subjectTime = new QTimeEdit();\r
+ subjectLabel = new QLabel("Subject Date:");\r
+ subjectDate.dateChanged.connect(this, "subjectDateTimeChanged()");\r
+ subjectTime.timeChanged.connect(this, "subjectDateTimeChanged()");\r
+ authorText.textChanged.connect(this, "authorChanged()");\r
+ urlText.textChanged.connect(this, "sourceUrlChanged()");\r
+\r
+ notebookBox = new QComboBox();\r
+ notebookLabel = new QLabel("Notebook");\r
+ createdLabel = new QLabel("Created:");\r
+ // selectedText = new String();\r
+\r
+ urlLabel.setVisible(false);\r
+ urlText.setVisible(false);\r
+ authorLabel.setVisible(false);\r
+ authorText.setVisible(false);\r
+ createdDate.setVisible(false);\r
+ alteredLabel.setVisible(false);\r
+ //notebookBox.setVisible(false);\r
+ notebookLabel.setVisible(false);\r
+ createdLabel.setVisible(false);\r
+ createdTime.setVisible(false);\r
+ alteredDate.setVisible(false);\r
+ alteredTime.setVisible(false);\r
+ subjectLabel.setVisible(false);\r
+ subjectDate.setVisible(false);\r
+ subjectTime.setVisible(false);\r
+ extendedOn = false;\r
+ buttonsVisible = true;\r
+ setAcceptDrops(true);\r
+\r
+ browser = new ContentView(this);\r
+ browser.page().setLinkDelegationPolicy(\r
+ QWebPage.LinkDelegationPolicy.DelegateAllLinks);\r
+ browser.linkClicked.connect(this, "linkClicked(QUrl)");\r
+ currentHyperlink = "";\r
+ \r
+ QVBoxLayout v = new QVBoxLayout();\r
+ QFormLayout notebookLayout = new QFormLayout();\r
+ QGridLayout dateLayout = new QGridLayout();\r
+ titleLabel.setReadOnly(false);\r
+ titleLabel.editingFinished.connect(this, "titleEdited()");\r
+ browser.page().contentsChanged.connect(this, "contentChanged()");\r
+ browser.page().selectionChanged.connect(this, "selectionChanged()");\r
+ browser.page().mainFrame().javaScriptWindowObjectCleared.connect(this,\r
+ "exposeToJavascript()");\r
+\r
+ notebookBox.activated.connect(this, "notebookChanged()");\r
+ resourceSignal = new NoteResourceSignal();\r
+ \r
+ QHBoxLayout tagLayout = new QHBoxLayout();\r
+ v.addWidget(titleLabel, 0);\r
+ notebookLayout.addRow(notebookLabel, notebookBox);\r
+ tagLayout.addLayout(notebookLayout, 0);\r
+ tagLayout.stretch(4);\r
+ tagLayout.addWidget(tagLabel, 0);\r
+ tagLayout.addWidget(tagEdit, 1);\r
+ v.addLayout(tagLayout);\r
+\r
+ QHBoxLayout urlLayout = new QHBoxLayout();\r
+ urlLayout.addWidget(urlLabel, 0);\r
+ urlLayout.addWidget(urlText, 0);\r
+ v.addLayout(urlLayout);\r
+\r
+ QHBoxLayout authorLayout = new QHBoxLayout();\r
+ authorLayout.addWidget(authorLabel, 0);\r
+ authorLayout.addWidget(authorText, 0);\r
+ v.addLayout(authorLayout);\r
+\r
+ dateLayout.addWidget(createdLabel, 0, 0);\r
+ dateLayout.addWidget(createdDate, 0, 1);\r
+ dateLayout.addWidget(createdTime, 0, 2);\r
+ dateLayout.setColumnStretch(9, 100);\r
+ dateLayout.addWidget(alteredLabel, 0, 3);\r
+ dateLayout.addWidget(alteredDate, 0, 4);\r
+ dateLayout.addWidget(alteredTime, 0, 5);\r
+ dateLayout.addWidget(subjectLabel, 0, 6);\r
+ dateLayout.addWidget(subjectDate, 0, 7);\r
+ dateLayout.addWidget(subjectTime, 0, 8);\r
+ v.addLayout(dateLayout, 0);\r
+\r
+ undoButton = newEditorButton("undo", "Undo Change");\r
+ redoButton = newEditorButton("redo", "Redo Change");\r
+ cutButton = newEditorButton("cut", "Cut");\r
+ copyButton = newEditorButton("copy", "Copy");\r
+ pasteButton = newEditorButton("paste", "Paste");\r
+ boldButton = newEditorButton("bold", "Bold");\r
+ underlineButton = newEditorButton("underline", "Underline");\r
+ italicButton = newEditorButton("italic", "Italic");\r
+\r
+ rightAlignButton = newEditorButton("justifyRight", "Right Align");\r
+ leftAlignButton = newEditorButton("justifyLeft", "Left Align");\r
+ centerAlignButton = newEditorButton("justifyCenter", "Center Align");\r
+\r
+ strikethroughButton = newEditorButton("strikethrough", "Strikethrough");\r
+ hlineButton = newEditorButton("hline", "Insert Horizontal Line");\r
+ indentButton = newEditorButton("indent", "Shift Right");\r
+ outdentButton = newEditorButton("outdent", "Shift Left");\r
+ bulletListButton = newEditorButton("bulletList", "Bullet List");\r
+ numberListButton = newEditorButton("numberList", "Number List");\r
+\r
+\r
+ QHBoxLayout buttonLayout;\r
+ buttonLayout = new QHBoxLayout();\r
+ buttonLayout.setSpacing(0);\r
+ v.addLayout(buttonLayout);\r
+ \r
+ buttonLayout.addWidget(undoButton);\r
+ buttonLayout.addWidget(redoButton);\r
+\r
+ buttonLayout.addWidget(newSeparator(), 0);\r
+ buttonLayout.addWidget(cutButton);\r
+ buttonLayout.addWidget(copyButton);\r
+ buttonLayout.addWidget(pasteButton);\r
+\r
+ buttonLayout.addWidget(newSeparator(), 0);\r
+ buttonLayout.addWidget(boldButton);\r
+ buttonLayout.addWidget(italicButton);\r
+ buttonLayout.addWidget(underlineButton);\r
+ buttonLayout.addWidget(strikethroughButton);\r
+ \r
+ buttonLayout.addWidget(newSeparator(), 0);\r
+ buttonLayout.addWidget(leftAlignButton);\r
+ buttonLayout.addWidget(centerAlignButton);\r
+ buttonLayout.addWidget(rightAlignButton);\r
+\r
+ buttonLayout.addWidget(newSeparator(), 0);\r
+ buttonLayout.addWidget(hlineButton);\r
+\r
+ buttonLayout.addWidget(indentButton);\r
+ buttonLayout.addWidget(outdentButton);\r
+ buttonLayout.addWidget(bulletListButton);\r
+ buttonLayout.addWidget(numberListButton);\r
+\r
+ // Setup the font & font size combo boxes\r
+ buttonLayout.addWidget(newSeparator(), 0);\r
+ fontList = new QComboBox();\r
+ fontSize = new QComboBox();\r
+ fontList.setToolTip("Font");\r
+ fontSize.setToolTip("Font Size");\r
+ fontList.activated.connect(this, "fontChanged(String)");\r
+ fontSize.activated.connect(this, "fontSizeChanged(String)");\r
+ buttonLayout.addWidget(fontList, 0);\r
+ buttonLayout.addWidget(fontSize, 0);\r
+ QFontDatabase fonts = new QFontDatabase();\r
+ List<String> fontFamilies = fonts.families();\r
+ for (int i = 0; i < fontFamilies.size(); i++) {\r
+ fontList.addItem(fontFamilies.get(i));\r
+ if (i == 0) {\r
+ loadFontSize(fontFamilies.get(i));\r
+ }\r
+ }\r
+\r
+ buttonLayout.addWidget(newSeparator(), 0);\r
+ fontColor = newEditorButton("fontColor", "Font Color");\r
+ fontColorMenu = new ColorMenu(this);\r
+ fontColor.setMenu(fontColorMenu.getMenu());\r
+ fontColorMenu.getMenu().triggered.connect(this, "fontColorClicked()");\r
+ buttonLayout.addWidget(fontColor);\r
+ fontHilight = newEditorButton("fontHilight", "Font Hilight Color");\r
+ fontHilightColorMenu = new ColorMenu(this);\r
+ fontHilight.setMenu(fontHilightColorMenu.getMenu());\r
+ fontHilightColorMenu.getMenu().triggered.connect(this, "fontHilightClicked()");\r
+ buttonLayout.addWidget(fontHilight);\r
+\r
+ buttonLayout.addWidget(new QLabel(), 1);\r
+ v.addWidget(browser, 1);\r
+// v.addLayout(buttonLayout,0);\r
+ setLayout(v);\r
+\r
+ browser.downloadAttachmentRequested.connect(this,\r
+ "downloadAttachment(QNetworkRequest)");\r
+ browser.downloadImageRequested.connect(this,\r
+ "downloadImage(QNetworkRequest)");\r
+ setTabOrder(notebookBox, tagEdit);\r
+ setTabOrder(tagEdit, browser);\r
+ \r
+ focusNoteShortcut = new QShortcut(this);\r
+ setupShortcut(focusNoteShortcut, "Focus_Note");\r
+ focusNoteShortcut.activated.connect(this, "focusNote()");\r
+ focusTitleShortcut = new QShortcut(this);\r
+ setupShortcut(focusTitleShortcut, "Focus_Title");\r
+ focusTitleShortcut.activated.connect(this, "focusTitle()");\r
+ focusTagShortcut = new QShortcut(this);\r
+ setupShortcut(focusTagShortcut, "Focus_Tag");\r
+ focusTagShortcut.activated.connect(this, "focusTag()");\r
+ focusAuthorShortcut = new QShortcut(this);\r
+ setupShortcut(focusAuthorShortcut, "Focus_Author");\r
+ focusAuthorShortcut.activated.connect(this, "focusAuthor()");\r
+ focusUrlShortcut = new QShortcut(this);\r
+ setupShortcut(focusUrlShortcut, "Focus_Url");\r
+ focusUrlShortcut.activated.connect(this, "focusUrl()");\r
+ \r
+ browser.page().mainFrame().setTextSizeMultiplier(Global.getTextSizeMultiplier());\r
+ browser.page().mainFrame().setZoomFactor(Global.getZoomFactor());\r
+ \r
+ previewPageList = new HashMap<String,Integer>();\r
+ \r
+ browser.page().microFocusChanged.connect(this, "microFocusChanged()");\r
+ logger.log(logger.HIGH, "Browser setup complete");\r
+ }\r
+\r
+ \r
+ private void setupShortcut(QShortcut action, String text) {\r
+ if (!Global.shortcutKeys.containsAction(text))\r
+ return;\r
+ action.setKey(new QKeySequence(Global.shortcutKeys.getShortcut(text)));\r
+ }\r
+ \r
+ \r
+\r
+ \r
+ // Getter for the QWebView\r
+ public QWebView getBrowser() {\r
+ return browser;\r
+ }\r
+\r
+ // Block signals while loading data or things are flagged as dirty by\r
+ // mistake\r
+ public void loadingData(boolean val) {\r
+ logger.log(logger.EXTREME, "Entering BrowserWindow.loadingData() " +val);\r
+ notebookBox.blockSignals(val);\r
+ browser.page().blockSignals(val);\r
+ browser.page().mainFrame().blockSignals(val);\r
+ titleLabel.blockSignals(val);\r
+ alteredDate.blockSignals(val);\r
+ alteredTime.blockSignals(val);\r
+ createdTime.blockSignals(val);\r
+ createdDate.blockSignals(val);\r
+ subjectDate.blockSignals(val);\r
+ subjectTime.blockSignals(val);\r
+ urlText.blockSignals(val);\r
+ authorText.blockSignals(val);\r
+ if (!val)\r
+ exposeToJavascript();\r
+ logger.log(logger.EXTREME, "Exiting BrowserWindow.loadingData() " +val);\r
+ }\r
+\r
+ // Enable/disable\r
+ public void setReadOnly(boolean v) {\r
+ setEnabled(true);\r
+ titleLabel.setEnabled(!v);\r
+ notebookBox.setEnabled(!v);\r
+ tagEdit.setEnabled(!v);\r
+ authorLabel.setEnabled(!v);\r
+ urlText.setEnabled(!v);\r
+ createdDate.setEnabled(!v);\r
+ subjectDate.setEnabled(!v);\r
+ alteredDate.setEnabled(!v);\r
+ getBrowser().setEnabled(true);\r
+ }\r
+ \r
+ // expose this class to Javascript on the web page\r
+ private void exposeToJavascript() {\r
+ browser.page().mainFrame().addToJavaScriptWindowObject("jambi", this);\r
+ }\r
+\r
+ // Custom event queue\r
+ @Override\r
+ public boolean event(QEvent e) {\r
+ if (e.type().equals(QEvent.Type.FocusOut)) {\r
+ logger.log(logger.EXTREME, "Focus lost");\r
+ focusLost.emit();\r
+ }\r
+ return super.event(e);\r
+ }\r
+\r
+ // clear out browser\r
+ public void clear() {\r
+ logger.log(logger.EXTREME, "Entering BrowserWindow.clear()");\r
+ setNote(null);\r
+ browser.setContent(new QByteArray());\r
+ tagEdit.setText("");\r
+ urlLabel.setText("Source URL:");\r
+ titleLabel.setText("");\r
+ logger.log(logger.EXTREME, "Exiting BrowserWindow.clear()");\r
+ }\r
+\r
+ // get/set current note\r
+ public void setNote(Note n) {\r
+ currentNote = n;\r
+ if (n == null)\r
+ n = new Note();\r
+ saveNoteTitle = n.getTitle();\r
+\r
+ }\r
+\r
+ public Note getNote() {\r
+ return currentNote;\r
+ }\r
+\r
+ // New Editor Button\r
+ private QPushButton newEditorButton(String name, String toolTip) {\r
+ QPushButton button = new QPushButton();\r
+ QIcon icon = new QIcon(iconPath + name + ".gif");\r
+ button.setIcon(icon);\r
+ button.setToolTip(toolTip);\r
+ button.clicked.connect(this, name + "Clicked()");\r
+ return button;\r
+ }\r
+\r
+ // New Separator\r
+ private QLabel newSeparator() {\r
+ return new QLabel(" ");\r
+ }\r
+\r
+ // Set the title in the window\r
+ public void setTitle(String t) {\r
+ titleLabel.setText(t);\r
+ saveNoteTitle = t;\r
+ checkNoteTitle();\r
+ }\r
+\r
+ // Return the current text title\r
+ public String getTitle() {\r
+ return titleLabel.text();\r
+ }\r
+\r
+ // Set the tag name string\r
+ public void setTag(String t) {\r
+ saveTagList = t;\r
+ tagEdit.setText(t);\r
+ }\r
+\r
+ // Set the source URL\r
+ public void setUrl(String t) {\r
+ urlLabel.setText("Source URL:\t");\r
+ urlText.setText(t);\r
+ }\r
+\r
+ public void setAuthor(String t) {\r
+ authorLabel.setText("Author:\t");\r
+ authorText.setText(t);\r
+ }\r
+\r
+ // Set the creation date\r
+ public void setCreation(long date) {\r
+ QDateTime dt = new QDateTime();\r
+ dt.setTime_t((int) (date / 1000));\r
+ createdDate.setDateTime(dt);\r
+ createdTime.setDateTime(dt);\r
+ createdDate.setDisplayFormat(Global.getDateFormat());\r
+ createdTime.setDisplayFormat(Global.getTimeFormat());\r
+ }\r
+\r
+ // Set the creation date\r
+ public void setAltered(long date) {\r
+ QDateTime dt = new QDateTime();\r
+ dt.setTime_t((int) (date / 1000));\r
+ alteredDate.setDateTime(dt);\r
+ alteredTime.setDateTime(dt);\r
+ alteredDate.setDisplayFormat(Global.getDateFormat());\r
+ alteredTime.setDisplayFormat(Global.getTimeFormat());\r
+ }\r
+\r
+ // Set the subject date\r
+ public void setSubjectDate(long date) {\r
+ QDateTime dt = new QDateTime();\r
+ dt.setTime_t((int) (date / 1000));\r
+ subjectDate.setDateTime(dt);\r
+ subjectTime.setDateTime(dt);\r
+ subjectDate.setDisplayFormat(Global.getDateFormat());\r
+ subjectTime.setDisplayFormat(Global.getTimeFormat());\r
+ }\r
+\r
+ // Toggle the extended attribute information\r
+ public void toggleInformation() {\r
+ if (extendedOn) {\r
+ extendedOn = false;\r
+ } else {\r
+ extendedOn = true;\r
+ }\r
+ urlLabel.setVisible(extendedOn);\r
+ urlText.setVisible(extendedOn);\r
+ authorText.setVisible(extendedOn);\r
+ authorLabel.setVisible(extendedOn);\r
+ createdDate.setVisible(extendedOn);\r
+ createdTime.setVisible(extendedOn);\r
+ createdLabel.setVisible(extendedOn);\r
+ alteredLabel.setVisible(extendedOn);\r
+ alteredDate.setVisible(extendedOn);\r
+ alteredTime.setVisible(extendedOn);\r
+ //notebookBox.setVisible(extendedOn);\r
+ notebookLabel.setVisible(extendedOn);\r
+ subjectLabel.setVisible(extendedOn);\r
+ subjectDate.setVisible(extendedOn);\r
+ subjectTime.setVisible(extendedOn);\r
+ }\r
+\r
+ public void hideButtons() {\r
+\r
+ buttonsVisible = false;\r
+ \r
+ undoButton.setVisible(false);\r
+ redoButton.setVisible(false);\r
+ cutButton.setVisible(false);\r
+ copyButton.setVisible(false);\r
+ pasteButton.setVisible(false);\r
+ boldButton.setVisible(false);\r
+ underlineButton.setVisible(false);\r
+ italicButton.setVisible(false);\r
+\r
+ rightAlignButton.setVisible(false);\r
+ leftAlignButton.setVisible(false);\r
+ centerAlignButton.setVisible(false);\r
+\r
+ strikethroughButton.setVisible(false);\r
+ hlineButton.setVisible(false);\r
+ indentButton.setVisible(false);\r
+ outdentButton.setVisible(false);\r
+ bulletListButton.setVisible(false);\r
+ numberListButton.setVisible(false);\r
+\r
+ fontList.setVisible(false);\r
+ fontSize.setVisible(false);\r
+ fontColor.setVisible(false);\r
+ fontHilight.setVisible(false);\r
+\r
+ }\r
+\r
+\r
+ // Is the extended view on?\r
+ public boolean isExtended() {\r
+ return extendedOn;\r
+ }\r
+\r
+ // Listener for when a link is clicked\r
+ @SuppressWarnings("unused")\r
+ private void openFile() {\r
+ logger.log(logger.EXTREME, "Starting openFile()");\r
+ File fileHandle = new File(selectedFile);\r
+ URI fileURL = fileHandle.toURI();\r
+ String localURL = fileURL.toString();\r
+ QUrl url = new QUrl(localURL);\r
+ QFile file = new QFile(selectedFile);\r
+ \r
+ logger.log(logger.EXTREME, "Adding to fileWatcher:"+file.fileName());\r
+ fileWatcher.addPath(file.fileName());\r
+ \r
+ if (!QDesktopServices.openUrl(url)) {\r
+ logger.log(logger.LOW, "Error opening file :" +url);\r
+ }\r
+ }\r
+ \r
+ \r
+ // Listener for when a link is clicked\r
+ @SuppressWarnings("unused")\r
+ private void linkClicked(QUrl url) {\r
+ logger.log(logger.EXTREME, "URL Clicked: " +url.toString());\r
+ if (url.toString().substring(0,8).equals("nnres://")) {\r
+ logger.log(logger.EXTREME, "URL is NN resource");\r
+ if (url.toString().endsWith("/vnd.evernote.ink")) {\r
+ logger.log(logger.EXTREME, "Unable to open ink note");\r
+ QMessageBox.information(this, "Unable Open", "This is an ink note.\n"+\r
+ "Ink notes are not supported since Evernote has not\n published any specifications on them\n" +\r
+ "and I'm too lazy to figure them out by myself.");\r
+ return;\r
+ }\r
+ String fullName = url.toString().substring(8);\r
+ int index = fullName.indexOf(".");\r
+ String guid = "";\r
+ String type = "";\r
+ if (index >-1) {\r
+ type = fullName.substring(index+1);\r
+ guid = fullName.substring(0,index);\r
+ }\r
+ index = guid.indexOf(Global.attachmentNameDelimeter);\r
+ if (index > -1) {\r
+ guid = guid.substring(0,index);\r
+ }\r
+ List<Resource> resList = currentNote.getResources();\r
+ Resource res = null;\r
+ for (int i=0; i<resList.size(); i++) {\r
+ if (resList.get(i).getGuid().equals(guid)) {\r
+ res = resList.get(i);\r
+ i=resList.size();\r
+ }\r
+ }\r
+ if (res == null) {\r
+ String resGuid = Global.resourceMap.get(guid);\r
+ if (resGuid != null) \r
+ res = conn.getNoteTable().noteResourceTable.getNoteResource(resGuid, true);\r
+ }\r
+ if (res != null) {\r
+ String fileName;\r
+ if (res.getAttributes() != null && \r
+ res.getAttributes().getFileName() != null && \r
+ !res.getAttributes().getFileName().trim().equals(""))\r
+ fileName = res.getGuid()+Global.attachmentNameDelimeter+res.getAttributes().getFileName();\r
+ else\r
+ fileName = res.getGuid()+"."+type;\r
+ QFile file = new QFile(Global.getDirectoryPath() +"res/"+fileName);\r
+ QFile.OpenMode mode = new QFile.OpenMode();\r
+ mode.set(QFile.OpenModeFlag.WriteOnly);\r
+ boolean openResult = file.open(mode);\r
+ logger.log(logger.EXTREME, "File opened:" +openResult);\r
+ QDataStream out = new QDataStream(file);\r
+ Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(res.getGuid(), true);\r
+ QByteArray binData = new QByteArray(resBinary.getData().getBody());\r
+ resBinary = null;\r
+ logger.log(logger.EXTREME, "Writing resource");\r
+ out.writeBytes(binData.toByteArray());\r
+ file.close();\r
+ \r
+ String whichOS = System.getProperty("os.name");\r
+ if (whichOS.contains("Windows")) \r
+ url.setUrl("file:///"+file.fileName());\r
+ else\r
+ url.setUrl("file://"+file.fileName());\r
+ // fileWatcher.removePath(file.fileName());\r
+ logger.log(logger.EXTREME, "Adding file watcher " +file.fileName());\r
+ fileWatcher.addPath(file.fileName());\r
+ \r
+ // If we can't open it, then prompt the user to save it.\r
+ if (!QDesktopServices.openUrl(url)) {\r
+ logger.log(logger.EXTREME, "We can't handle this. Where do we put it?");\r
+ QFileDialog dialog = new QFileDialog();\r
+ dialog.show();\r
+ if (dialog.exec()!=0) {\r
+ List<String> fileNames = dialog.selectedFiles(); //gets all selected filenames\r
+ if (fileNames.size() == 0) \r
+ return;\r
+ String sf = fileNames.get(0);\r
+ QFile saveFile = new QFile(sf);\r
+ mode.set(QFile.OpenModeFlag.WriteOnly);\r
+ saveFile.open(mode);\r
+ QDataStream saveOut = new QDataStream(saveFile);\r
+ saveOut.writeBytes(binData.toByteArray());\r
+ saveFile.close();\r
+ return;\r
+ }\r
+ }\r
+ }\r
+ return;\r
+ }\r
+ logger.log(logger.EXTREME, "Launching URL");\r
+ QDesktopServices.openUrl(url);\r
+ }\r
+\r
+ // Listener for when BOLD is clicked\r
+ @SuppressWarnings("unused")\r
+ private void undoClicked() {\r
+ browser.page().triggerAction(WebAction.Undo);\r
+ browser.setFocus();\r
+ }\r
+\r
+ // Listener for when BOLD is clicked\r
+ @SuppressWarnings("unused")\r
+ private void redoClicked() {\r
+ browser.page().triggerAction(WebAction.Redo);\r
+ browser.setFocus();\r
+ }\r
+\r
+ // Listener for when BOLD is clicked\r
+ @SuppressWarnings("unused")\r
+ private void boldClicked() {\r
+ browser.page().triggerAction(WebAction.ToggleBold);\r
+ microFocusChanged();\r
+ browser.setFocus();\r
+ }\r
+\r
+ // Listener for when Italics is clicked\r
+ @SuppressWarnings("unused")\r
+ private void italicClicked() {\r
+ browser.page().triggerAction(WebAction.ToggleItalic);\r
+ microFocusChanged();\r
+ browser.setFocus();\r
+ }\r
+\r
+ // Listener for when UNDERLINE is clicked\r
+ @SuppressWarnings("unused")\r
+ private void underlineClicked() {\r
+ browser.page().triggerAction(WebAction.ToggleUnderline);\r
+ microFocusChanged();\r
+ browser.setFocus();\r
+ }\r
+\r
+ // Listener for when Strikethrough is clicked\r
+ @SuppressWarnings("unused")\r
+ private void strikethroughClicked() {\r
+ browser.page().mainFrame().evaluateJavaScript(\r
+ "document.execCommand('strikeThrough', false, '');");\r
+ browser.setFocus();\r
+ }\r
+\r
+ // Listener for when cut is clicked\r
+ @SuppressWarnings("unused")\r
+ private void cutClicked() {\r
+ browser.page().triggerAction(WebAction.Cut);\r
+ browser.setFocus();\r
+ }\r
+\r
+ // Listener when COPY is clicked\r
+ @SuppressWarnings("unused")\r
+ private void copyClicked() {\r
+ browser.page().triggerAction(WebAction.Copy);\r
+ browser.setFocus();\r
+ }\r
+\r
+ // Listener when PASTE is clicked\r
+ void pasteClicked() {\r
+ logger.log(logger.EXTREME, "Paste Clicked");\r
+ if (forceTextPaste) {\r
+ pasteWithoutFormattingClicked();\r
+ return;\r
+ }\r
+ QClipboard clipboard = QApplication.clipboard();\r
+ QMimeData mime = clipboard.mimeData();\r
+ \r
+// String x = mime.html();\r
+\r
+ if (mime.hasImage()) {\r
+ logger.log(logger.EXTREME, "Image paste found");\r
+ insertImage(mime);\r
+ browser.setFocus();\r
+ return;\r
+ }\r
+\r
+ if (mime.hasUrls()) {\r
+ logger.log(logger.EXTREME, "URL paste found");\r
+ handleUrls(mime);\r
+ browser.setFocus();\r
+ return;\r
+ }\r
+ \r
+ String text = mime.html();\r
+ if (text.contains("en-tag") && mime.hasHtml()) {\r
+ logger.log(logger.EXTREME, "Intra-note paste found");\r
+ text = fixInternotePaste(text);\r
+ mime.setHtml(text);\r
+ clipboard.setMimeData(mime);\r
+ }\r
+\r
+ logger.log(logger.EXTREME, "Final paste choice encountered");\r
+ browser.page().triggerAction(WebAction.Paste);\r
+ browser.setFocus();\r
+\r
+ }\r
+\r
+ // Paste text without formatting\r
+ private void pasteWithoutFormattingClicked() {\r
+ logger.log(logger.EXTREME, "Paste without format clipped");\r
+ QClipboard clipboard = QApplication.clipboard();\r
+ QMimeData mime = clipboard.mimeData();\r
+ if (!mime.hasText())\r
+ return;\r
+ String text = mime.text();\r
+ clipboard.setText(text);\r
+ browser.page().triggerAction(WebAction.Paste);\r
+ QApplication.clipboard().setMimeData(mime);\r
+ browser.setFocus();\r
+\r
+ }\r
+ \r
+ // insert date/time\r
+ @SuppressWarnings("unused")\r
+ private void insertDateTime() {\r
+ String fmt = Global.getDateFormat() + " " + Global.getTimeFormat();\r
+ String dateTimeFormat = new String(fmt);\r
+ SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);\r
+ Calendar cal = Calendar.getInstance();\r
+ \r
+ browser.page().mainFrame().evaluateJavaScript(\r
+ "document.execCommand('insertHtml', false, '"+simple.format(cal.getTime())+"');");\r
+ \r
+ browser.setFocus();\r
+\r
+ }\r
+\r
+ // Listener when Left is clicked\r
+ @SuppressWarnings("unused")\r
+ private void justifyLeftClicked() {\r
+ browser.page().mainFrame().evaluateJavaScript(\r
+ "document.execCommand('JustifyLeft', false, '');");\r
+ browser.setFocus();\r
+ }\r
+\r
+ // Listener when Center is clicked\r
+ @SuppressWarnings("unused")\r
+ private void justifyCenterClicked() {\r
+ browser.page().mainFrame().evaluateJavaScript(\r
+ "document.execCommand('JustifyCenter', false, '');");\r
+ browser.setFocus();\r
+ }\r
+\r
+ // Listener when Left is clicked\r
+ @SuppressWarnings("unused")\r
+ private void justifyRightClicked() {\r
+ browser.page().mainFrame().evaluateJavaScript(\r
+ "document.execCommand('JustifyRight', false, '');");\r
+ browser.setFocus();\r
+ }\r
+\r
+ // Listener when HLINE is clicked\r
+ @SuppressWarnings("unused")\r
+ private void hlineClicked() {\r
+ browser.page().mainFrame().evaluateJavaScript(\r
+ "document.execCommand('insertHorizontalRule', false, '');");\r
+ browser.setFocus();\r
+ }\r
+\r
+ // Listener when outdent is clicked\r
+ private void outdentClicked() {\r
+ browser.page().mainFrame().evaluateJavaScript(\r
+ "document.execCommand('outdent', false, '');");\r
+ browser.setFocus();\r
+ }\r
+\r
+ // Listener when a bullet list is clicked\r
+ @SuppressWarnings("unused")\r
+ private void bulletListClicked() {\r
+ browser.page().mainFrame().evaluateJavaScript(\r
+ "document.execCommand('InsertUnorderedList', false, '');");\r
+ browser.setFocus();\r
+ }\r
+\r
+ // Listener when a bullet list is clicked\r
+ @SuppressWarnings("unused")\r
+ private void numberListClicked() {\r
+ browser.page().mainFrame().evaluateJavaScript(\r
+ "document.execCommand('InsertOrderedList', false, '');");\r
+ browser.setFocus();\r
+ }\r
+\r
+ // Listener when indent is clicked\r
+ private void indentClicked() {\r
+ browser.page().mainFrame().evaluateJavaScript(\r
+ "document.execCommand('indent', false, '');");\r
+ browser.setFocus();\r
+ }\r
+\r
+ // Listener when the font name is changed\r
+ @SuppressWarnings("unused")\r
+ private void fontChanged(String font) {\r
+ browser.page().mainFrame().evaluateJavaScript(\r
+ "document.execCommand('fontName',false,'" + font + "');");\r
+ browser.setFocus();\r
+ }\r
+\r
+ // Listener when a font size is changed\r
+ @SuppressWarnings("unused")\r
+ private void fontSizeChanged(String font) {\r
+ String text = browser.selectedText();\r
+ if (text.trim().equalsIgnoreCase(""))\r
+ return;\r
+\r
+ String selectedText = browser.selectedText();\r
+ String url = "<span style=\"font-size:" +font +"pt; \">"+selectedText +"</a>";\r
+ String script = "document.execCommand('insertHtml', false, '"+url+"');";\r
+ browser.page().mainFrame().evaluateJavaScript(script);\r
+/* browser.page().mainFrame().evaluateJavaScript(\r
+ "document.execCommand('fontSize',false,'"\r
+ + font + "');");\r
+*/\r
+ browser.setFocus();\r
+ }\r
+\r
+ // Load the font combo box based upon the font selected\r
+ private void loadFontSize(String name) { \r
+ QFontDatabase db = new QFontDatabase(); \r
+ fontSize.clear();\r
+ List<Integer> points = db.pointSizes(name); \r
+ for (int i=0; i<points.size(); i++) { \r
+ fontSize.addItem(points.get(i).toString()); \r
+ }\r
+ /*\r
+ fontSize.addItem("x-small");\r
+ fontSize.addItem("small");\r
+ fontSize.addItem("medium");\r
+ fontSize.addItem("large");\r
+ fontSize.addItem("x-large");\r
+ fontSize.addItem("xx-large");\r
+ fontSize.addItem("xxx-large");\r
+ */\r
+ }\r
+\r
+ // Listener when a font size is changed\r
+ @SuppressWarnings("unused")\r
+ private void fontColorClicked() {\r
+// QColorDialog dialog = new QColorDialog();\r
+// QColor color = QColorDialog.getColor();\r
+ QColor color = fontColorMenu.getColor();\r
+ if (color.isValid())\r
+ browser.page().mainFrame().evaluateJavaScript(\r
+ "document.execCommand('foreColor',false,'" + color.name()\r
+ + "');");\r
+ browser.setFocus();\r
+ }\r
+\r
+ // Listener for when a background color change is requested\r
+ @SuppressWarnings("unused")\r
+ private void fontHilightClicked() {\r
+// QColorDialog dialog = new QColorDialog();\r
+// QColor color = QColorDialog.getColor();\r
+ QColor color = fontHilightColorMenu.getColor();\r
+ if (color.isValid())\r
+ browser.page().mainFrame().evaluateJavaScript(\r
+ "document.execCommand('backColor',false,'" + color.name()\r
+ + "');");\r
+ browser.setFocus();\r
+ }\r
+ \r
+ // Listener for when a background color change is requested\r
+ @SuppressWarnings("unused")\r
+ private void superscriptClicked() {\r
+ browser.page().mainFrame().evaluateJavaScript(\r
+ "document.execCommand('superscript');");\r
+ browser.setFocus();\r
+ }\r
+ \r
+ // Listener for when a background color change is requested\r
+ @SuppressWarnings("unused")\r
+ private void subscriptClicked() {\r
+ browser.page().mainFrame().evaluateJavaScript(\r
+ "document.execCommand('subscript');");\r
+ browser.setFocus();\r
+ }\r
+ // Insert a to-do checkbox\r
+ @SuppressWarnings("unused")\r
+ private void todoClicked() {\r
+ FileNameMap fileNameMap = URLConnection.getFileNameMap();\r
+ String script_start = new String(\r
+ "document.execCommand('insertHtml', false, '");\r
+ String script_end = new String("');");\r
+ String todo = new String(\r
+ "<input TYPE=\"CHECKBOX\" value=\"false\" onClick=\"value=checked; window.jambi.contentChanged(); \" />");\r
+ browser.page().mainFrame().evaluateJavaScript(\r
+ script_start + todo + script_end);\r
+ browser.setFocus();\r
+ }\r
+\r
+ // Encrypt the selected text\r
+ @SuppressWarnings("unused")\r
+ private void encryptText() {\r
+ String text = browser.selectedText();\r
+ if (text.trim().equalsIgnoreCase(""))\r
+ return;\r
+\r
+ EnCryptDialog dialog = new EnCryptDialog();\r
+ dialog.exec();\r
+ if (!dialog.okPressed()) {\r
+ return;\r
+ }\r
+\r
+ EnCrypt crypt = new EnCrypt();\r
+ String encrypted = crypt.encrypt(text, dialog.getPassword().trim(), 64);\r
+\r
+ if (encrypted.trim().equals("")) {\r
+ QMessageBox.information(this, "Error", "Error Encrypting String");\r
+ return;\r
+ }\r
+ StringBuffer imgPath = new StringBuffer(Global.getDirectoryPath());\r
+ for (int i = 0; i < imgPath.length(); i++)\r
+ if (imgPath.charAt(i) == '\\')\r
+ imgPath.setCharAt(i, '/');\r
+ StringBuffer buffer = new StringBuffer(encrypted.length() + 100);\r
+ buffer.append("<img en-tag=\"en-crypt\" cipher=\"RC2\" hint=\""\r
+ + dialog.getHint().replace("'","\\'") + "\" length=\"64\" ");\r
+ buffer.append("contentEditable=\"false\" alt=\"");\r
+ buffer.append(encrypted);\r
+ buffer.append("\" src=\"" + imgPath.toString()\r
+ + "images/encrypt.png\" ");\r
+ Global.cryptCounter++;\r
+ buffer.append(" id=\"crypt"+Global.cryptCounter.toString() +"\"");\r
+ buffer.append(" onMouseOver=\"style.cursor=\\'hand\\'\"");\r
+ buffer.append(" onClick=\"window.jambi.decryptText(\\'crypt"+Global.cryptCounter.toString() \r
+ +"\\', \\'"+encrypted+"\\', \\'"+dialog.getHint().replace("'", "\\&apos;")+"\\');\"");\r
+ buffer.append("style=\"display:block\" />");\r
+\r
+ String script_start = new String(\r
+ "document.execCommand('insertHtml', false, '");\r
+ String script_end = new String("');");\r
+ browser.page().mainFrame().evaluateJavaScript(\r
+ script_start + buffer.toString() + script_end);\r
+ }\r
+\r
+ \r
+ // Insert a hyperlink\r
+ public void insertLink() {\r
+ logger.log(logger.EXTREME, "Inserting link");\r
+ String text = browser.selectedText();\r
+ if (text.trim().equalsIgnoreCase(""))\r
+ return;\r
+\r
+ InsertLinkDialog dialog = new InsertLinkDialog();\r
+ if (currentHyperlink != null && currentHyperlink != "") {\r
+ dialog.setUrl(currentHyperlink);\r
+ }\r
+ dialog.exec();\r
+ if (!dialog.okPressed()) {\r
+ logger.log(logger.EXTREME, "Insert link canceled");\r
+ return;\r
+ }\r
+ if (browser.insertLinkAction.text().equalsIgnoreCase("Insert Hyperlink")) {\r
+ String selectedText = browser.selectedText();\r
+ logger.log(logger.EXTREME, "Inserting link on text "+selectedText);\r
+ logger.log(logger.EXTREME, "URL Link " +dialog.getUrl().trim());\r
+ String url = "<a href=\"" +dialog.getUrl().trim()+"\" >"+selectedText +"</a>";\r
+ String script = "document.execCommand('insertHtml', false, '"+url+"');";\r
+ browser.page().mainFrame().evaluateJavaScript(script);\r
+ return;\r
+ } else {\r
+ String js = new String( "function getCursorPos() {"\r
+ +"var cursorPos;"\r
+ +"if (window.getSelection) {"\r
+ +" var selObj = window.getSelection();"\r
+ +" var selRange = selObj.getRangeAt(0);"\r
+ +" var workingNode = window.getSelection().anchorNode.parentNode;"\r
+ +" while(workingNode != null) { " \r
+ +" if (workingNode.nodeName.toLowerCase()=='a') workingNode.setAttribute('href','" +dialog.getUrl() +"');"\r
+ +" workingNode = workingNode.parentNode;"\r
+ +" }"\r
+ +"}"\r
+ +"} getCursorPos();");\r
+ browser.page().mainFrame().evaluateJavaScript(js);\r
+ contentChanged();\r
+ }\r
+ \r
+ }\r
+ \r
+ // Insert a table\r
+ public void insertTable() {\r
+ TableDialog dialog = new TableDialog();\r
+ dialog.exec();\r
+ if (!dialog.okPressed()) {\r
+ return;\r
+ }\r
+ \r
+ int cols = dialog.getCols();\r
+ int rows = dialog.getRows();\r
+ int width = dialog.getWidth();\r
+ boolean percent = dialog.isPercent();\r
+ \r
+ String newHTML = "<table border=\"1\" width=\"" +new Integer(width).toString();\r
+ if (percent)\r
+ newHTML = newHTML +"%";\r
+ newHTML = newHTML + "\"><tbody>";\r
+\r
+ for (int i=0; i<rows; i++) {\r
+ newHTML = newHTML +"<tr>";\r
+ for (int j=0; j<cols; j++) {\r
+ newHTML = newHTML +"<td> </td>";\r
+ }\r
+ newHTML = newHTML +"</tr>";\r
+ }\r
+ newHTML = newHTML+"</tbody></table>"; \r
+ \r
+ String script = "document.execCommand('insertHtml', false, '"+newHTML+"');";\r
+ browser.page().mainFrame().evaluateJavaScript(script);\r
+ }\r
+ \r
+ \r
+ // Text content changed\r
+ @SuppressWarnings("unused")\r
+ private void selectionChanged() {\r
+ browser.encryptAction.setEnabled(true);\r
+ browser.insertLinkAction.setEnabled(true);\r
+ String scriptStart = "var selection_text = (window.getSelection()).toString();"\r
+ + "var range = (window.getSelection()).getRangeAt(0);"\r
+ + "var parent_html = range.commonAncestorContainer.innerHTML;"\r
+ + "if (parent_html == undefined) {window.jambi.saveSelectedText(selection_text); return;}"\r
+ + "var first_text = range.startContainer.nodeValue.substr(range.startOffset);"\r
+ + "var last_text = (range.endContainer.nodeValue).substring(0,range.endOffset);"\r
+ + "var start = parent_html.indexOf(first_text);"\r
+ + "var end = parent_html.indexOf(last_text,start+1)+last_text.length;"\r
+ + "var value = parent_html.substring(start,end);"\r
+ + "window.jambi.saveSelectedText(value);" ;\r
+ browser.page().mainFrame().evaluateJavaScript(scriptStart);\r
+\r
+ }\r
+\r
+ public void saveSelectedText(String text) {\r
+ boolean enabled = true;\r
+ if (text.trim().length() == 0)\r
+ enabled=false;\r
+ if (text.indexOf("en-tag=\"en-crypt\"") >= 0)\r
+ enabled=false;\r
+ if (text.indexOf("<img en-tag=\"en-media\"") >= 0)\r
+ enabled=false;\r
+ if (text.indexOf("<a en-tag=\"en-media\"") >= 0)\r
+ enabled=false;\r
+ if (text.indexOf("<input ") >= 0)\r
+ enabled=false;\r
+ \r
+ browser.encryptAction.setEnabled(enabled);\r
+ browser.insertLinkAction.setEnabled(enabled);\r
+// selectedText = text;\r
+ }\r
+\r
+ // Decrypt clicked text\r
+ public void decryptText(String id, String text, String hint) {\r
+ EnCrypt crypt = new EnCrypt();\r
+ String plainText = null;\r
+ Calendar currentTime = new GregorianCalendar();\r
+ Long l = new Long(currentTime.getTimeInMillis());\r
+ String slot = new String(Long.toString(l));\r
+ \r
+ // First, try to decrypt with any keys we already have\r
+ for (int i=0; i<Global.passwordRemember.size(); i++) {\r
+ plainText = crypt.decrypt(text, Global.passwordRemember.get(i), 64);\r
+ if (plainText != null) {\r
+ slot = new String(Long.toString(l));\r
+ Global.passwordSafe.put(slot, Global.passwordRemember.get(i));\r
+ removeEncryption(id, plainText, false, slot); \r
+ return;\r
+ }\r
+ }\r
+ \r
+ \r
+ EnDecryptDialog dialog = new EnDecryptDialog();\r
+ dialog.setHint(hint);\r
+ while (plainText == null || !dialog.okPressed()) {\r
+ dialog.exec();\r
+ if (!dialog.okPressed()) {\r
+ return;\r
+ }\r
+ plainText = crypt.decrypt(text, dialog.getPassword().trim(), 64);\r
+ if (plainText == null) {\r
+ QMessageBox.warning(this, "Incorrect Password", "The password entered is not correct");\r
+ }\r
+ }\r
+ Global.passwordSafe.put(slot, dialog.getPassword());\r
+ removeEncryption(id, plainText, dialog.permanentlyDecrypt(), slot);\r
+ if (dialog.rememberPassword())\r
+ Global.passwordRemember.add(dialog.getPassword());\r
+\r
+ }\r
+\r
+ // Get the editor tag line\r
+ public TagLineEdit getTagLine() {\r
+ return tagEdit;\r
+ }\r
+\r
+ // Modify a note's tags\r
+ @SuppressWarnings("unused")\r
+ private void modifyTags() {\r
+ TagAssign tagWindow = new TagAssign(allTags, currentTags);\r
+ tagWindow.exec();\r
+ if (tagWindow.okClicked()) {\r
+ currentTags.clear();\r
+ StringBuffer tagDisplay = new StringBuffer();\r
+\r
+ List<QListWidgetItem> newTags = tagWindow.getTagList()\r
+ .selectedItems();\r
+ for (int i = 0; i < newTags.size(); i++) {\r
+ currentTags.add(newTags.get(i).text());\r
+ tagDisplay.append(newTags.get(i).text());\r
+ if (i < newTags.size() - 1) {\r
+ tagDisplay.append(Global.tagDelimeter + " ");\r
+ }\r
+ }\r
+ tagEdit.setText(tagDisplay.toString());\r
+ noteSignal.tagsChanged.emit(currentNote.getGuid(), currentTags);\r
+ }\r
+ }\r
+\r
+ // Tag line has been modified by typing text\r
+ @SuppressWarnings("unused")\r
+ private void modifyTagsTyping() {\r
+\r
+ String newTags = tagEdit.text();\r
+ List<String> test = tagEdit.tagCompleter.getTagList();\r
+ if (newTags.equalsIgnoreCase(saveTagList))\r
+ return;\r
+\r
+ // We know something has changed...\r
+ String oldTagArray[] = saveTagList.split(Global.tagDelimeter);\r
+ String newTagArray[] = newTags.split(Global.tagDelimeter);\r
+\r
+ List<String> newTagList = new ArrayList<String>();\r
+ List<String> oldTagList = new ArrayList<String>();\r
+\r
+ for (int i = 0; i < oldTagArray.length; i++)\r
+ if (!oldTagArray[i].trim().equals(""))\r
+ oldTagList.add(oldTagArray[i]);\r
+ for (int i = 0; i < newTagArray.length; i++)\r
+ if (!newTagArray[i].trim().equals(""))\r
+ newTagList.add(newTagArray[i]);\r
+\r
+ // We now have lists of the new & old. Remove duplicates. If all\r
+ // are removed from both then nothing has really changed\r
+ for (int i = newTagList.size() - 1; i >= 0; i--) {\r
+ String nTag = newTagList.get(i);\r
+ for (int j = oldTagList.size() - 1; j >= 0; j--) {\r
+ String oTag = oldTagList.get(j);\r
+ if (oTag.equalsIgnoreCase(nTag)) {\r
+ oldTagList.remove(j);\r
+ newTagList.remove(i);\r
+ j = -1;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (oldTagList.size() != 0 || newTagList.size() != 0) {\r
+ currentTags.clear();\r
+ for (int i = 0; i < newTagArray.length; i++)\r
+ if (!newTagArray[i].trim().equals(""))\r
+ currentTags.add(newTagArray[i].trim());\r
+\r
+ noteSignal.tagsChanged.emit(currentNote.getGuid(), currentTags);\r
+ }\r
+\r
+ }\r
+\r
+ // Tab button was pressed\r
+ public void tabPressed() {\r
+ if (!insideList) {\r
+ String script_start = new String(\r
+ "document.execCommand('insertHtml', false, ' ');");\r
+ browser.page().mainFrame().evaluateJavaScript(script_start);\r
+ } else \r
+ indentClicked();\r
+ }\r
+ \r
+ public void backtabPressed() {\r
+ if (insideList)\r
+ outdentClicked();\r
+ }\r
+ \r
+ public void setInsideList() {\r
+ insideList = true;\r
+ }\r
+ \r
+ // The title has been edited\r
+ @SuppressWarnings("unused")\r
+ private void titleEdited() {\r
+ // If we don't have a good note, or if the current title\r
+ // matches the old title then we don't need to do anything\r
+ if (currentNote == null)\r
+ return;\r
+ if (currentNote.getTitle().trim().equals(titleLabel.text().trim()))\r
+ return;\r
+ \r
+ // If we have a real change, we need to save it.\r
+ noteSignal.titleChanged.emit(currentNote.getGuid(), titleLabel.text());\r
+ currentNote.setTitle(titleLabel.text());\r
+ saveNoteTitle = titleLabel.text();\r
+ checkNoteTitle();\r
+ }\r
+\r
+ // Set the list of note tags\r
+ public void setAllTags(List<Tag> l) {\r
+ allTags = l;\r
+ tagEdit.setTagList(l);\r
+ }\r
+\r
+ // Setter for the current tags\r
+ public void setCurrentTags(List<String> s) {\r
+ currentTags = s;\r
+ }\r
+\r
+ // Save the list of notebooks\r
+ public void setNotebookList(List<Notebook> n) {\r
+ notebookList = n;\r
+ loadNotebookList();\r
+ }\r
+\r
+ // Load the notebook list and select the current notebook\r
+ private void loadNotebookList() {\r
+ if (notebookBox.count() != 0)\r
+ notebookBox.clear();\r
+ if (notebookList == null)\r
+ return;\r
+\r
+ for (int i = 0; i < notebookList.size(); i++) {\r
+ notebookBox.addItem(notebookList.get(i).getName());\r
+ if (currentNote != null) {\r
+ if (currentNote.getNotebookGuid().equals(\r
+ notebookList.get(i).getGuid())) {\r
+ notebookBox.setCurrentIndex(i);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ // Get the contents of the editor\r
+ public String getContent() {\r
+ return browser.page().currentFrame().toHtml();\r
+ }\r
+\r
+ // The note contents have changed\r
+ public void contentChanged() {\r
+ String content = getContent();\r
+ checkNoteTitle();\r
+ noteSignal.noteChanged.emit(currentNote.getGuid(), content); \r
+ \r
+ \r
+// noteSignal.noteChanged.emit(currentNote.getGuid(), unicode);\r
+ }\r
+\r
+ // The notebook selection has changed\r
+ @SuppressWarnings("unused")\r
+ private void notebookChanged() {\r
+ boolean changed = false;\r
+ String n = notebookBox.currentText();\r
+ for (int i = 0; i < notebookList.size(); i++) {\r
+ if (n.equals(notebookList.get(i).getName())) {\r
+ if (!notebookList.get(i).getGuid().equals(currentNote.getNotebookGuid())) {\r
+ currentNote.setNotebookGuid(notebookList.get(i).getGuid());\r
+ changed = true;\r
+ }\r
+ i = notebookList.size();\r
+ }\r
+ }\r
+ \r
+ // If the notebook changed, signal the update\r
+ if (changed)\r
+ noteSignal.notebookChanged.emit(currentNote.getGuid(), currentNote\r
+ .getNotebookGuid());\r
+ }\r
+\r
+ // Check the note title\r
+ private void checkNoteTitle() {\r
+ String text = browser.page().currentFrame().toPlainText();\r
+ if (saveNoteTitle.trim().equals("")) {\r
+ int newLine = text.indexOf("\n");\r
+ if (newLine > 0) {\r
+ text = text.substring(0, newLine);\r
+ if (text.trim().equals(""))\r
+ text = "Untitled Note";\r
+ titleLabel.setText(text);\r
+ } else {\r
+ if (text.length() > 20)\r
+ titleLabel.setText(text.substring(0, 20));\r
+ else {\r
+ if (text.trim().equals(""))\r
+ titleLabel.setText("Untitled Note");\r
+ else\r
+ titleLabel.setText(text);\r
+ }\r
+ }\r
+ noteSignal.titleChanged.emit(currentNote.getGuid(), titleLabel\r
+ .text());\r
+ }\r
+ }\r
+\r
+ // Return the note contents so we can email them\r
+ public String getContentsToEmail() {\r
+ return browser.page().currentFrame().toPlainText().trim();\r
+ /*\r
+ * int body = browser.page().currentFrame().toHtml().indexOf("<body>");\r
+ * String temp = browser.page().currentFrame().toHtml(); if (body == -1)\r
+ * temp = "<html><body><b>Test</b></body></html>"; else temp =\r
+ * "<html>"+temp.substring(body); return temp; // return\r
+ * urlEncode(browser.page().currentFrame().toHtml());\r
+ */\r
+ }\r
+\r
+ // Insert an image into the editor\r
+ private void insertImage(QMimeData mime) {\r
+ logger.log(logger.EXTREME, "Entering insertImage");\r
+ QImage img = (QImage) mime.imageData();\r
+ String script_start = new String(\r
+ "document.execCommand('insertHTML', false, '");\r
+ String script_end = new String("');");\r
+\r
+ long now = new Date().getTime();\r
+ String path = Global.getDirectoryPath() + "res/"\r
+ + (new Long(now).toString()) + ".jpg";\r
+\r
+ // This block is just a hack to make sure we wait at least 1ms so we\r
+ // don't\r
+ // have collisions on image names\r
+ long i = new Date().getTime();\r
+ while (now == i)\r
+ i = new Date().getTime();\r
+\r
+ // Open the file & write the data\r
+ QFile tfile = new QFile(path);\r
+ tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));\r
+ img.save(tfile);\r
+ tfile.close();\r
+ \r
+ Resource newRes = createResource(QUrl.fromLocalFile(path).toString(), 0, "image/jpeg", false);\r
+ if (newRes == null)\r
+ return;\r
+ currentNote.getResources().add(newRes);\r
+\r
+ // do the actual insert into the note\r
+ StringBuffer buffer = new StringBuffer(100);\r
+ buffer.append("<img src=\"");\r
+ buffer.append(tfile.fileName());\r
+ buffer.append("\" en-tag=en-media type=\"image/jpeg\""\r
+ +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""\r
+ +" guid=\"" +newRes.getGuid() +"\""\r
+ +" onContextMenu=\"window.jambi.imageContextMenu('" +tfile.fileName() +"');\""\r
+ + " />");\r
+ browser.page().mainFrame().evaluateJavaScript(\r
+ script_start + buffer + script_end);\r
+\r
+ return;\r
+ }\r
+\r
+ // Handle URLs that are trying to be pasted\r
+ public void handleUrls(QMimeData mime) {\r
+ logger.log(logger.EXTREME, "Starting handleUrls");\r
+ FileNameMap fileNameMap = URLConnection.getFileNameMap();\r
+\r
+ List<QUrl> urlList = mime.urls();\r
+ String url = new String();\r
+ String script_start = new String(\r
+ "document.execCommand('createLink', false, '");\r
+ String script_end = new String("');");\r
+\r
+ for (int i = 0; i < urlList.size(); i++) {\r
+ url = urlList.get(i).toString();\r
+ // Find out what type of file we have\r
+ String mimeType = fileNameMap.getContentTypeFor(url);\r
+\r
+ // If null returned, we need to guess at the file type\r
+ if (mimeType == null)\r
+ mimeType = "application/"\r
+ + url.substring(url.lastIndexOf(".") + 1);\r
+\r
+ // Check if we have an image or some other type of file\r
+ if (url.substring(0, 5).equalsIgnoreCase("file:")\r
+ && mimeType.substring(0, 5).equalsIgnoreCase("image")) {\r
+ handleLocalImageURLPaste(mime, mimeType);\r
+ return;\r
+ }\r
+ String[] type = mimeType.split("/");\r
+ boolean valid = validAttachment(type[1]);\r
+ boolean smallEnough = checkFileAttachmentSize(url);\r
+ if (smallEnough && valid\r
+ && url.substring(0, 5).equalsIgnoreCase("file:")\r
+ && !mimeType.substring(0, 5).equalsIgnoreCase("image")) {\r
+ handleLocalAttachment(mime, mimeType);\r
+ return;\r
+ }\r
+ browser.page().mainFrame().evaluateJavaScript(\r
+ script_start + url + script_end);\r
+ }\r
+ return;\r
+ }\r
+\r
+ // If a URL being pasted is an image URL, then attach the image\r
+ private void handleLocalImageURLPaste(QMimeData mime, String mimeType) {\r
+ List<QUrl> urlList = mime.urls();\r
+ String url = new String();\r
+ String script_start_image = new String(\r
+ "document.execCommand('insertHtml', false, '");\r
+ String script_end = new String("');");\r
+ StringBuffer buffer;\r
+\r
+ // Copy the image over into the resource directory and create a new resource \r
+ // record for each url pasted\r
+ for (int i = 0; i < urlList.size(); i++) {\r
+ url = urlList.get(i).toString();\r
+\r
+ Resource newRes = createResource(url, i, mimeType, false);\r
+ if (newRes == null)\r
+ return;\r
+ currentNote.getResources().add(newRes);\r
+ buffer = new StringBuffer(100);\r
+ \r
+ // Open the file & write the data\r
+ String fileName = Global.getDirectoryPath()+"res/"+newRes.getGuid();\r
+ QFile tfile = new QFile(fileName);\r
+ tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));\r
+ tfile.write(newRes.getData().getBody());\r
+ tfile.close();\r
+ fileName = fileName.replace('\\', '/');\r
+ buffer.append(script_start_image);\r
+ buffer.append("<img src=\"" +fileName);\r
+// if (mimeType.equalsIgnoreCase("image/jpg"))\r
+// mimeType = "image/jpeg";\r
+ buffer.append("\" en-tag=\"en-media\" type=\"" + mimeType +"\""\r
+ +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""\r
+ +" guid=\"" +newRes.getGuid() +"\""\r
+ +" onContextMenu=\"window.jambi.imageContextMenu('" +tfile.fileName() +"');\""\r
+ + " />");\r
+ buffer.append(script_end);\r
+ browser.page().mainFrame().evaluateJavaScript(buffer.toString());\r
+ }\r
+ return;\r
+ }\r
+ \r
+\r
+ // If a URL being pasted is a local file URL, then attach the file\r
+ private void handleLocalAttachment(QMimeData mime, String mimeType) {\r
+ logger.log(logger.EXTREME, "Attaching local file");\r
+ List<QUrl> urlList = mime.urls();\r
+ String script_start = new String(\r
+ "document.execCommand('insertHtml', false, '");\r
+ String script_end = new String("');");\r
+ StringBuffer buffer;\r
+\r
+ for (int i = 0; i < urlList.size(); i++) {\r
+ buffer = new StringBuffer(100);\r
+ String url = urlList.get(i).toString();\r
+\r
+ // Start building the HTML\r
+ String[] type = mimeType.split("/");\r
+ String icon = findIcon(type[1]);\r
+ if (icon.equals("attachment.png"))\r
+ icon = findIcon(type[0]);\r
+ if (icon.equals("attachment.png"))\r
+ icon = findIcon(url.substring(url.lastIndexOf(".")+1));\r
+ StringBuffer imageBuffer = new StringBuffer();\r
+ String whichOS = System.getProperty("os.name");\r
+ if (whichOS.contains("Windows")) \r
+ imageBuffer.append("file:///" + Global.getDirectoryPath()\r
+ + "images/" + icon);\r
+ else\r
+ imageBuffer.append("file://" + Global.getDirectoryPath()\r
+ + "images/" + icon);\r
+ // Fix stupid Windows file separation characters\r
+ if (whichOS.contains("Windows")) {\r
+ for (int z = imageBuffer.indexOf("\\"); z > 0; z = imageBuffer\r
+ .indexOf("\\")) {\r
+ int w = imageBuffer.indexOf("\\");\r
+ imageBuffer.replace(w, w + 1, "/");\r
+ }\r
+\r
+ }\r
+ logger.log(logger.EXTREME, "Creating resource ");\r
+ Resource newRes = createResource(url, i, mimeType, true);\r
+ if (newRes == null)\r
+ return;\r
+ logger.log(logger.EXTREME, "New resource size: " +newRes.getData().getSize());\r
+ currentNote.getResources().add(newRes);\r
+ \r
+ String fileName = newRes.getGuid() + Global.attachmentNameDelimeter+newRes.getAttributes().getFileName();\r
+ // If we have a PDF, we need to setup the preview.\r
+ if (icon.equalsIgnoreCase("pdf.png") && Global.pdfPreview()) {\r
+ logger.log(logger.EXTREME, "Setting up PDF preview");\r
+ if (newRes.getAttributes() != null && \r
+ newRes.getAttributes().getFileName() != null && \r
+ !newRes.getAttributes().getFileName().trim().equals(""))\r
+ fileName = newRes.getGuid()+Global.attachmentNameDelimeter+\r
+ newRes.getAttributes().getFileName();\r
+ else\r
+ fileName = newRes.getGuid()+".pdf";\r
+ QFile file = new QFile(Global.getDirectoryPath() +"res/"+fileName);\r
+ QFile.OpenMode mode = new QFile.OpenMode();\r
+ mode.set(QFile.OpenModeFlag.WriteOnly);\r
+ file.open(mode);\r
+ QDataStream out = new QDataStream(file);\r
+// Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(newRes.getGuid(), true);\r
+ QByteArray binData = new QByteArray(newRes.getData().getBody());\r
+// resBinary = null;\r
+ out.writeBytes(binData.toByteArray());\r
+ file.close();\r
+\r
+ PDFPreview pdfPreview = new PDFPreview();\r
+ if (pdfPreview.setupPreview(Global.currentDir+"res/"+fileName, "pdf",0));\r
+ imageBuffer = new StringBuffer(file.fileName()+".png");\r
+ }\r
+ \r
+ logger.log(logger.EXTREME, "Generating link tags");\r
+ buffer.append("<a en-tag=\"en-media\" guid=\"" +newRes.getGuid()+"\" ");\r
+ buffer.append(" onContextMenu=\"window.jambi.imageContextMenu('" +Global.getDirectoryPath() +"res/"+fileName +"');\" ");\r
+ buffer.append("type=\"" + mimeType + "\" href=\"nnres://" + fileName +"\" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\" >");\r
+ buffer.append("<img src=\"" + imageBuffer.toString()+"\" title=\"" +newRes.getAttributes().getFileName());\r
+ buffer.append("\"></img>");\r
+ buffer.append("</a>");\r
+ browser.page().mainFrame().evaluateJavaScript(\r
+ script_start + buffer.toString() + script_end);\r
+ }\r
+ return;\r
+ }\r
+ private Resource createResource(String url, int sequence, String mime, boolean attachment) {\r
+ logger.log(logger.EXTREME, "Inside create resource");\r
+ QFile resourceFile;\r
+ url = new QUrl(url).toLocalFile();\r
+ url = url.replace("/", File.separator);\r
+ resourceFile = new QFile(url); \r
+ resourceFile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly));\r
+ byte[] fileData = resourceFile.readAll().toByteArray();\r
+ resourceFile.close();\r
+ if (fileData.length == 0)\r
+ return null;\r
+ MessageDigest md;\r
+ try {\r
+ md = MessageDigest.getInstance("MD5");\r
+ md.update(fileData);\r
+ byte[] hash = md.digest();\r
+ \r
+ Resource r = new Resource();\r
+ Calendar time = new GregorianCalendar();\r
+ long prevTime = time.getTimeInMillis();\r
+ while (prevTime == time.getTimeInMillis()) {\r
+ time = new GregorianCalendar();\r
+ }\r
+ r.setGuid(time.getTimeInMillis()+new Integer(sequence).toString());\r
+ r.setNoteGuid(currentNote.getGuid());\r
+ r.setMime(mime);\r
+ r.setActive(true);\r
+ r.setUpdateSequenceNum(0);\r
+ r.setWidth((short) 0);\r
+ r.setHeight((short) 0);\r
+ r.setDuration((short) 0);\r
+ \r
+ Data d = new Data();\r
+ d.setBody(fileData);\r
+ d.setBodyIsSet(true);\r
+ d.setBodyHash(hash);\r
+ d.setBodyHashIsSet(true);\r
+ r.setData(d);\r
+ d.setSize(fileData.length);\r
+ \r
+ int fileNamePos = url.lastIndexOf(File.separator);\r
+ if (fileNamePos == -1)\r
+ fileNamePos = url.lastIndexOf("/");\r
+ String fileName = url.substring(fileNamePos+1);\r
+ ResourceAttributes a = new ResourceAttributes();\r
+ a.setAltitude(0);\r
+ a.setAltitudeIsSet(false);\r
+ a.setLongitude(0);\r
+ a.setLongitudeIsSet(false);\r
+ a.setLatitude(0);\r
+ a.setLatitudeIsSet(false);\r
+ a.setCameraMake("");\r
+ a.setCameraMakeIsSet(false);\r
+ a.setCameraModel("");\r
+ a.setCameraModelIsSet(false);\r
+ a.setAttachment(attachment);\r
+ a.setAttachmentIsSet(true);\r
+ a.setClientWillIndex(false);\r
+ a.setClientWillIndexIsSet(true);\r
+ a.setRecoType("");\r
+ a.setRecoTypeIsSet(false);\r
+ a.setSourceURL(url);\r
+ a.setSourceURLIsSet(true);\r
+ a.setTimestamp(0);\r
+ a.setTimestampIsSet(false);\r
+ a.setFileName(fileName);\r
+ a.setFileNameIsSet(true);\r
+ r.setAttributes(a);\r
+ \r
+ conn.getNoteTable().noteResourceTable.saveNoteResource(r, true);\r
+ return r;\r
+ } catch (NoSuchAlgorithmException e1) {\r
+ e1.printStackTrace();\r
+ }\r
+ return null;\r
+ }\r
+ \r
+\r
+ // find the appropriate icon for an attachment\r
+ private String findIcon(String appl) {\r
+ appl = appl.toLowerCase();\r
+ File f = new File(Global.getDirectoryPath()+"images"+File.separator +appl +".png");\r
+ if (f.exists())\r
+ return appl+".png";\r
+ return "attachment.png";\r
+ }\r
+\r
+ // Check if the account supports this type of attachment\r
+ private boolean validAttachment(String type) {\r
+ if (Global.isPremium())\r
+ return true;\r
+ if (type.equalsIgnoreCase("JPG"))\r
+ return true;\r
+ if (type.equalsIgnoreCase("PNG"))\r
+ return true;\r
+ if (type.equalsIgnoreCase("GIF"))\r
+ return true;\r
+ if (type.equalsIgnoreCase("MP3"))\r
+ return true;\r
+ if (type.equalsIgnoreCase("WAV"))\r
+ return true;\r
+ if (type.equalsIgnoreCase("AMR"))\r
+ return true;\r
+ if (type.equalsIgnoreCase("PDF"))\r
+ return true;\r
+ String error = "Non-premium accounts can only attach JPG, PNG, GIF, MP3, WAV, AMR, or PDF files.";\r
+ QMessageBox.information(this, "Non-Premium Account", error);\r
+\r
+ return false;\r
+ }\r
+\r
+ // Check the file attachment to be sure it isn't over 25 mb\r
+ private boolean checkFileAttachmentSize(String url) {\r
+ String fileName = url.substring(8);\r
+ QFile resourceFile = new QFile(fileName);\r
+ resourceFile.open(new QIODevice.OpenMode(\r
+ QIODevice.OpenModeFlag.ReadOnly));\r
+ long size = resourceFile.size();\r
+ resourceFile.close();\r
+ size = size / 1024 / 1024;\r
+ if (size < 50 && Global.isPremium())\r
+ return true;\r
+ if (size < 25)\r
+ return true;\r
+\r
+ String error = "A file attachment may not exceed 25MB.";\r
+ QMessageBox.information(this, "Attachment Size", error);\r
+ return false;\r
+ }\r
+\r
+\r
+ @SuppressWarnings("unused")\r
+ private void createdChanged() {\r
+ QDateTime dt = new QDateTime();\r
+ dt.setDate(createdDate.date());\r
+ dt.setTime(createdTime.time());\r
+ noteSignal.createdDateChanged.emit(currentNote.getGuid(), dt);\r
+\r
+ }\r
+\r
+ @SuppressWarnings("unused")\r
+ private void alteredChanged() {\r
+ QDateTime dt = new QDateTime();\r
+ dt.setDate(alteredDate.date());\r
+ dt.setTime(alteredTime.time());\r
+ noteSignal.alteredDateChanged.emit(currentNote.getGuid(), dt);\r
+ }\r
+\r
+ @SuppressWarnings("unused")\r
+ private void subjectDateTimeChanged() {\r
+ QDateTime dt = new QDateTime();\r
+ dt.setDate(subjectDate.date());\r
+ dt.setTime(subjectTime.time());\r
+ noteSignal.subjectDateChanged.emit(currentNote.getGuid(), dt);\r
+\r
+ }\r
+\r
+ @SuppressWarnings("unused")\r
+ private void sourceUrlChanged() {\r
+ noteSignal.sourceUrlChanged.emit(currentNote.getGuid(), urlText.text());\r
+ }\r
+\r
+ @SuppressWarnings("unused")\r
+ private void authorChanged() {\r
+ noteSignal.authorChanged.emit(currentNote.getGuid(), authorText.text());\r
+ }\r
+\r
+ // ************************************************************\r
+ // * User chose to save an attachment. Pares out the request *\r
+ // * into a guid & file. Save the result. *\r
+ // ************************************************************\r
+ public void downloadAttachment(QNetworkRequest request) {\r
+ String guid;\r
+ QFileDialog fd = new QFileDialog(this);\r
+ fd.setFileMode(FileMode.AnyFile);\r
+ fd.setConfirmOverwrite(true);\r
+ fd.setWindowTitle("Save File");\r
+ fd.setAcceptMode(AcceptMode.AcceptSave);\r
+ fd.setDirectory(System.getProperty("user.home"));\r
+ String name = request.url().toString();\r
+\r
+ int pos = name.lastIndexOf(Global.attachmentNameDelimeter);\r
+ if (pos > -1) {\r
+ guid = name.substring(0, pos).replace("nnres://", "");\r
+ name = name.substring(pos +Global.attachmentNameDelimeter.length());\r
+ fd.selectFile(name);\r
+ pos = name.lastIndexOf('.');\r
+ if (pos > -1) {\r
+ String mimeType = "(*." + name.substring(pos + 1)\r
+ + ");; All Files (*)";\r
+ fd.setFilter(tr(mimeType));\r
+ }\r
+ } else {\r
+ guid = name;\r
+ }\r
+ guid = guid.replace("nnres://", "").replace(Global.currentDir.replace("\\","/")+"res/", "");\r
+ pos = guid.lastIndexOf('.');\r
+ if (pos > 0)\r
+ guid = guid.substring(0,pos);\r
+ if (fd.exec() != 0 && fd.selectedFiles().size() > 0) {\r
+ name = name.replace('\\', '/');\r
+ Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);\r
+ QFile saveFile = new QFile(fd.selectedFiles().get(0));\r
+ QFile.OpenMode mode = new QFile.OpenMode();\r
+ mode.set(QFile.OpenModeFlag.WriteOnly);\r
+ saveFile.open(mode);\r
+ QDataStream saveOut = new QDataStream(saveFile);\r
+ QByteArray binData = new QByteArray(resBinary.getData().getBody());\r
+ saveOut.writeBytes(binData.toByteArray());\r
+ saveFile.close();\r
+\r
+ }\r
+ }\r
+\r
+ \r
+ // ************************************************************\r
+ // * User chose to save an attachment. Pares out the request *\r
+ // * into a guid & file. Save the result. --- DONE FROM downloadAttachment now!!!!! \r
+ // ************************************************************\r
+ public void downloadImage(QNetworkRequest request) {\r
+ QFileDialog fd = new QFileDialog(this);\r
+ fd.setFileMode(FileMode.AnyFile);\r
+ fd.setConfirmOverwrite(true);\r
+ fd.setWindowTitle("Save File");\r
+ fd.setAcceptMode(AcceptMode.AcceptSave);\r
+ fd.setDirectory(System.getProperty("user.home"));\r
+ String name = request.url().toString();\r
+ name = name.replace("nnres://", "");\r
+ String dPath = Global.getDirectoryPath() + "res/";\r
+ dPath = dPath.replace('\\', '/');\r
+ name = name.replace(dPath, "");\r
+ int pos = name.lastIndexOf('.');\r
+ String guid = name;\r
+ if (pos > -1) {\r
+ String mimeType = "(*." + name.substring(pos + 1)\r
+ + ");; All Files (*)";\r
+ fd.setFilter(tr(mimeType));\r
+ guid = guid.substring(0,pos);\r
+ }\r
+ pos = name.lastIndexOf(Global.attachmentNameDelimeter);\r
+ if (pos > -1) {\r
+ guid = name.substring(0, pos);\r
+ fd.selectFile(name.substring(pos+Global.attachmentNameDelimeter.length())); \r
+ }\r
+ if (fd.exec() != 0 && fd.selectedFiles().size() > 0) {\r
+ Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);\r
+ String fileName = fd.selectedFiles().get(0);\r
+ QFile saveFile = new QFile(fileName);\r
+ QFile.OpenMode mode = new QFile.OpenMode();\r
+ mode.set(QFile.OpenModeFlag.WriteOnly);\r
+ saveFile.open(mode);\r
+ QDataStream saveOut = new QDataStream(saveFile);\r
+ QByteArray binData = new QByteArray(resBinary.getData().getBody());\r
+ saveOut.writeBytes(binData.toByteArray());\r
+ saveFile.close();\r
+ }\r
+ }\r
+\r
+ \r
+ // *************************************************************\r
+ // * decrypt any hidden text. We could do an XML parse, but \r
+ // * it is quicker here just to scan for an <img tag & do the fix\r
+ // * the manual way\r
+ // *************************************************************\r
+ private void removeEncryption(String id, String plainText, boolean permanent, String slot) {\r
+ if (!permanent) {\r
+ plainText = " <en-crypt-temp slot=\""+slot +"\">" +plainText+"</en-crypt-temp> ";\r
+ }\r
+ \r
+ String html = browser.page().mainFrame().toHtml();\r
+ String text = html;\r
+ int imagePos = html.indexOf("<img");\r
+ int endPos;\r
+ for ( ;imagePos>0; ) {\r
+ // Find the end tag\r
+ endPos = text.indexOf(">", imagePos);\r
+ String tag = text.substring(imagePos-1,endPos);\r
+ if (tag.indexOf("id=\""+id+"\"") > -1) {\r
+ text = text.substring(0,imagePos) +plainText+text.substring(endPos+1);\r
+ \r
+ browser.setContent(new QByteArray(text));\r
+ contentChanged();\r
+ }\r
+ imagePos = text.indexOf("<img", imagePos+1);\r
+ }\r
+ }\r
+ \r
+ \r
+ //****************************************************************\r
+ //* Focus shortcuts\r
+ //****************************************************************\r
+ @SuppressWarnings("unused")\r
+ private void focusTitle() {\r
+ titleLabel.setFocus();\r
+ }\r
+ @SuppressWarnings("unused")\r
+ private void focusTag() {\r
+ tagEdit.setFocus();\r
+ }\r
+ @SuppressWarnings("unused")\r
+ private void focusNote() {\r
+ browser.setFocus();\r
+ }\r
+ @SuppressWarnings("unused")\r
+ private void focusAuthor() {\r
+ authorLabel.setFocus();\r
+ }\r
+ @SuppressWarnings("unused")\r
+ private void focusUrl() {\r
+ urlLabel.setFocus();\r
+ }\r
+ \r
+\r
+ //*****************************************************************\r
+ //* Set the document background color\r
+ //*****************************************************************\r
+ public void setBackgroundColor(String color) {\r
+ String js = "function changeBackground(color) {"\r
+ +"document.body.style.background = color;"\r
+ +"}" \r
+ +"changeBackground('" +color+"');";\r
+ browser.page().mainFrame().evaluateJavaScript(js);\r
+ contentChanged();\r
+ }\r
+ \r
+ \r
+ //****************************************************************\r
+ //* MicroFocus changed\r
+ //****************************************************************\r
+ private void microFocusChanged() {\r
+ \r
+ boldButton.setDown(false);\r
+ italicButton.setDown(false);\r
+ underlineButton.setDown(false);\r
+ browser.openAction.setEnabled(false);\r
+ browser.downloadAttachment.setEnabled(false);\r
+ browser.downloadImage.setEnabled(false);\r
+ browser.rotateImageLeft.setEnabled(false);\r
+ browser.rotateImageRight.setEnabled(false);\r
+ browser.insertTableAction.setEnabled(true);\r
+ browser.insertTableRowAction.setEnabled(false);\r
+ browser.deleteTableRowAction.setEnabled(false);\r
+ browser.insertLinkAction.setText("Insert Hyperlink");\r
+ currentHyperlink ="";\r
+ insideList = false;\r
+ forceTextPaste = false;\r
+ \r
+ String js = new String( "function getCursorPos() {"\r
+ +"var cursorPos;"\r
+ +"if (window.getSelection) {"\r
+ +" var selObj = window.getSelection();"\r
+ +" var selRange = selObj.getRangeAt(0);"\r
+ +" var workingNode = window.getSelection().anchorNode.parentNode;"\r
+ +" while(workingNode != null) { " \r
+// +" window.jambi.printNode(workingNode.nodeName);"\r
+ +" if (workingNode.nodeName=='EN-CRYPT-TEMP') window.jambi.forceTextPaste();"\r
+ +" if (workingNode.nodeName=='B') window.jambi.boldActive();"\r
+ +" if (workingNode.nodeName=='I') window.jambi.italicActive();"\r
+ +" if (workingNode.nodeName=='U') window.jambi.underlineActive();"\r
+ +" if (workingNode.nodeName=='UL') window.jambi.setInsideList();"\r
+ +" if (workingNode.nodeName=='OL') window.jambi.setInsideList();"\r
+ +" if (workingNode.nodeName=='LI') window.jambi.setInsideList();"\r
+ +" if (workingNode.nodeName=='TBODY') window.jambi.setInsideTable();"\r
+ +" if (workingNode.nodeName=='A') {for(var x = 0; x < workingNode.attributes.length; x++ ) {if (workingNode.attributes[x].nodeName.toLowerCase() == 'href') window.jambi.setInsideLink(workingNode.attributes[x].nodeValue);}}"\r
+ +" if (workingNode.nodeName=='SPAN') {"\r
+ +" if (workingNode.getAttribute('style') == 'text-decoration: underline;') window.jambi.underlineActive();"\r
+ +" }"\r
+ +" workingNode = workingNode.parentNode;"\r
+ +" }"\r
+ +"}"\r
+ +"} getCursorPos();");\r
+ browser.page().mainFrame().evaluateJavaScript(js);\r
+ }\r
+ \r
+ public void printNode(String n) {\r
+ System.out.println("Node Vaule: " +n);\r
+ }\r
+ \r
+ \r
+ //****************************************************************\r
+ //* Insert a table row\r
+ //****************************************************************\r
+ public void insertTableRow() {\r
+ \r
+ String js = new String( "function insertTableRow() {"\r
+ +" var selObj = window.getSelection();"\r
+ +" var selRange = selObj.getRangeAt(0);"\r
+ +" var workingNode = window.getSelection().anchorNode.parentNode;"\r
+ +" var cellCount = 0;"\r
+ +" while(workingNode != null) { " \r
+ +" if (workingNode.nodeName.toLowerCase()=='tr') {"\r
+ +" row = document.createElement('TR');"\r
+ +" var nodes = workingNode.getElementsByTagName('td');"\r
+ +" for (j=0; j<nodes.length; j=j+1) {"\r
+ +" cell = document.createElement('TD');"\r
+ +" cell.innerHTML=' ';"\r
+ +" row.appendChild(cell);"\r
+ +" }" \r
+ +" workingNode.parentNode.insertBefore(row,workingNode.nextSibling);"\r
+ +" return;"\r
+ +" }"\r
+ +" workingNode = workingNode.parentNode;"\r
+ +" }"\r
+ +"} insertTableRow();");\r
+ browser.page().mainFrame().evaluateJavaScript(js);\r
+ contentChanged();\r
+ }\r
+ //****************************************************************\r
+ //* Insert a table row\r
+ //****************************************************************\r
+ public void deleteTableRow() {\r
+ \r
+ String js = new String( "function deleteTableRow() {"\r
+ +" var selObj = window.getSelection();"\r
+ +" var selRange = selObj.getRangeAt(0);"\r
+ +" var workingNode = window.getSelection().anchorNode.parentNode;"\r
+ +" var cellCount = 0;"\r
+ +" while(workingNode != null) { " \r
+ +" if (workingNode.nodeName.toLowerCase()=='tr') {"\r
+ +" workingNode.parentNode.removeChild(workingNode);"\r
+ +" return;"\r
+ +" }"\r
+ +" workingNode = workingNode.parentNode;"\r
+ +" }"\r
+ +"} deleteTableRow();");\r
+ browser.page().mainFrame().evaluateJavaScript(js);\r
+ contentChanged();\r
+ }\r
+ public void setInsideTable() {\r
+ browser.insertTableRowAction.setEnabled(true);\r
+ browser.deleteTableRowAction.setEnabled(true);\r
+ browser.insertTableAction.setEnabled(false);\r
+ browser.encryptAction.setEnabled(false);\r
+ }\r
+ \r
+ public void setInsideLink(String link) {\r
+ browser.insertLinkAction.setText("Edit Hyperlink");\r
+ currentHyperlink = link;\r
+ }\r
+ \r
+ public void italicActive() {\r
+ italicButton.setDown(true);\r
+ }\r
+ public void boldActive() {\r
+ boldButton.setDown(true);\r
+ }\r
+ public void underlineActive() {\r
+ underlineButton.setDown(true);\r
+ }\r
+ public void forceTextPaste() {\r
+ forceTextPaste = true;\r
+ }\r
+ public void imageContextMenu(String f) {\r
+ browser.downloadImage.setEnabled(true);\r
+ browser.rotateImageRight.setEnabled(true);\r
+ browser.rotateImageLeft.setEnabled(true);\r
+ browser.openAction.setEnabled(true);\r
+ selectedFile = f;\r
+ }\r
+ public void rotateImageRight() {\r
+ QWebSettings.setMaximumPagesInCache(0);\r
+ QWebSettings.setObjectCacheCapacities(0, 0, 0);\r
+ QImage image = new QImage(selectedFile);\r
+ QMatrix matrix = new QMatrix();\r
+ matrix.rotate( 90.0 );\r
+ image = image.transformed(matrix);\r
+ image.save(selectedFile);\r
+ QWebSettings.setMaximumPagesInCache(0);\r
+ QWebSettings.setObjectCacheCapacities(0, 0, 0);\r
+ browser.setHtml(browser.page().mainFrame().toHtml());\r
+ browser.reload();\r
+ contentChanged();\r
+// resourceSignal.contentChanged.emit(selectedFile);\r
+\r
+ }\r
+ public void rotateImageLeft() {\r
+ QImage image = new QImage(selectedFile);\r
+ QMatrix matrix = new QMatrix();\r
+ matrix.rotate( -90.0 );\r
+ image = image.transformed(matrix);\r
+ image.save(selectedFile);\r
+ browser.setHtml(browser.page().mainFrame().toHtml());\r
+ browser.reload();\r
+ contentChanged();\r
+// resourceSignal.contentChanged.emit(selectedFile);\r
+ }\r
+ public void resourceContextMenu(String f) {\r
+ browser.downloadAttachment.setEnabled(true);\r
+ browser.openAction.setEnabled(true);\r
+ selectedFile = f;\r
+ }\r
+ \r
+ \r
+ //****************************************************************\r
+ //* Apply CSS style to specified word\r
+ //****************************************************************\r
+/* public void applyStyleToWords(String word, String style) {\r
+ QFile script = new QFile("D:\\NeverNote\\js\\hilight1.js");\r
+ script.open(OpenModeFlag.ReadOnly);\r
+ String s = script.readAll().toString();\r
+ String js = new String(s +" findit('"+word+"', '"+style+"');");\r
+ browser.page().mainFrame().evaluateJavaScript(js);\r
+ System.out.println(getContent());\r
+ }\r
+*/ \r
+ //****************************************************************\r
+ //* Someone tried to paste a resource between notes, so we need *\r
+ //* to do some special handling. *\r
+ //****************************************************************\r
+ private String fixInternotePaste(String text) {\r
+ logger.log(logger.EXTREME, "Fixing internote paste");\r
+ String returnValue = fixInternotePasteSearch(text, "<img", "src=\"");\r
+ return fixInternotePasteSearch(returnValue, "<a", "href=\"nnres://");\r
+ }\r
+ private String fixInternotePasteSearch(String text, String type, String locTag) {\r
+ \r
+ // First, let's fix the images.\r
+ int startPos = text.indexOf(type);\r
+ int endPos;\r
+ for (; startPos>=0;) {\r
+ endPos = text.indexOf(">", startPos+1);\r
+ String segment = text.substring(startPos, endPos);\r
+ if (segment.indexOf("en-tag") > -1) {\r
+ String newSegment = segment;\r
+ \r
+ int guidStartPos = segment.indexOf("guid=\"");\r
+ int guidEndPos = segment.indexOf("\"", guidStartPos+7);\r
+ String guid = segment.substring(guidStartPos+6,guidEndPos);\r
+ \r
+ Calendar currentTime = new GregorianCalendar();\r
+ Long l = new Long(currentTime.getTimeInMillis());\r
+ long prevTime = l;\r
+ while (l==prevTime) {\r
+ currentTime = new GregorianCalendar();\r
+ l= new Long(currentTime.getTimeInMillis());\r
+ }\r
+ \r
+ Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);\r
+ if (r==null)\r
+ return "";\r
+ String randint = new String(Long.toString(l));\r
+ String extension = null;\r
+ if (r.getMime()!= null) {\r
+ extension = r.getMime().toLowerCase();\r
+ if (extension.indexOf("/")>-1)\r
+ extension = extension.substring(extension.indexOf("/")+1);\r
+ }\r
+ String newFile = randint;\r
+ if (r.getAttributes().getFileName() != null && r.getAttributes().getFileName() != "")\r
+ if (!locTag.startsWith("src"))\r
+ newFile = newFile+Global.attachmentNameDelimeter+r.getAttributes().getFileName();\r
+ r.setNoteGuid(currentNote.getGuid());\r
+ \r
+ r.setGuid(randint);\r
+ conn.getNoteTable().noteResourceTable.saveNoteResource(r, true);\r
+ QFile f = new QFile(Global.getDirectoryPath() +"res/" +newFile);\r
+ QByteArray bin = new QByteArray(r.getData().getBody());\r
+ f.open(QFile.OpenModeFlag.WriteOnly);\r
+ f.write(bin);\r
+ f.close();\r
+ newSegment = newSegment.replace("guid=\""+guid, "guid=\""+randint);\r
+ currentNote.getResources().add(r);\r
+ \r
+ int startSrcPos = newSegment.indexOf(locTag);\r
+ int endSrcPos = newSegment.indexOf("\"",startSrcPos+locTag.length()+1);\r
+ String source; \r
+ if (locTag.startsWith("src")) {\r
+ source = newSegment.substring(startSrcPos+locTag.length(),endSrcPos);\r
+ newSegment = newSegment.replace(source, Global.getDirectoryPath().replace("\\", "/")+"res/"+newFile);\r
+ } else {\r
+ source = newSegment.substring(startSrcPos+locTag.length(),endSrcPos);\r
+ newSegment = newSegment.replace(source, newFile);\r
+ }\r
+ \r
+ text = text.substring(0,startPos) + newSegment + text.substring(endPos);\r
+ }\r
+ startPos = text.indexOf(type, startPos+1);\r
+ }\r
+ return text;\r
+ }\r
+\r
+\r
+ public void nextPage(String file) {\r
+ logger.log(logger.EXTREME, "Starting nextPage()");\r
+ \r
+ Integer pageNumber;\r
+ if (previewPageList.containsKey(file))\r
+ pageNumber = previewPageList.get(file)+1;\r
+ else\r
+ pageNumber = 2;\r
+ previewPageList.remove(file);\r
+ previewPageList.put(file, pageNumber);\r
+ PDFPreview pdfPreview = new PDFPreview();\r
+ boolean goodPreview = pdfPreview.setupPreview(file, "pdf", pageNumber);\r
+ if (goodPreview) {\r
+\r
+// String html = getContent();\r
+ QWebSettings.setMaximumPagesInCache(0);\r
+ QWebSettings.setObjectCacheCapacities(0, 0, 0);\r
+// browser.setContent(new QByteArray());\r
+ browser.setHtml(browser.page().mainFrame().toHtml());\r
+ browser.reload();\r
+// browser.setContent(new QByteArray(html));\r
+// browser.triggerPageAction(WebAction.Reload);\r
+// pdfMouseOver(selectedFile);\r
+ }\r
+ }\r
+\r
+ public void previousPage(String file) {\r
+ logger.log(logger.EXTREME, "Starting previousPage()");\r
+ \r
+ Integer pageNumber;\r
+ if (previewPageList.containsKey(file))\r
+ pageNumber = previewPageList.get(file)-1;\r
+ else\r
+ pageNumber = 1;\r
+ previewPageList.remove(file);\r
+ previewPageList.put(file, pageNumber);\r
+ PDFPreview pdfPreview = new PDFPreview();\r
+ boolean goodPreview = pdfPreview.setupPreview(file, "pdf", pageNumber);\r
+ if (goodPreview) {\r
+\r
+// String html = getContent();\r
+ QWebSettings.setMaximumPagesInCache(0);\r
+ QWebSettings.setObjectCacheCapacities(0, 0, 0);\r
+ browser.setHtml(browser.page().mainFrame().toHtml());\r
+ browser.reload();\r
+// browser.setContent(new QByteArray(html));\r
+// browser.triggerPageAction(WebAction.Reload);\r
+ }\r
+ }\r
+ \r
+/* public void pdfMouseOver(String name) { \r
+ int pageNumber;\r
+ if (previewPageList.containsKey(selectedFile))\r
+ pageNumber = previewPageList.get(selectedFile)+1;\r
+ else\r
+ pageNumber = 1;\r
+ \r
+ if (pageNumber <= 1)\r
+ browser.previousPageAction.setEnabled(false);\r
+ else\r
+ browser.previousPageAction.setEnabled(true);\r
+ \r
+ PDFPreview pdf = new PDFPreview();\r
+ int totalPages = pdf.getPageCount(name);\r
+ if (previewPageList.containsKey(selectedFile))\r
+ pageNumber = previewPageList.get(selectedFile)+1;\r
+ else\r
+ pageNumber = 1;\r
+ if (totalPages > pageNumber)\r
+ browser.nextPageAction.setEnabled(true);\r
+ else\r
+ browser.nextPageAction.setEnabled(false);\r
+ }\r
+ \r
+\r
+ public void pdfMouseOut() { \r
+// browser.nextPageAction.setVisible(false);\r
+// browser.previousPageAction.setVisible(false);\r
+ }\r
+*/\r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.gui;\r
+\r
+import java.util.List;\r
+\r
+import com.trolltech.qt.core.QSize;\r
+import com.trolltech.qt.gui.QAction;\r
+import com.trolltech.qt.gui.QColor;\r
+import com.trolltech.qt.gui.QIcon;\r
+import com.trolltech.qt.gui.QMenu;\r
+import com.trolltech.qt.gui.QPixmap;\r
+import com.trolltech.qt.gui.QWidget;\r
+\r
+public class ColorMenu extends Object {\r
+ \r
+ private final QMenu menu;\r
+ QWidget parent;\r
+ QColor currentColor;\r
+ \r
+ public ColorMenu(QWidget b) {\r
+ menu = new QMenu();\r
+ parent = b;\r
+ populateList();\r
+ currentColor = new QColor("black");\r
+ }\r
+ \r
+ \r
+ private void populateList() {\r
+ List<String> colorNames = QColor.colorNames();\r
+ for(int i=0; i<colorNames.size(); i++) {\r
+ QColor color = new QColor(colorNames.get(i));\r
+ QPixmap pix = new QPixmap(new QSize(22, 22));\r
+ pix.fill(color);\r
+ QAction newAction = new QAction(new QIcon(pix), "", parent);\r
+ newAction.setToolTip(colorNames.get(i));\r
+ newAction.hovered.connect(this, "itemHovered()");\r
+ menu.addAction(newAction);\r
+ }\r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void itemHovered() {\r
+ if (menu.activeAction() != null && menu.activeAction().toolTip() != null)\r
+ currentColor = new QColor(menu.activeAction().toolTip());\r
+ }\r
+ \r
+ public QColor getColor() {\r
+ return currentColor;\r
+ }\r
+ \r
+ public QMenu getMenu() {\r
+ return menu;\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.gui;\r
+\r
+import java.util.ArrayList;\r
+\r
+import com.evernote.edam.type.Note;\r
+\r
+import cx.fbn.nevernote.filters.AttributeFilter;\r
+import cx.fbn.nevernote.sql.NoteTable;\r
+\r
+public class ContainsAttributeFilterTable {\r
+ ArrayList<AttributeFilter> table;\r
+ \r
+ public ContainsAttributeFilterTable() {\r
+ table = new ArrayList<AttributeFilter>();\r
+ table.add(new AttributeFilter("Images"));\r
+ table.add(new AttributeFilter("Audio"));\r
+ table.add(new AttributeFilter("Ink"));\r
+ table.add(new AttributeFilter("Encrypted Text"));\r
+ table.add(new AttributeFilter("To-Do Items"));\r
+ table.add(new AttributeFilter("Unfinished to-do items"));\r
+ table.add(new AttributeFilter("Finished to-do items"));\r
+ table.add(new AttributeFilter("Attachment"));\r
+ table.add(new AttributeFilter("PDF"));\r
+\r
+\r
+\r
+\r
+ \r
+ }\r
+ \r
+ public void reset() {\r
+ for (int i=0; i<table.size(); i++) \r
+ table.get(i).set(false);\r
+ }\r
+ \r
+ public void select(String name) {\r
+ for (int i=0; i<table.size(); i++) \r
+ if (table.get(i).getName().equalsIgnoreCase(name))\r
+ table.get(i).set(true);\r
+ }\r
+ \r
+ public int size() {\r
+ return table.size();\r
+ }\r
+ \r
+ public boolean check(NoteTable sqlTable, Note n) {\r
+ boolean result = true;\r
+ \r
+ for (int i=0; i<table.size(); i++) {\r
+ if (table.get(i).isSet()) {\r
+ n = sqlTable.getNote(n.getGuid(), true, true, false, false, false);\r
+ if (table.get(i).getName().equalsIgnoreCase("images"))\r
+ result = checkMime(n, "image/");\r
+ if (table.get(i).getName().equalsIgnoreCase("audio"))\r
+ result = checkMime(n, "audio/");\r
+ if (table.get(i).getName().equalsIgnoreCase("ink"))\r
+ result = checkMime(n, "application/vnd.evernote.ink");\r
+ if (table.get(i).getName().equalsIgnoreCase("Attachment"))\r
+ result = checkAttachment(n);\r
+ if (table.get(i).getName().equalsIgnoreCase("pdf"))\r
+ result = checkMime(n, "application/pdf");\r
+ if (table.get(i).getName().equalsIgnoreCase("Encrypted Text"))\r
+ result = checkText(n.getContent(), "<en-crypt");\r
+ if (table.get(i).getName().equalsIgnoreCase("To-Do Items"))\r
+ result = checkText(n.getContent(), "<en-todo");\r
+ if (table.get(i).getName().equalsIgnoreCase("Unfinished to-do items"))\r
+ result = checkTodo(n.getContent(), false);\r
+ if (table.get(i).getName().equalsIgnoreCase("Finished to-do items"))\r
+ result = checkTodo(n.getContent(), true);\r
+\r
+\r
+ }\r
+ }\r
+ return result;\r
+ }\r
+ \r
+ private boolean checkMime(Note n, String mime) {\r
+ for (int i=0; i<n.getResourcesSize(); i++) {\r
+ if (n.getResources().get(i).getMime().startsWith(mime))\r
+ return true;\r
+ }\r
+ return false;\r
+ }\r
+\r
+ private boolean checkAttachment(Note n) {\r
+ for (int i=0; i<n.getResourcesSize(); i++) {\r
+ if (n.getResources().get(i).getAttributes() != null && n.getResources().get(i).getAttributes().isAttachment())\r
+ return true;\r
+ }\r
+ return false;\r
+ }\r
+ \r
+ private boolean checkTodo(String content, boolean checked) {\r
+ int pos = content.indexOf("<en-todo");\r
+ \r
+ for (; pos >=0 ; pos=content.indexOf("<en-todo", pos+1)) {\r
+ int endPos = content.indexOf("/>", pos);\r
+ String segment = content.substring(pos, endPos);\r
+ boolean currentState = false;\r
+ if (segment.indexOf("checked=\"true\"") > -1)\r
+ currentState = true;\r
+ if (currentState == checked)\r
+ return true;\r
+ }\r
+ \r
+ \r
+ return false;\r
+ \r
+ }\r
+ \r
+ private boolean checkText(String content, String text) {\r
+ if (content.indexOf(text) > -1)\r
+ return true;\r
+ else\r
+ return false;\r
+ }\r
+ // Get the name of a particular attribute check\r
+ public String getName(int i) {\r
+ return table.get(i).getName();\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+package cx.fbn.nevernote.gui;\r
+\r
+import com.trolltech.qt.core.QEvent;\r
+import com.trolltech.qt.core.QMimeData;\r
+import com.trolltech.qt.core.Qt;\r
+import com.trolltech.qt.gui.QAction;\r
+import com.trolltech.qt.gui.QContextMenuEvent;\r
+import com.trolltech.qt.gui.QDropEvent;\r
+import com.trolltech.qt.gui.QKeyEvent;\r
+import com.trolltech.qt.gui.QKeySequence;\r
+import com.trolltech.qt.gui.QMenu;\r
+import com.trolltech.qt.gui.QShortcut;\r
+import com.trolltech.qt.gui.QKeySequence.StandardKey;\r
+import com.trolltech.qt.network.QNetworkRequest;\r
+import com.trolltech.qt.webkit.QWebPage;\r
+import com.trolltech.qt.webkit.QWebView;\r
+\r
+import cx.fbn.nevernote.Global;\r
+\r
+public class ContentView extends QWebView {\r
+\r
+ BrowserWindow parent;\r
+ QMenu contextMenu = new QMenu(this);\r
+ QMenu tableMenu = new QMenu(this);\r
+ QAction cutAction;\r
+ QShortcut cutShortcut;\r
+ QAction copyAction;\r
+ QShortcut copyShortcut;\r
+ QAction pasteAction;\r
+ QShortcut pasteShortcut;\r
+ QAction pasteWithoutFormatAction;\r
+ QShortcut pasteWithoutFormatShortcut;\r
+ QAction todoAction;\r
+ QShortcut todoShortcut;\r
+ QAction encryptAction;\r
+ QShortcut encryptShortcut;\r
+ QAction downloadAttachment;\r
+ QShortcut downloadAttachmentShortcut;\r
+ QAction downloadImage;\r
+ QShortcut downloadImageShortcut;\r
+ QAction rotateImageRight;\r
+ QShortcut rotateImageRightShortcut;\r
+ QAction rotateImageLeft;\r
+ QShortcut rotateImageLeftShortcut; \r
+ QAction insertLinkAction;\r
+ QShortcut insertLinkShortcut;\r
+ QAction insertTableAction;\r
+ QShortcut insertTableShortcut;\r
+ QAction insertTableRowAction;\r
+ QShortcut insertTableRowShortcut;\r
+ QAction deleteTableRowAction;\r
+ QShortcut deleteTableRowShortcut;\r
+ QAction openAction;\r
+ \r
+ QAction redBackgroundColor;\r
+ \r
+ QShortcut insertDateTimeShortcut;\r
+ \r
+ Signal1<QNetworkRequest> downloadAttachmentRequested;\r
+ Signal1<QNetworkRequest> downloadImageRequested;\r
+ \r
+ public ContentView(BrowserWindow p) {\r
+ parent=p;\r
+ contextMenu = new QMenu(this);\r
+ \r
+ openAction = new QAction(tr("Open"), this);\r
+ openAction.setText(tr("Open"));\r
+ contextMenu.addAction(openAction);\r
+ openAction.triggered.connect(parent, "openFile()");\r
+ \r
+ cutAction = new QAction(tr("Cut"), this);\r
+ cutAction.triggered.connect(parent, "cutClicked()");\r
+ contextMenu.addAction(cutAction); \r
+ contextMenu.insertSeparator(cutAction);\r
+ setupShortcut(cutAction, "Edit_Cut");\r
+ cutShortcut = new QShortcut(this);\r
+ cutShortcut.activated.connect(parent, "cutClicked()");\r
+ setupShortcut(cutShortcut, "Edit_Cut");\r
+ \r
+ copyAction = new QAction(tr("Copy"), this);\r
+ copyAction.triggered.connect(parent, "copyClicked()");\r
+ contextMenu.addAction(copyAction); \r
+ setupShortcut(copyAction, "Edit_Copy");\r
+ copyShortcut = new QShortcut(this);\r
+ copyShortcut.activated.connect(parent, "copyClicked()");\r
+ setupShortcut(copyShortcut, "Edit_Copy");\r
+ \r
+ pasteAction = pageAction(QWebPage.WebAction.Paste);\r
+ pasteAction.disconnect();\r
+ pasteAction.triggered.connect(parent, "pasteClicked()");\r
+ \r
+ contextMenu.addAction(pasteAction); \r
+ setupShortcut(pasteAction, "Edit_Paste");\r
+ pasteShortcut = new QShortcut(this);\r
+ pasteShortcut.activated.connect(parent, "pasteClicked()");\r
+ setupShortcut(pasteShortcut, "Edit_Paste");\r
+ \r
+ pasteWithoutFormatAction = new QAction(tr("Paste Without Formatting"), this);\r
+ pasteWithoutFormatAction.triggered.connect(parent, "pasteWithoutFormattingClicked()");\r
+ contextMenu.addAction(pasteWithoutFormatAction); \r
+ setupShortcut(pasteWithoutFormatAction, "Edit_Paste_Without_Formatting");\r
+ pasteWithoutFormatShortcut = new QShortcut(this);\r
+ pasteWithoutFormatShortcut.activated.connect(parent, "pasteWithoutFormattingClicked()");\r
+ setupShortcut(pasteWithoutFormatShortcut, "Edit_Paste_Without_Formatting");\r
+ \r
+ contextMenu.addSeparator();\r
+ QMenu colorMenu = new QMenu(tr("Background Color"));\r
+ contextMenu.addMenu(colorMenu);\r
+ \r
+ colorMenu.addAction(setupColorMenuOption("White"));\r
+ colorMenu.addAction(setupColorMenuOption("Red"));\r
+ colorMenu.addAction(setupColorMenuOption("Blue"));\r
+ colorMenu.addAction(setupColorMenuOption("Green"));\r
+ colorMenu.addAction(setupColorMenuOption("Yellow"));\r
+ colorMenu.addAction(setupColorMenuOption("Black"));\r
+ colorMenu.addAction(setupColorMenuOption("Grey"));\r
+ colorMenu.addAction(setupColorMenuOption("Purple"));\r
+ colorMenu.addAction(setupColorMenuOption("Brown"));\r
+ colorMenu.addAction(setupColorMenuOption("Orange"));\r
+ colorMenu.addAction(setupColorMenuOption("Powder Blue"));\r
+ \r
+ \r
+ contextMenu.addSeparator();\r
+ todoAction = new QAction(tr("To-do"), this);\r
+ todoAction.triggered.connect(parent, "todoClicked()");\r
+ contextMenu.addAction(todoAction);\r
+ setupShortcut(todoAction, "Edit_Insert_Todo");\r
+ contextMenu.insertSeparator(todoAction);\r
+ todoShortcut = new QShortcut(this);\r
+ todoShortcut.activated.connect(parent, "todoClicked()");\r
+ setupShortcut(todoShortcut, "Edit_Insert_Todo");\r
+ \r
+ encryptAction = new QAction(tr("Encrypt Selected Text"), this);\r
+ encryptAction.triggered.connect(parent, "encryptText()");\r
+ contextMenu.addAction(encryptAction);\r
+ contextMenu.insertSeparator(encryptAction);\r
+ setupShortcut(encryptAction, "Edit_Encrypt_Text");\r
+ encryptAction.setEnabled(false);\r
+ encryptShortcut = new QShortcut(this);\r
+ encryptShortcut.activated.connect(parent, "encryptText()");\r
+ setupShortcut(encryptShortcut, "Edit_Encrypt_Text");\r
+ \r
+ insertLinkAction = new QAction(tr("Insert Hyperlink"), this);\r
+ insertLinkAction.triggered.connect(parent, "insertLink()");\r
+ setupShortcut(insertLinkAction, "Edit_Insert_Hyperlink");\r
+ contextMenu.addAction(insertLinkAction);\r
+ insertLinkAction.setEnabled(false);\r
+ insertLinkShortcut = new QShortcut(this);\r
+ setupShortcut(insertLinkShortcut, "Edit_Insert_Hyperlink");\r
+ insertLinkShortcut.activated.connect(parent, "insertLink()");\r
+ \r
+ contextMenu.addMenu(tableMenu);\r
+ tableMenu.setTitle("Table");\r
+ insertTableAction = new QAction(tr("Insert Table"), this);\r
+ insertTableAction.triggered.connect(parent, "insertTable()");\r
+ setupShortcut(insertTableAction, "Edit_Insert_Table");\r
+ tableMenu.addAction(insertTableAction);\r
+ insertTableShortcut = new QShortcut(this);\r
+ setupShortcut(insertTableShortcut, "Edit_Insert_Table");\r
+ insertTableShortcut.activated.connect(parent, "insertTable()");\r
+\r
+ insertTableRowAction = new QAction(tr("Insert Row"), this);\r
+ insertTableRowAction.triggered.connect(parent, "insertTableRow()");\r
+ setupShortcut(insertTableRowAction, "Edit_Insert_Table_Row");\r
+ tableMenu.addAction(insertTableRowAction);\r
+ insertTableRowShortcut = new QShortcut(this);\r
+ setupShortcut(insertTableRowShortcut, "Edit_Insert_Table_Row");\r
+ insertTableRowShortcut.activated.connect(parent, "insertTableRow()");\r
+ \r
+ deleteTableRowAction = new QAction(tr("Delete Row"), this);\r
+ deleteTableRowAction.triggered.connect(parent, "deleteTableRow()");\r
+ setupShortcut(deleteTableRowAction, "Edit_Delete_Table_Row");\r
+ tableMenu.addAction(deleteTableRowAction);\r
+ deleteTableRowShortcut = new QShortcut(this);\r
+ setupShortcut(deleteTableRowShortcut, "Edit_Delete_Table_Row");\r
+ deleteTableRowShortcut.activated.connect(parent, "deleteTableRow()");\r
+ \r
+ insertDateTimeShortcut = new QShortcut(this);\r
+ insertDateTimeShortcut.activated.connect(parent, "insertDateTime()");\r
+ setupShortcut(insertDateTimeShortcut, "Insert_DateTime");\r
+ \r
+ QMenu imageMenu = new QMenu();\r
+ imageMenu.setTitle("Image");\r
+ contextMenu.addMenu(imageMenu);\r
+ downloadImage = pageAction(QWebPage.WebAction.DownloadImageToDisk);\r
+ downloadImage.setText(tr("Save Image"));\r
+ imageMenu.addAction(downloadImage);\r
+// contextMenu.insertSeparator(downloadImage);\r
+// page().downloadRequested.connect(this, "downloadImage(QNetworkRequest)");\r
+ downloadImageRequested = new Signal1<QNetworkRequest>();\r
+ \r
+ rotateImageRight = new QAction(tr("Rotate Right"), this);\r
+ imageMenu.addAction(rotateImageRight);\r
+ rotateImageRight.triggered.connect(parent, "rotateImageRight()");\r
+ rotateImageRightShortcut = new QShortcut(this);\r
+ setupShortcut(rotateImageRightShortcut, "Edit_Image_Rotate_Right");\r
+ rotateImageRightShortcut.activated.connect(parent, "rotateImageRight()");\r
+ \r
+ rotateImageLeft = new QAction(tr("Rotate Left"), this);\r
+ imageMenu.addAction(rotateImageLeft);\r
+ rotateImageLeft.triggered.connect(parent, "rotateImageLeft()");\r
+ rotateImageLeftShortcut = new QShortcut(this);\r
+ setupShortcut(rotateImageLeftShortcut, "Edit_Image_Rotate_Left");\r
+ rotateImageLeftShortcut.activated.connect(parent, "rotateImageLeft()");\r
+ \r
+ downloadAttachment = pageAction(QWebPage.WebAction.DownloadLinkToDisk);\r
+ downloadAttachment.setText(tr("Save Attachment"));\r
+ contextMenu.addAction(downloadAttachment);\r
+ page().downloadRequested.connect(this, "downloadAttachment(QNetworkRequest)");\r
+ downloadAttachmentRequested = new Signal1<QNetworkRequest>();\r
+ \r
+ }\r
+ \r
+ private void setupShortcut(QAction action, String text) {\r
+ if (!Global.shortcutKeys.containsAction(text))\r
+ return;\r
+ action.setShortcut(Global.shortcutKeys.getShortcut(text));\r
+ }\r
+ \r
+ private void setupShortcut(QShortcut action, String text) {\r
+ if (!Global.shortcutKeys.containsAction(text))\r
+ return;\r
+ action.setKey(new QKeySequence(Global.shortcutKeys.getShortcut(text)));\r
+ }\r
+ \r
+ private QAction setupColorMenuOption(String color) {\r
+ QAction backgroundColor = new QAction(tr(color), this);\r
+ color = color.replace(" ", "");\r
+ backgroundColor.triggered.connect(this, "setBackground"+color+"()");\r
+ return backgroundColor;\r
+ }\r
+ \r
+ @Override\r
+ public boolean event(QEvent event)\r
+ {\r
+ if (event.type().equals(QEvent.Type.KeyPress)) {\r
+ QKeyEvent ke = (QKeyEvent) event;\r
+ if (ke.key() == Qt.Key.Key_Tab.value()) {\r
+ parent.tabPressed();\r
+ return true;\r
+ }\r
+ if (ke.key() == Qt.Key.Key_Backtab.value()) {\r
+ parent.backtabPressed();\r
+ return true;\r
+ }\r
+ }\r
+ return super.event(event);\r
+ }\r
+ \r
+ \r
+ @Override\r
+ public void keyPressEvent(QKeyEvent e) {\r
+ \r
+ // This is done because if we set the content editable, the scroll keys are\r
+ // ignored by webkit.\r
+ if (e.key() == Qt.Key.Key_PageUp.value() || e.key() == Qt.Key.Key_PageDown.value()) {\r
+ int bottom = page().mainFrame().geometry().bottom();\r
+ int top = page().mainFrame().geometry().top();\r
+ int scrollValue = top-bottom;\r
+ if (e.key() == Qt.Key.Key_PageDown.value())\r
+ scrollValue = -1*scrollValue;\r
+ page().mainFrame().scroll(0, scrollValue);\r
+ }\r
+ \r
+ // This is done to allow proper pasting of resources, otherwise it messes up multiple pastes\r
+ if (e.matches(StandardKey.Paste)) {\r
+ parent.pasteClicked();\r
+ e.accept();\r
+ return;\r
+ }\r
+ super.keyPressEvent(e);\r
+ }\r
+\r
+// public void downloadImage(QNetworkRequest req) {\r
+// System.out.println(req.url().toString());\r
+// downloadImageRequested.emit(req);\r
+// }\r
+ public void downloadAttachment(QNetworkRequest req) {\r
+ downloadAttachmentRequested.emit(req);\r
+ }\r
+\r
+ \r
+ @Override\r
+ public void dropEvent(QDropEvent e) {\r
+ setFocus();\r
+ QMimeData mime = e.mimeData();\r
+ parent.handleUrls(mime);\r
+ parent.contentChanged();\r
+// triggerPageAction(WebAction.Reload);\r
+ }\r
+ \r
+ @Override\r
+ public void contextMenuEvent(QContextMenuEvent event) {\r
+ if (event != null)\r
+ contextMenu.exec(event.globalPos());\r
+ }\r
+\r
+ \r
+ \r
+ @SuppressWarnings("unused")\r
+ private void setBackgroundWhite() {parent.setBackgroundColor("white");}\r
+ @SuppressWarnings("unused")\r
+ private void setBackgroundRed() {parent.setBackgroundColor("red");}\r
+ @SuppressWarnings("unused")\r
+ private void setBackgroundBlue() {parent.setBackgroundColor("blue");}\r
+ @SuppressWarnings("unused")\r
+ private void setBackgroundGreen() {parent.setBackgroundColor("green");}\r
+ @SuppressWarnings("unused")\r
+ private void setBackgroundYellow() {parent.setBackgroundColor("yellow");}\r
+ @SuppressWarnings("unused")\r
+ private void setBackgroundBlack() {parent.setBackgroundColor("black");}\r
+ @SuppressWarnings("unused")\r
+ private void setBackgroundPurple() {parent.setBackgroundColor("purple");}\r
+ @SuppressWarnings("unused")\r
+ private void setBackgroundBrown() {parent.setBackgroundColor("brown");}\r
+ @SuppressWarnings("unused")\r
+ private void setBackgroundGrey() {parent.setBackgroundColor("grey");}\r
+ @SuppressWarnings("unused")\r
+ private void setBackgroundOrange() {parent.setBackgroundColor("orange");}\r
+ @SuppressWarnings("unused")\r
+ private void setBackgroundPowderBlue() {parent.setBackgroundColor("powderblue");}\r
+\r
+\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.gui;\r
+\r
+import java.text.SimpleDateFormat;\r
+import java.util.ArrayList;\r
+\r
+import com.evernote.edam.type.Note;\r
+import com.trolltech.qt.core.QDateTime;\r
+\r
+import cx.fbn.nevernote.filters.AttributeFilter;\r
+\r
+public class DateAttributeFilterTable {\r
+ ArrayList<AttributeFilter> table;\r
+ boolean checkSince;\r
+ boolean checkCreated;\r
+ \r
+ public void setSince() {\r
+ checkSince = true;\r
+ }\r
+ \r
+ public void setBefore() {\r
+ checkSince = false;\r
+ }\r
+ \r
+ public void setCreated() {\r
+ checkCreated = true;\r
+ }\r
+ \r
+ public void setUpdated() {\r
+ checkCreated = false;\r
+ }\r
+ \r
+ public DateAttributeFilterTable() {\r
+ checkSince = true;\r
+ checkCreated = true;\r
+ table = new ArrayList<AttributeFilter>();\r
+ table.add(new AttributeFilter("Today"));\r
+ table.add(new AttributeFilter("Yesterday"));\r
+ table.add(new AttributeFilter("This Week"));\r
+ table.add(new AttributeFilter("Last Week"));\r
+ table.add(new AttributeFilter("This Month"));\r
+ table.add(new AttributeFilter("Last Month"));\r
+ table.add(new AttributeFilter("This Year"));\r
+ table.add(new AttributeFilter("Last Year"));\r
+ }\r
+ \r
+ public void reset() {\r
+ for (int i=0; i<table.size(); i++) \r
+ table.get(i).set(false);\r
+ }\r
+ \r
+ public void select(String name) {\r
+ for (int i=0; i<table.size(); i++) \r
+ if (table.get(i).getName().equals(name))\r
+ table.get(i).set(true);\r
+ }\r
+ \r
+ public int size() {\r
+ return table.size();\r
+ }\r
+ \r
+ public boolean check(Note n) {\r
+ QDateTime noteDate;\r
+ String dateTimeFormat = new String("MM/dd/yyyy HH:mm:ss");\r
+ SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);\r
+ StringBuilder creationDate = new StringBuilder(simple.format(n.getCreated()));\r
+ StringBuilder updatedDate = new StringBuilder(simple.format(n.getUpdated()));\r
+ if (checkCreated)\r
+ noteDate = QDateTime.fromString(creationDate.toString(), "MM/dd/yyyy HH:mm:ss");\r
+ else \r
+ noteDate = QDateTime.fromString(updatedDate.toString(), "MM/dd/yyyy HH:mm:ss");\r
+ \r
+ QDateTime current = new QDateTime();\r
+ current = QDateTime.currentDateTime();\r
+ \r
+ boolean result = true;\r
+ \r
+ for (int i=0; i<table.size(); i++) {\r
+ if (table.get(i).isSet()) {\r
+ if (table.get(i).getName().equalsIgnoreCase("today")) {\r
+ if (!checkToday(noteDate, current))\r
+ result = false;\r
+ }\r
+ if (table.get(i).getName().equalsIgnoreCase("yesterday")) {\r
+ if (!checkYesterday(noteDate, current))\r
+ result = false;\r
+ }\r
+ if (table.get(i).getName().equalsIgnoreCase("this week")) {\r
+ if (!checkWeek(noteDate, current))\r
+ result = false;\r
+ }\r
+ if (table.get(i).getName().equalsIgnoreCase("last week")) {\r
+ if (!checkLastWeek(noteDate, current))\r
+ result = false;\r
+ }\r
+ if (table.get(i).getName().equalsIgnoreCase("this month")) {\r
+ if (!checkMonth(noteDate, current))\r
+ result = false;\r
+ }\r
+ if (table.get(i).getName().equalsIgnoreCase("last month")) {\r
+ if (!checkLastMonth(noteDate, current))\r
+ result = false;\r
+ }\r
+ if (table.get(i).getName().equalsIgnoreCase("this year")) {\r
+ if (!checkYear(noteDate, current))\r
+ result = false;\r
+ }\r
+ if (table.get(i).getName().equalsIgnoreCase("last year")) {\r
+ if (!checkLastYear(noteDate, current))\r
+ result = false;\r
+ }\r
+ }\r
+ }\r
+ return result;\r
+ }\r
+ \r
+ \r
+ // Check if it was within the last day\r
+ private boolean checkToday(QDateTime noteDate, QDateTime current) {\r
+ if (checkSince)\r
+ return noteDate.daysTo(current) == 0;\r
+ else \r
+ return noteDate.daysTo(current) > 0;\r
+ }\r
+ \r
+ // Check if it was within the last two days\r
+ private boolean checkYesterday(QDateTime noteDate, QDateTime current) {\r
+ if (checkSince) \r
+ return noteDate.daysTo(current) <= 1;\r
+ else\r
+ return noteDate.daysTo(current) > 1;\r
+ }\r
+ \r
+ \r
+ // Check if it was within the last two days\r
+ private boolean checkWeek(QDateTime noteDate, QDateTime current) {\r
+ if (checkSince) \r
+ return noteDate.daysTo(current) <= 7;\r
+ else\r
+ return noteDate.daysTo(current) > 7;\r
+ }\r
+ \r
+ \r
+ \r
+ \r
+ // Check if it was within the last two weeks\r
+ private boolean checkLastWeek(QDateTime noteDate, QDateTime current) {\r
+ if (checkSince) \r
+ return noteDate.daysTo(current) <= 14;\r
+ else\r
+ return noteDate.daysTo(current) > 14;\r
+ }\r
+ \r
+ \r
+ \r
+ // Check if it was within the last month\r
+ private boolean checkMonth(QDateTime noteDate, QDateTime current) {\r
+ if (checkSince)\r
+ return noteDate.date().month() - current.date().month() == 0;\r
+ else\r
+ return noteDate.date().month() - current.date().month() != 0;\r
+ }\r
+ \r
+ \r
+ \r
+ \r
+ // Check if it was within the last two months\r
+ private boolean checkLastMonth(QDateTime noteDate, QDateTime current) {\r
+ int ny = noteDate.date().year();\r
+ int cy = current.date().year();\r
+ int nm = noteDate.date().month();\r
+ int cm = current.date().month();\r
+\r
+ while (cy-ny >= 1) {\r
+ cm = cm+12;\r
+ cy--;\r
+ }\r
+ if (checkSince) \r
+ return cm-nm <=1;\r
+ else\r
+ return cm-nm > 1;\r
+ }\r
+ \r
+ \r
+ \r
+ // Check if it was within the last two days\r
+ private boolean checkYear(QDateTime noteDate, QDateTime current) {\r
+ int ny = noteDate.date().year();\r
+ int cy = current.date().year();\r
+ if (checkSince)\r
+ return ny-cy == 0;\r
+ else\r
+ return ny-cy < 0;\r
+ } \r
+ \r
+ \r
+ \r
+ // Check if it was within the last two days\r
+ private boolean checkLastYear(QDateTime noteDate, QDateTime current) {\r
+ int ny = noteDate.date().year();\r
+ int cy = current.date().year();\r
+ if (checkSince) \r
+ return cy-ny <=1;\r
+ else\r
+ return cy-ny > 1;\r
+ }\r
+ \r
+ \r
+ // Get the name of a particular attribute check\r
+ public String getName(int i) {\r
+ return table.get(i).getName();\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+package cx.fbn.nevernote.gui;\r
+\r
+import com.trolltech.qt.gui.QAction;\r
+import com.trolltech.qt.gui.QMenu;\r
+import com.trolltech.qt.gui.QMenuBar;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.NeverNote;\r
+\r
+public class MainMenuBar extends QMenuBar {\r
+\r
+ private final NeverNote parent;\r
+ public QAction printAction; // Action when a user selects Print from the file menu\r
+ public QAction connectAction; // Connect/Disconnect to Evernote\r
+ public QAction fullReindexAction; // Action when a user wants to reindex the entire database\r
+ public QAction synchronizeAction; // Synchronize data with Evernote \r
+ public QAction settingsAction; // Show user config settings\r
+ public QAction emailAction; // Action when a user selects "email"\r
+ public QAction backupAction; // Backup the database\r
+ public QAction restoreAction; // Restore from a backup\r
+ public QAction emptyTrashAction; // Action when a user wants to clear the trash file\r
+ public QAction exitAction; // Action when user selects "exit"\r
+ public QAction aboutAction; // Action when a user selects "About"\r
+ public QAction loggerAction; // Action when a user selects "Log"\r
+ public QAction releaseAction; // Release notes\r
+\r
+ public QAction noteAdd; // Add a note\r
+ public QAction noteAttributes; // Action when a user selects note attributes\r
+ public QAction noteTags; // Assign a note tags\r
+ public QAction noteDelete; // Delete the current note\r
+ public QAction noteRestoreAction; // Restore a note\r
+ public QAction noteReindex; // Action when a user wants to reindex a note\r
+ public QAction noteDuplicateAction; // Duplicate an existing note\r
+ public QAction noteMergeAction; // Merge notes\r
+ public QAction noteExportAction; // Export notes\r
+ public QAction noteImportAction; // Import notes\r
+ \r
+ public QAction editFind; // find text in the current note\r
+ public QAction editUndo; // Undo last change\r
+ public QAction editRedo; // Redo last change\r
+ public QAction editCut; // Cut selected text\r
+ public QAction editPaste; // Paste selected text\r
+ public QAction editPasteWithoutFormat; // Paste selected text\r
+ public QAction editCopy; // Copy selected text;\r
+ \r
+ public QAction thumbnailView; // view thumbnails\r
+ public QAction hideSavedSearches; // show/hide saved searches\r
+ public QAction hideNotebooks; // show/hide notebooks\r
+ public QAction hideTags; // show/hide tags\r
+ public QAction hideAttributes; // show/hide note information\r
+ public QAction hideTrash; // show/hide trash tree\r
+ public QAction hideNoteList; // show/hide the list of notes\r
+ public QAction showEditorBar; // show/hide the editor button bar\r
+ public QAction hideLeftSide; // Hide the entire left side\r
+ \r
+ public QAction formatBold; // Bold selected text\r
+ public QAction formatItalic; // Italics selected text\r
+ public QAction formatUnderline; // Underline selected text\r
+ public QAction formatStrikethrough; // Strikethrough selected text\r
+ public QAction formatSuperscript; // Superscript selected text\r
+ public QAction formatSubscript; // Subscript selected text\r
+ public QAction formatNumberList; // insert a numbered list\r
+ public QAction formatBulletList; // insert a bulleted list;\r
+ public QAction alignLeftAction; // Left justify text\r
+ public QAction alignRightAction; // Right justify text\r
+ public QAction alignCenterAction; // Center text\r
+ public QAction horizontalLineAction; // Insert a horizontal line\r
+ public QAction indentAction; // Indent\r
+ public QAction outdentAction; // outdent menu action\r
+ \r
+ public QAction noteOnlineHistoryAction; // Pull note history from Evernote\r
+ \r
+ public QAction accountAction; // Account dialog box action\r
+ public QAction disableIndexing; // put indexing on hold.\r
+// public QAction compactAction; // free unused space in the database\r
+ public QAction databaseStatusAction; // Current database status\r
+ public QAction folderImportAction; // Automatically import files \r
+ \r
+ public QAction notebookEditAction; // Edit the selected notebook\r
+ public QAction notebookAddAction; // Add a new notebook\r
+ public QAction notebookDeleteAction; // Delete a notebook\r
+ public QAction notebookCloseAction; // Close notebooks\r
+ \r
+ public QAction savedSearchAddAction; // Add a saved search\r
+ public QAction savedSearchEditAction; // Edit a saved search\r
+ public QAction savedSearchDeleteAction; // Delete a saved search\r
+ \r
+ public QAction tagEditAction; // Edit a tag\r
+ public QAction tagAddAction; // Add a tag\r
+ public QAction tagDeleteAction; // Delete a tag\r
+ \r
+ //**************************************************************************\r
+ //* Menu Bar Titles\r
+ //**************************************************************************\r
+ \r
+ private QMenu fileMenu; // File menu\r
+ private QMenu noteMenu; // Note menu \r
+ private QMenu notebookMenu; // Notebook menu\r
+ private QMenu tagMenu; // Tag menu\r
+ private QMenu savedSearchMenu; // Saved Searches \r
+\r
+ private QMenu editMenu; // Edit menu\r
+\r
+ private QMenu formatMenu; // Text format menu\r
+ private QMenu viewMenu; // show/hide stuff\r
+ private QMenu listMenu; // bullet or numbered list\r
+ private QMenu indentMenu; // indent or outdent menu\r
+ private QMenu alignMenu; // Left/Right/Center justify\r
+ \r
+ private QMenu onlineMenu; // View online stuff (if connected)\r
+ \r
+ private QMenu toolsMenu; // Tools menu\r
+ \r
+ private QMenu helpMenu; \r
+ \r
+ public MainMenuBar(NeverNote p) {\r
+ parent = p;\r
+ \r
+ \r
+ fullReindexAction = new QAction(tr("Reindex Database"), this);\r
+ fullReindexAction.setToolTip("Reindex all notes");\r
+ fullReindexAction.triggered.connect(parent, "fullReindex()");\r
+ setupShortcut(fullReindexAction, "Tools_Reindex_Database");\r
+ \r
+ printAction = new QAction(tr("Print"), this);\r
+ printAction.setToolTip("Print the current note");\r
+ printAction.triggered.connect(parent, "printNote()");\r
+ setupShortcut(printAction, "File_Print");\r
+ \r
+ emailAction = new QAction(tr("Email"), this);\r
+ emailAction.setToolTip("Email the current note");\r
+ emailAction.triggered.connect(parent, "emailNote()");\r
+ setupShortcut(emailAction, "File_Email");\r
+ \r
+ backupAction = new QAction(tr("Backup Database"), this);\r
+ backupAction.setToolTip("Backup the current database");\r
+ backupAction.triggered.connect(parent, "databaseBackup()");\r
+ setupShortcut(backupAction, "File_Backup");\r
+\r
+ restoreAction = new QAction(tr("Restore Database"), this);\r
+ restoreAction.setToolTip("Restore the database from a backup");\r
+ restoreAction.triggered.connect(parent, "databaseRestore()");\r
+ setupShortcut(restoreAction, "File_Restore");\r
+ \r
+ emptyTrashAction = new QAction(tr("Empty Trash"), this);\r
+ emptyTrashAction.setToolTip("Empty the trash folder");\r
+ emptyTrashAction.triggered.connect(parent, "emptyTrash()");\r
+ setupShortcut(emptyTrashAction, "File_Empty_Trash");\r
+ \r
+ noteRestoreAction = new QAction(tr("Restore"), this);\r
+ noteRestoreAction.setToolTip("Restore a deleted file from the trash");\r
+ noteRestoreAction.triggered.connect(parent, "restoreNote()");\r
+ noteRestoreAction.setVisible(false);\r
+ setupShortcut(noteRestoreAction, "File_Note_Restore");\r
+ \r
+ settingsAction = new QAction(tr("Preferences"), this);\r
+ settingsAction.setToolTip("Program settings");\r
+ settingsAction.triggered.connect(parent, "settings()");\r
+ setupShortcut(settingsAction, "Edit_Preferences");\r
+ \r
+ exitAction = new QAction(tr("Exit"), this);\r
+ exitAction.setToolTip("Close the program");\r
+ exitAction.triggered.connect(parent, "close()");\r
+ exitAction.setShortcut("Ctrl+Q");\r
+ setupShortcut(exitAction, "File_Exit");\r
+ \r
+ noteAttributes = new QAction(tr("Extended Information"), this);\r
+ noteAttributes.setToolTip("Show/Hide extended note attributes");\r
+ noteAttributes.triggered.connect(parent, "toggleNoteInformation()");\r
+ noteAttributes.setShortcut("F8");\r
+ setupShortcut(noteAttributes, "View_Extended_Information");\r
+ \r
+ noteReindex = new QAction(tr("Reindex"), this);\r
+ noteReindex.setToolTip(tr("Reindex this note"));\r
+ noteReindex.triggered.connect(parent, "reindexNote()");\r
+ setupShortcut(noteReindex, "File_Note_Reindex");\r
+ \r
+ noteDuplicateAction = new QAction(tr("Duplicate"), this);\r
+ noteDuplicateAction.setToolTip(tr("Duplicate this note"));\r
+ noteDuplicateAction.triggered.connect(parent, "duplicateNote()");\r
+ setupShortcut(noteReindex, "File_Note_Duplicate");\r
+ \r
+ noteMergeAction = new QAction(tr("Merge Notes"), this);\r
+ noteMergeAction.setToolTip(tr("Merge Multiple notes"));\r
+ noteMergeAction.triggered.connect(parent, "mergeNotes()");\r
+ setupShortcut(noteMergeAction, "File_Note_Merge");\r
+ \r
+ noteExportAction = new QAction(tr("Export Selected Notes"), this);\r
+ noteExportAction.setToolTip(tr("Export selected notes"));\r
+ noteExportAction.triggered.connect(parent, "exportNotes()");\r
+ setupShortcut(noteExportAction, "File_Note_Export");\r
+ \r
+ noteImportAction = new QAction(tr("Import Notes"), this);\r
+ noteImportAction.setToolTip(tr("Import notes"));\r
+ noteImportAction.triggered.connect(parent, "importNotes()");\r
+ setupShortcut(noteImportAction, "File_Note_Import");\r
+ \r
+ noteAdd = new QAction(tr("Add"), this);\r
+ noteAdd.setToolTip(tr("Add a new note"));\r
+ noteAdd.triggered.connect(parent, "addNote()");\r
+ setupShortcut(noteAdd, "File_Note_Add");\r
+ //noteAdd.setShortcut("Ctrl+N");\r
+ \r
+ noteTags = new QAction(tr("Modify Tags"), this);\r
+ noteTags.setToolTip(tr("Change the tags assigned to this note"));\r
+ noteTags.triggered.connect(parent.browserWindow, "modifyTags()");\r
+ setupShortcut(noteTags, "File_Note_Modify_Tags");\r
+ \r
+ noteDelete = new QAction(tr("Delete"), this);\r
+ noteDelete.setToolTip(tr("Delete this note"));\r
+ noteDelete.triggered.connect(parent, "deleteNote()");\r
+ setupShortcut(noteDelete, "File_Note_Delete");\r
+ \r
+ editFind = new QAction(tr("Find In Note"), this);\r
+ editFind.setToolTip(tr("Find a string in the current note"));\r
+ editFind.triggered.connect(parent, "findText()");\r
+ setupShortcut(editFind, "Edit_Find_In_Note");\r
+ //editFind.setShortcut("Ctrl+F");\r
+ \r
+ editUndo = new QAction(tr("Undo"), this);\r
+ editUndo.setToolTip(tr("Undo"));\r
+ editUndo.triggered.connect(parent.browserWindow, "undoClicked()"); \r
+ setupShortcut(editUndo, "Edit_Undo");\r
+ //editUndo.setShortcut("Ctrl+Z");\r
+ \r
+ editRedo = new QAction(tr("Redo"), this);\r
+ editRedo.setToolTip(tr("Redo"));\r
+ editRedo.triggered.connect(parent.browserWindow, "redoClicked()");\r
+ setupShortcut(editRedo, "Edit_Redo");\r
+ //editRedo.setShortcut("Ctrl+Y");\r
+ \r
+ editCut = new QAction(tr("Cut"), this);\r
+ editCut.setToolTip(tr("Cut"));\r
+ editCut.triggered.connect(parent.browserWindow, "cutClicked()");\r
+ setupShortcut(editCut, "Edit_Cut");\r
+ //editCut.setShortcut("Ctrl+X");\r
+ \r
+ editCopy = new QAction(tr("Copy"), this);\r
+ editCopy.setToolTip(tr("Copy"));\r
+ editCopy.triggered.connect(parent.browserWindow, "copyClicked()");\r
+ setupShortcut(editCopy, "Edit_Copy");\r
+ //editCopy.setShortcut("Ctrl+C");\r
+ \r
+ editPaste = new QAction(tr("Paste"), this);\r
+ editPaste.setToolTip(tr("Paste"));\r
+ editPaste.triggered.connect(parent.browserWindow, "pasteClicked()");\r
+ setupShortcut(editPaste, "Edit_Paste");\r
+\r
+ editPasteWithoutFormat = new QAction(tr("Paste Without Formatting"), this);\r
+ editPasteWithoutFormat.setToolTip(tr("Paste Without Formatting"));\r
+ editPasteWithoutFormat.triggered.connect(parent.browserWindow, "pasteWithoutFormattingClicked()");\r
+ setupShortcut(editPasteWithoutFormat, "Edit_Paste_Without_Formatting");\r
+ \r
+ hideNoteList = new QAction(tr("Show Note List"), this);\r
+ hideNoteList.setToolTip("Show/Hide Note List");\r
+ hideNoteList.triggered.connect(parent, "toggleNoteListWindow()");\r
+ hideNoteList.setCheckable(true);\r
+ hideNoteList.setChecked(true);\r
+ setupShortcut(hideNoteList, "View_Show_Note_List");\r
+ \r
+ hideTags = new QAction(tr("Show Tags"), this);\r
+ hideTags.setToolTip("Show/Hide Tags");\r
+ hideTags.triggered.connect(parent, "toggleTagWindow()");\r
+ hideTags.setCheckable(true);\r
+ hideTags.setChecked(true);\r
+ setupShortcut(hideTags, "View_Show_Tags");\r
+ \r
+ hideNotebooks = new QAction(tr("Show Notebooks"), this);\r
+ hideNotebooks.setToolTip("Show/Hide Notebooks");\r
+ hideNotebooks.triggered.connect(parent, "toggleNotebookWindow()");\r
+ hideNotebooks.setCheckable(true);\r
+ hideNotebooks.setChecked(true);\r
+ setupShortcut(hideNotebooks, "View_Show_Notebooks");\r
+\r
+ thumbnailView = new QAction(tr("Preview"), this);\r
+ thumbnailView.setToolTip("Preview Notes");\r
+ thumbnailView.triggered.connect(parent, "thumbnailView()");\r
+ setupShortcut(thumbnailView, "View_Thumbnail");\r
+ \r
+ hideSavedSearches = new QAction(tr("Show Saved Searches"), this);\r
+ hideSavedSearches.setToolTip("Show/Hide Saved Searches");\r
+ hideSavedSearches.triggered.connect(parent, "toggleSavedSearchWindow()");\r
+ hideSavedSearches.setCheckable(true);\r
+ hideSavedSearches.setChecked(true);\r
+ setupShortcut(hideSavedSearches, "View_Show_SavedSearches");\r
+ \r
+ hideAttributes = new QAction(tr("Show Attribute Searches"), this);\r
+ hideAttributes.setToolTip("Show/Hide Attribute Searches");\r
+ hideAttributes.triggered.connect(parent, "toggleAttributesWindow()");\r
+ hideAttributes.setCheckable(true);\r
+ hideAttributes.setChecked(true);\r
+ setupShortcut(hideAttributes, "View_Show_Attribute_Searches");\r
+\r
+ hideTrash = new QAction(tr("Show Trash"), this);\r
+ hideTrash.setToolTip("Show/Hide Trash Tree");\r
+ hideTrash.triggered.connect(parent, "toggleTrashWindow()");\r
+ hideTrash.setCheckable(true);\r
+ hideTrash.setChecked(true);\r
+ setupShortcut(hideTrash, "View_Show_Trash");\r
+ \r
+\r
+ showEditorBar = new QAction(tr("Show Editor Button Bar"), this);\r
+ showEditorBar.setToolTip("Show/Hide Editor Button Bar");\r
+ showEditorBar.triggered.connect(parent, "toggleEditorButtonBar()");\r
+ showEditorBar.setCheckable(true);\r
+ showEditorBar.setChecked(true);\r
+ setupShortcut(showEditorBar, "View_Show_Editor_Button_Bar");\r
+ \r
+\r
+ hideLeftSide = new QAction(tr("Hide Left Side Panels"), this);\r
+ hideLeftSide.setToolTip("Hide The Entire Left Side");\r
+ hideLeftSide.triggered.connect(parent, "toggleLeftSide()");\r
+ hideLeftSide.setCheckable(true);\r
+ hideLeftSide.setChecked(false);\r
+ setupShortcut(hideLeftSide, "View_Show_Left_Side");\r
+ //hideLeftSide.setShortcut("F11");\r
+\r
+ alignLeftAction = new QAction(tr("Left"), this);\r
+ alignLeftAction.setToolTip(tr("Left Align"));\r
+ alignLeftAction.triggered.connect(parent.browserWindow, "justifyLeftClicked()");\r
+ setupShortcut(alignLeftAction, "Format_Alignment_Left");\r
+ //alignLeftAction.setShortcut("Ctrl+L");\r
+ \r
+ alignRightAction = new QAction(tr("Right"), this);\r
+ alignRightAction.setToolTip(tr("Right Align"));\r
+ alignRightAction.triggered.connect(parent.browserWindow, "justifyRightClicked()");\r
+ setupShortcut(alignRightAction, "Format_Alignment_Right");\r
+ //alignRightAction.setShortcut("Ctrl+R");\r
+ \r
+ alignCenterAction = new QAction(tr("Center"), this);\r
+ alignCenterAction.setToolTip(tr("Center Align"));\r
+ alignCenterAction.triggered.connect(parent.browserWindow, "justifyCenterClicked()");\r
+ setupShortcut(alignCenterAction, "Format_Alignment_Center");\r
+ //alignCenterAction.setShortcut("Ctrl+C");\r
+ \r
+ formatBold = new QAction(tr("Bold"), this);\r
+ formatBold.setToolTip(tr("Bold"));\r
+ formatBold.triggered.connect(parent.browserWindow, "boldClicked()");\r
+ setupShortcut(formatBold, "Format_Bold");\r
+ //formatBold.setShortcut("Ctrl+B");\r
+ \r
+ formatItalic = new QAction(tr("Italic"), this);\r
+ formatItalic.setToolTip(tr("Italic"));\r
+ formatItalic.triggered.connect(parent.browserWindow, "italicClicked()");\r
+ setupShortcut(formatItalic, "Format_Italic");\r
+ //formatItalic.setShortcut("Ctrl+I");\r
+ \r
+ formatUnderline = new QAction(tr("Underline"), this);\r
+ formatUnderline.setToolTip(tr("Underline"));\r
+ formatUnderline.triggered.connect(parent.browserWindow, "underlineClicked()");\r
+ setupShortcut(formatUnderline, "Format_Underline");\r
+// formatUnderline.setShortcut("Ctrl+U");\r
+\r
+ \r
+ formatSuperscript = new QAction(tr("Superscript"), this);\r
+ formatSuperscript.setToolTip(tr("Superscript"));\r
+ formatSuperscript.triggered.connect(parent.browserWindow, "superscriptClicked()");\r
+ setupShortcut(formatSuperscript, "Format_Superscript");\r
+\r
+\r
+ formatSubscript = new QAction(tr("Subscript"), this);\r
+ formatSubscript.setToolTip(tr("Subscript"));\r
+ formatSubscript.triggered.connect(parent.browserWindow, "subscriptClicked()");\r
+ setupShortcut(formatSubscript, "Format_Subscript");\r
+\r
+ \r
+ formatStrikethrough = new QAction(tr("Strikethrough"), this);\r
+ formatStrikethrough.setToolTip(tr("Strikethrough"));\r
+ formatStrikethrough.triggered.connect(parent.browserWindow, "strikethroughClicked()");\r
+ setupShortcut(formatStrikethrough, "Format_Strikethrough");\r
+\r
+ horizontalLineAction = new QAction(tr("Horizontal Line"), this);\r
+ horizontalLineAction.setToolTip(tr("Horizontal Line"));\r
+ horizontalLineAction.triggered.connect(parent.browserWindow, "hlineClicked()");\r
+ setupShortcut(horizontalLineAction, "Format_Horizontal_Line");\r
+ \r
+ formatBulletList = new QAction(tr("Bulleted List"), this);\r
+// formatBulletList.setText(tr("Numbered List"));\r
+ formatBulletList.triggered.connect(parent.browserWindow, "bulletListClicked()");\r
+ setupShortcut(formatBulletList, "Format_List_Bullet");\r
+// formatBulletList.setShortcut("Ctrl+Shift+B");\r
+ \r
+ formatNumberList = new QAction(tr("Numbered List"), this);\r
+ formatNumberList.setText(tr("Numbered list"));\r
+ formatNumberList.triggered.connect(parent.browserWindow, "numberListClicked()");\r
+ setupShortcut(formatNumberList, "Format_List_Numbered");\r
+// formatNumberList.setShortcut("Ctrl+Shift+O");\r
+\r
+ indentAction = new QAction(tr(">> Increase"), this);\r
+ indentAction.setText(tr(">> Increase"));\r
+ indentAction.triggered.connect(parent.browserWindow, "indentClicked()");\r
+ setupShortcut(indentAction, "Format_Indent_Increase");\r
+ //indentAction.setShortcut("Ctrl+M");\r
+\r
+ outdentAction = new QAction(tr("<< Decrease"), this);\r
+ outdentAction.setText(tr("<< Decrease"));\r
+ outdentAction.triggered.connect(parent.browserWindow, "outdentClicked()");\r
+ setupShortcut(outdentAction, "Format_Indent_Decrease");\r
+ //outdentAction.setShortcut("Ctrl+Shift+M");\r
+ \r
+ notebookAddAction = new QAction(tr("Add"), this);\r
+ notebookAddAction.triggered.connect(parent, "addNotebook()");\r
+ setupShortcut(notebookAddAction, "File_Notebook_Add");\r
+ \r
+ notebookEditAction = new QAction(tr("Edit"), this);\r
+ notebookEditAction.setEnabled(false);\r
+ notebookEditAction.triggered.connect(parent, "editNotebook()");\r
+ setupShortcut(notebookEditAction, "File_Notebook_Edit");\r
+ \r
+ notebookDeleteAction = new QAction(tr("Delete"), this);\r
+ notebookDeleteAction.setEnabled(false);\r
+ notebookDeleteAction.triggered.connect(parent, "deleteNotebook()");\r
+ setupShortcut(notebookDeleteAction, "File_Notebook_Delete");\r
+ \r
+ notebookCloseAction = new QAction(tr("Open/Close Notebooks"), this);\r
+// if (!Global.mimicEvernoteInterface) {\r
+ notebookCloseAction.setEnabled(true);\r
+ notebookCloseAction.triggered.connect(parent, "closeNotebooks()");\r
+ setupShortcut(notebookCloseAction, "File_Notebook_Close");\r
+// } else {\r
+// notebookCloseAction.setEnabled(false); \r
+// }\r
+ \r
+ tagAddAction = new QAction(tr("Add"),this);\r
+ tagAddAction.triggered.connect(parent, "addTag()");\r
+ //tagAddAction.setShortcut("Ctrl+Shift+T");\r
+ setupShortcut(tagAddAction, "File_Tag_Add");\r
+ \r
+ tagEditAction = new QAction(tr("Edit"), this);\r
+ tagEditAction.triggered.connect(parent, "editTag()");\r
+ tagEditAction.setEnabled(false);\r
+ setupShortcut(tagEditAction, "File_Tag_Edit");\r
+ \r
+ tagDeleteAction = new QAction(tr("Delete"), this);\r
+ tagDeleteAction.triggered.connect(parent, "deleteTag()");\r
+ tagDeleteAction.setEnabled(false); \r
+ setupShortcut(tagDeleteAction, "File_Tag_Delete");\r
+ \r
+ savedSearchAddAction = new QAction(tr("Add"),this);\r
+ savedSearchAddAction.triggered.connect(parent, "addSavedSearch()");\r
+ setupShortcut(savedSearchAddAction, "File_SavedSearch_Add");\r
+ \r
+ savedSearchEditAction = new QAction(tr("Edit"), this);\r
+ savedSearchEditAction.triggered.connect(parent, "editSavedSearch()");\r
+ savedSearchEditAction.setEnabled(false);\r
+ setupShortcut(savedSearchEditAction, "File_SavedSearch_Edit");\r
+ \r
+ savedSearchDeleteAction = new QAction(tr("Delete"), this);\r
+ savedSearchDeleteAction.triggered.connect(parent, "deleteSavedSearch()");\r
+ savedSearchDeleteAction.setEnabled(false); \r
+ setupShortcut(savedSearchDeleteAction, "File_SavedSearch_Delete");\r
+ \r
+ \r
+ connectAction = new QAction(tr("Connect"), this);\r
+ connectAction.setToolTip("Connect to Evernote");\r
+ connectAction.triggered.connect(parent, "remoteConnect()");\r
+ setupShortcut(connectAction, "Online_Connect");\r
+ \r
+ synchronizeAction = new QAction(tr("Synchronize with Evernote"), this);\r
+ synchronizeAction.setToolTip("Delete all local data & get a fresh copy");\r
+ synchronizeAction.triggered.connect(parent, "evernoteSync()");\r
+ synchronizeAction.setEnabled(false);\r
+ setupShortcut(synchronizeAction, "Online_Synchronize");\r
+ //synchronizeAction.setShortcut("F9");\r
+ \r
+ noteOnlineHistoryAction = new QAction(tr("Note History"), this);\r
+ noteOnlineHistoryAction.triggered.connect(parent, "viewNoteHistory()");\r
+ noteOnlineHistoryAction.setEnabled(false);\r
+ setupShortcut(noteOnlineHistoryAction, "Online_Note_History");\r
+ \r
+ \r
+ \r
+ \r
+ \r
+ accountAction = new QAction(tr("Account Information"), this);\r
+ accountAction.setToolTip(tr("Account Information"));\r
+ accountAction.triggered.connect(parent, "accountInformation()");\r
+ setupShortcut(accountAction, "Tools_Account_Information");\r
+ \r
+// compactAction = new QAction(tr("Compact Database"), this);\r
+// compactAction.setToolTip(tr("Free unused database space"));\r
+// compactAction.triggered.connect(parent, "compactDatabase()");\r
+// setupShortcut(compactAction, "Tools_Compact_Database");\r
+\r
+ databaseStatusAction = new QAction(tr("Database Status"), this);\r
+ databaseStatusAction.setToolTip(tr("Show current database information"));\r
+ databaseStatusAction.triggered.connect(parent, "databaseStatus()");\r
+ setupShortcut(databaseStatusAction, "Tools_Database_Status");\r
+ \r
+ \r
+ disableIndexing = new QAction(tr("Disable Note Indexing"), this);\r
+ disableIndexing.setToolTip("Manually Stop Note Indexing");\r
+ disableIndexing.triggered.connect(parent, "toggleNoteIndexing()");\r
+ disableIndexing.setCheckable(true);\r
+ disableIndexing.setChecked(false);\r
+ setupShortcut(disableIndexing, "Tools_Disable_Note_Indexing");\r
+ \r
+ \r
+ folderImportAction = new QAction(tr("Automatic Folder Importing"), this);\r
+ folderImportAction.setToolTip("Import Files Automatically");\r
+ folderImportAction.triggered.connect(parent, "folderImport()");\r
+ setupShortcut(folderImportAction, "Tools_Folder_Import");\r
+\r
+\r
+ loggerAction = new QAction(tr("Log"), this);\r
+ loggerAction.setToolTip("Show the detailed application log");\r
+ loggerAction.triggered.connect(parent, "logger()");\r
+ setupShortcut(loggerAction, "About_Log");\r
+ \r
+ releaseAction = new QAction(tr("Release Notes"), this);\r
+ releaseAction.setToolTip("Release notes");\r
+ releaseAction.triggered.connect(parent, "releaseNotes()"); \r
+ setupShortcut(releaseAction, "About_Release_Notes");\r
+ \r
+ aboutAction = new QAction(tr("About"), this);\r
+ aboutAction.setToolTip("About NeverNote");\r
+ aboutAction.triggered.connect(parent, "about()"); \r
+ setupShortcut(aboutAction, "About_About");\r
+ \r
+ setupMenuBar();\r
+ }\r
+ \r
+ public void setupMenuBar() {\r
+ fileMenu = addMenu(tr("&File"));\r
+ \r
+ noteMenu = fileMenu.addMenu(tr("&Note"));\r
+ notebookMenu = fileMenu.addMenu(tr("Notebook"));\r
+ tagMenu = fileMenu.addMenu(tr("Tag"));\r
+ savedSearchMenu = fileMenu.addMenu(tr("Saved Searches"));\r
+ fileMenu.addSeparator();\r
+ fileMenu.addAction(emailAction);\r
+ fileMenu.addAction(printAction);\r
+ fileMenu.addSeparator();\r
+ fileMenu.addAction(noteImportAction);\r
+ fileMenu.addAction(noteExportAction);\r
+ fileMenu.addAction(backupAction);\r
+ fileMenu.addAction(restoreAction);\r
+ fileMenu.addSeparator();\r
+ fileMenu.addAction(emptyTrashAction);\r
+ fileMenu.addAction(exitAction);\r
+\r
+ editMenu = addMenu("&Edit");\r
+ editMenu.addAction(editFind);\r
+ editMenu.addSeparator();\r
+ editMenu.addAction(editUndo);\r
+ editMenu.addAction(editRedo);\r
+ editMenu.addSeparator();\r
+ editMenu.addAction(editCut);\r
+ editMenu.addAction(editCopy);\r
+ editMenu.addAction(editPaste);\r
+ editMenu.addAction(editPasteWithoutFormat);\r
+ editMenu.addSeparator();\r
+ editMenu.addAction(settingsAction);\r
+ \r
+ viewMenu = addMenu("&View");\r
+ viewMenu.addAction(noteAttributes);\r
+ viewMenu.addSeparator();\r
+ viewMenu.addAction(thumbnailView);\r
+ viewMenu.addSeparator();\r
+ viewMenu.addAction(hideNoteList);\r
+ viewMenu.addAction(hideNotebooks);\r
+ viewMenu.addAction(hideTags);\r
+ viewMenu.addAction(hideAttributes);\r
+ viewMenu.addAction(hideSavedSearches);\r
+ viewMenu.addAction(hideTrash);\r
+ viewMenu.addAction(showEditorBar);\r
+ viewMenu.addAction(hideLeftSide);\r
+ \r
+ formatMenu = addMenu("&Format");\r
+ formatMenu.addAction(formatBold);\r
+ formatMenu.addAction(formatUnderline);\r
+ formatMenu.addAction(formatItalic);\r
+ formatMenu.addSeparator();\r
+ formatMenu.addAction(formatStrikethrough);\r
+ formatMenu.addAction(horizontalLineAction);\r
+ formatMenu.addSeparator();\r
+ formatMenu.addAction(formatSuperscript);\r
+ formatMenu.addAction(formatSubscript);\r
+ formatMenu.addSeparator();\r
+\r
+ alignMenu = formatMenu.addMenu(tr("Alignment"));\r
+ alignMenu.addAction(alignLeftAction);\r
+ alignMenu.addAction(alignCenterAction);\r
+ alignMenu.addAction(alignRightAction);\r
+ \r
+ listMenu = formatMenu.addMenu(tr("Lists"));\r
+ listMenu.addAction(formatBulletList);\r
+ listMenu.addAction(formatNumberList);\r
+ indentMenu = formatMenu.addMenu(tr("Indent"));\r
+ indentMenu.addAction(indentAction);\r
+ indentMenu.addAction(outdentAction);\r
+ \r
+ noteAttributes.setCheckable(true);\r
+ noteMenu.addAction(noteAdd);\r
+ noteMenu.addAction(noteDelete);\r
+ noteMenu.addAction(noteReindex);\r
+ noteMenu.addSeparator();\r
+ noteMenu.addAction(noteTags);\r
+ noteMenu.addAction(noteRestoreAction);\r
+ noteMenu.addSeparator();\r
+ noteMenu.addAction(noteDuplicateAction);\r
+ noteMenu.addAction(noteMergeAction);\r
+\r
+ \r
+ notebookMenu.addAction(notebookAddAction);\r
+ notebookMenu.addAction(notebookEditAction);\r
+ notebookMenu.addAction(notebookDeleteAction);\r
+// if (!Global.mimicEvernoteInterface) {\r
+ notebookMenu.addSeparator();\r
+ notebookMenu.addAction(notebookCloseAction);\r
+// }\r
+ \r
+ tagMenu.addAction(tagAddAction);\r
+ tagMenu.addAction(tagEditAction);\r
+ tagMenu.addAction(tagDeleteAction);\r
+ \r
+ savedSearchMenu.addAction(savedSearchAddAction);\r
+ savedSearchMenu.addAction(savedSearchEditAction);\r
+ savedSearchMenu.addAction(savedSearchDeleteAction);\r
+ \r
+ onlineMenu = addMenu(tr("&Online"));\r
+ onlineMenu.addAction(synchronizeAction);\r
+ onlineMenu.addAction(connectAction);\r
+ onlineMenu.addSeparator();\r
+ onlineMenu.addAction(noteOnlineHistoryAction);\r
+ \r
+ toolsMenu = addMenu(tr("&Tools"));\r
+ toolsMenu.addAction(accountAction);\r
+ toolsMenu.addAction(fullReindexAction);\r
+ toolsMenu.addAction(disableIndexing);\r
+// toolsMenu.addAction(compactAction);\r
+ toolsMenu.addAction(databaseStatusAction);\r
+ toolsMenu.addSeparator();\r
+ toolsMenu.addAction(folderImportAction);\r
+\r
+ helpMenu = addMenu(tr("&Help"));\r
+ helpMenu.addAction(releaseAction);\r
+ helpMenu.addAction(loggerAction);\r
+ helpMenu.addSeparator();\r
+ helpMenu.addAction(aboutAction);\r
+ \r
+ addMenu(fileMenu);\r
+ addMenu(editMenu);\r
+ addMenu(viewMenu);\r
+ addMenu(formatMenu);\r
+ addMenu(onlineMenu);\r
+ addMenu(toolsMenu);\r
+ addMenu(helpMenu);\r
+\r
+ }\r
+\r
+ \r
+ private void setupShortcut(QAction action, String text) {\r
+ if (!Global.shortcutKeys.containsAction(text))\r
+ return;\r
+ action.setShortcut(Global.shortcutKeys.getShortcut(text));\r
+ }\r
+\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.gui;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.Notebook;\r
+import com.trolltech.qt.core.QByteArray;\r
+import com.trolltech.qt.core.QMimeData;\r
+import com.trolltech.qt.core.Qt;\r
+import com.trolltech.qt.core.Qt.SortOrder;\r
+import com.trolltech.qt.gui.QAbstractItemView;\r
+import com.trolltech.qt.gui.QAction;\r
+import com.trolltech.qt.gui.QBrush;\r
+import com.trolltech.qt.gui.QColor;\r
+import com.trolltech.qt.gui.QContextMenuEvent;\r
+import com.trolltech.qt.gui.QDragEnterEvent;\r
+import com.trolltech.qt.gui.QDragMoveEvent;\r
+import com.trolltech.qt.gui.QHeaderView;\r
+import com.trolltech.qt.gui.QIcon;\r
+import com.trolltech.qt.gui.QMenu;\r
+import com.trolltech.qt.gui.QTreeWidget;\r
+import com.trolltech.qt.gui.QTreeWidgetItem;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.filters.NotebookCounter;\r
+import cx.fbn.nevernote.signals.NoteSignal;\r
+\r
+public class NotebookTreeWidget extends QTreeWidget {\r
+ private QAction deleteAction;\r
+ private QAction addAction;\r
+ private QAction editAction;\r
+ public NoteSignal noteSignal;\r
+// private final QTreeWidgetItem previousMouseOver;\r
+// private boolean previousMouseOverWasSelected;\r
+ \r
+ public void setAddAction(QAction a) {\r
+ addAction = a;\r
+ }\r
+ \r
+ public void setDeleteAction(QAction d) {\r
+ deleteAction = d;\r
+ }\r
+ \r
+ public void setEditAction(QAction e) {\r
+ editAction = e;\r
+ }\r
+ \r
+ public NotebookTreeWidget() {\r
+ noteSignal = new NoteSignal();\r
+ List<String> labels = new ArrayList<String>();\r
+ labels.add("Notebooks");\r
+ labels.add("");\r
+ setAcceptDrops(true);\r
+ setDragEnabled(true);\r
+ setColumnCount(2);\r
+ header().setResizeMode(0, QHeaderView.ResizeMode.ResizeToContents);\r
+ header().setResizeMode(1, QHeaderView.ResizeMode.Stretch);\r
+ header().setMovable(false);\r
+ setHeaderLabels(labels);\r
+ setDragDropMode(QAbstractItemView.DragDropMode.DragDrop);\r
+ // If we want to mimic Evernote's notebook selection\r
+ if (Global.mimicEvernoteInterface) {\r
+ setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection);\r
+ } else\r
+ setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection);\r
+\r
+// int width = Global.getColumnWidth("notebookTreeName");\r
+// if (width>0)\r
+// setColumnWidth(0, width);\r
+// previousMouseOver = new QTreeWidgetItem();\r
+ }\r
+ \r
+ public void selectNotebook(QTreeWidgetItem item) {\r
+ QTreeWidgetItem root = invisibleRootItem();\r
+ QTreeWidgetItem child;\r
+ \r
+ for (int i=0; i<root.childCount(); i++) {\r
+ child = root.child(i); \r
+ if (child.text(2).equals(item.text(2))) {\r
+ child.setSelected(true);\r
+ return;\r
+ }\r
+ }\r
+ \r
+ }\r
+ \r
+ public boolean selectGuid(String guid) {\r
+ QTreeWidgetItem root = invisibleRootItem();\r
+ QTreeWidgetItem child;\r
+\r
+ for (int i=0; i<root.childCount(); i++) {\r
+ child = root.child(i);\r
+ if (child.text(2).equals(guid)) {\r
+ child.setSelected(true);\r
+ return true;\r
+ }\r
+ }\r
+ return false;\r
+ }\r
+ \r
+ \r
+ public void load(List<Notebook> books, List<String> localBooks) {\r
+ Notebook book;\r
+ QTreeWidgetItem child;\r
+ clear();\r
+ String iconPath = new String("classpath:cx/fbn/nevernote/icons/");\r
+ QIcon blueIcon = new QIcon(iconPath+"notebook-blue.png");\r
+ QIcon greenIcon = new QIcon(iconPath+"notebook-green.png");\r
+ QIcon redIcon = new QIcon(iconPath+"notebook-red.png");\r
+ QIcon yellowIcon = new QIcon(iconPath+"notebook-yellow.png");\r
+// QIcon icon = new QIcon(iconPath+"nevernote.png");\r
+ if (books == null)\r
+ return;\r
+ Qt.Alignment ra = new Qt.Alignment(Qt.AlignmentFlag.AlignRight);\r
+ for (int i=0; i<books.size(); i++) {\r
+ book = books.get(i);\r
+ child = new QTreeWidgetItem();\r
+ child.setText(0, book.getName());\r
+ child.setIcon(0, greenIcon);\r
+ if (localBooks.contains(book.getGuid()))\r
+ child.setIcon(0, yellowIcon);\r
+ if (localBooks.contains(book.getGuid()) && \r
+ (book.getName().equalsIgnoreCase("Conflicting Changes") ||\r
+ book.getName().equalsIgnoreCase("Conflicting Changes (Local)")))\r
+ child.setIcon(0, redIcon);\r
+ if (book.isPublished())\r
+ child.setIcon(0, blueIcon);\r
+ child.setTextAlignment(1, ra.value());\r
+ child.setText(2, book.getGuid());\r
+ addTopLevelItem(child);\r
+ }\r
+\r
+ sortItems(0, SortOrder.AscendingOrder); \r
+ if (Global.mimicEvernoteInterface) {\r
+ child = new QTreeWidgetItem();\r
+ child.setIcon(0, greenIcon);\r
+ child.setText(0, "All Notebooks");\r
+// child.setText(1, "0");\r
+ child.setText(2, "");\r
+ child.setTextAlignment(1, ra.value());\r
+ insertTopLevelItem(0,child);\r
+ }\r
+ resizeColumnToContents(0);\r
+ resizeColumnToContents(1);\r
+ }\r
+ // update the display with the current number of notes\r
+ public void updateCounts(List<Notebook> books, List<NotebookCounter> counts) {\r
+ QTreeWidgetItem root = invisibleRootItem();\r
+ QTreeWidgetItem child;\r
+ \r
+ QBrush blue = new QBrush();\r
+ QBrush black = new QBrush();\r
+ black.setColor(QColor.black);\r
+ if (Global.tagBehavior().equalsIgnoreCase("ColorActive") && !Global.mimicEvernoteInterface)\r
+ blue.setColor(QColor.blue);\r
+ else\r
+ blue.setColor(QColor.black);\r
+ int total=0;\r
+ \r
+// for (int i=0; i<counts.size(); i++) {\r
+// total=total+counts.get(i).getCount();\r
+// }\r
+ \r
+ int size = books.size();\r
+ if (Global.mimicEvernoteInterface)\r
+ size++;\r
+ \r
+ for (int i=0; i<size; i++) {\r
+ child = root.child(i); \r
+ if (child != null) {\r
+ String guid = child.text(2);\r
+ child.setText(1,"0");\r
+ child.setForeground(0, black);\r
+ child.setForeground(1, black);\r
+ for (int j=0; j<counts.size(); j++) {\r
+ if (counts.get(j).getGuid().equals(guid)) {\r
+ child.setText(1, new Integer(counts.get(j).getCount()).toString());\r
+ total = total+counts.get(j).getCount();\r
+ if (counts.get(j).getCount() > 0) {\r
+ child.setForeground(0, blue);\r
+ child.setForeground(1, blue);\r
+ }\r
+ }\r
+// if (guid.equals("") && Global.mimicEvernoteInterface) {\r
+// child.setText(1, new Integer(total).toString());\r
+// }\r
+ }\r
+ }\r
+ }\r
+ \r
+ for (int i=0; i<size; i++) {\r
+ child = root.child(i); \r
+ if (child != null) {\r
+ String guid = child.text(2);\r
+ if (guid.equals("") && Global.mimicEvernoteInterface) \r
+ child.setText(1, new Integer(total).toString());\r
+ }\r
+ }\r
+ }\r
+ // Return a list of the notebook guids, ordered by the current display order.\r
+ public List<String> getNotebookGuids() {\r
+ List<String> names = new ArrayList<String>();\r
+ QTreeWidgetItem root = invisibleRootItem();\r
+ QTreeWidgetItem child;\r
+ for (int i=0; i<root.childCount(); i++) {\r
+ child = root.child(i);\r
+ String text = child.text(2);\r
+ names.add(text);\r
+ }\r
+ return names;\r
+ }\r
+ \r
+ @Override\r
+ public void contextMenuEvent(QContextMenuEvent event) {\r
+ QMenu menu = new QMenu(this);\r
+ menu.addAction(addAction);\r
+ menu.addAction(editAction);\r
+ menu.addAction(deleteAction);\r
+ menu.exec(event.globalPos());\r
+ }\r
+ \r
+ \r
+ @Override\r
+ public void dragEnterEvent(QDragEnterEvent event) {\r
+ if (event.mimeData().hasFormat("application/x-nevernote-note")) {\r
+ event.accept();\r
+ return;\r
+ }\r
+ }\r
+ \r
+ \r
+ @Override\r
+ protected void dragMoveEvent(QDragMoveEvent event) {\r
+ // if (event.mimeData().hasFormat("text/plain") &&\r
+ //event.answerRect().intersects(dropFrame.geometry()))\r
+ QTreeWidgetItem treeItem = itemAt(event.pos().x(), event.pos().y());\r
+ if (treeItem != null) {\r
+/* if (!previousMouseOver.text(0).equalsIgnoreCase(treeItem.text(0))) {\r
+ previousMouseOver.setSelected(previousMouseOverWasSelected);\r
+ previousMouseOverWasSelected = treeItem.isSelected();\r
+ previousMouseOver = treeItem;\r
+ blockSignals(true);\r
+ treeItem.setSelected(true);\r
+ blockSignals(false);\r
+ }\r
+*/ \r
+ }\r
+ if (event.mimeData().hasFormat("application/x-nevernote-note")) {\r
+ if (event.answerRect().intersects(childrenRect()))\r
+ event.acceptProposedAction();\r
+ return;\r
+ }\r
+ }\r
+\r
+ \r
+ @Override\r
+ public boolean dropMimeData(QTreeWidgetItem parent, int index, QMimeData data, Qt.DropAction action) {\r
+ if (data.hasFormat("application/x-nevernote-note")) {\r
+ QByteArray d = data.data("application/x-nevernote-note");\r
+ String s = d.toString();\r
+ String noteGuidArray[] = s.split(" ");\r
+ for (String element : noteGuidArray) {\r
+ if (!parent.text(0).equalsIgnoreCase("All Notebooks"))\r
+ noteSignal.notebookChanged.emit(element.trim(), parent.text(2));\r
+ }\r
+ return true;\r
+ }\r
+ return false;\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.gui;\r
+\r
+import java.awt.Image;\r
+import java.awt.Rectangle;\r
+import java.awt.image.BufferedImage;\r
+import java.io.File;\r
+import java.io.RandomAccessFile;\r
+import java.nio.ByteBuffer;\r
+import java.nio.channels.FileChannel;\r
+\r
+import javax.imageio.ImageIO;\r
+import javax.swing.ImageIcon;\r
+\r
+import com.sun.pdfview.PDFFile;\r
+import com.sun.pdfview.PDFPage;\r
+\r
+public class PDFPreview {\r
+\r
+ public int getPageCount(String filePath) {\r
+ File file = new File(filePath);\r
+ RandomAccessFile raf;\r
+ try {\r
+ raf = new RandomAccessFile(file, "r");\r
+ FileChannel channel = raf.getChannel();\r
+ ByteBuffer buf = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());\r
+ PDFFile pdffile = new PDFFile(buf);\r
+ return pdffile.getNumPages();\r
+ } catch (Exception e) {\r
+ return 0;\r
+ }\r
+ \r
+ }\r
+ \r
+ // Setup the preview for PDFs\r
+ public boolean setupPreview(String filePath, String appl, int pageNumber) {\r
+ // Fix stupid Windows file separation characters\r
+ String whichOS = System.getProperty("os.name");\r
+ if (whichOS.contains("Windows")) {\r
+ filePath = filePath.replace("\\","/");\r
+ }\r
+ if (appl.equals("pdf")) {\r
+ \r
+ try {\r
+ File file = new File(filePath);\r
+ RandomAccessFile raf = new RandomAccessFile(file, "r");\r
+ FileChannel channel = raf.getChannel();\r
+ ByteBuffer buf = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());\r
+ PDFFile pdffile = new PDFFile(buf);\r
+ \r
+ // draw the first page to an image\r
+ PDFPage page = pdffile.getPage(pageNumber);\r
+ //get the width and height for the doc at the default zoom \r
+ Rectangle rect = new Rectangle(0,0,\r
+ (int)page.getBBox().getWidth(),\r
+ (int)page.getBBox().getHeight()); \r
+ \r
+ //generate the image\r
+ Image img = page.getImage(\r
+ rect.width, rect.height, //width & height\r
+ rect, // clip rect\r
+ null, // null for the ImageObserver\r
+ true, // fill background with white\r
+ true // block until drawing is done\r
+ );\r
+ ImageIcon icon = new ImageIcon(img);\r
+ BufferedImage bi = new BufferedImage(icon.getIconWidth(), icon.getIconHeight(), BufferedImage.TYPE_INT_RGB);\r
+ bi.getGraphics().drawImage(icon.getImage(), 0, 0, null);\r
+ File outputfile;\r
+// if (pageNumber == 0)\r
+ outputfile = new File(filePath +".png");\r
+// else\r
+// outputfile = new File(filePath+"-page-"+pageNumber+".png");\r
+ ImageIO.write(bi, "png", outputfile);\r
+ return true;\r
+ } catch (Exception e) {}\r
+ }\r
+ return false;\r
+\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.gui;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.SavedSearch;\r
+import com.trolltech.qt.core.Qt.SortOrder;\r
+import com.trolltech.qt.gui.QAbstractItemView;\r
+import com.trolltech.qt.gui.QAction;\r
+import com.trolltech.qt.gui.QContextMenuEvent;\r
+import com.trolltech.qt.gui.QIcon;\r
+import com.trolltech.qt.gui.QMenu;\r
+import com.trolltech.qt.gui.QTreeWidget;\r
+import com.trolltech.qt.gui.QTreeWidgetItem;\r
+\r
+public class SavedSearchTreeWidget extends QTreeWidget {\r
+ private QAction editAction;\r
+ private QAction deleteAction;\r
+ private QAction addAction;\r
+ \r
+ \r
+ public SavedSearchTreeWidget() {\r
+// setAcceptDrops(true);\r
+// setDragEnabled(true);\r
+ setAcceptDrops(false);\r
+ setDragEnabled(false);\r
+// setDragDropMode(QAbstractItemView.DragDropMode.DragDrop);\r
+ setHeaderLabel("Saved Searches");\r
+ setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection);\r
+ }\r
+ \r
+ public void setEditAction(QAction e) {\r
+ editAction = e;\r
+ }\r
+ public void setDeleteAction(QAction d) {\r
+ deleteAction = d;\r
+ }\r
+ public void setAddAction(QAction a) {\r
+ addAction = a;\r
+ }\r
+ \r
+ public void load(List<SavedSearch> tempList) {\r
+ SavedSearch search;\r
+ List<QTreeWidgetItem> index = new ArrayList<QTreeWidgetItem>();\r
+ \r
+ //Clear out the tree & reload\r
+ clear();\r
+ String iconPath = new String("classpath:cx/fbn/nevernote/icons/");\r
+ QIcon icon = new QIcon(iconPath+"search.png");\r
+ \r
+ for (int i=0; i<tempList.size(); i++) {\r
+ search = tempList.get(i);\r
+ QTreeWidgetItem child = new QTreeWidgetItem();\r
+ child.setText(0, search.getName());\r
+ child.setIcon(0,icon);\r
+ child.setText(1, search.getGuid());\r
+ index.add(child);\r
+ addTopLevelItem(child);\r
+ } \r
+ sortItems(0, SortOrder.AscendingOrder);\r
+ }\r
+\r
+ \r
+ public boolean selectGuid(String guid) {\r
+ QTreeWidgetItem root = invisibleRootItem();\r
+ QTreeWidgetItem child;\r
+\r
+ for (int i=0; i<root.childCount(); i++) {\r
+ child = root.child(i);\r
+ if (child.text(1).equals(guid)) {\r
+ child.setSelected(true);\r
+ return true;\r
+ }\r
+ }\r
+ return false;\r
+ }\r
+ \r
+ \r
+ @Override\r
+ public void contextMenuEvent(QContextMenuEvent event) {\r
+ QMenu menu = new QMenu(this);\r
+ menu.addAction(addAction);\r
+ menu.addAction(editAction);\r
+ menu.addAction(deleteAction);\r
+ menu.exec(event.globalPos());\r
+ }\r
+ \r
+ \r
+ public void selectSavedSearch(QTreeWidgetItem item) {\r
+ QTreeWidgetItem root = invisibleRootItem();\r
+ QTreeWidgetItem child;\r
+ \r
+ for (int i=0; i<root.childCount(); i++) {\r
+ child = root.child(i); \r
+ if (child.text(1).equals(item.text(1))) {\r
+ child.setSelected(true);\r
+ return;\r
+ }\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.gui;\r
+\r
+import java.io.File;\r
+import java.io.FileNotFoundException;\r
+import java.util.HashMap;\r
+import java.util.Scanner;\r
+import java.util.Vector;\r
+\r
+import cx.fbn.nevernote.Global;\r
+\r
+public class ShortcutKeys {\r
+ public String File_Note_Add; // Add a new note\r
+ public String File_Note_Reindex; // Reindex the current note\r
+ public String File_Note_Modify_Tags; // Change current note tags\r
+ public String File_Note_Delete; // Delete a tag\r
+ public String File_Note_Restore; // Undelete a note\r
+ public String File_Note_Duplicate; // duplicate a note\r
+ public String File_Notebook_Add; // Add a notebook\r
+ public String File_Notebook_Edit; // Edit an existing notebook\r
+ public String File_Notebook_Delete; // Delete the existing notebook\r
+ public String File_Notebook_Open; // Open a closed (i.e. archived) notebook\r
+ public String File_Notebook_Close; // Close (i.e. archive) a notebook\r
+ public String File_Tag_Add; // Add a notebook\r
+ public String File_Tag_Edit; // Edit an existing notebook\r
+ public String File_Tag_Delete; // Delete the existing notebook\r
+ public String File_SavedSearch_Add; // Add a notebook\r
+ public String File_SavedSearch_Edit; // Edit an existing notebook\r
+ public String File_SavedSearch_Delete; // Delete the existing notebook\r
+ public String File_Email; // Email note\r
+ public String File_Print; // Print\r
+ public String File_Backup; // Backup the database\r
+ public String File_Restore; // Restore the database\r
+ public String File_Empty_Trash; // Purge all delete notes\r
+ public String File_Exit; // I'm outahere\r
+\r
+ public String Edit_Find_In_Note; // Search only within the current note\r
+ public String Edit_Undo; // Undo last change\r
+ public String Edit_Redo; // Redo the last undone change\r
+ public String Edit_Cut; // Cut current selection to the clipboard\r
+ public String Edit_Copy; // Copy the current selection to the clipboard\r
+ public String Edit_Paste; // Paste\r
+ public String Edit_Paste_Without_Formatting; // Paste as plain text\r
+ public String Edit_Preferences; // Settings dialog box\r
+ public String Edit_Insert_Hyperlink; // Encrypt selected text\r
+ public String Edit_Insert_Table; // Insert table into note\r
+ public String Edit_Insert_Table_Row; // Insert row into table\r
+ public String Edit_Delete_Table_Row; // Delete a table row\r
+ public String Edit_Insert_Todo; // Insert todo\r
+ public String Edit_Encrypt_Text; // Encrypt selected text\r
+ public String Edit_Rotate_Image_Right; // Rotate an image right\r
+ public String Edit_Rotate_Image_Left; // Rotate an image left\r
+\r
+ public String View_Extended_Information; // View details on the current note\r
+ public String View_Thumbnail; // View Image Thumbnail\r
+ public String View_Show_Note_List; // Show current notes\r
+ public String View_Show_Notebooks; // Show notebooks\r
+ public String View_Show_Tags; // Show the tags window\r
+ public String View_Show_Attribute_Searches; // Show the attribute selection tree\r
+ public String View_Show_SavedSearches; // Show the saved search tree\r
+ public String View_Show_Trash; // Show the trash window\r
+ public String View_Show_Editor_Button_Bar; // Hide the editor button bar\r
+ public String View_Show_Left_Side; // Hide all left hand windows\r
+\r
+ public String Format_Bold; // Bold (duh)\r
+ public String Format_Underline; // Underline\r
+ public String Format_Italic; // Italic\r
+ public String Format_Strikethrough; // Strikethrough\r
+ public String Format_Horizontal_Line; // Href line\r
+ public String Format_Superscript; // Set superscript\r
+ public String Format_Subscript; // Subscript\r
+ public String Format_Alignment_Left; // Left align text\r
+ public String Format_Alignment_Center; // Center text\r
+ public String Format_Alignment_Right; // Right align text\r
+ public String Format_List_Bullet; // Bullet list\r
+ public String Format_List_Numbered; // Numbered list \r
+ public String Format_Indent_Increase; // Increase the indentation\r
+ public String Format_Indent_Decrease; // Decrease the indent\r
+\r
+ public String Online_Note_History; // Synchronize with Evernote\r
+ \r
+ public String Online_Synchronize; // Synchronize with Evernote\r
+ public String Online_Connect; // Connect to Evernote\r
+ public String Tools_Account_Information; // Show account information\r
+ public String Tools_Reindex_Database; // Reindex the entire database\r
+ public String Tools_Disable_Note_Indexing; // Disable note indexing\r
+ public String Tools_Compact_Database; // Free unused database space\r
+ public String Tools_Database_Status; // Current database information\r
+\r
+ public String About_Release_Notes; // Current version's release notes\r
+ public String About_Log; // Message log\r
+ public String About_About; // About dialog box\r
+ \r
+ public String Focus_Title; // Switch focus to the title bar\r
+ public String Focus_Tag; // Switch focus to the tag edit\r
+ public String Focus_Note; // Switch focus to the note\r
+ public String Focus_Author; // Switch focus to the author\r
+ public String Focus_Url; // Switch focus to the URL\r
+ \r
+ public String Insert_DateTime; // Insert the current date/time\r
+ \r
+ HashMap<String, String> actionMap;\r
+ HashMap<String, String> shortcutMap;\r
+ \r
+ public ShortcutKeys() {\r
+ File_Note_Add = new String("Ctrl+N"); // Add a new note\r
+ File_Note_Reindex = new String(); // Reindex the current note\r
+ File_Note_Modify_Tags = new String(); // Change current note tags\r
+ File_Note_Delete = new String(); // Delete a tag\r
+ File_Note_Restore = new String(); // Undelete a note\r
+ File_Note_Duplicate = new String(); // Duplicate a note\r
+ File_Notebook_Add = new String(); // Add a notebook\r
+ File_Notebook_Edit = new String(); // Edit an existing notebook\r
+ File_Notebook_Delete = new String(); // Delete the existing notebook\r
+ File_Notebook_Open = new String(); // Open a closed (i.e. archived) notebook\r
+ File_Notebook_Close = new String(); // Close (i.e. archive) a notebook\r
+ File_Tag_Add = new String("Ctrl+Shift+T"); // Add a notebook\r
+ File_Tag_Edit = new String(); // Edit an existing notebook\r
+ File_Tag_Delete = new String(); // Delete the existing notebook\r
+ File_SavedSearch_Add = new String(); // Add a notebook\r
+ File_SavedSearch_Edit = new String(); // Edit an existing notebook\r
+ File_SavedSearch_Delete = new String(); // Delete the existing notebook\r
+ File_Email = new String("Ctrl+Shift+E"); // Email note\r
+ File_Print = new String("Ctrl+P"); // Print\r
+ File_Backup = new String(""); // Backup\r
+ File_Restore = new String(""); // Restore\r
+ File_Empty_Trash = new String(); // Purge all delete notes\r
+ File_Exit = new String("Ctrl+Q"); // I'm outahere\r
+\r
+ Edit_Find_In_Note = new String("Ctrl+F"); // Search only within the current note\r
+ Edit_Undo = new String("Ctrl+Z"); // Undo last change\r
+ Edit_Redo = new String("Ctrl+Y"); // Redo the last undone change\r
+ Edit_Cut = new String("Ctrl+X"); // Cut current selection to the clipboard\r
+ Edit_Copy = new String("Ctrl+C"); // Copy the current selection to the clipboard\r
+ Edit_Paste = new String("Ctrl+V"); // Paste\r
+ Edit_Paste_Without_Formatting = new String("Ctrl+Shift+P"); // Paste as plain text\r
+ Edit_Preferences = new String(); // Settings dialog box\r
+ \r
+ Edit_Insert_Hyperlink = new String("Ctrl+K"); // Insert a hyperlink\r
+ Edit_Insert_Table = new String(); // Insert a table\r
+ Edit_Insert_Table_Row = new String(); // Insert a table row\r
+ Edit_Delete_Table_Row = new String(); // Delete a table row\r
+ Edit_Insert_Todo = new String();\r
+ Edit_Encrypt_Text = new String();\r
+ Edit_Rotate_Image_Right = new String();\r
+ Edit_Rotate_Image_Left = new String();\r
+\r
+ View_Extended_Information = new String("F8"); // View details on the current note\r
+ View_Thumbnail = new String(); // View the thumbnail\r
+ View_Show_Note_List = new String("F10"); // Show current notes\r
+ View_Show_Notebooks = new String(); // Show notebooks\r
+ View_Show_Tags = new String(); // Show the tags window\r
+ View_Show_Attribute_Searches = new String(); // Show the attribute selection tree\r
+ View_Show_SavedSearches = new String(); // Show the saved search tree\r
+ View_Show_Trash = new String(); // Show the trash window\r
+ View_Show_Editor_Button_Bar = new String(); // Hide the editor button bar\r
+ View_Show_Left_Side = new String("F11"); // Hide all left hand windows\r
+\r
+ Format_Bold = new String("Ctrl+B"); // Bold (duh)\r
+ Format_Underline = new String("Ctrl+U"); // Underline\r
+ Format_Italic = new String("Ctrl+I"); // Italic\r
+ Format_Strikethrough = new String("Ctrl+-"); // Strikethrough\r
+ Format_Horizontal_Line = new String(); // Href line\r
+ Format_Superscript = new String("Ctrl+="); // Set superscript\r
+ Format_Subscript = new String("Ctrl++Shift+="); // Subscript\r
+ Format_Alignment_Left = new String("Ctrl+L"); // Left align text\r
+ Format_Alignment_Center = new String("Ctrl+C"); // Center text\r
+ Format_Alignment_Right = new String("Ctrl+R"); // Right align text\r
+ Format_List_Bullet = new String("Ctrl+Shift+B"); // Bullet list\r
+ Format_List_Numbered = new String("Ctrl+Shift+N"); // Numbered list \r
+ Format_Indent_Increase = new String("Ctrl+M"); // Increase the indentation\r
+ Format_Indent_Decrease = new String("Ctrl+Shift+M"); // Decrease the indent\r
+\r
+ Online_Note_History = new String();\r
+ \r
+ Online_Synchronize = new String("F9"); // Synchronize with Evernote\r
+ Online_Connect = new String(); // Connect to Evernote\r
+ Tools_Account_Information = new String(); // Show account information\r
+ Tools_Reindex_Database = new String(); // Reindex the entire database\r
+ Tools_Disable_Note_Indexing = new String(); // Disable note indexing\r
+ Tools_Compact_Database = new String(); // Free unused database space\r
+ Tools_Database_Status = new String(); // Current database information\r
+\r
+ About_Release_Notes = new String(); // Current version's release notes\r
+ About_Log = new String(); // Message log\r
+ About_About = new String(); // About dialog box\r
+ \r
+ Insert_DateTime = new String("Ctrl+;");\r
+ \r
+ Focus_Title = new String();\r
+ Focus_Tag = new String("Ctrl+Shift+T");\r
+ Focus_Note = new String();\r
+ Focus_Author = new String();\r
+ Focus_Url = new String();\r
+ \r
+ // Setup value Array\r
+ shortcutMap = new HashMap<String, String>();\r
+ actionMap = new HashMap<String, String>();\r
+ \r
+ // Load the defaults\r
+ loadKey("File_Note_Add", File_Note_Add);\r
+ loadKey("File_Tag_Add", File_Tag_Add);\r
+ loadKey("File_Email", File_Email);\r
+ loadKey("File_Print", File_Print);\r
+ loadKey("File_Backup", File_Backup);\r
+ loadKey("File_Restore", File_Restore);\r
+ loadKey("File_Exit", File_Exit);\r
+ \r
+ loadKey("Edit_Find_In_Note", Edit_Find_In_Note);\r
+ loadKey("Edit_Undo", Edit_Undo);\r
+ loadKey("Edit_Redo", Edit_Redo);\r
+ loadKey("Edit_Cut", Edit_Cut);\r
+ loadKey("Edit_Copy", Edit_Copy);\r
+ loadKey("Edit_Paste", Edit_Paste);\r
+ loadKey("Edit_Paste_Without_Formatting", Edit_Paste_Without_Formatting);\r
+ loadKey("Edit_Insert_Hyperlink", Edit_Insert_Hyperlink);\r
+ loadKey("Edit_Insert_Table_Row", Edit_Insert_Table_Row);\r
+ loadKey("Edit_Insert_Table_Row", Edit_Delete_Table_Row);\r
+ loadKey("Edit_Insert_Todo", Edit_Insert_Todo);\r
+ loadKey("Edit_Rotate_Image_Right", Edit_Rotate_Image_Right);\r
+ loadKey("Edit_Rotate_Image_Left", Edit_Rotate_Image_Left);\r
+ \r
+ loadKey("View_Extended_Information", View_Extended_Information);\r
+ loadKey("View_Thumbnail", View_Thumbnail);\r
+ loadKey("View_Show_Note_List", View_Show_Note_List);\r
+ loadKey("View_Show_Left_Side",View_Show_Left_Side);\r
+ \r
+ loadKey("Format_Bold", Format_Bold);\r
+ loadKey("Format_Underline", Format_Underline);\r
+ loadKey("Format_Italic", Format_Italic);\r
+ loadKey("Format_Strikethrough", Format_Strikethrough);\r
+ loadKey("Format_Superscript", Format_Superscript);\r
+ loadKey("Format_Subscript", Format_Subscript);\r
+ loadKey("Format_Alignment_Left", Format_Alignment_Left);\r
+ loadKey("Format_Alignment_Center", Format_Alignment_Center);\r
+ loadKey("Format_Alignment_Right", Format_Alignment_Right);\r
+ loadKey("Format_List_Bullet", Format_List_Bullet);\r
+ loadKey("Format_List_Numbered", Format_List_Numbered);\r
+ loadKey("Format_Indent_Increase", Format_Indent_Increase);\r
+ loadKey("Format_Indent_Decrease", Format_Indent_Decrease);\r
+ loadKey("Tools_Synchronize", Online_Synchronize);\r
+\r
+\r
+ loadKey("Focus_Title", Focus_Title);\r
+ loadKey("Focus_Tag", Focus_Tag);\r
+ loadKey("Focus_Note", Focus_Note);\r
+ loadKey("Focus_Author", Focus_Author);\r
+ loadKey("Focus_Url", Focus_Url);\r
+ \r
+ loadKey("Insert_DateTime", Insert_DateTime);\r
+ \r
+ loadCustomKeys();\r
+ \r
+ }\r
+ \r
+ // Read in the custom keys (if they exist)\r
+ private void loadCustomKeys() {\r
+ File file = new File(Global.getDirectoryPath()+"shortcuts.txt");\r
+ try {\r
+ Scanner scanner = new Scanner(file);\r
+ while ( scanner.hasNextLine() ){\r
+ String line = scanner.nextLine();\r
+ line = line.replace("\t", " "); // Replace tab characters\r
+ line = line.replace("\n", " "); // replace newline\r
+ line = line.replace("\r", " "); // replace carrage return\r
+ line = line.trim(); // compress the line\r
+ String split[] = line.split(" ");\r
+ Vector<String> keyVector = new Vector<String>();\r
+ for (int i=0; i<split.length; i++) {\r
+ if (!split[i].trim().equals("") && !split[i].trim().startsWith("//"))\r
+ keyVector.add(split[i]);\r
+ if (split[i].trim().startsWith("//"))\r
+ i=split.length;\r
+ }\r
+ if (keyVector.size() == 1)\r
+ removeByAction(keyVector.get(0));\r
+ if (keyVector.size() >=2) \r
+ loadKey(keyVector.get(0), keyVector.get(1));\r
+ \r
+ }\r
+ } catch (FileNotFoundException e) {\r
+ return;\r
+ }\r
+ }\r
+ \r
+ \r
+ // Load a key value into the map for later use\r
+ public void loadKey(String action, String shortcut) {\r
+ shortcut = shortcut.trim().toLowerCase();\r
+ action = action.trim().toLowerCase();\r
+ \r
+ // If we have an existing one, remove it.\r
+ if (actionMap.containsKey(action))\r
+ removeByAction(action);\r
+ if (shortcutMap.containsKey(shortcut))\r
+ removeByShortcut(shortcut);\r
+ \r
+ if (shortcut.equals("")) {\r
+ removeByShortcut(shortcut);\r
+ return;\r
+ }\r
+ \r
+ // Add the new value\r
+ actionMap.put(action.toLowerCase(), shortcut);\r
+ shortcutMap.put(shortcut.toLowerCase(), action);\r
+ }\r
+ \r
+ // Remove a shortcut by the Shortcut key\r
+ public void removeByShortcut(String shortcut) {\r
+ String action = shortcutMap.get(shortcut.toLowerCase());\r
+ shortcutMap.remove(shortcut.toLowerCase());\r
+ if (action != null)\r
+ actionMap.remove(action.toLowerCase());\r
+ }\r
+ \r
+ // Remove a shortcut by the action itself\r
+ public void removeByAction(String action) {\r
+ String shortcut = actionMap.get(action.toLowerCase());\r
+ actionMap.remove(action.toLowerCase());\r
+ if (shortcut != null)\r
+ shortcutMap.remove(shortcut.toLowerCase());\r
+ }\r
+ \r
+ // Check if a shortcut key exists\r
+ public boolean containsShortcut(String shortcut) {\r
+ return shortcutMap.containsKey(shortcut.toLowerCase());\r
+ }\r
+ \r
+ // Check if an action exists\r
+ public boolean containsAction(String action) {\r
+ return actionMap.containsKey(action.toLowerCase());\r
+ }\r
+ \r
+ // Get a key based upon the action\r
+ public String getShortcut(String action) {\r
+ return actionMap.get(action.toLowerCase());\r
+ }\r
+ \r
+ // Get an action based upon the key\r
+ public String getAction(String shortcut) {\r
+ return shortcutMap.get(shortcut.toLowerCase());\r
+ }\r
+ \r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+package cx.fbn.nevernote.gui;\r
+\r
+import java.text.SimpleDateFormat;\r
+import java.util.List;\r
+import java.util.SortedMap;\r
+\r
+import com.evernote.edam.type.Note;\r
+import com.trolltech.qt.core.QByteArray;\r
+import com.trolltech.qt.core.QDateTime;\r
+import com.trolltech.qt.core.QModelIndex;\r
+import com.trolltech.qt.core.Qt;\r
+import com.trolltech.qt.core.Qt.SortOrder;\r
+import com.trolltech.qt.gui.QAbstractItemView;\r
+import com.trolltech.qt.gui.QAction;\r
+import com.trolltech.qt.gui.QApplication;\r
+import com.trolltech.qt.gui.QColor;\r
+import com.trolltech.qt.gui.QContextMenuEvent;\r
+import com.trolltech.qt.gui.QDragEnterEvent;\r
+import com.trolltech.qt.gui.QDropEvent;\r
+import com.trolltech.qt.gui.QFontMetrics;\r
+import com.trolltech.qt.gui.QHeaderView;\r
+import com.trolltech.qt.gui.QKeyEvent;\r
+import com.trolltech.qt.gui.QMenu;\r
+import com.trolltech.qt.gui.QStandardItemModel;\r
+import com.trolltech.qt.gui.QTableView;\r
+import com.trolltech.qt.gui.QKeySequence.StandardKey;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.filters.NoteSortFilterProxyModel;\r
+import cx.fbn.nevernote.signals.NoteSignal;\r
+import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+import cx.fbn.nevernote.utilities.ListManager;\r
+\r
+public class TableView extends QTableView {\r
+// private final ListManager runner;\r
+ private final ApplicationLogger logger;\r
+ public QStandardItemModel model; // Standard item model\r
+ public NoteSortFilterProxyModel proxyModel; // note sort model\r
+ private QAction deleteAction;\r
+ private QAction addAction;\r
+ private QAction restoreAction;\r
+ private QAction noteHistoryAction;\r
+ private QAction duplicateAction;\r
+ private QAction mergeNotesAction;\r
+ \r
+ // Note title colors\r
+ private QAction noteTitleColorWhite;\r
+ private QAction noteTitleColorRed;\r
+ private QAction noteTitleColorBlue;\r
+ private QAction noteTitleColorGreen;\r
+ private QAction noteTitleColorYellow;\r
+ private QAction noteTitleColorBlack;\r
+ private QAction noteTitleColorGray;\r
+ private QAction noteTitleColorCyan;\r
+ private QAction noteTitleColorMagenta;\r
+\r
+\r
+ \r
+ public QHeaderView header;\r
+ int fontHeight;\r
+ public Signal1<String> rowChanged;\r
+ public Signal0 resetViewport;\r
+ public NoteSignal noteSignal;\r
+ \r
+ public TableView(ApplicationLogger l) {\r
+ logger = l;\r
+ header = horizontalHeader();\r
+ header.setMovable(true);\r
+ \r
+ noteSignal = new NoteSignal();\r
+ setAcceptDrops(true);\r
+ setDragEnabled(true);\r
+ setDragDropMode(QAbstractItemView.DragDropMode.DragDrop);\r
+ setDropIndicatorShown(false);\r
+ \r
+ model = new QStandardItemModel(0,Global.noteTableColumnCount, this);\r
+ \r
+ model.setHeaderData(Global.noteTableCreationPosition, Qt.Orientation.Horizontal, "Date Created");\r
+ model.setHeaderData(Global.noteTableTagPosition, Qt.Orientation.Horizontal, "Tags");\r
+ model.setHeaderData(Global.noteTableGuidPosition, Qt.Orientation.Horizontal, "Guid");\r
+ model.setHeaderData(Global.noteTableNotebookPosition, Qt.Orientation.Horizontal, "Notebook");\r
+ model.setHeaderData(Global.noteTableTitlePosition, Qt.Orientation.Horizontal, "Title");\r
+ model.setHeaderData(Global.noteTableChangedPosition, Qt.Orientation.Horizontal, "Date Changed");\r
+ model.setHeaderData(Global.noteTableAuthorPosition, Qt.Orientation.Horizontal, "Author");\r
+ model.setHeaderData(Global.noteTableSourceUrlPosition, Qt.Orientation.Horizontal, "Source Url");\r
+ model.setHeaderData(Global.noteTableSubjectDatePosition, Qt.Orientation.Horizontal, "Subject Date");\r
+ model.setHeaderData(Global.noteTableSynchronizedPosition, Qt.Orientation.Horizontal, "Synchronized");\r
+ header.sortIndicatorChanged.connect(this, "resetViewport()");\r
+ \r
+ proxyModel = new NoteSortFilterProxyModel(this);\r
+ proxyModel.setSourceModel(model);\r
+ \r
+ setAlternatingRowColors(false);\r
+ setModel(proxyModel);\r
+ \r
+ setSortingEnabled(true);\r
+ int sortCol = proxyModel.sortColumn();\r
+ SortOrder sortOrder = proxyModel.sortOrder();\r
+ sortByColumn(sortCol, sortOrder);\r
+\r
+ setSelectionBehavior(SelectionBehavior.SelectRows);\r
+ setSelectionMode(SelectionMode.SingleSelection);\r
+ verticalHeader().setVisible(false);\r
+ hideColumn(Global.noteTableGuidPosition); // Hide the guid column\r
+ setShowGrid(false);\r
+ setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers);\r
+ \r
+ QFontMetrics f = QApplication.fontMetrics();\r
+ fontHeight = f.height();\r
+ rowChanged = new Signal1<String>();\r
+ resetViewport = new Signal0();\r
+ }\r
+ \r
+ // This should rescroll to the current item in the list when a column is \r
+ // sorted. Somehow I can't get this to work, but this part is correct.\r
+ @SuppressWarnings("unused")\r
+ private void resetViewport() {\r
+// if (currentIndex() == null) \r
+// return;\r
+ \r
+// resetViewport.emit();\r
+ }\r
+ \r
+ \r
+ public void load(ListManager runner, boolean reload) {\r
+\r
+ proxyModel.clear();\r
+ setSortingEnabled(true);\r
+ for (int i=0; i<runner.getNoteIndex().size(); i++) {\r
+ if (Global.showDeleted == true && !runner.getNoteIndex().get(i).isActive())\r
+ proxyModel.addGuid(runner.getNoteIndex().get(i).getGuid());\r
+ if (!Global.showDeleted == true && runner.getNoteIndex().get(i).isActive()) \r
+ proxyModel.addGuid(runner.getNoteIndex().get(i).getGuid());\r
+ }\r
+ if (!reload) {\r
+ logger.log(logger.EXTREME, "TableView.load() reload starting.");\r
+ proxyModel.filter();\r
+ logger.log(logger.EXTREME, "TableView.load() leaving reload.");\r
+ QFontMetrics f = QApplication.fontMetrics();\r
+ fontHeight = f.height();\r
+ for (int i=0; i<model.rowCount(); i++)\r
+ setRowHeight(i, fontHeight);\r
+ resetViewport.emit();\r
+ return;\r
+ }\r
+ logger.log(logger.EXTREME, "TableView.load() Filling table data from scratch");\r
+ model.setRowCount(runner.getMasterNoteIndex().size());\r
+ \r
+ for (int i=0; i<runner.getMasterNoteIndex().size(); i++) {\r
+ if (runner.getMasterNoteIndex().get(i) != null) { \r
+ insertRow(runner, runner.getMasterNoteIndex().get(i), false, i); \r
+ }\r
+ }\r
+ \r
+\r
+ \r
+ int width;\r
+ width = Global.getColumnWidth("noteTableCreationPosition");\r
+ if (width>0) setColumnWidth(Global.noteTableCreationPosition, width);\r
+ width = Global.getColumnWidth("noteTableChangedPosition");\r
+ if (width>0) setColumnWidth(Global.noteTableChangedPosition, width);\r
+ width = Global.getColumnWidth("noteTableTitlePosition");\r
+ if (width>0) setColumnWidth(Global.noteTableTitlePosition, width);\r
+ width = Global.getColumnWidth("noteTableTagPosition");\r
+ if (width>0) setColumnWidth(Global.noteTableTagPosition, width);\r
+ width = Global.getColumnWidth("noteTableGuidPosition");\r
+ if (width>0) setColumnWidth(Global.noteTableGuidPosition, width);\r
+ width = Global.getColumnWidth("noteTableNotebookPosition");\r
+ if (width>0) setColumnWidth(Global.noteTableNotebookPosition, width);\r
+ width = Global.getColumnWidth("noteTableSourceUrlPosition");\r
+ if (width>0) setColumnWidth(Global.noteTableSourceUrlPosition, width);\r
+ width = Global.getColumnWidth("noteTableAuthorPosition");\r
+ if (width>0) setColumnWidth(Global.noteTableAuthorPosition, width);\r
+ width = Global.getColumnWidth("noteTableSubjectDatePosition");\r
+ if (width>0) setColumnWidth(Global.noteTableSubjectDatePosition, width);\r
+ width = Global.getColumnWidth("noteTableSynchronizedPosition");\r
+ if (width>0) setColumnWidth(Global.noteTableSynchronizedPosition, width);\r
+ \r
+ int from = header.visualIndex(Global.noteTableCreationPosition);\r
+ int to = Global.getColumnPosition("noteTableCreationPosition");\r
+ if (to>=0) header.moveSection(from, to);\r
+\r
+ from = header.visualIndex(Global.noteTableTitlePosition);\r
+ to = Global.getColumnPosition("noteTableTitlePosition");\r
+ if (to>=0) header.moveSection(from, to);\r
+ \r
+ from = header.visualIndex(Global.noteTableTagPosition);\r
+ to = Global.getColumnPosition("noteTableTagPosition");\r
+ if (to>=0) header.moveSection(from, to);\r
+ \r
+ from = header.visualIndex(Global.noteTableNotebookPosition);\r
+ to = Global.getColumnPosition("noteTableNotebookPosition");\r
+ if (to>=0) header.moveSection(from, to);\r
+ \r
+ from = header.visualIndex(Global.noteTableChangedPosition);\r
+ to = Global.getColumnPosition("noteTableChangedPosition");\r
+ if (to>=0) header.moveSection(from, to);\r
+ \r
+ from = header.visualIndex(Global.noteTableSourceUrlPosition);\r
+ to = Global.getColumnPosition("noteTableSourceUrlPosition");\r
+ if (to>=0) header.moveSection(from, to);\r
+ \r
+ from = header.visualIndex(Global.noteTableAuthorPosition);\r
+ to = Global.getColumnPosition("noteTableAuthorPosition");\r
+ if (to>=0) header.moveSection(from, to);\r
+ \r
+ from = header.visualIndex(Global.noteTableSubjectDatePosition);\r
+ to = Global.getColumnPosition("noteTableSubjectDatePosition");\r
+ if (to>=0) header.moveSection(from, to);\r
+ \r
+ from = header.visualIndex(Global.noteTableSynchronizedPosition);\r
+ to = Global.getColumnPosition("noteTableSynchronizedPosition");\r
+ if (to>=0) header.moveSection(from, to);\r
+\r
+ proxyModel.filter();\r
+ \r
+ QFontMetrics f = QApplication.fontMetrics();\r
+ fontHeight = f.height();\r
+ for (int i=0; i<model.rowCount(); i++)\r
+ setRowHeight(i, fontHeight);\r
+ \r
+ resetViewport.emit();\r
+ }\r
+\r
+ public void insertRow(ListManager runner, Note tempNote, boolean newNote, int row) {\r
+ if (newNote)\r
+ proxyModel.addGuid(tempNote.getGuid());\r
+ String fmt = Global.getDateFormat() + " " + Global.getTimeFormat();\r
+ String dateTimeFormat = new String(fmt);\r
+ SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);\r
+\r
+ \r
+ String tagNames = runner.getTagNamesForNote(tempNote);\r
+ StringBuilder creationDate = new StringBuilder(simple.format(tempNote.getCreated())); \r
+ StringBuilder changedDate = new StringBuilder(simple.format(tempNote.getUpdated()));\r
+ StringBuilder subjectDate;\r
+ if (tempNote.getAttributes().getSubjectDate() == 0) \r
+ subjectDate = creationDate;\r
+ else\r
+ subjectDate = new StringBuilder(simple.format(tempNote.getAttributes().getSubjectDate()));\r
+\r
+ String sync = "true";\r
+ for (int i=0; i<runner.getUnsynchronizedNotes().size(); i++) {\r
+ if (runner.getUnsynchronizedNotes().get(i).equalsIgnoreCase(tempNote.getGuid())) {\r
+ sync = "false";\r
+ i = runner.getUnsynchronizedNotes().size();\r
+ }\r
+ } \r
+ \r
+ if (row > model.rowCount())\r
+ model.insertRow(0);\r
+ \r
+ if (row < 0) {\r
+ row = model.rowCount();\r
+ model.insertRow(row);\r
+// row = model.rowCount()-1;\r
+ }\r
+\r
+ QColor backgroundColor = new QColor(QColor.white);\r
+ QColor foregroundColor = new QColor(QColor.black);\r
+ \r
+ if (runner.titleColors != null && runner.titleColors.containsKey(tempNote.getGuid())) {\r
+ int color = runner.titleColors.get(tempNote.getGuid());\r
+ backgroundColor.setRgb(color);\r
+ }\r
+ if (backgroundColor.rgb() == QColor.black.rgb() || backgroundColor.rgb() == QColor.blue.rgb()) \r
+ foregroundColor.setRgb(QColor.white.rgb());\r
+ \r
+ \r
+ QDateTime created = QDateTime.fromString(creationDate.toString(), fmt);\r
+ QDateTime changed = QDateTime.fromString(changedDate.toString(), fmt);\r
+ QDateTime subjectDateFormat = QDateTime.fromString(subjectDate.toString(), fmt);\r
+ model.setData(model.index(row, Global.noteTableCreationPosition), created.toString(fmt));\r
+ model.setData(model.index(row, Global.noteTableChangedPosition), changed.toString(fmt));\r
+ model.setData(model.index(row, Global.noteTableTitlePosition), tempNote.getTitle());\r
+ model.setData(model.index(row, Global.noteTableTagPosition), tagNames);\r
+ model.setData(model.index(row, Global.noteTableGuidPosition), tempNote.getGuid());\r
+ model.setData(model.index(row, Global.noteTableSubjectDatePosition), subjectDateFormat.toString(fmt));\r
+ model.setData(model.index(row, Global.noteTableAuthorPosition), tempNote.getAttributes().getAuthor());\r
+ model.setData(model.index(row, Global.noteTableSourceUrlPosition), tempNote.getAttributes().getSourceURL());\r
+ model.setData(model.index(row, Global.noteTableNotebookPosition), runner.getNotebookNameByGuid(tempNote.getNotebookGuid()));\r
+ model.setData(model.index(row, Global.noteTableSynchronizedPosition), sync);\r
+ \r
+ for (int i=0; i<Global.noteTableColumnCount; i++) {\r
+ model.setData(row, i, backgroundColor, Qt.ItemDataRole.BackgroundRole);\r
+ model.setData(row, i, foregroundColor, Qt.ItemDataRole.ForegroundRole);\r
+ } \r
+ \r
+ if (newNote) {\r
+ QFontMetrics f = QApplication.fontMetrics();\r
+ fontHeight = f.height();\r
+ for (int i=0; i<model.rowCount(); i++)\r
+ setRowHeight(i, fontHeight);\r
+ }\r
+ }\r
+ protected boolean filterAcceptsRow(int sourceRow, QModelIndex sourceParent) {\r
+ return true;\r
+ }\r
+\r
+ public void setAddAction(QAction a) {\r
+ addAction = a;\r
+ }\r
+ \r
+ public void setMergeNotesAction(QAction a) {\r
+ mergeNotesAction = a;\r
+ }\r
+ \r
+ public void setNoteHistoryAction(QAction a) {\r
+ noteHistoryAction = a;\r
+ }\r
+ \r
+ public void setDeleteAction(QAction d) {\r
+ deleteAction = d;\r
+ }\r
+ \r
+ public void setRestoreAction(QAction r) {\r
+ restoreAction = r;\r
+ }\r
+ public void setNoteDuplicateAction(QAction d) {\r
+ duplicateAction = d;\r
+ }\r
+ \r
+ @Override\r
+ public void keyPressEvent(QKeyEvent e) {\r
+ if (e.matches(StandardKey.MoveToStartOfDocument)) {\r
+ if (model.rowCount() > 0) {\r
+ clearSelection();\r
+ selectRow(0);\r
+ }\r
+ }\r
+ if (e.matches(StandardKey.MoveToEndOfDocument)) {\r
+ if (model.rowCount() > 0) {\r
+ clearSelection();\r
+ selectRow(model().rowCount()-1);\r
+ }\r
+ }\r
+ super.keyPressEvent(e);\r
+ }\r
+ \r
+ @Override\r
+ public void contextMenuEvent(QContextMenuEvent event) {\r
+ QMenu menu = new QMenu(this);\r
+ if (Global.showDeleted) {\r
+ menu.addAction(restoreAction);\r
+ } else {\r
+ menu.addAction(addAction);\r
+ }\r
+ menu.addAction(deleteAction);\r
+ menu.addSeparator();\r
+ menu.addAction(duplicateAction);\r
+ menu.addAction(noteHistoryAction);\r
+ menu.addAction(mergeNotesAction);\r
+ \r
+ QMenu titleColorMenu = new QMenu();\r
+ titleColorMenu.setTitle("Title Color");\r
+ menu.addMenu(titleColorMenu);\r
+ noteTitleColorWhite = new QAction(titleColorMenu);\r
+ noteTitleColorRed = new QAction(titleColorMenu);\r
+ noteTitleColorBlue = new QAction(titleColorMenu);\r
+ noteTitleColorGreen = new QAction(titleColorMenu);\r
+ noteTitleColorYellow = new QAction(titleColorMenu);\r
+ noteTitleColorBlack = new QAction(titleColorMenu);\r
+ noteTitleColorGray = new QAction(titleColorMenu);\r
+ noteTitleColorCyan = new QAction(titleColorMenu);\r
+ noteTitleColorMagenta = new QAction(titleColorMenu);\r
+ \r
+ noteTitleColorWhite.setText("White");\r
+ noteTitleColorRed.setText("Red");\r
+ noteTitleColorBlue.setText("Blue");\r
+ noteTitleColorGreen.setText("Green");\r
+ noteTitleColorYellow.setText("Yellow");\r
+ noteTitleColorBlack.setText("Black");\r
+ noteTitleColorGray.setText("Gray");\r
+ noteTitleColorCyan.setText("Cyan");\r
+ noteTitleColorMagenta.setText("Magenta");\r
+ \r
+ titleColorMenu.addAction(noteTitleColorWhite);\r
+ titleColorMenu.addAction(noteTitleColorRed);\r
+ titleColorMenu.addAction(noteTitleColorBlue);\r
+ titleColorMenu.addAction(noteTitleColorGreen);\r
+ titleColorMenu.addAction(noteTitleColorYellow);\r
+ titleColorMenu.addAction(noteTitleColorBlack);\r
+ titleColorMenu.addAction(noteTitleColorGray);\r
+ titleColorMenu.addAction(noteTitleColorCyan);\r
+ titleColorMenu.addAction(noteTitleColorMagenta);\r
+ \r
+ noteTitleColorWhite.triggered.connect(this, "titleColorWhite()");\r
+ \r
+ noteTitleColorWhite.triggered.connect(this, "titleColorWhite()");\r
+ noteTitleColorRed.triggered.connect(this, "titleColorRed()");\r
+ noteTitleColorBlue.triggered.connect(this, "titleColorBlue()");\r
+ noteTitleColorGreen.triggered.connect(this, "titleColorGreen()");\r
+ noteTitleColorYellow.triggered.connect(this, "titleColorYellow()");\r
+ noteTitleColorBlack.triggered.connect(this, "titleColorBlack()");\r
+ noteTitleColorGray.triggered.connect(this, "titleColorGray()");\r
+ noteTitleColorCyan.triggered.connect(this, "titleColorCyan()");\r
+ noteTitleColorMagenta.triggered.connect(this, "titleColorMagenta()");\r
+ \r
+ menu.exec(event.globalPos());\r
+ }\r
+ \r
+ \r
+ @SuppressWarnings("unused")\r
+ private void titleColorWhite() {noteSignal.titleColorChanged.emit(QColor.white.rgb());}\r
+ @SuppressWarnings("unused")\r
+ private void titleColorRed() {noteSignal.titleColorChanged.emit(QColor.red.rgb());}\r
+ @SuppressWarnings("unused")\r
+ private void titleColorBlue() {noteSignal.titleColorChanged.emit(QColor.blue.rgb());}\r
+ @SuppressWarnings("unused")\r
+ private void titleColorGreen() {noteSignal.titleColorChanged.emit(QColor.green.rgb());}\r
+ @SuppressWarnings("unused")\r
+ private void titleColorYellow(){noteSignal.titleColorChanged.emit(QColor.yellow.rgb());}\r
+ @SuppressWarnings("unused")\r
+ private void titleColorBlack() {noteSignal.titleColorChanged.emit(QColor.black.rgb());}\r
+ @SuppressWarnings("unused")\r
+ private void titleColorGray() {noteSignal.titleColorChanged.emit(QColor.gray.rgb());}\r
+ @SuppressWarnings("unused")\r
+ private void titleColorCyan() {noteSignal.titleColorChanged.emit(QColor.cyan.rgb());}\r
+ @SuppressWarnings("unused")\r
+ private void titleColorMagenta() {noteSignal.titleColorChanged.emit(QColor.magenta.rgb());}\r
+ \r
+ \r
+\r
+ @Override\r
+ public void dragEnterEvent(QDragEnterEvent event) {\r
+ StringBuffer guid = new StringBuffer(1000);\r
+ \r
+ showColumn(Global.noteTableGuidPosition);\r
+ List<QModelIndex> selections = selectionModel().selectedRows();\r
+ hideColumn(Global.noteTableGuidPosition);\r
+ \r
+ if (selections.size() > 0) {\r
+ QModelIndex index;\r
+ for (int i=0; i<selections.size(); i++) {\r
+ int row = selections.get(i).row();\r
+ index = proxyModel.index(row, Global.noteTableGuidPosition);\r
+ SortedMap<Integer, Object> ix = proxyModel.itemData(index);\r
+ guid.append((String)ix.values().toArray()[0]);\r
+ guid.append(" ");\r
+ }\r
+ }\r
+ event.mimeData().setData("application/x-nevernote-note", new QByteArray(guid.toString()));\r
+ event.accept();\r
+ \r
+ }\r
+ \r
+ @Override\r
+ public void dropEvent(QDropEvent event) {\r
+ if (event.source() == this)\r
+ event.ignore();\r
+ }\r
+ \r
+ // Return a column width\r
+ public int getColumnWidth(int col) {\r
+ return columnWidth(col);\r
+ }\r
+\r
+/*\r
+ @Override\r
+ public void scrollTo(final QModelIndex index, ScrollHint hint) {\r
+ QRect area = viewport().rect();\r
+ QRect rect = visualRect(index);\r
+\r
+ if (rect.top() < area.top())\r
+ verticalScrollBar().setValue(\r
+ verticalScrollBar().value() + rect.top() - area.top());\r
+ else if (rect.bottom() > area.bottom())\r
+ verticalScrollBar().setValue(\r
+ verticalScrollBar().value() + Math.min(\r
+ rect.bottom() - area.bottom(), rect.top() - area.top()));\r
+ update();\r
+ }\r
+ \r
+ @Override\r
+ protected void updateGeometries() {\r
+ verticalScrollBar().setPageStep(viewport().height());\r
+ verticalScrollBar().setRange(0, Math.max(0, viewport().height()));\r
+ }\r
+ @Override\r
+ protected int verticalOffset() {\r
+ return verticalScrollBar().value();\r
+ }\r
+*/\r
+ \r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+package cx.fbn.nevernote.gui;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.Tag;\r
+import com.trolltech.qt.core.Qt.CaseSensitivity;\r
+import com.trolltech.qt.gui.QCompleter;\r
+import com.trolltech.qt.gui.QStringListModel;\r
+\r
+public class TagLineCompleter extends QCompleter {\r
+ private List<Tag> tags;\r
+ private List<String> currentTags;\r
+ private QStringListModel model; \r
+ private final TagLineEdit editor;\r
+ \r
+ public TagLineCompleter(TagLineEdit e) {\r
+ editor = e;\r
+ setWidget(editor);\r
+// editor.setCompleter(this);\r
+ currentTags = new ArrayList<String>();\r
+ setTagList(new ArrayList<Tag>());\r
+ setCaseSensitivity(CaseSensitivity.CaseInsensitive);\r
+ }\r
+ \r
+ public List<String> getTagList(){\r
+ return currentTags;\r
+ }\r
+ \r
+ public void update(List<String> t, String prefix) {\r
+ currentTags = t;\r
+ \r
+ buildModelList();\r
+ \r
+ setCompletionPrefix(prefix);\r
+ if (!prefix.trim().equals(""))\r
+ complete();\r
+ }\r
+ \r
+ public List<Tag> getTags() {\r
+ return tags;\r
+ }\r
+ \r
+ private List<String> buildModelList() {\r
+ \r
+ model = (QStringListModel) model();\r
+ if (model == null) {\r
+ model = new QStringListModel();\r
+ setModel(model);\r
+ }\r
+ for (int i=0; i<model.rowCount(); i++)\r
+ model.removeRow(i);\r
+ \r
+ List<String> newTagList = new ArrayList<String>();\r
+\r
+ for (int i=0; i<tags.size(); i++) {\r
+ boolean found=false;\r
+ for (int j=0; j<currentTags.size() && !found; j++) {\r
+ if (currentTags.get(j).trim().equalsIgnoreCase(tags.get(i).getName())) {\r
+ found = true;\r
+ }\r
+ }\r
+ if (!found) \r
+ newTagList.add(tags.get(i).getName());\r
+ }\r
+ \r
+ model.setStringList(newTagList);\r
+ return newTagList;\r
+ }\r
+ \r
+ public void setTagList(List<Tag> t) {\r
+ tags = t;\r
+ resetList();\r
+ buildModelList();\r
+// model = new QStringListModel(buildModelList(), this);\r
+// setModel(model);\r
+ }\r
+ \r
+ public void resetList() {\r
+ currentTags.clear();\r
+ }\r
+\r
+\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.gui;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.Tag;\r
+import com.trolltech.qt.core.QEvent;\r
+import com.trolltech.qt.gui.QLineEdit;\r
+\r
+import cx.fbn.nevernote.Global;\r
+\r
+public class TagLineEdit extends QLineEdit {\r
+ private String text;\r
+ private final boolean changed;\r
+ public Signal2<List<String>, String> text_changed = new Signal2<List<String>, String>();\r
+ public TagLineCompleter tagCompleter;\r
+ public Signal0 focusLost = new Signal0();\r
+ \r
+ public TagLineEdit(List<Tag> allTags) {\r
+ textChanged.connect(this, "textChanged(String)");\r
+ tagCompleter = new TagLineCompleter(this);\r
+ text_changed.connect(tagCompleter, "update(List, String)");\r
+ tagCompleter.activated.connect(this, "completeText(String)");\r
+ changed = false;\r
+ }\r
+ \r
+ public boolean hasChanged() {\r
+ return changed;\r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void textChanged(String t) {\r
+ text = t;\r
+ int cursor_pos = cursorPosition();\r
+ String temp_text = text.substring(0,cursor_pos);\r
+ int delimeter = temp_text.trim().lastIndexOf(Global.tagDelimeter);\r
+ String prefix = "";\r
+ if (delimeter > 0)\r
+ prefix = temp_text.substring(delimeter+1).trim();\r
+ else\r
+ prefix = temp_text.trim();\r
+ \r
+ List<String> newTags = new ArrayList<String>();\r
+ List<String> currentTags = new ArrayList<String>();\r
+ String list[] = text.split(Global.tagDelimeter);\r
+ for (String element : list) {\r
+ currentTags.add(element.trim());\r
+ }\r
+ \r
+ text_changed.emit(currentTags, prefix.trim());\r
+ \r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void completeText(String text){\r
+ int cursor_pos = cursorPosition();\r
+ String before_text = text().substring(0,cursor_pos);\r
+ String after_text = text().substring(cursor_pos);\r
+ int prefix_len = before_text.lastIndexOf(Global.tagDelimeter);\r
+ if (prefix_len == -1) {\r
+ prefix_len = cursor_pos;\r
+ before_text = "";\r
+ } else {\r
+ before_text = before_text.substring(0,cursor_pos-1);\r
+ }\r
+ int nextTagPos = after_text.indexOf(Global.tagDelimeter);\r
+ if (nextTagPos == -1) {\r
+ nextTagPos = 0;\r
+ after_text = "";\r
+ }\r
+ setText(before_text +text +Global.tagDelimeter +" " +after_text);\r
+ setCursorPosition(cursor_pos - prefix_len + text().length() +2);\r
+ }\r
+\r
+ public void setTagList(List<Tag> t) {\r
+ tagCompleter.resetList();\r
+ tagCompleter.setTagList(t);\r
+ }\r
+ \r
+ @Override\r
+ public boolean event(QEvent e) {\r
+ if (e.type().equals(QEvent.Type.FocusOut)) {\r
+ focusLost.emit();\r
+ }\r
+ return super.event(e);\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.gui;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.Tag;\r
+import com.trolltech.qt.core.QByteArray;\r
+import com.trolltech.qt.core.QMimeData;\r
+import com.trolltech.qt.core.Qt;\r
+import com.trolltech.qt.core.Qt.MatchFlag;\r
+import com.trolltech.qt.core.Qt.MatchFlags;\r
+import com.trolltech.qt.core.Qt.SortOrder;\r
+import com.trolltech.qt.gui.QAbstractItemView;\r
+import com.trolltech.qt.gui.QAction;\r
+import com.trolltech.qt.gui.QBrush;\r
+import com.trolltech.qt.gui.QColor;\r
+import com.trolltech.qt.gui.QContextMenuEvent;\r
+import com.trolltech.qt.gui.QDragEnterEvent;\r
+import com.trolltech.qt.gui.QDragMoveEvent;\r
+import com.trolltech.qt.gui.QHeaderView;\r
+import com.trolltech.qt.gui.QIcon;\r
+import com.trolltech.qt.gui.QMenu;\r
+import com.trolltech.qt.gui.QTreeWidget;\r
+import com.trolltech.qt.gui.QTreeWidgetItem;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.filters.TagCounter;\r
+import cx.fbn.nevernote.signals.NoteSignal;\r
+import cx.fbn.nevernote.signals.TagSignal;\r
+import cx.fbn.nevernote.sql.DatabaseConnection;\r
+\r
+public class TagTreeWidget extends QTreeWidget {\r
+ private QAction editAction;\r
+ private QAction deleteAction;\r
+ private QAction addAction;\r
+ public TagSignal tagSignal;\r
+ public NoteSignal noteSignal;\r
+ private boolean showAllTags;\r
+ private final DatabaseConnection db;\r
+ \r
+ \r
+ public TagTreeWidget(DatabaseConnection d) {\r
+ List<String> headers = new ArrayList<String>();\r
+ if (Global.tagBehavior().equalsIgnoreCase("HideInactiveCount"))\r
+ headers.add("Tags");\r
+ else\r
+ headers.add("Tags");\r
+ headers.add("");\r
+ showAllTags = true;\r
+ setAcceptDrops(true);\r
+ setDragEnabled(true);\r
+ setColumnCount(2);\r
+ header().setResizeMode(0, QHeaderView.ResizeMode.ResizeToContents);\r
+ header().setResizeMode(1, QHeaderView.ResizeMode.Stretch);\r
+ header().setMovable(false);\r
+ db = d;\r
+ tagSignal = new TagSignal();\r
+ noteSignal = new NoteSignal();\r
+ setDragDropMode(QAbstractItemView.DragDropMode.DragDrop);\r
+ setHeaderLabels(headers);\r
+ setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection);\r
+ \r
+ int width = Global.getColumnWidth("tagTreeName");\r
+ if (width>0)\r
+ setColumnWidth(0, width);\r
+\r
+ }\r
+ \r
+ public void setEditAction(QAction e) {\r
+ editAction = e;\r
+ }\r
+ public void setDeleteAction(QAction d) {\r
+ deleteAction = d;\r
+ }\r
+ public void setAddAction(QAction a) {\r
+ addAction = a;\r
+ }\r
+ \r
+ public void load(List<Tag> tags) {\r
+ Tag tag;\r
+ List<QTreeWidgetItem> index = new ArrayList<QTreeWidgetItem>();\r
+ QTreeWidgetItem child;\r
+ \r
+ //Clear out the tree & reload\r
+ clear();\r
+ String iconPath = new String("classpath:cx/fbn/nevernote/icons/");\r
+ QIcon icon = new QIcon(iconPath+"tag.png");\r
+ \r
+ Qt.Alignment ra = new Qt.Alignment(Qt.AlignmentFlag.AlignRight);\r
+ \r
+ // Create a copy. We delete them out as they are found\r
+ List<Tag> tempList = new ArrayList<Tag>();\r
+ for (int i=0; i<tags.size(); i++) {\r
+ tempList.add(tags.get(i));\r
+ }\r
+ \r
+ while (tempList.size() > 0) {\r
+ for (int i=0; i<tempList.size(); i++) {\r
+ tag = tempList.get(i);\r
+ if (tag.getParentGuid()==null || tag.getParentGuid().equals("")) {\r
+ child = new QTreeWidgetItem();\r
+ child.setText(0, tag.getName());\r
+ child.setIcon(0,icon);\r
+ child.setText(2, tag.getGuid());\r
+ child.setTextAlignment(1, ra.value());\r
+ index.add(child);\r
+ addTopLevelItem(child);\r
+ tempList.remove(i);\r
+ } else {\r
+ // We need to find the parent\r
+ for (int j=0; j<index.size(); j++) {\r
+ if (index.get(j).text(2).equals(tag.getParentGuid())) {\r
+ child = new QTreeWidgetItem();\r
+ child.setText(0, tag.getName());\r
+ child.setIcon(0, icon);\r
+ child.setText(2, tag.getGuid());\r
+ child.setTextAlignment(1, ra.value());\r
+ tempList.remove(i);\r
+ index.add(child); \r
+ index.get(j).addChild(child);\r
+ }\r
+ }\r
+ }\r
+ } \r
+ }\r
+ resizeColumnToContents(0);\r
+ resizeColumnToContents(1);\r
+ sortItems(0, SortOrder.AscendingOrder);\r
+ }\r
+ // Show (unhide) all tags\r
+ public void showAllTags(boolean value) {\r
+ showAllTags = value;\r
+ }\r
+ public void unhideAllTags() {\r
+ MatchFlags flags = new MatchFlags();\r
+ flags.set(MatchFlag.MatchWildcard);\r
+ flags.set(MatchFlag.MatchRecursive);\r
+ List <QTreeWidgetItem> children = findItems("*", flags);\r
+ for (int i=0; i<children.size(); i++) {\r
+ children.get(i).setHidden(false);\r
+ }\r
+ }\r
+ // update the display with the current number of notes\r
+ public void updateCounts(List<TagCounter> counts) {\r
+ \r
+ MatchFlags flags = new MatchFlags();\r
+ flags.set(MatchFlag.MatchWildcard);\r
+ flags.set(MatchFlag.MatchRecursive);\r
+// List<QTreeWidgetItem> children = new ArrayList<QTreeWidgetItem>();\r
+ List <QTreeWidgetItem> children = findItems("*", flags);\r
+ \r
+ QBrush black = new QBrush();\r
+ black.setColor(QColor.black);\r
+ QBrush blue = new QBrush();\r
+ blue.setColor(QColor.blue);\r
+ if (!Global.tagBehavior().equalsIgnoreCase("ColorActive"))\r
+ blue.setColor(QColor.black);\r
+ \r
+ for (int i=0; i<children.size(); i++) {\r
+ children.get(i).setText(1,"0");\r
+ children.get(i).setForeground(0, black); \r
+ children.get(i).setForeground(1, black);\r
+ if (!showAllTags && (Global.tagBehavior().equalsIgnoreCase("HideInactiveCount") || Global.tagBehavior().equalsIgnoreCase("HideInactiveNoCount")))\r
+ children.get(i).setHidden(true);\r
+ else\r
+ children.get(i).setHidden(false);\r
+ if (children.get(i).isSelected())\r
+ children.get(i).setHidden(false);\r
+ }\r
+ for (int i=0; i<counts.size(); i++) {\r
+ for (int j=0; j<children.size(); j++) {\r
+ String guid = children.get(j).text(2);\r
+ if (counts.get(i).getGuid().equals(guid)) {\r
+ children.get(j).setText(1, new Integer(counts.get(i).getCount()).toString());\r
+ if (counts.get(i).getCount() > 0 || children.get(j).isSelected()) {\r
+ children.get(j).setForeground(0, blue); \r
+ children.get(j).setForeground(1, blue);\r
+ QTreeWidgetItem parent = children.get(j);\r
+ while (parent != null) {\r
+ parent.setForeground(0, blue); \r
+ parent.setForeground(1, blue);\r
+ parent.setHidden(false);\r
+ parent = parent.parent();\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ \r
+ public boolean selectGuid(String guid) {\r
+ MatchFlags flags = new MatchFlags();\r
+ flags.set(MatchFlag.MatchWildcard);\r
+ flags.set(MatchFlag.MatchRecursive);\r
+// List<QTreeWidgetItem> children = new ArrayList<QTreeWidgetItem>();\r
+ List <QTreeWidgetItem> children = findItems("*", flags);\r
+\r
+ for (int i=0; i<children.size(); i++) {\r
+ if (children.get(i).text(2).equals(guid)) {\r
+ children.get(i).setSelected(true);\r
+ return true;\r
+ }\r
+ }\r
+ return false;\r
+ }\r
+ \r
+ @Override\r
+ protected void dragMoveEvent(QDragMoveEvent event) {\r
+ if (event.mimeData().hasFormat("application/x-nevernote-note")) {\r
+ if (event.answerRect().intersects(childrenRect()))\r
+ event.acceptProposedAction();\r
+ return;\r
+ }\r
+ }\r
+\r
+ \r
+ @Override\r
+ public void dragEnterEvent(QDragEnterEvent event) {\r
+ if (event.mimeData().hasFormat("application/x-nevernote-note")) {\r
+ event.accept();\r
+ return;\r
+ }\r
+ if (event.source() == this) {\r
+ event.mimeData().setData("application/x-nevernote-tag", new QByteArray(currentItem().text(2)));\r
+ event.accept();\r
+ return;\r
+ }\r
+ event.ignore();\r
+ }\r
+\r
+ @Override\r
+ public boolean dropMimeData(QTreeWidgetItem parent, int index, QMimeData data, Qt.DropAction action) {\r
+ if (data.hasFormat("application/x-nevernote-tag")) {\r
+ QByteArray d = data.data("application/x-nevernote-tag");\r
+ String current = d.toString();\r
+ \r
+ // Check we don't do a dumb thing like move a parent to a child of itself\r
+ if (!checkParent(parent, current))\r
+ return false;\r
+ QTreeWidgetItem newChild;\r
+ if (parent == null) {\r
+ tagSignal.changeParent.emit(current, "");\r
+ db.getTagTable().updateTagParent(current, "");\r
+ newChild = new QTreeWidgetItem(this);\r
+ } else {\r
+ tagSignal.changeParent.emit(current, parent.text(2));\r
+ db.getTagTable().updateTagParent(current, parent.text(2));\r
+ newChild = new QTreeWidgetItem(parent);\r
+ }\r
+ copyTreeItem(currentItem(), newChild);\r
+ currentItem().setHidden(true);\r
+ sortItems(0, SortOrder.AscendingOrder);\r
+ return true;\r
+ }\r
+ if (data.hasFormat("application/x-nevernote-note")) {\r
+ QByteArray d = data.data("application/x-nevernote-note");\r
+ String s = d.toString();\r
+ String noteGuidArray[] = s.split(" ");\r
+ for (String element : noteGuidArray) {\r
+ if (!db.getNoteTable().noteTagsTable.checkNoteNoteTags(element.trim(), parent.text(2))) {\r
+ db.getNoteTable().noteTagsTable.saveNoteTag(element.trim(), parent.text(2));\r
+ noteSignal.tagsAdded.emit(element.trim(), parent.text(2));\r
+ }\r
+ }\r
+ //tagSignal.listChanged.emit();\r
+ \r
+ return true;\r
+ }\r
+ return false;\r
+ }\r
+ \r
+ @Override\r
+ public void contextMenuEvent(QContextMenuEvent event) {\r
+ QMenu menu = new QMenu(this);\r
+ menu.addAction(addAction);\r
+ menu.addAction(editAction);\r
+ menu.addAction(deleteAction);\r
+ menu.exec(event.globalPos());\r
+ }\r
+ \r
+ // Copy an individual item within the tree. I need to do this because\r
+ // Qt doesn't call the dropMimeData on a move, just a copy.\r
+ private void copyTreeItem(QTreeWidgetItem source, QTreeWidgetItem target) {\r
+ target.setText(0, source.text(0));\r
+ target.setIcon(0, source.icon(0));\r
+ target.setText(1, source.text(1));\r
+ target.setText(2, source.text(2));\r
+ Qt.Alignment ra = new Qt.Alignment(Qt.AlignmentFlag.AlignRight);\r
+ target.setTextAlignment(1, ra.value());\r
+ \r
+ for (int i=0; i<source.childCount(); i++) {\r
+ QTreeWidgetItem newChild = new QTreeWidgetItem(target);\r
+ copyTreeItem(source.child(i), newChild);\r
+ source.child(i).setHidden(true);\r
+ }\r
+ return;\r
+ }\r
+ \r
+ // Check that we don't copy a parent as a child of a current child.\r
+ private boolean checkParent(QTreeWidgetItem parent, String child) {\r
+ if (parent != null)\r
+ if (parent.text(2).equals(child))\r
+ return false;\r
+ if (parent == null)\r
+ return true;\r
+ return checkParent(parent.parent(), child);\r
+ }\r
+\r
+\r
+ public void selectSavedSearch(QTreeWidgetItem item) {\r
+ MatchFlags flags = new MatchFlags();\r
+ flags.set(MatchFlag.MatchWildcard);\r
+ flags.set(MatchFlag.MatchRecursive);\r
+ List <QTreeWidgetItem> children = findItems("*", flags);\r
+ \r
+ for (int j=0; j<children.size(); j++) {\r
+ String guid = children.get(j).text(2);\r
+ if (item.text(2).equals(guid)) {\r
+ children.get(j).setSelected(true);\r
+ }\r
+ }\r
+ }\r
+}\r
--- /dev/null
+package cx.fbn.nevernote.gui;\r
+\r
+import com.trolltech.qt.core.QByteArray;\r
+import com.trolltech.qt.core.QFile;\r
+import com.trolltech.qt.core.QIODevice;\r
+import com.trolltech.qt.core.QObject;\r
+import com.trolltech.qt.core.QSize;\r
+import com.trolltech.qt.core.QUrl;\r
+import com.trolltech.qt.core.Qt.Orientation;\r
+import com.trolltech.qt.core.Qt.ScrollBarPolicy;\r
+import com.trolltech.qt.gui.QImage;\r
+import com.trolltech.qt.gui.QPainter;\r
+import com.trolltech.qt.webkit.QWebPage;\r
+\r
+import cx.fbn.nevernote.Global;\r
+\r
+public class Thumbnailer extends QObject {\r
+ public QWebPage page;\r
+ public QImage image;\r
+ public QPainter painter;\r
+ public Signal1<String> finished;\r
+ public String guid;\r
+ \r
+ public Thumbnailer(String g, QSize s)\r
+ {\r
+ guid = g;\r
+ finished = new Signal1<String>();\r
+ page = new QWebPage();\r
+ painter = new QPainter();\r
+\r
+ page.mainFrame().setScrollBarPolicy(Orientation.Horizontal, ScrollBarPolicy.ScrollBarAlwaysOff);\r
+ page.mainFrame().setScrollBarPolicy(Orientation.Vertical, ScrollBarPolicy.ScrollBarAlwaysOff);\r
+ page.loadFinished.connect(this, "loadFinished(Boolean)");\r
+ }\r
+ \r
+ public void setContent(String content) {\r
+ QFile file = new QFile(Global.currentDir+"res/thumbnail-"+guid+".html");\r
+ file.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));\r
+ file.write(new QByteArray(content));\r
+ file.close(); \r
+ page.mainFrame().load(new QUrl(QUrl.fromLocalFile(file.fileName()).toString()));\r
+ }\r
+ \r
+\r
+ \r
+ public void loadFinished(Boolean ok)\r
+ {\r
+ if (!ok)\r
+ return;\r
+ \r
+ QSize size = page.currentFrame().contentsSize();\r
+ if (size.height() > 2000)\r
+ size.setHeight(800);\r
+ if (size.width() < 600)\r
+ size.setWidth(600);\r
+ if (size.width() > 2000)\r
+ size.setWidth(600);\r
+ \r
+ page.setViewportSize(size);\r
+ image = new QImage(size, QImage.Format.Format_RGB32);\r
+ painter.begin(image);\r
+\r
+ page.mainFrame().render(painter); //<<<< THIS CAN LOCKUP if height too big!!!!\r
+ painter.end();\r
+ \r
+ image.save(Global.currentDir+"res/thumbnail-"+guid+".png");\r
+ finished.emit(guid);\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.gui;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.trolltech.qt.core.QByteArray;\r
+import com.trolltech.qt.core.Qt;\r
+import com.trolltech.qt.gui.QAbstractItemView;\r
+import com.trolltech.qt.gui.QAction;\r
+import com.trolltech.qt.gui.QBrush;\r
+import com.trolltech.qt.gui.QColor;\r
+import com.trolltech.qt.gui.QContextMenuEvent;\r
+import com.trolltech.qt.gui.QDragEnterEvent;\r
+import com.trolltech.qt.gui.QHeaderView;\r
+import com.trolltech.qt.gui.QIcon;\r
+import com.trolltech.qt.gui.QMenu;\r
+import com.trolltech.qt.gui.QTreeWidget;\r
+import com.trolltech.qt.gui.QTreeWidgetItem;\r
+\r
+public class TrashTreeWidget extends QTreeWidget {\r
+ private QAction emptyAction;\r
+ private QTreeWidgetItem trashItem;\r
+ private Integer trashCount; \r
+ \r
+ public void setEmptyAction(QAction a) {\r
+ emptyAction = a;\r
+ }\r
+ \r
+ \r
+ public TrashTreeWidget() {\r
+ trashCount = 0;\r
+ }\r
+ \r
+ public void updateCounts(Integer cnt) {\r
+ QBrush gray = new QBrush();\r
+ gray.setColor(QColor.gray);\r
+ QBrush black = new QBrush();\r
+ black.setColor(QColor.black);\r
+ \r
+ trashCount = cnt;\r
+ trashItem.setText(1, trashCount.toString());\r
+ header().resizeSection(1, 0);\r
+ if (trashCount > 0) {\r
+ trashItem.setForeground(0, black); \r
+ trashItem.setForeground(1, black); \r
+ } else {\r
+ trashItem.setForeground(0, gray); \r
+ trashItem.setForeground(1, gray); \r
+ }\r
+ }\r
+ \r
+ public void load() {\r
+ String iconPath = new String("classpath:cx/fbn/nevernote/icons/");\r
+ QIcon trashIcon = new QIcon(iconPath+"trash.png");\r
+ trashItem = new QTreeWidgetItem();\r
+ trashItem.setIcon(0, trashIcon);\r
+ trashItem.setText(0, "Trash");\r
+ Qt.Alignment ra = new Qt.Alignment(Qt.AlignmentFlag.AlignRight);\r
+ trashItem.setTextAlignment(1, ra.value());\r
+ List<String> headers = new ArrayList<String>();\r
+ headers.add("");\r
+ headers.add("");\r
+ setHeaderLabels(headers);\r
+ setColumnCount(2);\r
+ header().setResizeMode(0, QHeaderView.ResizeMode.ResizeToContents);\r
+ header().setResizeMode(1, QHeaderView.ResizeMode.Stretch);\r
+ header().setMovable(false);\r
+ setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection);\r
+ addTopLevelItem(trashItem);\r
+
+ }\r
+\r
+ @Override\r
+ public void contextMenuEvent(QContextMenuEvent event) {\r
+ QMenu menu = new QMenu(this);\r
+ menu.addAction(emptyAction);\r
+ menu.exec(event.globalPos());\r
+ }\r
+ \r
+ \r
+ @Override\r
+ public void dragEnterEvent(QDragEnterEvent event) {\r
+ event.mimeData().setData("application/x-nevernote-trash", new QByteArray(currentItem().text(1)));\r
+ event.accept();\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.signals;\r
+\r
+import com.trolltech.qt.QSignalEmitter;\r
+\r
+public class DBRunnerSignal extends QSignalEmitter {\r
+ public Signal0 stop = new Signal0();\r
+ public Signal0 start = new Signal0();\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.signals;\r
+\r
+import com.trolltech.qt.QSignalEmitter;\r
+\r
+\r
+public class NoteIndexSignal extends QSignalEmitter {\r
+ public Signal1<Boolean> listChanged = new Signal1<Boolean>();\r
+ public Signal0 notebookSelectionChanged = new Signal0();\r
+ public Signal0 tagSelectionChanged = new Signal0();\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.signals;\r
+\r
+import com.trolltech.qt.QSignalEmitter;\r
+\r
+\r
+public class NoteResourceSignal extends QSignalEmitter {\r
+ public Signal1<String> resourceIndexed = new Signal1<String>();\r
+ public Signal2<String, Boolean> resourceIndexNeeded = new Signal2<String, Boolean>();\r
+ public Signal3<String,String,String> resourceGuidChanged = new Signal3<String,String,String>();\r
+ public Signal1<String> contentChanged = new Signal1<String>();\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+package cx.fbn.nevernote.signals;\r
+\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.Note;\r
+import com.trolltech.qt.QSignalEmitter;\r
+import com.trolltech.qt.core.QDateTime;\r
+\r
+\r
+public class NoteSignal extends QSignalEmitter {\r
+ @SuppressWarnings("unchecked")\r
+ public Signal2<String, List> tagsChanged = new Signal2<String, List>(); \r
+ public Signal2<String, String> tagsAdded = new Signal2<String, String>();\r
+ public Signal2<String, String> titleChanged = new Signal2<String, String>();\r
+ public Signal2<String, String> noteChanged = new Signal2<String, String>();\r
+ public Signal2<String, String> notebookChanged = new Signal2<String,String>();\r
+ public Signal2<String, QDateTime> createdDateChanged = new Signal2<String, QDateTime>();\r
+ public Signal2<String, QDateTime> alteredDateChanged = new Signal2<String, QDateTime>();\r
+ public Signal2<String, QDateTime> subjectDateChanged = new Signal2<String, QDateTime>();\r
+ public Signal2<String, String> authorChanged = new Signal2<String, String>();\r
+ public Signal2<String, String> sourceUrlChanged = new Signal2<String, String>();\r
+ public Signal0 quotaChanged = new Signal0();\r
+ public Signal1<String> noteIndexed = new Signal1<String>();\r
+ public Signal1<Note> noteAdded = new Signal1<Note>();\r
+ public Signal2<String, String> guidChanged = new Signal2<String, String>();\r
+ public Signal1<Integer> titleColorChanged = new Signal1<Integer>();\r
+}\r
+\r
+\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.signals;\r
+\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.Notebook;\r
+import com.trolltech.qt.QSignalEmitter;\r
+\r
+import cx.fbn.nevernote.filters.NotebookCounter;\r
+\r
+\r
+public class NotebookSignal extends QSignalEmitter {\r
+ public Signal0 listChanged = new Signal0();\r
+ public Signal2<List<Notebook>, List<NotebookCounter>> refreshNotebookTreeCounts = new Signal2<List<Notebook>, List<NotebookCounter>>();\r
+ public Signal1<List<NotebookCounter>> countsChanged = new Signal1<List<NotebookCounter>>();\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.signals;\r
+\r
+import com.trolltech.qt.QSignalEmitter;\r
+\r
+\r
+public class SavedSearchSignal extends QSignalEmitter {\r
+ public Signal0 listChanged = new Signal0();\r
+ public Signal0 listSelectionChanged = new Signal0();\r
+}\r
--- /dev/null
+/*
+ * This file is part of NeverNote
+ * 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.signals;
+
+import com.trolltech.qt.QSignalEmitter;
+public class StatusSignal extends QSignalEmitter {
+ public Signal1<String> message = new Signal1<String>();
+}
--- /dev/null
+/*
+ * This file is part of NeverNote
+ * 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.signals;
+
+import com.evernote.edam.notestore.NoteStore;
+import com.evernote.edam.type.User;
+import com.evernote.edam.userstore.UserStore;
+import com.trolltech.qt.QSignalEmitter;
+
+
+public class SyncSignal extends QSignalEmitter {
+ public Signal1<Boolean> finished = new Signal1<Boolean>();
+ public Signal0 errorDisconnect = new Signal0();
+// public Signal1<Long> setSequenceDate = new Signal1<Long>();
+ public Signal1<Long> saveUploadAmount = new Signal1<Long>();
+// public Signal1<Integer> setUpdateSequenceNumber = new Signal1<Integer>();
+ public Signal1<Integer> saveEvernoteUpdateCount = new Signal1<Integer>();
+ public Signal1<User> saveUserInformation = new Signal1<User>();
+ public Signal1<String> saveAuthToken = new Signal1<String>();
+ public Signal1<UserStore.Client> saveUserStore = new Signal1<UserStore.Client>();
+ public Signal1<NoteStore.Client> saveNoteStore = new Signal1<NoteStore.Client>();
+ public Signal1<Boolean> authRefreshComplete = new Signal1<Boolean>();
+
+ public Signal0 refreshNotebooks = new Signal0();
+ public Signal0 refreshTags = new Signal0();
+ public Signal0 refreshSavedSearches = new Signal0();
+ public Signal0 refreshNotes = new Signal0();
+ public Signal0 refreshLists = new Signal0();
+}
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.signals;\r
+\r
+import java.util.List;\r
+\r
+import com.trolltech.qt.QSignalEmitter;\r
+\r
+import cx.fbn.nevernote.filters.TagCounter;\r
+\r
+\r
+public class TagSignal extends QSignalEmitter {\r
+ public Signal0 listChanged = new Signal0();\r
+ public Signal2<String,String> changeParent = new Signal2<String, String>();\r
+ public Signal1<List<TagCounter>> refreshTagTreeCounts = new Signal1<List<TagCounter>>();\r
+ public Signal1<List<TagCounter>> countsChanged = new Signal1<List<TagCounter>>();\r
+\r
+}\r
--- /dev/null
+/*
+ * This file is part of NeverNote
+ * 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.signals;
+
+import com.trolltech.qt.QSignalEmitter;
+
+public class ThreadSignal extends QSignalEmitter {
+ public Signal1<String> filterChanged = new Signal1<String>();
+ public Signal0 exit = new Signal0();
+ public Signal2<String, String> deleteNoteFromWordIndex = new Signal2<String, String>();
+ public Signal4<String, String, String, Integer> addNoteToWordIndex = new Signal4<String, String, String, Integer>();
+ public Signal3<String, String, Boolean> indexNeeded = new Signal3<String, String, Boolean>();
+}
--- /dev/null
+/*
+ * This file is part of NeverNote
+ * 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.signals;
+
+import com.trolltech.qt.QSignalEmitter;
+
+public class TrashSignal extends QSignalEmitter {
+ public Signal1<Integer> countChanged = new Signal1<Integer>();
+}
--- /dev/null
+/*
+ * This file is part of NeverNote
+ * 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.io.File;
+
+import cx.fbn.nevernote.Global;
+import cx.fbn.nevernote.sql.requests.DatabaseRequest;
+import cx.fbn.nevernote.utilities.ApplicationLogger;
+
+
+public class DatabaseConnection {
+ // Table helpers
+ private final WordsTable wordsTable;
+ private final TagTable tagTable;
+ private final NotebookTable notebookTable;
+ private final NoteTable noteTable;
+ private final DeletedTable deletedTable;
+ private final SavedSearchTable searchTable;
+ private final WatchFolderTable watchFolderTable;
+ private final InvalidXMLTable invalidXMLTable;
+ private final SyncTable syncTable;
+ private final ApplicationLogger logger;
+ int id;
+
+
+ public DatabaseConnection(ApplicationLogger l, int i) {
+ id = i;
+ tagTable = new TagTable(id);
+ notebookTable = new NotebookTable(id);
+ noteTable = new NoteTable(id);
+ deletedTable = new DeletedTable(id);
+ searchTable = new SavedSearchTable(id);
+ watchFolderTable = new WatchFolderTable(id);
+ wordsTable = new WordsTable(id);
+ invalidXMLTable = new InvalidXMLTable(id);
+ syncTable = new SyncTable(id);
+ logger = l;
+
+ }
+
+
+ // Initialize the database connection
+ public void dbSetup() {
+ logger.log(logger.HIGH, "Entering DatabaseConnection.dbSetup " +id);
+
+ File f = new File(Global.getDirectoryPath() +File.separator +"db" +File.separator +"NeverNote.h2.db");
+ boolean dbExists = f.exists();
+
+ // If it doesn't exist and we are the main thread, then we need to create stuff.
+ if (!dbExists && id == 0) {
+ createTables();
+ Global.setAutomaticLogin(false);
+ }
+
+ logger.log(logger.HIGH, "Leaving DatabaseConnection.dbSetup" +id);
+ }
+
+
+ public void dbShutdown() {
+ DatabaseRequest req = new DatabaseRequest();
+ req.type = DatabaseRequest.Shutdown;
+ Global.dbRunner.addWork(req);
+ }
+
+ public void upgradeDb(String version) {
+ if (version.equals("0.85")) {
+ DatabaseRequest req = new DatabaseRequest();
+ req.type = DatabaseRequest.Execute_Sql;
+ req.string1 = new String("alter table note add column titleColor integer");
+ Global.dbRunner.addWork(req);
+ Global.dbClientWait(id);
+ req.type = DatabaseRequest.Execute_Sql;
+ req.string1 = new String("update note set titlecolor=-1");
+ Global.dbRunner.addWork(req);
+ Global.dbClientWait(id);
+ req.type = DatabaseRequest.Execute_Sql;
+ req.string1 = new String("alter table note add column thumbnail blob");
+ Global.dbRunner.addWork(req);
+ Global.dbClientWait(id);
+ req.string1 = new String("alter table note add column thumbnailneeded boolean");
+ Global.dbRunner.addWork(req);
+ Global.dbClientWait(id);
+ req.string1 = new String("Update note set thumbnailneeded = true;");
+ Global.dbRunner.addWork(req);
+ Global.dbClientWait(id);
+ req.string1 = new String("create index NOTE_NOTEBOOK_INDEX on note (notebookguid, guid);");
+ Global.dbRunner.addWork(req);
+ Global.dbClientWait(id);
+ req.string1 = new String("create index NOTETAGS_TAG_INDEX on notetags (tagguid, noteguid);");
+ Global.dbRunner.addWork(req);
+ Global.dbClientWait(id);
+ version = "0.86";
+ Global.setDatabaseVersion(version);
+ }
+ }
+
+ public void checkDatabaseVersion() {
+ if (!Global.getDatabaseVersion().equals("0.86")) {
+ upgradeDb(Global.getDatabaseVersion());
+ }
+ }
+
+ public void compactDatabase() {
+ DatabaseRequest request = new DatabaseRequest();
+ request.requestor_id = id;
+ request.type = DatabaseRequest.Compact;
+ Global.dbRunner.addWork(request);
+ Global.dbClientWait(id);
+ }
+
+ public void backupDatabase(int highSequence, long date) {
+ DatabaseRequest request = new DatabaseRequest();
+ request.requestor_id = id;
+ request.int1 = highSequence;
+ request.long1 = date;
+ request.type = DatabaseRequest.Backup_Database;
+ Global.dbRunner.addWork(request);
+ Global.dbClientWait(id);
+ }
+
+
+ public void createTables() {
+ Global.setDatabaseVersion("0.85");
+// Global.setUpdateSequenceNumber(0);
+ Global.setAutomaticLogin(false);
+ Global.saveCurrentNoteGuid("");
+ Global.saveUploadAmount(0);
+
+ }
+
+ //***************************************************************
+ //* Table get methods
+ //***************************************************************
+ public DeletedTable getDeletedTable() {
+ return deletedTable;
+ }
+ public TagTable getTagTable() {
+ return tagTable;
+ }
+ public NoteTable getNoteTable() {
+ return noteTable;
+ }
+ public NotebookTable getNotebookTable() {
+ return notebookTable;
+ }
+ public SavedSearchTable getSavedSearchTable() {
+ return searchTable;
+ }
+ public WatchFolderTable getWatchFolderTable() {
+ return watchFolderTable;
+ }
+ public WordsTable getWordsTable() {
+ return wordsTable;
+ }
+ public InvalidXMLTable getInvalidXMLTable() {
+ return invalidXMLTable;
+ }
+ public SyncTable getSyncTable() {
+ return syncTable;
+ }
+}
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.sql;\r
+\r
+import java.util.List;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.sql.requests.DeletedItemRequest;\r
+import cx.fbn.nevernote.sql.runners.DeletedItemRecord;\r
+import cx.fbn.nevernote.utilities.ListManager;\r
+\r
+public class DeletedTable {\r
+ ListManager parent;\r
+ int id;\r
+ \r
+ // Constructor\r
+ public DeletedTable(int i) {\r
+ id = i;\r
+ }\r
+ // Create the table\r
+ public void createTable() {\r
+ DeletedItemRequest request = new DeletedItemRequest();\r
+ request.requestor_id = id;\r
+ request.type = DeletedItemRequest.Create_Table;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Drop the table\r
+ public void dropTable() {\r
+ DeletedItemRequest request = new DeletedItemRequest();\r
+ request.requestor_id = id;\r
+ request.type = DeletedItemRequest.Drop_Table;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Add an item to the deleted table\r
+ public void addDeletedItem(String guid, String type) {\r
+ DeletedItemRequest request = new DeletedItemRequest();\r
+ request.requestor_id = id;\r
+ request.string1 = guid;\r
+ request.string2 = type;\r
+ request.type = DeletedItemRequest.Add_Deleted_Item;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ public List<DeletedItemRecord> getAllDeleted() {\r
+ DeletedItemRequest request = new DeletedItemRequest();\r
+ request.requestor_id = id;\r
+ request.type = DeletedItemRequest.Get_All;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ DeletedItemRequest req = Global.dbRunner.deletedItemResponse.get(id).copy();\r
+ return req.responseDeletedRecords;\r
+ }\r
+ public void expungeDeletedItem(String guid, String type) {\r
+ DeletedItemRequest request = new DeletedItemRequest();\r
+ request.requestor_id = id;\r
+ request.string1 = guid;\r
+ request.string2 = type;\r
+ request.type = DeletedItemRequest.Expunge_Record;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ public void expungeAllDeletedRecords() {\r
+ DeletedItemRequest request = new DeletedItemRequest();\r
+ request.requestor_id = id;\r
+ request.type = DeletedItemRequest.Expunge_All;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.sql;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.sql.requests.InvalidXMLRequest;\r
+import cx.fbn.nevernote.utilities.ListManager;\r
+\r
+public class InvalidXMLTable {\r
+ ListManager parent;\r
+ int id;\r
+ \r
+ // Constructor\r
+ public InvalidXMLTable(int i) {\r
+ id = i;\r
+ }\r
+ // Create the table\r
+ public void createTable() {\r
+ InvalidXMLRequest request = new InvalidXMLRequest();\r
+ request.requestor_id = id;\r
+ request.type = InvalidXMLRequest.Create_Table;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Drop the table\r
+ public void dropTable() {\r
+ InvalidXMLRequest request = new InvalidXMLRequest();\r
+ request.requestor_id = id;\r
+ request.type = InvalidXMLRequest.Drop_Table;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Add an invalid XML element to the table\r
+ public void addInvalidElement(String element) {\r
+ InvalidXMLRequest request = new InvalidXMLRequest();\r
+ request.requestor_id = id;\r
+ request.string1 = element;\r
+ request.type = InvalidXMLRequest.Add_Invalid_Element;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Add an invalid XML attribute to the table\r
+ public void addInvalidAttribute(String element, String attribute) {\r
+ InvalidXMLRequest request = new InvalidXMLRequest();\r
+ request.requestor_id = id;\r
+ request.string1 = element;\r
+ request.string2 = attribute;\r
+ request.type = InvalidXMLRequest.Add_Invalid_Attribute;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Get invalid attributes for a given element\r
+ public List<String> getInvalidAttributeElements() {\r
+ InvalidXMLRequest request = new InvalidXMLRequest();\r
+ request.requestor_id = id;\r
+ request.type = InvalidXMLRequest.Get_Invalid_Attribute_Elements;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ InvalidXMLRequest req = Global.dbRunner.invalidXMLResponse.get(id).copy();\r
+ return req.responseList;\r
+ }\r
+ // Get the list of elements which we have invalid attributes for\r
+ public ArrayList<String> getInvalidAttributes(String element) {\r
+ InvalidXMLRequest request = new InvalidXMLRequest();\r
+ request.requestor_id = id;\r
+ request.string1 = element;\r
+ request.type = InvalidXMLRequest.Get_Invalid_Attributes;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ InvalidXMLRequest req = Global.dbRunner.invalidXMLResponse.get(id).copy();\r
+ return req.responseArrayList;\r
+ }\r
+ // Add an invalid XML attribute to the table\r
+ public List<String> getInvalidElements() {\r
+ InvalidXMLRequest request = new InvalidXMLRequest();\r
+ request.requestor_id = id;\r
+ request.type = InvalidXMLRequest.Get_Invalid_Elements;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ InvalidXMLRequest req = Global.dbRunner.invalidXMLResponse.get(id).copy();\r
+ return req.responseList;\r
+ }\r
+ \r
+ \r
+\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.sql;\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.Resource;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.sql.requests.ResourceRequest;\r
+\r
+\r
+public class NoteResourceTable {\r
+ private final int id;\r
+ \r
+ // Constructor\r
+ public NoteResourceTable(int i) {\r
+ id = i;\r
+ }\r
+ // Create the table\r
+ public void createTable() {\r
+ ResourceRequest request = new ResourceRequest();\r
+ request.requestor_id = id;\r
+ request.type = ResourceRequest.Create_Table;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Drop the table\r
+ public void dropTable() { \r
+ ResourceRequest request = new ResourceRequest();\r
+ request.requestor_id = id;\r
+ request.type = ResourceRequest.Drop_Table;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Reset the dirty flag\r
+ public void resetDirtyFlag(String guid) {\r
+ ResourceRequest request = new ResourceRequest();\r
+ request.requestor_id = id;\r
+ request.type = ResourceRequest.Reset_Dirty_Flag;\r
+ request.string1 = new String(guid);\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Set if the resource should be indexed\r
+ public void setIndexNeeded(String guid, Boolean indexNeeded) {\r
+ ResourceRequest request = new ResourceRequest();\r
+ request.requestor_id = id;\r
+ request.type = ResourceRequest.Set_Index_Needed;\r
+ request.string1 = new String(guid);\r
+ request.bool1 = indexNeeded;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // get any unindexed resource\r
+ public List<String> getNextUnindexed(int limit) {\r
+ ResourceRequest request = new ResourceRequest();\r
+ request.requestor_id = id;\r
+ request.type = ResourceRequest.Get_Next_Unindexed;\r
+ request.int1 = limit;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ ResourceRequest req = Global.dbRunner.resourceResponse.get(id).copy();\r
+ return req.responseStrings;\r
+ }\r
+ public void saveNoteResource(Resource r, boolean isDirty) {\r
+ ResourceRequest request = new ResourceRequest();\r
+ request.requestor_id = id;\r
+ request.type = ResourceRequest.Save_Note_Resource;\r
+ request.resource = r.deepCopy();\r
+ request.bool1 = isDirty;\r
+ Global.dbRunner.addWork(request);\r
+// Global.dbClientWait(id);\r
+ }\r
+ // delete an old resource\r
+ public void expungeNoteResource(String guid) {\r
+ ResourceRequest request = new ResourceRequest();\r
+ request.requestor_id = id;\r
+ request.type = ResourceRequest.Expunge_Note_Resource;\r
+ request.string1 = new String(guid);\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+\r
+ // Get a note resource from the database by it's hash value\r
+ public String getNoteResourceGuidByHashHex(String noteGuid, String hash) {\r
+ ResourceRequest request = new ResourceRequest();\r
+ request.requestor_id = id;\r
+ request.type = ResourceRequest.Get_Note_Resource_Guid_By_Hash_Hex;\r
+ request.string1 = new String(noteGuid);\r
+ request.string2 = new String(hash);\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ ResourceRequest req = Global.dbRunner.resourceResponse.get(id).copy();\r
+ return req.responseString; \r
+ }\r
+ // Get a note resource from the database by it's hash value\r
+ public Resource getNoteResourceDataBodyByHashHex(String noteGuid, String hash) {\r
+ ResourceRequest request = new ResourceRequest();\r
+ request.requestor_id = id;\r
+ request.type = ResourceRequest.Get_Note_Resource_Data_Body_By_Hash_Hex;\r
+ request.string1 = new String(noteGuid);\r
+ request.string2 = new String(hash);\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ ResourceRequest req = Global.dbRunner.resourceResponse.get(id).copy();\r
+ return req.responseResource;\r
+ }\r
+\r
+ // Update a note resource guid\r
+ public void updateNoteResourceGuid(String oldGuid, String newGuid, boolean isDirty) {\r
+ ResourceRequest request = new ResourceRequest();\r
+ request.requestor_id = id;\r
+ request.type = ResourceRequest.Update_Note_Resource_Guid;\r
+ request.string1 = new String(oldGuid);\r
+ request.string2 = new String(newGuid);\r
+ request.bool1 = isDirty;\r
+ Global.dbRunner.addWork(request);\r
+// Global.dbClientWait(id);\r
+ }\r
+ \r
+\r
+ // Reset update sequence number to zero\r
+ public void resetUpdateSequenceNumber(String guid, boolean isDirty) {\r
+ ResourceRequest request = new ResourceRequest();\r
+ request.requestor_id = id;\r
+ request.type = ResourceRequest.Reset_Update_Sequence_Number;\r
+ request.string1 = new String(guid);\r
+ request.bool1 = isDirty;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ \r
+ // Get a note's resourcesby Guid\r
+ public Resource getNoteResource(String guid, boolean withBinary) {\r
+ if (guid == null) \r
+ return null;\r
+ ResourceRequest request = new ResourceRequest();\r
+ request.requestor_id = id;\r
+ request.type = ResourceRequest.Get_Note_Resource;\r
+ request.string1 = new String(guid);\r
+ request.bool1 = withBinary;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ ResourceRequest req = Global.dbRunner.resourceResponse.get(id).copy();\r
+ return req.responseResource;\r
+ }\r
+ \r
+ \r
+ // Get a note's resourcesby Guid\r
+ public List<Resource> getNoteResources(String noteGuid, boolean withBinary) {\r
+ ResourceRequest request = new ResourceRequest();\r
+ request.requestor_id = id;\r
+ request.type = ResourceRequest.Get_Note_Resources;\r
+ request.string1 = new String(noteGuid);\r
+ request.bool1 = withBinary;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ ResourceRequest req = Global.dbRunner.resourceResponse.get(id).copy();\r
+ return req.responseResources;\r
+ }\r
+ \r
+ \r
+ // Get all of a note's recognition data by the note guid\r
+ public List<Resource> getNoteResourcesRecognition(String noteGuid) {\r
+ ResourceRequest request = new ResourceRequest();\r
+ request.requestor_id = id;\r
+ request.type = ResourceRequest.Get_Note_Resources_Recognition;\r
+ request.string1 = new String(noteGuid);\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ ResourceRequest req = Global.dbRunner.resourceResponse.get(id).copy();\r
+ return req.responseResources;\r
+ }\r
+ \r
+ // Get a note's recognition data by it's guid.\r
+ public Resource getNoteResourceRecognition(String guid) {\r
+ ResourceRequest request = new ResourceRequest();\r
+ request.requestor_id = id;\r
+ request.type = ResourceRequest.Get_Note_Resource_Recognition;\r
+ request.string1 = new String(guid);\r
+ Global.dbRunner.addWork(request); \r
+ Global.dbClientWait(id);\r
+ ResourceRequest req = Global.dbRunner.resourceResponse.get(id).copy();\r
+ return req.responseResource;\r
+ }\r
+ // Save Note Resource\r
+ public void updateNoteResource(Resource r, boolean isDirty) {\r
+ ResourceRequest request = new ResourceRequest();\r
+ request.requestor_id = id;\r
+ request.type = ResourceRequest.Update_Note_Resource;\r
+ request.resource = r.deepCopy();\r
+ request.bool1 = isDirty;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ \r
+ // Drop the table\r
+ public void reindexAll() { \r
+ ResourceRequest request = new ResourceRequest();\r
+ request.requestor_id = id;\r
+ request.type = ResourceRequest.Reindex_All;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Count unindexed notes\r
+ public int getResourceCount() {\r
+ ResourceRequest request = new ResourceRequest();\r
+ request.requestor_id = id;\r
+ request.type = ResourceRequest.Get_Resource_Count;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ ResourceRequest req = Global.dbRunner.resourceResponse.get(id).copy();\r
+ return req.responseInteger;\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.sql;\r
+\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.Note;\r
+import com.trolltech.qt.core.QByteArray;\r
+import com.trolltech.qt.core.QDateTime;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.sql.requests.NoteRequest;\r
+import cx.fbn.nevernote.utilities.Pair;\r
+\r
+public class NoteTable {\r
+ public NoteResourceTable noteResourceTable;\r
+ public NoteTagsTable noteTagsTable;\r
+ \r
+ int id;\r
+ \r
+ // Constructor\r
+ public NoteTable(int i) {\r
+ id = i;\r
+ noteTagsTable = new NoteTagsTable(id);\r
+ noteResourceTable = new NoteResourceTable(id);\r
+ }\r
+ // Create the table\r
+ public void createTable() {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Create_Table;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Drop the table\r
+ public void dropTable() {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Drop_Table;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Save Note List from Evernote \r
+ public void addNote(Note n, boolean isDirty) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.note = n.deepCopy();\r
+ request.bool1 = isDirty;\r
+ request.type = NoteRequest.Add_Note;\r
+ Global.dbRunner.addWork(request);\r
+ } \r
+ // Get a note by Guid\r
+ public Note getNote(String noteGuid, boolean loadContent, boolean loadResources, boolean loadRecognition, boolean loadBinary, boolean loadTags) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Get_Note;\r
+ request.string1 = new String(noteGuid);\r
+ request.bool1 = loadContent;\r
+ request.bool2 = loadResources;\r
+ request.bool3 = loadRecognition;\r
+ request.bool4 = loadBinary;\r
+ request.bool5 = loadTags;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NoteRequest req = Global.dbRunner.noteResponse.get(id).copy();\r
+ return req.responseNote;\r
+ }\r
+ // Update a note's title\r
+ public void updateNoteTitle(String guid, String title) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Update_Note_Title;\r
+ request.string1 = new String(guid);\r
+ request.string2 = new String(title);\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Update a note's creation date\r
+ public void updateNoteCreatedDate(String guid, QDateTime date) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Update_Note_Creation_Date;\r
+ request.string1 = new String(guid);\r
+ request.date = new QDateTime(date);\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Update a note's creation date\r
+ public void updateNoteAlteredDate(String guid, QDateTime date) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Update_Note_Altered_Date;\r
+ request.string1 = new String(guid);\r
+ request.date = new QDateTime(date);\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Update a note's creation date\r
+ public void updateNoteSubjectDate(String guid, QDateTime date) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Update_Note_Subject_Date;\r
+ request.string1 = new String(guid);\r
+ request.date = new QDateTime(date);\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Update a note's author\r
+ public void updateNoteAuthor(String guid, String author) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Update_Note_Author;\r
+ request.string1 = new String(guid);\r
+ request.string2 = new String(author);\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Update a note's creation date\r
+ public void updateNoteSourceUrl(String guid, String url) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Update_Note_Source_Url;\r
+ request.string1 = new String(guid);\r
+ request.string2 = new String(url);\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Update the notebook that a note is assigned to\r
+ public void updateNoteNotebook(String guid, String notebookGuid, boolean expungeFromRemote) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Update_Note_Notebook;\r
+ request.string1 = new String(guid);\r
+ request.string2 = new String(notebookGuid);\r
+ request.bool1 = expungeFromRemote;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Update a note's content\r
+ public void updateNoteContent(String guid, String content) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Update_Note_Content;\r
+ request.string1 = new String(guid);\r
+ request.string2 = new String(content);\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Get a note's contents as a binary string (useful for unicode on sync)\r
+ public String getNoteContentBinary(String guid) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Get_Note_Content_Binary;\r
+ request.string1 = new String(guid);\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NoteRequest req = Global.dbRunner.noteResponse.get(id).copy();\r
+ return req.responseString;\r
+ }\r
+ // Check a note to see if it passes the attribute selection criteria\r
+ public boolean checkAttributeSelection(Note n) {\r
+ if (Global.createdSinceFilter.check(n) &&\r
+ Global.createdBeforeFilter.check(n) && \r
+ Global.changedSinceFilter.check(n) &&\r
+ Global.changedBeforeFilter.check(n) &&\r
+ Global.containsFilter.check(this, n))\r
+ return true;\r
+ \r
+ return false;\r
+ }\r
+ // Delete a note\r
+ public void deleteNote(String guid) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Delete_Note;\r
+ request.string1 = new String(guid);\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ public void restoreNote(String guid) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Restore_Note;\r
+ request.string1 = new String(guid);\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Purge a note (actually delete it instead of just marking it deleted)\r
+ public void expungeNote(String guid, boolean permanentExpunge, boolean needsSync) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Expunge_Note;\r
+ request.string1 = new String(guid);\r
+ request.bool1 = permanentExpunge;\r
+ request.bool2 = needsSync;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Purge all deleted notes;\r
+ public void expungeAllDeletedNotes() {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Expunge_All_Deleted_Notes;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Update the note sequence number\r
+ public void updateNoteSequence(String guid, int sequence) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Update_Note_Sequence;\r
+ request.string1 = new String(guid);\r
+ request.int1 = sequence;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Update the note Guid\r
+ public void updateNoteGuid(String oldGuid, String newGuid) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Update_Note_Guid;\r
+ request.string1 = new String(oldGuid);\r
+ request.string2 = new String(newGuid);\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Update a note\r
+ public void updateNote(Note n, boolean isNew) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Update_Note;\r
+ request.note = n.deepCopy();\r
+ request.bool1 = isNew;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Does a note exist?\r
+ public boolean exists(String guid) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Exists;\r
+ request.string1 = new String(guid);\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NoteRequest req = Global.dbRunner.noteResponse.get(id).copy();\r
+ return req.responseBoolean;\r
+ }\r
+ // This is a convience method to check if a tag exists & update/create based upon it\r
+ public void syncNote(Note note, boolean isDirty) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Sync_Note;\r
+ request.note = note.deepCopy();\r
+ request.bool1 = isDirty;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Get a list of notes that need to be updated\r
+ public List <Note> getDirty() {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Get_Dirty;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NoteRequest req = Global.dbRunner.noteResponse.get(id).copy();\r
+ return req.responseNotes;\r
+ }\r
+ // Get a list of notes that need to be updated\r
+ public List <String> getUnsynchronizedGUIDs() {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Get_Unsynchronized_Guids;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NoteRequest req = Global.dbRunner.noteResponse.get(id).copy();\r
+ return req.responseStrings;\r
+ }\r
+ public boolean isNoteDirty(String guid) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Is_Note_Dirty;\r
+ request.string1 = new String(guid);\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NoteRequest req = Global.dbRunner.noteResponse.get(id).copy();\r
+ return req.responseBoolean;\r
+ }\r
+ // Reset the dirty bit\r
+ public void resetDirtyFlag(String guid) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Reset_Dirty_Flag;\r
+ request.string1 = new String(guid);\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Get all notes\r
+ public List<String> getAllGuids() {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Get_All_Guids;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NoteRequest req = Global.dbRunner.noteResponse.get(id).copy();\r
+ return req.responseStrings;\r
+ }\r
+ // Get all notes\r
+ public List<Note> getAllNotes() {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Get_All_Notes;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NoteRequest req = Global.dbRunner.noteResponse.get(id).copy();\r
+ return req.responseNotes;\r
+ }\r
+ // Count unindexed notes\r
+ public int getUnindexedCount() {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Get_Unindexed_Count;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NoteRequest req = Global.dbRunner.noteResponse.get(id).copy();\r
+ return req.responseInt;\r
+ }\r
+ // Count unsynchronized count\r
+ public int getDirtyCount() {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Get_Dirty_Count;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NoteRequest req = Global.dbRunner.noteResponse.get(id).copy();\r
+ return req.responseInt;\r
+ }\r
+ // Count unindexed notes\r
+ public int getNoteCount() {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Get_Note_Count;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NoteRequest req = Global.dbRunner.noteResponse.get(id).copy();\r
+ return req.responseInt;\r
+ }\r
+ // Count deleted notes\r
+ public int getDeletedCount() {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Get_Deleted_Count;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NoteRequest req = Global.dbRunner.noteResponse.get(id).copy();\r
+ return req.responseInt;\r
+ }\r
+ // Reset a note's sequence count to zero. This is useful when moving a conflicting note\r
+ public void resetSequenceNumber(String guid) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.string1 = new String(guid);\r
+ request.type = NoteRequest.Reset_Note_Sequence;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ \r
+ // Update a note resource by the hash\r
+ public void updateNoteResourceGuidbyHash(String noteGuid, String resGuid, String hash) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Update_Resource_Guid_By_Hash;\r
+ request.string1 = new String(noteGuid);\r
+ request.string2 = new String(resGuid);\r
+ request.string3 = new String(hash);\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ \r
+ // Get the title color of notes\r
+ public List<Pair<String,Integer>> getNoteTitleColors() {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Get_Title_Colors;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NoteRequest req = Global.dbRunner.noteResponse.get(id).copy();\r
+ return req.responsePair;\r
+ }\r
+ \r
+ // Get the title color of notes\r
+ public void setNoteTitleColor(String guid, int color) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.string1 = new String(guid);\r
+ request.int1 = color;\r
+ request.type = NoteRequest.Set_Title_Colors;\r
+ Global.dbRunner.addWork(request); \r
+ }\r
+ \r
+ \r
+ //********************************************************************************\r
+ //********************************************************************************\r
+ //* Indexing Functions\r
+ //********************************************************************************\r
+ //********************************************************************************\r
+ // set/unset a note to be reindexed\r
+ public void setIndexNeeded(String guid, Boolean flag) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Set_Index_Needed;\r
+ request.string1 = new String(guid);\r
+ request.bool1 = flag;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Set all notes to be reindexed\r
+ public void reindexAllNotes() {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Reindex_All_Notes;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Get all unindexed notes\r
+ public List <String> getUnindexed() {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Get_Unindexed;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NoteRequest req = Global.dbRunner.noteResponse.get(id).copy();\r
+ return req.responseStrings;\r
+ }\r
+ public List<String> getNextUnindexed(int limit) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Get_Next_Unindexed;\r
+ request.int1 = limit;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NoteRequest req = Global.dbRunner.noteResponse.get(id).copy();\r
+ return req.responseStrings;\r
+ }\r
+ \r
+ \r
+ //*********************************************************************************\r
+ //* Thumbnail Functions\r
+ //*********************************************************************************\r
+ // Set if a new thumbnail is needed\r
+ public void setThumbnailNeeded(String guid, boolean needed) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Set_Thumbnail_Needed;\r
+ request.string1 = new String(guid);\r
+ request.bool1 = needed;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Is a thumbail needed for this guid?\r
+ public boolean isThumbnailNeeded(String guid) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Is_Thumbail_Needed;\r
+ request.string1 = new String(guid);\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NoteRequest req = Global.dbRunner.noteResponse.get(id).copy();\r
+ return req.responseBoolean;\r
+ }\r
+ // Set if a new thumbnail is needed\r
+ public void setThumbnail(String guid, QByteArray thumbnail) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Set_Thumbnail;\r
+ request.string1 = new String(guid);\r
+ request.bytes = thumbnail;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Set if a new thumbnail is needed\r
+ public QByteArray getThumbnail(String guid) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Get_Thumbnail;\r
+ request.string1 = new String(guid);\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NoteRequest req = Global.dbRunner.noteResponse.get(id).copy();\r
+ return req.responseBytes;\r
+ }\r
+ \r
+\r
+ \r
+ // Update a note content's hash. This happens if a resource is edited outside of NN\r
+ public void updateResourceContentHash(String guid, String oldHash, String newHash) {\r
+ NoteRequest request = new NoteRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteRequest.Update_Resource_Content_Hash;\r
+ request.string1 = new String(guid);\r
+ request.string2 = new String(oldHash);\r
+ request.string3 = new String(newHash);\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+} \r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.sql;\r
+\r
+import java.util.List;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.sql.requests.NoteTagsRequest;\r
+import cx.fbn.nevernote.sql.runners.NoteTagsRecord;\r
+import cx.fbn.nevernote.utilities.Pair;\r
+\r
+public class NoteTagsTable {\r
+ private final int id;\r
+ \r
+ // Constructor\r
+ public NoteTagsTable(int i) {\r
+ id = i;\r
+ }\r
+ // Create the table\r
+ public void createTable() {\r
+ NoteTagsRequest request = new NoteTagsRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteTagsRequest.Create_Table;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Drop the table\r
+ public void dropTable() {\r
+ NoteTagsRequest request = new NoteTagsRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteTagsRequest.Drop_Table;\r
+ Global.dbRunner.addWork(request); }\r
+ // Get a note tags by the note's Guid\r
+ public List<String> getNoteTags(String noteGuid) {\r
+ NoteTagsRequest request = new NoteTagsRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteTagsRequest.Get_Note_Tags;\r
+ request.string1 = new String(noteGuid);\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NoteTagsRequest req = Global.dbRunner.noteTagsResponse.get(id).copy();\r
+ return req.responseStrings;\r
+ }\r
+ // Get a note tags by the note's Guid\r
+ public List<NoteTagsRecord> getAllNoteTags() {\r
+ NoteTagsRequest request = new NoteTagsRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteTagsRequest.Get_All_Note_Tags;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NoteTagsRequest req = Global.dbRunner.noteTagsResponse.get(id).copy();\r
+ return req.responseNoteTagsRecord;\r
+ }\r
+ // Check if a note has a specific tag already\r
+ public boolean checkNoteNoteTags(String noteGuid, String tagGuid) {\r
+ NoteTagsRequest request = new NoteTagsRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteTagsRequest.Check_Note_Note_Tags;\r
+ request.string1 = new String(noteGuid);\r
+ request.string2 = new String(tagGuid);\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NoteTagsRequest req = Global.dbRunner.noteTagsResponse.get(id).copy();\r
+ return req.responseBoolean;\r
+ }\r
+ // Save Note Tags\r
+ public void saveNoteTag(String noteGuid, String tagGuid) {\r
+ NoteTagsRequest request = new NoteTagsRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteTagsRequest.Save_Note_Tag;\r
+ request.string1 = new String(noteGuid);\r
+ request.string2 = new String(tagGuid);\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Delete a note's tags\r
+ public void deleteNoteTag(String noteGuid) {\r
+ NoteTagsRequest request = new NoteTagsRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteTagsRequest.Delete_Note_Tag;\r
+ request.string1 = new String(noteGuid);\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Get tag counts\r
+ public List<Pair<String,Integer>> getTagCounts() {\r
+ NoteTagsRequest request = new NoteTagsRequest();\r
+ request.requestor_id = id;\r
+ request.type = NoteTagsRequest.Tag_Counts;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NoteTagsRequest req = Global.dbRunner.noteTagsResponse.get(id).copy();\r
+ return req.responseCounts;\r
+ \r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.sql;\r
+\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.Notebook;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.sql.requests.NotebookRequest;\r
+import cx.fbn.nevernote.utilities.Pair;\r
+\r
+public class NotebookTable {\r
+ int id;\r
+ \r
+ public NotebookTable(int i) {\r
+ id = i;\r
+ }\r
+ \r
+ // Create the table\r
+ public void createTable() {\r
+ NotebookRequest request = new NotebookRequest();\r
+ request.requestor_id = id;\r
+ request.type = NotebookRequest.Create_Table;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Drop the table\r
+ public void dropTable() {\r
+ NotebookRequest request = new NotebookRequest();\r
+ request.requestor_id = id;\r
+ request.type = NotebookRequest.Drop_Table;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Save an individual notebook\r
+ public void addNotebook(Notebook tempNotebook, boolean isDirty, boolean local) {\r
+ NotebookRequest request = new NotebookRequest();\r
+ request.requestor_id = id;\r
+ request.type = NotebookRequest.Add_Notebook;\r
+ request.notebook = tempNotebook;\r
+ request.bool1 = isDirty;\r
+ request.bool2 = local;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Delete the notebook based on a guid\r
+ public void expungeNotebook(String guid, boolean needsSync) {\r
+ NotebookRequest request = new NotebookRequest();\r
+ request.requestor_id = id;\r
+ request.type = NotebookRequest.Expunge_Notebook;\r
+ request.string1 = guid;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Update a notebook\r
+ public void updateNotebook(Notebook tempNotebook, boolean isDirty) {\r
+ NotebookRequest request = new NotebookRequest();\r
+ request.requestor_id = id;\r
+ request.type = NotebookRequest.Update_Notebook;\r
+ request.notebook = tempNotebook;\r
+ request.bool1 = isDirty;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Load notebooks from the database\r
+ public List<Notebook> getAll() {\r
+ NotebookRequest request = new NotebookRequest();\r
+ request.requestor_id = id;\r
+ request.type = NotebookRequest.Get_All;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NotebookRequest req = Global.dbRunner.notebookResponse.get(id).copy();\r
+ return req.responseNotebooks;\r
+ \r
+ } \r
+ public List<Notebook> getAllLocal() {\r
+ NotebookRequest request = new NotebookRequest();\r
+ request.requestor_id = id;\r
+ request.type = NotebookRequest.Get_All_Local;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NotebookRequest req = Global.dbRunner.notebookResponse.get(id).copy();\r
+ return req.responseNotebooks;\r
+ }\r
+ // Archive or un-archive a notebook\r
+ public void setArchived(String guid, boolean isDirty) {\r
+ NotebookRequest request = new NotebookRequest();\r
+ request.requestor_id = id;\r
+ request.type = NotebookRequest.Set_Archived;\r
+ request.string1 = guid;\r
+ request.bool1 = isDirty;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Load non-archived notebooks from the database\r
+ public List<Notebook> getAllArchived() {\r
+ NotebookRequest request = new NotebookRequest();\r
+ request.requestor_id = id;\r
+ request.type = NotebookRequest.Get_All_Archived;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NotebookRequest req = Global.dbRunner.notebookResponse.get(id).copy();\r
+ return req.responseNotebooks;\r
+ } \r
+ // Check for a local/remote notebook\r
+ public boolean isNotebookLocal(String guid) {\r
+ NotebookRequest request = new NotebookRequest();\r
+ request.requestor_id = id;\r
+ request.type = NotebookRequest.Is_Notebook_Local;\r
+ request.string1 = guid;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NotebookRequest req =(Global.dbRunner.notebookResponse.get(id)).copy();\r
+ return req.responseBoolean;\r
+ }\r
+ // Update a notebook sequence number\r
+ public void updateNotebookSequence(String guid, int sequence) {\r
+ NotebookRequest request = new NotebookRequest();\r
+ request.requestor_id = id;\r
+ request.type = NotebookRequest.Update_Notebook_Sequence;\r
+ request.int1 = sequence;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Update a notebook GUID number\r
+ public void updateNotebookGuid(String oldGuid, String newGuid) {\r
+ NotebookRequest request = new NotebookRequest();\r
+ request.requestor_id = id;\r
+ request.type = NotebookRequest.Update_Notebook_Guid;\r
+ request.string1 = oldGuid;\r
+ request.string2 = newGuid;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Get a list of notes that need to be updated\r
+ public List <Notebook> getDirty() {\r
+ NotebookRequest request = new NotebookRequest();\r
+ request.requestor_id = id;\r
+ request.type = NotebookRequest.Get_Dirty;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NotebookRequest req = Global.dbRunner.notebookResponse.get(id).copy();\r
+ return req.responseNotebooks;\r
+ }\r
+\r
+ // This is a convience method to check if a tag exists & update/create based upon it\r
+ public void syncNotebook(Notebook notebook, boolean isDirty) {\r
+ NotebookRequest request = new NotebookRequest();\r
+ request.requestor_id = id;\r
+ request.type = NotebookRequest.Sync_Notebook;\r
+ request.notebook = notebook;\r
+ request.bool1 = isDirty;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Reset the dirty flag. Typically done after a sync.\r
+ public void resetDirtyFlag(String guid) {\r
+ NotebookRequest request = new NotebookRequest();\r
+ request.requestor_id = id;\r
+ request.type = NotebookRequest.Reset_Dirty;\r
+ request.string1 = guid;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // does a record exist?\r
+ public String findNotebookByName(String newname) {\r
+ NotebookRequest request = new NotebookRequest();\r
+ request.requestor_id = id;\r
+ request.type = NotebookRequest.Find_Note_By_Name;\r
+ request.string1 = newname;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NotebookRequest req = Global.dbRunner.notebookResponse.get(id).copy();\r
+ return req.responseString;\r
+ }\r
+ // Get Notebook counts\r
+ public List<Pair<String,Integer>> getNotebookCounts() {\r
+ NotebookRequest request = new NotebookRequest();\r
+ request.requestor_id = id;\r
+ request.type = NotebookRequest.Notebook_Counts;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ NotebookRequest req = Global.dbRunner.notebookResponse.get(id).copy();\r
+ return req.responseCounts;\r
+ \r
+ }\r
+}\r
+\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.sql;\r
+\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.SavedSearch;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.sql.requests.SavedSearchRequest;\r
+\r
+public class SavedSearchTable {\r
+ int id;\r
+ \r
+ // Constructor\r
+ public SavedSearchTable(int i) {\r
+ id = i;\r
+ }\r
+ // Create the table\r
+ public void createTable() {\r
+ SavedSearchRequest request = new SavedSearchRequest();\r
+ request.requestor_id = id;\r
+ request.type = SavedSearchRequest.Create_Table;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Drop the table\r
+ public void dropTable() {\r
+ SavedSearchRequest request = new SavedSearchRequest();\r
+ request.requestor_id = id;\r
+ request.type = SavedSearchRequest.Drop_Table;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // get all tags\r
+ public List<SavedSearch> getAll() {\r
+ SavedSearchRequest request = new SavedSearchRequest();\r
+ request.requestor_id = id;\r
+ request.type = SavedSearchRequest.Get_All;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ SavedSearchRequest req = Global.dbRunner.savedSearchResponse.get(id).copy();\r
+ return req.responseSavedSearches;\r
+ }\r
+ public SavedSearch getSavedSearch(String guid) {\r
+ SavedSearchRequest request = new SavedSearchRequest();\r
+ request.requestor_id = id;\r
+ request.type = SavedSearchRequest.Get_Saved_Search;\r
+ request.string1 = new String(guid);\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ SavedSearchRequest req = Global.dbRunner.savedSearchResponse.get(id).copy();\r
+ return req.responseSavedSearch;\r
+ }\r
+ // Update a saved search\r
+ public void updateSavedSearch(SavedSearch search, boolean isDirty) {\r
+ SavedSearchRequest request = new SavedSearchRequest();\r
+ request.requestor_id = id;\r
+ request.type = SavedSearchRequest.Update_Saved_Search;\r
+ request.savedSearch = search.deepCopy();\r
+ request.bool1 = isDirty;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Delete a saved search\r
+ public void expungeSavedSearch(String guid, boolean needsSync) {\r
+ SavedSearchRequest request = new SavedSearchRequest();\r
+ request.requestor_id = id;\r
+ request.type = SavedSearchRequest.Expunge_Saved_Search;\r
+ request.string1 = new String(guid);\r
+ request.bool1 = needsSync;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Save a saved search\r
+ public void addSavedSearch(SavedSearch search, boolean isDirty) {\r
+ SavedSearchRequest request = new SavedSearchRequest();\r
+ request.requestor_id = id;\r
+ request.type = SavedSearchRequest.Add_Saved_Search;\r
+ request.savedSearch = search.deepCopy();\r
+ request.bool1 = isDirty;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Update sequence number\r
+ public void updateSavedSearchSequence(String guid, int sequence) {\r
+ SavedSearchRequest request = new SavedSearchRequest();\r
+ request.requestor_id = id;\r
+ request.type = SavedSearchRequest.Update_Saved_Search_Sequence;\r
+ request.string1 = new String(guid);\r
+ request.int1 = sequence;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Update saved search guid\r
+ public void updateSavedSearchGuid(String oldGuid, String newGuid) {\r
+ SavedSearchRequest request = new SavedSearchRequest();\r
+ request.requestor_id = id;\r
+ request.type = SavedSearchRequest.Get_Saved_Search;\r
+ request.string1 = new String(oldGuid);\r
+ request.string2 = new String(newGuid);\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ public void resetDirtyFlag(String guid) {\r
+ SavedSearchRequest request = new SavedSearchRequest();\r
+ request.requestor_id = id;\r
+ request.type = SavedSearchRequest.Reset_Dirty_Flag;\r
+ request.string1 = new String(guid);\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Get dirty records\r
+ public List<SavedSearch> getDirty() {\r
+ SavedSearchRequest request = new SavedSearchRequest();\r
+ request.requestor_id = id;\r
+ request.type = SavedSearchRequest.Get_Dirty;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ SavedSearchRequest req = Global.dbRunner.savedSearchResponse.get(id).copy();\r
+ return req.responseSavedSearches;\r
+ }\r
+ // Find a guid based upon the name\r
+ public String findSavedSearchByName(String name) {\r
+ SavedSearchRequest request = new SavedSearchRequest();\r
+ request.requestor_id = id;\r
+ request.type = SavedSearchRequest.Find_Saved_Search_By_Name;\r
+ request.string1 = new String(name);\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ SavedSearchRequest req = Global.dbRunner.savedSearchResponse.get(id).copy();\r
+ return req.string1;\r
+ }\r
+ // given a guid, does the saved search exist\r
+ public boolean exists(String guid) {\r
+ SavedSearchRequest request = new SavedSearchRequest();\r
+ request.requestor_id = id;\r
+ request.type = SavedSearchRequest.Exists;\r
+ request.string1 = new String(guid);\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ SavedSearchRequest req = Global.dbRunner.savedSearchResponse.get(id).copy();\r
+ return req.bool1;\r
+ }\r
+ // This is a convience method to check if a tag exists & update/create based upon it\r
+ public void syncSavedSearch(SavedSearch search, boolean isDirty) {\r
+ SavedSearchRequest request = new SavedSearchRequest();\r
+ request.requestor_id = id;\r
+ request.type = SavedSearchRequest.Sync_Saved_Search;\r
+ request.savedSearch = search.deepCopy();\r
+ request.bool1 = isDirty;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.sql;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.sql.requests.SyncRequest;\r
+\r
+public class SyncTable {\r
+ int id;\r
+ \r
+ // Constructor\r
+ public SyncTable(int i) {\r
+ id = i;\r
+ }\r
+ // Create the table\r
+ public void createTable() {\r
+ SyncRequest request = new SyncRequest();\r
+ request.requestor_id = id;\r
+ request.type = SyncRequest.Create_Table;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Drop the table\r
+ public void dropTable() {\r
+ SyncRequest request = new SyncRequest();\r
+ request.requestor_id = id;\r
+ request.type = SyncRequest.Drop_Table;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Set the last sequence date\r
+ public void setLastSequenceDate(long date) {\r
+ SyncRequest request = new SyncRequest();\r
+ request.requestor_id = id;\r
+ request.type = SyncRequest.Set_Record;\r
+ request.key = "LastSequenceDate";\r
+ request.value = new Long(date).toString();\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Set the last sequence date\r
+ public void setUpdateSequenceNumber(int number) {\r
+ SyncRequest request = new SyncRequest();\r
+ request.requestor_id = id;\r
+ request.type = SyncRequest.Set_Record;\r
+ request.key = "UpdateSequenceNumber";\r
+ request.value = new Integer(number).toString();\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // get last sequence date\r
+ public long getLastSequenceDate() {\r
+ SyncRequest request = new SyncRequest();\r
+ request.requestor_id = id;\r
+ request.type = SyncRequest.Get_Record;\r
+ request.key = "LastSequenceDate";\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ SyncRequest req = Global.dbRunner.syncResponse.get(id).copy();\r
+ Long date = new Long(req.responseValue);\r
+ return date;\r
+ }\r
+ // Get invalid attributes for a given element\r
+ public int getUpdateSequenceNumber() {\r
+ SyncRequest request = new SyncRequest();\r
+ request.requestor_id = id;\r
+ request.type = SyncRequest.Get_Record;\r
+ request.key = "UpdateSequenceNumber";\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ SyncRequest req = Global.dbRunner.syncResponse.get(id).copy();\r
+ Integer number = new Integer(req.responseValue);\r
+ return number;\r
+ }\r
+\r
+ \r
+ \r
+\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.sql;\r
+\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.Tag;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.sql.requests.DeletedItemRequest;\r
+import cx.fbn.nevernote.sql.requests.TagRequest;\r
+\r
+public class TagTable {\r
+ int id;\r
+ \r
+ public TagTable (int i) {\r
+ id = i;\r
+ }\r
+ // Create the table\r
+ public void createTable() {\r
+ TagRequest request = new TagRequest();\r
+ request.requestor_id = id;\r
+ request.type = TagRequest.Create_Table;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Drop the table\r
+ public void dropTable() {\r
+ TagRequest request = new TagRequest();\r
+ request.requestor_id = id;\r
+ request.type = DeletedItemRequest.Drop_Table;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // get all tags\r
+ public List<Tag> getAll() {\r
+ TagRequest request = new TagRequest();\r
+ request.requestor_id = id;\r
+ request.type = DeletedItemRequest.Get_All;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ TagRequest req = Global.dbRunner.tagResponse.get(id).copy();\r
+ return req.responseTags;\r
+ }\r
+ public Tag getTag(String guid) {\r
+ TagRequest request = new TagRequest();\r
+ request.requestor_id = id;\r
+ request.string1 = new String(guid);\r
+ request.type = TagRequest.Get_Tag;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ TagRequest req = Global.dbRunner.tagResponse.get(id).copy();\r
+ return req.responseTag;\r
+ }\r
+ // Update a tag\r
+ public void updateTag(Tag tempTag, boolean isDirty) {\r
+ TagRequest request = new TagRequest();\r
+ request.requestor_id = id;\r
+ request.type = TagRequest.Update_Tag;\r
+ request.tag = tempTag.deepCopy();\r
+ request.bool1 = isDirty;\r
+ Global.dbRunner.addWork(request);\r
+\r
+ }\r
+ // Delete a tag\r
+ public void expungeTag(String guid, boolean needsSync) {\r
+ TagRequest request = new TagRequest();\r
+ request.requestor_id = id;\r
+ request.string1 = new String(guid);\r
+ request.bool1 = needsSync;\r
+ request.type = TagRequest.Expunge_Tag;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Save a tag\r
+ public void addTag(Tag tempTag, boolean isDirty) {\r
+ TagRequest request = new TagRequest();\r
+ request.requestor_id = id;\r
+ request.type = TagRequest.Add_Tag;\r
+ request.tag = tempTag.deepCopy();\r
+ request.bool1 = isDirty;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Update a tag's parent\r
+ public void updateTagParent(String guid, String parentGuid) {\r
+ TagRequest request = new TagRequest();\r
+ request.requestor_id = id;\r
+ request.type = TagRequest.Update_Parent;\r
+ request.string1 = new String(guid);\r
+ request.string2 = new String(parentGuid);\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ //Save tags from Evernote\r
+ public void saveTags(List<Tag> tags) {\r
+ TagRequest request = new TagRequest();\r
+ request.requestor_id = id;\r
+ request.type = TagRequest.Save_Tags;\r
+ for (int i=0; i<tags.size(); i++) \r
+ request.tags.add(tags.get(i).deepCopy());\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Update a tag sequence number\r
+ public void updateTagSequence(String guid, int sequence) {\r
+ TagRequest request = new TagRequest();\r
+ request.requestor_id = id;\r
+ request.type = TagRequest.Update_Tag_Sequence;\r
+ request.string1 = new String(guid);\r
+ request.int1 = sequence;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Update a tag sequence number\r
+ public void updateTagGuid(String oldGuid, String newGuid) {\r
+ TagRequest request = new TagRequest();\r
+ request.requestor_id = id;\r
+ request.string1 = new String(oldGuid);\r
+ request.string2 = new String(newGuid);\r
+ request.type = TagRequest.Update_Tag_Guid;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Get dirty tags\r
+ public List<Tag> getDirty() {\r
+ TagRequest request = new TagRequest();\r
+ request.requestor_id = id;\r
+ request.type = TagRequest.Get_Dirty;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ TagRequest req = Global.dbRunner.tagResponse.get(id).copy();\r
+ return req.responseTags;\r
+ }\r
+ // Find a guid based upon the name\r
+ public String findTagByName(String name) {\r
+ TagRequest request = new TagRequest();\r
+ request.requestor_id = id;\r
+ request.type = TagRequest.Find_Tag_By_Name;\r
+ request.string1 = new String(name);\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ TagRequest req = Global.dbRunner.tagResponse.get(id).copy();\r
+ return req.responseString;\r
+ }\r
+ // given a guid, does the tag exist\r
+ public boolean exists(String guid) {\r
+ TagRequest request = new TagRequest();\r
+ request.requestor_id = id;\r
+ request.string1 = new String(guid);\r
+ request.type = TagRequest.Exists;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ TagRequest req = Global.dbRunner.tagResponse.get(id).copy();\r
+ return req.responseBool;\r
+\r
+ }\r
+ // This is a convience method to check if a tag exists & update/create based upon it\r
+ public void syncTag(Tag tag, boolean isDirty) {\r
+ TagRequest request = new TagRequest();\r
+ request.requestor_id = id;\r
+ request.tag = tag.deepCopy();\r
+ request.bool1 = isDirty;\r
+ request.type = TagRequest.Sync_Tag;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ public void resetDirtyFlag(String guid) {\r
+ TagRequest request = new TagRequest();\r
+ request.requestor_id = id;\r
+ request.type = TagRequest.Reset_Dirty_Flag;\r
+ request.string1 = new String(guid);\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.sql;\r
+\r
+import java.util.List;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.sql.requests.WatchFolderRequest;\r
+import cx.fbn.nevernote.sql.runners.WatchFolderRecord;\r
+import cx.fbn.nevernote.utilities.ListManager;\r
+\r
+public class WatchFolderTable {\r
+ ListManager parent;\r
+ int id;\r
+ \r
+ // Constructor\r
+ public WatchFolderTable(int i) {\r
+ id = i;\r
+ }\r
+ // Create the table\r
+ public void createTable() {\r
+ WatchFolderRequest request = new WatchFolderRequest();\r
+ request.requestor_id = id;\r
+ request.type = WatchFolderRequest.Create_Tables;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Drop the table\r
+ public void dropTable() {\r
+ WatchFolderRequest request = new WatchFolderRequest();\r
+ request.requestor_id = id;\r
+ request.type = WatchFolderRequest.Drop_Tables;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Add an item to the deleted table\r
+ public void addWatchFolder(String folder, String notebook, boolean keep, int depth) {\r
+ WatchFolderRequest request = new WatchFolderRequest();\r
+ request.requestor_id = id;\r
+ request.string1 = folder;\r
+ request.string2 = notebook;\r
+ request.bool1 = keep;\r
+ request.int1 = depth;\r
+ request.type = WatchFolderRequest.Add_Watch_Folder;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ public List<WatchFolderRecord> getAll() {\r
+ WatchFolderRequest request = new WatchFolderRequest();\r
+ request.requestor_id = id;\r
+ request.type = WatchFolderRequest.Get_All;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ WatchFolderRequest req = Global.dbRunner.watchFolderResponse.get(id).copy();\r
+ return req.responseWatchFolders;\r
+ }\r
+ public void expungeFolder(String folder) {\r
+ WatchFolderRequest request = new WatchFolderRequest();\r
+ request.requestor_id = id;\r
+ request.string1 = folder;\r
+ request.type = WatchFolderRequest.Expunge_Folder;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ public void expungeAll() {\r
+ WatchFolderRequest request = new WatchFolderRequest();\r
+ request.requestor_id = id;\r
+ request.type = WatchFolderRequest.Expunge_All;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ public String getNotebook(String dir) {\r
+ WatchFolderRequest request = new WatchFolderRequest();\r
+ request.requestor_id = id;\r
+ request.type = WatchFolderRequest.Get_Notebook;\r
+ request.string1 = dir;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ WatchFolderRequest req = Global.dbRunner.watchFolderResponse.get(id).copy();\r
+ return req.responseString;\r
+ }\r
+\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.sql;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.sql.requests.WordRequest;\r
+\r
+\r
+public class WordsTable {\r
+ private final int id;\r
+ \r
+ // Constructor\r
+ public WordsTable(int i) {\r
+ id = i;\r
+ }\r
+ // Create the table\r
+ public void createTable() {\r
+ WordRequest request = new WordRequest();\r
+ request.requestor_id = id;\r
+ request.type = WordRequest.Create_Table;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Drop the table\r
+ public void dropTable() {\r
+ WordRequest request = new WordRequest();\r
+ request.requestor_id = id;\r
+ request.type = WordRequest.Drop_Table;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Count unindexed notes\r
+ public int getWordCount() {\r
+ WordRequest request = new WordRequest();\r
+ request.requestor_id = id;\r
+ request.type = WordRequest.Get_Word_Count;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ WordRequest req = Global.dbRunner.wordResponse.get(id).copy();\r
+ return req.responseInt;\r
+ }\r
+\r
+ // Clear out the word index table\r
+ public void clearWordIndex() {\r
+ WordRequest request = new WordRequest();\r
+ request.requestor_id = id;\r
+ request.type = WordRequest.Clear_Word_Index;\r
+ Global.dbRunner.addWork(request);\r
+ } \r
+\r
+ //********************************************************************************\r
+ //********************************************************************************\r
+ //* Support adding & deleting index words\r
+ //********************************************************************************\r
+ //********************************************************************************\r
+ public void expungeFromWordIndex(String guid, String type) {\r
+ WordRequest request = new WordRequest();\r
+ request.requestor_id = id;\r
+ request.type = WordRequest.Expunge_From_Word_Index;\r
+ request.string1 = guid;\r
+ request.string2 = type;\r
+ Global.dbRunner.addWork(request);\r
+ }\r
+ // Reindex a note\r
+ public synchronized void addWordToNoteIndex(String guid, String word, String type, Integer weight) {\r
+ WordRequest request = new WordRequest();\r
+ request.requestor_id = id;\r
+ request.type = WordRequest.Add_Word_To_Note_Index;\r
+ request.string1 = guid;\r
+ request.string2 = word;\r
+ request.string3 = type;\r
+ request.int1 = weight;\r
+ Global.dbRunner.addWork(request);\r
+ Global.dbClientWait(id);\r
+ }\r
+\r
+\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.sql.driver;\r
+\r
+import java.io.ByteArrayInputStream;\r
+import java.sql.Blob;\r
+import java.sql.Connection;\r
+import java.sql.PreparedStatement;\r
+import java.sql.ResultSet;\r
+import java.sql.SQLException;\r
+import java.sql.Statement;\r
+import java.util.HashMap;\r
+\r
+public class NSqlQuery {\r
+ \r
+ private final Connection connection;\r
+ private String lastError;\r
+ private ResultSet resultSet;\r
+ private PreparedStatement preparedStatement;\r
+ private final HashMap<String, Integer> positionMap;\r
+ private ByteArrayInputStream fis;\r
+ \r
+ \r
+ public NSqlQuery(Connection c) {\r
+ connection = c;\r
+ positionMap = new HashMap<String, Integer>();\r
+ }\r
+ \r
+ \r
+ public boolean next() {\r
+ lastError = null;\r
+ \r
+ if (resultSet == null) {\r
+ lastError = "Result set is null";\r
+ return false;\r
+ }\r
+ try {\r
+ return resultSet.next();\r
+ } catch (SQLException e) {\r
+ e.printStackTrace();\r
+ lastError = e.getMessage();\r
+ return false;\r
+ }\r
+ }\r
+ \r
+ \r
+ public boolean exec(String sql) {\r
+ Statement st;\r
+ boolean retVal = false;\r
+ lastError = "";\r
+ resultSet = null;\r
+ try {\r
+ st = connection.createStatement();\r
+ retVal = st.execute(sql);\r
+ resultSet = st.getResultSet();\r
+ } catch (SQLException e) {\r
+ e.printStackTrace();\r
+ lastError = e.getMessage();\r
+ }\r
+ return retVal;\r
+ }\r
+ \r
+ public boolean exec() {\r
+ lastError = "";\r
+ resultSet = null;\r
+ \r
+ if (preparedStatement == null) {\r
+ lastError = "No SQL statement prepared";\r
+ return false;\r
+ }\r
+\r
+ try {\r
+ preparedStatement.execute();\r
+ resultSet = preparedStatement.getResultSet();\r
+ } catch (SQLException e) {\r
+ e.printStackTrace();\r
+ lastError = e.getMessage();\r
+ return false;\r
+ }\r
+ \r
+ \r
+ return true;\r
+ }\r
+ \r
+ \r
+ public String lastError() {\r
+ if (lastError == null)\r
+ return "";\r
+ return lastError;\r
+ }\r
+ \r
+ \r
+ public Object valueObject(int position) {\r
+ lastError = null;\r
+ if (resultSet == null) {\r
+ lastError = "ResultSet is null";\r
+ return null;\r
+ }\r
+ \r
+ try {\r
+ return resultSet.getObject(position+1);\r
+ } catch (SQLException e) {\r
+ e.printStackTrace();\r
+ lastError = e.getMessage();\r
+ return null;\r
+ }\r
+ }\r
+ \r
+ \r
+ public String valueString(int position) {\r
+ lastError = null;\r
+ if (resultSet == null) {\r
+ lastError = "ResultSet is null";\r
+ return null;\r
+ }\r
+ \r
+ try {\r
+ return resultSet.getString(position+1);\r
+ } catch (SQLException e) {\r
+ e.printStackTrace();\r
+ lastError = e.getMessage();\r
+ return null;\r
+ }\r
+ }\r
+ \r
+ public boolean valueBoolean(int position, boolean unknown) {\r
+ try {\r
+ return resultSet.getBoolean(position+1);\r
+ } catch (SQLException e) {\r
+ e.printStackTrace();\r
+ return unknown;\r
+ }\r
+ }\r
+\r
+ public long valueLong(int position) {\r
+ try {\r
+ return resultSet.getLong(position+1);\r
+ } catch (SQLException e) {\r
+ e.printStackTrace();\r
+ return 0;\r
+ }\r
+ }\r
+ \r
+ public int valueInteger(int position) {\r
+ try {\r
+ return resultSet.getInt(position+1);\r
+ } catch (SQLException e) {\r
+ e.printStackTrace();\r
+ return 0;\r
+ }\r
+ }\r
+ \r
+ public void bindValue(String field, String value) {\r
+ Integer position = positionMap.get(field.toLowerCase());\r
+ lastError = null;\r
+ if (preparedStatement == null) {\r
+ lastError = "No prepared statement exists";\r
+ return;\r
+ }\r
+ if (position != null && position > 0) {\r
+ try {\r
+ preparedStatement.setString(position, value);\r
+ } catch (SQLException e) {\r
+ e.printStackTrace();\r
+ lastError = e.getMessage();\r
+ }\r
+ return;\r
+ } \r
+ }\r
+ \r
+ public void bindValue(String field, boolean value) {\r
+ Integer position = positionMap.get(field.toLowerCase());\r
+ lastError = null;\r
+ if (preparedStatement == null) {\r
+ lastError = "No prepared statement exists";\r
+ return;\r
+ }\r
+ if (position > 0) {\r
+ try {\r
+ preparedStatement.setBoolean(position, value);\r
+ } catch (SQLException e) {\r
+ e.printStackTrace();\r
+ lastError = e.getMessage();\r
+ }\r
+ return;\r
+ } \r
+ }\r
+ \r
+ \r
+\r
+ public void bindValue(String field, int value) {\r
+ Integer position = positionMap.get(field.toLowerCase());\r
+ lastError = null;\r
+ if (preparedStatement == null) {\r
+ lastError = "No prepared statement exists";\r
+ return;\r
+ }\r
+ if (position > 0) {\r
+ try {\r
+ preparedStatement.setInt(position, value);\r
+ } catch (SQLException e) {\r
+ e.printStackTrace();\r
+ lastError = e.getMessage();\r
+ }\r
+ return;\r
+ } \r
+ }\r
+ \r
+ \r
+\r
+ public void bindValue(String field, double value) {\r
+ Integer position = positionMap.get(field.toLowerCase());\r
+ lastError = null;\r
+ if (preparedStatement == null) {\r
+ lastError = "No prepared statement exists";\r
+ return;\r
+ }\r
+ if (position > 0) {\r
+ try {\r
+ preparedStatement.setDouble(position, value);\r
+ } catch (SQLException e) {\r
+ e.printStackTrace();\r
+ lastError = e.getMessage();\r
+ }\r
+ return;\r
+ } \r
+ }\r
+ \r
+ \r
+ \r
+ public void bindValue(String field, byte[] value) {\r
+ Integer position = positionMap.get(field.toLowerCase());\r
+ lastError = null;\r
+ if (preparedStatement == null) {\r
+ lastError = "No prepared statement exists";\r
+ return;\r
+ }\r
+ if (position > 0) {\r
+ try {\r
+ preparedStatement.setBytes(position, value);\r
+ } catch (SQLException e) {\r
+ e.printStackTrace();\r
+ lastError = e.getMessage();\r
+ }\r
+ return;\r
+ } \r
+ }\r
+ \r
+ \r
+ \r
+ public boolean prepare(String statement) {\r
+ positionMap.clear();\r
+ preparedStatement = null;\r
+ lastError = null;\r
+ \r
+ int position = 1;\r
+ for (int i=statement.indexOf(":"); i>0; i=statement.indexOf(":",i)) {\r
+ int endField = statement.indexOf(" ",i+1);\r
+ int nextComma = statement.indexOf(",",i+1);\r
+ int nextBracket = statement.indexOf(")",i+1);\r
+ \r
+ if (nextComma > 0 && nextComma < endField)\r
+ endField = nextComma;\r
+ if (endField == -1)\r
+ endField = nextBracket;\r
+ if (nextBracket > 0 && nextBracket < endField)\r
+ endField = nextBracket;\r
+ \r
+ String fieldName = null;\r
+ if (endField > 0) {\r
+ fieldName = statement.substring(i,endField);\r
+ }\r
+ else {\r
+ fieldName = statement.substring(i);\r
+ endField = statement.length();\r
+ }\r
+ statement = statement.substring(0,i)+"?" +statement.substring(endField);\r
+ positionMap.put(fieldName.toLowerCase(), new Integer(position));\r
+ position++;\r
+ }\r
+ \r
+ \r
+ try {\r
+ preparedStatement = connection.prepareStatement(statement);\r
+ } catch (SQLException e) {\r
+ e.printStackTrace();\r
+ lastError = e.getMessage();\r
+ return false;\r
+ }\r
+ \r
+ \r
+ return true;\r
+ }\r
+ \r
+ \r
+ public void bindBlob(String field, byte[] value) {\r
+ Integer position = positionMap.get(field.toLowerCase());\r
+ lastError = null;\r
+ if (preparedStatement == null) {\r
+ lastError = "No prepared statement exists";\r
+ return;\r
+ }\r
+ if (position != null && position > 0) {\r
+ try {\r
+ fis = new ByteArrayInputStream(value);\r
+ preparedStatement.setBinaryStream(position, fis);\r
+ } catch (SQLException e) {\r
+ e.printStackTrace();\r
+ lastError = e.getMessage();\r
+ }\r
+ return;\r
+ } \r
+ }\r
+ \r
+ \r
+ public byte[] getBlob(int position) {\r
+ Blob dataBinary;\r
+ try {\r
+ dataBinary = resultSet.getBlob(position+1);\r
+ byte[] b;\r
+ if (dataBinary == null)\r
+ return null;\r
+ b = dataBinary.getBytes(1, (int) dataBinary.length());\r
+ return b;\r
+ } catch (SQLException e) {\r
+ e.printStackTrace();\r
+ lastError = e.getMessage();\r
+ }\r
+ return null;\r
+ }\r
+ \r
+ \r
+\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.sql.requests;\r
+\r
+\r
+public class DBRunnerRequest {\r
+ public static int GENERIC = 1;\r
+ public static int DATABASE = 2;\r
+ public static int DELETED_ITEM = 3;\r
+ public static int NOTEBOOK = 4;\r
+ public static int TAG = 5;\r
+ public static int SAVED_SEARCH = 6;\r
+ public static int NOTE = 7;\r
+ public static int RESOURCE = 8;\r
+ public static int NOTE_TAGS = 9;\r
+ public static int ENSEARCH = 10;\r
+ public static int WATCH_FOLDER = 11;\r
+ public static int WORD = 12;\r
+ public static int Invalid_XML = 13;\r
+ public static int Sync = 14;\r
+ \r
+ public volatile int requestor_id;\r
+ public volatile int category;\r
+ public volatile int type;\r
+ public volatile String request;\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.sql.requests;\r
+\r
+\r
+public class DatabaseRequest extends DBRunnerRequest {\r
+ public static int Create_Tables = 1;\r
+ public static int Drop_Tables = 2;\r
+ public static int Setup = 3;\r
+ public static int Shutdown = 4;\r
+ public static int Compact = 5;\r
+ public static int Execute_Sql = 6;\r
+ public static int Execute_Sql_Index = 7;\r
+ public static int Backup_Database = 8;\r
+\r
+ public volatile String string1;\r
+ public volatile String string2;\r
+ public volatile int int1;\r
+ public volatile long long1;\r
+ \r
+ public DatabaseRequest() {\r
+ category = DATABASE;\r
+ }\r
+ \r
+ public DatabaseRequest copy() {\r
+ DatabaseRequest request = new DatabaseRequest();\r
+ \r
+ request.requestor_id = requestor_id;\r
+ request.type = type;\r
+ request.category = category;\r
+ request.long1 = long1;\r
+ request.int1 = int1;\r
+ if (string1 != null)\r
+ request.string1 = new String(string1);\r
+ if (string2 != null)\r
+ request.string2 = new String(string2);\r
+ \r
+ return request;\r
+ }\r
+ \r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.sql.requests;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import cx.fbn.nevernote.sql.runners.DeletedItemRecord;\r
+\r
+public class DeletedItemRequest extends DBRunnerRequest {\r
+ public static int Create_Table = 1;\r
+ public static int Drop_Table = 2;\r
+ public static int Add_Deleted_Item = 3;\r
+ public static int Expunge_All = 4;\r
+ public static int Get_All = 5;\r
+ public static int Expunge_Record = 6;\r
+\r
+ public volatile String string1;\r
+ public volatile String string2;\r
+ \r
+ public List<DeletedItemRecord> responseDeletedRecords;\r
+ \r
+ public DeletedItemRequest() {\r
+ category = DELETED_ITEM;\r
+ }\r
+ \r
+ public DeletedItemRequest copy() {\r
+ DeletedItemRequest request = new DeletedItemRequest();\r
+ \r
+ request.requestor_id = requestor_id;\r
+ request.type = type;\r
+ request.category = category;\r
+ \r
+ if (string1 != null)\r
+ request.string1 = new String(string1);\r
+ if (string2 != null)\r
+ request.string2 = new String(string2);\r
+ \r
+ if (responseDeletedRecords != null) {\r
+ request.responseDeletedRecords = new ArrayList<DeletedItemRecord>();\r
+ for (int i=0; i<responseDeletedRecords.size(); i++) {\r
+ DeletedItemRecord record = new DeletedItemRecord();\r
+ record.guid = new String(responseDeletedRecords.get(i).guid);\r
+ record.type = new String(responseDeletedRecords.get(i).type);\r
+ request.responseDeletedRecords.add(record);\r
+ }\r
+ }\r
+ \r
+ return request;\r
+ }\r
+ \r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.sql.requests;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.Note;\r
+import com.evernote.edam.type.Tag;\r
+\r
+\r
+public class EnSearchRequest extends DBRunnerRequest {\r
+ public volatile String string1;\r
+ public volatile List<Tag> tags;\r
+ public volatile int int1;\r
+ public volatile int int2;\r
+ public volatile List<Note> responseNotes;\r
+ public volatile List<String> responseStrings;\r
+\r
+ \r
+ public EnSearchRequest() {\r
+ category = ENSEARCH;\r
+ }\r
+ \r
+ public EnSearchRequest copy() {\r
+ EnSearchRequest request = new EnSearchRequest();\r
+ \r
+ request.requestor_id = requestor_id;\r
+ request.type = type;\r
+ request.int1 = int1;\r
+ request.int2 = int2;\r
+ request.category = category;\r
+ if (string1 != null)\r
+ request.string1 = new String(string1);\r
+ if (tags!=null) { \r
+ request.tags = new ArrayList<Tag>();\r
+ for (int i=0; i<tags.size(); i++)\r
+ request.tags.add(tags.get(i).deepCopy());\r
+ }\r
+ \r
+ if (responseNotes != null) {\r
+ request.responseNotes = new ArrayList<Note>();\r
+ for (int i=0; i<responseNotes.size(); i++) {\r
+ request.responseNotes.add(responseNotes.get(i).deepCopy());\r
+ }\r
+ }\r
+ \r
+ if (responseStrings != null) {\r
+ request.responseStrings = new ArrayList<String>();\r
+ for (int i=0; i<responseStrings.size(); i++) {\r
+ request.responseStrings.add(new String(responseStrings.get(i)));\r
+ }\r
+ }\r
+\r
+ return request;\r
+ }\r
+ \r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.sql.requests;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+\r
+public class InvalidXMLRequest extends DBRunnerRequest {\r
+ public static int Create_Table = 1;\r
+ public static int Drop_Table = 2;\r
+ public static int Get_Invalid_Elements = 3;\r
+ public static int Get_Invalid_Attributes = 4;\r
+ public static int Get_Invalid_Attribute_Elements = 5;\r
+ public static int Add_Invalid_Element = 6;\r
+ public static int Add_Invalid_Attribute = 7;\r
+\r
+\r
+ public volatile String string1;\r
+ public volatile String string2;\r
+ public volatile String string3;\r
+ \r
+ public String responseString1;\r
+ public List<String> responseList;\r
+ public ArrayList<String> responseArrayList;\r
+ \r
+ public InvalidXMLRequest() {\r
+ category = Invalid_XML;\r
+ }\r
+ \r
+ public InvalidXMLRequest copy() {\r
+ InvalidXMLRequest req = new InvalidXMLRequest();\r
+ req.type = type;\r
+ req.category = category;\r
+ req.requestor_id = requestor_id;\r
+ \r
+ if (string1 != null)\r
+ req.string1 = new String(string1);\r
+ if (string2 != null)\r
+ req.string2 = new String(string2);\r
+ if (string3 != null)\r
+ req.string3 = new String(string3);\r
+ if (responseString1 != null)\r
+ req.responseString1 = new String(responseString1);\r
+ \r
+ if (responseList != null) {\r
+ req.responseList = new ArrayList<String>();\r
+ for (int i=0; i<responseList.size(); i++) {\r
+ req.responseList.add(new String(responseList.get(i)));\r
+ }\r
+ }\r
+ \r
+ if (responseArrayList != null) {\r
+ req.responseArrayList = new ArrayList<String>();\r
+ for (int i=0; i<responseArrayList.size(); i++) {\r
+ req.responseArrayList.add(new String(responseArrayList.get(i)));\r
+ }\r
+ }\r
+\r
+ return req;\r
+ }\r
+ \r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.sql.requests;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.Note;\r
+import com.trolltech.qt.core.QByteArray;\r
+import com.trolltech.qt.core.QDateTime;\r
+\r
+import cx.fbn.nevernote.utilities.Pair;\r
+\r
+public class NoteRequest extends DBRunnerRequest {\r
+ public static int Create_Table = 1;\r
+ public static int Drop_Table = 2;\r
+ public static int Add_Note = 3;\r
+ public static int Get_Note = 4;\r
+ public static int Update_Note_Title = 5;\r
+ public static int Update_Note_Creation_Date = 6;\r
+ public static int Update_Note_Altered_Date = 7;\r
+ public static int Update_Note_Subject_Date = 8;\r
+ public static int Update_Note_Source_Url = 9;\r
+ public static int Update_Note_Author = 10;\r
+ public static int Update_Note_Notebook = 11;\r
+ public static int Update_Note_Content = 12;\r
+ public static int Delete_Note = 13;\r
+ public static int Restore_Note = 14;\r
+ public static int Expunge_Note = 15;\r
+ public static int Expunge_All_Deleted_Notes = 16;\r
+ public static int Update_Note_Sequence = 17;\r
+ public static int Update_Note_Guid = 18;\r
+ public static int Update_Note = 19;\r
+ public static int Exists = 20;\r
+ public static int Sync_Note = 21;\r
+ public static int Get_Dirty = 22;\r
+ public static int Get_Unsynchronized_Guids = 23;\r
+ public static int Reset_Dirty_Flag = 24;\r
+ public static int Get_All_Guids = 25;\r
+ public static int Get_All_Notes = 26;\r
+ public static int Get_Unindexed_Count = 27;\r
+ public static int Get_Dirty_Count = 28;\r
+ public static int Update_Resource_Guid_By_Hash = 29;\r
+ public static int Set_Index_Needed = 30;\r
+ public static int Reindex_All_Notes = 31;\r
+ public static int Get_Unindexed = 32;\r
+ public static int Get_Next_Unindexed = 33;\r
+ public static int Update_Resource_Content_Hash = 34;\r
+ public static int Get_Note_Count = 35;\r
+ public static int Reset_Note_Sequence = 36;\r
+ public static int Get_Deleted_Count = 37;\r
+ public static int Is_Note_Dirty = 38;\r
+ public static int Get_Note_Content_Binary = 39;\r
+ public static int Get_Title_Colors = 40;\r
+ public static int Set_Title_Colors = 41;\r
+ public static int Set_Thumbnail = 42;\r
+ public static int Get_Thumbnail = 43;\r
+ public static int Is_Thumbail_Needed = 44;\r
+ public static int Set_Thumbnail_Needed = 45;\r
+\r
+ public volatile String string1;\r
+ public volatile String string2;\r
+ public volatile String string3;\r
+ public volatile QDateTime date;\r
+ public volatile int int1;\r
+ public volatile boolean bool1;\r
+ public volatile boolean bool2;\r
+ public volatile boolean bool3;\r
+ public volatile boolean bool4;\r
+ public volatile boolean bool5;\r
+ public volatile Note note;\r
+ public volatile List<Note> notes;\r
+ public volatile QByteArray bytes;\r
+ \r
+ public volatile List<Note> responseNotes;\r
+ public volatile Note responseNote;\r
+ public volatile String responseString;\r
+ public volatile boolean responseBoolean;\r
+ public volatile List<String> responseStrings;\r
+ public volatile int responseInt;\r
+ public volatile List<Pair<String,Integer>> responsePair;\r
+ public volatile QByteArray responseBytes;\r
+ \r
+ public NoteRequest() {\r
+ category = NOTE;\r
+ }\r
+ \r
+ public NoteRequest copy() {\r
+ NoteRequest request = new NoteRequest();\r
+ \r
+ request.requestor_id = requestor_id;\r
+ request.type = type;\r
+ request.category = category;\r
+ request.bool1 = bool1;\r
+ request.bool2 = bool2;\r
+ request.bool3 = bool3;\r
+ request.bool4 = bool4;\r
+ request.bool5 = bool5;\r
+ request.int1 = int1;\r
+ \r
+ if (date != null)\r
+ request.date = new QDateTime(date);\r
+\r
+ if (string1 != null)\r
+ request.string1 = new String(string1);\r
+ if (string2 != null)\r
+ request.string2 = new String(string2);\r
+ if (string3 != null)\r
+ request.string3 = new String(string3);\r
+ \r
+ if (note != null)\r
+ request.note = note.deepCopy();\r
+\r
+ if (notes != null) {\r
+ request.notes = new ArrayList<Note>();\r
+ for (int i=0; i<notes.size(); i++)\r
+ request.notes.add(notes.get(i).deepCopy());\r
+ }\r
+ \r
+ request.responseInt = responseInt;\r
+ request.responseBoolean = responseBoolean;\r
+ if (bytes != null)\r
+ request.bytes = new QByteArray(bytes);\r
+ \r
+ if (responseNotes != null) {\r
+ request.responseNotes = new ArrayList<Note>();\r
+ for (int i=0; i<responseNotes.size(); i++)\r
+ if (responseNotes.get(i) != null) \r
+ request.responseNotes.add(responseNotes.get(i).deepCopy());\r
+ }\r
+\r
+ if (responseNote != null) {\r
+ request.responseNote = responseNote.deepCopy();\r
+ }\r
+ \r
+ if (responseString != null) {\r
+ request.responseString = new String(responseString);\r
+ }\r
+ \r
+ if (responseStrings != null) {\r
+ request.responseStrings = new ArrayList<String>();\r
+ for (int i=0; i<responseStrings.size(); i++) \r
+ request.responseStrings.add(new String(responseStrings.get(i)));\r
+ }\r
+ \r
+ if (responsePair != null) {\r
+ request.responsePair = new ArrayList<Pair<String,Integer>>();\r
+ for (int i=0; i<responsePair.size(); i++) {\r
+ Pair<String,Integer> p = new Pair<String,Integer>();\r
+ p.setFirst(responsePair.get(i).getFirst());\r
+ p.setSecond(responsePair.get(i).getSecond());\r
+ request.responsePair.add(p);\r
+ }\r
+ }\r
+ if (responseBytes != null)\r
+ request.responseBytes = new QByteArray(responseBytes);\r
+\r
+ return request;\r
+ }\r
+ \r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.sql.requests;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import cx.fbn.nevernote.sql.runners.NoteTagsRecord;\r
+import cx.fbn.nevernote.utilities.Pair;\r
+\r
+public class NoteTagsRequest extends DBRunnerRequest {\r
+ public static int Create_Table = 1;\r
+ public static int Drop_Table = 2;\r
+ public static int Get_Note_Tags = 3;\r
+ public static int Get_All_Note_Tags = 4;\r
+ public static int Check_Note_Note_Tags = 5;\r
+ public static int Save_Note_Tag = 6;\r
+ public static int Delete_Note_Tag = 7;\r
+ public static int Tag_Counts = 8;\r
+\r
+\r
+ public volatile String string1;\r
+ public volatile String string2;\r
+ \r
+ public volatile List<String> responseStrings;\r
+ public volatile List<NoteTagsRecord> responseNoteTagsRecord;\r
+ public volatile boolean responseBoolean;\r
+ public volatile List<Pair<String,Integer>> responseCounts;\r
+ \r
+ public NoteTagsRequest() {\r
+ category = NOTE_TAGS;\r
+ }\r
+ \r
+ public NoteTagsRequest copy() {\r
+ NoteTagsRequest request = new NoteTagsRequest();\r
+ \r
+ request.requestor_id = requestor_id;\r
+ request.type = type;\r
+ request.category = category;\r
+ if (string1 != null)\r
+ request.string1 = new String(string1);\r
+ if (string2 != null)\r
+ request.string2 = new String(string2);\r
+ \r
+ if (responseStrings != null) {\r
+ request.responseStrings = new ArrayList<String>();\r
+ for (int i=0; i<responseStrings.size(); i++) {\r
+ request.responseStrings.add(new String(responseStrings.get(i)));\r
+ }\r
+ }\r
+ \r
+ if (responseNoteTagsRecord != null) {\r
+ request.responseNoteTagsRecord = new ArrayList<NoteTagsRecord>();\r
+ for (int i=0; i<responseNoteTagsRecord.size(); i++) {\r
+ NoteTagsRecord record = new NoteTagsRecord();\r
+ record.noteGuid = new String(responseNoteTagsRecord.get(i).noteGuid);\r
+ record.tagGuid = new String(responseNoteTagsRecord.get(i).tagGuid);\r
+ request.responseNoteTagsRecord.add(record);\r
+ }\r
+ }\r
+ \r
+ if (responseCounts != null) {\r
+ request.responseCounts = new ArrayList<Pair<String,Integer>>();\r
+ for (int i=0; i<responseCounts.size(); i++) {\r
+ Pair<String,Integer> newPair = new Pair<String,Integer>();\r
+ newPair.setFirst(responseCounts.get(i).getFirst());\r
+ newPair.setSecond(responseCounts.get(i).getSecond());\r
+ request.responseCounts.add(newPair);\r
+ }\r
+ }\r
+ \r
+ return request;\r
+ }\r
+ \r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.sql.requests;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.Notebook;\r
+\r
+import cx.fbn.nevernote.utilities.Pair;\r
+\r
+public class NotebookRequest extends DBRunnerRequest {\r
+ public static int Create_Table = 1;\r
+ public static int Drop_Table = 2;\r
+// public static int Get_Notebook = 3;\r
+// public static int Get_All_Notebooks = 4;\r
+ public static int Add_Notebook = 5;\r
+ public static int Expunge_Notebook = 6;\r
+ public static int Find_Note_By_Name = 7;\r
+ public static int Get_All = 8;\r
+ public static int Get_Dirty = 9;\r
+ public static int Is_Notebook_Local = 10;\r
+ public static int Reset_Dirty = 11;\r
+// public static int Save_Notebooks = 12;\r
+ public static int Set_Archived = 13;\r
+ public static int Sync_Notebook = 14;\r
+ public static int Update_Notebook = 15;\r
+ public static int Update_Notebook_Guid = 16;\r
+ public static int Update_Notebook_Sequence = 17;\r
+ public static int Get_All_Local = 18;\r
+ public static int Get_All_Archived = 19;\r
+ public static int Notebook_Counts = 20;\r
+\r
+ public volatile boolean bool1;\r
+ public volatile boolean bool2;\r
+ public volatile String string1;\r
+ public volatile String string2;\r
+ public volatile Notebook notebook;\r
+ public volatile int int1;\r
+ \r
+ public volatile List<Notebook> responseNotebooks;\r
+ public volatile boolean responseBoolean;\r
+ public volatile String responseString;\r
+ public volatile List<Pair<String,Integer>> responseCounts;\r
+ \r
+ public NotebookRequest() {\r
+ category = NOTEBOOK;\r
+ }\r
+ \r
+ public NotebookRequest copy() {\r
+ NotebookRequest request = new NotebookRequest();\r
+ \r
+ request.category = category;\r
+ request.requestor_id = requestor_id;\r
+ request.type = type;\r
+ request.bool1 = bool1;\r
+ request.bool2 = bool2;\r
+ if (string1 != null)\r
+ request.string1 = new String(string1);\r
+ if (string2 != null)\r
+ request.string2 = new String(string2);\r
+ if (notebook != null)\r
+ request.notebook = notebook.deepCopy();\r
+ if (responseNotebooks != null) {\r
+ request.responseNotebooks = new ArrayList<Notebook>();\r
+ for (int i=0; i<responseNotebooks.size(); i++) {\r
+ request.responseNotebooks.add(responseNotebooks.get(i).deepCopy());\r
+ }\r
+ }\r
+ if (responseString != null) {\r
+ request.responseString = new String(responseString);\r
+ }\r
+ \r
+ if (responseCounts != null) {\r
+ request.responseCounts = new ArrayList<Pair<String,Integer>>();\r
+ for (int i=0; i<responseCounts.size(); i++) {\r
+ Pair<String,Integer> newPair = new Pair<String,Integer>();\r
+ newPair.setFirst(responseCounts.get(i).getFirst());\r
+ newPair.setSecond(responseCounts.get(i).getSecond());\r
+ request.responseCounts.add(newPair);\r
+ }\r
+ }\r
+ \r
+ \r
+ return request;\r
+ }\r
+ \r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.sql.requests;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.Resource;\r
+\r
+public class ResourceRequest extends DBRunnerRequest {\r
+ public static int Create_Table = 1;\r
+ public static int Drop_Table = 2;\r
+ public static int Reset_Dirty_Flag = 3;\r
+ public static int Get_Next_Unindexed = 4;\r
+ public static int Set_Index_Needed = 5;\r
+ public static int Save_Note_Resource = 6;\r
+ public static int Expunge_Note_Resource = 7;\r
+ public static int Get_Note_Resource_Guid_By_Hash_Hex = 8;\r
+ public static int Get_Note_Resource_Data_Body_By_Hash_Hex = 9;\r
+ public static int Get_Note_Resource = 10;\r
+ public static int Get_Note_Resources = 11;\r
+ public static int Get_Note_Resources_Recognition = 12;\r
+ public static int Get_Note_Resource_Recognition = 13;\r
+ public static int Update_Note_Resource = 14;\r
+ public static int Reindex_All = 15;\r
+ public static int Get_Resource_Count = 16;\r
+ public static int Update_Note_Resource_Guid = 17;\r
+ public static int Reset_Update_Sequence_Number = 18;\r
+ \r
+\r
+\r
+ public volatile String string1;\r
+ public volatile String string2;\r
+ public volatile Resource resource;\r
+ public volatile boolean bool1;\r
+ public volatile int int1;\r
+ \r
+ public volatile List<String> responseStrings;\r
+ public volatile String responseString;\r
+ public volatile List<Resource> responseResources;\r
+ public volatile Resource responseResource;\r
+ public volatile int responseInteger;\r
+ \r
+ public ResourceRequest() {\r
+ category = RESOURCE;\r
+ }\r
+ \r
+ public ResourceRequest copy() {\r
+ ResourceRequest request = new ResourceRequest();\r
+ \r
+ request.requestor_id = requestor_id;\r
+ request.type = type;\r
+ request.category = category;\r
+ if (string1 != null)\r
+ request.string1 = new String(string1);\r
+ if (string2 != null)\r
+ request.string2 = new String(string2);\r
+ if (resource != null)\r
+ request.resource = resource.deepCopy();\r
+ request.bool1 = bool1;\r
+ request.int1 = int1;\r
+ \r
+ if (responseStrings != null) {\r
+ request.responseStrings = new ArrayList<String>();\r
+ for (int i=0; i<responseStrings.size(); i++) \r
+ request.responseStrings.add(new String(responseStrings.get(i))); \r
+ }\r
+ \r
+ if (responseResource != null) {\r
+ request.responseResource = responseResource.deepCopy();\r
+ }\r
+ \r
+ if (responseString != null) \r
+ request.responseString = new String(responseString);\r
+ \r
+ if (responseResources != null) {\r
+ request.responseResources = new ArrayList<Resource>();\r
+ for (int i=0; i<responseResources.size(); i++) \r
+ request.responseResources.add(responseResources.get(i).deepCopy()); \r
+ }\r
+ \r
+ request.responseInteger = responseInteger;\r
+ return request;\r
+ }\r
+ \r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.sql.requests;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.SavedSearch;\r
+\r
+public class SavedSearchRequest extends DBRunnerRequest {\r
+ public static int Create_Table = 1;\r
+ public static int Drop_Table = 2;\r
+ public static int Get_All = 3;\r
+ public static int Update_Saved_Search = 4;\r
+ public static int Expunge_Saved_Search = 5;\r
+ public static int Get_Saved_Search = 6;\r
+ public static int Add_Saved_Search = 7;\r
+ public static int Update_Saved_Search_Sequence = 8;\r
+ public static int Get_Dirty = 9;\r
+ public static int Find_Saved_Search_By_Name = 10;\r
+ public static int Exists = 11;\r
+ public static int Sync_Saved_Search = 12;\r
+ public static int Reset_Dirty_Flag = 13;\r
+ \r
+\r
+ public volatile String string1;\r
+ public volatile String string2;\r
+ public volatile int int1;\r
+ public volatile boolean bool1;\r
+ public volatile SavedSearch savedSearch;\r
+ public volatile List<SavedSearch> savedSearches;\r
+ \r
+ public volatile List<SavedSearch> responseSavedSearches;\r
+ public volatile SavedSearch responseSavedSearch;\r
+ public volatile String responseString;\r
+ public volatile boolean responseBoolean;\r
+ \r
+ public SavedSearchRequest() {\r
+ category = SAVED_SEARCH;\r
+ }\r
+ \r
+ public SavedSearchRequest copy() {\r
+ SavedSearchRequest request = new SavedSearchRequest();\r
+ \r
+ request.requestor_id = requestor_id;\r
+ request.type = type;\r
+ request.category = category;\r
+ if (string1 != null)\r
+ request.string1 = new String(string1);\r
+ if (string2 != null)\r
+ request.string2 = new String(string2);\r
+ request.bool1 = bool1;\r
+ \r
+ if (responseString != null)\r
+ request.responseString = new String(responseString);\r
+ \r
+ if (savedSearch != null)\r
+ request.savedSearch = savedSearch.deepCopy();\r
+ if (savedSearches != null)\r
+ for (int i=0; i<savedSearches.size(); i++)\r
+ request.savedSearches.add(savedSearches.get(i).deepCopy());\r
+ \r
+ request.responseBoolean = responseBoolean;\r
+ \r
+ if (responseSavedSearches != null) {\r
+ request.responseSavedSearches = new ArrayList<SavedSearch>();\r
+ for (int i=0; i<responseSavedSearches.size(); i++) \r
+ request.responseSavedSearches.add(responseSavedSearches.get(i).deepCopy()); \r
+ }\r
+ \r
+ if (responseSavedSearch != null) {\r
+ request.responseSavedSearch = responseSavedSearch.deepCopy();\r
+ }\r
+\r
+ return request;\r
+ }\r
+ \r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.sql.requests;\r
+\r
+\r
+\r
+public class SyncRequest extends DBRunnerRequest {\r
+ public static int Create_Table = 1;\r
+ public static int Drop_Table = 2;\r
+ public static int Set_Record = 3;\r
+ public static int Get_Record = 4;\r
+\r
+\r
+ public volatile int int1;\r
+ public volatile long long1;\r
+ public volatile String key;\r
+ public volatile String value;\r
+ \r
+ public String responseValue;\r
+ \r
+ public SyncRequest() {\r
+ category = Sync;\r
+ }\r
+ \r
+ public SyncRequest copy() {\r
+ SyncRequest req = new SyncRequest();\r
+ req.type = type;\r
+ req.category = category;\r
+ req.requestor_id = requestor_id;\r
+ \r
+ req.int1 = int1;\r
+ req.long1 = long1;\r
+ if (key != null) \r
+ req.key = new String(key);\r
+ if (value != null) \r
+ req.value = new String(value);\r
+ if (responseValue != null) \r
+ req.responseValue = new String(responseValue);\r
+\r
+ return req;\r
+ }\r
+ \r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.sql.requests;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.Tag;\r
+\r
+public class TagRequest extends DBRunnerRequest {\r
+ public static int Create_Table = 1;\r
+ public static int Drop_Table = 2;\r
+ public static int Add_Tag = 3;\r
+ public static int Delete_Tag = 4;\r
+ public static int Get_All = 5;\r
+ public static int Get_Tag = 6;\r
+ public static int Update_Tag = 7;\r
+ public static int Expunge_Tag = 8;\r
+ public static int Update_Parent = 9;\r
+ public static int Save_Tags = 10;\r
+ public static int Update_Tag_Sequence = 11;\r
+ public static int Update_Tag_Guid = 12;\r
+ public static int Get_Dirty = 13;\r
+ public static int Find_Tag_By_Name = 14;\r
+ public static int Exists = 15;\r
+ public static int Reset_Dirty_Flag = 16;\r
+ public static int Sync_Tag = 17;\r
+\r
+ public volatile String string1;\r
+ public volatile String string2; \r
+ public volatile boolean bool1;\r
+ public volatile int int1;\r
+\r
+ public volatile Tag tag;\r
+ public volatile List<Tag> tags;\r
+ \r
+ public volatile List<Tag> responseTags;\r
+ public volatile Tag responseTag;\r
+ public volatile String responseString;\r
+ public volatile boolean responseBool;\r
+ \r
+ public TagRequest() {\r
+ category = TAG;\r
+ }\r
+ \r
+ public TagRequest copy() {\r
+ TagRequest request = new TagRequest();\r
+ \r
+ request.requestor_id = requestor_id;\r
+ request.type = type;\r
+ request.category = category;\r
+ request.int1 = int1;\r
+ if (string1 != null)\r
+ request.string1 = new String(string1);\r
+ if (string2 != null)\r
+ request.string2 = new String(string2);\r
+ if (tag != null)\r
+ request.tag = tag;\r
+ request.bool1 = bool1;\r
+ if (tags != null && tags.size() > 0) {\r
+ for (int i=0; i<tags.size(); i++)\r
+ request.tags.add(tags.get(i));\r
+ }\r
+ \r
+ responseBool = request.responseBool;\r
+ if (responseString != null) {\r
+ request.responseString = new String(responseString);\r
+ }\r
+ \r
+ if (responseTag != null)\r
+ request.responseTag = responseTag.deepCopy();\r
+ \r
+ if (responseTags != null) {\r
+ request.responseTags = new ArrayList<Tag>();\r
+ for (int i =0; i<responseTags.size(); i++)\r
+ request.responseTags.add(responseTags.get(i).deepCopy());\r
+ }\r
+ \r
+ return request;\r
+ }\r
+ \r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.sql.requests;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import cx.fbn.nevernote.sql.runners.WatchFolderRecord;\r
+\r
+\r
+public class WatchFolderRequest extends DBRunnerRequest {\r
+ public static int Create_Tables = 1;\r
+ public static int Drop_Tables = 2;\r
+ public static int Expunge_Folder = 3;\r
+ public static int Get_All = 4;\r
+ public static int Add_Watch_Folder = 5;\r
+ public static int Expunge_All = 6;\r
+ public static int Get_Notebook = 7;\r
+\r
+ public volatile String string1;\r
+ public volatile String string2;\r
+ public volatile Boolean bool1;\r
+ public volatile Integer int1;\r
+ \r
+ public List<WatchFolderRecord> responseWatchFolders;\r
+ public String responseString;\r
+ \r
+ public WatchFolderRequest() {\r
+ category = WATCH_FOLDER;\r
+ }\r
+ \r
+ public WatchFolderRequest copy() {\r
+ WatchFolderRequest request = new WatchFolderRequest();\r
+ \r
+ request.requestor_id = requestor_id;\r
+ request.type = type;\r
+ request.category = category;\r
+ if (string1 != null)\r
+ request.string1 = new String(string1);\r
+ if (string2 != null)\r
+ request.string2 = new String(string2);\r
+ if (int1 != null)\r
+ request.int1 = new Integer(int1);\r
+ if (bool1 != null)\r
+ request.bool1 = new Boolean(bool1);\r
+ \r
+ if (responseWatchFolders != null) {\r
+ request.responseWatchFolders = new ArrayList<WatchFolderRecord>();\r
+ for (int i=0; i<responseWatchFolders.size(); i++) {\r
+ WatchFolderRecord newRec = new WatchFolderRecord();\r
+ newRec.depth = responseWatchFolders.get(i).depth;\r
+ newRec.keep = responseWatchFolders.get(i).keep;\r
+ newRec.folder = responseWatchFolders.get(i).folder;\r
+ newRec.notebook = responseWatchFolders.get(i).notebook;\r
+ request.responseWatchFolders.add(newRec);\r
+ }\r
+ }\r
+ \r
+ if (responseString != null) {\r
+ request.responseString = new String(responseString);\r
+ }\r
+ \r
+ return request;\r
+ }\r
+ \r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.sql.requests;\r
+\r
+\r
+public class WordRequest extends DBRunnerRequest {\r
+ public static int Create_Table = 1;\r
+ public static int Drop_Table = 2;\r
+ public static int Get_Word_Count = 3;\r
+ public static int Clear_Word_Index = 4;\r
+ public static int Expunge_From_Word_Index = 5;\r
+ public static int Add_Word_To_Note_Index = 6;\r
+\r
+\r
+ public volatile String string1;\r
+ public volatile String string2;\r
+ public volatile String string3;\r
+ public volatile String string4;\r
+ public volatile int int1;\r
+ \r
+ public int responseInt;\r
+ \r
+ public WordRequest() {\r
+ category = WORD;\r
+ }\r
+ \r
+ public WordRequest copy() {\r
+ WordRequest req = new WordRequest();\r
+ req.type = type;\r
+ req.category = category;\r
+ req.requestor_id = requestor_id;\r
+ \r
+ req.responseInt = responseInt;\r
+ \r
+ if (string1 != null)\r
+ req.string1 = new String(string1);\r
+ if (string2 != null)\r
+ req.string2 = new String(string2);\r
+ if (string3 != null)\r
+ req.string3 = new String(string3);\r
+ if (string4 != null)\r
+ req.string4 = new String(string4);\r
+ req.int1 = int1;\r
+\r
+ return req;\r
+ }\r
+ \r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.sql.runners;\r
+\r
+public class DeletedItemRecord {\r
+ public String guid;\r
+ public String type;\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.sql.runners;\r
+\r
+public class NoteTagsRecord {\r
+ public String noteGuid;\r
+ public String tagGuid;\r
+}\r
--- /dev/null
+/*
+ * This file is part of NeverNote
+ * 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.runners;
+
+import java.io.File;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
+import com.trolltech.qt.sql.QJdbc;
+
+import cx.fbn.nevernote.Global;
+import cx.fbn.nevernote.sql.driver.NSqlQuery;
+import cx.fbn.nevernote.utilities.ApplicationLogger;
+
+public class RDatabaseConnection {
+ // Table helpers
+ private RTagTable tagTable;
+ private RNotebookTable notebookTable;
+ private RNoteTable noteTable;
+ private RDeletedTable deletedTable;
+ private RSavedSearchTable searchTable;
+ private RWatchFolderTable watchFolderTable;
+ private RInvalidXMLTable invalidXMLTable;
+ private final ApplicationLogger logger;
+ private Connection conn;
+ private final String databaseName;
+ private RWordsTable wordsTable;
+ private RSyncTable syncTable;
+
+
+ public RDatabaseConnection(ApplicationLogger l, String c) {
+ logger = l;
+ databaseName = Global.databaseName;
+ }
+
+ private void setupTables() {
+ tagTable = new RTagTable(logger, this);
+ notebookTable = new RNotebookTable(logger, this);
+ noteTable = new RNoteTable(logger, this);
+ deletedTable = new RDeletedTable(logger, this);
+ searchTable = new RSavedSearchTable(logger, this);
+ watchFolderTable = new RWatchFolderTable(logger, this);
+ invalidXMLTable = new RInvalidXMLTable(logger, this);
+ wordsTable = new RWordsTable(logger, this);
+ syncTable = new RSyncTable(logger, this);
+ }
+
+ //***************************************************************
+ //***************************************************************
+ //** These functions deal starting & stopping the database
+ //***************************************************************
+ //***************************************************************
+ // Initialize the database connection
+ public void dbSetup(String url,String userid, String userPassword, String cypherPassword) {
+ logger.log(logger.HIGH, "Entering RDatabaseConnection.dbSetup");
+
+ // This thread cleans things up if we crash
+// ShutdownRunner shutdownRunner = new ShutdownRunner(this);
+// Runtime.getRuntime().addShutdownHook(shutdownRunner);
+
+/* if (QSqlDatabase.isDriverAvailable("QSQLITE"))
+ logger.log(logger.MEDIUM, "SQL Driver check was successful.");
+ else {
+ logger.log(logger.MEDIUM, "SQL Driver check has failed.");
+ System.err.println("Database failure");
+ System.exit(16);
+ }
+*/
+
+ try {
+ Class.forName("org.h2.Driver");
+ } catch (ClassNotFoundException e1) {
+ e1.printStackTrace();
+ System.exit(16);
+ }
+
+ QJdbc.initialize();
+// db = QSqlDatabase.addDatabase("QSQLITE", connectionName);
+// db = QSqlDatabase.addDatabase("QJDBC", connectionName);
+// db.setDatabaseName("jdbc:h2:"+Global.getDirectoryPath() +File.separator +"db" +File.separator +databaseName);
+
+ setupTables();
+
+ File f = new File(Global.getDirectoryPath() +File.separator +"db" +File.separator +databaseName +".h2.db");
+ boolean dbExists = f.exists();
+
+ try {
+ String passwordString = null;
+ if (cypherPassword==null || cypherPassword.trim().equals(""))
+ passwordString = userPassword;
+ else
+ passwordString = cypherPassword+" "+userPassword;
+ conn = DriverManager.getConnection(url,userid,passwordString);
+ } catch (SQLException e) {
+ e.printStackTrace();
+ return;
+ }
+
+ if (!dbExists)
+ createTables();
+
+ logger.log(logger.HIGH, "Leaving RDatabaseConnection.dbSetup");
+ }
+ // Tear down the database connections
+ public void dbShutdown() {
+ logger.log(logger.HIGH, "Entering RDatabaseConnection.dbShutdown");
+ try {
+ conn.close();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ logger.log(logger.HIGH, "Leaving RDatabaseConnection.dbShutdown");
+ }
+
+ public void backupDatabase() {
+ }
+
+ public void executeSql(String sql) {
+ NSqlQuery query = new NSqlQuery(conn);
+ query.exec(sql);
+ }
+
+ // Create note tables
+ public void dropTables() {
+ logger.log(logger.HIGH, "Entering RDatabaseConnection.dropTables");
+ getTagTable().dropTable();
+ getNotebookTable().dropTable();
+ getNoteTable().dropTable();
+ getDeletedTable().dropTable();
+ getSavedSearchTable().dropTable();
+ logger.log(logger.HIGH, "Leaving RDatabaseConnection.dropTables");
+ }
+ public void createTables() {
+ logger.log(logger.HIGH, "Entering RDatabaseConnection.createTables");
+ getTagTable().createTable();
+ notebookTable.createTable();
+ noteTable.createTable();
+ deletedTable.createTable();
+ searchTable.createTable();
+ watchFolderTable.createTable();
+ invalidXMLTable.createTable();
+ wordsTable.createTable();
+ syncTable.createTable();
+ logger.log(logger.HIGH, "Leaving RDatabaseConnection.createTables");
+ }
+
+
+ public void compactDatabase() {
+ logger.log(logger.HIGH, "Entering RDatabaseConnection.compactDatabase");
+ NSqlQuery query = new NSqlQuery(conn);
+ query.exec("vacuum");
+ logger.log(logger.HIGH, "Leaving RDatabaseConnection.PragmaSettings");
+ }
+
+
+ public Connection getConnection() {
+ return conn;
+ }
+
+ //***************************************************************
+ //* Table get methods
+ //***************************************************************
+ public RDeletedTable getDeletedTable() {
+ return deletedTable;
+ }
+ public RTagTable getTagTable() {
+ return tagTable;
+ }
+ public RNoteTable getNoteTable() {
+ return noteTable;
+ }
+ public RNotebookTable getNotebookTable() {
+ return notebookTable;
+ }
+ public RSavedSearchTable getSavedSearchTable() {
+ return searchTable;
+ }
+ public RWatchFolderTable getWatchFolderTable() {
+ return watchFolderTable;
+ }
+ public RInvalidXMLTable getInvalidXMLTable() {
+ return invalidXMLTable;
+ }
+ public RWordsTable getWordsTable() {
+ return wordsTable;
+ }
+ public RSyncTable getSyncTable() {
+ return syncTable;
+ }
+}
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.sql.runners;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import cx.fbn.nevernote.sql.driver.NSqlQuery;\r
+import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+import cx.fbn.nevernote.utilities.ListManager;\r
+\r
+public class RDeletedTable {\r
+ ListManager parent;\r
+ private final ApplicationLogger logger;\r
+ private final RDatabaseConnection db;\r
+\r
+ \r
+ // Constructor\r
+ public RDeletedTable(ApplicationLogger l, RDatabaseConnection d) {\r
+ logger = l;\r
+ db = d;\r
+ }\r
+ // Create the table\r
+ public void createTable() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ logger.log(logger.HIGH, "Creating table DeletedItems...");\r
+ if (!query.exec("Create table DeletedItems (guid varchar primary key, type varchar)"))\r
+ logger.log(logger.HIGH, "Table DeletedItems creation FAILED!!!"); \r
+ }\r
+ // Drop the table\r
+ public void dropTable() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.exec("Drop table DeletedItems");\r
+ }\r
+ // Add an item to the deleted table\r
+ public void addDeletedItem(String guid, String type) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("Insert Into DeletedItems (guid, type) Values(:guid, :type)");\r
+ query.bindValue(":guid", guid);\r
+ query.bindValue(":type", type);\r
+ if (!query.exec()) {\r
+ logger.log(logger.MEDIUM, "Insert into deleted items failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ }\r
+ // Add an item to the deleted table\r
+ public void expungeDeletedItem(String guid, String type) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("delete from DeletedItems where guid=:guid and type=:type");\r
+ query.bindValue(":guid", guid);\r
+ query.bindValue(":type", type);\r
+ if (!query.exec()) {\r
+ logger.log(logger.MEDIUM, "Expunge deleted items failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ }\r
+ public List<DeletedItemRecord> getAllDeleted() {\r
+ logger.log(logger.HIGH, "Entering DeletedTable.getAllDeleted");\r
+ List<DeletedItemRecord> list = new ArrayList<DeletedItemRecord>();\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.exec("Select guid, type from DeletedItems");\r
+ while (query.next()) {\r
+ DeletedItemRecord record = new DeletedItemRecord();\r
+ record.guid = query.valueString(0);\r
+ record.type = query.valueString(1);\r
+ list.add(record);\r
+ }\r
+ logger.log(logger.HIGH, "Leaving DeletedTable.getAllDeleted");\r
+ return list;\r
+\r
+ }\r
+ public void expungeAllDeletedRecords() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.exec("delete from DeletedItems");\r
+ }\r
+\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.sql.runners;\r
+\r
+import java.text.SimpleDateFormat;\r
+import java.util.ArrayList;\r
+import java.util.Calendar;\r
+import java.util.GregorianCalendar;\r
+import java.util.List;\r
+import java.util.regex.Pattern;\r
+\r
+import com.evernote.edam.type.Note;\r
+import com.evernote.edam.type.Notebook;\r
+import com.evernote.edam.type.Tag;\r
+\r
+import cx.fbn.nevernote.sql.driver.NSqlQuery;\r
+import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+\r
+public class REnSearch {\r
+ \r
+ private final List<String> searchWords;\r
+ private final List<String> notebooks;\r
+ private final List<String> tags;\r
+ private final List<String> intitle;\r
+ private final List<String> created;\r
+ private final List<String> updated;\r
+ private final List<String> resource;\r
+ private final List<String> subjectDate;\r
+ private final List<String> longitude;\r
+ private final List<String> latitude;\r
+ private final List<String> altitude;\r
+ private final List<String> author;\r
+ private final List<String> source;\r
+ private final List<String> sourceApplication;\r
+ private final List<String> recoType;\r
+ private final List<String> todo;\r
+ private final List<Tag> tagIndex;\r
+ private final ApplicationLogger logger;\r
+ private final RDatabaseConnection db;\r
+ private boolean any;\r
+ private int minimumWordLength = 3;\r
+ private int minimumRecognitionWeight = 80;\r
+ private final RDatabaseConnection conn;\r
+ \r
+ public REnSearch(RDatabaseConnection c, ApplicationLogger l, RDatabaseConnection d, String s, List<Tag> t, int m, int r) {\r
+ db = d;\r
+ logger = l;\r
+ conn = c;\r
+ tagIndex = t;\r
+ minimumWordLength = m;\r
+ minimumRecognitionWeight = r;\r
+ searchWords = new ArrayList<String>();\r
+ notebooks = new ArrayList<String>();\r
+ tags = new ArrayList<String>();\r
+ intitle = new ArrayList<String>();\r
+ created = new ArrayList<String>();\r
+ updated = new ArrayList<String>();\r
+ resource = new ArrayList<String>();\r
+ subjectDate = new ArrayList<String>();\r
+ longitude = new ArrayList<String>();\r
+ latitude = new ArrayList<String>();\r
+ altitude = new ArrayList<String>();\r
+ author = new ArrayList<String>();\r
+ source = new ArrayList<String>();\r
+ sourceApplication = new ArrayList<String>();\r
+ recoType = new ArrayList<String>();\r
+ todo = new ArrayList<String>();\r
+ any = false;\r
+ \r
+ if (s == null) \r
+ return;\r
+ if (s.trim().equals(""))\r
+ return;\r
+ \r
+ resolveSearch(s);\r
+ }\r
+ \r
+ public List<String> getWords() { return searchWords; }\r
+ public List<String> getNotebooks() { return notebooks; }\r
+ public List<String> getIntitle() { return intitle; }\r
+ public List<String> getTags() { return tags; }\r
+ public List<String> getResource() { return resource; }\r
+ public List<String> getAuthor() { return author; } \r
+ public List<String> getSource() { return source; } \r
+ public List<String> getSourceApplication() { return sourceApplication; } \r
+ public List<String> getRecoType() { return recoType; } \r
+ public List<String> getToDo() { return todo; }\r
+ public List<String> getLongitude() { return longitude; }\r
+ public List<String> getLatitude() { return latitude; }\r
+ public List<String> getAltitude() { return altitude; }\r
+ public List<String> getCreated() { return created; }\r
+ public List<String> getUpdated() { return updated; }\r
+ public List<String> getSubjectDate() { return subjectDate; }\r
+ \r
+\r
+ // match tag names\r
+ private boolean matchTagsAll(List<String> tagNames) {\r
+ List<String> list = getTags();\r
+ \r
+ for (int j=0; j<list.size(); j++) {\r
+ boolean negative = false;\r
+ negative = false;\r
+ if (list.get(j).startsWith("-"))\r
+ negative = true;\r
+ int pos = list.get(j).indexOf(":");\r
+ String filterName = cleanupWord(list.get(j).substring(pos+1));\r
+ filterName = filterName.replace("*", ".*"); // setup for regular expression pattern match\r
+ \r
+ if (tagNames.size() == 0 && !negative)\r
+ return false;\r
+ if (tagNames.size() == 0 && negative)\r
+ return true;\r
+ \r
+ for (int i=0; i<tagNames.size(); i++) { \r
+ boolean matches = Pattern.matches(filterName.toLowerCase(),tagNames.get(i).toLowerCase());\r
+ if (matches && negative)\r
+ return false;\r
+ if (!matches && !negative)\r
+ return false;\r
+ }\r
+ }\r
+ return true;\r
+ }\r
+ \r
+ // match tag names\r
+ private boolean matchTagsAny(List<String> tagNames) {\r
+ List<String> list = getTags();\r
+ if (list.size() == 0)\r
+ return true;\r
+ \r
+ boolean negative = false; \r
+ boolean found = false;\r
+ \r
+ for (int j=0; j<list.size(); j++) {\r
+ negative = false;\r
+ if (list.get(j).startsWith("-"))\r
+ negative = true;\r
+ int pos = list.get(j).indexOf(":");\r
+ String filterName = cleanupWord(list.get(j).substring(pos+1));\r
+ filterName = filterName.replace("*", ".*"); // setup for regular expression pattern match\r
+ \r
+ if (tagNames.size() == 0)\r
+ found = false;\r
+\r
+ for (int i=0; i<tagNames.size(); i++) { \r
+ boolean matches = Pattern.matches(filterName.toLowerCase(),tagNames.get(i).toLowerCase());\r
+ if (matches)\r
+ found = true;\r
+ }\r
+ }\r
+ if (negative)\r
+ return !found;\r
+ else\r
+ return found;\r
+ }\r
+ \r
+ // Match notebooks in search terms against notes\r
+ private boolean matchNotebook(String guid) {\r
+ if (getNotebooks().size() == 0)\r
+ return true;\r
+ RNotebookTable bookTable = new RNotebookTable(logger, conn);\r
+ List<Notebook> books = bookTable.getAll();\r
+\r
+ String name = new String("");\r
+ for (int i=0; i<books.size(); i++) {\r
+ if (guid.equalsIgnoreCase(books.get(i).getGuid())) {\r
+ name = books.get(i).getName();\r
+ i=books.size();\r
+ }\r
+ }\r
+ if (any)\r
+ return matchListAny(getNotebooks(), name);\r
+ else\r
+ return matchListAll(getNotebooks(), name);\r
+ }\r
+ // Match notebooks in search terms against notes\r
+ private boolean matchListAny(List<String> list, String title) {\r
+ if (list.size() == 0)\r
+ return true;\r
+ boolean negative = false;\r
+ boolean found = false;\r
+ for (int i=0; i<list.size(); i++) {\r
+ int pos = list.get(i).indexOf(":");\r
+ negative = false;\r
+ if (list.get(i).startsWith("-"))\r
+ negative = true;\r
+ String filterName = cleanupWord(list.get(i).substring(pos+1));\r
+ filterName = filterName.replace("*", ".*"); // setup for regular expression pattern match\r
+ boolean matches = Pattern.matches(filterName.toLowerCase(),title.toLowerCase());\r
+ if (matches)\r
+ found = true;\r
+ }\r
+ if (negative)\r
+ return !found;\r
+ else\r
+ return found;\r
+ }\r
+ // Match notebooks in search terms against notes\r
+ private boolean matchContentAny(Note n) {\r
+ if (todo.size() == 0 && resource.size() == 0)\r
+ return true;\r
+ \r
+ \r
+ n = conn.getNoteTable().getNote(n.getGuid(), true, true, false, false, false);\r
+ for (int i=0; i<todo.size(); i++) {\r
+ String value = todo.get(i);\r
+ value = value.replace("\"", "");\r
+ boolean desiredState;\r
+ if (!value.endsWith(":false") && !value.endsWith(":true") && !value.endsWith(":*") && !value.endsWith("*"))\r
+ return false;\r
+ if (value.endsWith(":false"))\r
+ desiredState = false;\r
+ else\r
+ desiredState = true;\r
+ if (value.startsWith("-"))\r
+ desiredState = !desiredState;\r
+ int pos = n.getContent().indexOf("<en-todo");\r
+ if (pos == -1 && value.startsWith("-") && (value.endsWith("*") || value.endsWith(":")))\r
+ return true;\r
+ if (value.endsWith("*"))\r
+ return true;\r
+ while (pos > -1) {\r
+ int endPos = n.getContent().indexOf("/>", pos);\r
+ String segment = n.getContent().substring(pos, endPos);\r
+ boolean currentState;\r
+ if (segment.toLowerCase().indexOf("checked=\"true\"") == -1)\r
+ currentState = false;\r
+ else\r
+ currentState = true;\r
+ if (desiredState == currentState)\r
+ return true;\r
+ \r
+ pos = n.getContent().indexOf("<en-todo", pos+1);\r
+ }\r
+ }\r
+ \r
+ // Check resources\r
+ for (int i=0; i<resource.size(); i++) {\r
+ String resourceString = resource.get(i);\r
+ resourceString = resourceString.replace("\"", "");\r
+ boolean negative = false;\r
+ if (resourceString.startsWith("-"))\r
+ negative = true;\r
+ resourceString = resourceString.substring(resourceString.indexOf(":")+1);\r
+ for (int j=0; j<n.getResourcesSize(); j++) {\r
+ boolean match = stringMatch(n.getResources().get(j).getMime(), resourceString, negative);\r
+ if (match)\r
+ return true;\r
+ }\r
+ }\r
+ return false;\r
+ }\r
+ \r
+ \r
+ // Take the initial search & split it apart\r
+ private void resolveSearch(String search) {\r
+ List<String> words = new ArrayList<String>();\r
+ StringBuffer b = new StringBuffer(search);\r
+ \r
+ int len = search.length();\r
+ char nextChar = ' ';\r
+ boolean quote = false;\r
+ for (int i=0; i<len; i++) {\r
+ if (search.charAt(i)==nextChar && !quote) {\r
+ b.setCharAt(i,'\0');\r
+ nextChar = ' ';\r
+ } else {\r
+ if (search.charAt(i)=='\"') {\r
+ if (!quote) {\r
+ quote=true;\r
+ } else {\r
+ quote=false;\r
+ }\r
+ }\r
+ }\r
+ if (((i+2)<len) && search.charAt(i) == '\\') {\r
+ i=i+2;\r
+ }\r
+ }\r
+ \r
+ search = b.toString();\r
+ int pos = 0;\r
+ for (int i=0; i<search.length(); i++) {\r
+ if (search.charAt(i) == '\0') {\r
+ search = search.substring(1);\r
+ i=0;\r
+ } else {\r
+ pos = search.indexOf('\0');\r
+ if (pos > 0) {\r
+ words.add(search.substring(0,pos).toLowerCase());\r
+ search = search.substring(pos);\r
+ i=0;\r
+ }\r
+ }\r
+ }\r
+ if (search.charAt(0)=='\0') \r
+ words.add(search.substring(1).toLowerCase());\r
+ else\r
+ words.add(search.toLowerCase());\r
+ parseTerms(words);\r
+ }\r
+\r
+ \r
+ // Parse out individual words into separate lists\r
+ // Supported options\r
+ // Tags\r
+ // Notebooks\r
+ // Intitle\r
+ // author\r
+ // source\r
+ // source application\r
+ // created\r
+ // updated\r
+ // subject date\r
+\r
+ private void parseTerms(List<String> words) {\r
+ int minLen = minimumWordLength;\r
+ \r
+ for (int i=0; i<words.size(); i++) {\r
+ String word = words.get(i);\r
+ int pos = word.indexOf(":");\r
+ if (word.startsWith("any:")) {\r
+ any = true;\r
+ word = word.substring(4).trim();\r
+ pos = word.indexOf(":");\r
+ }\r
+ if (pos < 0 && (word.length() >= minLen || word.indexOf('*')>=0)) \r
+ getWords().add(word);\r
+ if (word.startsWith("intitle:")) \r
+ intitle.add("*"+word+"*");\r
+ if (word.startsWith("-intitle:")) \r
+ intitle.add("*"+word+"*");\r
+ if (word.startsWith("notebook:")) \r
+ notebooks.add(word);\r
+ if (word.startsWith("-notebook:")) \r
+ notebooks.add(word);\r
+ if (word.startsWith("tag:")) \r
+ tags.add(word);\r
+ if (word.startsWith("-tag:")) \r
+ tags.add(word);\r
+ if (word.startsWith("resource:")) \r
+ resource.add(word);\r
+ if (word.startsWith("-resource:")) \r
+ resource.add(word);\r
+ if (word.startsWith("author:")) \r
+ author.add(word);\r
+ if (word.startsWith("-author:")) \r
+ author.add(word);\r
+ if (word.startsWith("source:")) \r
+ source.add(word);\r
+ if (word.startsWith("-source:")) \r
+ source.add(word);\r
+ if (word.startsWith("sourceapplication:")) \r
+ sourceApplication.add(word);\r
+ if (word.startsWith("-sourceapplication:")) \r
+ sourceApplication.add(word);\r
+ if (word.startsWith("recotype:")) \r
+ recoType.add(word);\r
+ if (word.startsWith("-recotype:")) \r
+ recoType.add(word);\r
+ if (word.startsWith("todo:")) \r
+ todo.add(word);\r
+ if (word.startsWith("-todo:")) \r
+ todo.add(word);\r
+\r
+ if (word.startsWith("latitude:")) \r
+ latitude.add(word);\r
+ if (word.startsWith("-latitude:")) \r
+ latitude.add(word);\r
+ if (word.startsWith("longitude:")) \r
+ longitude.add(word);\r
+ if (word.startsWith("-longitude:")) \r
+ longitude.add(word);\r
+ if (word.startsWith("altitude:")) \r
+ altitude.add(word);\r
+ if (word.startsWith("-altitude:")) \r
+ altitude.add(word);\r
+\r
+ if (word.startsWith("created:")) \r
+ created.add(word);\r
+ if (word.startsWith("-created:")) \r
+ created.add(word);\r
+ if (word.startsWith("updated:")) \r
+ updated.add(word);\r
+ if (word.startsWith("-updated:")) \r
+ updated.add(word);\r
+ if (word.startsWith("subjectdate:")) \r
+ created.add(word);\r
+ if (word.startsWith("-subjectdate:")) \r
+ created.add(word);\r
+ \r
+ }\r
+ }\r
+ // Match notebooks in search terms against notes\r
+ private boolean matchListAll(List<String> list, String title) {\r
+ if (list.size() == 0)\r
+ return true;\r
+ boolean negative = false;\r
+ for (int i=0; i<list.size(); i++) {\r
+ int pos = list.get(i).indexOf(":");\r
+ negative = false;\r
+ if (list.get(i).startsWith("-"))\r
+ negative = true;\r
+ String filterName = cleanupWord(list.get(i).substring(pos+1));\r
+ filterName = filterName.replace("*", ".*"); // setup for regular expression pattern match\r
+ boolean matches = Pattern.matches(filterName.toLowerCase(),title.toLowerCase());\r
+ if (matches && negative)\r
+ return false;\r
+ if (matches && !negative)\r
+ return true;\r
+ }\r
+ if (negative)\r
+ return true;\r
+ else\r
+ return false;\r
+ }\r
+ // Match notebooks in search terms against notes\r
+ private boolean matchContentAll(Note n) {\r
+ if (todo.size() == 0 && resource.size() == 0)\r
+ return true;\r
+ \r
+ boolean returnTodo = false;\r
+ boolean returnResource = false;\r
+ \r
+ if (todo.size() == 0)\r
+ returnTodo = true;\r
+ if (resource.size() == 0)\r
+ returnResource = true;\r
+ \r
+ \r
+ n = conn.getNoteTable().getNote(n.getGuid(), true, true, false, false, false);\r
+ for (int i=0; i<todo.size(); i++) {\r
+ String value = todo.get(i);\r
+ value = value.replace("\"", "");\r
+ boolean desiredState;\r
+ if (!value.endsWith(":false") && !value.endsWith(":true") && !value.endsWith(":*") && !value.endsWith("*"))\r
+ return false;\r
+ if (value.endsWith(":false"))\r
+ desiredState = false;\r
+ else\r
+ desiredState = true;\r
+ if (value.startsWith("-"))\r
+ desiredState = !desiredState;\r
+ int pos = n.getContent().indexOf("<en-todo");\r
+ if (pos == -1 && value.startsWith("-") && (value.endsWith("*") || value.endsWith(":")))\r
+ return true;\r
+ if (pos > -1 && value.startsWith("-") && (value.endsWith("*") || value.endsWith(":")))\r
+ return false;\r
+ if (pos == -1) \r
+ return false;\r
+ if (value.endsWith("*"))\r
+ returnTodo = true;\r
+ while (pos > -1) {\r
+ int endPos = n.getContent().indexOf("/>", pos);\r
+ String segment = n.getContent().substring(pos, endPos);\r
+ boolean currentState;\r
+ if (segment.toLowerCase().indexOf("checked=\"true\"") == -1)\r
+ currentState = false;\r
+ else\r
+ currentState = true;\r
+ if (desiredState == currentState)\r
+ returnTodo = true;\r
+ \r
+ pos = n.getContent().indexOf("<en-todo", pos+1);\r
+ }\r
+ }\r
+ \r
+ // Check resources\r
+ for (int i=0; i<resource.size(); i++) {\r
+ String resourceString = resource.get(i);\r
+ resourceString = resourceString.replace("\"", "");\r
+ boolean negative = false;\r
+ if (resourceString.startsWith("-"))\r
+ negative = true;\r
+ resourceString = resourceString.substring(resourceString.indexOf(":")+1);\r
+ if (resourceString.equals(""))\r
+ return false;\r
+ for (int j=0; j<n.getResourcesSize(); j++) {\r
+ boolean match = stringMatch(n.getResources().get(j).getMime(), resourceString, negative);\r
+ if (!match)\r
+ return false;\r
+ returnResource = true;\r
+ }\r
+ }\r
+ \r
+ \r
+ return returnResource && returnTodo;\r
+ }\r
+ \r
+ private boolean stringMatch(String content, String text, boolean negative) {\r
+ String regex;\r
+ if (content == null && !negative)\r
+ return false;\r
+ if (content == null && negative)\r
+ return true;\r
+ \r
+ if (text.endsWith("*")) {\r
+ text = text.substring(0,text.length()-1);\r
+ regex = text;\r
+ } else {\r
+ regex = text;\r
+ }\r
+ content = content.toLowerCase();\r
+ regex = regex.toLowerCase();\r
+ boolean matches = content.startsWith(regex);\r
+ if (negative)\r
+ return !matches;\r
+ return matches;\r
+ }\r
+ \r
+ // Remove odd strings from search terms\r
+ private String cleanupWord(String word) {\r
+ if (word.startsWith("\""))\r
+ word = word.substring(1);\r
+ if (word.endsWith("\""))\r
+ word = word.substring(0,word.length()-1);\r
+ word = word.replace("\\\"","\"");\r
+ word = word.replace("\\\\","\\");\r
+ \r
+ return word;\r
+ }\r
+\r
+ \r
+ // Match dates\r
+ private boolean matchDatesAll(List<String> dates, long noteDate) {\r
+ if (dates.size()== 0) \r
+ return true;\r
+ \r
+ boolean negative = false;\r
+ for (int i=0; i<dates.size(); i++) {\r
+ String requiredDate = dates.get(i);\r
+ if (requiredDate.startsWith("-"))\r
+ negative = true;\r
+ \r
+ int response = 0;\r
+ requiredDate = requiredDate.substring(requiredDate.indexOf(":")+1);\r
+ try {\r
+ response = dateCheck(requiredDate, noteDate);\r
+ } catch (java.lang.NumberFormatException e) {return false;} {\r
+ if (negative && response < 0)\r
+ return false;\r
+ if (!negative && response > 0)\r
+ return false;\r
+ }\r
+ }\r
+ return true;\r
+ }\r
+ private boolean matchDatesAny(List<String> dates, long noteDate) {\r
+ if (dates.size()== 0) \r
+ return true;\r
+ \r
+ boolean negative = false;\r
+ for (int i=0; i<dates.size(); i++) {\r
+ String requiredDate = dates.get(i);\r
+ if (requiredDate.startsWith("-"))\r
+ negative = true;\r
+ \r
+ int response = 0;\r
+ requiredDate = requiredDate.substring(requiredDate.indexOf(":")+1);\r
+ try {\r
+ response = dateCheck(requiredDate, noteDate);\r
+ } catch (java.lang.NumberFormatException e) {return false;} {\r
+ if (negative && response > 0)\r
+ return true;\r
+ if (!negative && response < 0)\r
+ return true;\r
+ }\r
+ }\r
+ return false;\r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void printCalendar(Calendar calendar) {\r
+ // define output format and print\r
+ SimpleDateFormat sdf = new SimpleDateFormat("d MMM yyyy hh:mm:ss aaa");\r
+ String date = sdf.format(calendar.getTime());\r
+ System.err.print(date);\r
+ calendar = new GregorianCalendar();\r
+ }\r
+ \r
+ \r
+ //****************************************\r
+ //****************************************\r
+ // Match search terms against notes\r
+ //****************************************\r
+ //****************************************\r
+ public List<Note> matchWords() {\r
+ logger.log(logger.EXTREME, "Inside EnSearch.matchWords()");\r
+ \r
+ StringBuffer buffer = new StringBuffer(100);\r
+ Integer counter = 0;\r
+ boolean subSelect = false;\r
+ \r
+ buffer.append("Select guid from Note ");\r
+ if (searchWords.size() > 0) \r
+ subSelect = true;\r
+ if (subSelect) {\r
+ buffer.append(" where guid in ");\r
+ \r
+ // Build the query words\r
+ String connector;\r
+ if (any)\r
+ connector = new String("or");\r
+ else\r
+ connector = new String("and");\r
+ for (int i=0; i<getWords().size(); i++) {\r
+ buffer.append("(Select distinct guid from words where ");\r
+ buffer.append("weight >= :weight"+counter.toString() +" and ");\r
+ if (getWords().get(i).indexOf("*")==-1)\r
+ buffer.append("word=:word" +counter.toString());\r
+ else\r
+ buffer.append("word like :word" +counter.toString());\r
+ counter++;\r
+ buffer.append(") ");\r
+ if (i < getWords().size() -1)\r
+ buffer.append(" " +connector +" guid in ");\r
+ }\r
+ }\r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ if (!query.prepare(buffer.toString()))\r
+ logger.log(logger.HIGH, "EnSearch Sql Prepare Failed:" +query.lastError());\r
+ \r
+ if (subSelect) {\r
+ // Do the binding\r
+ Integer binder = 0;\r
+ for (int i=0; i<getWords().size(); i++) {\r
+ String val = getWords().get(i);\r
+ val = val.replace('*', '%');\r
+ query.bindValue(":weight"+binder.toString(), minimumRecognitionWeight);\r
+ query.bindValue(":word"+binder.toString(), cleanupWord(val));\r
+ binder++;\r
+ } \r
+ }\r
+\r
+ List<Note> guids = new ArrayList<Note>();\r
+ RNoteTable noteTable = new RNoteTable(logger, conn); \r
+ if (!query.exec()) \r
+ logger.log(logger.EXTREME, "EnSearch.matchWords query failed: " +query.lastError());\r
+ List<String> validGuids = new ArrayList<String>();\r
+ while (query.next()) {\r
+ String guid = query.valueString(0);\r
+ validGuids.add(guid);\r
+ }\r
+\r
+ List<Note> noteIndex = noteTable.getAllNotes();\r
+ for (int i=0; i<noteIndex.size(); i++) {\r
+ Note n = noteIndex.get(i);\r
+ boolean good = true;\r
+ \r
+ if (!validGuids.contains(n.getGuid()))\r
+ good = false;\r
+ \r
+ // Start matching special stuff, like tags & notebooks\r
+ if (any) {\r
+ if (good && !matchTagsAny(n.getTagNames()))\r
+ good = false;\r
+ if (good && !matchNotebook(n.getNotebookGuid()))\r
+ good = false;\r
+ if (good && !matchListAny(getIntitle(), n.getTitle()))\r
+ good = false;\r
+ if (good && !matchListAny(getAuthor(), n.getAttributes().getAuthor()))\r
+ good = false;\r
+ if (good && !matchListAny(getSource(), n.getAttributes().getSource()))\r
+ good = false;\r
+ if (good && !matchListAny(getSourceApplication(), n.getAttributes().getSourceApplication()))\r
+ good = false;\r
+ if (good && !matchContentAny(n))\r
+ good = false;\r
+ if (good && !matchDatesAny(getCreated(), n.getCreated()))\r
+ good = false;\r
+ if (good && !matchDatesAny(getUpdated(), n.getUpdated()))\r
+ good = false;\r
+ if (good && n.getAttributes() != null && !matchDatesAny(getSubjectDate(), n.getAttributes().getSubjectDate()))\r
+ good = false;\r
+ } else {\r
+ if (good && !matchTagsAll(n.getTagNames()))\r
+ good = false;\r
+ if (good && !matchNotebook(n.getNotebookGuid()))\r
+ good = false;\r
+ if (good && !matchListAll(getIntitle(), n.getTitle()))\r
+ good = false;\r
+ if (good && !matchListAll(getAuthor(), n.getAttributes().getAuthor()))\r
+ good = false;\r
+ if (good && !matchListAll(getSource(), n.getAttributes().getSource()))\r
+ good = false;\r
+ if (good && !matchListAll(getSourceApplication(), n.getAttributes().getSourceApplication()))\r
+ good = false;\r
+ if (good && !matchContentAll(n))\r
+ good = false;\r
+ if (good && !matchDatesAll(getCreated(), n.getCreated()))\r
+ good = false;\r
+ if (good && !matchDatesAll(getUpdated(), n.getUpdated()))\r
+ good = false;\r
+ if (good && n.getAttributes() != null && !matchDatesAll(getSubjectDate(), n.getAttributes().getSubjectDate()))\r
+ good = false;\r
+ }\r
+ if (good) {\r
+ guids.add(n);\r
+ }\r
+ }\r
+ \r
+ // For performance reasons, we didn't get the tags for every note individually. We now need to \r
+ // get them\r
+ List<NoteTagsRecord> noteTags = noteTable.noteTagsTable.getAllNoteTags();\r
+ for (int i=0; i<guids.size(); i++) {\r
+ List<String> tags = new ArrayList<String>();\r
+ List<String> names = new ArrayList<String>();\r
+ for (int j=0; j<noteTags.size(); j++) {\r
+ if (guids.get(i).getGuid().equals(noteTags.get(j).noteGuid)) {\r
+ tags.add(noteTags.get(j).tagGuid);\r
+ names.add(getTagNameByGuid(noteTags.get(j).tagGuid));\r
+ }\r
+ }\r
+ \r
+ guids.get(i).setTagGuids(tags);\r
+ guids.get(i).setTagNames(names);\r
+ };\r
+ logger.log(logger.EXTREME, "Leaving EnSearch.matchWords()");\r
+ return guids;\r
+ }\r
+ \r
+ \r
+ \r
+ private String getTagNameByGuid(String guid) {\r
+ for (int i=0; i<tagIndex.size(); i++) {\r
+ if (tagIndex.get(i).getGuid().equals(guid)) \r
+ return tagIndex.get(i).getName();\r
+ } \r
+ return "";\r
+ }\r
+\r
+ // Compare dates\r
+ public int dateCheck(String date, long noteDate) throws java.lang.NumberFormatException {\r
+ int offset = 0;\r
+ boolean found = false;\r
+ GregorianCalendar calendar = new GregorianCalendar();\r
+ \r
+ if (date.contains("-")) {\r
+ String modifier = date.substring(date.indexOf("-")+1);\r
+ offset = new Integer(modifier);\r
+ offset = 0-offset;\r
+ date = date.substring(0,date.indexOf("-"));\r
+ }\r
+ \r
+ if (date.contains("+")) {\r
+ String modifier = date.substring(date.indexOf("+")+1);\r
+ offset = new Integer(modifier);\r
+ date = date.substring(0,date.indexOf("+"));\r
+ }\r
+ \r
+ if (date.equalsIgnoreCase("today")) {\r
+ calendar.add(Calendar.DATE, offset);\r
+ calendar.set(Calendar.HOUR, 0);\r
+ calendar.set(Calendar.MINUTE, 0);\r
+ calendar.set(Calendar.SECOND, 1);\r
+ found = true;\r
+ }\r
+ \r
+ if (date.equalsIgnoreCase("month")) {\r
+ calendar.add(Calendar.MONTH, offset);\r
+ calendar.set(Calendar.DAY_OF_MONTH, 1);\r
+ calendar.set(Calendar.HOUR, 0);\r
+ calendar.set(Calendar.MINUTE, 0);\r
+ calendar.set(Calendar.SECOND, 1);\r
+ found = true;\r
+ }\r
+\r
+ if (date.equalsIgnoreCase("year")) {\r
+ calendar.add(Calendar.YEAR, offset);\r
+ calendar.set(Calendar.MONTH, Calendar.JANUARY);\r
+ calendar.set(Calendar.DAY_OF_MONTH, 1);\r
+ calendar.set(Calendar.HOUR, 0);\r
+ calendar.set(Calendar.MINUTE, 0);\r
+ calendar.set(Calendar.SECOND, 1);\r
+ found = true;\r
+ }\r
+\r
+ if (date.equalsIgnoreCase("week")) {\r
+ calendar.add(Calendar.DATE, 0-calendar.get(Calendar.DAY_OF_WEEK)+1);\r
+ calendar.add(Calendar.DATE,(offset*7));\r
+ calendar.set(Calendar.HOUR, 0);\r
+ calendar.set(Calendar.MINUTE, 0);\r
+ calendar.set(Calendar.SECOND, 1);\r
+\r
+ found = true;\r
+ }\r
+ \r
+ // If nothing was found, then we have a date number\r
+ if (!found) {\r
+ calendar = stringToGregorianCalendar(date);\r
+ }\r
+ \r
+ \r
+ String dateTimeFormat = new String("yyyyMMdd-HHmmss");\r
+ SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);\r
+ StringBuilder creationDate = new StringBuilder(simple.format(noteDate));\r
+ GregorianCalendar nCalendar = stringToGregorianCalendar(creationDate.toString().replace("-", "T"));\r
+ if (calendar == null || nCalendar == null) // If we have something invalid, it automatically fails\r
+ return 1;\r
+ return calendar.compareTo(nCalendar);\r
+ }\r
+ private GregorianCalendar stringToGregorianCalendar(String date) {\r
+ String datePart = date;\r
+ GregorianCalendar calendar = new GregorianCalendar();\r
+ boolean GMT = false;\r
+ String timePart = "";\r
+ if (date.contains("T")) {\r
+ datePart = date.substring(0,date.indexOf("T"));\r
+ timePart = date.substring(date.indexOf("T")+1);\r
+ } else {\r
+ timePart = "000001";\r
+ }\r
+ if (datePart.length() != 8)\r
+ return null;\r
+ calendar.set(Calendar.YEAR, new Integer(datePart.substring(0,4)));\r
+ calendar.set(Calendar.MONTH, new Integer(datePart.substring(4,6))-1);\r
+ calendar.set(Calendar.DAY_OF_MONTH, new Integer(datePart.substring(6)));\r
+ if (timePart.endsWith("Z")) {\r
+ GMT = true;\r
+ timePart = timePart.substring(0,timePart.length()-1);\r
+ }\r
+ timePart = timePart.concat("000000");\r
+ timePart = timePart.substring(0,6);\r
+ calendar.set(Calendar.HOUR, new Integer(timePart.substring(0,2)));\r
+ calendar.set(Calendar.MINUTE, new Integer(timePart.substring(2,4)));\r
+ calendar.set(Calendar.SECOND, new Integer(timePart.substring(4)));\r
+ if (GMT)\r
+ calendar.set(Calendar.ZONE_OFFSET, -1*(calendar.get(Calendar.ZONE_OFFSET)/(1000*60*60)));\r
+ return calendar;\r
+\r
+ }\r
+ \r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.sql.runners;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import cx.fbn.nevernote.sql.driver.NSqlQuery;\r
+import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+import cx.fbn.nevernote.utilities.ListManager;\r
+\r
+public class RInvalidXMLTable {\r
+ ListManager parent;\r
+ private final ApplicationLogger logger;\r
+ private final RDatabaseConnection db;\r
+\r
+ \r
+ // Constructor\r
+ public RInvalidXMLTable(ApplicationLogger l, RDatabaseConnection d) {\r
+ logger = l;\r
+ db = d;\r
+ }\r
+ // Create the table\r
+ public void createTable() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+// query.exec("drop table InvalidXML");\r
+ logger.log(logger.HIGH, "Creating table InvalidXML...");\r
+ if (!query.exec("Create table InvalidXML (type varchar, element varchar, attribute varchar,primary key(type, element,attribute) );"))\r
+ logger.log(logger.HIGH, "Table InvalidXML creation FAILED!!!"); \r
+// query.clear();\r
+ \r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ELEMENT', 'button', '');");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ELEMENT', 'embed', '');");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ELEMENT', 'fieldset', '');");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ELEMENT', 'form', '');");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ELEMENT', 'input', '');");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ELEMENT', 'label', '');");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ELEMENT', 'legend', '');");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ELEMENT', 'o:p', '')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ELEMENT', 'option', '')"); \r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ELEMENT', 'script', '')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ELEMENT', 'select', '')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ELEMENT', 'wbr', '')");\r
+ \r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'a', 'class')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'a', 'done')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'a', 'id')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'a', 'onclick')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'a', 'onmousedown')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'div', 'id')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'dl', 'class')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'dl', 'id')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'dt', 'class')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'h1', 'class')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'h2', 'class')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'h3', 'class')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'h4', 'class')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'h5', 'class')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'img', 'gptag')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'li', 'class')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'ol', 'class')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'ol', 'id')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'p', 'class')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'p', 'id')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'p', 'span')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'span', 'accesskey')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'span', 'action')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'span', 'alt')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'span', 'bgcolor')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'span', 'checked')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'span', 'class')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'span', 'flashvars')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'span', 'for')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'span', 'height')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'span', 'id')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'span', 'maxlength')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'span', 'method')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'span', 'name')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'span', 'onblur')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'span', 'onchange')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'span', 'aclick')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'span', 'onsubmit')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'span', 'quality')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'span', 'selected')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'span', 'src')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'span', 'target')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'span', 'type')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'span', 'value')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'span', 'width')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'span', 'wmode')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'table', 'class')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'td', 'class')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'tr', 'class')");\r
+ query.exec("Insert into InvalidXML (type, element, attribute) values ('ATTRIBUTE', 'ul', 'class')");\r
+\r
+ }\r
+ // Drop the table\r
+ public void dropTable() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.exec("Drop table InvalidXML");\r
+ }\r
+ // Add an item to the table\r
+ public void addAttribute(String element, String attribute) {\r
+ if (attributeExists(element,attribute))\r
+ return;\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("Insert Into InvalidXML (type, element, attribute) Values('ATTRIBUTE', :element, :attribute)");\r
+ query.bindValue(":element", element);\r
+ query.bindValue(":attribute", attribute);\r
+ if (!query.exec()) {\r
+ logger.log(logger.MEDIUM, "Insert Attribute into invalidXML failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ }\r
+ // Add an item to the table\r
+ public void addElement(String element) {\r
+ if (elementExists(element))\r
+ return;\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("Insert Into InvalidXML (type, element) Values('ELEMENT', :element)");\r
+ query.bindValue(":element", element);\r
+ if (!query.exec()) {\r
+ logger.log(logger.MEDIUM, "Insert Element into invalidXML failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ }\r
+ // get invalid elements\r
+ public List<String> getInvalidElements() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ if (!query.exec("Select element from InvalidXML where type = 'ELEMENT'")) {\r
+ logger.log(logger.MEDIUM, "getInvalidElement from invalidXML failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ return null;\r
+ }\r
+ List<String> elements = new ArrayList<String>();\r
+ while (query.next()) {\r
+ elements.add(query.valueString(0));\r
+ }\r
+ return elements;\r
+ }\r
+ \r
+ // get invalid elements\r
+ public List<String> getInvalidAttributeElements() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ if (!query.exec("Select distinct element from InvalidXML where type = 'ATTRIBUTE'")) {\r
+ logger.log(logger.MEDIUM, "getInvalidElement from invalidXML failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ return null;\r
+ }\r
+ List<String> elements = new ArrayList<String>();\r
+ while (query.next()) {\r
+ elements.add(query.valueString(0));\r
+ }\r
+ return elements;\r
+ }\r
+ // get invalid attributes for a given element\r
+ public ArrayList<String> getInvalidAttributes(String element) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("Select attribute from InvalidXML where type = 'ATTRIBUTE' and element = :element");\r
+ query.bindValue(":element", element);\r
+ if (!query.exec()) {\r
+ logger.log(logger.MEDIUM, "getInvalidElement from invalidXML failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ return null;\r
+ }\r
+ ArrayList<String> elements = new ArrayList<String>();\r
+ while (query.next()) {\r
+ elements.add(query.valueString(0));\r
+ }\r
+ return elements;\r
+ }\r
+\r
+ // Determine if an element already is in the table\r
+ public boolean elementExists(String element) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("Select element from InvalidXML where type='ELEMENT' and element=:element");\r
+ query.bindValue(":element", element);\r
+ if (!query.exec()) {\r
+ logger.log(logger.MEDIUM, "elementExists in invalidXML failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ if (query.next())\r
+ return true;\r
+ else\r
+ return false;\r
+ }\r
+ \r
+ // Determine if an element already is in the table\r
+ public boolean attributeExists(String element, String attribute) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("Select element from InvalidXML where type='ATTRIBUTE' and element=:element and attribute=:attribute");\r
+ query.bindValue(":element", element);\r
+ query.bindValue(":attribute", attribute);\r
+ if (!query.exec()) {\r
+ logger.log(logger.MEDIUM, "attributeExists in invalidXML failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ if (query.next())\r
+ return true;\r
+ else\r
+ return false;\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.sql.runners;\r
+import java.text.SimpleDateFormat;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.Data;\r
+import com.evernote.edam.type.Resource;\r
+import com.evernote.edam.type.ResourceAttributes;\r
+import com.trolltech.qt.core.QByteArray;\r
+\r
+import cx.fbn.nevernote.sql.driver.NSqlQuery;\r
+import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+\r
+\r
+\r
+public class RNoteResourceTable {\r
+ /**\r
+ * \r
+ */\r
+ private static final long serialVersionUID = 1L;\r
+ private final ApplicationLogger logger;\r
+ private final RDatabaseConnection db; \r
+ \r
+ // Constructor\r
+ public RNoteResourceTable(ApplicationLogger l, RDatabaseConnection d) {\r
+ logger = l;\r
+ db = d;\r
+ }\r
+ // Create the table\r
+ public void createTable() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ // Create the NoteResource table\r
+ logger.log(logger.HIGH, "Creating table NoteResource...");\r
+ if (!query.exec("Create table NoteResources (guid varchar primary key, " +\r
+ "noteGuid varchar, updateSequenceNumber integer, dataHash varchar, "+\r
+ "dataSize integer, dataBinary blob, "+\r
+ "mime varchar, width integer, height integer, duration integer, "+\r
+ "active integer, recognitionHash varchar, recognitionSize integer, " +\r
+ "recognitionBinary varchar, attributeSourceUrl varchar, attributeTimestamp timestamp, " +\r
+ "attributeLatitude double, attributeLongitude double, "+\r
+ "attributeAltitude double, attributeCameraMake varchar, attributeCameraModel varchar, "\r
+ +"attributeClientWillIndex varchar, attributeRecoType varchar, attributeFileName varchar,"+\r
+ "attributeAttachment boolean, isDirty boolean, indexNeeded boolean)"))\r
+ logger.log(logger.HIGH, "Table NoteResource creation FAILED!!!"); \r
+ if (!query.exec("CREATE INDEX unindexed_resources on noteresources (indexneeded desc, guid);"))\r
+ logger.log(logger.HIGH, "Noteresources unindexed_resources index creation FAILED!!!");\r
+ if (!query.exec("CREATE INDEX resources_dataheshhex on noteresources (datahash, guid);"))\r
+ logger.log(logger.HIGH, "Noteresources resources_datahash index creation FAILED!!!"); \r
+ \r
+ }\r
+ // Drop the table\r
+ public void dropTable() { \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.exec("Drop table NoteResources");\r
+ }\r
+ // Reset the dirty flag\r
+ public void resetDirtyFlag(String guid) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ query.prepare("Update noteresources set isdirty=false where guid=:guid");\r
+ query.bindValue(":guid", guid);\r
+ if (!query.exec())\r
+ logger.log(logger.EXTREME, "Error resetting noteresource dirty field. " +query.lastError());\r
+ }\r
+ // Set if the resource should be indexed\r
+ public void setIndexNeeded(String guid, Boolean indexNeeded) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection()); \r
+ query.prepare("Update noteresources set indexNeeded=:needed where guid=:guid");\r
+ query.bindValue(":needed", indexNeeded);\r
+ query.bindValue(":guid", guid);\r
+ if (!query.exec())\r
+ logger.log(logger.EXTREME, "Error setting noteresource indexneeded field: " +query.lastError());\r
+ }\r
+ // get any unindexed resource\r
+ public List<String> getNextUnindexed(int limit) {\r
+ List<String> guids = new ArrayList<String>();\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ if (!query.exec("Select guid from NoteResources where indexNeeded = true limit " +limit))\r
+ logger.log(logger.EXTREME, "NoteResources SQL retrieve has failed on getNextUnindexed(): " +query.lastError());\r
+\r
+ // Get a list of the notes\r
+ String guid;\r
+ while (query.next()) {\r
+ guid = new String();\r
+ guid = query.valueString(0);\r
+ guids.add(guid);\r
+ } \r
+ return guids; \r
+ }\r
+\r
+\r
+ \r
+ public void saveNoteResource(Resource r, boolean isDirty) {\r
+ logger.log(logger.HIGH, "Entering DBRunner.saveNoteResources");\r
+ boolean check;\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ SimpleDateFormat simple = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");\r
+ \r
+ check = query.prepare("Insert Into NoteResources ("\r
+ +"guid, noteGuid, dataHash, dataSize, dataBinary, updateSequenceNumber, "\r
+ +"mime, width, height, duration, active, recognitionHash, " \r
+ +"recognitionSize, recognitionBinary, attributeSourceUrl, attributeTimestamp, "\r
+ +"attributeLatitude, attributeLongitude, attributeAltitude, attributeCameraMake, "\r
+ +"attributeCameraModel, "\r
+ +"attributeClientWillIndex, attributeRecoType, attributeFileName, attributeAttachment, isDirty, "\r
+ +"indexNeeded) Values("\r
+ +":guid, :noteGuid, :dataHash,:dataSize, :dataBody, :updateSequenceNumber, "\r
+ +":mime, :width, :height, :duration, :active, :recognitionHash, " \r
+ +":recognitionSize, :recognitionBody, :attributeSourceUrl, :attributeTimestamp, "\r
+ +":attributeLatitude, :attributeLongitude, :attributeAltitude, :attributeCameraMake, "\r
+ +":attributeCameraModel, "\r
+ +":attributeClientWillIndex, :attributeRecoType, :attributeFileName, :attributeAttachment, "\r
+ +":isDirty, true)");\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "NoteResource SQL insert prepare has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ \r
+ query.bindValue(":guid", r.getGuid());\r
+ query.bindValue(":noteGuid", r.getNoteGuid());\r
+ if (r.getData() != null) {\r
+// query.bindValue(":dataHash", new QByteArray(r.getData().getBodyHash()).toHex());\r
+// query.bindValue(":dataHash", "");\r
+ query.bindValue(":dataHash", byteArrayToHexString(r.getData().getBodyHash()));\r
+ query.bindValue(":dataSize", r.getData().getSize());\r
+ query.bindBlob(":dataBody", r.getData().getBody());\r
+ }\r
+ query.bindValue(":updateSequenceNumber", r.getUpdateSequenceNum());\r
+ query.bindValue(":mime", r.getMime());\r
+ query.bindValue(":width", new Integer(r.getWidth()));\r
+ query.bindValue(":height", new Integer(r.getHeight()));\r
+ query.bindValue(":duration", new Integer(r.getDuration()));\r
+ query.bindValue(":active", r.isActive());\r
+ if (r.getRecognition() != null) {\r
+ query.bindValue(":recognitionHash", r.getRecognition().getBodyHash());\r
+ query.bindValue(":recognitionSize", r.getRecognition().getSize());\r
+ if (r.getRecognition().getBody() != null)\r
+ query.bindValue(":recognitionBody", new String(r.getRecognition().getBody()));\r
+ else\r
+ query.bindValue(":recognitionBody", "");\r
+ } else {\r
+ query.bindValue(":recognitionHash", "");\r
+ query.bindValue(":recognitionSize", 0);\r
+ query.bindValue(":recognitionBody", "");\r
+ }\r
+ if (r.getAttributes() != null) {\r
+ query.bindValue(":attributeSourceUrl", r.getAttributes().getSourceURL());\r
+ StringBuilder ts = new StringBuilder(simple.format(r.getAttributes().getTimestamp()));\r
+ query.bindValue(":attributeTimestamp", ts.toString());\r
+ query.bindValue(":attributeLatitude", r.getAttributes().getLatitude());\r
+ query.bindValue(":attributeLongitude", r.getAttributes().getLongitude());\r
+ query.bindValue(":attributeAltitude", r.getAttributes().getAltitude());\r
+ query.bindValue(":attributeCameraMake", r.getAttributes().getCameraMake());\r
+ query.bindValue(":attributeCameraModel", r.getAttributes().getCameraModel());\r
+ query.bindValue(":attributeClientWillIndex", r.getAttributes().isClientWillIndex());\r
+ query.bindValue(":attributeRecoType", r.getAttributes().getRecoType());\r
+ query.bindValue(":attributeFileName", r.getAttributes().getFileName());\r
+ query.bindValue(":attributeAttachment", r.getAttributes().isAttachment()); \r
+ }\r
+ query.bindValue(":isDirty", isDirty);\r
+ \r
+ check = query.exec();\r
+ if (!check) {\r
+ logger.log(logger.MEDIUM, "*** NoteResource Table insert failed."); \r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ \r
+ \r
+ logger.log(logger.HIGH, "Leaving DBRunner.saveNoteResources");\r
+ }\r
+ // delete an old resource\r
+ public void expungeNoteResource(String guid) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("delete from NoteResources where guid=:guid");\r
+ query.bindValue(":guid", guid);\r
+ query.exec();\r
+ }\r
+\r
+ \r
+ // Get a note resource from the database by it's hash value\r
+ public String getNoteResourceGuidByHashHex(String noteGuid, String hash) {\r
+ logger.log(logger.HIGH, "Entering DBRunner.getNoteResourceGuidByHashHex");\r
+\r
+ boolean check;\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ check = query.prepare("Select guid from NoteResources " +\r
+ "where noteGuid=:noteGuid and dataHash=:hash");\r
+ if (check)\r
+ logger.log(logger.EXTREME, "NoteResource SQL select prepare was successful.");\r
+ else {\r
+ logger.log(logger.EXTREME, "NoteResource SQL select prepare has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ query.bindValue(":noteGuid", noteGuid);\r
+ query.bindValue(":hash", hash);\r
+ \r
+ check = query.exec();\r
+ if (!check) {\r
+ logger.log(logger.MEDIUM, "dbRunner.getNoteResourceGuidByHashHex Select failed." +\r
+ "Note Guid:" +noteGuid+\r
+ "Data Body Hash:" +hash); \r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ if (!query.next()) {\r
+ logger.log(logger.MEDIUM, "Note Resource not found.");\r
+ return null;\r
+ }\r
+ return query.valueString(0);\r
+ }\r
+\r
+ // Get a note resource from the database by it's hash value\r
+ public Resource getNoteResourceDataBodyByHashHex(String noteGuid, String hash) {\r
+ logger.log(logger.HIGH, "Entering DBRunner.getNoteResourceDataBodyByHash");\r
+\r
+ boolean check;\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ check = query.prepare("Select guid, mime, from NoteResources " +\r
+ "where noteGuid=:noteGuid and dataHash=:hash");\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "NoteResource SQL select prepare has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ query.bindValue(":noteGuid", noteGuid);\r
+ query.bindValue(":hash", hash);\r
+ \r
+ if (!query.exec()) {\r
+ logger.log(logger.MEDIUM, "NoteResource Select failed." +\r
+ "Note Guid:" +noteGuid+\r
+ "Data Body Hash:" +hash); \r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ if (!query.next()) {\r
+ logger.log(logger.MEDIUM, "Note Resource not found.");\r
+ return null;\r
+ }\r
+ \r
+ Resource r = new Resource();\r
+ r.setGuid(query.valueString(0));\r
+ r.setMime(query.valueString(1));\r
+ \r
+ NSqlQuery binary = new NSqlQuery(db.getConnection());\r
+ if (!binary.prepare("Select databinary from NoteResources " +\r
+ "where guid=:guid")) {\r
+ logger.log(logger.MEDIUM, "Prepare for NoteResources Binary failed");\r
+ logger.log(logger.MEDIUM, binary.lastError());\r
+ }\r
+ \r
+ if (!binary.exec()) {\r
+ logger.log(logger.MEDIUM, "NoteResources Binary Select failed." +\r
+ "Note Guid:" +noteGuid+\r
+ "Data Body Hash:" +hash); \r
+ logger.log(logger.MEDIUM, binary.lastError());\r
+ }\r
+ if (!binary.next()) {\r
+ logger.log(logger.MEDIUM, "Note Resource Binary not found.");\r
+ return null;\r
+ }\r
+ \r
+ Data d = new Data();\r
+ r.setData(d);\r
+ d.setBody(binary.valueString(0).getBytes());\r
+ logger.log(logger.HIGH, "Leaving DBRunner.getNoteResourceDataBodyByHash");\r
+ return r;\r
+ }\r
+\r
+ \r
+ // Get a note's resourcesby Guid\r
+ public Resource getNoteResource(String guid, boolean withBinary) {\r
+ if (guid == null)\r
+ return null;\r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ String queryString;\r
+ queryString = new String("Select guid, noteGuid, mime, width, height, duration, "\r
+ +"active, updateSequenceNumber, dataHash, dataSize, "\r
+ +"recognitionHash, recognitionSize, "\r
+ +"attributeLatitude, attributeLongitude, attributeAltitude, "\r
+ +"attributeCameraMake, attributeCameraModel, attributeClientWillIndex, "\r
+ +"attributeRecoType, attributeFileName, attributeAttachment, recognitionBinary "\r
+ +" from NoteResources where guid=:guid");\r
+\r
+ \r
+ query.prepare(queryString);\r
+ \r
+ query.bindValue(":guid", guid);\r
+ if (!query.exec()) {\r
+ logger.log(logger.EXTREME, "NoteResources SQL select has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ return null;\r
+ }\r
+ Resource r = null;\r
+ if (query.next()) {\r
+ \r
+ r = new Resource();\r
+ r.setGuid(query.valueString(0)); // Resource Guid\r
+ r.setNoteGuid(query.valueString(1)); // note Guid\r
+ r.setMime(query.valueString(2)); // Mime Type\r
+ r.setWidth(new Short(query.valueString(3))); // Width\r
+ r.setHeight(new Short(query.valueString(4))); // Height\r
+ r.setDuration(new Short(query.valueString(5))); // Duration\r
+ r.setActive(new Boolean(query.valueString(6))); // active\r
+ r.setUpdateSequenceNum(new Integer(query.valueString(7))); // update sequence number\r
+ \r
+ Data d = new Data();\r
+ byte[] h = query.valueString(8).getBytes(); // data hash\r
+ QByteArray hData = new QByteArray(h);\r
+ QByteArray bData = new QByteArray(QByteArray.fromHex(hData));\r
+ d.setBodyHash(bData.toByteArray());\r
+ d.setSize(new Integer(query.valueString(9)));\r
+ r.setData(d);\r
+ \r
+ Data rec = new Data();\r
+ if (query.valueObject(10) != null)\r
+ rec.setBodyHash(query.valueString(10).getBytes()); // Recognition Hash\r
+ if (query.valueObject(11) != null)\r
+ rec.setSize(new Integer(query.valueString(11)));\r
+ else\r
+ rec.setSize(0);\r
+ r.setRecognition(rec);\r
+\r
+ ResourceAttributes a = new ResourceAttributes();\r
+ if (!query.valueString(12).equals("")) // Latitude\r
+ a.setLatitude(new Float(query.valueString(12)));\r
+ if (!query.valueString(13).equals("")) // Longitude\r
+ a.setLongitude(new Float(query.valueString(13)));\r
+ if (!query.valueString(14).equals("")) // Altitude\r
+ a.setAltitude(new Float(query.valueString(14)));\r
+ a.setCameraMake(stringValue(query.valueString(15))); // Camera Make\r
+ a.setCameraModel(stringValue(query.valueString(16)));\r
+ a.setClientWillIndex(booleanValue(query.valueString(17).toString(),false)); // Camera Model\r
+ a.setRecoType(stringValue(query.valueString(18))); // Recognition Type\r
+ a.setFileName(stringValue(query.valueString(19))); // File Name\r
+ a.setAttachment(booleanValue(query.valueString(20).toString(),false));\r
+ r.setAttributes(a);\r
+ \r
+ if (withBinary) {\r
+ \r
+ query.prepare("Select dataBinary from NoteResources where guid=:guid");\r
+ query.bindValue(":guid", r.getGuid());\r
+ query.exec();\r
+ if (query.next()) {\r
+ byte[] b = query.getBlob(0);\r
+ r.getData().setBody(b);\r
+ }\r
+ } \r
+ }\r
+ return r;\r
+ }\r
+ \r
+ \r
+ // Get a note's resourcesby Guid\r
+ public List<Resource> getNoteResources(String noteGuid, boolean withBinary) {\r
+ if (noteGuid == null)\r
+ return null;\r
+ List<Resource> res = new ArrayList<Resource>();\r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("Select guid"\r
+ +" from NoteResources where noteGuid = :noteGuid");\r
+ query.bindValue(":noteGuid", noteGuid);\r
+ if (!query.exec()) {\r
+ logger.log(logger.EXTREME, "NoteResources SQL select has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ return null;\r
+ }\r
+ while (query.next()) {\r
+ String guid = (query.valueString(0));\r
+ res.add(getNoteResource(guid, withBinary));\r
+ } \r
+ return res;\r
+ }\r
+ // Get all of a note's recognition data by the note guid\r
+ public List<Resource> getNoteResourcesRecognition(String noteGuid) {\r
+ if (noteGuid == null)\r
+ return null;\r
+ boolean check;\r
+ List<Resource> res = new ArrayList<Resource>();\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ check = query.prepare("Select "\r
+ +"recognitionHash, recognitionSize, recognitionBinary "\r
+ +" from NoteResources where noteGuid=:guid");\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "NoteTable.getNoteRecognition SQL prepare has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ return null;\r
+ }\r
+ query.bindValue(":guid", noteGuid);\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "NoteTable.getNoteRecognition exec has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ return null;\r
+ }\r
+ while (query.next()) { \r
+ Resource r = new Resource(); \r
+ res.add(r);\r
+ Data rec = new Data();\r
+ rec.setBodyHash(query.valueString(0).getBytes());\r
+ String x = new String(query.valueString(1));\r
+ if (!x.equals("")) {\r
+ rec.setSize(new Integer(x));\r
+ rec.setBody(query.valueString(2).getBytes());\r
+ } else\r
+ rec.setSize(0);\r
+ r.setRecognition(rec);\r
+ } \r
+ return res;\r
+ }\r
+ \r
+ \r
+ // Get a note's recognition data by it's guid.\r
+ public Resource getNoteResourceRecognition(String guid) {\r
+ if (guid == null)\r
+ return null;\r
+ boolean check;\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ check = query.prepare("Select "\r
+ +"recognitionHash, recognitionSize, recognitionBinary, noteGuid "\r
+ +" from NoteResources where guid=:guid");\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "NoteTable.getNoteRecognition SQL prepare has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ return null;\r
+ }\r
+ query.bindValue(":guid", guid);\r
+ query.exec();\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "NoteTable.getNoteRecognition exec has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ return null;\r
+ }\r
+ Resource r = null;\r
+ while (query.next()) {\r
+ \r
+ r = new Resource(); \r
+ Data rec = new Data();\r
+ rec.setBodyHash(query.valueString(0).getBytes());\r
+ String x = new String(query.valueString(1));\r
+ if (!x.equals("")) {\r
+ rec.setSize(new Integer(x));\r
+ rec.setBody(query.valueString(2).getBytes());\r
+ } else\r
+ rec.setSize(0);\r
+ r.setRecognition(rec);\r
+ r.setNoteGuid(query.valueString(3));\r
+ } \r
+ return r;\r
+ }\r
+\r
+ // Save Note Resource\r
+ public void updateNoteResource(Resource r, boolean isDirty) {\r
+ logger.log(logger.HIGH, "Entering ListManager.updateNoteResource");\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("delete from NoteResources where guid=:recGuid");\r
+ query.bindValue(":recGuid", r.getGuid());\r
+ query.exec();\r
+ saveNoteResource(r, isDirty);\r
+ logger.log(logger.HIGH, "Leaving RNoteResourceTable.updateNoteResource");\r
+ }\r
+ // Update note resource GUID\r
+ public void updateNoteResourceGuid(String oldGuid, String newGuid, boolean isDirty) {\r
+ logger.log(logger.HIGH, "Entering RNoteResourceTable.updateNoteResourceGuid");\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("update NoteResources set guid=:newGuid, isDirty=:isDirty where guid=:oldGuid");\r
+ query.bindValue(":newGuid", newGuid);\r
+ query.bindValue(":isDirty", isDirty);\r
+ query.bindValue(":oldGuid", oldGuid);\r
+ query.exec();\r
+ logger.log(logger.HIGH, "Leaving RNoteResourceTable.updateNoteResourceGuid");\r
+ }\r
+ // Update note resource GUID\r
+ public void resetUpdateSequenceNumber(String guid, boolean isDirty) {\r
+ logger.log(logger.HIGH, "Entering RNoteResourceTable.updateNoteResourceGuid");\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("update NoteResources set updateSequenceNumber=0, isDirty=:isDirty where guid=:guid");\r
+ query.bindValue(":isDirty", isDirty);\r
+ query.bindValue(":guid", guid);\r
+ query.exec();\r
+ logger.log(logger.HIGH, "Leaving RNoteResourceTable.updateNoteResourceGuid");\r
+ }\r
+ \r
+ // Drop the table\r
+ public void reindexAll() { \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.exec("Update NoteResources set indexneeded=true");\r
+ }\r
+ // Count unindexed notes\r
+ public int getResourceCount() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.exec("select count(*) from noteresources");\r
+ query.next(); \r
+ int returnValue = new Integer(query.valueString(0));\r
+ return returnValue;\r
+ }\r
+\r
+ //********************************************\r
+ //** Utility Functions\r
+ //********************************************\r
+ // Convert a byte array to a hex string\r
+ private static String byteArrayToHexString(byte data[]) {\r
+ StringBuffer buf = new StringBuffer();\r
+ for (byte element : data) {\r
+ int halfbyte = (element >>> 4) & 0x0F;\r
+ int two_halfs = 0;\r
+ do {\r
+ if ((0 <= halfbyte) && (halfbyte <= 9))\r
+ buf.append((char) ('0' + halfbyte));\r
+ else\r
+ buf.append((char) ('a' + (halfbyte - 10)));\r
+ halfbyte = element & 0x0F;\r
+ } while(two_halfs++ < 1);\r
+ }\r
+ return buf.toString(); \r
+ }\r
+\r
+ \r
+ private String stringValue(Object value) {\r
+ if (value != null && value.toString() != null) \r
+ return value.toString();\r
+ else\r
+ return null;\r
+ }\r
+ \r
+ private boolean booleanValue(Object value, boolean unknown) {\r
+ if (value != null && value.toString() != null) {\r
+ try {\r
+ if ((Integer)value > 0)\r
+ return true;\r
+ else\r
+ return false;\r
+ } catch (java.lang.ClassCastException e) {\r
+ try {\r
+ String stringValue = (String)value;\r
+ if (stringValue.equalsIgnoreCase("true"))\r
+ return true;\r
+ else \r
+ return false;\r
+ } catch (java.lang.ClassCastException e1) { \r
+ return unknown;\r
+ }\r
+ }\r
+ }\r
+ else\r
+ return unknown;\r
+ }\r
+\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.sql.runners;\r
+\r
+import java.text.DateFormat;\r
+import java.text.ParseException;\r
+import java.text.SimpleDateFormat;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.Note;\r
+import com.evernote.edam.type.NoteAttributes;\r
+import com.evernote.edam.type.Resource;\r
+import com.evernote.edam.type.Tag;\r
+import com.trolltech.qt.core.QByteArray;\r
+import com.trolltech.qt.core.QDateTime;\r
+import com.trolltech.qt.core.QTextCodec;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.evernote.EnmlConverter;\r
+import cx.fbn.nevernote.sql.driver.NSqlQuery;\r
+import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+import cx.fbn.nevernote.utilities.Pair;\r
+\r
+public class RNoteTable {\r
+ private final ApplicationLogger logger;\r
+ public final RNoteTagsTable noteTagsTable;\r
+ public RNoteResourceTable noteResourceTable;\r
+ private final RDatabaseConnection db;\r
+ int id;\r
+\r
+ // Prepared Queries to improve speed\r
+ private NSqlQuery getQueryWithContent;\r
+ private NSqlQuery getQueryWithoutContent;\r
+ private NSqlQuery getAllQueryWithoutContent;\r
+ \r
+ // Constructor\r
+ public RNoteTable(ApplicationLogger l, RDatabaseConnection d) {\r
+ logger = l;\r
+ db = d;\r
+ id = 0;\r
+ noteResourceTable = new RNoteResourceTable(logger, db);\r
+ noteTagsTable = new RNoteTagsTable(logger, db);\r
+ getQueryWithContent = null;\r
+ getQueryWithoutContent = null;\r
+ \r
+ }\r
+ // Create the table\r
+ public void createTable() {\r
+ getQueryWithContent = new NSqlQuery(db.getConnection());\r
+ getQueryWithoutContent = new NSqlQuery(db.getConnection());\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ logger.log(logger.HIGH, "Creating table Note...");\r
+ if (!query.exec("Create table Note (guid varchar primary key, " +\r
+ "updateSequenceNumber integer, title varchar, content varchar, contentHash varchar, "+\r
+ "contentLength integer, created timestamp, updated timestamp, deleted timestamp, " \r
+ +"active integer, notebookGuid varchar, attributeSubjectDate timestamp, "+\r
+ "attributeLatitude double, attributeLongitude double, attributeAltitude double,"+\r
+ "attributeAuthor varchar, attributeSource varchar, attributeSourceUrl varchar, "+\r
+ "attributeSourceApplication varchar, indexNeeded boolean, isExpunged boolean, " +\r
+ "isDirty boolean)")) \r
+ logger.log(logger.HIGH, "Table Note creation FAILED!!!"); \r
+ if (!query.exec("CREATE INDEX unindexed_notess on note (indexneeded desc, guid);"))\r
+ logger.log(logger.HIGH, "Note unindexed_notes index creation FAILED!!!");\r
+ if (!query.exec("CREATE INDEX unsynchronized_notes on note (isDirty desc, guid);"))\r
+ logger.log(logger.HIGH, "note unsynchronized_notes index creation FAILED!!!"); \r
+ noteTagsTable.createTable();\r
+ noteResourceTable.createTable(); \r
+ }\r
+ // Drop the table\r
+ public void dropTable() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.exec("Drop table Note");\r
+ noteTagsTable.dropTable();\r
+ noteResourceTable.dropTable();\r
+ }\r
+ // Save Note List from Evernote \r
+ public void addNote(Note n, boolean isDirty) {\r
+ logger.log(logger.EXTREME, "Inside addNote");\r
+ if (n == null)\r
+ return;\r
+ \r
+ SimpleDateFormat simple = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");\r
+\r
+ NSqlQuery query = new NSqlQuery(db.getConnection()); \r
+ query.prepare("Insert Into Note ("\r
+ +"guid, updateSequenceNumber, title, content, "\r
+ +"contentHash, contentLength, created, updated, deleted, active, notebookGuid, "\r
+ +"attributeSubjectDate, attributeLatitude, attributeLongitude, attributeAltitude, "\r
+ +"attributeAuthor, attributeSource, attributeSourceUrl, attributeSourceApplication, "\r
+ +"indexNeeded, isExpunged, isDirty, titlecolor, thumbnailneeded" \r
+ +") Values("\r
+ +":guid, :updateSequenceNumber, :title, :content, "\r
+ +":contentHash, :contentLength, :created, :updated, :deleted, :active, :notebookGuid, "\r
+ +":attributeSubjectDate, :attributeLatitude, :attributeLongitude, :attributeAltitude, "\r
+ +":attributeAuthor, :attributeSource, :attributeSourceUrl, :attributeSourceApplication, "\r
+ +":indexNeeded, :isExpunged, :isDirty, -1, true) ");\r
+\r
+ StringBuilder created = new StringBuilder(simple.format(n.getCreated())); \r
+ StringBuilder updated = new StringBuilder(simple.format(n.getUpdated())); \r
+ StringBuilder deleted = new StringBuilder(simple.format(n.getDeleted()));\r
+\r
+ EnmlConverter enml = new EnmlConverter(logger);\r
+ \r
+ query.bindValue(":guid", n.getGuid());\r
+ query.bindValue(":updateSequenceNumber", n.getUpdateSequenceNum());\r
+ query.bindValue(":title", n.getTitle());\r
+ query.bindValue(":content", enml.fixEnXMLCrap(enml.fixEnMediaCrap(n.getContent())));\r
+ query.bindValue(":contentHash", n.getContentHash());\r
+ query.bindValue(":contentLength", n.getContentLength());\r
+ query.bindValue(":created", created.toString());\r
+ query.bindValue(":updated", updated.toString());\r
+ query.bindValue(":deleted", deleted.toString());\r
+ query.bindValue(":active", n.isActive());\r
+ query.bindValue(":notebookGuid", n.getNotebookGuid());\r
+ \r
+ if (n.getAttributes() != null) {\r
+ created = new StringBuilder(simple.format(n.getAttributes().getSubjectDate()));\r
+ query.bindValue(":attributeSubjectDate", created.toString());\r
+ query.bindValue(":attributeLatitude", n.getAttributes().getLatitude());\r
+ query.bindValue(":attributeLongitude", n.getAttributes().getLongitude());\r
+ query.bindValue(":attributeAltitude", n.getAttributes().getAltitude());\r
+ query.bindValue(":attributeAuthor", n.getAttributes().getAuthor());\r
+ query.bindValue(":attributeSource", n.getAttributes().getSource());\r
+ query.bindValue(":attributeSourceUrl", n.getAttributes().getSourceURL());\r
+ query.bindValue(":attributeSourceApplication", n.getAttributes().getSourceApplication());\r
+ }\r
+ query.bindValue(":indexNeeded", true);\r
+ query.bindValue(":isExpunged", false);\r
+ query.bindValue(":isDirty", isDirty);\r
+\r
+ \r
+ if (!query.exec())\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ \r
+ // Save the note tags\r
+ if (n.getTagGuids() != null) {\r
+ for (int i=0; i<n.getTagGuids().size(); i++) \r
+ noteTagsTable.saveNoteTag(n.getGuid(), n.getTagGuids().get(i));\r
+ }\r
+ logger.log(logger.EXTREME, "Leaving addNote");\r
+ } \r
+ // Setup queries for get to save time later\r
+ private void prepareQueries() {\r
+ getQueryWithContent = new NSqlQuery(db.getConnection());\r
+ getQueryWithoutContent = new NSqlQuery(db.getConnection());\r
+ getAllQueryWithoutContent = new NSqlQuery(db.getConnection());\r
+ \r
+ if (!getQueryWithContent.prepare("Select "\r
+ +"guid, updateSequenceNumber, title, "\r
+ +"created, updated, deleted, active, notebookGuid, "\r
+ +"attributeSubjectDate, attributeLatitude, attributeLongitude, attributeAltitude, "\r
+ +"attributeAuthor, attributeSource, attributeSourceUrl, attributeSourceApplication, "\r
+ +"content, contentHash, contentLength"\r
+ +" from Note where guid=:guid and isExpunged=false")) {\r
+ logger.log(logger.EXTREME, "Note SQL select prepare with content has failed.");\r
+ logger.log(logger.MEDIUM, getQueryWithContent.lastError());\r
+ }\r
+ \r
+ if (!getQueryWithoutContent.prepare("Select "\r
+ +"guid, updateSequenceNumber, title, "\r
+ +"created, updated, deleted, active, notebookGuid, "\r
+ +"attributeSubjectDate, attributeLatitude, attributeLongitude, attributeAltitude, "\r
+ +"attributeAuthor, attributeSource, attributeSourceUrl, attributeSourceApplication "\r
+ +" from Note where guid=:guid and isExpunged=false")) {\r
+ logger.log(logger.EXTREME, "Note SQL select prepare without content has failed.");\r
+ logger.log(logger.MEDIUM, getQueryWithoutContent.lastError());\r
+ }\r
+ if (!getAllQueryWithoutContent.prepare("Select "\r
+ +"guid, updateSequenceNumber, title, "\r
+ +"created, updated, deleted, active, notebookGuid, "\r
+ +"attributeSubjectDate, attributeLatitude, attributeLongitude, attributeAltitude, "\r
+ +"attributeAuthor, attributeSource, attributeSourceUrl, attributeSourceApplication "\r
+ +" from Note where isExpunged = false")) {\r
+ logger.log(logger.EXTREME, "Note SQL select prepare without content has failed.");\r
+ logger.log(logger.MEDIUM, getQueryWithoutContent.lastError());\r
+ }\r
+ }\r
+\r
+ // Get a note's content in raw, binary format for the sync.\r
+ public String getNoteContentBinary(String guid) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("Select content from note where guid=:guid");\r
+ query.bindValue(":guid", guid);\r
+ query.exec();\r
+ \r
+ query.next();\r
+ return query.valueString(0);\r
+ }\r
+ // Get a note by Guid\r
+ public Note getNote(String noteGuid, boolean loadContent, boolean loadResources, boolean loadRecognition, boolean loadBinary, boolean loadTags) {\r
+ if (noteGuid == null)\r
+ return null;\r
+ if (noteGuid.trim().equals(""))\r
+ return null;\r
+\r
+ prepareQueries();\r
+ NSqlQuery query;\r
+ if (loadContent) {\r
+ query = getQueryWithContent;\r
+ } else {\r
+ query = getQueryWithoutContent;\r
+ }\r
+ \r
+ query.bindValue(":guid", noteGuid);\r
+ if (!query.exec()) {\r
+ logger.log(logger.EXTREME, "Note SQL select exec has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ return null;\r
+ }\r
+ if (!query.next()) {\r
+ logger.log(logger.EXTREME, "SQL Retrieve failed for note guid " +noteGuid + " in getNote()");\r
+ logger.log(logger.EXTREME, " -> " +query.lastError().toString());\r
+ logger.log(logger.EXTREME, " -> " +query.lastError());\r
+ return null;\r
+ }\r
+ Note n = mapNoteFromQuery(query, loadContent, loadResources, loadRecognition, loadBinary, loadTags);\r
+ n.setContent(fixCarriageReturn(n.getContent()));\r
+ return n;\r
+ }\r
+ // Get a note by Guid\r
+ public Note mapNoteFromQuery(NSqlQuery query, boolean loadContent, boolean loadResources, boolean loadRecognition, boolean loadBinary, boolean loadTags) {\r
+ DateFormat indfm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");\r
+// indfm = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy");\r
+\r
+ \r
+ Note n = new Note();\r
+ NoteAttributes na = new NoteAttributes();\r
+ n.setAttributes(na);\r
+ \r
+ n.setGuid(query.valueString(0));\r
+ n.setUpdateSequenceNum(new Integer(query.valueString(1)));\r
+ n.setTitle(query.valueString(2));\r
+\r
+ try {\r
+ n.setCreated(indfm.parse(query.valueString(3)).getTime());\r
+ n.setUpdated(indfm.parse(query.valueString(4)).getTime());\r
+ n.setDeleted(indfm.parse(query.valueString(5)).getTime());\r
+ } catch (ParseException e) {\r
+ e.printStackTrace();\r
+ }\r
+\r
+ n.setActive(query.valueBoolean(6,true));\r
+ n.setNotebookGuid(query.valueString(7));\r
+ \r
+ try {\r
+ String attributeSubjectDate = query.valueString(8);\r
+ if (!attributeSubjectDate.equals(""))\r
+ na.setSubjectDate(indfm.parse(attributeSubjectDate).getTime());\r
+ } catch (ParseException e) {\r
+ e.printStackTrace();\r
+ }\r
+ na.setLatitude(new Float(query.valueString(9)));\r
+ na.setLongitude(new Float(query.valueString(10)));\r
+ na.setAltitude(new Float(query.valueString(11)));\r
+ na.setAuthor(query.valueString(12));\r
+ na.setSource(query.valueString(13));\r
+ na.setSourceURL(query.valueString(14));\r
+ na.setSourceApplication(query.valueString(15));\r
+ \r
+ if (loadTags) {\r
+ n.setTagGuids(noteTagsTable.getNoteTags(n.getGuid()));\r
+ List<String> tagNames = new ArrayList<String>();\r
+ RTagTable tagTable = new RTagTable(logger, db);\r
+ for (int i=0; i<n.getTagGuids().size(); i++) {\r
+ String currentGuid = n.getTagGuids().get(i);\r
+ Tag tag = tagTable.getTag(currentGuid);\r
+ tagNames.add(tag.getName());\r
+ }\r
+ n.setTagNames(tagNames);\r
+ }\r
+ \r
+ if (loadContent) {\r
+ \r
+ QTextCodec codec = QTextCodec.codecForLocale();\r
+ codec = QTextCodec.codecForName("UTF-8");\r
+ String unicode = codec.fromUnicode(query.valueString(16)).toString();\r
+ n.setContent(unicode);\r
+// n.setContent(query.valueString(16).toString());\r
+ \r
+ String contentHash = query.valueString(17);\r
+ if (contentHash != null)\r
+ n.setContentHash(contentHash.getBytes());\r
+ n.setContentLength(new Integer(query.valueString(18)));\r
+ }\r
+ if (loadResources)\r
+ n.setResources(noteResourceTable.getNoteResources(n.getGuid(), loadBinary));\r
+ if (loadRecognition) {\r
+ if (n.getResources() == null) {\r
+ List<Resource> resources = noteResourceTable.getNoteResourcesRecognition(n.getGuid());\r
+ n.setResources(resources);\r
+ } else {\r
+ // We need to merge the recognition resources with the note resources retrieved earlier\r
+ for (int i=0; i<n.getResources().size(); i++) {\r
+ Resource r = noteResourceTable.getNoteResourceRecognition(n.getResources().get(i).getGuid());\r
+ n.getResources().get(i).setRecognition(r.getRecognition());\r
+ }\r
+ }\r
+ }\r
+ n.setContent(fixCarriageReturn(n.getContent()));\r
+ return n;\r
+ }\r
+ // Update a note's title\r
+ public void updateNoteTitle(String guid, String title) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ boolean check = query.prepare("Update Note set title=:title, isDirty=true where guid=:guid");\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "Update note title sql prepare has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ query.bindValue(":title", title);\r
+ query.bindValue(":guid", guid);\r
+ check = query.exec();\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "Update note title has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ }\r
+ // Update a note's creation date\r
+ public void updateNoteCreatedDate(String guid, QDateTime date) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ boolean check = query.prepare("Update Note set created=:created, isDirty=true where guid=:guid");\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "Update note creation update sql prepare has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ \r
+ query.bindValue(":created", date.toString("yyyy-MM-dd HH:mm:ss"));\r
+ query.bindValue(":guid", guid);\r
+ \r
+ check = query.exec();\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "Update note creation date has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ }\r
+ // Update a note's creation date\r
+ public void updateNoteAlteredDate(String guid, QDateTime date) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ boolean check = query.prepare("Update Note set updated=:altered, isDirty=true where guid=:guid");\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "Update note altered sql prepare has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ \r
+ query.bindValue(":altered", date.toString("yyyy-MM-dd HH:mm:ss"));\r
+ query.bindValue(":guid", guid);\r
+ \r
+ check = query.exec();\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "Update note altered date has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ }\r
+ // Update a note's creation date\r
+ public void updateNoteSubjectDate(String guid, QDateTime date) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ boolean check = query.prepare("Update Note set attributeSubjectDate=:altered, isDirty=true where guid=:guid");\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "Update note subject date sql prepare has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ \r
+ query.bindValue(":altered", date.toString("yyyy-MM-dd HH:mm:ss"));\r
+ query.bindValue(":guid", guid);\r
+ \r
+ check = query.exec();\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "Update note subject date date has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ }\r
+ // Update a note's creation date\r
+ public void updateNoteAuthor(String guid, String author) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ boolean check = query.prepare("Update Note set attributeAuthor=:author, isDirty=true where guid=:guid");\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "Update note author sql prepare has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+\r
+ query.bindValue(":author", author);\r
+ query.bindValue(":guid", guid);\r
+\r
+ check = query.exec();\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "Update note author has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ \r
+ }\r
+ // Update a note's creation date\r
+ public void updateNoteSourceUrl(String guid, String url) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ boolean check = query.prepare("Update Note set attributeSourceUrl=:url, isDirty=true where guid=:guid");\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "Update note url sql prepare has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ \r
+ query.bindValue(":url", url);\r
+ query.bindValue(":guid", guid);\r
+\r
+ check = query.exec();\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "Update note url has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ \r
+ }\r
+ // Update the notebook that a note is assigned to\r
+ public void updateNoteNotebook(String guid, String notebookGuid, boolean expungeFromRemote) {\r
+ String currentNotebookGuid = new String("");\r
+ \r
+ \r
+ // If we are going from a synchronized notebook to a local notebook, we\r
+ // need to tell Evernote to purge the note online. However, if this is \r
+ // conflicting change we move it to the local notebook without deleting it \r
+ // or it would then delete the copy on the remote server.\r
+ RNotebookTable notebookTable = new RNotebookTable(logger, db);\r
+ RDeletedTable deletedTable = new RDeletedTable(logger, db);\r
+ if (expungeFromRemote) {\r
+ if (!notebookTable.isNotebookLocal(currentNotebookGuid) & notebookTable.isNotebookLocal(notebookGuid)) {\r
+ deletedTable.addDeletedItem(guid, "NOTE");\r
+ }\r
+ }\r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ boolean check = query.prepare("Update Note set notebookGuid=:notebook, isDirty=true where guid=:guid");\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "Update note notebook sql prepare has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ query.bindValue(":notebook", notebookGuid);\r
+ query.bindValue(":guid", guid);\r
+ \r
+ check = query.exec();\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "Update note notebook has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ };\r
+ }\r
+ // Update a note's title\r
+ public void updateNoteContent(String guid, String content) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ boolean check = query.prepare("Update Note set content=:content, updated=CURRENT_TIMESTAMP(), isDirty=true, indexNeeded=true " +\r
+ " where guid=:guid");\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "Update note content sql prepare has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ \r
+ query.bindValue(":content", content);\r
+ query.bindValue(":guid", guid);\r
+\r
+ check = query.exec();\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "Update note content has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ }\r
+\r
+ \r
+ // Check a note to see if it passes the attribute selection criteria\r
+ public boolean checkAttributeSelection(Note n) {\r
+ if (Global.createdSinceFilter.check(n) &&\r
+ Global.createdBeforeFilter.check(n) && \r
+ Global.changedSinceFilter.check(n) &&\r
+ Global.changedBeforeFilter.check(n) )\r
+ return true;\r
+ \r
+ return false;\r
+ }\r
+ // Delete a note\r
+ public void deleteNote(String guid) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("Update Note set deleted=CURRENT_TIMESTAMP(), active=false, isDirty=true where guid=:guid");\r
+ query.bindValue(":guid", guid);\r
+ if (!query.exec()) {\r
+ logger.log(logger.MEDIUM, "Note delete failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ }\r
+ public void restoreNote(String guid) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("Update Note set deleted='1969-12-31 19.00.00', active=true, isDirty=true where guid=:guid");\r
+// query.prepare("Update Note set deleted=0, active=true, isDirty=true where guid=:guid");\r
+ query.bindValue(":guid", guid);\r
+ if (!query.exec()) {\r
+ logger.log(logger.MEDIUM, "Note restore failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ }\r
+ // Purge a note (actually delete it instead of just marking it deleted)\r
+ public void expungeNote(String guid, boolean permanentExpunge, boolean needsSync) {\r
+ \r
+ if (!permanentExpunge) {\r
+ hideExpungedNote(guid, needsSync);\r
+ return;\r
+ }\r
+ \r
+ \r
+ NSqlQuery note = new NSqlQuery(db.getConnection());\r
+ NSqlQuery resources = new NSqlQuery(db.getConnection());\r
+ NSqlQuery tags = new NSqlQuery(db.getConnection());\r
+ NSqlQuery words = new NSqlQuery(db.getConnection());\r
+ \r
+ note.prepare("Delete from Note where guid=:guid");\r
+ resources.prepare("Delete from NoteResources where noteGuid=:guid");\r
+ tags.prepare("Delete from NoteTags where noteGuid=:guid");\r
+ words.prepare("Delete from words where guid=:guid");\r
+\r
+ note.bindValue(":guid", guid);\r
+ resources.bindValue(":guid", guid);\r
+ tags.bindValue(":guid", guid);\r
+ words.bindValue(":guid", guid);\r
+ \r
+ // Start purging notes.\r
+ if (!note.exec()) {\r
+ logger.log(logger.MEDIUM, "Purge from note failed.");\r
+ logger.log(logger.MEDIUM, note.lastError());\r
+ }\r
+ if (!resources.exec()) {\r
+ logger.log(logger.MEDIUM, "Purge from resources failed.");\r
+ logger.log(logger.MEDIUM, resources.lastError());\r
+ }\r
+ if (!tags.exec()) {\r
+ logger.log(logger.MEDIUM, "Note tags delete failed.");\r
+ logger.log(logger.MEDIUM, tags.lastError());\r
+ }\r
+ if (!words.exec()) {\r
+ logger.log(logger.MEDIUM, "Word delete failed.");\r
+ logger.log(logger.MEDIUM, words.lastError());\r
+ }\r
+ if (needsSync) {\r
+ RDeletedTable deletedTable = new RDeletedTable(logger, db);\r
+ deletedTable.addDeletedItem(guid, "Note");\r
+ }\r
+\r
+ }\r
+ // Purge a note (actually delete it instead of just marking it deleted)\r
+ public void hideExpungedNote(String guid, boolean needsSync) {\r
+ NSqlQuery note = new NSqlQuery(db.getConnection());\r
+ NSqlQuery resources = new NSqlQuery(db.getConnection());\r
+ NSqlQuery tags = new NSqlQuery(db.getConnection());\r
+ NSqlQuery words = new NSqlQuery(db.getConnection());\r
+ \r
+ note.prepare("Update Note set isExpunged=true where guid=:guid");\r
+ resources.prepare("Delete from NoteResources where noteGuid=:guid");\r
+ tags.prepare("Delete from NoteTags where noteGuid=:guid");\r
+ words.prepare("Delete from words where guid=:guid");\r
+\r
+ note.bindValue(":guid", guid);\r
+ resources.bindValue(":guid", guid);\r
+ tags.bindValue(":guid", guid);\r
+ words.bindValue(":guid", guid);\r
+\r
+ // Start purging notes.\r
+ if (!note.exec()) {\r
+ logger.log(logger.MEDIUM, "Purge from note failed.");\r
+ logger.log(logger.MEDIUM, note.lastError());\r
+ }\r
+ if (!resources.exec()) {\r
+ logger.log(logger.MEDIUM, "Purge from resources failed.");\r
+ logger.log(logger.MEDIUM, resources.lastError());\r
+ }\r
+ if (!tags.exec()) {\r
+ logger.log(logger.MEDIUM, "Note tags delete failed.");\r
+ logger.log(logger.MEDIUM, tags.lastError());\r
+ }\r
+ if (!words.exec()) {\r
+ logger.log(logger.MEDIUM, "Word delete failed.");\r
+ logger.log(logger.MEDIUM, words.lastError());\r
+ }\r
+ if (needsSync) {\r
+ RDeletedTable deletedTable = new RDeletedTable(logger, db);\r
+ deletedTable.addDeletedItem(guid, "Note");\r
+ }\r
+ }\r
+\r
+ \r
+ // Purge all deleted notes;\r
+ public void expungeAllDeletedNotes() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.exec("select guid, updateSequenceNumber from note where active = false");\r
+ while (query.next()) {\r
+ String guid = query.valueString(0);\r
+ Integer usn = new Integer(query.valueString(1));\r
+ if (usn == 0)\r
+ expungeNote(guid, true, false);\r
+ else\r
+ expungeNote(guid, false, true);\r
+ }\r
+ }\r
+ // Update the note sequence number\r
+ public void updateNoteSequence(String guid, int sequence) {\r
+ boolean check;\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ check = query.prepare("Update Note set updateSequenceNumber=:sequence where guid=:guid");\r
+\r
+ query.bindValue(":sequence", sequence);\r
+ query.bindValue(":guid", guid);\r
+ \r
+ query.exec();\r
+ if (!check) {\r
+ logger.log(logger.MEDIUM, "Note sequence update failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ } \r
+ }\r
+ // Update the note Guid\r
+ public void updateNoteGuid(String oldGuid, String newGuid) {\r
+ boolean check;\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("Update Note set guid=:newGuid where guid=:oldGuid");\r
+\r
+ query.bindValue(":newGuid", newGuid);\r
+ query.bindValue(":oldGuid", oldGuid);\r
+\r
+ check = query.exec();\r
+ if (!check) {\r
+ logger.log(logger.MEDIUM, "Note Guid update failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ } \r
+ \r
+ query.prepare("Update NoteTags set noteGuid=:newGuid where noteGuid=:oldGuid");\r
+ query.bindValue(":newGuid", newGuid);\r
+ query.bindValue(":oldGuid", oldGuid);\r
+ check = query.exec();\r
+ if (!check) {\r
+ logger.log(logger.MEDIUM, "Note guid update failed for NoteTags.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ \r
+ query.prepare("Update words set guid=:newGuid where guid=:oldGuid");\r
+ query.bindValue(":newGuid", newGuid);\r
+ query.bindValue(":oldGuid", oldGuid);\r
+ query.exec();\r
+ if (!check) {\r
+ logger.log(logger.MEDIUM, "Note guid update failed for Words.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ query.prepare("Update noteresources set noteguid=:newGuid where noteguid=:oldGuid");\r
+ query.bindValue(":newGuid", newGuid);\r
+ query.bindValue(":oldGuid", oldGuid);\r
+ query.exec();\r
+ if (!check) {\r
+ logger.log(logger.MEDIUM, "Note guid update failed for noteresources.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ }\r
+ // Update a note\r
+ public void updateNote(Note n, boolean isNew) {\r
+ boolean isExpunged = isNoteExpunged(n.getGuid());\r
+ \r
+ expungeNote(n.getGuid(), !isExpunged, false);\r
+ addNote(n, false);\r
+ }\r
+ // Does a note exist?\r
+ public boolean exists(String guid) {\r
+ if (guid == null)\r
+ return false;\r
+ if (guid.trim().equals(""))\r
+ return false;\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("Select guid from note where guid=:guid");\r
+ query.bindValue(":guid", guid);\r
+ if (!query.exec())\r
+ logger.log(logger.EXTREME, "note.exists SQL retrieve has failed.");\r
+ boolean retVal = query.next();\r
+ return retVal;\r
+ }\r
+ // Does a note exist?\r
+ public boolean isNoteExpunged(String guid) {\r
+ if (guid == null)\r
+ return false;\r
+ if (guid.trim().equals(""))\r
+ return false;\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("Select isExpunged from note where guid=:guid and isExpunged = true");\r
+ query.bindValue(":guid", guid);\r
+ if (!query.exec())\r
+ logger.log(logger.EXTREME, "note.isNoteExpunged SQL retrieve has failed.");\r
+ boolean retVal = query.next();\r
+ return retVal;\r
+ }\r
+ // This is a convience method to check if a tag exists & update/create based upon it\r
+ public void syncNote(Note tag, boolean isDirty) {\r
+ if (exists(tag.getGuid()))\r
+ updateNote(tag, isDirty);\r
+ else\r
+ addNote(tag, isDirty);\r
+ }\r
+ // Get a list of notes that need to be updated\r
+ public List <Note> getDirty() {\r
+ String guid;\r
+ Note tempNote;\r
+ List<Note> notes = new ArrayList<Note>();\r
+ List<String> index = new ArrayList<String>();\r
+ \r
+ boolean check; \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ check = query.exec("Select guid from Note where isDirty = true and notebookGuid not in (select guid from notebook where local = true)");\r
+ if (!check) \r
+ logger.log(logger.EXTREME, "Note SQL retrieve has failed: " +query.lastError().toString());\r
+ \r
+ // Get a list of the notes\r
+ while (query.next()) {\r
+ guid = new String();\r
+ guid = query.valueString(0);\r
+ index.add(guid); \r
+ } \r
+ \r
+ // Start getting notes\r
+ for (int i=0; i<index.size(); i++) {\r
+ tempNote = getNote(index.get(i), true,true,false,true,true);\r
+ notes.add(tempNote);\r
+ }\r
+ return notes; \r
+ }\r
+ // Get a list of notes that need to be updated\r
+ public boolean isNoteDirty(String guid) {\r
+ \r
+ boolean check; \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ check = query.prepare("Select guid from Note where isDirty = true and guid=:guid");\r
+ query.bindValue(":guid", guid);\r
+ check = query.exec();\r
+ if (!check) \r
+ logger.log(logger.EXTREME, "Note SQL retrieve has failed: " +query.lastError().toString());\r
+ \r
+ boolean returnValue;\r
+ // Get a list of the notes\r
+ if (query.next()) \r
+ returnValue = true; \r
+ else\r
+ returnValue = false;\r
+\r
+ return returnValue; \r
+ }\r
+ // Get a list of notes that need to be updated\r
+ public List <String> getUnsynchronizedGUIDs() {\r
+ String guid;\r
+ List<String> index = new ArrayList<String>();\r
+ \r
+ boolean check; \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ check = query.exec("Select guid from Note where isDirty = true");\r
+ if (!check) \r
+ logger.log(logger.EXTREME, "Note SQL retrieve has failed: " +query.lastError().toString());\r
+ \r
+ // Get a list of the notes\r
+ while (query.next()) {\r
+ guid = new String();\r
+ guid = query.valueString(0);\r
+ index.add(guid); \r
+ } \r
+ return index; \r
+ }\r
+ // Reset the dirty bit\r
+ public void resetDirtyFlag(String guid) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ query.prepare("Update note set isdirty=false where guid=:guid");\r
+ query.bindValue(":guid", guid);\r
+ if (!query.exec())\r
+ logger.log(logger.EXTREME, "Error resetting note dirty field.");\r
+ }\r
+ // Get all notes\r
+ public List<String> getAllGuids() {\r
+ List<String> notes = new ArrayList<String>();\r
+ \r
+ boolean check; \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ check = query.exec("Select guid from Note");\r
+ if (!check)\r
+ logger.log(logger.EXTREME, "Notebook SQL retrieve has failed: "+query.lastError());\r
+\r
+ // Get a list of the notes\r
+ while (query.next()) {\r
+ notes.add(new String(query.valueString(0))); \r
+ }\r
+ return notes;\r
+ }\r
+ // Get all notes\r
+ public List<Note> getAllNotes() {\r
+ List<Note> notes = new ArrayList<Note>();\r
+ prepareQueries();\r
+ boolean check; \r
+ NSqlQuery query = getAllQueryWithoutContent;\r
+ check = query.exec();\r
+ if (!check)\r
+ logger.log(logger.EXTREME, "Notebook SQL retrieve has failed: "+query.lastError());\r
+ // Get a list of the notes\r
+ while (query.next()) {\r
+ notes.add(mapNoteFromQuery(query, false, false, false, false, true));\r
+ }\r
+ return notes;\r
+ }\r
+ // Count unindexed notes\r
+ public int getUnindexedCount() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.exec("select count(*) from note where indexneeded=true and isExpunged = false");\r
+ query.next(); \r
+ int returnValue = new Integer(query.valueString(0));\r
+ return returnValue;\r
+ }\r
+ // Count unsynchronized notes\r
+ public int getDirtyCount() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.exec("select count(*) from note where isDirty=true and isExpunged = false");\r
+ query.next(); \r
+ int returnValue = new Integer(query.valueString(0));\r
+ return returnValue;\r
+ }\r
+ // Count notes\r
+ public int getNoteCount() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.exec("select count(*) from note where isExpunged = false");\r
+ query.next(); \r
+ int returnValue = new Integer(query.valueString(0));\r
+ return returnValue;\r
+ }\r
+ // Count deleted notes\r
+ public int getDeletedCount() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.exec("select count(*) from note where isExpunged = false and active = false");\r
+ if (!query.next()) \r
+ return 0;\r
+ int returnValue = new Integer(query.valueString(0));\r
+ return returnValue;\r
+ }\r
+ // Reset a note sequence number to zero. This is useful for moving conflicting notes\r
+ public void resetNoteSequence(String guid) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ boolean check = query.prepare("Update Note set updateSequenceNumber=0, isDirty=true where guid=:guid");\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "Update note ResetSequence sql prepare has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ query.bindValue(":guid", guid);\r
+ check = query.exec();\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "Update note sequence number has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ }\r
+ \r
+ \r
+ // Update a note resource by the hash\r
+ public void updateNoteResourceGuidbyHash(String noteGuid, String resGuid, String hash) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+/* query.prepare("Select guid from NoteResources where noteGuid=:noteGuid and datahash=:hex");\r
+ query.bindValue(":noteGuid", noteGuid);\r
+ query.bindValue(":hex", hash);\r
+ query.exec();\r
+ if (!query.next()) {\r
+ logger.log(logger.LOW, "Error finding note resource in RNoteTable.updateNoteResourceGuidbyHash. GUID="+noteGuid +" resGuid="+ resGuid+" hash="+hash);\r
+ return;\r
+ }\r
+ String guid = query.valueString(0);\r
+*/ \r
+ query.prepare("update noteresources set guid=:guid where noteGuid=:noteGuid and datahash=:hex");\r
+ query.bindValue(":guid", resGuid);\r
+ query.bindValue(":noteGuid", noteGuid);\r
+ query.bindValue(":hex", hash);\r
+ if (!query.exec()) {\r
+ logger.log(logger.EXTREME, "Note Resource Update by Hash failed");\r
+ logger.log(logger.EXTREME, query.lastError().toString());\r
+ }\r
+ }\r
+\r
+ // Fix CRLF problem that is on some notes\r
+ private String fixCarriageReturn(String note) {\r
+ if (note == null || !Global.enableCarriageReturnFix)\r
+ return note;\r
+ QByteArray a0Hex = new QByteArray("a0");\r
+ String a0 = QByteArray.fromHex(a0Hex).toString();\r
+ note = note.replace("<div>"+a0+"</div>", "<div> </div>");\r
+ return note.replace("<div/>", "<div> </div>");\r
+ }\r
+ \r
+ \r
+ \r
+ //********************************************************************************\r
+ //********************************************************************************\r
+ //* Indexing Functions\r
+ //********************************************************************************\r
+ //********************************************************************************\r
+ // set/unset a note to be reindexed\r
+ public void setIndexNeeded(String guid, Boolean flag) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("Update Note set indexNeeded=:flag where guid=:guid");\r
+\r
+ if (flag)\r
+ query.bindValue(":flag", 1);\r
+ else\r
+ query.bindValue(":flag", 0);\r
+ query.bindValue(":guid", guid);\r
+ if (!query.exec()) {\r
+ logger.log(logger.MEDIUM, "Note indexNeeded update failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ } \r
+ }\r
+ // Set all notes to be reindexed\r
+ public void reindexAllNotes() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ if (!query.exec("Update Note set indexNeeded=true")) {\r
+ logger.log(logger.MEDIUM, "Note reindexAllNotes update failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ } \r
+ }\r
+\r
+ // Get all unindexed notes\r
+ public List <String> getUnindexed() {\r
+ String guid;\r
+ List<String> index = new ArrayList<String>();\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ if (!query.exec("Select guid from Note where isExpunged = false and indexNeeded = true and DATEDIFF('MINUTE',updated,CURRENT_TIMESTAMP)>5"))\r
+ logger.log(logger.EXTREME, "Note SQL retrieve has failed on getUnindexed().");\r
+\r
+ // Get a list of the notes\r
+ while (query.next()) {\r
+ guid = new String();\r
+ guid = query.valueString(0);\r
+ index.add(guid); \r
+ } \r
+ return index; \r
+ }\r
+ public List<String> getNextUnindexed(int limit) {\r
+ List<String> guids = new ArrayList<String>();\r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ if (!query.exec("Select guid from Note where isExpunged = false and indexNeeded = true and DATEDIFF('MINUTE',Updated,CURRENT_TIMESTAMP)>5 limit " +limit))\r
+ logger.log(logger.EXTREME, "Note SQL retrieve has failed on getUnindexed().");\r
+ \r
+ // Get a list of the notes\r
+ String guid;\r
+ while (query.next()) {\r
+ guid = new String();\r
+ guid = query.valueString(0);\r
+ guids.add(guid);\r
+ } \r
+ return guids; \r
+ }\r
+ \r
+ \r
+ //**********************************************************************************\r
+ //* Title color functions\r
+ //**********************************************************************************\r
+ // Get the title color of all notes\r
+ public List<Pair<String, Integer>> getNoteTitleColors() {\r
+ List<Pair<String,Integer>> returnValue = new ArrayList<Pair<String,Integer>>();\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ if (!query.exec("Select guid,titleColor from Note where titleColor != -1"))\r
+ logger.log(logger.EXTREME, "Note SQL retrieve has failed on getUnindexed().");\r
+\r
+ String guid;\r
+ Integer color;\r
+ \r
+ // Get a list of the notes\r
+ while (query.next()) {\r
+ Pair<String, Integer> pair = new Pair<String,Integer>();\r
+ guid = query.valueString(0);\r
+ color = query.valueInteger(1);\r
+ pair.setFirst(guid);\r
+ pair.setSecond(color);\r
+ returnValue.add(pair); \r
+ } \r
+\r
+ \r
+ \r
+ return returnValue;\r
+ }\r
+ // Set a title color\r
+ // Reset the dirty bit\r
+ public void setNoteTitleColor(String guid, int color) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ query.prepare("Update note set titlecolor=:color where guid=:guid");\r
+ query.bindValue(":guid", guid);\r
+ query.bindValue(":color", color);\r
+ if (!query.exec())\r
+ logger.log(logger.EXTREME, "Error updating title color.");\r
+ }\r
+\r
+ \r
+ \r
+ //**********************************************************************************\r
+ //* Thumbnail functions\r
+ //**********************************************************************************\r
+ // Set if a new thumbnail is needed\r
+ public void setThumbnailNeeded(String guid, boolean needed) {\r
+ \r
+ boolean check; \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ check = query.prepare("Update note set thumbnailneeded = :needed where guid=:guid");\r
+ query.bindValue(":guid", guid);\r
+ query.bindValue(":needed", needed);\r
+ check = query.exec();\r
+ if (!check) \r
+ logger.log(logger.EXTREME, "Note SQL set thumbail needed failed: " +query.lastError().toString());\r
+\r
+ }\r
+ // Is a thumbail needed for this guid?\r
+ public boolean isThumbnailNeeded(String guid) {\r
+ \r
+ boolean check; \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ check = query.prepare("select thumbnailneeded from note where guid=:guid");\r
+ query.bindValue(":guid", guid);\r
+ check = query.exec();\r
+ if (!check) \r
+ logger.log(logger.EXTREME, "Note SQL isThumbnailNeeded query failed: " +query.lastError().toString());\r
+ \r
+ boolean returnValue;\r
+ // Get a list of the notes\r
+ if (query.next()) \r
+ returnValue = query.valueBoolean(0, false); \r
+ else\r
+ returnValue = false;\r
+\r
+ return returnValue; \r
+ }\r
+ // Set if a new thumbnail is needed\r
+ public void setThumbnail(String guid, QByteArray thumbnail) {\r
+ \r
+ boolean check; \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ check = query.prepare("Update note set thumbnail = :thumbnail where guid=:guid");\r
+ query.bindValue(":guid", guid);\r
+ query.bindValue(":thumbnail", thumbnail.toByteArray());\r
+ check = query.exec();\r
+ if (!check) \r
+ logger.log(logger.EXTREME, "Note SQL set thumbail failed: " +query.lastError().toString());\r
+\r
+ }\r
+ // Set if a new thumbnail is needed\r
+ public QByteArray getThumbnail(String guid) {\r
+ \r
+ boolean check; \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ check = query.prepare("Select thumbnail from note where guid=:guid");\r
+ query.bindValue(":guid", guid);\r
+ check = query.exec();\r
+ if (!check) \r
+ logger.log(logger.EXTREME, "Note SQL get thumbail failed: " +query.lastError().toString());\r
+ // Get a list of the notes\r
+ if (query.next()) \r
+ if (query.getBlob(0) != null)\r
+ return new QByteArray(query.getBlob(0)); \r
+ return null;\r
+ }\r
+ \r
+ \r
+ // Update a note content's hash. This happens if a resource is edited outside of NN\r
+ public void updateResourceContentHash(String guid, String oldHash, String newHash) {\r
+ Note n = getNote(guid, true, false, false, false,false);\r
+ int position = n.getContent().indexOf("<en-media");\r
+ int endPos;\r
+ for (;position>-1;) {\r
+ endPos = n.getContent().indexOf(">", position+1);\r
+ String oldSegment = n.getContent().substring(position,endPos);\r
+ int hashPos = oldSegment.indexOf("hash=\"");\r
+ int hashEnd = oldSegment.indexOf("\"", hashPos+7);\r
+ String hash = oldSegment.substring(hashPos+6, hashEnd);\r
+ if (hash.equalsIgnoreCase(oldHash)) {\r
+ String newSegment = oldSegment.replace(oldHash, newHash);\r
+ String content = n.getContent().substring(0,position) +\r
+ newSegment +\r
+ n.getContent().substring(endPos);\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("update note set isdirty=true, content=:content where guid=:guid");\r
+ query.bindValue(":content", content);\r
+ query.bindValue(":guid", n.getGuid());\r
+ query.exec();\r
+ }\r
+ \r
+ position = n.getContent().indexOf("<en-media", position+1);\r
+ }\r
+ }\r
+} \r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.sql.runners;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import cx.fbn.nevernote.sql.driver.NSqlQuery;\r
+import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+import cx.fbn.nevernote.utilities.Pair;\r
+\r
+public class RNoteTagsTable {\r
+ private final ApplicationLogger logger;\r
+ RDatabaseConnection db;\r
+\r
+ \r
+ // Constructor\r
+ public RNoteTagsTable(ApplicationLogger l,RDatabaseConnection d) {\r
+ logger = l;\r
+ db = d;\r
+ }\r
+ // Create the table\r
+ public void createTable() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ // Create the NoteTag table\r
+ logger.log(logger.HIGH, "Creating table NoteTags...");\r
+ if (!query.exec("Create table NoteTags (noteGuid varchar, " +\r
+ "tagGuid varchar, primary key(noteGuid, tagGuid))"))\r
+ logger.log(logger.HIGH, "Table NoteTags creation FAILED!!!"); \r
+ }\r
+ // Drop the table\r
+ public void dropTable() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.exec("drop table NoteTags");\r
+ }\r
+ // Get a note tags by the note's Guid\r
+ public List<String> getNoteTags(String noteGuid) {\r
+ if (noteGuid == null)\r
+ return null;\r
+ boolean check;\r
+ List<String> tags = new ArrayList<String>();\r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ check = query.exec("Select "\r
+ +"TagGuid from NoteTags where noteGuid = '" +noteGuid +"'");\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "NoteTags SQL select has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ return null;\r
+ }\r
+ while (query.next()) {\r
+ tags.add(query.valueString(0));\r
+ } \r
+ return tags;\r
+ }\r
+ // Get a note tags by the note's Guid\r
+ public List<NoteTagsRecord> getAllNoteTags() {\r
+ List<NoteTagsRecord> tags = new ArrayList<NoteTagsRecord>();\r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ if (!query.exec("Select TagGuid, NoteGuid from NoteTags")) {\r
+ logger.log(logger.EXTREME, "NoteTags SQL select has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ return null;\r
+ }\r
+ while (query.next()) {\r
+ NoteTagsRecord record = new NoteTagsRecord();\r
+ record.tagGuid = query.valueString(0);\r
+ record.noteGuid = query.valueString(1);\r
+ tags.add(record);\r
+ } \r
+ return tags;\r
+ }\r
+ // Check if a note has a specific tag already\r
+ public boolean checkNoteNoteTags(String noteGuid, String tagGuid) {\r
+ if (noteGuid == null || tagGuid == null)\r
+ return false;\r
+ boolean check;\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ check = query.prepare("Select "\r
+ +"NoteGuid, TagGuid from NoteTags where noteGuid = :noteGuid and tagGuid = :tagGuid");\r
+ if (!check)\r
+ logger.log(logger.EXTREME, "checkNoteTags SQL prepare has failed.");\r
+ \r
+ query.bindValue(":noteGuid", noteGuid);\r
+ query.bindValue(":tagGuid", tagGuid);\r
+ query.exec();\r
+ \r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "checkNoteTags SQL select has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ return false;\r
+ }\r
+ \r
+ if (query.next()) {\r
+ return true;\r
+ } \r
+ return false;\r
+ }\r
+ // Save Note Tags\r
+ public void saveNoteTag(String noteGuid, String tagGuid) {\r
+ boolean check;\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+\r
+ check = query.prepare("Insert Into NoteTags (noteGuid, tagGuid) "\r
+ +"Values("\r
+ +":noteGuid, :tagGuid)");\r
+ if (!check)\r
+ logger.log(logger.EXTREME, "Note SQL insert prepare has failed.");\r
+ \r
+ query.bindValue(":noteGuid", noteGuid);\r
+ query.bindValue(":tagGuid", tagGuid);\r
+ \r
+ check = query.exec();\r
+ if (!check) {\r
+ logger.log(logger.MEDIUM, "NoteTags Table insert failed."); \r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ check = query.prepare("Update Note set isDirty=1 where guid=:guid");\r
+ if (!check)\r
+ logger.log(logger.EXTREME, "RNoteTagsTable.saveNoteTag prepare has failed.");\r
+ query.bindValue(":guid", noteGuid);\r
+ if (!check) {\r
+ logger.log(logger.MEDIUM, "RNoteTagsTable.saveNoteTag has failed to set note as dirty."); \r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ }\r
+ // Delete a note's tags\r
+ public void deleteNoteTag(String noteGuid) {\r
+ boolean check;\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ check = query.prepare("Delete from NoteTags where noteGuid = :noteGuid");\r
+ if (!check)\r
+ logger.log(logger.EXTREME, "Note SQL delete prepare has failed.");\r
+ \r
+ query.bindValue(":noteGuid", noteGuid);\r
+ check = query.exec();\r
+ if (!check) {\r
+ logger.log(logger.MEDIUM, "NoteTags Table delete failed."); \r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+\r
+ }\r
+ // Get a note tag counts\r
+ public List<Pair<String,Integer>> getTagCounts() {\r
+ List<Pair<String,Integer>> counts = new ArrayList<Pair<String,Integer>>(); \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ if (!query.exec("select tagguid, count(noteguid) from notetags group by tagguid;")) {\r
+ logger.log(logger.EXTREME, "NoteTags SQL getTagCounts has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ return null;\r
+ }\r
+ while (query.next()) {\r
+ Pair<String,Integer> newCount = new Pair<String,Integer>();\r
+ newCount.setFirst(query.valueString(0));\r
+ newCount.setSecond(query.valueInteger(1));\r
+ counts.add(newCount);\r
+ } \r
+ return counts;\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.sql.runners;\r
+\r
+import java.text.DateFormat;\r
+import java.text.ParseException;\r
+import java.text.SimpleDateFormat;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.Notebook;\r
+\r
+import cx.fbn.nevernote.sql.driver.NSqlQuery;\r
+import cx.fbn.nevernote.sql.requests.NotebookRequest;\r
+import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+import cx.fbn.nevernote.utilities.Pair;\r
+\r
+public class RNotebookTable {\r
+ \r
+ private final ApplicationLogger logger;\r
+ RDatabaseConnection db;\r
+ public NotebookRequest mainResponse;\r
+ \r
+ // Constructor\r
+ public RNotebookTable(ApplicationLogger l, RDatabaseConnection d) {\r
+ logger = l;\r
+ db = d;\r
+ mainResponse = new NotebookRequest();\r
+ }\r
+ // Create the table\r
+ public void createTable() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ logger.log(logger.HIGH, "Creating table Notebook...");\r
+ if (!query.exec("Create table Notebook (guid varchar primary key, " +\r
+ "sequence integer, name varchar, defaultNotebook varchar, "+\r
+ "serviceCreated timestamp, serviceUpdated timestamp, published boolean, isDirty boolean, "+\r
+ "autoEncrypt boolean, local boolean, archived boolean)")) \r
+ logger.log(logger.HIGH, "Table Notebook creation FAILED!!!"); \r
+ Notebook newnote = new Notebook();\r
+ newnote.setDefaultNotebook(true);\r
+ newnote.setName("My Notebook");\r
+ newnote.setPublished(false);\r
+ newnote.setGuid("1");\r
+ addNotebook(newnote, true, false);\r
+ \r
+ }\r
+ // Drop the table\r
+ public void dropTable() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.exec("Drop table Notebook");\r
+ }\r
+ // Save an individual notebook\r
+ public void addNotebook(Notebook tempNotebook, boolean isDirty, boolean local) {\r
+ boolean check;\r
+ \r
+ SimpleDateFormat simple = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ check = query.prepare("Insert Into Notebook (guid, sequence, name, defaultNotebook, "\r
+ +"serviceCreated, serviceUpdated, published, " \r
+ + "isDirty, autoEncrypt," \r
+ + "local, archived) Values("\r
+ +":guid, :sequence, :name, :defaultNotebook, "\r
+ +":serviceCreated, :serviceUpdated, :published, "\r
+ +":isDirty, :autoEncrypt, "\r
+ +":local, false)");\r
+ query.bindValue(":guid", tempNotebook.getGuid());\r
+ query.bindValue(":sequence", tempNotebook.getUpdateSequenceNum());\r
+ query.bindValue(":name", tempNotebook.getName());\r
+ query.bindValue(":defaultNotebook", tempNotebook.isDefaultNotebook());\r
+ \r
+ StringBuilder serviceCreated = new StringBuilder(simple.format(tempNotebook.getServiceCreated())); \r
+ StringBuilder serviceUpdated = new StringBuilder(simple.format(tempNotebook.getServiceUpdated()));\r
+ if (serviceUpdated.toString() == null)\r
+ serviceUpdated = serviceCreated;\r
+ query.bindValue(":serviceCreated", serviceCreated.toString());\r
+ query.bindValue(":serviceUpdated", serviceCreated.toString());\r
+ query.bindValue(":published",tempNotebook.isPublished());\r
+ \r
+ if (isDirty)\r
+ query.bindValue(":isDirty", true);\r
+ else\r
+ query.bindValue(":isDirty", false);\r
+ query.bindValue(":autoEncrypt", false);\r
+ query.bindValue(":local", local);\r
+\r
+ check = query.exec();\r
+ if (!check) {\r
+ logger.log(logger.MEDIUM, "Notebook Table insert failed.");\r
+ logger.log(logger.MEDIUM, query.lastError().toString());\r
+ }\r
+ }\r
+ // Delete the notebook based on a guid\r
+ public void expungeNotebook(String guid, boolean needsSync) {\r
+ boolean check;\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+\r
+ check = query.prepare("delete from Notebook "\r
+ +"where guid=:guid");\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "Notebook SQL delete prepare has failed.");\r
+ logger.log(logger.EXTREME, query.lastError().toString());\r
+ }\r
+ query.bindValue(":guid", guid);\r
+ check = query.exec();\r
+ if (!check) \r
+ logger.log(logger.MEDIUM, "Notebook delete failed.");\r
+ \r
+ // Signal the parent that work needs to be done\r
+ if (needsSync) {\r
+ RDeletedTable deletedTable = new RDeletedTable(logger, db);\r
+ deletedTable.addDeletedItem(guid, "Notebook");\r
+ }\r
+ }\r
+ // Update a notebook\r
+ public void updateNotebook(Notebook tempNotebook, boolean isDirty) {\r
+ boolean check;\r
+ \r
+ SimpleDateFormat simple = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");\r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ check = query.prepare("Update Notebook set sequence=:sequence, name=:name, defaultNotebook=:defaultNotebook, " +\r
+ "serviceCreated=:serviceCreated, serviceUpdated=:serviceUpdated, "+\r
+ "published=:published, isDirty=:isDirty where guid=:guid ");\r
+ query.bindValue(":sequence", tempNotebook.getUpdateSequenceNum());\r
+ query.bindValue(":name", tempNotebook.getName());\r
+ query.bindValue(":defaultNotebook", tempNotebook.isDefaultNotebook());\r
+\r
+ StringBuilder serviceCreated = new StringBuilder(simple.format(tempNotebook.getServiceCreated())); \r
+ StringBuilder serviceUpdated = new StringBuilder(simple.format(tempNotebook.getServiceUpdated())); \r
+ query.bindValue(":serviceCreated", serviceCreated.toString());\r
+ query.bindValue(":serviceUpdated", serviceUpdated.toString());\r
+ \r
+ query.bindValue(":published", tempNotebook.isPublished());\r
+ query.bindValue(":isDirty", isDirty);\r
+ query.bindValue(":guid", tempNotebook.getGuid());\r
+ \r
+ check = query.exec();\r
+ if (!check) {\r
+ logger.log(logger.MEDIUM, "Notebook Table update failed.");\r
+ logger.log(logger.MEDIUM, query.lastError().toString());\r
+ }\r
+ }\r
+ // Load notebooks from the database\r
+ public List<Notebook> getAll() {\r
+ Notebook tempNotebook;\r
+ List<Notebook> index = new ArrayList<Notebook>();\r
+ boolean check;\r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ check = query.exec("Select guid, sequence, name, defaultNotebook, " +\r
+ "serviceCreated, "+\r
+ "serviceUpdated, "+\r
+ "published, defaultNotebook from Notebook order by name");\r
+ if (!check)\r
+ logger.log(logger.EXTREME, "Notebook SQL retrieve has failed.");\r
+ while (query.next()) {\r
+ tempNotebook = new Notebook();\r
+ tempNotebook.setGuid(query.valueString(0));\r
+ int sequence = new Integer(query.valueString(1)).intValue();\r
+ tempNotebook.setUpdateSequenceNum(sequence);\r
+ tempNotebook.setName(query.valueString(2));\r
+ DateFormat indfm = null;\r
+ try {\r
+ indfm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");\r
+// indfm = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy");\r
+ } catch (Exception e) { }\r
+ try {\r
+ tempNotebook.setServiceCreated(indfm.parse(query.valueString(4)).getTime());\r
+ tempNotebook.setServiceUpdated(indfm.parse(query.valueString(5)).getTime());\r
+ } catch (ParseException e) {\r
+ e.printStackTrace();\r
+ }\r
+ tempNotebook.setPublished(new Boolean(query.valueString(6)));\r
+ tempNotebook.setDefaultNotebook(new Boolean(query.valueString(7)));\r
+ index.add(tempNotebook); \r
+ } \r
+ return index;\r
+ } \r
+ public List<Notebook> getAllLocal() {\r
+ Notebook tempNotebook;\r
+ List<Notebook> index = new ArrayList<Notebook>();\r
+ boolean check;\r
+\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ check = query.exec("Select guid, sequence, name, defaultNotebook, " +\r
+ "serviceCreated, serviceUpdated, published from Notebook where local=true order by name");\r
+ if (!check)\r
+ logger.log(logger.EXTREME, "Notebook SQL retrieve has failed.");\r
+ while (query.next()) {\r
+ tempNotebook = new Notebook();\r
+ tempNotebook.setGuid(query.valueString(0));\r
+ int sequence = new Integer(query.valueString(1)).intValue();\r
+ tempNotebook.setUpdateSequenceNum(sequence);\r
+ tempNotebook.setName(query.valueString(2));\r
+ \r
+ DateFormat indfm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");\r
+// indfm = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy");\r
+ try {\r
+ tempNotebook.setServiceCreated(indfm.parse(query.valueString(4)).getTime());\r
+ tempNotebook.setServiceUpdated(indfm.parse(query.valueString(5)).getTime());\r
+ } catch (ParseException e) {\r
+ e.printStackTrace();\r
+ }\r
+ index.add(tempNotebook); \r
+ } \r
+ return index;\r
+ }\r
+ // Archive or un-archive a notebook\r
+ public void setArchived(String guid, boolean val) {\r
+ boolean check; \r
+ NSqlQuery query = new NSqlQuery(db.getConnection()); \r
+ check = query.prepare("Update notebook set archived=:archived where guid=:guid");\r
+ if (!check)\r
+ logger.log(logger.EXTREME, "Notebook SQL archive update has failed.");\r
+ query.bindValue(":guid", guid);\r
+ query.bindValue(":archived", val);\r
+ query.exec();\r
+ }\r
+ // Load non-archived notebooks from the database\r
+ public List<Notebook> getAllArchived() {\r
+ Notebook tempNotebook;\r
+ List<Notebook> index = new ArrayList<Notebook>();\r
+ boolean check;\r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ check = query.exec("Select guid, sequence, name, defaultNotebook, " +\r
+ "serviceCreated, serviceUpdated, published from Notebook where archived=true order by name");\r
+ if (!check)\r
+ logger.log(logger.EXTREME, "Notebook SQL retrieve has failed.");\r
+ while (query.next()) {\r
+ tempNotebook = new Notebook();\r
+ tempNotebook.setGuid(query.valueString(0));\r
+ int sequence = new Integer(query.valueString(1)).intValue();\r
+ tempNotebook.setUpdateSequenceNum(sequence);\r
+ tempNotebook.setName(query.valueString(2));\r
+ \r
+ DateFormat indfm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");\r
+// indfm = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy");\r
+ try {\r
+ tempNotebook.setServiceCreated(indfm.parse(query.valueString(4)).getTime());\r
+ tempNotebook.setServiceUpdated(indfm.parse(query.valueString(5)).getTime());\r
+ } catch (ParseException e) {\r
+ e.printStackTrace();\r
+ }\r
+ tempNotebook.setPublished(new Boolean(query.valueString(6)));\r
+ index.add(tempNotebook); \r
+ } \r
+ return index;\r
+ } \r
+ // Check for a local/remote notebook\r
+ public boolean isNotebookLocal(String guid) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ query.prepare("Select local from Notebook where guid=:guid");\r
+ query.bindValue(":guid", guid);\r
+ query.exec();\r
+ if (!query.next()) {\r
+ return false;\r
+ }\r
+ boolean returnValue = false;\r
+ String returnVal = query.valueString(0);\r
+ if (returnVal.equals("false"))\r
+ returnValue = false;\r
+ else\r
+ returnValue = true;\r
+ return returnValue;\r
+ }\r
+ // Update a notebook sequence number\r
+ public void updateNotebookSequence(String guid, int sequence) {\r
+ boolean check;\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ check = query.prepare("Update Notebook set sequence=:sequence where guid=:guid");\r
+ query.bindValue(":guid", guid);\r
+ query.bindValue(":sequence", sequence);\r
+ query.exec();\r
+ if (!check) {\r
+ logger.log(logger.MEDIUM, "Notebook sequence update failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ } \r
+ }\r
+ // Update a notebook GUID number\r
+ public void updateNotebookGuid(String oldGuid, String newGuid) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("Update Notebook set guid=:newGuid where guid=:oldGuid");\r
+ query.bindValue(":oldGuid", oldGuid);\r
+ query.bindValue(":newGuid", newGuid);\r
+ if (!query.exec()) {\r
+ logger.log(logger.MEDIUM, "Notebook guid update failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ } \r
+ \r
+ // Update any notes containing the notebook guid\r
+ query.prepare("Update Note set notebookGuid=:newGuid where notebookGuid=:oldGuid");\r
+ query.bindValue(":oldGuid", oldGuid);\r
+ query.bindValue(":newGuid", newGuid);\r
+ if (!query.exec()) {\r
+ logger.log(logger.MEDIUM, "Notebook guid update for note failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ } \r
+ \r
+ // Update any watch folders with the new guid\r
+ query = new NSqlQuery(db.getConnection());\r
+ query.prepare("Update WatchFolders set notebook=:newGuid where notebook=:oldGuid");\r
+ query.bindValue(":oldGuid", oldGuid);\r
+ query.bindValue(":newGuid", newGuid);\r
+ if (!query.exec()) {\r
+ logger.log(logger.MEDIUM, "Update WatchFolder notebook failed.");\r
+ logger.log(logger.MEDIUM, query.lastError().toString());\r
+ } \r
+ }\r
+ // Get a list of notes that need to be updated\r
+ public List <Notebook> getDirty() {\r
+ Notebook tempNotebook;\r
+ List<Notebook> index = new ArrayList<Notebook>();\r
+ boolean check;\r
+ \r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ check = query.exec("Select guid, sequence, name, defaultNotebook, " +\r
+ "serviceCreated, serviceUpdated, published from Notebook where isDirty = true and local=false");\r
+ if (!check) \r
+ logger.log(logger.EXTREME, "Notebook SQL retrieve has failed.");\r
+ while (query.next()) {\r
+ tempNotebook = new Notebook();\r
+ tempNotebook.setGuid(query.valueString(0));\r
+ int sequence = new Integer(query.valueString(1)).intValue();\r
+ tempNotebook.setUpdateSequenceNum(sequence);\r
+ tempNotebook.setName(query.valueString(2));\r
+ \r
+ DateFormat indfm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");\r
+// indfm = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy");\r
+ try {\r
+ tempNotebook.setServiceCreated(indfm.parse(query.valueString(4)).getTime());\r
+ tempNotebook.setServiceUpdated(indfm.parse(query.valueString(5)).getTime());\r
+ } catch (ParseException e) {\r
+ e.printStackTrace();\r
+ }\r
+ tempNotebook.setPublished(new Boolean(query.valueString(6)));\r
+ index.add(tempNotebook); \r
+ } \r
+ return index; \r
+ }\r
+ // This is a convience method to check if a tag exists & update/create based upon it\r
+ public void syncNotebook(Notebook notebook, boolean isDirty) {\r
+ if (!exists(notebook.getGuid())) {\r
+ addNotebook(notebook, isDirty, isDirty);\r
+ return;\r
+ }\r
+ updateNotebook(notebook, isDirty);\r
+ }\r
+ // does a record exist?\r
+ private boolean exists(String guid) {\r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ query.prepare("Select guid from notebook where guid=:guid");\r
+ query.bindValue(":guid", guid);\r
+ if (!query.exec())\r
+ logger.log(logger.EXTREME, "notebook SQL retrieve has failed.");\r
+ boolean retval = query.next();\r
+ return retval;\r
+ }\r
+ // Reset the dirty flag. Typically done after a sync.\r
+ public void resetDirtyFlag(String guid) {\r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ query.prepare("Update notebook set isdirty='false' where guid=:guid");\r
+ query.bindValue(":guid", guid);\r
+ if (!query.exec())\r
+ logger.log(logger.EXTREME, "Error resetting notebook dirty field.");\r
+ }\r
+ \r
+ \r
+ \r
+\r
+ // does a record exist?\r
+ public String findNotebookByName(String newname) {\r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ query.prepare("Select guid from notebook where name=:newname");\r
+ query.bindValue(":newname", newname);\r
+ if (!query.exec())\r
+ logger.log(logger.EXTREME, "notebook SQL retrieve has failed.");\r
+ String val = null;\r
+ if (query.next())\r
+ val = query.valueString(0);\r
+ return val;\r
+ }\r
+ // Get a note tag counts\r
+ public List<Pair<String,Integer>> getNotebookCounts() {\r
+ List<Pair<String,Integer>> counts = new ArrayList<Pair<String,Integer>>(); \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ if (!query.exec("select notebookGuid, count(guid) from note where active=1 group by notebookguid;")) {\r
+ logger.log(logger.EXTREME, "NoteTags SQL getTagCounts has failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ return null;\r
+ }\r
+ while (query.next()) {\r
+ Pair<String,Integer> newCount = new Pair<String,Integer>();\r
+ newCount.setFirst(query.valueString(0));\r
+ newCount.setSecond(query.valueInteger(1));\r
+ counts.add(newCount);\r
+ } \r
+ return counts;\r
+ }\r
+\r
+}\r
+\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.sql.runners;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.QueryFormat;\r
+import com.evernote.edam.type.SavedSearch;\r
+\r
+import cx.fbn.nevernote.sql.driver.NSqlQuery;\r
+import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+\r
+public class RSavedSearchTable {\r
+ private final ApplicationLogger logger;\r
+ private final RDatabaseConnection db;\r
+\r
+ \r
+ // Constructor\r
+ public RSavedSearchTable(ApplicationLogger l, RDatabaseConnection d) {\r
+ logger = l;\r
+ db = d;\r
+ }\r
+ // Create the table\r
+ public void createTable() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ logger.log(logger.HIGH, "Creating table SavedSearch...");\r
+ if (!query.exec("Create table SavedSearch (guid varchar primary key, " +\r
+ "name varchar, query varchar, format integer, sequence integer, isDirty boolean)"))\r
+ logger.log(logger.HIGH, "Table SavedSearch creation FAILED!!!"); \r
+ }\r
+ // Drop the table\r
+ public void dropTable() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.exec("Drop table SavedSearch");\r
+ }\r
+ // get all tags\r
+ public List<SavedSearch> getAll() {\r
+ SavedSearch tempSearch;\r
+ List<SavedSearch> index = new ArrayList<SavedSearch>();\r
+ boolean check;\r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ check = query.exec("Select guid, name, query, format, sequence"\r
+ +" from SavedSearch");\r
+ if (!check)\r
+ logger.log(logger.EXTREME, "SavedSearch SQL retrieve has failed in getAll().");\r
+ while (query.next()) {\r
+ tempSearch = new SavedSearch();\r
+ tempSearch.setGuid(query.valueString(0));\r
+ tempSearch.setName(query.valueString(1));\r
+ tempSearch.setQuery(query.valueString(2));\r
+ int fmt = new Integer(query.valueString(3));\r
+ if (fmt == 1)\r
+ tempSearch.setFormat(QueryFormat.USER);\r
+ else\r
+ tempSearch.setFormat(QueryFormat.SEXP);\r
+ int sequence = new Integer(query.valueString(4)).intValue();\r
+ tempSearch.setUpdateSequenceNum(sequence);\r
+ index.add(tempSearch); \r
+ } \r
+ return index;\r
+ }\r
+ public SavedSearch getSavedSearch(String guid) {\r
+ SavedSearch tempSearch = null;\r
+ boolean check;\r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ check = query.prepare("Select guid, name, query, format, sequence"\r
+ +" from SavedSearch where guid=:guid");\r
+ if (!check)\r
+ logger.log(logger.EXTREME, "SavedSearch SQL prepare has failed in getSavedSearch.");\r
+ query.bindValue(":guid", guid);\r
+ query.exec();\r
+ if (!check)\r
+ logger.log(logger.EXTREME, "SavedSearch SQL retrieve has failed in getSavedSearch.");\r
+ if (query.next()) {\r
+ tempSearch = new SavedSearch();\r
+ tempSearch.setGuid(query.valueString(0));\r
+ tempSearch.setName(query.valueString(1));\r
+ tempSearch.setQuery(query.valueString(2));\r
+ int fmt = new Integer(query.valueString(3));\r
+ if (fmt == 1)\r
+ tempSearch.setFormat(QueryFormat.USER);\r
+ else\r
+ tempSearch.setFormat(QueryFormat.SEXP);\r
+ int sequence = new Integer(query.valueString(4)).intValue();\r
+ tempSearch.setUpdateSequenceNum(sequence);\r
+ }\r
+ return tempSearch;\r
+ }\r
+ // Update a tag\r
+ public void updateSavedSearch(SavedSearch search, boolean isDirty) {\r
+ boolean check;\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ check = query.prepare("Update SavedSearch set sequence=:sequence, "+\r
+ "name=:name, isDirty=:isDirty, query=:query, format=:format "\r
+ +"where guid=:guid");\r
+ \r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "SavedSearch SQL update prepare has failed.");\r
+ logger.log(logger.EXTREME, query.lastError().toString());\r
+ }\r
+ query.bindValue(":sequence", search.getUpdateSequenceNum());\r
+ query.bindValue(":name", search.getName());\r
+ query.bindValue(":isDirty", isDirty);\r
+ query.bindValue(":query", search.getQuery());\r
+ if (search.getFormat() == QueryFormat.USER)\r
+ query.bindValue(":format", 1);\r
+ else\r
+ query.bindValue(":format", 2);\r
+ \r
+ query.bindValue(":guid", search.getGuid());\r
+ \r
+ check = query.exec();\r
+ if (!check) {\r
+ logger.log(logger.MEDIUM, "Tag Table update failed.");\r
+ logger.log(logger.EXTREME, query.lastError().toString());\r
+ }\r
+ }\r
+ // Delete a tag\r
+ public void expungeSavedSearch(String guid, boolean needsSync) {\r
+ boolean check;\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+\r
+ check = query.prepare("delete from SavedSearch "\r
+ +"where guid=:guid");\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "SavedSearch SQL delete prepare has failed.");\r
+ logger.log(logger.EXTREME, query.lastError().toString());\r
+ }\r
+ query.bindValue(":guid", guid);\r
+ check = query.exec();\r
+ if (!check) {\r
+ logger.log(logger.MEDIUM, "Saved Search delete failed.");\r
+ logger.log(logger.EXTREME, query.lastError().toString());\r
+ }\r
+\r
+ // Add the work to the parent queue\r
+ if (needsSync) {\r
+ RDeletedTable del = new RDeletedTable(logger, db);\r
+ del.addDeletedItem(guid, "SavedSearch");\r
+ }\r
+ }\r
+ // Save a tag\r
+ public void addSavedSearch(SavedSearch search, boolean isDirty) {\r
+ boolean check;\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ check = query.prepare("Insert Into SavedSearch (guid, query, sequence, format, name, isDirty)"\r
+ +" Values(:guid, :query, :sequence, :format, :name, :isDirty)");\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "Search SQL insert prepare has failed.");\r
+ logger.log(logger.EXTREME, query.lastError().toString());\r
+ }\r
+ query.bindValue(":guid", search.getGuid());\r
+ query.bindValue(":query", search.getQuery());\r
+ query.bindValue(":sequence", search.getUpdateSequenceNum());\r
+ if (search.getFormat() == QueryFormat.USER)\r
+ query.bindValue(":format", 1);\r
+ else\r
+ query.bindValue(":format", 2);\r
+ query.bindValue(":name", search.getName());\r
+ query.bindValue(":isDirty", isDirty);\r
+ \r
+ check = query.exec();\r
+ if (!check) {\r
+ logger.log(logger.MEDIUM, "Search Table insert failed.");\r
+ logger.log(logger.MEDIUM, query.lastError().toString());\r
+ }\r
+ }\r
+ // Update a tag sequence number\r
+ public void updateSavedSearchSequence(String guid, int sequence) {\r
+ boolean check;\r
+ ;\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ check = query.prepare("Update SavedSearch set sequence=:sequence where guid=:guid");\r
+ query.bindValue(":sequence", sequence);\r
+ query.bindValue(":guid", guid);\r
+ query.exec();\r
+ if (!check) {\r
+ logger.log(logger.MEDIUM, "SavedSearch sequence update failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ }\r
+ // Update a tag sequence number\r
+ public void updateSavedSearchGuid(String oldGuid, String newGuid) {\r
+ boolean check;\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ check = query.prepare("Update SavedSearch set guid=:newGuid where guid=:oldGuid");\r
+ query.bindValue(":newGuid", newGuid);\r
+ query.bindValue(":oldGuid", oldGuid);\r
+ query.exec();\r
+ if (!check) {\r
+ logger.log(logger.MEDIUM, "SavedSearch guid update failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ }\r
+ // Get dirty tags\r
+ public List<SavedSearch> getDirty() {\r
+ SavedSearch search;\r
+ List<SavedSearch> index = new ArrayList<SavedSearch>();\r
+ boolean check;\r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ check = query.exec("Select guid, query, sequence, name, format"\r
+ +" from SavedSearch where isDirty = true");\r
+ if (!check)\r
+ logger.log(logger.EXTREME, "SavedSearch getDirty prepare has failed.");\r
+ while (query.next()) {\r
+ search = new SavedSearch();\r
+ search.setGuid(query.valueString(0));\r
+ search.setQuery(query.valueString(1));\r
+ int sequence = new Integer(query.valueString(2)).intValue();\r
+ search.setUpdateSequenceNum(sequence);\r
+ search.setName(query.valueString(3));\r
+ int fmt = new Integer(query.valueString(4)).intValue();\r
+ if (fmt == 1)\r
+ search.setFormat(QueryFormat.USER);\r
+ else\r
+ search.setFormat(QueryFormat.SEXP);\r
+ index.add(search); \r
+ } \r
+ return index;\r
+ }\r
+ // Find a guid based upon the name\r
+ public String findSavedSearchByName(String name) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ query.prepare("Select guid from SavedSearch where name=:name");\r
+ query.bindValue(":name", name);\r
+ if (!query.exec())\r
+ logger.log(logger.EXTREME, "SavedSearch SQL retrieve has failed in findSavedSearchByName().");\r
+ String val = null;\r
+ if (query.next())\r
+ val = query.valueString(0);\r
+ return val;\r
+ }\r
+ // given a guid, does the tag exist\r
+ public boolean exists(String guid) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("Select guid from SavedSearch where guid=:guid");\r
+ query.bindValue(":guid", guid);\r
+ if (!query.exec())\r
+ logger.log(logger.EXTREME, "SavedSearch SQL retrieve has failed in exists().");\r
+ boolean retval = query.next();\r
+ return retval;\r
+ }\r
+ // This is a convience method to check if a tag exists & update/create based upon it\r
+ public void syncSavedSearch(SavedSearch search, boolean isDirty) {\r
+ if (exists(search.getGuid()))\r
+ updateSavedSearch(search, isDirty);\r
+ else\r
+ addSavedSearch(search, isDirty);\r
+ }\r
+ public void resetDirtyFlag(String guid) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ query.prepare("Update SavedSearch set isdirty=false where guid=:guid");\r
+ query.bindValue(":guid", guid);\r
+ if (!query.exec())\r
+ logger.log(logger.EXTREME, "Error resetting SavedSearch dirty field in resetDirtyFlag().");\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.sql.runners;\r
+\r
+import cx.fbn.nevernote.sql.driver.NSqlQuery;\r
+import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+import cx.fbn.nevernote.utilities.ListManager;\r
+\r
+public class RSyncTable {\r
+ ListManager parent;\r
+ private final ApplicationLogger logger;\r
+ private final RDatabaseConnection db;\r
+\r
+ \r
+ // Constructor\r
+ public RSyncTable(ApplicationLogger l, RDatabaseConnection d) {\r
+ logger = l;\r
+ db = d;\r
+ }\r
+ // Create the table\r
+ public void createTable() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ logger.log(logger.HIGH, "Creating table Sync...");\r
+ if (!query.exec("Create table Sync (key varchar primary key, value varchar);"))\r
+ logger.log(logger.HIGH, "Table Sync creation FAILED!!!"); \r
+ addRecord("LastSequenceDate","0");\r
+ addRecord("UpdateSequenceNumber", "0");\r
+ }\r
+ // Drop the table\r
+ public void dropTable() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.exec("Drop table Sync");\r
+ }\r
+ // Add an item to the table\r
+ public void addRecord(String key, String value) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("Insert Into Sync (key, value) values (:key, :value);");\r
+ query.bindValue(":key", key);\r
+ query.bindValue(":value", value);\r
+ if (!query.exec()) {\r
+ logger.log(logger.MEDIUM, "Add to into Sync failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ }\r
+ // Set a key field\r
+ public String getRecord(String key) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("Select value from Sync where key=:key");\r
+ query.bindValue(":key", key);\r
+ if (!query.exec()) {\r
+ logger.log(logger.MEDIUM, "getRecord from sync failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ return null;\r
+ }\r
+ if (query.next()) {\r
+ return (query.valueString(0));\r
+ }\r
+ return null;\r
+ }\r
+ // Set a key field\r
+ public void setRecord(String key, String value) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("Update Sync set value=:value where key=:key");\r
+ query.bindValue(":key", key);\r
+ query.bindValue(":value", value);\r
+ if (!query.exec()) {\r
+ logger.log(logger.MEDIUM, "setRecord from sync failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ return;\r
+ }\r
+\r
+ \r
+\r
+\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.sql.runners;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.Tag;\r
+\r
+import cx.fbn.nevernote.sql.driver.NSqlQuery;\r
+import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+\r
+public class RTagTable {\r
+ private final ApplicationLogger logger;\r
+ RDatabaseConnection db;\r
+\r
+ public RTagTable (ApplicationLogger l, RDatabaseConnection d) {\r
+ logger = l;\r
+ db = d;\r
+ }\r
+ // Create the table\r
+ public void createTable() {\r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ logger.log(logger.HIGH, "Creating table Tag...");\r
+ if (!query.exec("Create table Tag (guid varchar primary key, " +\r
+ "parentGuid varchar, sequence integer, hashCode integer, name varchar, isDirty boolean)"))\r
+ logger.log(logger.HIGH, "Table TAG creation FAILED!!!"); \r
+ \r
+ }\r
+ // Drop the table\r
+ public void dropTable() {\r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.exec("Drop table Tag");\r
+ \r
+ }\r
+ // get all tags\r
+ public List<Tag> getAll() {\r
+ \r
+ Tag tempTag;\r
+ List<Tag> index = new ArrayList<Tag>();\r
+ boolean check;\r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ check = query.exec("Select guid, parentGuid, sequence, name"\r
+ +" from Tag");\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "Tag SQL retrieve has failed.");\r
+ logger.log(logger.EXTREME, query.lastError());\r
+ }\r
+ while (query.next()) {\r
+ tempTag = new Tag();\r
+ tempTag.setGuid(query.valueString(0));\r
+ if (query.valueString(1) != null)\r
+ tempTag.setParentGuid(query.valueString(1));\r
+ else\r
+ tempTag.setParentGuid(null);\r
+ int sequence = new Integer(query.valueString(2)).intValue();\r
+ tempTag.setUpdateSequenceNum(sequence);\r
+ tempTag.setName(query.valueString(3));\r
+ index.add(tempTag); \r
+ } \r
+ \r
+ return index;\r
+ }\r
+ public Tag getTag(String guid) {\r
+ Tag tempTag = new Tag(); \r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ if (!query.prepare("Select guid, parentGuid, sequence, name"\r
+ +" from Tag where guid=:guid"))\r
+ logger.log(logger.EXTREME, "Tag select by guid SQL prepare has failed.");\r
+\r
+ query.bindValue(":guid", guid);\r
+ if (!query.exec())\r
+ logger.log(logger.EXTREME, "Tag select by guid SQL exec has failed.");\r
+ \r
+ if (!query.next()) {\r
+ return tempTag;\r
+ }\r
+ tempTag.setGuid(query.valueString(0));\r
+ tempTag.setParentGuid(query.valueString(1));\r
+ int sequence = new Integer(query.valueString(2)).intValue();\r
+ tempTag.setUpdateSequenceNum(sequence);\r
+ tempTag.setName(query.valueString(3));\r
+ return tempTag;\r
+ }\r
+ // Update a tag\r
+ public void updateTag(Tag tempTag, boolean isDirty) {\r
+ boolean check;\r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ check = query.prepare("Update Tag set parentGuid=:parentGuid, sequence=:sequence, "+\r
+ "hashCode=:hashCode, name=:name, isDirty=:isDirty "\r
+ +"where guid=:guid");\r
+ \r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "Tag SQL update prepare has failed.");\r
+ logger.log(logger.EXTREME, query.lastError());\r
+ }\r
+ query.bindValue(":parentGuid", tempTag.getParentGuid());\r
+ query.bindValue(":sequence", tempTag.getUpdateSequenceNum());\r
+ query.bindValue(":hashCode", tempTag.hashCode());\r
+ query.bindValue(":name", tempTag.getName());\r
+ query.bindValue(":isDirty", isDirty);\r
+ query.bindValue(":guid", tempTag.getGuid());\r
+ \r
+ check = query.exec();\r
+ if (!check)\r
+ logger.log(logger.MEDIUM, "Tag Table update failed.");\r
+ \r
+ }\r
+ // Delete a tag\r
+ public void expungeTag(String guid, boolean needsSync) {\r
+ boolean check;\r
+ \r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+\r
+ check = query.prepare("delete from Tag "\r
+ +"where guid=:guid");\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "Tag SQL delete prepare has failed.");\r
+ logger.log(logger.EXTREME, query.lastError());\r
+ }\r
+ query.bindValue(":guid", guid);\r
+ check = query.exec();\r
+ if (!check)\r
+ logger.log(logger.MEDIUM, "Tag delete failed.");\r
+ \r
+ check = query.prepare("delete from NoteTags "\r
+ +"where tagGuid=:guid");\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "NoteTags SQL delete prepare has failed.");\r
+ logger.log(logger.EXTREME, query.lastError());\r
+ }\r
+ \r
+ query.bindValue(":guid", guid);\r
+ check = query.exec();\r
+ if (!check)\r
+ logger.log(logger.MEDIUM, "NoteTags delete failed.");\r
+ \r
+ // Add the work to the parent queue\r
+ if (needsSync) {\r
+ RDeletedTable del = new RDeletedTable(logger, db);\r
+ del.addDeletedItem(guid, "Tag");\r
+ }\r
+ }\r
+ // Save a tag\r
+ public void addTag(Tag tempTag, boolean isDirty) {\r
+ boolean check;\r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ check = query.prepare("Insert Into Tag (guid, parentGuid, sequence, hashCode, name, isDirty)"\r
+ +" Values(:guid, :parentGuid, :sequence, :hashCode, :name, :isDirty)");\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "Tag SQL insert prepare has failed.");\r
+ logger.log(logger.EXTREME, query.lastError());\r
+ }\r
+ query.bindValue(":guid", tempTag.getGuid());\r
+ query.bindValue(":parentGuid", tempTag.getParentGuid());\r
+ query.bindValue(":sequence", tempTag.getUpdateSequenceNum());\r
+ query.bindValue(":hashCode", tempTag.hashCode());\r
+ query.bindValue(":name", tempTag.getName());\r
+ query.bindValue(":isDirty", isDirty);\r
+ \r
+ check = query.exec();\r
+ if (!check) {\r
+ logger.log(logger.MEDIUM, "Tag Table insert failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ }\r
+ // Update a tag's parent\r
+ public void updateTagParent(String guid, String parentGuid) {\r
+ boolean check;\r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ check = query.prepare("Update Tag set parentGuid=:parentGuid where guid=:guid");\r
+ if (!check) {\r
+ logger.log(logger.EXTREME, "Tag SQL tag parent update prepare has failed.");\r
+ logger.log(logger.EXTREME, query.lastError());\r
+ }\r
+\r
+ query.bindValue(":parentGuid", parentGuid);\r
+ query.bindValue(":guid", guid);\r
+ \r
+ check = query.exec();\r
+ if (!check) {\r
+ logger.log(logger.MEDIUM, "Tag parent update failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ }\r
+ //Save tags from Evernote\r
+ public void saveTags(List<Tag> tags) {\r
+ Tag tempTag;\r
+ for (int i=0; i<tags.size(); i++) {\r
+ tempTag = tags.get(i);\r
+ addTag(tempTag, false);\r
+ } \r
+ }\r
+ // Update a tag sequence number\r
+ public void updateTagSequence(String guid, int sequence) {\r
+ boolean check;\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ check = query.prepare("Update Tag set sequence=:sequence where guid=:guid");\r
+ query.bindValue(":sequence", sequence);\r
+ query.bindValue(":guid", guid);\r
+ \r
+ query.exec();\r
+ if (!check) {\r
+ logger.log(logger.MEDIUM, "Tag sequence update failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ \r
+ }\r
+ // Update a tag sequence number\r
+ public void updateTagGuid(String oldGuid, String newGuid) {\r
+ boolean check;\r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ check = query.prepare("Update Tag set guid=:newGuid where guid=:oldGuid");\r
+ query.bindValue(":newGuid", newGuid);\r
+ query.bindValue(":oldGuid", oldGuid);\r
+ query.exec();\r
+ if (!check) {\r
+ logger.log(logger.MEDIUM, "Tag guid update failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ \r
+ check = query.prepare("Update Tag set parentGuid=:newGuid where parentGuid=:oldGuid");\r
+ query.bindValue(":newGuid", newGuid);\r
+ query.bindValue(":oldGuid", oldGuid);\r
+ query.exec();\r
+ if (!check) {\r
+ logger.log(logger.MEDIUM, "Tag guid update failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ \r
+ check = query.prepare("Update NoteTags set tagGuid=:newGuid where tagGuid=:oldGuid");\r
+ query.bindValue(":newGuid", newGuid);\r
+ query.bindValue(":oldGuid", oldGuid);\r
+ query.exec();\r
+ if (!check) {\r
+ logger.log(logger.MEDIUM, "Tag guid update failed for NoteTags.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ \r
+ }\r
+ // Get dirty tags\r
+ public List<Tag> getDirty() {\r
+ Tag tempTag;\r
+ List<Tag> index = new ArrayList<Tag>();\r
+ boolean check;\r
+ \r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ check = query.exec("Select guid, parentGuid, sequence, name"\r
+ +" from Tag where isDirty = true");\r
+ if (!check)\r
+ logger.log(logger.EXTREME, "Tag SQL retrieve has failed.");\r
+ while (query.next()) {\r
+ tempTag = new Tag();\r
+ tempTag.setGuid(query.valueString(0));\r
+ tempTag.setParentGuid(query.valueString(1));\r
+ int sequence = new Integer(query.valueString(2)).intValue();\r
+ tempTag.setUpdateSequenceNum(sequence);\r
+ tempTag.setName(query.valueString(3));\r
+ if (tempTag.getParentGuid() != null && tempTag.getParentGuid().equals(""))\r
+ tempTag.setParentGuid(null);\r
+ index.add(tempTag); \r
+ }\r
+ return index;\r
+ }\r
+ // Find a guid based upon the name\r
+ public String findTagByName(String name) {\r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ query.prepare("Select guid from tag where name=:name");\r
+ query.bindValue(":name", name);\r
+ if (!query.exec())\r
+ logger.log(logger.EXTREME, "Tag SQL retrieve has failed.");\r
+ String val = null;\r
+ if (query.next())\r
+ val = query.valueString(0);\r
+ return val;\r
+ }\r
+ // given a guid, does the tag exist\r
+ public boolean exists(String guid) {\r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ query.prepare("Select guid from tag where guid=:guid");\r
+ query.bindValue(":guid", guid);\r
+ if (!query.exec())\r
+ logger.log(logger.EXTREME, "Tag SQL retrieve has failed.");\r
+ boolean retval = query.next();\r
+ return retval;\r
+ }\r
+ // This is a convience method to check if a tag exists & update/create based upon it\r
+ public void syncTag(Tag tag, boolean isDirty) {\r
+ if (exists(tag.getGuid()))\r
+ updateTag(tag, isDirty);\r
+ else\r
+ addTag(tag, isDirty);\r
+ }\r
+ public void resetDirtyFlag(String guid) {\r
+ \r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ \r
+ query.prepare("Update tag set isdirty=false where guid=:guid");\r
+ query.bindValue(":guid", guid);\r
+ if (!query.exec())\r
+ logger.log(logger.EXTREME, "Error resetting tag dirty field.");\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.sql.runners;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import cx.fbn.nevernote.sql.driver.NSqlQuery;\r
+import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+import cx.fbn.nevernote.utilities.ListManager;\r
+\r
+public class RWatchFolderTable {\r
+ ListManager parent;\r
+ private final ApplicationLogger logger;\r
+ private final RDatabaseConnection db;\r
+\r
+ \r
+ // Constructor\r
+ public RWatchFolderTable(ApplicationLogger l, RDatabaseConnection d) {\r
+ logger = l;\r
+ db = d;\r
+ }\r
+ // Create the table\r
+ public void createTable() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ logger.log(logger.HIGH, "Creating table WatchFolder...");\r
+ if (!query.exec("Create table WatchFolders (folder varchar primary key, notebook varchar," +\r
+ "keep boolean, depth integer)"));\r
+ logger.log(logger.HIGH, "Table WatchFolders creation FAILED!!!"); \r
+ }\r
+ // Drop the table\r
+ public void dropTable() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.exec("Drop table WatchFolders");\r
+ }\r
+ // Add an folder\r
+ public void addWatchFolder(String folder, String notebook, boolean keep, int depth) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("Insert Into WatchFolders (folder, notebook, keep, depth) " +\r
+ "values (:folder, :notebook, :keep, :depth)");\r
+ query.bindValue(":folder", folder);\r
+ query.bindValue(":notebook", notebook);\r
+ query.bindValue(":keep", keep);\r
+ query.bindValue(":depth", depth);\r
+ if (!query.exec()) {\r
+ logger.log(logger.MEDIUM, "Insert into WatchFolder failed.");\r
+ }\r
+ }\r
+ // remove an folder\r
+ public void expungeWatchFolder(String folder) {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("delete from WatchFolders where folder=:folder");\r
+ query.bindValue(":folder", folder);\r
+ if (!query.exec()) {\r
+ logger.log(logger.MEDIUM, "Expunge WatchFolder failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ }\r
+ public void expungeAll() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ if (!query.exec("delete from WatchFolders")) {\r
+ logger.log(logger.MEDIUM, "Expunge all WatchFolder failed.");\r
+ logger.log(logger.MEDIUM, query.lastError());\r
+ }\r
+ }\r
+ public List<WatchFolderRecord> getAll() {\r
+ logger.log(logger.HIGH, "Entering RWatchFolders.getAll");\r
+ \r
+ List<WatchFolderRecord> list = new ArrayList<WatchFolderRecord>();\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.exec("Select folder, (select name from notebook where guid = notebook), keep, depth from WatchFolders");\r
+ while (query.next()) {\r
+ WatchFolderRecord record = new WatchFolderRecord();\r
+ record.folder = query.valueString(0);\r
+ record.notebook = query.valueString(1);\r
+ record.keep = new Boolean(query.valueString(2));\r
+ record.depth = new Integer(query.valueString(3));\r
+ list.add(record);\r
+ }\r
+ logger.log(logger.HIGH, "Leaving RWatchFolders.getAll");\r
+ return list;\r
+\r
+ }\r
+ \r
+ public String getNotebook(String dir) {\r
+ logger.log(logger.HIGH, "Entering RWatchFolders.getNotebook");\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.prepare("Select notebook from WatchFolders where folder=:dir");\r
+ query.bindValue(":dir", dir);\r
+ query.exec();\r
+ String response = null;\r
+ while (query.next()) {\r
+ response = query.valueString(0);\r
+ }\r
+ logger.log(logger.HIGH, "Leaving RWatchFolders.getNotebook");\r
+ return response;\r
+\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.sql.runners;\r
+\r
+import cx.fbn.nevernote.sql.driver.NSqlQuery;\r
+import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+\r
+public class RWordsTable {\r
+ private final ApplicationLogger logger;\r
+ private final RDatabaseConnection db;\r
+\r
+ \r
+ // Constructor\r
+ public RWordsTable(ApplicationLogger l, RDatabaseConnection d) {\r
+ logger = l;\r
+ db = d;\r
+ }\r
+ // Create the table\r
+ public void createTable() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ logger.log(logger.HIGH, "Creating table WORDS ...");\r
+ if (!query.exec("create table words (word varchar, guid varchar, source varchar, weight int, primary key (word, guid, source));")) {\r
+ logger.log(logger.HIGH, "Table WORDS creation FAILED!!!"); \r
+ logger.log(logger.HIGH, query.lastError());\r
+ } \r
+ }\r
+ // Drop the table\r
+ public void dropTable() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.exec("drop table words");\r
+ }\r
+ // Count unindexed notes\r
+ public int getWordCount() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ query.exec("select count(*) from words");\r
+ query.next(); \r
+ int returnValue = new Integer(query.valueString(0));\r
+ return returnValue;\r
+ }\r
+\r
+ // Clear out the word index table\r
+ public void clearWordIndex() {\r
+ NSqlQuery query = new NSqlQuery(db.getConnection());\r
+ logger.log(logger.HIGH, "DELETE FROM WORDS");\r
+ \r
+ boolean check = query.exec("DELETE FROM WORDS");\r
+ if (!check)\r
+ logger.log(logger.HIGH, "Table WORDS clear has FAILED!!!"); \r
+ } \r
+\r
+ //********************************************************************************\r
+ //********************************************************************************\r
+ //* Support adding & deleting index words\r
+ //********************************************************************************\r
+ //********************************************************************************\r
+ public void expungeFromWordIndex(String guid, String type) {\r
+ NSqlQuery deleteWords = new NSqlQuery(db.getConnection());\r
+ if (!deleteWords.prepare("delete from words where guid=:guid and source=:source")) {\r
+ logger.log(logger.EXTREME, "Note SQL select prepare deleteWords has failed.");\r
+ logger.log(logger.MEDIUM, deleteWords.lastError());\r
+ }\r
+ \r
+ deleteWords.bindValue(":guid", guid);\r
+ deleteWords.bindValue(":source", type);\r
+ deleteWords.exec();\r
+\r
+ }\r
+ // Reindex a note\r
+ public synchronized void addWordToNoteIndex(String guid, String word, String type, Integer weight) {\r
+ NSqlQuery findWords = new NSqlQuery(db.getConnection());\r
+ if (!findWords.prepare("Select weight from words where guid=:guid and source=:type and word=:word")) {\r
+ logger.log(logger.MEDIUM, "Prepare failed in addWordToNoteIndex()");\r
+ logger.log(logger.MEDIUM, findWords.lastError());\r
+ }\r
+ \r
+ findWords.bindValue(":guid", guid);\r
+ findWords.bindValue(":type", type);\r
+ findWords.bindValue(":word", word);\r
+ \r
+ boolean addNeeded = true;\r
+ findWords.exec();\r
+ // If we have a match, find out which has the heigher weight & update accordingly\r
+ if (findWords.next()) {\r
+ int recordWeight = new Integer(findWords.valueString(0));\r
+ addNeeded = false;\r
+ if (recordWeight < weight) {\r
+ NSqlQuery updateWord = new NSqlQuery(db.getConnection());\r
+ if (!updateWord.prepare("Update words set weight=:weight where guid=:guid and source=:type and word=:word")) {\r
+ logger.log(logger.MEDIUM, "Prepare failed for find words in addWordToNoteIndex()");\r
+ logger.log(logger.MEDIUM, findWords.lastError()); \r
+ }\r
+ \r
+ updateWord.bindValue(":weight", weight);\r
+ updateWord.bindValue(":guid", guid);\r
+ updateWord.bindValue(":type", type);\r
+ updateWord.bindValue(":word",word);\r
+ updateWord.exec();\r
+ }\r
+ }\r
+ \r
+ \r
+ if (!addNeeded)\r
+ return;\r
+ \r
+ NSqlQuery insertWords = new NSqlQuery(db.getConnection());\r
+ if (!insertWords.prepare("Insert Into Words (word, guid, weight, source)"\r
+ +" Values(:word, :guid, :weight, :type )")) {\r
+ logger.log(logger.EXTREME, "Note SQL select prepare checkWords has failed.");\r
+ logger.log(logger.MEDIUM, insertWords.lastError());\r
+ }\r
+ insertWords.bindValue(":word", word);\r
+ insertWords.bindValue(":guid", guid);\r
+ insertWords.bindValue(":weight", weight);\r
+ insertWords.bindValue(":type", type);\r
+ insertWords.exec();\r
+ }\r
+\r
+\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.sql.runners;\r
+\r
+public class WatchFolderRecord {\r
+ public String folder;\r
+ public String notebook;\r
+ public boolean keep;\r
+ public int depth;\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.threads;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+import java.util.Vector;\r
+import java.util.concurrent.LinkedBlockingQueue;\r
+\r
+import com.evernote.edam.type.Note;\r
+import com.evernote.edam.type.Notebook;\r
+import com.evernote.edam.type.Tag;\r
+import com.trolltech.qt.core.QMutex;\r
+import com.trolltech.qt.core.QObject;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.filters.NotebookCounter;\r
+import cx.fbn.nevernote.filters.TagCounter;\r
+import cx.fbn.nevernote.signals.NotebookSignal;\r
+import cx.fbn.nevernote.signals.TagSignal;\r
+import cx.fbn.nevernote.signals.TrashSignal;\r
+import cx.fbn.nevernote.sql.DatabaseConnection;\r
+import cx.fbn.nevernote.sql.runners.NoteTagsRecord;\r
+import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+import cx.fbn.nevernote.utilities.Pair;\r
+\r
+public class CounterRunner extends QObject implements Runnable {\r
+ \r
+ private final ApplicationLogger logger;\r
+ private volatile boolean keepRunning;\r
+ public int ID;\r
+ public volatile NotebookSignal notebookSignal;\r
+ public volatile TrashSignal trashSignal;\r
+ public volatile TagSignal tagSignal;\r
+ private volatile Vector<String> notebookIndex;\r
+ private volatile Vector<String> noteIndex;\r
+ private volatile Vector<Boolean> activeIndex;\r
+ public int type;\r
+ public QMutex threadLock;\r
+ \r
+ public static int EXIT=0;\r
+ public static int NOTEBOOK=1;\r
+ public static int TAG=2;\r
+ public static int TRASH=3;\r
+ public static int TAG_ALL = 4;\r
+ public static int NOTEBOOK_ALL = 5;\r
+ \r
+ public boolean ready = false;\r
+ public boolean abortCount = false;\r
+ private volatile LinkedBlockingQueue<Integer> readyQueue = new LinkedBlockingQueue<Integer>();\r
+ \r
+ \r
+ //*********************************************\r
+ //* Constructor *\r
+ //*********************************************\r
+ public CounterRunner(String logname, int t) {\r
+ type = t;\r
+ threadLock = new QMutex();\r
+ logger = new ApplicationLogger(logname);\r
+// setAutoDelete(false); \r
+ keepRunning = true;\r
+ notebookSignal = new NotebookSignal();\r
+ tagSignal = new TagSignal();\r
+ trashSignal = new TrashSignal();\r
+ \r
+ notebookIndex = new Vector<String>();\r
+ activeIndex = new Vector<Boolean>();\r
+ noteIndex = new Vector<String>();\r
+ }\r
+ \r
+ \r
+ \r
+ //*********************************************\r
+ //* Run unit *\r
+ //*********************************************\r
+ @Override\r
+ public void run() {\r
+ boolean keepRunning = true;\r
+ \r
+ thread().setPriority(Thread.MIN_PRIORITY);\r
+ while(keepRunning) {\r
+ ready = true;\r
+ try {\r
+ \r
+ type = readyQueue.take();\r
+ threadLock.lock();\r
+ if (type == EXIT)\r
+ keepRunning = false;\r
+ if (type == NOTEBOOK)\r
+ countNotebookResults();\r
+ if (type == NOTEBOOK_ALL)\r
+ countNotebookResults();\r
+ if (type == TAG)\r
+ countTagResults();\r
+ if (type == TAG_ALL)\r
+ countTagResults();\r
+ if (type == TRASH)\r
+ countTrashResults();\r
+ threadLock.unlock();\r
+ } catch (InterruptedException e) {}\r
+ }\r
+ }\r
+ \r
+ \r
+ \r
+ public void setNoteIndex(List<Note> idx) {\r
+ abortCount = true;\r
+ threadLock.lock();\r
+ abortCount = false;\r
+ notebookIndex.clear();\r
+ activeIndex.clear();\r
+ noteIndex.clear();\r
+ if (idx != null) {\r
+ for (int i=0; i<idx.size(); i++) {\r
+ if (Global.showDeleted && !idx.get(i).isActive()) {\r
+ notebookIndex.add(new String(idx.get(i).getNotebookGuid()));\r
+ noteIndex.add(new String(idx.get(i).getGuid()));\r
+ activeIndex.add(new Boolean(idx.get(i).isActive()));\r
+ } \r
+ if (!Global.showDeleted && idx.get(i).isActive()) {\r
+ notebookIndex.add(new String(idx.get(i).getNotebookGuid()));\r
+ noteIndex.add(new String(idx.get(i).getGuid()));\r
+ activeIndex.add(new Boolean(idx.get(i).isActive())); \r
+ }\r
+ }\r
+ }\r
+ threadLock.unlock();\r
+ }\r
+ public void release(int type) {\r
+ readyQueue.add(type);\r
+ }\r
+ \r
+ //*********************************************\r
+ //* Getter & Setter method to tell the thread *\r
+ //* to keep running. *\r
+ //*********************************************\r
+ public void setKeepRunning(boolean b) {\r
+ keepRunning = b;\r
+ }\r
+ public boolean keepRunning() {\r
+ return keepRunning;\r
+ }\r
+ \r
+ \r
+ //*********************************************\r
+ //* Do the actual counting *\r
+ //*********************************************\r
+ private void countNotebookResults() {\r
+ logger.log(logger.EXTREME, "Entering ListManager.countNotebookResults"); \r
+ if (abortCount)\r
+ return;\r
+ DatabaseConnection conn = new DatabaseConnection(logger, Global.tagCounterThreadId);\r
+ List<NotebookCounter> nCounter = new ArrayList<NotebookCounter>();\r
+ if (abortCount)\r
+ return;\r
+ List<Notebook> books = conn.getNotebookTable().getAll();\r
+ \r
+ if (abortCount)\r
+ return;\r
+\r
+ if (type == NOTEBOOK_ALL) {\r
+ for (int i=0; i<books.size(); i++) {\r
+ if (abortCount)\r
+ return;\r
+\r
+ nCounter.add(new NotebookCounter());\r
+ nCounter.get(i).setCount(0);\r
+ nCounter.get(i).setGuid(books.get(i).getGuid());\r
+ }\r
+ if (abortCount)\r
+ return;\r
+ List<Pair<String, Integer>> notebookCounts = conn.getNotebookTable().getNotebookCounts();\r
+ if (abortCount)\r
+ return;\r
+ for (int i=0; notebookCounts != null && i<notebookCounts.size(); i++) {\r
+ if (abortCount)\r
+ return;\r
+ for (int j=0; j<nCounter.size(); j++) {\r
+ if (abortCount)\r
+ return;\r
+\r
+ if (notebookCounts.get(i).getFirst().equals(nCounter.get(j).getGuid())) {\r
+ nCounter.get(j).setCount(notebookCounts.get(i).getSecond());\r
+ j=nCounter.size();\r
+ }\r
+ }\r
+ }\r
+ if (abortCount)\r
+ return;\r
+\r
+ notebookSignal.countsChanged.emit(nCounter);\r
+ return;\r
+ }\r
+ \r
+ if (abortCount)\r
+ return;\r
+ for (int i=notebookIndex.size()-1; i>=0 && keepRunning; i--) {\r
+ if (abortCount)\r
+ return;\r
+ boolean notebookFound = false;\r
+ for (int j=0; j<nCounter.size() && keepRunning; j++) {\r
+ if (abortCount)\r
+ return;\r
+ if (nCounter.get(j).getGuid().equals(notebookIndex.get(i))) {\r
+ notebookFound = true;\r
+ if (activeIndex.get(i)) {\r
+ int c = nCounter.get(j).getCount()+1;\r
+ nCounter.get(j).setCount(c);\r
+ }\r
+ j=nCounter.size();\r
+ }\r
+ }\r
+ if (abortCount)\r
+ return;\r
+ if (!notebookFound) {\r
+ NotebookCounter newCounter = new NotebookCounter();\r
+ newCounter.setGuid(notebookIndex.get(i));\r
+ newCounter.setCount(1);\r
+ nCounter.add(newCounter);\r
+ }\r
+ }\r
+ if (abortCount)\r
+ return;\r
+ notebookSignal.countsChanged.emit(nCounter);\r
+ logger.log(logger.EXTREME, "Leaving ListManager.countNotebookResults()");\r
+ }\r
+ \r
+ \r
+ private void countTagResults() {\r
+ logger.log(logger.EXTREME, "Entering ListManager.countTagResults"); \r
+ DatabaseConnection conn = new DatabaseConnection(logger, Global.tagCounterThreadId);\r
+ List<TagCounter> counter = new ArrayList<TagCounter>();\r
+ List<Tag> allTags = conn.getTagTable().getAll();\r
+ \r
+ if (abortCount) \r
+ return;\r
+ if (allTags == null)\r
+ return;\r
+ for (int k=0; k<allTags.size() && keepRunning; k++) {\r
+ TagCounter newCounter = new TagCounter();\r
+ newCounter.setGuid(allTags.get(k).getGuid());\r
+ newCounter.setCount(0);\r
+ counter.add(newCounter);\r
+ }\r
+ \r
+ if (type == TAG_ALL) {\r
+ List<Pair<String, Integer>> tagCounts = conn.getNoteTable().noteTagsTable.getTagCounts();\r
+ if (abortCount)\r
+ return;\r
+ for (int i=0; tagCounts != null && i<tagCounts.size(); i++) {\r
+ if (abortCount)\r
+ return;\r
+ for (int j=0; j<counter.size(); j++) {\r
+ if (abortCount)\r
+ return;\r
+ if (tagCounts.get(i).getFirst().equals(counter.get(j).getGuid())) {\r
+ if (abortCount)\r
+ return;\r
+ counter.get(j).setCount(tagCounts.get(i).getSecond());\r
+ j=counter.size();\r
+ }\r
+ }\r
+ }\r
+ if (abortCount)\r
+ return;\r
+ tagSignal.countsChanged.emit(counter);\r
+ return;\r
+ }\r
+ \r
+ \r
+ if (abortCount)\r
+ return;\r
+ List<NoteTagsRecord> tags = conn.getNoteTable().noteTagsTable.getAllNoteTags();\r
+ for (int i=noteIndex.size()-1; i>=0; i--) {\r
+ if (abortCount)\r
+ return;\r
+ String note = noteIndex.get(i);\r
+ for (int x=0; tags!= null && x<tags.size() && keepRunning; x++) {\r
+ if (abortCount)\r
+ return;\r
+ String tag = tags.get(x).tagGuid;\r
+ for (int j=0; j<counter.size() && keepRunning; j++) {\r
+ if (abortCount)\r
+ return;\r
+ if (counter.get(j).getGuid().equals(tag) && note.equals(tags.get(x).noteGuid)) {\r
+ int c = counter.get(j).getCount()+1;\r
+ counter.get(j).setCount(c);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ if (abortCount)\r
+ return;\r
+ tagSignal.countsChanged.emit(counter);\r
+ logger.log(logger.EXTREME, "Leaving ListManager.countTagResults()");\r
+ }\r
+ \r
+ \r
+ private void countTrashResults() {\r
+ logger.log(logger.EXTREME, "Entering CounterRunner.countTrashResults()"); \r
+ DatabaseConnection conn = new DatabaseConnection(logger, Global.trashCounterThreadId);\r
+ if (abortCount)\r
+ return;\r
+\r
+ Integer tCounter = conn.getNoteTable().getDeletedCount();\r
+ \r
+ if (abortCount)\r
+ return;\r
+\r
+ trashSignal.countChanged.emit(tCounter);\r
+ logger.log(logger.EXTREME, "Leaving CounterRunner.countTrashResults()");\r
+ }\r
+\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.threads;\r
+\r
+import java.util.Vector;\r
+import java.util.concurrent.LinkedBlockingQueue;\r
+\r
+import com.trolltech.qt.core.QObject;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.signals.DBRunnerSignal;\r
+import cx.fbn.nevernote.sql.requests.DBRunnerRequest;\r
+import cx.fbn.nevernote.sql.requests.DatabaseRequest;\r
+import cx.fbn.nevernote.sql.requests.DeletedItemRequest;\r
+import cx.fbn.nevernote.sql.requests.EnSearchRequest;\r
+import cx.fbn.nevernote.sql.requests.InvalidXMLRequest;\r
+import cx.fbn.nevernote.sql.requests.NoteRequest;\r
+import cx.fbn.nevernote.sql.requests.NoteTagsRequest;\r
+import cx.fbn.nevernote.sql.requests.NotebookRequest;\r
+import cx.fbn.nevernote.sql.requests.ResourceRequest;\r
+import cx.fbn.nevernote.sql.requests.SavedSearchRequest;\r
+import cx.fbn.nevernote.sql.requests.SyncRequest;\r
+import cx.fbn.nevernote.sql.requests.TagRequest;\r
+import cx.fbn.nevernote.sql.requests.WatchFolderRequest;\r
+import cx.fbn.nevernote.sql.requests.WordRequest;\r
+import cx.fbn.nevernote.sql.runners.RDatabaseConnection;\r
+import cx.fbn.nevernote.sql.runners.REnSearch;\r
+import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+\r
+public class DBRunner extends QObject implements Runnable {\r
+ private ApplicationLogger logger;\r
+ \r
+ private RDatabaseConnection conn;\r
+ private volatile LinkedBlockingQueue<DBRunnerRequest> workQueue;\r
+ \r
+ public volatile Vector<DBRunnerRequest> genericResponse;\r
+ public volatile Vector<DeletedItemRequest> deletedItemResponse;\r
+ public volatile Vector<NotebookRequest> notebookResponse;\r
+ public volatile Vector<TagRequest> tagResponse;\r
+ public volatile Vector<SavedSearchRequest> savedSearchResponse;\r
+ public volatile Vector<NoteRequest> noteResponse;\r
+ public volatile Vector<ResourceRequest> resourceResponse;\r
+ public volatile Vector<NoteTagsRequest> noteTagsResponse;\r
+ public volatile Vector<EnSearchRequest> enSearchResponse;\r
+ public volatile Vector<WatchFolderRequest> watchFolderResponse;\r
+ public volatile Vector<WordRequest> wordResponse;\r
+ public volatile Vector<InvalidXMLRequest> invalidXMLResponse;\r
+ public volatile Vector<SyncRequest> syncResponse;\r
+ \r
+ // priority queues\r
+ public volatile Vector<DBRunnerRequest> user;\r
+ public volatile Vector<DBRunnerRequest> background;\r
+ public volatile Vector<DBRunnerRequest> discretionary;\r
+ private static int MAX_EMPTY_QUEUE_COUNT = 100;\r
+ private static int MAX_QUEUED_WAITING = 100;\r
+\r
+ \r
+ public DBRunnerSignal dbSignal;\r
+ public boolean keepRunning;\r
+ private final String url;\r
+ private final String cypherPassword;\r
+ private final String userid;\r
+ private final String userPassword;\r
+ \r
+ public DBRunner(String u, String id, String pass, String cypher) {\r
+ workQueue=new LinkedBlockingQueue<DBRunnerRequest>(MAX_QUEUED_WAITING);\r
+\r
+ url=u;\r
+ userid = id;\r
+ userPassword = pass;\r
+ cypherPassword=cypher;\r
+ \r
+ //***********************************************\r
+ //* These are the priority queues. \r
+ //***********************************************\r
+ user = new Vector<DBRunnerRequest>();\r
+ background = new Vector<DBRunnerRequest>();\r
+ discretionary = new Vector<DBRunnerRequest>();\r
+\r
+ //***********************************************\r
+ //* These are database response queues. Each\r
+ //* thread has its own individual queue and \r
+ //* will access it based upod it's individual\r
+ //* thread ID\r
+ //***********************************************\r
+ \r
+ genericResponse = new Vector<DBRunnerRequest>();\r
+ for (int i=0; i<Global.dbThreadId; i++)\r
+ genericResponse.add(new DBRunnerRequest());\r
+ \r
+ deletedItemResponse = new Vector<DeletedItemRequest>();\r
+ for (int i=0; i<Global.dbThreadId; i++)\r
+ deletedItemResponse.add(new DeletedItemRequest());\r
+ \r
+ notebookResponse = new Vector<NotebookRequest>();\r
+ for (int i=0; i<Global.dbThreadId; i++)\r
+ notebookResponse.add(new NotebookRequest());\r
+\r
+ tagResponse = new Vector<TagRequest>();\r
+ for (int i=0; i<Global.dbThreadId; i++)\r
+ tagResponse.add(new TagRequest());\r
+\r
+ savedSearchResponse = new Vector<SavedSearchRequest>();\r
+ for (int i=0; i<Global.dbThreadId; i++)\r
+ savedSearchResponse.add(new SavedSearchRequest());\r
+\r
+ noteResponse = new Vector<NoteRequest>();\r
+ for (int i=0; i<Global.dbThreadId; i++)\r
+ noteResponse.add(new NoteRequest());\r
+ \r
+ resourceResponse = new Vector<ResourceRequest>();\r
+ for (int i=0; i<Global.dbThreadId; i++)\r
+ resourceResponse.add(new ResourceRequest());\r
+ \r
+ noteTagsResponse = new Vector<NoteTagsRequest>();\r
+ for (int i=0; i<Global.dbThreadId; i++)\r
+ noteTagsResponse.add(new NoteTagsRequest());\r
+ \r
+ enSearchResponse = new Vector<EnSearchRequest>();\r
+ for (int i=0; i<Global.dbThreadId; i++)\r
+ enSearchResponse.add(new EnSearchRequest());\r
+ \r
+ watchFolderResponse = new Vector<WatchFolderRequest>();\r
+ for (int i=0; i<Global.dbThreadId; i++)\r
+ watchFolderResponse.add(new WatchFolderRequest());\r
+ \r
+ wordResponse = new Vector<WordRequest>();\r
+ for (int i=0; i<Global.dbThreadId; i++)\r
+ wordResponse.add(new WordRequest());\r
+\r
+ invalidXMLResponse = new Vector<InvalidXMLRequest>();\r
+ for (int i=0; i<Global.dbThreadId; i++)\r
+ invalidXMLResponse.add(new InvalidXMLRequest());\r
+ \r
+ syncResponse = new Vector<SyncRequest>();\r
+ for (int i=0; i<Global.dbThreadId; i++)\r
+ syncResponse.add(new SyncRequest());\r
+\r
+\r
+ \r
+ dbSignal = new DBRunnerSignal();\r
+ \r
+ }\r
+\r
+ \r
+ public void run() {\r
+ logger = new ApplicationLogger("dbrunner.log");\r
+ conn = new RDatabaseConnection(logger, "dbrunner");\r
+ conn.dbSetup(url,userid, userPassword, cypherPassword);\r
+ \r
+ thread().setPriority(Thread.NORM_PRIORITY);\r
+ \r
+ \r
+ dbSignal.start.connect(this, "releaseThread()");\r
+ \r
+ keepRunning=true;\r
+ while(keepRunning) {\r
+ try {\r
+ DBRunnerRequest request;\r
+ //System.gc();\r
+ request = workQueue.take();\r
+ logger.log(logger.EXTREME, "Work pulled. Current size is now " +workQueue.size());\r
+ prioritizeWork(request); \r
+ \r
+ // Now the queue should be empty. \r
+ // Try to do work\r
+ while (user.size() > 0 || background.size() > 0 || discretionary.size() > 0) {\r
+ if (workQueue.size() > 0)\r
+ emptyQueue();\r
+ if (user.size() > 0)\r
+ releaseWork(user);\r
+ else\r
+ if (background.size() > 0)\r
+ releaseWork(background);\r
+ else\r
+ releaseWork(discretionary);\r
+ }\r
+ } catch (InterruptedException e) {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+ return;\r
+ }\r
+ \r
+ @SuppressWarnings("unused")\r
+ private void releaseThread() {\r
+ Global.dbContinue();\r
+ }\r
+ \r
+ private void emptyQueue() {\r
+ logger.log(logger.EXTREME, "Draining queue. Current size " +workQueue.size());\r
+ int count = 0;\r
+ while (workQueue.size() > 0 && count > MAX_EMPTY_QUEUE_COUNT) {\r
+ DBRunnerRequest request;\r
+ try {\r
+ request = workQueue.take();\r
+ prioritizeWork(request);\r
+ } catch (InterruptedException e) {}\r
+ count++;\r
+ logger.log(logger.EXTREME, "Draining queue - counter is now " +count);\r
+ }\r
+ }\r
+ \r
+ private void releaseWork(Vector<DBRunnerRequest> queue) {\r
+ logger.log(logger.EXTREME, "Releasing work. Current size is " +workQueue.size());\r
+ while(queue.size() > 0) {\r
+ DBRunnerRequest request = queue.get(0);\r
+ queue.remove(0);\r
+ doWork(request);\r
+ }\r
+ logger.log(logger.EXTREME, "Leaving release queue.");\r
+ }\r
+\r
+ private void prioritizeWork(DBRunnerRequest request) {\r
+ logger.log(logger.EXTREME, "Entering prioritizeWork()");\r
+ if (request.requestor_id == Global.mainThreadId || \r
+ (request.category == DBRunnerRequest.NOTE) && (request.type == NoteRequest.Set_Index_Needed)) {\r
+ user.add(request);\r
+ return;\r
+ } \r
+ if (request.requestor_id == Global.tagCounterThreadId) {\r
+ background.add(request);\r
+ return;\r
+ }\r
+ if (request.requestor_id == Global.trashCounterThreadId) {\r
+ discretionary.add(request);\r
+ return;\r
+ }\r
+ \r
+ // Anything remaining should be index threads, put\r
+ // them in a low priority\r
+ discretionary.add(request);\r
+ logger.log(logger.EXTREME, "Leaving prioritizeWork()");\r
+ }\r
+ \r
+ \r
+ public synchronized void addWork(DBRunnerRequest s) {\r
+ while(!workQueue.offer(s));\r
+ }\r
+ \r
+ private void doWork(DBRunnerRequest s) {\r
+ if (s.category == DBRunnerRequest.GENERIC){\r
+ String work = new String(s.request);\r
+ if (work.equalsIgnoreCase("shutdown"))\r
+ keepRunning = false;\r
+ } else if (s.category == DBRunnerRequest.DATABASE){\r
+ DatabaseRequest work = copyDatabaseRequest(s);\r
+ doDatabaseRequest(work);\r
+ } else if (s.category == DBRunnerRequest.DELETED_ITEM) {\r
+ DeletedItemRequest work = copyDeletedItemRequest(s);\r
+ Global.dbrunnerWorkLock.unlock(); \r
+ doDeletedItemRequest(work);\r
+ } else if (s.category == DBRunnerRequest.NOTEBOOK) {\r
+ NotebookRequest work = copyNotebookRequest(s);\r
+ doNotebookRequest(work);\r
+ } else if (s.category == DBRunnerRequest.TAG ) {\r
+ TagRequest work = copyTagRequest(s);\r
+ doTagRequest(work);\r
+ } else if (s.category == DBRunnerRequest.SAVED_SEARCH ) {\r
+ SavedSearchRequest work = copySavedSearchRequest(s);\r
+ doSavedSearchRequest(work);\r
+ } else if (s.category == DBRunnerRequest.NOTE) {\r
+ NoteRequest work = copyNoteRequest(s);\r
+ doNoteRequest(work);\r
+ } else if (s.category == DBRunnerRequest.RESOURCE) {\r
+ ResourceRequest work = copyResourceRequest(s);\r
+ doResourceRequest(work);\r
+ } else if (s.category == DBRunnerRequest.NOTE_TAGS) {\r
+ NoteTagsRequest work = copyNoteTagsRequest(s);\r
+ doNoteTagsRequest(work);\r
+ } else if (s.category == DBRunnerRequest.ENSEARCH) {\r
+ EnSearchRequest work = copyEnSearchRequest(s);\r
+ doEnSearchRequest(work);\r
+ } else if (s.category == DBRunnerRequest.WATCH_FOLDER) {\r
+ WatchFolderRequest work = copyWatchFolderRequest(s);\r
+ doWatchFolderRequest(work);\r
+ } else if (s.category == DBRunnerRequest.WORD) {\r
+ WordRequest work = copyWordRequest(s);\r
+ doWordRequest(work);\r
+ } else if (s.category == DBRunnerRequest.Invalid_XML) {\r
+ InvalidXMLRequest work = copyInvalidXMLRequest(s);\r
+ doInvalidXMLRequest(work);\r
+ } else if (s.category == DBRunnerRequest.Sync) {\r
+ SyncRequest work = copySyncRequest(s);\r
+ doSyncRequest(work);\r
+ } \r
+ return;\r
+ }\r
+ \r
+ \r
+ //*********************************************\r
+ //* If the requestor is expecting a response, *\r
+ //* release them so they can pick it up. *\r
+ //*********************************************\r
+ private void release(int i) {\r
+ logger.log(logger.EXTREME, "Releasing "+i);\r
+ Global.dbClientContinue(i);\r
+// if (i == Global.mainThreadId)\r
+// Global.mainThreadWait.wakeOne();\r
+ }\r
+ \r
+ //**************************************\r
+ //* Copy items off the work queue so *\r
+ //* the resources can be freed up. *\r
+ //**************************************\r
+ private DatabaseRequest copyDatabaseRequest(DBRunnerRequest n) {\r
+ DatabaseRequest request = new DatabaseRequest();\r
+ DatabaseRequest old = (DatabaseRequest) n;\r
+ request = old.copy();\r
+ return request;\r
+ }\r
+ private SyncRequest copySyncRequest(DBRunnerRequest n) {\r
+ SyncRequest request = new SyncRequest();\r
+ SyncRequest old = (SyncRequest) n;\r
+ request = old.copy();\r
+ return request;\r
+ }\r
+ private DeletedItemRequest copyDeletedItemRequest(DBRunnerRequest r) {\r
+ DeletedItemRequest request = new DeletedItemRequest();\r
+ DeletedItemRequest old = (DeletedItemRequest) r;\r
+ request = old.copy();\r
+ return request;\r
+ } \r
+ private NotebookRequest copyNotebookRequest(DBRunnerRequest n) {\r
+ NotebookRequest request = new NotebookRequest();\r
+ NotebookRequest old = (NotebookRequest) n;\r
+ request = old.copy();\r
+ return request;\r
+ }\r
+ private TagRequest copyTagRequest(DBRunnerRequest n) {\r
+ TagRequest request = new TagRequest();\r
+ TagRequest old = (TagRequest) n;\r
+ request = old.copy();\r
+ return request;\r
+ }\r
+ private SavedSearchRequest copySavedSearchRequest(DBRunnerRequest n) {\r
+ SavedSearchRequest request = new SavedSearchRequest();\r
+ SavedSearchRequest old = (SavedSearchRequest) n;\r
+ request = old.copy();\r
+ return request;\r
+ }\r
+ private NoteRequest copyNoteRequest(DBRunnerRequest n) {\r
+ NoteRequest request = new NoteRequest();\r
+ NoteRequest old = (NoteRequest) n;\r
+ request = old.copy();\r
+ return request;\r
+ }\r
+ private ResourceRequest copyResourceRequest(DBRunnerRequest n) {\r
+ ResourceRequest request = new ResourceRequest();\r
+ ResourceRequest old = (ResourceRequest) n;\r
+ request = old.copy();\r
+ return request;\r
+ }\r
+ private NoteTagsRequest copyNoteTagsRequest(DBRunnerRequest n) {\r
+ NoteTagsRequest request = new NoteTagsRequest();\r
+ NoteTagsRequest old = (NoteTagsRequest) n;\r
+ request = old.copy();\r
+ return request;\r
+ }\r
+ private EnSearchRequest copyEnSearchRequest(DBRunnerRequest n) {\r
+ EnSearchRequest request = new EnSearchRequest();\r
+ EnSearchRequest old = (EnSearchRequest) n;\r
+ request = old.copy();\r
+ return request;\r
+ }\r
+ private WatchFolderRequest copyWatchFolderRequest(DBRunnerRequest n) {\r
+ WatchFolderRequest request = new WatchFolderRequest();\r
+ WatchFolderRequest old = (WatchFolderRequest) n;\r
+ request = old.copy();\r
+ return request;\r
+ }\r
+ private WordRequest copyWordRequest(DBRunnerRequest n) {\r
+ WordRequest request = new WordRequest();\r
+ WordRequest old = (WordRequest) n;\r
+ request = old.copy();\r
+ return request;\r
+ }\r
+ private InvalidXMLRequest copyInvalidXMLRequest(DBRunnerRequest n) {\r
+ InvalidXMLRequest request = new InvalidXMLRequest();\r
+ InvalidXMLRequest old = (InvalidXMLRequest) n;\r
+ request = old.copy();\r
+ return request;\r
+ } \r
+ //**************************************\r
+ //* Database requests *\r
+ //**************************************\r
+ private void doDatabaseRequest(DatabaseRequest r) {\r
+ if (r.type == DatabaseRequest.Create_Tables) {\r
+ conn.createTables();\r
+ release(r.requestor_id);\r
+ return;\r
+ } else if (r.type == DatabaseRequest.Drop_Tables) {\r
+ conn.dropTables();\r
+ return;\r
+ } else if (r.type == DatabaseRequest.Compact) {\r
+ conn.compactDatabase();\r
+ release(r.requestor_id);\r
+ return;\r
+ } else if (r.type == DatabaseRequest.Setup) {\r
+ conn.dbSetup(url,userid, userPassword, cypherPassword);\r
+ return;\r
+ } else if (r.type == DatabaseRequest.Shutdown) {\r
+ conn.dbShutdown();\r
+ keepRunning = false;\r
+ return;\r
+ } else if (r.type == DatabaseRequest.Execute_Sql) {\r
+ conn.executeSql(r.string1);\r
+ release(r.requestor_id);\r
+ return;\r
+ } else if (r.type == DatabaseRequest.Execute_Sql_Index) {\r
+ release(r.requestor_id);\r
+ return;\r
+ } else if (r.type == DatabaseRequest.Backup_Database) {\r
+ conn.backupDatabase();\r
+ release(r.requestor_id);\r
+ return;\r
+ }\r
+ return;\r
+ }\r
+ \r
+ //**************************************\r
+ //* Notebook database requests *\r
+ //**************************************\r
+ private void doNotebookRequest(NotebookRequest n) {\r
+ logger.log(logger.EXTREME, "Notebook request: " +n.category + " " + n.type + " from " +n.requestor_id);\r
+ if (n.type == NotebookRequest.Create_Table) {\r
+ conn.getNotebookTable().createTable();\r
+ }\r
+ if (n.type == NotebookRequest.Drop_Table) {\r
+ conn.getNotebookTable().dropTable();\r
+ }\r
+ if (n.type == NotebookRequest.Expunge_Notebook) {\r
+ conn.getNotebookTable().expungeNotebook(n.string1, n.bool1);\r
+ }\r
+ if (n.type == NotebookRequest.Add_Notebook) {\r
+ conn.getNotebookTable().addNotebook(n.notebook, n.bool1, n.bool2);\r
+ }\r
+ if (n.type == NotebookRequest.Update_Notebook) {\r
+ conn.getNotebookTable().updateNotebook(n.notebook, n.bool1);\r
+ }\r
+ if (n.type == NotebookRequest.Sync_Notebook) {\r
+ conn.getNotebookTable().syncNotebook(n.notebook, n.bool1);\r
+ }\r
+ if (n.type == NotebookRequest.Get_All) {\r
+ notebookResponse.get(n.requestor_id).responseNotebooks = conn.getNotebookTable().getAll();\r
+ release(n.requestor_id);\r
+ }\r
+ if (n.type == NotebookRequest.Get_All_Local) {\r
+ notebookResponse.get(n.requestor_id).responseNotebooks = conn.getNotebookTable().getAllLocal();\r
+ release(n.requestor_id);\r
+ }\r
+ if (n.type == NotebookRequest.Get_All_Archived) {\r
+ notebookResponse.get(n.requestor_id).responseNotebooks = conn.getNotebookTable().getAllArchived();\r
+ release(n.requestor_id);\r
+ }\r
+ if (n.type == NotebookRequest.Get_Dirty) {\r
+ notebookResponse.get(n.requestor_id).responseNotebooks = conn.getNotebookTable().getDirty();\r
+ release(n.requestor_id);\r
+ }\r
+ if (n.type == NotebookRequest.Set_Archived) {\r
+ conn.getNotebookTable().setArchived(n.string1, n.bool1);\r
+ }\r
+ if (n.type == NotebookRequest.Is_Notebook_Local) {\r
+ notebookResponse.get(n.requestor_id).responseBoolean = conn.getNotebookTable().isNotebookLocal(n.string1);\r
+ release(n.requestor_id);\r
+ }\r
+ if (n.type == NotebookRequest.Reset_Dirty) {\r
+ conn.getNotebookTable().resetDirtyFlag(n.string1);\r
+ }\r
+ if (n.type == NotebookRequest.Find_Note_By_Name) {\r
+ notebookResponse.get(n.requestor_id).responseString = conn.getNotebookTable().findNotebookByName(n.string1);\r
+ release(n.requestor_id);\r
+ }\r
+ if (n.type == NotebookRequest.Update_Notebook_Guid) {\r
+ conn.getNotebookTable().updateNotebookGuid(n.string1, n.string2);\r
+ }\r
+ if (n.type == NotebookRequest.Update_Notebook_Sequence) {\r
+ conn.getNotebookTable().updateNotebookSequence(n.string1, n.int1);\r
+ }\r
+ if (n.type == NotebookRequest.Notebook_Counts) {\r
+ notebookResponse.get(n.requestor_id).responseCounts = conn.getNotebookTable().getNotebookCounts();\r
+ release(n.requestor_id);\r
+ }\r
+ logger.log(logger.EXTREME, "End of Notebook request");\r
+ return;\r
+ }\r
+\r
+ //******************************************\r
+ //* Deleted (expunged) database requests *\r
+ //******************************************\r
+ private void doDeletedItemRequest(DeletedItemRequest r) {\r
+ logger.log(logger.EXTREME, "DeletedItem request: " +r.category + " " + r.type + " from " +r.requestor_id);\r
+ if (r.type == DeletedItemRequest.Create_Table) {\r
+ conn.getDeletedTable().createTable();\r
+ } else if (r.type == DeletedItemRequest.Drop_Table) {\r
+ conn.getDeletedTable().dropTable();\r
+ } else if (r.type == DeletedItemRequest.Expunge_All) {\r
+ conn.getDeletedTable().expungeAllDeletedRecords();\r
+ } else if (r.type == DeletedItemRequest.Add_Deleted_Item) {\r
+ conn.getDeletedTable().addDeletedItem(r.string1, r.string2);\r
+ } else if (r.type == DeletedItemRequest.Get_All) {\r
+ deletedItemResponse.get(r.requestor_id).responseDeletedRecords = conn.getDeletedTable().getAllDeleted();\r
+ release(r.requestor_id);\r
+ } else if (r.type == DeletedItemRequest.Expunge_Record) {\r
+ conn.getDeletedTable().expungeDeletedItem(r.string1, r.string2);\r
+ release(r.requestor_id);\r
+ }\r
+ logger.log(logger.EXTREME, "End Of DeletedItem request");\r
+ return;\r
+ }\r
+\r
+ //******************************************\r
+ //* Tag database requests *\r
+ //******************************************\r
+ private void doTagRequest(TagRequest r) {\r
+ logger.log(logger.EXTREME, "Tag request: " +r.category + " " + r.type + " from " +r.requestor_id);\r
+ if (r.type == TagRequest.Create_Table) {\r
+ conn.getTagTable().createTable();\r
+ } else if (r.type == TagRequest.Drop_Table) {\r
+ conn.getTagTable().dropTable();\r
+ } else if (r.type == TagRequest.Add_Tag) {\r
+ conn.getTagTable().addTag(r.tag, r.bool1);\r
+ } else if (r.type == TagRequest.Expunge_Tag) {\r
+ conn.getTagTable().expungeTag(r.string1, r.bool1);\r
+ } else if (r.type == TagRequest.Exists) {\r
+ tagResponse.get(r.requestor_id).responseBool = conn.getTagTable().exists(r.string1);\r
+ release(r.requestor_id);\r
+ } else if (r.type == TagRequest.Find_Tag_By_Name) {\r
+ tagResponse.get(r.requestor_id).responseString = conn.getTagTable().findTagByName(r.string1);\r
+ release(r.requestor_id);\r
+ } else if (r.type == TagRequest.Get_All) {\r
+ tagResponse.get(r.requestor_id).responseTags = conn.getTagTable().getAll();\r
+ release(r.requestor_id);\r
+ } else if (r.type == TagRequest.Get_Dirty) {\r
+ tagResponse.get(r.requestor_id).responseTags = conn.getTagTable().getDirty();\r
+ release(r.requestor_id);\r
+ } else if (r.type == TagRequest.Get_Tag) {\r
+ tagResponse.get(r.requestor_id).responseTag = conn.getTagTable().getTag(r.string1);\r
+ release(r.requestor_id);\r
+ } else if (r.type == TagRequest.Reset_Dirty_Flag) {\r
+ conn.getTagTable().resetDirtyFlag(r.string1);\r
+ } else if (r.type == TagRequest.Save_Tags) {\r
+ conn.getTagTable().saveTags(r.tags);\r
+ } else if (r.type == TagRequest.Sync_Tag) {\r
+ conn.getTagTable().syncTag(r.tag, r.bool1);\r
+ } else if (r.type == TagRequest.Update_Parent) {\r
+ conn.getTagTable().updateTagParent(r.string1, r.string2);\r
+ } else if (r.type == TagRequest.Update_Tag) {\r
+ conn.getTagTable().updateTag(r.tag, r.bool1);\r
+ } else if (r.type == TagRequest.Update_Tag_Guid) {\r
+ conn.getTagTable().updateTagGuid(r.string1, r.string2);\r
+ } else if (r.type == TagRequest.Update_Tag_Sequence) {\r
+ conn.getTagTable().updateTagSequence(r.string1, r.int1);\r
+ } \r
+ logger.log(logger.EXTREME, "End of tag request");\r
+ return;\r
+ }\r
+\r
+ //******************************************\r
+ //* Saved Search database requests *\r
+ //******************************************\r
+ private void doSavedSearchRequest(SavedSearchRequest r) {\r
+ logger.log(logger.EXTREME, "Saved Search request: " +r.category + " " + r.type + " from " +r.requestor_id);\r
+ if (r.type == SavedSearchRequest.Create_Table) {\r
+ conn.getSavedSearchTable().createTable();\r
+ } else if (r.type == SavedSearchRequest.Drop_Table) {\r
+ conn.getSavedSearchTable().dropTable();\r
+ } else if (r.type == SavedSearchRequest.Add_Saved_Search) {\r
+ conn.getSavedSearchTable().addSavedSearch(r.savedSearch, r.bool1);\r
+ } else if (r.type == SavedSearchRequest.Exists) {\r
+ savedSearchResponse.get(r.requestor_id).responseBoolean = conn.getSavedSearchTable().exists(r.string1);\r
+ release(r.requestor_id);\r
+ } else if (r.type == SavedSearchRequest.Expunge_Saved_Search) {\r
+ conn.getSavedSearchTable().expungeSavedSearch(r.string1, r.bool1);\r
+ } else if (r.type == SavedSearchRequest.Find_Saved_Search_By_Name) {\r
+ savedSearchResponse.get(r.requestor_id).responseString = conn.getSavedSearchTable().findSavedSearchByName(r.string1);\r
+ release(r.requestor_id);\r
+ } else if (r.type == SavedSearchRequest.Get_All) {\r
+ savedSearchResponse.get(r.requestor_id).responseSavedSearches = conn.getSavedSearchTable().getAll();\r
+ release(r.requestor_id);\r
+ } else if (r.type == SavedSearchRequest.Get_Dirty) {\r
+ savedSearchResponse.get(r.requestor_id).responseSavedSearches = conn.getSavedSearchTable().getDirty();\r
+ release(r.requestor_id);\r
+ } else if (r.type == SavedSearchRequest.Get_Saved_Search) {\r
+ savedSearchResponse.get(r.requestor_id).responseSavedSearch = conn.getSavedSearchTable().getSavedSearch(r.string1);\r
+ release(r.requestor_id);\r
+ } else if (r.type == SavedSearchRequest.Sync_Saved_Search) {\r
+ conn.getSavedSearchTable().syncSavedSearch(r.savedSearch, r.bool1);\r
+ } else if (r.type == SavedSearchRequest.Update_Saved_Search) {\r
+ conn.getSavedSearchTable().updateSavedSearch(r.savedSearch, r.bool1);\r
+ } else if (r.type == SavedSearchRequest.Reset_Dirty_Flag) {\r
+ conn.getSavedSearchTable().resetDirtyFlag(r.string1);\r
+ } \r
+ logger.log(logger.EXTREME, "End of saved search request");\r
+ return;\r
+ }\r
+\r
+ //******************************************\r
+ //* Saved Search database requests *\r
+ //******************************************\r
+ private void doNoteRequest(NoteRequest r) {\r
+ logger.log(logger.EXTREME, "Note request: " +r.category + " " + r.type + " from " +r.requestor_id);\r
+ if (r.type == NoteRequest.Create_Table) {\r
+ conn.getNoteTable().createTable();\r
+ } else if (r.type == NoteRequest.Drop_Table) {\r
+ conn.getNoteTable().dropTable();\r
+ } else if (r.type == NoteRequest.Get_Note) {\r
+ noteResponse.get(r.requestor_id).responseNote = conn.getNoteTable().getNote(r.string1, r.bool1, r.bool2, r.bool3, r.bool4, r.bool5);\r
+ logger.log(logger.EXTREME, "Releasing " +r.requestor_id);\r
+ release(r.requestor_id);\r
+ } else if (r.type == NoteRequest.Add_Note) {\r
+ conn.getNoteTable().addNote(r.note, r.bool1);\r
+ } else if (r.type == NoteRequest.Update_Note_Title) {\r
+ conn.getNoteTable().updateNoteTitle(r.string1, r.string2);\r
+ } else if (r.type == NoteRequest.Update_Note_Creation_Date) {\r
+ conn.getNoteTable().updateNoteCreatedDate(r.string1, r.date);\r
+ } else if (r.type == NoteRequest.Update_Note_Altered_Date) {\r
+ conn.getNoteTable().updateNoteAlteredDate(r.string1, r.date);\r
+ } else if (r.type == NoteRequest.Update_Note_Subject_Date) {\r
+ conn.getNoteTable().updateNoteSubjectDate(r.string1, r.date);\r
+ } else if (r.type == NoteRequest.Update_Note_Source_Url) {\r
+ conn.getNoteTable().updateNoteSourceUrl(r.string1, r.string2);\r
+ } else if (r.type == NoteRequest.Update_Note_Author) {\r
+ conn.getNoteTable().updateNoteAuthor(r.string1, r.string2);\r
+ } else if (r.type == NoteRequest.Update_Note_Notebook) {\r
+ conn.getNoteTable().updateNoteNotebook(r.string1, r.string2, r.bool1);\r
+ } else if (r.type == NoteRequest.Update_Note_Content) {\r
+ conn.getNoteTable().updateNoteContent(r.string1, r.string2);\r
+ } else if (r.type == NoteRequest.Delete_Note) {\r
+ conn.getNoteTable().deleteNote(r.string1);\r
+ } else if (r.type == NoteRequest.Restore_Note) {\r
+ conn.getNoteTable().restoreNote(r.string1);\r
+ } else if (r.type == NoteRequest.Expunge_Note) {\r
+ conn.getNoteTable().expungeNote(r.string1, r.bool1, r.bool2);\r
+ } else if (r.type == NoteRequest.Expunge_All_Deleted_Notes) {\r
+ conn.getNoteTable().expungeAllDeletedNotes();\r
+ } else if (r.type == NoteRequest.Update_Note_Sequence) {\r
+ conn.getNoteTable().updateNoteSequence(r.string1, r.int1);\r
+ } else if (r.type == NoteRequest.Update_Note_Guid) {\r
+ conn.getNoteTable().updateNoteGuid(r.string1, r.string2);\r
+ } else if (r.type == NoteRequest.Update_Note) {\r
+ conn.getNoteTable().updateNote(r.note, r.bool1);\r
+ } else if (r.type == NoteRequest.Exists) {\r
+ noteResponse.get(r.requestor_id).responseBoolean =conn.getNoteTable().exists(r.string1);\r
+ release(r.requestor_id);\r
+ } else if (r.type == NoteRequest.Sync_Note) {\r
+ conn.getNoteTable().syncNote(r.note, r.bool1);\r
+ } else if (r.type == NoteRequest.Get_Dirty) {\r
+ noteResponse.get(r.requestor_id).responseNotes = conn.getNoteTable().getDirty();\r
+ release(r.requestor_id);\r
+ } else if (r.type == NoteRequest.Get_Unsynchronized_Guids) {\r
+ noteResponse.get(r.requestor_id).responseStrings = conn.getNoteTable().getUnsynchronizedGUIDs();\r
+ release(r.requestor_id);\r
+ } else if (r.type == NoteRequest.Reset_Dirty_Flag) {\r
+ conn.getNoteTable().resetDirtyFlag(r.string1);\r
+ } else if (r.type == NoteRequest.Get_All_Guids) {\r
+ noteResponse.get(r.requestor_id).responseStrings = conn.getNoteTable().getAllGuids();\r
+ release(r.requestor_id);\r
+ } else if (r.type == NoteRequest.Get_All_Notes) {\r
+ noteResponse.get(r.requestor_id).responseNotes = conn.getNoteTable().getAllNotes();\r
+ release(r.requestor_id);\r
+ } else if (r.type == NoteRequest.Get_Unindexed_Count) {\r
+ noteResponse.get(r.requestor_id).responseInt = conn.getNoteTable().getUnindexedCount();\r
+ release(r.requestor_id);\r
+ } else if (r.type == NoteRequest.Get_Dirty_Count) {\r
+ noteResponse.get(r.requestor_id).responseInt = conn.getNoteTable().getDirtyCount();\r
+ logger.log(logger.EXTREME, "Note request: " +r.category + " " + r.type + " from " +r.requestor_id);\r
+ release(r.requestor_id);\r
+ } else if (r.type == NoteRequest.Update_Resource_Guid_By_Hash) {\r
+ conn.getNoteTable().updateNoteResourceGuidbyHash(r.string1, r.string2, r.string3);\r
+ } else if (r.type == NoteRequest.Set_Index_Needed) {\r
+ conn.getNoteTable().setIndexNeeded(r.string1, r.bool1);\r
+ } else if (r.type == NoteRequest.Reindex_All_Notes) {\r
+ conn.getNoteTable().reindexAllNotes();\r
+ } else if (r.type == NoteRequest.Get_Unindexed) {\r
+ noteResponse.get(r.requestor_id).responseStrings = conn.getNoteTable().getUnindexed();\r
+ release(r.requestor_id);\r
+ } else if (r.type == NoteRequest.Get_Next_Unindexed) {\r
+ noteResponse.get(r.requestor_id).responseStrings = conn.getNoteTable().getNextUnindexed(r.int1);\r
+ release(r.requestor_id);\r
+ } else if (r.type == NoteRequest.Update_Resource_Content_Hash) {\r
+ conn.getNoteTable().updateResourceContentHash(r.string1, r.string2, r.string3);\r
+ } else if (r.type == NoteRequest.Get_Note_Count) {\r
+ noteResponse.get(r.requestor_id).responseInt = conn.getNoteTable().getNoteCount();\r
+ release(r.requestor_id);\r
+ } else if (r.type == NoteRequest.Reset_Note_Sequence) {\r
+ conn.getNoteTable().resetNoteSequence(r.string1);\r
+ } else if (r.type == NoteRequest.Get_Deleted_Count) {\r
+ noteResponse.get(r.requestor_id).responseInt = conn.getNoteTable().getDeletedCount();\r
+ release(r.requestor_id);\r
+ } else if (r.type == NoteRequest.Is_Note_Dirty) {\r
+ noteResponse.get(r.requestor_id).responseBoolean = conn.getNoteTable().isNoteDirty(r.string1);\r
+ release(r.requestor_id);\r
+ } else if (r.type == NoteRequest.Get_Note_Content_Binary) {\r
+ noteResponse.get(r.requestor_id).responseString = conn.getNoteTable().getNoteContentBinary(r.string1);\r
+ release(r.requestor_id);\r
+ } else if (r.type == NoteRequest.Get_Title_Colors) {\r
+ noteResponse.get(r.requestor_id).responsePair = conn.getNoteTable().getNoteTitleColors();\r
+ release(r.requestor_id);\r
+ } else if (r.type == NoteRequest.Set_Title_Colors) {\r
+ conn.getNoteTable().setNoteTitleColor(r.string1, r.int1);\r
+ } else if (r.type == NoteRequest.Get_Thumbnail) {\r
+ noteResponse.get(r.requestor_id).responseBytes = conn.getNoteTable().getThumbnail(r.string1);\r
+ release(r.requestor_id);\r
+ } else if (r.type == NoteRequest.Is_Thumbail_Needed) {\r
+ noteResponse.get(r.requestor_id).responseBoolean = conn.getNoteTable().isThumbnailNeeded(r.string1);\r
+ release(r.requestor_id);\r
+ } else if (r.type == NoteRequest.Set_Thumbnail_Needed) {\r
+ conn.getNoteTable().setThumbnailNeeded(r.string1, r.bool1);\r
+ } else if (r.type == NoteRequest.Set_Thumbnail) {\r
+ conn.getNoteTable().setThumbnail(r.string1, r.bytes);\r
+ } \r
+ logger.log(logger.EXTREME, "End of Note request");\r
+ return;\r
+ }\r
+\r
+ //******************************************\r
+ //* Note Resource database requests *\r
+ //******************************************\r
+ private void doResourceRequest(ResourceRequest r) {\r
+ logger.log(logger.EXTREME, "Resource request: " +r.category + " " + r.type);\r
+ if (r.type == ResourceRequest.Create_Table) {\r
+ conn.getNoteTable().noteResourceTable.createTable();\r
+ } else if (r.type == ResourceRequest.Drop_Table) {\r
+ conn.getNoteTable().noteResourceTable.dropTable();\r
+ } if (r.type == ResourceRequest.Expunge_Note_Resource) {\r
+ conn.getNoteTable().noteResourceTable.expungeNoteResource(r.string1);\r
+ } else if (r.type == ResourceRequest.Get_Next_Unindexed) {\r
+ resourceResponse.get(r.requestor_id).responseStrings = conn.getNoteTable().noteResourceTable.getNextUnindexed(r.int1);\r
+ release(r.requestor_id);\r
+ } else if (r.type == ResourceRequest.Get_Note_Resource) {\r
+ resourceResponse.get(r.requestor_id).responseResource = conn.getNoteTable().noteResourceTable.getNoteResource(r.string1, r.bool1);\r
+ release(r.requestor_id);\r
+ } else if (r.type == ResourceRequest.Get_Note_Resource_Data_Body_By_Hash_Hex) {\r
+ resourceResponse.get(r.requestor_id).responseResource = conn.getNoteTable().noteResourceTable.getNoteResourceDataBodyByHashHex(r.string1, r.string2);\r
+ release(r.requestor_id);\r
+ } else if (r.type == ResourceRequest.Get_Note_Resource_Guid_By_Hash_Hex) {\r
+ resourceResponse.get(r.requestor_id).responseString = conn.getNoteTable().noteResourceTable.getNoteResourceGuidByHashHex(r.string1, r.string2);\r
+ release(r.requestor_id);\r
+ } else if (r.type == ResourceRequest.Get_Note_Resource_Recognition) {\r
+ resourceResponse.get(r.requestor_id).responseResource = conn.getNoteTable().noteResourceTable.getNoteResourceRecognition(r.string1);\r
+ release(r.requestor_id);\r
+ } else if (r.type == ResourceRequest.Get_Note_Resources) {\r
+ resourceResponse.get(r.requestor_id).responseResources = conn.getNoteTable().noteResourceTable.getNoteResources(r.string1, r.bool1);\r
+ release(r.requestor_id);\r
+ } else if (r.type == ResourceRequest.Get_Note_Resources_Recognition) {\r
+ resourceResponse.get(r.requestor_id).responseResources = conn.getNoteTable().noteResourceTable.getNoteResourcesRecognition(r.string1);\r
+ release(r.requestor_id);\r
+ } else if (r.type == ResourceRequest.Get_Resource_Count) {\r
+ resourceResponse.get(r.requestor_id).responseInteger = conn.getNoteTable().noteResourceTable.getResourceCount();\r
+ release(r.requestor_id);\r
+ } else if (r.type == ResourceRequest.Reindex_All) {\r
+ conn.getNoteTable().noteResourceTable.reindexAll();\r
+ } else if (r.type == ResourceRequest.Reset_Dirty_Flag) {\r
+ conn.getNoteTable().noteResourceTable.resetDirtyFlag(r.string1);\r
+ } else if (r.type == ResourceRequest.Save_Note_Resource) {\r
+ conn.getNoteTable().noteResourceTable.saveNoteResource(r.resource, r.bool1);\r
+ } else if (r.type == ResourceRequest.Set_Index_Needed) {\r
+ conn.getNoteTable().noteResourceTable.setIndexNeeded(r.string1, r.bool1);\r
+ } else if (r.type == ResourceRequest.Update_Note_Resource) {\r
+ conn.getNoteTable().noteResourceTable.updateNoteResource(r.resource, r.bool1);\r
+ } else if (r.type == ResourceRequest.Update_Note_Resource_Guid) {\r
+ conn.getNoteTable().noteResourceTable.updateNoteResourceGuid(r.string1, r.string2, r.bool1);\r
+ } else if (r.type == ResourceRequest.Reset_Update_Sequence_Number) {\r
+ conn.getNoteTable().noteResourceTable.resetUpdateSequenceNumber(r.string1, r.bool1);\r
+ }\r
+ logger.log(logger.EXTREME, "End of note resource request");\r
+ }\r
+\r
+\r
+ //******************************************\r
+ //* Note Resource database requests *\r
+ //******************************************\r
+ private void doNoteTagsRequest(NoteTagsRequest r) {\r
+ logger.log(logger.EXTREME, "Note Tags request: " +r.category + " " + r.type + " from " +r.requestor_id);\r
+ if (r.type == NoteTagsRequest.Create_Table) {\r
+ conn.getNoteTable().noteTagsTable.createTable();\r
+ } else if (r.type == NoteTagsRequest.Drop_Table) {\r
+ conn.getNoteTable().noteTagsTable.dropTable();\r
+ } else if (r.type == NoteTagsRequest.Check_Note_Note_Tags) {\r
+ noteTagsResponse.get(r.requestor_id).responseBoolean = conn.getNoteTable().noteTagsTable.checkNoteNoteTags(r.string1, r.string2);\r
+ release(r.requestor_id);\r
+ } if (r.type == NoteTagsRequest.Delete_Note_Tag) {\r
+ conn.getNoteTable().noteTagsTable.deleteNoteTag(r.string1);\r
+ } if (r.type == NoteTagsRequest.Get_All_Note_Tags) {\r
+ noteTagsResponse.get(r.requestor_id).responseNoteTagsRecord = conn.getNoteTable().noteTagsTable.getAllNoteTags();\r
+ release(r.requestor_id);\r
+ } if (r.type == NoteTagsRequest.Get_Note_Tags) {\r
+ noteTagsResponse.get(r.requestor_id).responseStrings = conn.getNoteTable().noteTagsTable.getNoteTags(r.string1);\r
+ release(r.requestor_id);\r
+ } if (r.type == NoteTagsRequest.Save_Note_Tag) {\r
+ conn.getNoteTable().noteTagsTable.saveNoteTag(r.string1, r.string2);\r
+ } \r
+ if (r.type == NoteTagsRequest.Tag_Counts) {\r
+ noteTagsResponse.get(r.requestor_id).responseCounts = conn.getNoteTable().noteTagsTable.getTagCounts();\r
+ release(r.requestor_id);\r
+ } \r
+ logger.log(logger.EXTREME, "End of note tags request");\r
+ }\r
+\r
+\r
+ //**************************************\r
+ //* Search requests *\r
+ //**************************************\r
+ private void doEnSearchRequest(EnSearchRequest r) {\r
+ logger.log(logger.EXTREME, "EnSearch request: " +r.category + " " + r.type + " from " +r.requestor_id);\r
+ REnSearch s = new REnSearch(conn, logger, conn, r.string1, r.tags, r.int1, r.int2);\r
+ enSearchResponse.get(r.requestor_id).responseNotes = s.matchWords();\r
+ enSearchResponse.get(r.requestor_id).responseStrings = s.getWords();\r
+ release(r.requestor_id);\r
+ logger.log(logger.EXTREME, "End of EnSearch request");\r
+ return;\r
+ }\r
+ \r
+ \r
+ \r
+ //**************************************\r
+ //* Watch Folders *\r
+ //**************************************\r
+ private void doWatchFolderRequest(WatchFolderRequest r) {\r
+ logger.log(logger.EXTREME, "Watch folder request: " +r.category + " " + r.type + " from " +r.requestor_id);\r
+ if (r.type == WatchFolderRequest.Create_Tables) {\r
+ conn.getWatchFolderTable().createTable();\r
+ } else if (r.type == WatchFolderRequest.Add_Watch_Folder) {\r
+ conn.getWatchFolderTable().addWatchFolder(r.string1, r.string2, r.bool1, r.int1);\r
+ } else if (r.type == WatchFolderRequest.Get_All) {\r
+ watchFolderResponse.get(r.requestor_id).responseWatchFolders = conn.getWatchFolderTable().getAll();\r
+ release(r.requestor_id);\r
+ }\r
+ else if (r.type == WatchFolderRequest.Get_Notebook) {\r
+ watchFolderResponse.get(r.requestor_id).responseString = conn.getWatchFolderTable().getNotebook(r.string1);\r
+ release(r.requestor_id);\r
+ } else if (r.type == WatchFolderRequest.Drop_Tables) {\r
+ conn.getWatchFolderTable().dropTable();\r
+ } else if (r.type == WatchFolderRequest.Expunge_Folder) {\r
+ conn.getWatchFolderTable().expungeWatchFolder(r.string1);\r
+ } else if (r.type == WatchFolderRequest.Expunge_All) {\r
+ conn.getWatchFolderTable().expungeAll();\r
+ }\r
+ logger.log(logger.EXTREME, "End of watch folder request");\r
+ }\r
+ \r
+ //**************************************\r
+ //* Word Index *\r
+ //**************************************\r
+ private void doWordRequest(WordRequest r) {\r
+ logger.log(logger.EXTREME, "Word request: " +r.category + " " + r.type + " from " +r.requestor_id);\r
+ if (r.type == WordRequest.Create_Table) {\r
+ conn.getWordsTable().createTable();\r
+ } else if (r.type == WordRequest.Drop_Table) {\r
+ conn.getWordsTable().dropTable();\r
+ } else if (r.type == WordRequest.Expunge_From_Word_Index) {\r
+ conn.getWordsTable().expungeFromWordIndex(r.string1, r.string2);\r
+ } else if (r.type == WordRequest.Clear_Word_Index) {\r
+ conn.getWordsTable().clearWordIndex();\r
+ } else if (r.type == WordRequest.Get_Word_Count) {\r
+ wordResponse.get(r.requestor_id).responseInt = conn.getWordsTable().getWordCount();\r
+ release(r.requestor_id);\r
+ } else if (r.type == WordRequest.Add_Word_To_Note_Index) {\r
+ conn.getWordsTable().addWordToNoteIndex(r.string1, r.string2, r.string3, r.int1);\r
+ release(r.requestor_id);\r
+ } \r
+ logger.log(logger.EXTREME, "End of word request");\r
+ }\r
+ \r
+ \r
+ //**************************************\r
+ //* Invalid XML *\r
+ //**************************************\r
+ private void doInvalidXMLRequest(InvalidXMLRequest r) {\r
+ if (r.type == InvalidXMLRequest.Create_Table) {\r
+ conn.getInvalidXMLTable().createTable();\r
+ return;\r
+ } else if (r.type == InvalidXMLRequest.Drop_Table) {\r
+ conn.getInvalidXMLTable().dropTable();\r
+ return;\r
+ } else if (r.type == InvalidXMLRequest.Get_Invalid_Elements) {\r
+ invalidXMLResponse.get(r.requestor_id).responseList = conn.getInvalidXMLTable().getInvalidElements();\r
+ release(r.requestor_id);\r
+ return;\r
+ } else if (r.type == InvalidXMLRequest.Get_Invalid_Attributes) {\r
+ invalidXMLResponse.get(r.requestor_id).responseArrayList = conn.getInvalidXMLTable().getInvalidAttributes(r.string1);\r
+ release(r.requestor_id);\r
+ return;\r
+ } else if (r.type == InvalidXMLRequest.Get_Invalid_Attribute_Elements) {\r
+ invalidXMLResponse.get(r.requestor_id).responseList = conn.getInvalidXMLTable().getInvalidAttributeElements();\r
+ release(r.requestor_id);\r
+ return;\r
+ } else if (r.type == InvalidXMLRequest.Add_Invalid_Element) {\r
+ conn.getInvalidXMLTable().addElement(r.string1);\r
+ return;\r
+ } else if (r.type == InvalidXMLRequest.Add_Invalid_Attribute) {\r
+ conn.getInvalidXMLTable().addAttribute(r.string1, r.string2);\r
+ return;\r
+ } \r
+ }\r
+ \r
+ \r
+ //**************************************\r
+ //* Sync database *\r
+ //**************************************\r
+ private void doSyncRequest(SyncRequest r) {\r
+ if (r.type == SyncRequest.Create_Table) {\r
+ conn.getInvalidXMLTable().createTable();\r
+ return;\r
+ } else if (r.type == SyncRequest.Drop_Table) {\r
+ conn.getInvalidXMLTable().dropTable();\r
+ return;\r
+ } else if (r.type == SyncRequest.Get_Record) {\r
+ syncResponse.get(r.requestor_id).responseValue = conn.getSyncTable().getRecord(r.key);\r
+ release(r.requestor_id);\r
+ return;\r
+ } else if (r.type == SyncRequest.Set_Record) {\r
+ conn.getSyncTable().setRecord(r.key,r.value);\r
+ return;\r
+ } \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.threads;\r
+\r
+import java.util.concurrent.LinkedBlockingQueue;\r
+\r
+import com.evernote.edam.type.Note;\r
+import com.evernote.edam.type.Resource;\r
+import com.trolltech.qt.core.QByteArray;\r
+import com.trolltech.qt.core.QObject;\r
+import com.trolltech.qt.xml.QDomDocument;\r
+import com.trolltech.qt.xml.QDomElement;\r
+import com.trolltech.qt.xml.QDomNodeList;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.signals.NoteResourceSignal;\r
+import cx.fbn.nevernote.signals.NoteSignal;\r
+import cx.fbn.nevernote.sql.DatabaseConnection;\r
+import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+import cx.fbn.nevernote.utilities.StringUtils;\r
+\r
+//public class IndexRunner implements QRunnable {\r
+public class IndexRunner extends QObject implements Runnable {\r
+ \r
+ private final ApplicationLogger logger;\r
+ private String guid;\r
+ private QByteArray resourceBinary;\r
+ public volatile NoteSignal noteSignal;\r
+ public volatile NoteResourceSignal resourceSignal;\r
+ private int indexType;\r
+ public final int CONTENT=1; \r
+ public final int RESOURCE=2;\r
+ private boolean keepRunning;\r
+// public volatile int ID;\r
+ private final QDomDocument doc;\r
+ private final int threadID;\r
+ private static String regex = Global.getWordRegex();\r
+ private final DatabaseConnection conn;\r
+ private volatile LinkedBlockingQueue<String> workQueue;\r
+// private static int MAX_EMPTY_QUEUE_COUNT = 1;\r
+ private static int MAX_QUEUED_WAITING = 1000;\r
+ \r
+\r
+ \r
+ public IndexRunner(String logname) {\r
+ logger = new ApplicationLogger(logname);\r
+ threadID = Global.indexThreadId;\r
+ conn = new DatabaseConnection(logger, threadID);\r
+ noteSignal = new NoteSignal();\r
+ resourceSignal = new NoteResourceSignal();\r
+// threadSignal = new ThreadSignal();\r
+ indexType = CONTENT;\r
+ guid = null;\r
+ keepRunning = true;\r
+ doc = new QDomDocument();\r
+ workQueue=new LinkedBlockingQueue<String>(MAX_QUEUED_WAITING);\r
+ }\r
+ \r
+ \r
+ public void setIndexType(int t) {\r
+ indexType = t;\r
+ }\r
+ \r
+ \r
+ @Override\r
+ public void run() {\r
+ thread().setPriority(Thread.MIN_PRIORITY);\r
+ logger.log(logger.EXTREME, "Starting index thread ");\r
+ while (keepRunning) {\r
+ try {\r
+ String work = workQueue.take();\r
+ if (work.startsWith("CONTENT")) {\r
+ work = work.replace("CONTENT ", "");\r
+ guid = work;\r
+ indexType = CONTENT;\r
+ }\r
+ if (work.startsWith("RESOURCE")) {\r
+ work = work.replace("RESOURCE ", "");\r
+ guid = work;\r
+ indexType = RESOURCE;\r
+ }\r
+ if (work.startsWith("STOP")) {\r
+ keepRunning = false;\r
+ guid = work;\r
+ }\r
+ if (guid == null || guid.trim().equals("")) {\r
+ setIndexType(0);\r
+ resourceSignal.resourceIndexed.emit("null or empty guid");\r
+ }\r
+ logger.log(logger.EXTREME, "Type:" +indexType);\r
+ if (indexType == CONTENT && keepRunning) {\r
+ logger.log(logger.MEDIUM, "Indexing note: "+guid);\r
+ indexNoteContent();\r
+ setIndexType(0);\r
+ }\r
+ if (indexType == RESOURCE && keepRunning) {\r
+ logger.log(logger.MEDIUM, "Indexing resource: "+guid);\r
+ indexResource();\r
+ setIndexType(0);\r
+ }\r
+ } catch (InterruptedException e) {\r
+ // TODO Auto-generated catch block\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+ }\r
+ \r
+ // Reindex a note\r
+ public void indexNoteContent() {\r
+ logger.log(logger.EXTREME, "Entering indexRunner.indexNoteContent()");\r
+ \r
+ logger.log(logger.EXTREME, "Getting note content");\r
+ Note n = conn.getNoteTable().getNote(guid,true,false,true,true, true);\r
+ String data = n.getContent();\r
+ \r
+ logger.log(logger.EXTREME, "Removing any encrypted data");\r
+ data = removeEnCrypt(data);\r
+ logger.log(logger.EXTREME, "Removing xml markups");\r
+ String text = StringUtils.unescapeHTML(data.replaceAll("\\<.*?\\>", ""),0);\r
+ \r
+ logger.log(logger.EXTREME, "Splitting words");\r
+ String[] result = text.toString().split(regex);\r
+ logger.log(logger.EXTREME, "Deleting existing words for note from index");\r
+ conn.getWordsTable().expungeFromWordIndex(guid, "CONTENT");\r
+ \r
+ logger.log(logger.EXTREME, "Number of words found: " +result.length);\r
+ for (int j=0; j<result.length && keepRunning; j++) {\r
+ logger.log(logger.EXTREME, "Result word: " +result[j]);\r
+ if (result[j].length() > 0) {\r
+ if (Character.isLetterOrDigit(result[j].charAt(0))) {\r
+ int len = result[j].length();\r
+ StringBuffer buffer = new StringBuffer(result[j].toLowerCase());\r
+ logger.log(logger.EXTREME, "Processing " +buffer);\r
+ for (int k=len-1; k>=0 && keepRunning; k--) {\r
+ if (!Character.isLetterOrDigit(result[j].charAt(k)))\r
+ buffer.deleteCharAt(k);\r
+ else\r
+ k=-1;\r
+ }\r
+\r
+ if (buffer.length()>=Global.minimumWordCount) {\r
+ logger.log(logger.EXTREME, "Adding " +buffer);\r
+ conn.getWordsTable().addWordToNoteIndex(guid, buffer.toString(), "CONTENT", 100);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ // If we were interrupted, we will reindex this note next time\r
+ if (Global.keepRunning) {\r
+ logger.log(logger.EXTREME, "Resetting note guid needed");\r
+ conn.getNoteTable().setIndexNeeded(guid, false);\r
+ }\r
+ logger.log(logger.EXTREME, "Leaving indexRunner.indexNoteContent()");\r
+ }\r
+\r
+ \r
+ public synchronized boolean addWork(String request) {\r
+ if (workQueue.size() == 0) {\r
+ workQueue.offer(request);\r
+ return true;\r
+ }\r
+ return false;\r
+ }\r
+ \r
+ public synchronized int getWorkQueueSize() {\r
+ return workQueue.size();\r
+ }\r
+ \r
+ public void indexResource() {\r
+ \r
+ if (guid == null)\r
+ return;\r
+ \r
+ Resource r = conn.getNoteTable().noteResourceTable.getNoteResourceRecognition(guid);\r
+ if (r == null || r.getRecognition() == null || r.getRecognition().getBody() == null || r.getRecognition().getBody().length == 0) \r
+ resourceBinary = new QByteArray(" ");\r
+ else\r
+ resourceBinary = new QByteArray(r.getRecognition().getBody());\r
+ \r
+ conn.getWordsTable().expungeFromWordIndex(guid, "RESOURCE");\r
+ \r
+ doc.setContent(resourceBinary);\r
+ QDomElement docElem = doc.documentElement();\r
+ \r
+ // look for text tags\r
+ QDomNodeList anchors = docElem.elementsByTagName("t");\r
+ for (int i=0; i<anchors.length() && keepRunning; i++) {\r
+ QDomElement enmedia = anchors.at(i).toElement();\r
+ String weight = new String(enmedia.attribute("w"));\r
+ String text = new String(enmedia.text()).toLowerCase();\r
+ if (!text.equals("")) {\r
+ conn.getWordsTable().addWordToNoteIndex(guid, text, "RESOURCE", new Integer(weight));\r
+ }\r
+ }\r
+ if (Global.keepRunning)\r
+ conn.getNoteTable().noteResourceTable.setIndexNeeded(guid,false);\r
+ }\r
+\r
+ \r
+ private String removeEnCrypt(String content) {\r
+ int index = content.indexOf("<en-crypt");\r
+ int endPos;\r
+ boolean tagFound = true;\r
+ while (tagFound && keepRunning) {\r
+ endPos = content.indexOf("</en-crypt>", index)+11;\r
+ if (endPos > -1 && index > -1) {\r
+ content = content.substring(0,index)+content.substring(endPos);\r
+ index = content.indexOf("<en-crypt");\r
+ } else {\r
+ tagFound = false;\r
+ }\r
+ }\r
+ return content;\r
+ }\r
+\r
+ \r
+ \r
+ \r
+\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.threads;\r
+\r
+import java.util.GregorianCalendar;\r
+import java.util.List;\r
+import java.util.concurrent.LinkedBlockingQueue;\r
+\r
+import com.evernote.edam.type.Resource;\r
+import com.trolltech.qt.core.QMutex;\r
+import com.trolltech.qt.core.QObject;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.evernote.EnmlConverter;\r
+import cx.fbn.nevernote.sql.DatabaseConnection;\r
+import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+import cx.fbn.nevernote.utilities.Pair;\r
+\r
+public class SaveRunner extends QObject implements Runnable {\r
+ \r
+ private final ApplicationLogger logger;\r
+ private volatile boolean keepRunning;\r
+ public QMutex threadLock;\r
+ private final DatabaseConnection conn;\r
+ private boolean idle;\r
+ private final int threadID;\r
+\r
+ private volatile LinkedBlockingQueue<Pair<String, String>> workQueue = new LinkedBlockingQueue<Pair<String, String>>();\r
+ \r
+ \r
+ //*********************************************\r
+ //* Constructor *\r
+ //*********************************************\r
+ public SaveRunner(String logname) {\r
+ logger = new ApplicationLogger(logname);\r
+ threadID = Global.saveThreadId;\r
+ conn = new DatabaseConnection(logger, threadID);\r
+ threadLock = new QMutex();\r
+ keepRunning = true;\r
+ }\r
+ \r
+ \r
+ \r
+ //*********************************************\r
+ //* Run unit *\r
+ //*********************************************\r
+ @Override\r
+ public void run() {\r
+ thread().setPriority(Thread.MIN_PRIORITY);\r
+ boolean keepRunning = true;\r
+ \r
+ while(keepRunning) {\r
+ try {\r
+ Pair<String, String> content;\r
+ idle = true;\r
+ content = workQueue.take();\r
+ if (!content.getFirst().equalsIgnoreCase("stop")) { \r
+ idle = false;\r
+ \r
+ // This is a bit of a hack. It causes this thread to pause for 0.2 seconds.\r
+ // This helps make sure that the main thread gets to the\r
+ // database first when switching notes, othrewise it really \r
+ // slows things down when fetching new notes.\r
+ GregorianCalendar now = new GregorianCalendar();\r
+ long prev = now.getTimeInMillis();\r
+ prev = prev+200;\r
+ while (prev>now.getTimeInMillis()) {\r
+ now = new GregorianCalendar(); \r
+ }\r
+ \r
+ updateNoteContent(content.getFirst(), content.getSecond());\r
+ } else {\r
+ return;\r
+ }\r
+ threadLock.unlock();\r
+ } catch (InterruptedException e) { }\r
+ }\r
+ }\r
+ \r
+ \r
+ public synchronized void addWork(String guid, String content) {\r
+ while(workQueue.size() > 0) {}\r
+ Pair<String, String> pair = new Pair<String, String>(guid, content);\r
+ workQueue.offer(pair);\r
+ }\r
+ \r
+ public synchronized void release(String guid, String content) {\r
+ Pair<String, String> pair = new Pair<String, String>(guid, content);\r
+ workQueue.add(pair);\r
+ }\r
+ \r
+ public synchronized int getWorkQueueSize() {\r
+ return workQueue.size();\r
+ }\r
+\r
+ \r
+ //*********************************************\r
+ //* Getter & Setter method to tell the thread *\r
+ //* to keep running. *\r
+ //*********************************************\r
+ public void setKeepRunning(boolean b) {\r
+ keepRunning = b;\r
+ }\r
+ public boolean keepRunning() {\r
+ return keepRunning;\r
+ }\r
+ \r
+ public boolean isIdle() {\r
+ return idle;\r
+ }\r
+ \r
+ \r
+ //*********************************************\r
+ //* Do the actual work *\r
+ //*********************************************\r
+ public void updateNoteContent(String guid, String content) {\r
+ logger.log(logger.HIGH, "Entering ListManager.updateNoteContent");\r
+ \r
+ // Actually save the content\r
+ EnmlConverter enml = new EnmlConverter(logger);\r
+ String newContent = enml.convert(guid, content);\r
+ String fixedContent = enml.fixEnXMLCrap(newContent);\r
+ conn.getNoteTable().updateNoteContent(guid, fixedContent);\r
+\r
+\r
+ logger.log(logger.EXTREME, "Saving new note resources");\r
+ List<Resource> oldResources = conn.getNoteTable().noteResourceTable.getNoteResources(guid, false);\r
+ List<String> newResources = enml.getResources();\r
+ removeObsoleteResources(oldResources, newResources);\r
+ \r
+ logger.log(logger.HIGH, "Leaving ListManager.updateNoteContent");\r
+ }\r
+ \r
+ // Remove resources that are no longer needed\r
+ private void removeObsoleteResources(List<Resource> oldResources, List<String> newResources) {\r
+ if (oldResources == null || oldResources.size() == 0)\r
+ return;\r
+ if (newResources == null || newResources.size() == 0) {\r
+ for (int i=0; i<oldResources.size(); i++) {\r
+ conn.getNoteTable().noteResourceTable.expungeNoteResource(oldResources.get(i).getGuid());\r
+ }\r
+ }\r
+ for (int i=0; i<oldResources.size(); i++) {\r
+ boolean matchFound = false;\r
+ for (int j=0; j<newResources.size(); j++) {\r
+ if (newResources.get(j).equalsIgnoreCase(oldResources.get(i).getGuid())) \r
+ matchFound = true;\r
+ if (Global.resourceMap.get(newResources.get(j))!= null) {\r
+ if (Global.resourceMap.get(newResources.get(j)).equalsIgnoreCase(oldResources.get(i).getGuid())) \r
+ matchFound = true;\r
+ }\r
+ if (matchFound)\r
+ j = newResources.size();\r
+ }\r
+ if (!matchFound)\r
+ conn.getNoteTable().noteResourceTable.expungeNoteResource(oldResources.get(i).getGuid());\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+package cx.fbn.nevernote.threads;\r
+\r
+import java.net.UnknownHostException;\r
+import java.util.ArrayList;\r
+import java.util.Calendar;\r
+import java.util.Date;\r
+import java.util.GregorianCalendar;\r
+import java.util.List;\r
+import java.util.Vector;\r
+import java.util.concurrent.LinkedBlockingQueue;\r
+\r
+import org.apache.thrift.TException;\r
+import org.apache.thrift.protocol.TBinaryProtocol;\r
+import org.apache.thrift.transport.THttpClient;\r
+import org.apache.thrift.transport.TTransportException;\r
+\r
+import com.evernote.edam.error.EDAMNotFoundException;\r
+import com.evernote.edam.error.EDAMSystemException;\r
+import com.evernote.edam.error.EDAMUserException;\r
+import com.evernote.edam.notestore.NoteStore;\r
+import com.evernote.edam.notestore.SyncChunk;\r
+import com.evernote.edam.notestore.SyncState;\r
+import com.evernote.edam.type.Data;\r
+import com.evernote.edam.type.Note;\r
+import com.evernote.edam.type.Notebook;\r
+import com.evernote.edam.type.Resource;\r
+import com.evernote.edam.type.SavedSearch;\r
+import com.evernote.edam.type.Tag;\r
+import com.evernote.edam.type.User;\r
+import com.evernote.edam.userstore.AuthenticationResult;\r
+import com.evernote.edam.userstore.UserStore;\r
+import com.trolltech.qt.core.QObject;\r
+import com.trolltech.qt.gui.QMessageBox;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.signals.NoteIndexSignal;\r
+import cx.fbn.nevernote.signals.NoteResourceSignal;\r
+import cx.fbn.nevernote.signals.NoteSignal;\r
+import cx.fbn.nevernote.signals.NotebookSignal;\r
+import cx.fbn.nevernote.signals.SavedSearchSignal;\r
+import cx.fbn.nevernote.signals.StatusSignal;\r
+import cx.fbn.nevernote.signals.SyncSignal;\r
+import cx.fbn.nevernote.signals.TagSignal;\r
+import cx.fbn.nevernote.sql.DatabaseConnection;\r
+import cx.fbn.nevernote.sql.runners.DeletedItemRecord;\r
+import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+\r
+public class SyncRunner extends QObject implements Runnable {\r
+ \r
+ private final ApplicationLogger logger;\r
+ private final DatabaseConnection conn;\r
+ private boolean idle;\r
+ private boolean error;\r
+ public volatile boolean isConnected;\r
+ public volatile boolean keepRunning;\r
+ public volatile String authToken;\r
+ private long evernoteUpdateCount;\r
+ \r
+ public volatile NoteStore.Client noteStore;\r
+ private UserStore.Client userStore;\r
+ \r
+ public volatile StatusSignal status;\r
+ public volatile TagSignal tagSignal;\r
+ public volatile NotebookSignal notebookSignal;\r
+ public volatile NoteIndexSignal noteIndexSignal;\r
+ public volatile NoteSignal noteSignal;\r
+ public volatile SavedSearchSignal searchSignal;\r
+ public volatile NoteResourceSignal resourceSignal;\r
+ public volatile SyncSignal syncSignal;\r
+ public volatile boolean authRefreshNeeded;\r
+ public volatile boolean syncNeeded;\r
+ public volatile boolean disableUploads;\r
+ public volatile boolean syncDeletedContent;\r
+ private volatile Vector<String> dirtyNoteGuids;\r
+ \r
+ public volatile String username = ""; \r
+ public volatile String password = ""; \r
+ public volatile String userStoreUrl;\r
+ private final static String consumerKey = "baumgarte"; \r
+ private final static String consumerSecret = "eb8b5740e17cb55f";\r
+ public String noteStoreUrlBase;\r
+ private THttpClient userStoreTrans;\r
+ private TBinaryProtocol userStoreProt;\r
+ private AuthenticationResult authResult;\r
+ private User user; \r
+ private long authTimeRemaining;\r
+ public long authRefreshTime;\r
+ public long failedRefreshes = 0;\r
+ public THttpClient noteStoreTrans;\r
+ public TBinaryProtocol noteStoreProt;\r
+ public String noteStoreUrl;\r
+ public long sequenceDate;\r
+ public int updateSequenceNumber;\r
+ private boolean refreshNeeded;\r
+ private volatile LinkedBlockingQueue<String> workQueue;\r
+// private static int MAX_EMPTY_QUEUE_COUNT = 1;\r
+ private static int MAX_QUEUED_WAITING = 1000;\r
+ \r
+ \r
+ \r
+ public SyncRunner(String logname) {\r
+ logger = new ApplicationLogger(logname);\r
+ \r
+ noteSignal = new NoteSignal();\r
+ status = new StatusSignal();\r
+ tagSignal = new TagSignal();\r
+ notebookSignal = new NotebookSignal();\r
+ noteIndexSignal = new NoteIndexSignal();\r
+ noteSignal = new NoteSignal();\r
+ searchSignal = new SavedSearchSignal();\r
+ syncSignal = new SyncSignal();\r
+ resourceSignal = new NoteResourceSignal();\r
+ \r
+// this.setAutoDelete(false);\r
+ conn = new DatabaseConnection(logger, Global.syncThreadId);\r
+ isConnected = false;\r
+ syncNeeded = false;\r
+ authRefreshNeeded = false;\r
+ keepRunning = true;\r
+ idle = true;\r
+ noteStore = null;\r
+ userStore = null;\r
+ authToken = null;\r
+ disableUploads = false;\r
+// setAutoDelete(false);\r
+ workQueue=new LinkedBlockingQueue<String>(MAX_QUEUED_WAITING);\r
+ }\r
+ @Override\r
+ public void run() {\r
+ try {\r
+ logger.log(logger.EXTREME, "Starting thread");\r
+ while(keepRunning) {\r
+ String work = workQueue.take();\r
+ logger.log(logger.EXTREME, "Work found: " +work);\r
+ if (work.equalsIgnoreCase("stop"))\r
+ return;\r
+ idle=false;\r
+ error=false;\r
+ if (authRefreshNeeded == true) {\r
+ logger.log(logger.EXTREME, "Refreshing connection");\r
+ refreshConnection();\r
+ }\r
+ if (syncNeeded) {\r
+ logger.log(logger.EXTREME, "SyncNeeded is true");\r
+ refreshNeeded=false;\r
+ sequenceDate = conn.getSyncTable().getLastSequenceDate();\r
+ updateSequenceNumber = conn.getSyncTable().getUpdateSequenceNumber();\r
+ try {\r
+ logger.log(logger.EXTREME, "Beginning sync");\r
+ evernoteSync();\r
+ logger.log(logger.EXTREME, "Sync finished");\r
+ } catch (UnknownHostException e) {\r
+ status.message.emit(e.getMessage());\r
+ }\r
+ }\r
+ dirtyNoteGuids = null;\r
+ idle=true;\r
+ logger.log(logger.EXTREME, "Signaling refresh finished. refreshNeeded=" +refreshNeeded);\r
+ syncSignal.finished.emit(refreshNeeded);\r
+ }\r
+ } \r
+ catch (InterruptedException e1) {\r
+ e1.printStackTrace();\r
+ }\r
+ }\r
+\r
+ \r
+ public DatabaseConnection getConnection() {\r
+ return conn;\r
+ }\r
+\r
+ public boolean isIdle() {\r
+ return idle;\r
+ }\r
+\r
+\r
+ public void setConnected(boolean c) {\r
+ isConnected = c;\r
+ }\r
+ public void setKeepRunning(boolean r) {\r
+ logger.log(logger.EXTREME, "Setting keepRunning=" +r);\r
+ keepRunning = r;\r
+ }\r
+ public void setNoteStore(NoteStore.Client c) {\r
+ logger.log(logger.EXTREME, "Setting NoteStore in sync thread");\r
+ noteStore = c;\r
+ }\r
+ public void setUserStore(UserStore.Client c) {\r
+ logger.log(logger.EXTREME, "Setting UserStore in sync thread");\r
+ userStore = c;\r
+ }\r
+\r
+ public void setEvernoteUpdateCount(long s) {\r
+ logger.log(logger.EXTREME, "Setting Update Count in sync thread");\r
+ evernoteUpdateCount = s;\r
+ }\r
+ \r
+ //***************************************************************\r
+ //***************************************************************\r
+ //** These functions deal with Evernote communications\r
+ //***************************************************************\r
+ //***************************************************************\r
+ // Synchronize changes with Evernote\r
+ @SuppressWarnings("unused")\r
+ private void evernoteSync() throws java.net.UnknownHostException {\r
+ logger.log(logger.HIGH, "Entering SyncRunner.evernoteSync");\r
+\r
+ if (isConnected && keepRunning) {\r
+ error = false;\r
+ logger.log(logger.EXTREME, "Synchronizing with Evernote");\r
+ status.message.emit("Synchronizing with Evernote");\r
+ \r
+ // Get user information\r
+ try {\r
+ logger.log(logger.EXTREME, "getting user from userstore");\r
+ User user = userStore.getUser(authToken);\r
+ logger.log(logger.EXTREME, "Saving user information");\r
+ syncSignal.saveUserInformation.emit(user);\r
+ } catch (EDAMUserException e1) {\r
+ e1.printStackTrace();\r
+ status.message.emit("User exception getting user account information. Aborting sync and disconnecting");\r
+ syncSignal.errorDisconnect.emit();\r
+ enDisconnect();\r
+ return;\r
+ } catch (EDAMSystemException e1) {\r
+ e1.printStackTrace();\r
+ status.message.emit("System error user account information. Aborting sync and disconnecting!");\r
+ syncSignal.errorDisconnect.emit();\r
+ enDisconnect();\r
+ return;\r
+ } catch (TException e1) {\r
+ e1.printStackTrace();\r
+ syncSignal.errorDisconnect.emit();\r
+ status.message.emit("Transaction error getting user account information. Aborting sync and disconnecting!");\r
+ enDisconnect();\r
+ return;\r
+ }\r
+ \r
+ // Get sync state\r
+ SyncState syncState = null;\r
+ try { \r
+ logger.log(logger.EXTREME, "Getting sync state");\r
+ syncState = noteStore.getSyncState(authToken); \r
+ syncSignal.saveUploadAmount.emit(syncState.getUploaded());\r
+ syncSignal.saveEvernoteUpdateCount.emit(syncState.getUpdateCount());\r
+ evernoteUpdateCount = syncState.getUpdateCount();\r
+ } catch (EDAMUserException e) {\r
+ e.printStackTrace();\r
+ status.message.emit("Error getting sync state! Aborting sync and disconnecting!");\r
+ syncSignal.errorDisconnect.emit();\r
+ enDisconnect();\r
+ return;\r
+ } catch (EDAMSystemException e) {\r
+ e.printStackTrace();\r
+ status.message.emit("Error getting sync state! Aborting sync and disconnecting!");\r
+ syncSignal.errorDisconnect.emit();\r
+ enDisconnect();\r
+ return;\r
+ } catch (TException e) {\r
+ e.printStackTrace();\r
+ status.message.emit("Error getting sync state! Aborting sync and disconnecting!");\r
+ syncSignal.errorDisconnect.emit();\r
+ enDisconnect();\r
+ return;\r
+ }\r
+ \r
+ if (syncState == null) {\r
+ logger.log(logger.EXTREME, "Sync State is null");\r
+ status.message.emit("Syncronization Error!");\r
+ return;\r
+ }\r
+\r
+ // Determine what to do. \r
+ // If we need to do a full sync.\r
+ logger.log(logger.LOW, "Full Sequence Before: " +syncState.getFullSyncBefore());\r
+ logger.log(logger.LOW, "Last Sequence Date: " +sequenceDate);\r
+ if (syncState.getFullSyncBefore() > sequenceDate) {\r
+ logger.log(logger.EXTREME, "Full sequence date has expired");\r
+ sequenceDate = 0;\r
+ conn.getSyncTable().setLastSequenceDate(0);\r
+ updateSequenceNumber = 0;\r
+ conn.getSyncTable().setUpdateSequenceNumber(0);\r
+ }\r
+\r
+ // If there are remote changes\r
+ logger.log(logger.LOW, "Update Count: " +syncState.getUpdateCount());\r
+ logger.log(logger.LOW, "Last Update Count: " +updateSequenceNumber);\r
+ \r
+ if (syncState.getUpdateCount() > updateSequenceNumber) {\r
+ logger.log(logger.EXTREME, "Refresh needed is true");\r
+ refreshNeeded = true;\r
+ logger.log(logger.EXTREME, "Downloading changes");\r
+ syncRemoteToLocal();\r
+ }\r
+ \r
+ if (!disableUploads) {\r
+ logger.log(logger.EXTREME, "Uploading changes");\r
+ // Synchronize remote changes\r
+ if (!error)\r
+ syncExpunged();\r
+ if (!error)\r
+ syncLocalTags();\r
+ if (!error)\r
+ syncLocalNotebooks();\r
+ if (!error) \r
+ syncDeletedNotes();\r
+ if (!error)\r
+ syncLocalNotes();\r
+ if (!error)\r
+ syncLocalSavedSearches();\r
+ }\r
+ if (refreshNeeded)\r
+ syncSignal.refreshLists.emit();\r
+ if (!error) {\r
+ logger.log(logger.EXTREME, "Sync completed. Errors=" +error);\r
+ if (!disableUploads)\r
+ status.message.emit("Synchronizing complete");\r
+ else\r
+ status.message.emit("Download syncronization complete. Uploads have been disabled.");\r
+ \r
+ logger.log(logger.EXTREME, "Saving sync time");\r
+ if (syncState.getCurrentTime() > sequenceDate)\r
+ sequenceDate = syncState.getCurrentTime();\r
+ if (syncState.getUpdateCount() > updateSequenceNumber)\r
+ updateSequenceNumber = syncState.getUpdateCount();\r
+ conn.getSyncTable().setLastSequenceDate(sequenceDate);\r
+ conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
+ }\r
+ }\r
+ logger.log(logger.HIGH, "Leaving SyncRunner.evernoteSync");\r
+ }\r
+ // Sync deleted items with Evernote\r
+ private void syncExpunged() {\r
+ logger.log(logger.HIGH, "Entering SyncRunner.syncExpunged");\r
+ \r
+ List<DeletedItemRecord> expunged = conn.getDeletedTable().getAllDeleted();\r
+ boolean error = false;\r
+ for (int i=0; i<expunged.size(); i++) {\r
+ \r
+ if (authRefreshNeeded)\r
+ refreshConnection();\r
+\r
+ try {\r
+ if (expunged.get(i).type.equalsIgnoreCase("TAG")) {\r
+ logger.log(logger.EXTREME, "Tag expunged");\r
+ updateSequenceNumber = noteStore.expungeTag(authToken, expunged.get(i).guid);\r
+ conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
+ \r
+ }\r
+ if (expunged.get(i).type.equalsIgnoreCase("NOTEBOOK")) {\r
+ logger.log(logger.EXTREME, "Notebook expunged");\r
+ updateSequenceNumber = noteStore.expungeNotebook(authToken, expunged.get(i).guid);\r
+ conn.getSyncTable().setLastSequenceDate(sequenceDate);\r
+ }\r
+ if (expunged.get(i).type.equalsIgnoreCase("NOTE")) {\r
+ logger.log(logger.EXTREME, "Note expunged");\r
+ updateSequenceNumber = noteStore.deleteNote(authToken, expunged.get(i).guid);\r
+ conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
+ }\r
+ if (expunged.get(i).type.equalsIgnoreCase("SAVEDSEARCH")) {\r
+ logger.log(logger.EXTREME, "saved search expunged");\r
+ updateSequenceNumber = noteStore.expungeSearch(authToken, expunged.get(i).guid);\r
+ conn.getSyncTable().setLastSequenceDate(sequenceDate);\r
+ }\r
+ } catch (EDAMUserException e) {\r
+ logger.log(logger.LOW, "EDAM User Excepton in syncExpunged: " +expunged.get(i).guid);\r
+ logger.log(logger.LOW, e.getStackTrace());\r
+ error = true;\r
+ } catch (EDAMSystemException e) {\r
+ logger.log(logger.LOW, "EDAM System Excepton in syncExpunged: "+expunged.get(i).guid);\r
+ logger.log(logger.LOW, e.getStackTrace());\r
+ error=true;\r
+ } catch (EDAMNotFoundException e) {\r
+ logger.log(logger.LOW, "EDAM Not Found Excepton in syncExpunged: "+expunged.get(i).guid);\r
+// logger.log(logger.LOW, e.getStackTrace());\r
+ //error=true;\r
+ } catch (TException e) {\r
+ logger.log(logger.LOW, "EDAM TExcepton in syncExpunged: "+expunged.get(i).guid);\r
+ logger.log(logger.LOW, e.getStackTrace());\r
+ error=true;\r
+ }\r
+ }\r
+ if (!error)\r
+ conn.getDeletedTable().expungeAllDeletedRecords();\r
+ \r
+ logger.log(logger.HIGH, "Leaving SyncRunner.syncExpunged");\r
+\r
+ }\r
+ private void syncDeletedNotes() {\r
+ if (syncDeletedContent)\r
+ return;\r
+ logger.log(logger.HIGH, "Entering SyncRunner.syncDeletedNotes");\r
+ status.message.emit("Synchronizing deleted notes.");\r
+\r
+ List<Note> notes = conn.getNoteTable().getDirty();\r
+ // Sync the local notebooks with Evernote's\r
+ for (int i=0; i<notes.size() && keepRunning; i++) {\r
+ \r
+ if (authRefreshNeeded)\r
+ refreshConnection();\r
+ \r
+ Note enNote = notes.get(i);\r
+ try {\r
+ if (enNote.getUpdateSequenceNum() > 0 && (enNote.isActive() == false || enNote.getDeleted() > 0)) {\r
+ if (syncDeletedContent) {\r
+ logger.log(logger.EXTREME, "Deleted note found & synch content selected");\r
+ Note delNote = conn.getNoteTable().getNote(enNote.getGuid(), true, true, true, true, true);\r
+ delNote = getNoteContent(delNote);\r
+ delNote = noteStore.updateNote(authToken, delNote);\r
+ enNote.setUpdateSequenceNum(delNote.getUpdateSequenceNum());\r
+ conn.getNoteTable().updateNoteSequence(enNote.getGuid(), enNote.getUpdateSequenceNum());\r
+ } else {\r
+ logger.log(logger.EXTREME, "Deleted note found & sync content not selected");\r
+ int usn = noteStore.deleteNote(authToken, enNote.getGuid());\r
+ enNote.setUpdateSequenceNum(usn);\r
+ conn.getNoteTable().updateNoteSequence(enNote.getGuid(), enNote.getUpdateSequenceNum()); \r
+ }\r
+ logger.log(logger.EXTREME, "Resetting deleted dirty flag");\r
+ conn.getNoteTable().resetDirtyFlag(enNote.getGuid());\r
+ updateSequenceNumber = enNote.getUpdateSequenceNum();\r
+ logger.log(logger.EXTREME, "Saving sequence number");\r
+ conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
+ } \r
+ } catch (EDAMUserException e) {\r
+ //logger.log(logger.LOW, "*** EDAM User Excepton syncLocalNotes "+e);\r
+ //status.message.emit("Error sending local note: " +e.getParameter());\r
+ //logger.log(logger.LOW, e.toString()); \r
+ //error = true;\r
+ } catch (EDAMSystemException e) {\r
+ logger.log(logger.LOW, "*** EDAM System Excepton syncLocalNotes "+e);\r
+ status.message.emit("Error: " +e);\r
+ logger.log(logger.LOW, e.toString()); \r
+ error = true;\r
+ } catch (EDAMNotFoundException e) {\r
+ //logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalNotes " +e);\r
+ //status.message.emit("Error deleting local note: " +e +" - Continuing");\r
+ //logger.log(logger.LOW, e.toString()); \r
+ //error = true;\r
+ } catch (TException e) {\r
+ logger.log(logger.LOW, "*** EDAM TExcepton syncLocalNotes "+e);\r
+ status.message.emit("Error sending local note: " +e);\r
+ logger.log(logger.LOW, e.toString()); \r
+ error = true;\r
+ } \r
+ }\r
+ }\r
+ // Sync notes with Evernote\r
+ private void syncLocalNotes() {\r
+ logger.log(logger.HIGH, "Entering SyncRunner.syncNotes");\r
+ status.message.emit("Sending local notes.");\r
+\r
+ List<Note> notes = conn.getNoteTable().getDirty();\r
+ // Sync the local notebooks with Evernote's\r
+ for (int i=0; i<notes.size() && keepRunning; i++) {\r
+ \r
+ if (authRefreshNeeded)\r
+ refreshConnection();\r
+ \r
+ Note enNote = notes.get(i);\r
+ if (enNote.isActive()) {\r
+ try {\r
+ logger.log(logger.EXTREME, "Active dirty note found - non new");\r
+ if (enNote.getUpdateSequenceNum() > 0) {\r
+ enNote = getNoteContent(enNote);\r
+ logger.log(logger.MEDIUM, "Updating note : "+ enNote.getGuid() +" <title>" +enNote.getTitle()+"</title>");\r
+ enNote = noteStore.updateNote(authToken, enNote);\r
+ } else { \r
+ logger.log(logger.EXTREME, "Active dirty found - new note");\r
+ logger.log(logger.MEDIUM, "Creating note : "+ enNote.getGuid() +" <title>" +enNote.getTitle()+"</title>");\r
+ String oldGuid = enNote.getGuid();\r
+ enNote = getNoteContent(enNote);\r
+ enNote = noteStore.createNote(authToken, enNote);\r
+ noteSignal.guidChanged.emit(oldGuid, enNote.getGuid());\r
+ conn.getNoteTable().updateNoteGuid(oldGuid, enNote.getGuid());\r
+ }\r
+ updateSequenceNumber = enNote.getUpdateSequenceNum();\r
+ logger.log(logger.EXTREME, "Saving note");\r
+ conn.getNoteTable().updateNoteSequence(enNote.getGuid(), enNote.getUpdateSequenceNum());\r
+ List<Resource> rl = enNote.getResources();\r
+ logger.log(logger.EXTREME, "Getting note resources");\r
+ for (int j=0; j<enNote.getResourcesSize() && keepRunning; j++) {\r
+ Resource newRes = rl.get(j);\r
+ Data d = newRes.getData();\r
+ if (d!=null) { \r
+ logger.log(logger.EXTREME, "Calculating resource hash");\r
+ String hash = byteArrayToHexString(d.getBodyHash());\r
+ logger.log(logger.EXTREME, "updating resources by hash");\r
+ String oldGuid = conn.getNoteTable().noteResourceTable.getNoteResourceGuidByHashHex(enNote.getGuid(), hash);\r
+ conn.getNoteTable().updateNoteResourceGuidbyHash(enNote.getGuid(), newRes.getGuid(), hash);\r
+ resourceSignal.resourceGuidChanged.emit(enNote.getGuid(), oldGuid, newRes.getGuid());\r
+ }\r
+ }\r
+ logger.log(logger.EXTREME, "Resetting note dirty flag");\r
+ conn.getNoteTable().resetDirtyFlag(enNote.getGuid());\r
+ updateSequenceNumber = enNote.getUpdateSequenceNum();\r
+ logger.log(logger.EXTREME, "Emitting note sequence number change");\r
+ conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
+\r
+ } catch (EDAMUserException e) {\r
+ logger.log(logger.LOW, "*** EDAM User Excepton syncLocalNotes "+e);\r
+ status.message.emit("Error sending local note: " +e.getParameter());\r
+ logger.log(logger.LOW, e.toString()); \r
+ error = true;\r
+ } catch (EDAMSystemException e) {\r
+ logger.log(logger.LOW, "*** EDAM System Excepton syncLocalNotes "+e);\r
+ status.message.emit("Error: " +e);\r
+ logger.log(logger.LOW, e.toString()); \r
+ error = true;\r
+ } catch (EDAMNotFoundException e) {\r
+ logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalNotes " +e);\r
+ status.message.emit("Error sending local note: " +e);\r
+ logger.log(logger.LOW, e.toString()); \r
+ error = true;\r
+ } catch (TException e) {\r
+ logger.log(logger.LOW, "*** EDAM TExcepton syncLocalNotes "+e);\r
+ status.message.emit("Error sending local note: " +e);\r
+ logger.log(logger.LOW, e.toString()); \r
+ error = true;\r
+ }\r
+ }\r
+ }\r
+ logger.log(logger.HIGH, "Entering SyncRunner.syncNotes");\r
+\r
+ }\r
+ // Sync Notebooks with Evernote\r
+ private void syncLocalNotebooks() {\r
+ logger.log(logger.HIGH, "Entering SyncRunner.syncLocalNotebooks");\r
+ \r
+ status.message.emit("Sending local notebooks.");\r
+ List<Notebook> remoteList = new ArrayList<Notebook>();\r
+ try {\r
+ logger.log(logger.EXTREME, "Getting remote notebooks to compare with local");\r
+ remoteList = noteStore.listNotebooks(authToken);\r
+ } catch (EDAMUserException e1) {\r
+ logger.log(logger.LOW, "*** EDAM User Excepton syncLocalNotebooks getting remote Notebook List");\r
+ status.message.emit("Error: " +e1);\r
+ logger.log(logger.LOW, e1.toString()); \r
+ error = true;\r
+ } catch (EDAMSystemException e1) {\r
+ logger.log(logger.LOW, "*** EDAM System Excepton syncLocalNotebooks getting remote Notebook List");\r
+ status.message.emit("Error: " +e1);\r
+ logger.log(logger.LOW, e1.toString()); \r
+ error = true;\r
+ } catch (TException e1) {\r
+ logger.log(logger.LOW, "*** EDAM Transaction Excepton syncLocalNotebooks getting remote Notebook List");\r
+ status.message.emit("Error: " +e1);\r
+ logger.log(logger.LOW, e1.toString()); \r
+ error = true;\r
+ }\r
+ logger.log(logger.EXTREME, "Getting local dirty notebooks");\r
+ List<Notebook> notebooks = conn.getNotebookTable().getDirty();\r
+ int sequence;\r
+ // Sync the local notebooks with Evernote's\r
+ for (int i=0; i<notebooks.size() && keepRunning; i++) {\r
+ \r
+ if (authRefreshNeeded)\r
+ refreshConnection();\r
+ \r
+ Notebook enNotebook = notebooks.get(i);\r
+ try {\r
+ if (enNotebook.getUpdateSequenceNum() > 0) {\r
+ logger.log(logger.EXTREME, "Existing notebook is dirty");\r
+ sequence = noteStore.updateNotebook(authToken, enNotebook);\r
+ } else {\r
+ logger.log(logger.EXTREME, "New dirty notebook found");\r
+ String oldGuid = enNotebook.getGuid();\r
+ boolean found = false;\r
+ \r
+ // Look for a notebook with the same name. If one is found, we don't need \r
+ // to create another one\r
+ logger.log(logger.EXTREME, "Looking for matching notebook name");\r
+ for (int k=0; k<remoteList.size() && !found && keepRunning; k++) {\r
+ if (remoteList.get(k).getName().equalsIgnoreCase(enNotebook.getName())) {\r
+ enNotebook = remoteList.get(k);\r
+ logger.log(logger.EXTREME, "Matching notebook found");\r
+ found = true;\r
+ }\r
+ }\r
+ if (!found)\r
+ enNotebook = noteStore.createNotebook(authToken, enNotebook);\r
+ \r
+ logger.log(logger.EXTREME, "Updating notebook in database");\r
+ conn.getNotebookTable().updateNotebookGuid(oldGuid, enNotebook.getGuid());\r
+ sequence = enNotebook.getUpdateSequenceNum();\r
+ }\r
+ logger.log(logger.EXTREME, "Updating notebook sequence in database");\r
+ conn.getNotebookTable().updateNotebookSequence(enNotebook.getGuid(), sequence);\r
+ logger.log(logger.EXTREME, "Resetting dirty flag in notebook");\r
+ conn.getNotebookTable().resetDirtyFlag(enNotebook.getGuid());\r
+ updateSequenceNumber = sequence;\r
+ logger.log(logger.EXTREME, "Emitting sequence number to main thread");\r
+ conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
+ } catch (EDAMUserException e) {\r
+ logger.log(logger.LOW, "*** EDAM User Excepton syncLocalNotebooks");\r
+ logger.log(logger.LOW, e.toString()); \r
+ error = true;\r
+ } catch (EDAMSystemException e) {\r
+ logger.log(logger.LOW, "*** EDAM System Excepton syncLocalNotebooks");\r
+ logger.log(logger.LOW, e.toString()); \r
+ error = true;\r
+ } catch (EDAMNotFoundException e) {\r
+ logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalNotebooks");\r
+ logger.log(logger.LOW, e.toString()); \r
+ error = true;\r
+ } catch (TException e) {\r
+ logger.log(logger.LOW, "*** EDAM TExcepton syncLocalNotebooks");\r
+ logger.log(logger.LOW, e.toString()); \r
+ error = true;\r
+ } \r
+ }\r
+ logger.log(logger.HIGH, "Leaving SyncRunner.syncLocalNotebooks");\r
+\r
+ }\r
+ // Sync Tags with Evernote\r
+ private void syncLocalTags() {\r
+ logger.log(logger.HIGH, "Entering SyncRunner.syncLocalTags");\r
+ List<Tag> remoteList = new ArrayList<Tag>();\r
+ status.message.emit("Sending local tags.");\r
+ \r
+ try {\r
+ logger.log(logger.EXTREME, "Getting remote tags to compare names with the local tags");\r
+ remoteList = noteStore.listTags(authToken);\r
+ } catch (EDAMUserException e1) {\r
+ logger.log(logger.LOW, "*** EDAM User Excepton syncLocalTags getting remote Tag List");\r
+ status.message.emit("Error: " +e1);\r
+ logger.log(logger.LOW, e1.toString()); \r
+ error = true;\r
+ } catch (EDAMSystemException e1) {\r
+ logger.log(logger.LOW, "*** EDAM System Excepton syncLocalTags getting remote Tag List");\r
+ status.message.emit("Error: " +e1);\r
+ logger.log(logger.LOW, e1.toString()); \r
+ error = true;\r
+ } catch (TException e1) {\r
+ logger.log(logger.LOW, "*** EDAM Transaction Excepton syncLocalTags getting remote Tag List");\r
+ status.message.emit("Error: " +e1);\r
+ logger.log(logger.LOW, e1.toString()); \r
+ error = true;\r
+ } \r
+ \r
+ int sequence;\r
+ \r
+ Tag enTag = findNextTag();\r
+ while(enTag!=null) {\r
+ if (authRefreshNeeded)\r
+ refreshConnection();\r
+\r
+ try {\r
+ if (enTag.getUpdateSequenceNum() > 0) {\r
+ logger.log(logger.EXTREME, "Updating tag");\r
+ sequence = noteStore.updateTag(authToken, enTag);\r
+ } else {\r
+ \r
+ // Look for a tag with the same name. If one is found, we don't need \r
+ // to create another one\r
+ logger.log(logger.EXTREME, "New tag. Comparing with remote names");\r
+ boolean found = false;\r
+ String oldGuid = enTag.getGuid();\r
+ for (int k=0; k<remoteList.size() && !found && keepRunning; k++) {\r
+ if (remoteList.get(k).getName().equalsIgnoreCase(enTag.getName())) {\r
+ conn.getTagTable().updateTagGuid(enTag.getGuid(), remoteList.get(k).getGuid());\r
+ enTag = remoteList.get(k);\r
+ logger.log(logger.EXTREME, "Matching tag name found");\r
+ found = true;\r
+ }\r
+ }\r
+ if (!found)\r
+ enTag = noteStore.createTag(authToken, enTag);\r
+ else\r
+ enTag.setUpdateSequenceNum(noteStore.updateTag(authToken,enTag));\r
+ sequence = enTag.getUpdateSequenceNum();\r
+ if (!oldGuid.equals(enTag.getGuid())) {\r
+ logger.log(logger.EXTREME, "Updating tag guid");\r
+ conn.getTagTable().updateTagGuid(oldGuid, enTag.getGuid());\r
+ }\r
+ }\r
+ logger.log(logger.EXTREME, "Updating tag sequence number");\r
+ conn.getTagTable().updateTagSequence(enTag.getGuid(), sequence);\r
+ logger.log(logger.EXTREME, "Resetting tag dirty flag");\r
+ conn.getTagTable().resetDirtyFlag(enTag.getGuid());\r
+ logger.log(logger.EXTREME, "Emitting sequence number to the main thread.");\r
+ updateSequenceNumber = sequence;\r
+ conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
+ } catch (EDAMUserException e) {\r
+ logger.log(logger.LOW, "*** EDAM User Excepton syncLocalTags");\r
+ logger.log(logger.LOW, e.toString()); \r
+ error = true;\r
+ } catch (EDAMSystemException e) {\r
+ logger.log(logger.LOW, "** EDAM System Excepton syncLocalTags");\r
+ logger.log(logger.LOW, e.toString()); \r
+ error = true;\r
+ } catch (EDAMNotFoundException e) {\r
+ logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalTags");\r
+ logger.log(logger.LOW, e.toString()); \r
+ error = true;\r
+ } catch (TException e) {\r
+ logger.log(logger.LOW, "*** EDAM TExcepton syncLocalTags");\r
+ logger.log(logger.LOW, e.toString()); \r
+ error = true;\r
+ } \r
+ \r
+ // Find the next tag\r
+ logger.log(logger.EXTREME, "Finding next tag");\r
+ enTag = findNextTag();\r
+ }\r
+ logger.log(logger.HIGH, "Leaving SyncRunner.syncLocalTags");\r
+ }\r
+ // Sync Tags with Evernote\r
+ private void syncLocalSavedSearches() {\r
+ logger.log(logger.HIGH, "Entering SyncRunner.syncLocalSavedSearches");\r
+ List<SavedSearch> remoteList = new ArrayList<SavedSearch>();\r
+ status.message.emit("Sending saved searches.");\r
+ \r
+ logger.log(logger.EXTREME, "Getting saved searches to compare with local");\r
+ try {\r
+ remoteList = noteStore.listSearches(authToken);\r
+ } catch (EDAMUserException e1) {\r
+ logger.log(logger.LOW, "*** EDAM User Excepton syncLocalTags getting remote saved search List");\r
+ status.message.emit("Error: " +e1);\r
+ logger.log(logger.LOW, e1.toString()); \r
+ error = true;\r
+ } catch (EDAMSystemException e1) {\r
+ logger.log(logger.LOW, "*** EDAM System Excepton syncLocalTags getting remote saved search List");\r
+ status.message.emit("Error: " +e1);\r
+ logger.log(logger.LOW, e1.toString()); \r
+ error = true;\r
+ } catch (TException e1) {\r
+ logger.log(logger.LOW, "*** EDAM Transaction Excepton syncLocalTags getting remote saved search List");\r
+ status.message.emit("Error: " +e1);\r
+ logger.log(logger.LOW, e1.toString()); \r
+ error = true;\r
+ } \r
+ \r
+ List<SavedSearch> searches = conn.getSavedSearchTable().getDirty();\r
+ int sequence;\r
+ // Sync the local notebooks with Evernote's\r
+ logger.log(logger.EXTREME, "Beginning to send saved searches");\r
+ for (int i=0; i<searches.size() && keepRunning; i++) {\r
+ \r
+ if (authRefreshNeeded)\r
+ refreshConnection();\r
+ \r
+ SavedSearch enSearch = searches.get(i);\r
+ try {\r
+ if (enSearch.getUpdateSequenceNum() > 0) \r
+ sequence = noteStore.updateSearch(authToken, enSearch);\r
+ else {\r
+ logger.log(logger.EXTREME, "New saved search found.");\r
+ // Look for a tag with the same name. If one is found, we don't need \r
+ // to create another one\r
+ boolean found = false;\r
+ logger.log(logger.EXTREME, "Matching remote saved search names with local");\r
+ for (int k=0; k<remoteList.size() && !found && keepRunning; k++) {\r
+ if (remoteList.get(k).getName().equalsIgnoreCase(enSearch.getName())) {\r
+ enSearch = remoteList.get(k);\r
+ found = true;\r
+ logger.log(logger.EXTREME, "Matching saved search found");\r
+ sequence = enSearch.getUpdateSequenceNum();\r
+ }\r
+ }\r
+\r
+ String oldGuid = enSearch.getGuid();\r
+ if (!found)\r
+ enSearch = noteStore.createSearch(authToken, enSearch);\r
+ sequence = enSearch.getUpdateSequenceNum();\r
+ logger.log(logger.EXTREME, "Updating tag guid in local database");\r
+ conn.getTagTable().updateTagGuid(oldGuid, enSearch.getGuid());\r
+ }\r
+ logger.log(logger.EXTREME, "Updating tag sequence in local database");\r
+ conn.getSavedSearchTable().updateSavedSearchSequence(enSearch.getGuid(), sequence);\r
+ logger.log(logger.EXTREME, "Resetting tag dirty flag");\r
+ conn.getSavedSearchTable().resetDirtyFlag(enSearch.getGuid());\r
+ logger.log(logger.EXTREME, "Emitting sequence number to the main thread.");\r
+ updateSequenceNumber = sequence;\r
+ conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
+ } catch (EDAMUserException e) {\r
+ logger.log(logger.LOW, "*** EDAM User Excepton syncLocalTags");\r
+ logger.log(logger.LOW, e.toString()); \r
+ error = true;\r
+ } catch (EDAMSystemException e) {\r
+ logger.log(logger.LOW, "** EDAM System Excepton syncLocalTags");\r
+ logger.log(logger.LOW, e.toString()); \r
+ error = true;\r
+ } catch (EDAMNotFoundException e) {\r
+ logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalTags");\r
+ logger.log(logger.LOW, e.toString()); \r
+ error = true;\r
+ } catch (TException e) {\r
+ logger.log(logger.LOW, "*** EDAM TExcepton syncLocalTags");\r
+ logger.log(logger.LOW, e.toString()); \r
+ error = true;\r
+ } \r
+ }\r
+ logger.log(logger.HIGH, "Entering SyncRunner.syncLocalSavedSearches");\r
+ } \r
+\r
+ // Sync evernote changes with local database\r
+ private void syncRemoteToLocal() {\r
+ logger.log(logger.HIGH, "Entering SyncRunner.syncRemoteToLocal");\r
+\r
+ List<Note> dirtyNotes = conn.getNoteTable().getDirty();\r
+ dirtyNoteGuids = new Vector<String>();\r
+ for (int i=0; i<dirtyNotes.size() && keepRunning; i++) {\r
+ dirtyNoteGuids.add(dirtyNotes.get(i).getGuid());\r
+ }\r
+ \r
+ int chunkSize = 10;\r
+ SyncChunk chunk = null;\r
+ boolean fullSync = false;\r
+ boolean more = true;\r
+ \r
+ if (updateSequenceNumber == 0)\r
+ fullSync = true;\r
+ \r
+ status.message.emit("Downloading 0% complete.");\r
+ \r
+ while(more && keepRunning) {\r
+ \r
+ if (authRefreshNeeded)\r
+ refreshConnection();\r
+ \r
+ chunk = null;\r
+ int sequence = updateSequenceNumber;\r
+ try {\r
+ logger.log(logger.EXTREME, "Getting chunk from Evernote");\r
+ chunk = noteStore.getSyncChunk(authToken, sequence, chunkSize, fullSync);\r
+ } catch (EDAMUserException e) {\r
+ error = true;\r
+ e.printStackTrace();\r
+ status.message.emit(e.getMessage());\r
+ } catch (EDAMSystemException e) {\r
+ error = true;\r
+ e.printStackTrace();\r
+ status.message.emit(e.getMessage());\r
+ } catch (TException e) {\r
+ error = true;\r
+ e.printStackTrace();\r
+ status.message.emit(e.getMessage());\r
+ } \r
+ if (error || chunk == null) \r
+ return;\r
+ \r
+ \r
+ \r
+ syncRemoteTags(chunk.getTags());\r
+ syncRemoteSavedSearches(chunk.getSearches());\r
+ syncRemoteNotebooks(chunk.getNotebooks());\r
+ syncRemoteNotes(chunk.getNotes(), fullSync);\r
+ syncRemoteResources(chunk.getResources());\r
+ \r
+ // Do the local deletes\r
+ logger.log(logger.EXTREME, "Doing local deletes");\r
+ List<String> guid = chunk.getExpungedNotes();\r
+ if (guid != null) \r
+ for (int i=0; i<guid.size() && keepRunning; i++) {\r
+ logger.log(logger.EXTREME, "Expunging local note from database");\r
+ conn.getNoteTable().expungeNote(guid.get(i), true, false);\r
+ }\r
+ guid = chunk.getExpungedNotebooks();\r
+ if (guid != null)\r
+ for (int i=0; i<guid.size() && keepRunning; i++) {\r
+ logger.log(logger.EXTREME, "Expunging local notebook from database");\r
+ conn.getNotebookTable().expungeNotebook(guid.get(i), false);\r
+ }\r
+ guid = chunk.getExpungedTags();\r
+ if (guid != null)\r
+ for (int i=0; i<guid.size() && keepRunning; i++) {\r
+ logger.log(logger.EXTREME, "Expunging tags from local database");\r
+ conn.getTagTable().expungeTag(guid.get(i), false);\r
+ }\r
+ guid = chunk.getExpungedSearches();\r
+ if (guid != null) \r
+ for (int i=0; i<guid.size() && keepRunning; i++) {\r
+ logger.log(logger.EXTREME, "Expunging saved search from local database");\r
+ conn.getSavedSearchTable().expungeSavedSearch(guid.get(i), false);\r
+ }\r
+\r
+ \r
+ // Check for more notes\r
+ if (chunk.getChunkHighUSN() <= updateSequenceNumber) \r
+ more = false;\r
+ if (error)\r
+ more = false;\r
+ logger.log(logger.EXTREME, "More notes? " +more);\r
+\r
+ \r
+ // Save the chunk sequence number\r
+ if (!error && chunk.getChunkHighUSN() > 0) {\r
+ logger.log(logger.EXTREME, "emitting sequence number to main thread");\r
+ updateSequenceNumber = chunk.getChunkHighUSN();\r
+ conn.getSyncTable().setLastSequenceDate(chunk.getCurrentTime());\r
+ conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
+ }\r
+ \r
+ \r
+ if (more) {\r
+ long pct = chunk.getChunkHighUSN() * 100;\r
+ conn.getSyncTable().setLastSequenceDate(chunk.getCurrentTime());\r
+ pct = pct/evernoteUpdateCount;\r
+ status.message.emit("Downloading " +new Long(pct).toString()+"% complete.");\r
+ }\r
+ }\r
+\r
+ logger.log(logger.HIGH, "Leaving SyncRunner.syncRemoteToLocal");\r
+ }\r
+ // Sync remote tags\r
+ private void syncRemoteTags(List<Tag> tags) {\r
+ logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteTags");\r
+ if (tags != null) {\r
+ for (int i=0; i<tags.size() && keepRunning; i++) {\r
+ String oldGuid;\r
+ oldGuid = conn.getTagTable().findTagByName(tags.get(i).getName());\r
+ if (oldGuid != null && !tags.get(i).getGuid().equalsIgnoreCase(oldGuid))\r
+ conn.getTagTable().updateTagGuid(oldGuid, tags.get(i).getGuid());\r
+ conn.getTagTable().syncTag(tags.get(i), false);\r
+ }\r
+ }\r
+ logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteTags");\r
+ }\r
+ // Sync remote tags\r
+ private void syncRemoteSavedSearches(List<SavedSearch> searches) {\r
+ logger.log(logger.EXTREME, "Entering SyncRunner.syncSavedSearches");\r
+ if (searches != null) {\r
+ for (int i=0; i<searches.size() && keepRunning; i++) {\r
+ String oldGuid;\r
+ oldGuid = conn.getSavedSearchTable().findSavedSearchByName(searches.get(i).getName());\r
+ if (oldGuid != null && !searches.get(i).getGuid().equalsIgnoreCase(oldGuid))\r
+ conn.getSavedSearchTable().updateSavedSearchGuid(oldGuid, searches.get(i).getGuid());\r
+ conn.getSavedSearchTable().syncSavedSearch(searches.get(i), false);\r
+ }\r
+ }\r
+ logger.log(logger.EXTREME, "Leaving SyncRunner.syncSavedSearches");\r
+ }\r
+ // Sync remote Notebooks 2\r
+ private void syncRemoteNotebooks(List<Notebook> notebooks) {\r
+ logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteNotebooks");\r
+ if (notebooks != null) {\r
+ for (int i=0; i<notebooks.size() && keepRunning; i++) {\r
+ String oldGuid;\r
+ oldGuid = conn.getNotebookTable().findNotebookByName(notebooks.get(i).getName());\r
+ if (oldGuid != null && !conn.getNotebookTable().isNotebookLocal(oldGuid) && !notebooks.get(i).getGuid().equalsIgnoreCase(oldGuid))\r
+ conn.getNotebookTable().updateNotebookGuid(oldGuid, notebooks.get(i).getGuid());\r
+ conn.getNotebookTable().syncNotebook(notebooks.get(i), false); \r
+ }\r
+ } \r
+ logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteNotebooks");\r
+ }\r
+ // Sync remote Resources\r
+ private void syncRemoteResources(List<Resource> resource) {\r
+ // This is how the logic for this works.\r
+ // 1.) If the resource is not in the local database, we add it.\r
+ // 2.) If a copy of the resource is in the local database and the note isn't dirty, we update the local copy\r
+ // 3.) If a copy of the resource is in the local databbase and it is dirty and the hash doesn't match, we ignore it because there\r
+ // is a conflict. The note conflict should get a copy of the resource at that time.\r
+ \r
+ logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteResources");\r
+ if (resource != null) {\r
+ for (int i=0; i<resource.size() && keepRunning; i++) {\r
+ boolean saveNeeded = false;\r
+/* #1 */ Resource r = getEvernoteResource(resource.get(i).getGuid(), true,true,true);\r
+ Resource l = conn.getNoteTable().noteResourceTable.getNoteResource(r.getGuid(), false);\r
+ if (l == null) {\r
+ saveNeeded = true;\r
+ } else {\r
+/* #2 */ boolean isNoteDirty = conn.getNoteTable().isNoteDirty(r.getNoteGuid());\r
+ if (!isNoteDirty)\r
+ saveNeeded = true;\r
+ else {\r
+/* #3 */ String remoteHash = "";\r
+ if (r != null && r.getData() != null && r.getData().getBodyHash() != null)\r
+ remoteHash = byteArrayToHexString(r.getData().getBodyHash());\r
+ String localHash = "";\r
+ if (l != null && l.getData() != null && l.getData().getBodyHash() != null)\r
+ remoteHash = byteArrayToHexString(l.getData().getBodyHash());\r
+ \r
+ if (localHash.equalsIgnoreCase(remoteHash))\r
+ saveNeeded = true;\r
+ }\r
+ }\r
+ \r
+ if (saveNeeded) \r
+ conn.getNoteTable().noteResourceTable.updateNoteResource(r, false);\r
+\r
+ }\r
+ }\r
+ logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteResources");\r
+ }\r
+ // Sync remote notebooks\r
+ private void syncRemoteNotes(List<Note> note, boolean fullSync) {\r
+ logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteNotes");\r
+ if (note != null) {\r
+ for (int i=0; i<note.size() && keepRunning; i++) {\r
+ Note n = getEvernoteNote(note.get(i).getGuid(), true, fullSync, true,true);\r
+ if (n!=null) {\r
+ \r
+ // Basically, this is how the sync logic for a note works.\r
+ // If the remote note has changed and the local has not, we\r
+ // accept the change.\r
+ // If both the local & remote have changed but the sequence\r
+ // numbers are the same, we don't accept the change. This\r
+ // seems to happen when attachments are indexed by the server.\r
+ // If both the local & remote have changed and the sequence numbers\r
+ // are different we move the local copy to a local notebook (making sure\r
+ // to copy all resources) and we accept the new one. \r
+ boolean conflictingNote = true;\r
+ logger.log(logger.EXTREME, "Checking for duplicate note " +n.getGuid());\r
+ if (dirtyNoteGuids.contains(n.getGuid())) { \r
+ logger.log(logger.EXTREME, "Conflict check beginning");\r
+ conflictingNote = checkForConflict(n);\r
+ logger.log(logger.EXTREME, "Conflict check results " +conflictingNote);\r
+ if (conflictingNote)\r
+ moveConflictingNote(n.getGuid());\r
+ }\r
+ if (conflictingNote || fullSync) {\r
+ logger.log(logger.EXTREME, "Saving Note");\r
+ conn.getNoteTable().syncNote(n, false);\r
+ noteSignal.noteChanged.emit(n.getGuid(), null); // Signal to ivalidate note cache\r
+ logger.log(logger.EXTREME, "Note Saved");\r
+ if (fullSync && n.getResources() != null) {\r
+ for (int q=0; q<n.getResources().size() && keepRunning; q++) {\r
+ logger.log(logger.EXTREME, "Getting note resources.");\r
+ conn.getNoteTable().noteResourceTable.updateNoteResource(n.getResources().get(q), false);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteNotes");\r
+ }\r
+ private Note getEvernoteNote(String guid, boolean withContent, boolean withResourceData, boolean withResourceRecognition, boolean withResourceAlternateData) { \r
+ Note n = null;\r
+ try {\r
+ logger.log(logger.EXTREME, "Retrieving note " +guid);\r
+ n = noteStore.getNote(authToken, guid, withContent, withResourceData, withResourceRecognition, withResourceAlternateData);\r
+ logger.log(logger.EXTREME, "Note " +guid +" has been retrieved.");\r
+ } catch (EDAMUserException e) {\r
+ logger.log(logger.LOW, "*** EDAM User Excepton getEvernoteNote");\r
+ logger.log(logger.LOW, e.toString()); \r
+ error = true;\r
+ e.printStackTrace();\r
+ } catch (EDAMSystemException e) {\r
+ logger.log(logger.LOW, "*** EDAM System Excepton getEvernoteNote");\r
+ logger.log(logger.LOW, e.toString()); \r
+ error = true;\r
+ e.printStackTrace();\r
+ } catch (EDAMNotFoundException e) {\r
+ logger.log(logger.LOW, "*** EDAM Not Found Excepton getEvernoteNote");\r
+ logger.log(logger.LOW, e.toString()); \r
+ error = true;\r
+ e.printStackTrace();\r
+ } catch (TException e) {\r
+ logger.log(logger.LOW, "*** EDAM TExcepton getEvernoteNote");\r
+ logger.log(logger.LOW, e.toString()); \r
+ error = true;\r
+ e.printStackTrace();\r
+ }\r
+ return n;\r
+ }\r
+ private Resource getEvernoteResource(String guid, boolean withData, boolean withRecognition, boolean withAttributes) { \r
+ Resource n = null;\r
+ try {\r
+ logger.log(logger.EXTREME, "Retrieving resource " +guid);\r
+ n = noteStore.getResource(authToken, guid, withData, withRecognition, withAttributes, withAttributes);\r
+ logger.log(logger.EXTREME, "Resource " +guid +" has been retrieved.");\r
+ } catch (EDAMUserException e) {\r
+ logger.log(logger.LOW, "*** EDAM User Excepton getEvernoteNote");\r
+ logger.log(logger.LOW, e.toString()); \r
+ error = true;\r
+ e.printStackTrace();\r
+ } catch (EDAMSystemException e) {\r
+ logger.log(logger.LOW, "*** EDAM System Excepton getEvernoteNote");\r
+ logger.log(logger.LOW, e.toString()); \r
+ error = true;\r
+ e.printStackTrace();\r
+ } catch (EDAMNotFoundException e) {\r
+ logger.log(logger.LOW, "*** EDAM Not Found Excepton getEvernoteNote");\r
+ logger.log(logger.LOW, e.toString()); \r
+ error = true;\r
+ e.printStackTrace();\r
+ } catch (TException e) {\r
+ logger.log(logger.LOW, "*** EDAM TExcepton getEvernoteNote");\r
+ logger.log(logger.LOW, e.toString()); \r
+ error = true;\r
+ e.printStackTrace();\r
+ }\r
+ return n;\r
+ }\r
+\r
+ \r
+ private boolean checkForConflict(Note n) {\r
+ logger.log(logger.EXTREME, "Checking note sequence number " +n.getGuid());\r
+ Note oldNote = conn.getNoteTable().getNote(n.getGuid(), false, false, false, false, false);\r
+ logger.log(logger.EXTREME, "Local/Remote sequence numbers: " +oldNote.getUpdateSequenceNum()+"/"+n.getUpdateSequenceNum());\r
+ if (oldNote.getUpdateSequenceNum() == n.getUpdateSequenceNum())\r
+ return false;\r
+ return true;\r
+ }\r
+ \r
+ private void moveConflictingNote(String guid) {\r
+ logger.log(logger.EXTREME, "Conflicting change found for note " +guid);\r
+ List<Notebook> books = conn.getNotebookTable().getAllLocal();\r
+ String notebookGuid = null;\r
+ for (int i=0; i<books.size() && keepRunning; i++) {\r
+ if (books.get(i).getName().equalsIgnoreCase("Conflicting Changes (local)") ||\r
+ books.get(i).getName().equalsIgnoreCase("Conflicting Changes")) {\r
+ notebookGuid = books.get(i).getGuid();\r
+ i=books.size();\r
+ }\r
+ }\r
+ \r
+ if (notebookGuid == null) {\r
+ logger.log(logger.EXTREME, "Building conflicting change notebook " +guid);\r
+ Calendar currentTime = new GregorianCalendar();\r
+ Long l = new Long(currentTime.getTimeInMillis());\r
+ long prevTime = l;\r
+ while (prevTime==l) {\r
+ currentTime = new GregorianCalendar();\r
+ l=currentTime.getTimeInMillis();\r
+ }\r
+ String randint = new String(Long.toString(l));\r
+ \r
+ Notebook newBook = new Notebook();\r
+ newBook.setUpdateSequenceNum(0);\r
+ newBook.setGuid(randint);\r
+ newBook.setName("Conflicting Changes");\r
+ newBook.setServiceCreated(new Date().getTime());\r
+ newBook.setServiceUpdated(new Date().getTime());\r
+ newBook.setDefaultNotebook(false);\r
+ newBook.setPublished(false);\r
+ \r
+ conn.getNotebookTable().addNotebook(newBook, false, true);\r
+ notebookGuid = newBook.getGuid();\r
+ }\r
+ \r
+ // Now that we have a good notebook guid, we need to move the conflicting note\r
+ // to the local notebook\r
+ logger.log(logger.EXTREME, "Moving conflicting note " +guid);\r
+ Calendar currentTime = new GregorianCalendar();\r
+ Long l = new Long(currentTime.getTimeInMillis());\r
+ long prevTime = l;\r
+ while (prevTime==l) {\r
+ currentTime = new GregorianCalendar();\r
+ l = currentTime.getTimeInMillis();\r
+ }\r
+ String newGuid = new String(Long.toString(l));\r
+ \r
+ Note oldNote = conn.getNoteTable().getNote(guid, true, true, false, false, false);\r
+ for (int i=0; i<oldNote.getResources().size() && keepRunning; i++) {\r
+ l = new Long(currentTime.getTimeInMillis());\r
+ String newResG = new String(Long.toString(l));\r
+ String oldResG = oldNote.getResources().get(i).getGuid();\r
+ conn.getNoteTable().noteResourceTable.resetUpdateSequenceNumber(oldResG, true);\r
+ conn.getNoteTable().noteResourceTable.updateNoteResourceGuid(oldResG, newResG, true);\r
+ }\r
+ \r
+ conn.getNoteTable().resetSequenceNumber(guid);\r
+ conn.getNoteTable().updateNoteGuid(guid, newGuid);\r
+ conn.getNoteTable().updateNoteNotebook(newGuid, notebookGuid, true);\r
+ \r
+ \r
+ noteSignal.guidChanged.emit(guid,newGuid);\r
+ }\r
+ \r
+ \r
+\r
+ \r
+ //******************************************************\r
+ //******************************************************\r
+ //** Utility Functions\r
+ //******************************************************\r
+ //******************************************************\r
+ // Convert a byte array to a hex string\r
+ private static String byteArrayToHexString(byte data[]) {\r
+ StringBuffer buf = new StringBuffer();\r
+ for (byte element : data) {\r
+ int halfbyte = (element >>> 4) & 0x0F;\r
+ int two_halfs = 0;\r
+ do {\r
+ if ((0 <= halfbyte) && (halfbyte <= 9))\r
+ buf.append((char) ('0' + halfbyte));\r
+ else\r
+ buf.append((char) ('a' + (halfbyte - 10)));\r
+ halfbyte = element & 0x0F;\r
+ } while(two_halfs++ < 1);\r
+ }\r
+ return buf.toString(); \r
+ }\r
+\r
+ \r
+ \r
+ //*******************************************************\r
+ //* Find dirty tags, which do not have newly created parents\r
+ //*******************************************************\r
+ private Tag findNextTag() {\r
+ logger.log(logger.HIGH, "Entering SyncRunner.findNextTag");\r
+ Tag nextTag = null;\r
+ List<Tag> tags = conn.getTagTable().getDirty();\r
+ \r
+ // Find the parent. If the parent has a sequence > 0 then it is a good\r
+ // parent.\r
+ for (int i=0; i<tags.size() && keepRunning; i++) {\r
+ if (tags.get(i).getParentGuid() == null) {\r
+ logger.log(logger.HIGH, "Leaving SyncRunner.findNextTag - tag found without parent");\r
+ return tags.get(i);\r
+ }\r
+ Tag parentTag = conn.getTagTable().getTag(tags.get(i).getParentGuid());\r
+ if (parentTag.getUpdateSequenceNum() > 0) {\r
+ logger.log(logger.HIGH, "Leaving SyncRunner.findNextTag - tag found");\r
+ return tags.get(i);\r
+ }\r
+ }\r
+ \r
+ logger.log(logger.HIGH, "Leaving SyncRunner.findNextTag - no tags returned");\r
+ return nextTag;\r
+ }\r
+ \r
+ \r
+ // Connect to Evernote\r
+ public boolean enConnect() {\r
+ try {\r
+ userStoreTrans = new THttpClient(userStoreUrl);\r
+ } catch (TTransportException e) {\r
+ QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Transport Excepton", e.getLocalizedMessage());\r
+ mb.exec();\r
+ e.printStackTrace();\r
+ }\r
+ userStoreProt = new TBinaryProtocol(userStoreTrans);\r
+ userStore = new UserStore.Client(userStoreProt, userStoreProt);\r
+ syncSignal.saveUserStore.emit(userStore);\r
+ try {\r
+ authResult = userStore.authenticate(username, password, consumerKey, consumerSecret);\r
+ } catch (EDAMUserException e) {\r
+ QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Error", "Incorrect username/password");\r
+ mb.exec();\r
+ isConnected = false;\r
+ return false;\r
+ } catch (EDAMSystemException e) {\r
+ QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "EDAM System Excepton", e.getLocalizedMessage());\r
+ mb.exec();\r
+ e.printStackTrace();\r
+ isConnected = false;\r
+ } catch (TException e) {\r
+ QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Transport Excepton", e.getLocalizedMessage());\r
+ mb.exec();\r
+ e.printStackTrace();\r
+ isConnected = false;\r
+ }\r
+ \r
+ boolean versionOk = false;\r
+ try {\r
+// versionOk = userStore.checkVersion("Dave's EDAMDemo (Java)", \r
+ versionOk = userStore.checkVersion("NeverNote", \r
+ com.evernote.edam.userstore.Constants.EDAM_VERSION_MAJOR, \r
+ com.evernote.edam.userstore.Constants.EDAM_VERSION_MINOR);\r
+ } catch (TException e) {\r
+ e.printStackTrace();\r
+ isConnected = false;\r
+ } \r
+ if (!versionOk) { \r
+ System.err.println("Incomatible EDAM client protocol version"); \r
+ isConnected = false;\r
+ }\r
+ if (authResult != null) {\r
+ user = authResult.getUser(); \r
+ authToken = authResult.getAuthenticationToken(); \r
+ noteStoreUrl = noteStoreUrlBase + user.getShardId();\r
+ syncSignal.saveAuthToken.emit(authToken);\r
+ syncSignal.saveNoteStore.emit(noteStore);\r
+ \r
+ \r
+ try {\r
+ noteStoreTrans = new THttpClient(noteStoreUrl);\r
+ } catch (TTransportException e) {\r
+ QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Transport Excepton", e.getLocalizedMessage());\r
+ mb.exec();\r
+ e.printStackTrace();\r
+ isConnected = false;\r
+ } \r
+ noteStoreProt = new TBinaryProtocol(noteStoreTrans);\r
+ noteStore = \r
+ new NoteStore.Client(noteStoreProt, noteStoreProt); \r
+ isConnected = true;\r
+ authTimeRemaining = authResult.getExpiration() - authResult.getCurrentTime();\r
+ authRefreshTime = authTimeRemaining / 2;\r
+ }\r
+ \r
+ // Get user information\r
+ try {\r
+ User user = userStore.getUser(authToken);\r
+ syncSignal.saveUserInformation.emit(user);\r
+ } catch (EDAMUserException e1) {\r
+ e1.printStackTrace();\r
+ } catch (EDAMSystemException e1) {\r
+ e1.printStackTrace();\r
+ } catch (TException e1) {\r
+ e1.printStackTrace();\r
+ }\r
+ \r
+ return isConnected;\r
+ }\r
+ // Disconnect from the database \r
+ public void enDisconnect() {\r
+ isConnected = false;\r
+ }\r
+ // Refresh the connection\r
+ private synchronized void refreshConnection() {\r
+ logger.log(logger.EXTREME, "Entering SyncRunner.refreshConnection()");\r
+// Calendar cal = Calendar.getInstance();\r
+ \r
+ // If we are not connected let's get out of here\r
+ if (!isConnected)\r
+ return;\r
+ \r
+ // If we fail too many times, then let's give up.\r
+ if (failedRefreshes >=5) {\r
+ logger.log(logger.EXTREME, "Refresh attempts have failed. Disconnecting.");\r
+ isConnected = false;\r
+ return;\r
+ }\r
+ \r
+ // If this is the first time through, then we need to set this\r
+// if (authRefreshTime == 0 || cal.getTimeInMillis() > authRefreshTime) \r
+// authRefreshTime = cal.getTimeInMillis();\r
+ \r
+ // // Default to checking again in 5 min. This in case we fail.\r
+ // authRefreshTime = authRefreshTime +(5*60*1000); \r
+\r
+ // Try to get a new token\r
+ AuthenticationResult newAuth = null; \r
+ logger.log(logger.EXTREME, "Beginning to try authentication refresh");\r
+ try {\r
+ if (userStore != null && authToken != null) \r
+ newAuth = userStore.refreshAuthentication(authToken); \r
+ else\r
+ return;\r
+ logger.log(logger.EXTREME, "UserStore.refreshAuthentication has succeeded.");\r
+ } catch (EDAMUserException e) {\r
+ e.printStackTrace();\r
+ syncSignal.authRefreshComplete.emit(false);\r
+ failedRefreshes++;\r
+ return;\r
+ } catch (EDAMSystemException e) {\r
+ e.printStackTrace();\r
+ syncSignal.authRefreshComplete.emit(false);\r
+ failedRefreshes++;\r
+ return; \r
+ } catch (TException e) { \r
+ e.printStackTrace();\r
+ syncSignal.authRefreshComplete.emit(false);\r
+ failedRefreshes++;\r
+ return;\r
+ }\r
+ \r
+ // If we didn't get a good auth, then we've failed\r
+ if (newAuth == null) {\r
+ failedRefreshes++;\r
+ logger.log(logger.EXTREME, "Authentication failure #" +failedRefreshes);\r
+ syncSignal.authRefreshComplete.emit(false);\r
+ return;\r
+ }\r
+ \r
+ // We got a good token. Now we need to setup the time to renew it.\r
+ logger.log(logger.EXTREME, "Saving authentication tokens");\r
+ authResult = newAuth;\r
+ authToken = new String(newAuth.getAuthenticationToken());\r
+// authTimeRemaining = authResult.getExpiration() - authResult.getCurrentTime();\r
+// authRefreshTime = cal.getTimeInMillis() + (authTimeRemaining/4); \r
+ failedRefreshes=0;\r
+ syncSignal.authRefreshComplete.emit(true);\r
+ authRefreshNeeded = false;\r
+ \r
+ // This should never happen, but if it does we consider this a faild attempt.\r
+// if (authTimeRemaining <= 0) {\r
+// failedRefreshes++;\r
+// syncSignal.authRefreshComplete.emit(false);\r
+// }\r
+ }\r
+ \r
+ public synchronized boolean addWork(String request) {\r
+ if (workQueue.offer(request))\r
+ return true;\r
+ return false;\r
+ }\r
+ \r
+ private Note getNoteContent(Note n) {\r
+ n.setContent(conn.getNoteTable().getNoteContentBinary(n.getGuid()));\r
+ return n;\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+package cx.fbn.nevernote.utilities;\r
+\r
+//RSA - Rivest, Shamir, & Adleman\r
+\r
+import java.io.InputStream;\r
+import java.io.OutputStream;\r
+import java.security.InvalidAlgorithmParameterException;\r
+import java.security.InvalidKeyException;\r
+import java.security.spec.AlgorithmParameterSpec;\r
+\r
+import javax.crypto.Cipher;\r
+import javax.crypto.CipherInputStream;\r
+import javax.crypto.CipherOutputStream;\r
+import javax.crypto.spec.IvParameterSpec;\r
+import javax.crypto.spec.SecretKeySpec;\r
+ \r
+public class AESEncrypter\r
+{\r
+ private Cipher cipher;\r
+ private String password;\r
+ private String userid;\r
+ private final SecretKeySpec skeySpec;\r
+ private final AlgorithmParameterSpec paramSpec;\r
+ \r
+ public AESEncrypter()\r
+ {\r
+ String key = "x331aq5wDQ8xO81v";\r
+ skeySpec = new SecretKeySpec(key.getBytes(), "AES");\r
+ password = new String("");\r
+ userid = new String("");\r
+ \r
+ // Create an 8-byte initialization vector\r
+ byte[] iv = new byte[]\r
+ {\r
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f\r
+ };\r
+ \r
+ paramSpec = new IvParameterSpec(iv);\r
+ try\r
+ {\r
+ cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");\r
+ }\r
+ catch (Exception e)\r
+ {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+ \r
+ public void setPassword(String s) {\r
+ password = s;\r
+ }\r
+ public String getPassword() {\r
+ return password;\r
+ }\r
+ public void setUserid(String s) {\r
+ userid = s;\r
+ }\r
+ public String getUserid() {\r
+ return userid;\r
+ }\r
+ \r
+ public void encrypt(OutputStream out)\r
+ {\r
+ // CBC requires an initialization vector\r
+ try {\r
+ cipher.init(Cipher.ENCRYPT_MODE, skeySpec, paramSpec);\r
+ out = new CipherOutputStream(out, cipher);\r
+\r
+// String u = new String(userid +" " +password);\r
+ StringBuffer u = new StringBuffer(1024);\r
+ u.append("Userid:" +userid+ " " +password);\r
+ for (int i=u.length(); i<128; i++)\r
+ u.append('\0');\r
+\r
+ out.write(u.toString().getBytes());\r
+ out.close();\r
+ }\r
+ catch (java.io.IOException e)\r
+ {\r
+ System.out.println("Encrypt i/o exception");\r
+ } catch (InvalidKeyException e1) {\r
+ e1.printStackTrace();\r
+ } catch (InvalidAlgorithmParameterException e1) {\r
+ e1.printStackTrace();\r
+ }\r
+ }\r
+ \r
+ public void decrypt(InputStream in)\r
+ {\r
+ byte[] buf = new byte[1024];\r
+ // CBC requires an initialization vector\r
+ try {\r
+ cipher.init(Cipher.DECRYPT_MODE, skeySpec, paramSpec);\r
+ // Bytes read from in will be decrypted\r
+ in = new CipherInputStream(in, cipher);\r
+ if (in.read(buf) >= 0)\r
+ {\r
+ String line = new String(buf);\r
+ int offset = line.indexOf(" ");\r
+ if (offset > 0) {\r
+ userid = line.substring(line.indexOf(":")+1, offset);\r
+ password = line.substring(offset+1);\r
+ password = password.trim();\r
+ }\r
+ \r
+ }\r
+ in.close();\r
+ } catch (java.io.IOException e) {\r
+ return;\r
+ } catch (InvalidKeyException e1) {\r
+ return; \r
+ } catch (InvalidAlgorithmParameterException e1) {\r
+ return;\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/*
+ * This file is part of NeverNote
+ * 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.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+
+import cx.fbn.nevernote.Global;
+
+
+public class ApplicationLogger {
+
+ public final int LOW = 1;
+ public final int MEDIUM = 2;
+ public final int HIGH = 3;
+ public final int EXTREME = 4;
+
+ FileOutputStream fileStream;
+ PrintStream stdoutPrintStream;
+
+// private final List<String> logText;
+
+ public ApplicationLogger(String name){
+// logText = new ArrayList<String>();
+ try {
+ fileStream = new FileOutputStream(Global.currentDir+"logs/"+name);
+ } catch (FileNotFoundException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+// stdoutStream = new OutStream(new ByteArrayOutputStream(), name);
+ stdoutPrintStream = new PrintStream(fileStream);
+// systemStdoutPrintStream = System.out;
+ }
+
+// public List<String> getText() {
+// return stdoutStream.getText();
+// }
+
+
+ /**
+ * @return the logText
+ */
+// public List<String> getLogText() {
+// return logText;
+// }
+
+
+ public synchronized void log(int messageLevel, String s) {
+ if (messageLevel <= Global.messageLevel) {
+ String DATE_FORMAT_NOW = "yyyy-MM-dd HH:mm:ss.SS ";
+ Calendar cal = Calendar.getInstance();
+ SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_NOW);
+
+ stdoutPrintStream.println(sdf.format(cal.getTime()) +s);
+// System.setOut(stdoutPrintStream);
+// System.out.print(sdf.format(cal.getTime()) +s);
+// System.setOut(systemStdoutPrintStream);
+ }
+ }
+
+ public void log(int level, StackTraceElement e[]) {
+ if (level >= Global.messageLevel) {
+ String DATE_FORMAT_NOW = "yyyy-MM-dd HH:mm:ss.SS ";
+ Calendar cal = Calendar.getInstance();
+ SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_NOW);
+
+// System.setOut(systemStdoutPrintStream);
+ System.out.println(e);
+ System.out.println("*** Stack Trace Requested ***");
+ System.out.println(sdf.format(cal.getTime()));
+ for (StackTraceElement element : e) {
+ System.out.println("Line Number: " +new Integer(element.getLineNumber()));
+ System.out.println("Class Name: " +element.getClassName());
+ System.out.println("Method Name:" +element.getMethodName());
+ System.out.println("File Name:" +element.getFileName());
+ System.out.println("-Next Element-");
+ }
+ System.out.println("**************************");
+ System.setOut(stdoutPrintStream);
+ System.out.print(e);
+ System.out.print("*** Stack Trace Requested ***");
+ System.out.print(sdf.format(cal.getTime()));
+ for (StackTraceElement element : e) {
+ System.out.print("Line Number: " +new Integer(element.getLineNumber()));
+ System.out.print("Class Name: " +element.getClassName());
+ System.out.print("Method Name:" +element.getMethodName());
+ System.out.print("File Name:" +element.getFileName());
+ System.out.print("-Next Element-");
+ }
+ System.out.print("**************************");
+ }
+ }
+}
--- /dev/null
+package cx.fbn.nevernote.utilities;\r
+\r
+\r
+/**\r
+ * <p>Encodes and decodes to and from Base64 notation.</p>\r
+ * <p>Homepage: <a href="http://iharder.net/base64">http://iharder.net/base64</a>.</p>\r
+ * \r
+ * <p>Example:</p>\r
+ * \r
+ * <code>String encoded = Base64.encode( myByteArray );</code>\r
+ * <br />\r
+ * <code>byte[] myByteArray = Base64.decode( encoded );</code>\r
+ *\r
+ * <p>The <tt>options</tt> parameter, which appears in a few places, is used to pass \r
+ * several pieces of information to the encoder. In the "higher level" methods such as \r
+ * encodeBytes( bytes, options ) the options parameter can be used to indicate such \r
+ * things as first gzipping the bytes before encoding them, not inserting linefeeds,\r
+ * and encoding using the URL-safe and Ordered dialects.</p>\r
+ *\r
+ * <p>Note, according to <a href="http://www.faqs.org/rfcs/rfc3548.html">RFC3548</a>,\r
+ * Section 2.1, implementations should not add line feeds unless explicitly told\r
+ * to do so. I've got Base64 set to this behavior now, although earlier versions\r
+ * broke lines by default.</p>\r
+ *\r
+ * <p>The constants defined in Base64 can be OR-ed together to combine options, so you \r
+ * might make a call like this:</p>\r
+ *\r
+ * <code>String encoded = Base64.encodeBytes( mybytes, Base64.GZIP | Base64.DO_BREAK_LINES );</code>\r
+ * <p>to compress the data before encoding it and then making the output have newline characters.</p>\r
+ * <p>Also...</p>\r
+ * <code>String encoded = Base64.encodeBytes( crazyString.getBytes() );</code>\r
+ *\r
+ *\r
+ *\r
+ * <p>\r
+ * Change Log:\r
+ * </p>\r
+ * <ul>\r
+ * <li>v2.3.4 - Fixed bug when working with gzipped streams whereby flushing\r
+ * the Base64.OutputStream closed the Base64 encoding (by padding with equals\r
+ * signs) too soon. Also added an option to suppress the automatic decoding\r
+ * of gzipped streams. Also added experimental support for specifying a\r
+ * class loader when using the\r
+ * {@link #decodeToObject(java.lang.String, int, java.lang.ClassLoader)}\r
+ * method.</li>\r
+ * <li>v2.3.3 - Changed default char encoding to US-ASCII which reduces the internal Java\r
+ * footprint with its CharEncoders and so forth. Fixed some javadocs that were\r
+ * inconsistent. Removed imports and specified things like java.io.IOException\r
+ * explicitly inline.</li>\r
+ * <li>v2.3.2 - Reduced memory footprint! Finally refined the "guessing" of how big the\r
+ * final encoded data will be so that the code doesn't have to create two output\r
+ * arrays: an oversized initial one and then a final, exact-sized one. Big win\r
+ * when using the {@link #encodeBytesToBytes(byte[])} family of methods (and not\r
+ * using the gzip options which uses a different mechanism with streams and stuff).</li>\r
+ * <li>v2.3.1 - Added {@link #encodeBytesToBytes(byte[], int, int, int)} and some\r
+ * similar helper methods to be more efficient with memory by not returning a\r
+ * String but just a byte array.</li>\r
+ * <li>v2.3 - <strong>This is not a drop-in replacement!</strong> This is two years of comments\r
+ * and bug fixes queued up and finally executed. Thanks to everyone who sent\r
+ * me stuff, and I'm sorry I wasn't able to distribute your fixes to everyone else.\r
+ * Much bad coding was cleaned up including throwing exceptions where necessary \r
+ * instead of returning null values or something similar. Here are some changes\r
+ * that may affect you:\r
+ * <ul>\r
+ * <li><em>Does not break lines, by default.</em> This is to keep in compliance with\r
+ * <a href="http://www.faqs.org/rfcs/rfc3548.html">RFC3548</a>.</li>\r
+ * <li><em>Throws exceptions instead of returning null values.</em> Because some operations\r
+ * (especially those that may permit the GZIP option) use IO streams, there\r
+ * is a possiblity of an java.io.IOException being thrown. After some discussion and\r
+ * thought, I've changed the behavior of the methods to throw java.io.IOExceptions\r
+ * rather than return null if ever there's an error. I think this is more\r
+ * appropriate, though it will require some changes to your code. Sorry,\r
+ * it should have been done this way to begin with.</li>\r
+ * <li><em>Removed all references to System.out, System.err, and the like.</em>\r
+ * Shame on me. All I can say is sorry they were ever there.</li>\r
+ * <li><em>Throws NullPointerExceptions and IllegalArgumentExceptions</em> as needed\r
+ * such as when passed arrays are null or offsets are invalid.</li>\r
+ * <li>Cleaned up as much javadoc as I could to avoid any javadoc warnings.\r
+ * This was especially annoying before for people who were thorough in their\r
+ * own projects and then had gobs of javadoc warnings on this file.</li>\r
+ * </ul>\r
+ * <li>v2.2.1 - Fixed bug using URL_SAFE and ORDERED encodings. Fixed bug\r
+ * when using very small files (~< 40 bytes).</li>\r
+ * <li>v2.2 - Added some helper methods for encoding/decoding directly from\r
+ * one file to the next. Also added a main() method to support command line\r
+ * encoding/decoding from one file to the next. Also added these Base64 dialects:\r
+ * <ol>\r
+ * <li>The default is RFC3548 format.</li>\r
+ * <li>Calling Base64.setFormat(Base64.BASE64_FORMAT.URLSAFE_FORMAT) generates\r
+ * URL and file name friendly format as described in Section 4 of RFC3548.\r
+ * http://www.faqs.org/rfcs/rfc3548.html</li>\r
+ * <li>Calling Base64.setFormat(Base64.BASE64_FORMAT.ORDERED_FORMAT) generates\r
+ * URL and file name friendly format that preserves lexical ordering as described\r
+ * in http://www.faqs.org/qa/rfcc-1940.html</li>\r
+ * </ol>\r
+ * Special thanks to Jim Kellerman at <a href="http://www.powerset.com/">http://www.powerset.com/</a>\r
+ * for contributing the new Base64 dialects.\r
+ * </li>\r
+ * \r
+ * <li>v2.1 - Cleaned up javadoc comments and unused variables and methods. Added\r
+ * some convenience methods for reading and writing to and from files.</li>\r
+ * <li>v2.0.2 - Now specifies UTF-8 encoding in places where the code fails on systems\r
+ * with other encodings (like EBCDIC).</li>\r
+ * <li>v2.0.1 - Fixed an error when decoding a single byte, that is, when the\r
+ * encoded data was a single byte.</li>\r
+ * <li>v2.0 - I got rid of methods that used booleans to set options. \r
+ * Now everything is more consolidated and cleaner. The code now detects\r
+ * when data that's being decoded is gzip-compressed and will decompress it\r
+ * automatically. Generally things are cleaner. You'll probably have to\r
+ * change some method calls that you were making to support the new\r
+ * options format (<tt>int</tt>s that you "OR" together).</li>\r
+ * <li>v1.5.1 - Fixed bug when decompressing and decoding to a \r
+ * byte[] using <tt>decode( String s, boolean gzipCompressed )</tt>. \r
+ * Added the ability to "suspend" encoding in the Output Stream so \r
+ * you can turn on and off the encoding if you need to embed base64 \r
+ * data in an otherwise "normal" stream (like an XML file).</li> \r
+ * <li>v1.5 - Output stream pases on flush() command but doesn't do anything itself.\r
+ * This helps when using GZIP streams.\r
+ * Added the ability to GZip-compress objects before encoding them.</li>\r
+ * <li>v1.4 - Added helper methods to read/write files.</li>\r
+ * <li>v1.3.6 - Fixed OutputStream.flush() so that 'position' is reset.</li>\r
+ * <li>v1.3.5 - Added flag to turn on and off line breaks. Fixed bug in input stream\r
+ * where last buffer being read, if not completely full, was not returned.</li>\r
+ * <li>v1.3.4 - Fixed when "improperly padded stream" error was thrown at the wrong time.</li>\r
+ * <li>v1.3.3 - Fixed I/O streams which were totally messed up.</li>\r
+ * </ul>\r
+ *\r
+ * <p>\r
+ * I am placing this code in the Public Domain. Do with it as you will.\r
+ * This software comes with no guarantees or warranties but with\r
+ * plenty of well-wishing instead!\r
+ * Please visit <a href="http://iharder.net/base64">http://iharder.net/base64</a>\r
+ * periodically to check for updates or to contribute improvements.\r
+ * </p>\r
+ *\r
+ * @author Robert Harder\r
+ * @author rob@iharder.net\r
+ * @version 2.3.3\r
+ */\r
+public class Base64\r
+{\r
+ \r
+/* ******** P U B L I C F I E L D S ******** */ \r
+ \r
+ \r
+ /** No options specified. Value is zero. */\r
+ public final static int NO_OPTIONS = 0;\r
+ \r
+ /** Specify encoding in first bit. Value is one. */\r
+ public final static int ENCODE = 1;\r
+ \r
+ \r
+ /** Specify decoding in first bit. Value is zero. */\r
+ public final static int DECODE = 0;\r
+ \r
+\r
+ /** Specify that data should be gzip-compressed in second bit. Value is two. */\r
+ public final static int GZIP = 2;\r
+\r
+ /** Specify that gzipped data should <em>not</em> be automatically gunzipped. */\r
+ public final static int DONT_GUNZIP = 4;\r
+ \r
+ \r
+ /** Do break lines when encoding. Value is 8. */\r
+ public final static int DO_BREAK_LINES = 8;\r
+ \r
+ /** \r
+ * Encode using Base64-like encoding that is URL- and Filename-safe as described\r
+ * in Section 4 of RFC3548: \r
+ * <a href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.\r
+ * It is important to note that data encoded this way is <em>not</em> officially valid Base64, \r
+ * or at the very least should not be called Base64 without also specifying that is\r
+ * was encoded using the URL- and Filename-safe dialect.\r
+ */\r
+ public final static int URL_SAFE = 16;\r
+\r
+\r
+ /**\r
+ * Encode using the special "ordered" dialect of Base64 described here:\r
+ * <a href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/qa/rfcc-1940.html</a>.\r
+ */\r
+ public final static int ORDERED = 32;\r
+ \r
+ \r
+/* ******** P R I V A T E F I E L D S ******** */ \r
+ \r
+ \r
+ /** Maximum line length (76) of Base64 output. */\r
+ private final static int MAX_LINE_LENGTH = 76;\r
+ \r
+ \r
+ /** The equals sign (=) as a byte. */\r
+ private final static byte EQUALS_SIGN = (byte)'=';\r
+ \r
+ \r
+ /** The new line character (\n) as a byte. */\r
+ private final static byte NEW_LINE = (byte)'\n';\r
+ \r
+ \r
+ /** Preferred encoding. */\r
+ private final static String PREFERRED_ENCODING = "US-ASCII";\r
+ \r
+ \r
+ private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding\r
+ private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding\r
+ \r
+ \r
+/* ******** S T A N D A R D B A S E 6 4 A L P H A B E T ******** */ \r
+ \r
+ /** The 64 valid Base64 values. */\r
+ /* Host platform me be something funny like EBCDIC, so we hardcode these values. */\r
+ private final static byte[] _STANDARD_ALPHABET = {\r
+ (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',\r
+ (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',\r
+ (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', \r
+ (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',\r
+ (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',\r
+ (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',\r
+ (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', \r
+ (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z',\r
+ (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', \r
+ (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'+', (byte)'/'\r
+ };\r
+ \r
+ \r
+ /** \r
+ * Translates a Base64 value to either its 6-bit reconstruction value\r
+ * or a negative number indicating some other meaning.\r
+ **/\r
+ private final static byte[] _STANDARD_DECODABET = {\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8\r
+ -5,-5, // Whitespace: Tab and Linefeed\r
+ -9,-9, // Decimal 11 - 12\r
+ -5, // Whitespace: Carriage Return\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26\r
+ -9,-9,-9,-9,-9, // Decimal 27 - 31\r
+ -5, // Whitespace: Space\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42\r
+ 62, // Plus sign at decimal 43\r
+ -9,-9,-9, // Decimal 44 - 46\r
+ 63, // Slash at decimal 47\r
+ 52,53,54,55,56,57,58,59,60,61, // Numbers zero through nine\r
+ -9,-9,-9, // Decimal 58 - 60\r
+ -1, // Equals sign at decimal 61\r
+ -9,-9,-9, // Decimal 62 - 64\r
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13, // Letters 'A' through 'N'\r
+ 14,15,16,17,18,19,20,21,22,23,24,25, // Letters 'O' through 'Z'\r
+ -9,-9,-9,-9,-9,-9, // Decimal 91 - 96\r
+ 26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm'\r
+ 39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z'\r
+ -9,-9,-9,-9 // Decimal 123 - 126\r
+ /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */\r
+ };\r
+ \r
+ \r
+/* ******** U R L S A F E B A S E 6 4 A L P H A B E T ******** */\r
+ \r
+ /**\r
+ * Used in the URL- and Filename-safe dialect described in Section 4 of RFC3548: \r
+ * <a href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.\r
+ * Notice that the last two bytes become "hyphen" and "underscore" instead of "plus" and "slash."\r
+ */\r
+ private final static byte[] _URL_SAFE_ALPHABET = {\r
+ (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',\r
+ (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',\r
+ (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', \r
+ (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',\r
+ (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',\r
+ (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',\r
+ (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', \r
+ (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z',\r
+ (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', \r
+ (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'-', (byte)'_'\r
+ };\r
+ \r
+ /**\r
+ * Used in decoding URL- and Filename-safe dialects of Base64.\r
+ */\r
+ private final static byte[] _URL_SAFE_DECODABET = {\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8\r
+ -5,-5, // Whitespace: Tab and Linefeed\r
+ -9,-9, // Decimal 11 - 12\r
+ -5, // Whitespace: Carriage Return\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26\r
+ -9,-9,-9,-9,-9, // Decimal 27 - 31\r
+ -5, // Whitespace: Space\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42\r
+ -9, // Plus sign at decimal 43\r
+ -9, // Decimal 44\r
+ 62, // Minus sign at decimal 45\r
+ -9, // Decimal 46\r
+ -9, // Slash at decimal 47\r
+ 52,53,54,55,56,57,58,59,60,61, // Numbers zero through nine\r
+ -9,-9,-9, // Decimal 58 - 60\r
+ -1, // Equals sign at decimal 61\r
+ -9,-9,-9, // Decimal 62 - 64\r
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13, // Letters 'A' through 'N'\r
+ 14,15,16,17,18,19,20,21,22,23,24,25, // Letters 'O' through 'Z'\r
+ -9,-9,-9,-9, // Decimal 91 - 94\r
+ 63, // Underscore at decimal 95\r
+ -9, // Decimal 96\r
+ 26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm'\r
+ 39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z'\r
+ -9,-9,-9,-9 // Decimal 123 - 126\r
+ /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */\r
+ };\r
+\r
+\r
+\r
+/* ******** O R D E R E D B A S E 6 4 A L P H A B E T ******** */\r
+\r
+ /**\r
+ * I don't get the point of this technique, but someone requested it,\r
+ * and it is described here:\r
+ * <a href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/qa/rfcc-1940.html</a>.\r
+ */\r
+ private final static byte[] _ORDERED_ALPHABET = {\r
+ (byte)'-',\r
+ (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4',\r
+ (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9',\r
+ (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',\r
+ (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',\r
+ (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',\r
+ (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',\r
+ (byte)'_',\r
+ (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',\r
+ (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',\r
+ (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',\r
+ (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z'\r
+ };\r
+ \r
+ /**\r
+ * Used in decoding the "ordered" dialect of Base64.\r
+ */\r
+ private final static byte[] _ORDERED_DECODABET = {\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8\r
+ -5,-5, // Whitespace: Tab and Linefeed\r
+ -9,-9, // Decimal 11 - 12\r
+ -5, // Whitespace: Carriage Return\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26\r
+ -9,-9,-9,-9,-9, // Decimal 27 - 31\r
+ -5, // Whitespace: Space\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42\r
+ -9, // Plus sign at decimal 43\r
+ -9, // Decimal 44\r
+ 0, // Minus sign at decimal 45\r
+ -9, // Decimal 46\r
+ -9, // Slash at decimal 47\r
+ 1,2,3,4,5,6,7,8,9,10, // Numbers zero through nine\r
+ -9,-9,-9, // Decimal 58 - 60\r
+ -1, // Equals sign at decimal 61\r
+ -9,-9,-9, // Decimal 62 - 64\r
+ 11,12,13,14,15,16,17,18,19,20,21,22,23, // Letters 'A' through 'M'\r
+ 24,25,26,27,28,29,30,31,32,33,34,35,36, // Letters 'N' through 'Z'\r
+ -9,-9,-9,-9, // Decimal 91 - 94\r
+ 37, // Underscore at decimal 95\r
+ -9, // Decimal 96\r
+ 38,39,40,41,42,43,44,45,46,47,48,49,50, // Letters 'a' through 'm'\r
+ 51,52,53,54,55,56,57,58,59,60,61,62,63, // Letters 'n' through 'z'\r
+ -9,-9,-9,-9 // Decimal 123 - 126\r
+ /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243\r
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */\r
+ };\r
+\r
+ \r
+/* ******** D E T E R M I N E W H I C H A L H A B E T ******** */\r
+\r
+\r
+ /**\r
+ * Returns one of the _SOMETHING_ALPHABET byte arrays depending on\r
+ * the options specified.\r
+ * It's possible, though silly, to specify ORDERED <b>and</b> URLSAFE\r
+ * in which case one of them will be picked, though there is\r
+ * no guarantee as to which one will be picked.\r
+ */\r
+ private final static byte[] getAlphabet( int options ) {\r
+ if ((options & URL_SAFE) == URL_SAFE) {\r
+ return _URL_SAFE_ALPHABET;\r
+ } else if ((options & ORDERED) == ORDERED) {\r
+ return _ORDERED_ALPHABET;\r
+ } else {\r
+ return _STANDARD_ALPHABET;\r
+ }\r
+ } // end getAlphabet\r
+\r
+\r
+ /**\r
+ * Returns one of the _SOMETHING_DECODABET byte arrays depending on\r
+ * the options specified.\r
+ * It's possible, though silly, to specify ORDERED and URL_SAFE\r
+ * in which case one of them will be picked, though there is\r
+ * no guarantee as to which one will be picked.\r
+ */\r
+ private final static byte[] getDecodabet( int options ) {\r
+ if( (options & URL_SAFE) == URL_SAFE) {\r
+ return _URL_SAFE_DECODABET;\r
+ } else if ((options & ORDERED) == ORDERED) {\r
+ return _ORDERED_DECODABET;\r
+ } else {\r
+ return _STANDARD_DECODABET;\r
+ }\r
+ } // end getAlphabet\r
+\r
+\r
+ \r
+ /** Defeats instantiation. */\r
+ Base64(){}\r
+ \r
+\r
+ \r
+ \r
+/* ******** E N C O D I N G M E T H O D S ******** */ \r
+ \r
+ \r
+ /**\r
+ * Encodes up to the first three bytes of array <var>threeBytes</var>\r
+ * and returns a four-byte array in Base64 notation.\r
+ * The actual number of significant bytes in your array is\r
+ * given by <var>numSigBytes</var>.\r
+ * The array <var>threeBytes</var> needs only be as big as\r
+ * <var>numSigBytes</var>.\r
+ * Code can reuse a byte array by passing a four-byte array as <var>b4</var>.\r
+ *\r
+ * @param b4 A reusable byte array to reduce array instantiation\r
+ * @param threeBytes the array to convert\r
+ * @param numSigBytes the number of significant bytes in your array\r
+ * @return four byte array in Base64 notation.\r
+ * @since 1.5.1\r
+ */\r
+ private static byte[] encode3to4( byte[] b4, byte[] threeBytes, int numSigBytes, int options ) {\r
+ encode3to4( threeBytes, 0, numSigBytes, b4, 0, options );\r
+ return b4;\r
+ } // end encode3to4\r
+\r
+ \r
+ /**\r
+ * <p>Encodes up to three bytes of the array <var>source</var>\r
+ * and writes the resulting four Base64 bytes to <var>destination</var>.\r
+ * The source and destination arrays can be manipulated\r
+ * anywhere along their length by specifying \r
+ * <var>srcOffset</var> and <var>destOffset</var>.\r
+ * This method does not check to make sure your arrays\r
+ * are large enough to accomodate <var>srcOffset</var> + 3 for\r
+ * the <var>source</var> array or <var>destOffset</var> + 4 for\r
+ * the <var>destination</var> array.\r
+ * The actual number of significant bytes in your array is\r
+ * given by <var>numSigBytes</var>.</p>\r
+ * <p>This is the lowest level of the encoding methods with\r
+ * all possible parameters.</p>\r
+ *\r
+ * @param source the array to convert\r
+ * @param srcOffset the index where conversion begins\r
+ * @param numSigBytes the number of significant bytes in your array\r
+ * @param destination the array to hold the conversion\r
+ * @param destOffset the index where output will be put\r
+ * @return the <var>destination</var> array\r
+ * @since 1.3\r
+ */\r
+ private static byte[] encode3to4( \r
+ byte[] source, int srcOffset, int numSigBytes,\r
+ byte[] destination, int destOffset, int options ) {\r
+ \r
+ byte[] ALPHABET = getAlphabet( options ); \r
+ \r
+ // 1 2 3 \r
+ // 01234567890123456789012345678901 Bit position\r
+ // --------000000001111111122222222 Array position from threeBytes\r
+ // --------| || || || | Six bit groups to index ALPHABET\r
+ // >>18 >>12 >> 6 >> 0 Right shift necessary\r
+ // 0x3f 0x3f 0x3f Additional AND\r
+ \r
+ // Create buffer with zero-padding if there are only one or two\r
+ // significant bytes passed in the array.\r
+ // We have to shift left 24 in order to flush out the 1's that appear\r
+ // when Java treats a value as negative that is cast from a byte to an int.\r
+ int inBuff = ( numSigBytes > 0 ? ((source[ srcOffset ] << 24) >>> 8) : 0 )\r
+ | ( numSigBytes > 1 ? ((source[ srcOffset + 1 ] << 24) >>> 16) : 0 )\r
+ | ( numSigBytes > 2 ? ((source[ srcOffset + 2 ] << 24) >>> 24) : 0 );\r
+\r
+ switch( numSigBytes )\r
+ {\r
+ case 3:\r
+ destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ];\r
+ destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];\r
+ destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ];\r
+ destination[ destOffset + 3 ] = ALPHABET[ (inBuff ) & 0x3f ];\r
+ return destination;\r
+ \r
+ case 2:\r
+ destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ];\r
+ destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];\r
+ destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ];\r
+ destination[ destOffset + 3 ] = EQUALS_SIGN;\r
+ return destination;\r
+ \r
+ case 1:\r
+ destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ];\r
+ destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];\r
+ destination[ destOffset + 2 ] = EQUALS_SIGN;\r
+ destination[ destOffset + 3 ] = EQUALS_SIGN;\r
+ return destination;\r
+ \r
+ default:\r
+ return destination;\r
+ } // end switch\r
+ } // end encode3to4\r
+\r
+\r
+\r
+ /**\r
+ * Performs Base64 encoding on the <code>raw</code> ByteBuffer,\r
+ * writing it to the <code>encoded</code> ByteBuffer.\r
+ * This is an experimental feature. Currently it does not\r
+ * pass along any options (such as {@link #DO_BREAK_LINES}\r
+ * or {@link #GZIP}.\r
+ *\r
+ * @param raw input buffer\r
+ * @param encoded output buffer\r
+ * @since 2.3\r
+ */\r
+ public static void encode( java.nio.ByteBuffer raw, java.nio.ByteBuffer encoded ){\r
+ byte[] raw3 = new byte[3];\r
+ byte[] enc4 = new byte[4];\r
+\r
+ while( raw.hasRemaining() ){\r
+ int rem = Math.min(3,raw.remaining());\r
+ raw.get(raw3,0,rem);\r
+ Base64.encode3to4(enc4, raw3, rem, Base64.NO_OPTIONS );\r
+ encoded.put(enc4);\r
+ } // end input remaining\r
+ }\r
+\r
+\r
+ /**\r
+ * Performs Base64 encoding on the <code>raw</code> ByteBuffer,\r
+ * writing it to the <code>encoded</code> CharBuffer.\r
+ * This is an experimental feature. Currently it does not\r
+ * pass along any options (such as {@link #DO_BREAK_LINES}\r
+ * or {@link #GZIP}.\r
+ *\r
+ * @param raw input buffer\r
+ * @param encoded output buffer\r
+ * @since 2.3\r
+ */\r
+ public static void encode( java.nio.ByteBuffer raw, java.nio.CharBuffer encoded ){\r
+ byte[] raw3 = new byte[3];\r
+ byte[] enc4 = new byte[4];\r
+\r
+ while( raw.hasRemaining() ){\r
+ int rem = Math.min(3,raw.remaining());\r
+ raw.get(raw3,0,rem);\r
+ Base64.encode3to4(enc4, raw3, rem, Base64.NO_OPTIONS );\r
+ for( int i = 0; i < 4; i++ ){\r
+ encoded.put( (char)(enc4[i] & 0xFF) );\r
+ }\r
+ } // end input remaining\r
+ }\r
+\r
+\r
+ \r
+ \r
+ /**\r
+ * Serializes an object and returns the Base64-encoded\r
+ * version of that serialized object. \r
+ * \r
+ * <p>As of v 2.3, if the object\r
+ * cannot be serialized or there is another error,\r
+ * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>\r
+ * In earlier versions, it just returned a null value, but\r
+ * in retrospect that's a pretty poor way to handle it.</p>\r
+ * \r
+ * The object is not GZip-compressed before being encoded.\r
+ *\r
+ * @param serializableObject The object to encode\r
+ * @return The Base64-encoded object\r
+ * @throws java.io.IOException if there is an error\r
+ * @throws NullPointerException if serializedObject is null\r
+ * @since 1.4\r
+ */\r
+ public static String encodeObject( java.io.Serializable serializableObject )\r
+ throws java.io.IOException {\r
+ return encodeObject( serializableObject, NO_OPTIONS );\r
+ } // end encodeObject\r
+ \r
+\r
+\r
+ /**\r
+ * Serializes an object and returns the Base64-encoded\r
+ * version of that serialized object.\r
+ * \r
+ * <p>As of v 2.3, if the object\r
+ * cannot be serialized or there is another error,\r
+ * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>\r
+ * In earlier versions, it just returned a null value, but\r
+ * in retrospect that's a pretty poor way to handle it.</p>\r
+ * \r
+ * The object is not GZip-compressed before being encoded.\r
+ * <p>\r
+ * Example options:<pre>\r
+ * GZIP: gzip-compresses object before encoding it.\r
+ * DO_BREAK_LINES: break lines at 76 characters\r
+ * </pre>\r
+ * <p>\r
+ * Example: <code>encodeObject( myObj, Base64.GZIP )</code> or\r
+ * <p>\r
+ * Example: <code>encodeObject( myObj, Base64.GZIP | Base64.DO_BREAK_LINES )</code>\r
+ *\r
+ * @param serializableObject The object to encode\r
+ * @param options Specified options\r
+ * @return The Base64-encoded object\r
+ * @see Base64#GZIP\r
+ * @see Base64#DO_BREAK_LINES\r
+ * @throws java.io.IOException if there is an error\r
+ * @since 2.0\r
+ */\r
+ public static String encodeObject( java.io.Serializable serializableObject, int options )\r
+ throws java.io.IOException {\r
+\r
+ if( serializableObject == null ){\r
+ throw new NullPointerException( "Cannot serialize a null object." );\r
+ } // end if: null\r
+ \r
+ // Streams\r
+ java.io.ByteArrayOutputStream baos = null; \r
+ java.io.OutputStream b64os = null;\r
+ java.util.zip.GZIPOutputStream gzos = null;\r
+ java.io.ObjectOutputStream oos = null;\r
+ \r
+ \r
+ try {\r
+ // ObjectOutputStream -> (GZIP) -> Base64 -> ByteArrayOutputStream\r
+ baos = new java.io.ByteArrayOutputStream();\r
+ b64os = new Base64.OutputStream( baos, ENCODE | options );\r
+ if( (options & GZIP) != 0 ){\r
+ // Gzip\r
+ gzos = new java.util.zip.GZIPOutputStream(b64os);\r
+ oos = new java.io.ObjectOutputStream( gzos );\r
+ } else {\r
+ // Not gzipped\r
+ oos = new java.io.ObjectOutputStream( b64os );\r
+ }\r
+ oos.writeObject( serializableObject );\r
+ } // end try\r
+ catch( java.io.IOException e ) {\r
+ // Catch it and then throw it immediately so that\r
+ // the finally{} block is called for cleanup.\r
+ throw e;\r
+ } // end catch\r
+ finally {\r
+ try{ oos.close(); } catch( Exception e ){}\r
+ try{ gzos.close(); } catch( Exception e ){}\r
+ try{ b64os.close(); } catch( Exception e ){}\r
+ try{ baos.close(); } catch( Exception e ){}\r
+ } // end finally\r
+ \r
+ // Return value according to relevant encoding.\r
+ try {\r
+ return new String( baos.toByteArray(), PREFERRED_ENCODING );\r
+ } // end try\r
+ catch (java.io.UnsupportedEncodingException uue){\r
+ // Fall back to some Java default\r
+ return new String( baos.toByteArray() );\r
+ } // end catch\r
+ \r
+ } // end encode\r
+ \r
+ \r
+\r
+ /**\r
+ * Encodes a byte array into Base64 notation.\r
+ * Does not GZip-compress data.\r
+ * \r
+ * @param source The data to convert\r
+ * @return The data in Base64-encoded form\r
+ * @throws NullPointerException if source array is null\r
+ * @since 1.4\r
+ */\r
+ public static String encodeBytes( byte[] source ) {\r
+ // Since we're not going to have the GZIP encoding turned on,\r
+ // we're not going to have an java.io.IOException thrown, so\r
+ // we should not force the user to have to catch it.\r
+ String encoded = null;\r
+ try {\r
+ encoded = encodeBytes(source, 0, source.length, NO_OPTIONS);\r
+ } catch (java.io.IOException ex) {\r
+ assert false : ex.getMessage();\r
+ } // end catch\r
+ assert encoded != null;\r
+ return encoded;\r
+ } // end encodeBytes\r
+ \r
+\r
+\r
+ /**\r
+ * Encodes a byte array into Base64 notation.\r
+ * <p>\r
+ * Example options:<pre>\r
+ * GZIP: gzip-compresses object before encoding it.\r
+ * DO_BREAK_LINES: break lines at 76 characters\r
+ * <i>Note: Technically, this makes your encoding non-compliant.</i>\r
+ * </pre>\r
+ * <p>\r
+ * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or\r
+ * <p>\r
+ * Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DO_BREAK_LINES )</code>\r
+ *\r
+ * \r
+ * <p>As of v 2.3, if there is an error with the GZIP stream,\r
+ * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>\r
+ * In earlier versions, it just returned a null value, but\r
+ * in retrospect that's a pretty poor way to handle it.</p>\r
+ * \r
+ *\r
+ * @param source The data to convert\r
+ * @param options Specified options\r
+ * @return The Base64-encoded data as a String\r
+ * @see Base64#GZIP\r
+ * @see Base64#DO_BREAK_LINES\r
+ * @throws java.io.IOException if there is an error\r
+ * @throws NullPointerException if source array is null\r
+ * @since 2.0\r
+ */\r
+ public static String encodeBytes( byte[] source, int options ) throws java.io.IOException {\r
+ return encodeBytes( source, 0, source.length, options );\r
+ } // end encodeBytes\r
+ \r
+ \r
+ /**\r
+ * Encodes a byte array into Base64 notation.\r
+ * Does not GZip-compress data.\r
+ * \r
+ * <p>As of v 2.3, if there is an error,\r
+ * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>\r
+ * In earlier versions, it just returned a null value, but\r
+ * in retrospect that's a pretty poor way to handle it.</p>\r
+ * \r
+ *\r
+ * @param source The data to convert\r
+ * @param off Offset in array where conversion should begin\r
+ * @param len Length of data to convert\r
+ * @return The Base64-encoded data as a String\r
+ * @throws NullPointerException if source array is null\r
+ * @throws IllegalArgumentException if source array, offset, or length are invalid\r
+ * @since 1.4\r
+ */\r
+ public static String encodeBytes( byte[] source, int off, int len ) {\r
+ // Since we're not going to have the GZIP encoding turned on,\r
+ // we're not going to have an java.io.IOException thrown, so\r
+ // we should not force the user to have to catch it.\r
+ String encoded = null;\r
+ try {\r
+ encoded = encodeBytes( source, off, len, NO_OPTIONS );\r
+ } catch (java.io.IOException ex) {\r
+ assert false : ex.getMessage();\r
+ } // end catch\r
+ assert encoded != null;\r
+ return encoded;\r
+ } // end encodeBytes\r
+ \r
+ \r
+\r
+ /**\r
+ * Encodes a byte array into Base64 notation.\r
+ * <p>\r
+ * Example options:<pre>\r
+ * GZIP: gzip-compresses object before encoding it.\r
+ * DO_BREAK_LINES: break lines at 76 characters\r
+ * <i>Note: Technically, this makes your encoding non-compliant.</i>\r
+ * </pre>\r
+ * <p>\r
+ * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or\r
+ * <p>\r
+ * Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DO_BREAK_LINES )</code>\r
+ *\r
+ * \r
+ * <p>As of v 2.3, if there is an error with the GZIP stream,\r
+ * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>\r
+ * In earlier versions, it just returned a null value, but\r
+ * in retrospect that's a pretty poor way to handle it.</p>\r
+ * \r
+ *\r
+ * @param source The data to convert\r
+ * @param off Offset in array where conversion should begin\r
+ * @param len Length of data to convert\r
+ * @param options Specified options\r
+ * @return The Base64-encoded data as a String\r
+ * @see Base64#GZIP\r
+ * @see Base64#DO_BREAK_LINES\r
+ * @throws java.io.IOException if there is an error\r
+ * @throws NullPointerException if source array is null\r
+ * @throws IllegalArgumentException if source array, offset, or length are invalid\r
+ * @since 2.0\r
+ */\r
+ public static String encodeBytes( byte[] source, int off, int len, int options ) throws java.io.IOException {\r
+ byte[] encoded = encodeBytesToBytes( source, off, len, options );\r
+\r
+ // Return value according to relevant encoding.\r
+ try {\r
+ return new String( encoded, PREFERRED_ENCODING );\r
+ } // end try\r
+ catch (java.io.UnsupportedEncodingException uue) {\r
+ return new String( encoded );\r
+ } // end catch\r
+ \r
+ } // end encodeBytes\r
+\r
+\r
+\r
+\r
+ /**\r
+ * Similar to {@link #encodeBytes(byte[])} but returns\r
+ * a byte array instead of instantiating a String. This is more efficient\r
+ * if you're working with I/O streams and have large data sets to encode.\r
+ *\r
+ *\r
+ * @param source The data to convert\r
+ * @return The Base64-encoded data as a byte[] (of ASCII characters)\r
+ * @throws NullPointerException if source array is null\r
+ * @since 2.3.1\r
+ */\r
+ public static byte[] encodeBytesToBytes( byte[] source ) {\r
+ byte[] encoded = null;\r
+ try {\r
+ encoded = encodeBytesToBytes( source, 0, source.length, Base64.NO_OPTIONS );\r
+ } catch( java.io.IOException ex ) {\r
+ assert false : "IOExceptions only come from GZipping, which is turned off: " + ex.getMessage();\r
+ }\r
+ return encoded;\r
+ }\r
+\r
+\r
+ /**\r
+ * Similar to {@link #encodeBytes(byte[], int, int, int)} but returns\r
+ * a byte array instead of instantiating a String. This is more efficient\r
+ * if you're working with I/O streams and have large data sets to encode.\r
+ *\r
+ *\r
+ * @param source The data to convert\r
+ * @param off Offset in array where conversion should begin\r
+ * @param len Length of data to convert\r
+ * @param options Specified options\r
+ * @return The Base64-encoded data as a String\r
+ * @see Base64#GZIP\r
+ * @see Base64#DO_BREAK_LINES\r
+ * @throws java.io.IOException if there is an error\r
+ * @throws NullPointerException if source array is null\r
+ * @throws IllegalArgumentException if source array, offset, or length are invalid\r
+ * @since 2.3.1\r
+ */\r
+ public static byte[] encodeBytesToBytes( byte[] source, int off, int len, int options ) throws java.io.IOException {\r
+\r
+ if( source == null ){\r
+ throw new NullPointerException( "Cannot serialize a null array." );\r
+ } // end if: null\r
+\r
+ if( off < 0 ){\r
+ throw new IllegalArgumentException( "Cannot have negative offset: " + off );\r
+ } // end if: off < 0\r
+\r
+ if( len < 0 ){\r
+ throw new IllegalArgumentException( "Cannot have length offset: " + len );\r
+ } // end if: len < 0\r
+\r
+ if( off + len > source.length ){\r
+ throw new IllegalArgumentException(\r
+ String.format( "Cannot have offset of %d and length of %d with array of length %d", off,len,source.length));\r
+ } // end if: off < 0\r
+\r
+\r
+\r
+ // Compress?\r
+ if( (options & GZIP) != 0 ) {\r
+ java.io.ByteArrayOutputStream baos = null;\r
+ java.util.zip.GZIPOutputStream gzos = null;\r
+ Base64.OutputStream b64os = null;\r
+\r
+ try {\r
+ // GZip -> Base64 -> ByteArray\r
+ baos = new java.io.ByteArrayOutputStream();\r
+ b64os = new Base64.OutputStream( baos, ENCODE | options );\r
+ gzos = new java.util.zip.GZIPOutputStream( b64os );\r
+\r
+ gzos.write( source, off, len );\r
+ gzos.close();\r
+ } // end try\r
+ catch( java.io.IOException e ) {\r
+ // Catch it and then throw it immediately so that\r
+ // the finally{} block is called for cleanup.\r
+ throw e;\r
+ } // end catch\r
+ finally {\r
+ try{ gzos.close(); } catch( Exception e ){}\r
+ try{ b64os.close(); } catch( Exception e ){}\r
+ try{ baos.close(); } catch( Exception e ){}\r
+ } // end finally\r
+\r
+ return baos.toByteArray();\r
+ } // end if: compress\r
+\r
+ // Else, don't compress. Better not to use streams at all then.\r
+ else {\r
+ boolean breakLines = (options & DO_BREAK_LINES) > 0;\r
+\r
+ //int len43 = len * 4 / 3;\r
+ //byte[] outBuff = new byte[ ( len43 ) // Main 4:3\r
+ // + ( (len % 3) > 0 ? 4 : 0 ) // Account for padding\r
+ // + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines\r
+ // Try to determine more precisely how big the array needs to be.\r
+ // If we get it right, we don't have to do an array copy, and\r
+ // we save a bunch of memory.\r
+ int encLen = ( len / 3 ) * 4 + ( len % 3 > 0 ? 4 : 0 ); // Bytes needed for actual encoding\r
+ if( breakLines ){\r
+ encLen += encLen / MAX_LINE_LENGTH; // Plus extra newline characters\r
+ }\r
+ byte[] outBuff = new byte[ encLen ];\r
+\r
+\r
+ int d = 0;\r
+ int e = 0;\r
+ int len2 = len - 2;\r
+ int lineLength = 0;\r
+ for( ; d < len2; d+=3, e+=4 ) {\r
+ encode3to4( source, d+off, 3, outBuff, e, options );\r
+\r
+ lineLength += 4;\r
+ if( breakLines && lineLength >= MAX_LINE_LENGTH )\r
+ {\r
+ outBuff[e+4] = NEW_LINE;\r
+ e++;\r
+ lineLength = 0;\r
+ } // end if: end of line\r
+ } // en dfor: each piece of array\r
+\r
+ if( d < len ) {\r
+ encode3to4( source, d+off, len - d, outBuff, e, options );\r
+ e += 4;\r
+ } // end if: some padding needed\r
+\r
+\r
+ // Only resize array if we didn't guess it right.\r
+ if( e < outBuff.length - 1 ){\r
+ byte[] finalOut = new byte[e];\r
+ System.arraycopy(outBuff,0, finalOut,0,e);\r
+ //System.err.println("Having to resize array from " + outBuff.length + " to " + e );\r
+ return finalOut;\r
+ } else {\r
+ //System.err.println("No need to resize array.");\r
+ return outBuff;\r
+ }\r
+ \r
+ } // end else: don't compress\r
+\r
+ } // end encodeBytesToBytes\r
+ \r
+\r
+ \r
+ \r
+ \r
+/* ******** D E C O D I N G M E T H O D S ******** */\r
+ \r
+ \r
+ /**\r
+ * Decodes four bytes from array <var>source</var>\r
+ * and writes the resulting bytes (up to three of them)\r
+ * to <var>destination</var>.\r
+ * The source and destination arrays can be manipulated\r
+ * anywhere along their length by specifying \r
+ * <var>srcOffset</var> and <var>destOffset</var>.\r
+ * This method does not check to make sure your arrays\r
+ * are large enough to accomodate <var>srcOffset</var> + 4 for\r
+ * the <var>source</var> array or <var>destOffset</var> + 3 for\r
+ * the <var>destination</var> array.\r
+ * This method returns the actual number of bytes that \r
+ * were converted from the Base64 encoding.\r
+ * <p>This is the lowest level of the decoding methods with\r
+ * all possible parameters.</p>\r
+ * \r
+ *\r
+ * @param source the array to convert\r
+ * @param srcOffset the index where conversion begins\r
+ * @param destination the array to hold the conversion\r
+ * @param destOffset the index where output will be put\r
+ * @param options alphabet type is pulled from this (standard, url-safe, ordered)\r
+ * @return the number of decoded bytes converted\r
+ * @throws NullPointerException if source or destination arrays are null\r
+ * @throws IllegalArgumentException if srcOffset or destOffset are invalid\r
+ * or there is not enough room in the array.\r
+ * @since 1.3\r
+ */\r
+ private static int decode4to3( \r
+ byte[] source, int srcOffset, \r
+ byte[] destination, int destOffset, int options ) {\r
+ \r
+ // Lots of error checking and exception throwing\r
+ if( source == null ){\r
+ throw new NullPointerException( "Source array was null." );\r
+ } // end if\r
+ if( destination == null ){\r
+ throw new NullPointerException( "Destination array was null." );\r
+ } // end if\r
+ if( srcOffset < 0 || srcOffset + 3 >= source.length ){\r
+ throw new IllegalArgumentException( String.format(\r
+ "Source array with length %d cannot have offset of %d and still process four bytes.", source.length, srcOffset ) );\r
+ } // end if\r
+ if( destOffset < 0 || destOffset +2 >= destination.length ){\r
+ throw new IllegalArgumentException( String.format(\r
+ "Destination array with length %d cannot have offset of %d and still store three bytes.", destination.length, destOffset ) );\r
+ } // end if\r
+ \r
+ \r
+ byte[] DECODABET = getDecodabet( options ); \r
+ \r
+ // Example: Dk==\r
+ if( source[ srcOffset + 2] == EQUALS_SIGN ) {\r
+ // Two ways to do the same thing. Don't know which way I like best.\r
+ //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )\r
+ // | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 );\r
+ int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 )\r
+ | ( ( DECODABET[ source[ srcOffset + 1] ] & 0xFF ) << 12 );\r
+ \r
+ destination[ destOffset ] = (byte)( outBuff >>> 16 );\r
+ return 1;\r
+ }\r
+ \r
+ // Example: DkL=\r
+ else if( source[ srcOffset + 3 ] == EQUALS_SIGN ) {\r
+ // Two ways to do the same thing. Don't know which way I like best.\r
+ //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )\r
+ // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )\r
+ // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 );\r
+ int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 )\r
+ | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 )\r
+ | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6 );\r
+ \r
+ destination[ destOffset ] = (byte)( outBuff >>> 16 );\r
+ destination[ destOffset + 1 ] = (byte)( outBuff >>> 8 );\r
+ return 2;\r
+ }\r
+ \r
+ // Example: DkLE\r
+ else {\r
+ // Two ways to do the same thing. Don't know which way I like best.\r
+ //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )\r
+ // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )\r
+ // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 )\r
+ // | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 );\r
+ int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 )\r
+ | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 )\r
+ | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6)\r
+ | ( ( DECODABET[ source[ srcOffset + 3 ] ] & 0xFF ) );\r
+\r
+ \r
+ destination[ destOffset ] = (byte)( outBuff >> 16 );\r
+ destination[ destOffset + 1 ] = (byte)( outBuff >> 8 );\r
+ destination[ destOffset + 2 ] = (byte)( outBuff );\r
+\r
+ return 3;\r
+ }\r
+ } // end decodeToBytes\r
+ \r
+\r
+\r
+\r
+\r
+ /**\r
+ * Low-level access to decoding ASCII characters in\r
+ * the form of a byte array. <strong>Ignores GUNZIP option, if\r
+ * it's set.</strong> This is not generally a recommended method,\r
+ * although it is used internally as part of the decoding process.\r
+ * Special case: if len = 0, an empty array is returned. Still,\r
+ * if you need more speed and reduced memory footprint (and aren't\r
+ * gzipping), consider this method.\r
+ *\r
+ * @param source The Base64 encoded data\r
+ * @return decoded data\r
+ * @since 2.3.1\r
+ */\r
+ public static byte[] decode( byte[] source ){\r
+ byte[] decoded = null;\r
+ try {\r
+ decoded = decode( source, 0, source.length, Base64.NO_OPTIONS );\r
+ } catch( java.io.IOException ex ) {\r
+ assert false : "IOExceptions only come from GZipping, which is turned off: " + ex.getMessage();\r
+ }\r
+ return decoded;\r
+ }\r
+\r
+ \r
+ \r
+ /**\r
+ * Low-level access to decoding ASCII characters in\r
+ * the form of a byte array. <strong>Ignores GUNZIP option, if\r
+ * it's set.</strong> This is not generally a recommended method,\r
+ * although it is used internally as part of the decoding process.\r
+ * Special case: if len = 0, an empty array is returned. Still,\r
+ * if you need more speed and reduced memory footprint (and aren't\r
+ * gzipping), consider this method.\r
+ *\r
+ * @param source The Base64 encoded data\r
+ * @param off The offset of where to begin decoding\r
+ * @param len The length of characters to decode\r
+ * @param options Can specify options such as alphabet type to use\r
+ * @return decoded data\r
+ * @throws java.io.IOException If bogus characters exist in source data\r
+ * @since 1.3\r
+ */\r
+ public static byte[] decode( byte[] source, int off, int len, int options )\r
+ throws java.io.IOException {\r
+ \r
+ // Lots of error checking and exception throwing\r
+ if( source == null ){\r
+ throw new NullPointerException( "Cannot decode null source array." );\r
+ } // end if\r
+ if( off < 0 || off + len > source.length ){\r
+ throw new IllegalArgumentException( String.format(\r
+ "Source array with length %d cannot have offset of %d and process %d bytes.", source.length, off, len ) );\r
+ } // end if\r
+ \r
+ if( len == 0 ){\r
+ return new byte[0];\r
+ }else if( len < 4 ){\r
+ throw new IllegalArgumentException( \r
+ "Base64-encoded string must have at least four characters, but length specified was " + len );\r
+ } // end if\r
+ \r
+ byte[] DECODABET = getDecodabet( options );\r
+ \r
+ int len34 = len * 3 / 4; // Estimate on array size\r
+ byte[] outBuff = new byte[ len34 ]; // Upper limit on size of output\r
+ int outBuffPosn = 0; // Keep track of where we're writing\r
+ \r
+ byte[] b4 = new byte[4]; // Four byte buffer from source, eliminating white space\r
+ int b4Posn = 0; // Keep track of four byte input buffer\r
+ int i = 0; // Source array counter\r
+ byte sbiCrop = 0; // Low seven bits (ASCII) of input\r
+ byte sbiDecode = 0; // Special value from DECODABET\r
+ \r
+ for( i = off; i < off+len; i++ ) { // Loop through source\r
+ \r
+ sbiCrop = (byte)(source[i] & 0x7f); // Only the low seven bits\r
+ sbiDecode = DECODABET[ sbiCrop ]; // Special value\r
+ \r
+ // White space, Equals sign, or legit Base64 character\r
+ // Note the values such as -5 and -9 in the\r
+ // DECODABETs at the top of the file.\r
+ if( sbiDecode >= WHITE_SPACE_ENC ) {\r
+ if( sbiDecode >= EQUALS_SIGN_ENC ) {\r
+ b4[ b4Posn++ ] = sbiCrop; // Save non-whitespace\r
+ if( b4Posn > 3 ) { // Time to decode?\r
+ outBuffPosn += decode4to3( b4, 0, outBuff, outBuffPosn, options );\r
+ b4Posn = 0;\r
+ \r
+ // If that was the equals sign, break out of 'for' loop\r
+ if( sbiCrop == EQUALS_SIGN ) {\r
+ break;\r
+ } // end if: equals sign\r
+ } // end if: quartet built\r
+ } // end if: equals sign or better\r
+ } // end if: white space, equals sign or better\r
+ else {\r
+ // There's a bad input character in the Base64 stream.\r
+ throw new java.io.IOException( String.format(\r
+ "Bad Base64 input character '%c' in array position %d", source[i], i ) );\r
+ } // end else: \r
+ } // each input character\r
+ \r
+ byte[] out = new byte[ outBuffPosn ];\r
+ System.arraycopy( outBuff, 0, out, 0, outBuffPosn ); \r
+ return out;\r
+ } // end decode\r
+ \r
+ \r
+ \r
+ \r
+ /**\r
+ * Decodes data from Base64 notation, automatically\r
+ * detecting gzip-compressed data and decompressing it.\r
+ *\r
+ * @param s the string to decode\r
+ * @return the decoded data\r
+ * @throws java.io.IOException If there is a problem\r
+ * @since 1.4\r
+ */\r
+ public static byte[] decode( String s ) throws java.io.IOException {\r
+ return decode( s, NO_OPTIONS );\r
+ }\r
+\r
+ \r
+ \r
+ /**\r
+ * Decodes data from Base64 notation, automatically\r
+ * detecting gzip-compressed data and decompressing it.\r
+ *\r
+ * @param s the string to decode\r
+ * @param options encode options such as URL_SAFE\r
+ * @return the decoded data\r
+ * @throws java.io.IOException if there is an error\r
+ * @throws NullPointerException if <tt>s</tt> is null\r
+ * @since 1.4\r
+ */\r
+ public static byte[] decode( String s, int options ) throws java.io.IOException {\r
+ \r
+ if( s == null ){\r
+ throw new NullPointerException( "Input string was null." );\r
+ } // end if\r
+ \r
+ byte[] bytes;\r
+ try {\r
+ bytes = s.getBytes( PREFERRED_ENCODING );\r
+ } // end try\r
+ catch( java.io.UnsupportedEncodingException uee ) {\r
+ bytes = s.getBytes();\r
+ } // end catch\r
+ //</change>\r
+ \r
+ // Decode\r
+ bytes = decode( bytes, 0, bytes.length, options );\r
+ \r
+ // Check to see if it's gzip-compressed\r
+ // GZIP Magic Two-Byte Number: 0x8b1f (35615)\r
+ boolean dontGunzip = (options & DONT_GUNZIP) != 0;\r
+ if( (bytes != null) && (bytes.length >= 4) && (!dontGunzip) ) {\r
+ \r
+ int head = (bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00);\r
+ if( java.util.zip.GZIPInputStream.GZIP_MAGIC == head ) {\r
+ java.io.ByteArrayInputStream bais = null;\r
+ java.util.zip.GZIPInputStream gzis = null;\r
+ java.io.ByteArrayOutputStream baos = null;\r
+ byte[] buffer = new byte[2048];\r
+ int length = 0;\r
+\r
+ try {\r
+ baos = new java.io.ByteArrayOutputStream();\r
+ bais = new java.io.ByteArrayInputStream( bytes );\r
+ gzis = new java.util.zip.GZIPInputStream( bais );\r
+\r
+ while( ( length = gzis.read( buffer ) ) >= 0 ) {\r
+ baos.write(buffer,0,length);\r
+ } // end while: reading input\r
+\r
+ // No error? Get new bytes.\r
+ bytes = baos.toByteArray();\r
+\r
+ } // end try\r
+ catch( java.io.IOException e ) {\r
+ e.printStackTrace();\r
+ // Just return originally-decoded bytes\r
+ } // end catch\r
+ finally {\r
+ try{ baos.close(); } catch( Exception e ){}\r
+ try{ gzis.close(); } catch( Exception e ){}\r
+ try{ bais.close(); } catch( Exception e ){}\r
+ } // end finally\r
+\r
+ } // end if: gzipped\r
+ } // end if: bytes.length >= 2\r
+ \r
+ return bytes;\r
+ } // end decode\r
+\r
+\r
+\r
+ /**\r
+ * Attempts to decode Base64 data and deserialize a Java\r
+ * Object within. Returns <tt>null</tt> if there was an error.\r
+ *\r
+ * @param encodedObject The Base64 data to decode\r
+ * @return The decoded and deserialized object\r
+ * @throws NullPointerException if encodedObject is null\r
+ * @throws java.io.IOException if there is a general error\r
+ * @throws ClassNotFoundException if the decoded object is of a\r
+ * class that cannot be found by the JVM\r
+ * @since 1.5\r
+ */\r
+ public static Object decodeToObject( String encodedObject )\r
+ throws java.io.IOException, java.lang.ClassNotFoundException {\r
+ return decodeToObject(encodedObject,NO_OPTIONS,null);\r
+ }\r
+ \r
+\r
+ /**\r
+ * Attempts to decode Base64 data and deserialize a Java\r
+ * Object within. Returns <tt>null</tt> if there was an error.\r
+ * If <tt>loader</tt> is not null, it will be the class loader\r
+ * used when deserializing.\r
+ *\r
+ * @param encodedObject The Base64 data to decode\r
+ * @param options Various parameters related to decoding\r
+ * @param loader Optional class loader to use in deserializing classes.\r
+ * @return The decoded and deserialized object\r
+ * @throws NullPointerException if encodedObject is null\r
+ * @throws java.io.IOException if there is a general error\r
+ * @throws ClassNotFoundException if the decoded object is of a \r
+ * class that cannot be found by the JVM\r
+ * @since 2.3.4\r
+ */\r
+ public static Object decodeToObject( \r
+ String encodedObject, int options, final ClassLoader loader )\r
+ throws java.io.IOException, java.lang.ClassNotFoundException {\r
+ \r
+ // Decode and gunzip if necessary\r
+ byte[] objBytes = decode( encodedObject, options );\r
+ \r
+ java.io.ByteArrayInputStream bais = null;\r
+ java.io.ObjectInputStream ois = null;\r
+ Object obj = null;\r
+ \r
+ try {\r
+ bais = new java.io.ByteArrayInputStream( objBytes );\r
+\r
+ // If no custom class loader is provided, use Java's builtin OIS.\r
+ if( loader == null ){\r
+ ois = new java.io.ObjectInputStream( bais );\r
+ } // end if: no loader provided\r
+\r
+ // Else make a customized object input stream that uses\r
+ // the provided class loader.\r
+ else {\r
+ ois = new java.io.ObjectInputStream(bais){\r
+ @SuppressWarnings("unchecked")\r
+ @Override\r
+ public Class<?> resolveClass(java.io.ObjectStreamClass streamClass)\r
+ throws java.io.IOException, ClassNotFoundException {\r
+ Class c = Class.forName(streamClass.getName(), false, loader);\r
+ if( c == null ){\r
+ return super.resolveClass(streamClass);\r
+ } else {\r
+ return c; // Class loader knows of this class.\r
+ } // end else: not null\r
+ } // end resolveClass\r
+ }; // end ois\r
+ } // end else: no custom class loader\r
+ \r
+ obj = ois.readObject();\r
+ } // end try\r
+ catch( java.io.IOException e ) {\r
+ throw e; // Catch and throw in order to execute finally{}\r
+ } // end catch\r
+ catch( java.lang.ClassNotFoundException e ) {\r
+ throw e; // Catch and throw in order to execute finally{}\r
+ } // end catch\r
+ finally {\r
+ try{ bais.close(); } catch( Exception e ){}\r
+ try{ ois.close(); } catch( Exception e ){}\r
+ } // end finally\r
+ \r
+ return obj;\r
+ } // end decodeObject\r
+ \r
+ \r
+ \r
+ /**\r
+ * Convenience method for encoding data to a file.\r
+ *\r
+ * <p>As of v 2.3, if there is a error,\r
+ * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>\r
+ * In earlier versions, it just returned false, but\r
+ * in retrospect that's a pretty poor way to handle it.</p>\r
+ * \r
+ * @param dataToEncode byte array of data to encode in base64 form\r
+ * @param filename Filename for saving encoded data\r
+ * @throws java.io.IOException if there is an error\r
+ * @throws NullPointerException if dataToEncode is null\r
+ * @since 2.1\r
+ */\r
+ public static void encodeToFile( byte[] dataToEncode, String filename )\r
+ throws java.io.IOException {\r
+ \r
+ if( dataToEncode == null ){\r
+ throw new NullPointerException( "Data to encode was null." );\r
+ } // end iff\r
+ \r
+ Base64.OutputStream bos = null;\r
+ try {\r
+ bos = new Base64.OutputStream( \r
+ new java.io.FileOutputStream( filename ), Base64.ENCODE );\r
+ bos.write( dataToEncode );\r
+ } // end try\r
+ catch( java.io.IOException e ) {\r
+ throw e; // Catch and throw to execute finally{} block\r
+ } // end catch: java.io.IOException\r
+ finally {\r
+ try{ bos.close(); } catch( Exception e ){}\r
+ } // end finally\r
+ \r
+ } // end encodeToFile\r
+ \r
+ \r
+ /**\r
+ * Convenience method for decoding data to a file.\r
+ *\r
+ * <p>As of v 2.3, if there is a error,\r
+ * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>\r
+ * In earlier versions, it just returned false, but\r
+ * in retrospect that's a pretty poor way to handle it.</p>\r
+ * \r
+ * @param dataToDecode Base64-encoded data as a string\r
+ * @param filename Filename for saving decoded data\r
+ * @throws java.io.IOException if there is an error\r
+ * @since 2.1\r
+ */\r
+ public static void decodeToFile( String dataToDecode, String filename )\r
+ throws java.io.IOException {\r
+ \r
+ Base64.OutputStream bos = null;\r
+ try{\r
+ bos = new Base64.OutputStream( \r
+ new java.io.FileOutputStream( filename ), Base64.DECODE );\r
+ bos.write( dataToDecode.getBytes( PREFERRED_ENCODING ) );\r
+ } // end try\r
+ catch( java.io.IOException e ) {\r
+ throw e; // Catch and throw to execute finally{} block\r
+ } // end catch: java.io.IOException\r
+ finally {\r
+ try{ bos.close(); } catch( Exception e ){}\r
+ } // end finally\r
+ \r
+ } // end decodeToFile\r
+ \r
+ \r
+ \r
+ \r
+ /**\r
+ * Convenience method for reading a base64-encoded\r
+ * file and decoding it.\r
+ *\r
+ * <p>As of v 2.3, if there is a error,\r
+ * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>\r
+ * In earlier versions, it just returned false, but\r
+ * in retrospect that's a pretty poor way to handle it.</p>\r
+ * \r
+ * @param filename Filename for reading encoded data\r
+ * @return decoded byte array\r
+ * @throws java.io.IOException if there is an error\r
+ * @since 2.1\r
+ */\r
+ public static byte[] decodeFromFile( String filename )\r
+ throws java.io.IOException {\r
+ \r
+ byte[] decodedData = null;\r
+ Base64.InputStream bis = null;\r
+ try\r
+ {\r
+ // Set up some useful variables\r
+ java.io.File file = new java.io.File( filename );\r
+ byte[] buffer = null;\r
+ int length = 0;\r
+ int numBytes = 0;\r
+ \r
+ // Check for size of file\r
+ if( file.length() > Integer.MAX_VALUE )\r
+ {\r
+ throw new java.io.IOException( "File is too big for this convenience method (" + file.length() + " bytes)." );\r
+ } // end if: file too big for int index\r
+ buffer = new byte[ (int)file.length() ];\r
+ \r
+ // Open a stream\r
+ bis = new Base64.InputStream( \r
+ new java.io.BufferedInputStream( \r
+ new java.io.FileInputStream( file ) ), Base64.DECODE );\r
+ \r
+ // Read until done\r
+ while( ( numBytes = bis.read( buffer, length, 4096 ) ) >= 0 ) {\r
+ length += numBytes;\r
+ } // end while\r
+ \r
+ // Save in a variable to return\r
+ decodedData = new byte[ length ];\r
+ System.arraycopy( buffer, 0, decodedData, 0, length );\r
+ \r
+ } // end try\r
+ catch( java.io.IOException e ) {\r
+ throw e; // Catch and release to execute finally{}\r
+ } // end catch: java.io.IOException\r
+ finally {\r
+ try{ bis.close(); } catch( Exception e) {}\r
+ } // end finally\r
+ \r
+ return decodedData;\r
+ } // end decodeFromFile\r
+ \r
+ \r
+ \r
+ /**\r
+ * Convenience method for reading a binary file\r
+ * and base64-encoding it.\r
+ *\r
+ * <p>As of v 2.3, if there is a error,\r
+ * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>\r
+ * In earlier versions, it just returned false, but\r
+ * in retrospect that's a pretty poor way to handle it.</p>\r
+ * \r
+ * @param filename Filename for reading binary data\r
+ * @return base64-encoded string\r
+ * @throws java.io.IOException if there is an error\r
+ * @since 2.1\r
+ */\r
+ public static String encodeFromFile( String filename )\r
+ throws java.io.IOException {\r
+ \r
+ String encodedData = null;\r
+ Base64.InputStream bis = null;\r
+ try\r
+ {\r
+ // Set up some useful variables\r
+ java.io.File file = new java.io.File( filename );\r
+ byte[] buffer = new byte[ Math.max((int)(file.length() * 1.4),40) ]; // Need max() for math on small files (v2.2.1)\r
+ int length = 0;\r
+ int numBytes = 0;\r
+ \r
+ // Open a stream\r
+ bis = new Base64.InputStream( \r
+ new java.io.BufferedInputStream( \r
+ new java.io.FileInputStream( file ) ), Base64.ENCODE );\r
+ \r
+ // Read until done\r
+ while( ( numBytes = bis.read( buffer, length, 4096 ) ) >= 0 ) {\r
+ length += numBytes;\r
+ } // end while\r
+ \r
+ // Save in a variable to return\r
+ encodedData = new String( buffer, 0, length, Base64.PREFERRED_ENCODING );\r
+ \r
+ } // end try\r
+ catch( java.io.IOException e ) {\r
+ throw e; // Catch and release to execute finally{}\r
+ } // end catch: java.io.IOException\r
+ finally {\r
+ try{ bis.close(); } catch( Exception e) {}\r
+ } // end finally\r
+ \r
+ return encodedData;\r
+ } // end encodeFromFile\r
+ \r
+ /**\r
+ * Reads <tt>infile</tt> and encodes it to <tt>outfile</tt>.\r
+ *\r
+ * @param infile Input file\r
+ * @param outfile Output file\r
+ * @throws java.io.IOException if there is an error\r
+ * @since 2.2\r
+ */\r
+ public static void encodeFileToFile( String infile, String outfile )\r
+ throws java.io.IOException {\r
+ \r
+ String encoded = Base64.encodeFromFile( infile );\r
+ java.io.OutputStream out = null;\r
+ try{\r
+ out = new java.io.BufferedOutputStream(\r
+ new java.io.FileOutputStream( outfile ) );\r
+ out.write( encoded.getBytes("US-ASCII") ); // Strict, 7-bit output.\r
+ } // end try\r
+ catch( java.io.IOException e ) {\r
+ throw e; // Catch and release to execute finally{}\r
+ } // end catch\r
+ finally {\r
+ try { out.close(); }\r
+ catch( Exception ex ){}\r
+ } // end finally \r
+ } // end encodeFileToFile\r
+\r
+\r
+ /**\r
+ * Reads <tt>infile</tt> and decodes it to <tt>outfile</tt>.\r
+ *\r
+ * @param infile Input file\r
+ * @param outfile Output file\r
+ * @throws java.io.IOException if there is an error\r
+ * @since 2.2\r
+ */\r
+ public static void decodeFileToFile( String infile, String outfile )\r
+ throws java.io.IOException {\r
+ \r
+ byte[] decoded = Base64.decodeFromFile( infile );\r
+ java.io.OutputStream out = null;\r
+ try{\r
+ out = new java.io.BufferedOutputStream(\r
+ new java.io.FileOutputStream( outfile ) );\r
+ out.write( decoded );\r
+ } // end try\r
+ catch( java.io.IOException e ) {\r
+ throw e; // Catch and release to execute finally{}\r
+ } // end catch\r
+ finally {\r
+ try { out.close(); }\r
+ catch( Exception ex ){}\r
+ } // end finally \r
+ } // end decodeFileToFile\r
+ \r
+ \r
+ /* ******** I N N E R C L A S S I N P U T S T R E A M ******** */\r
+ \r
+ \r
+ \r
+ /**\r
+ * A {@link Base64.InputStream} will read data from another\r
+ * <tt>java.io.InputStream</tt>, given in the constructor,\r
+ * and encode/decode to/from Base64 notation on the fly.\r
+ *\r
+ * @see Base64\r
+ * @since 1.3\r
+ */\r
+ public static class InputStream extends java.io.FilterInputStream {\r
+ \r
+ private final boolean encode; // Encoding or decoding\r
+ private int position; // Current position in the buffer\r
+ private final byte[] buffer; // Small buffer holding converted data\r
+ private final int bufferLength; // Length of buffer (3 or 4)\r
+ private int numSigBytes; // Number of meaningful bytes in the buffer\r
+ private int lineLength;\r
+ private final boolean breakLines; // Break lines at less than 80 characters\r
+ private final int options; // Record options used to create the stream.\r
+ private final byte[] decodabet; // Local copies to avoid extra method calls\r
+ \r
+ \r
+ /**\r
+ * Constructs a {@link Base64.InputStream} in DECODE mode.\r
+ *\r
+ * @param in the <tt>java.io.InputStream</tt> from which to read data.\r
+ * @since 1.3\r
+ */\r
+ public InputStream( java.io.InputStream in ) {\r
+ this( in, DECODE );\r
+ } // end constructor\r
+ \r
+ \r
+ /**\r
+ * Constructs a {@link Base64.InputStream} in\r
+ * either ENCODE or DECODE mode.\r
+ * <p>\r
+ * Valid options:<pre>\r
+ * ENCODE or DECODE: Encode or Decode as data is read.\r
+ * DO_BREAK_LINES: break lines at 76 characters\r
+ * (only meaningful when encoding)</i>\r
+ * </pre>\r
+ * <p>\r
+ * Example: <code>new Base64.InputStream( in, Base64.DECODE )</code>\r
+ *\r
+ *\r
+ * @param in the <tt>java.io.InputStream</tt> from which to read data.\r
+ * @param options Specified options\r
+ * @see Base64#ENCODE\r
+ * @see Base64#DECODE\r
+ * @see Base64#DO_BREAK_LINES\r
+ * @since 2.0\r
+ */\r
+ public InputStream( java.io.InputStream in, int options ) {\r
+ \r
+ super( in );\r
+ this.options = options; // Record for later\r
+ this.breakLines = (options & DO_BREAK_LINES) > 0;\r
+ this.encode = (options & ENCODE) > 0;\r
+ this.bufferLength = encode ? 4 : 3;\r
+ this.buffer = new byte[ bufferLength ];\r
+ this.position = -1;\r
+ this.lineLength = 0;\r
+ this.decodabet = getDecodabet(options);\r
+ } // end constructor\r
+ \r
+ /**\r
+ * Reads enough of the input stream to convert\r
+ * to/from Base64 and returns the next byte.\r
+ *\r
+ * @return next byte\r
+ * @since 1.3\r
+ */\r
+ @Override\r
+ public int read() throws java.io.IOException {\r
+ \r
+ // Do we need to get data?\r
+ if( position < 0 ) {\r
+ if( encode ) {\r
+ byte[] b3 = new byte[3];\r
+ int numBinaryBytes = 0;\r
+ for( int i = 0; i < 3; i++ ) {\r
+ int b = in.read();\r
+\r
+ // If end of stream, b is -1.\r
+ if( b >= 0 ) {\r
+ b3[i] = (byte)b;\r
+ numBinaryBytes++;\r
+ } else {\r
+ break; // out of for loop\r
+ } // end else: end of stream\r
+ \r
+ } // end for: each needed input byte\r
+ \r
+ if( numBinaryBytes > 0 ) {\r
+ encode3to4( b3, 0, numBinaryBytes, buffer, 0, options );\r
+ position = 0;\r
+ numSigBytes = 4;\r
+ } // end if: got data\r
+ else {\r
+ return -1; // Must be end of stream\r
+ } // end else\r
+ } // end if: encoding\r
+ \r
+ // Else decoding\r
+ else {\r
+ byte[] b4 = new byte[4];\r
+ int i = 0;\r
+ for( i = 0; i < 4; i++ ) {\r
+ // Read four "meaningful" bytes:\r
+ int b = 0;\r
+ do{ b = in.read(); }\r
+ while( b >= 0 && decodabet[ b & 0x7f ] <= WHITE_SPACE_ENC );\r
+ \r
+ if( b < 0 ) {\r
+ break; // Reads a -1 if end of stream\r
+ } // end if: end of stream\r
+ \r
+ b4[i] = (byte)b;\r
+ } // end for: each needed input byte\r
+ \r
+ if( i == 4 ) {\r
+ numSigBytes = decode4to3( b4, 0, buffer, 0, options );\r
+ position = 0;\r
+ } // end if: got four characters\r
+ else if( i == 0 ){\r
+ return -1;\r
+ } // end else if: also padded correctly\r
+ else {\r
+ // Must have broken out from above.\r
+ throw new java.io.IOException( "Improperly padded Base64 input." );\r
+ } // end \r
+ \r
+ } // end else: decode\r
+ } // end else: get data\r
+ \r
+ // Got data?\r
+ if( position >= 0 ) {\r
+ // End of relevant data?\r
+ if( /*!encode &&*/ position >= numSigBytes ){\r
+ return -1;\r
+ } // end if: got data\r
+ \r
+ if( encode && breakLines && lineLength >= MAX_LINE_LENGTH ) {\r
+ lineLength = 0;\r
+ return '\n';\r
+ } // end if\r
+ else {\r
+ lineLength++; // This isn't important when decoding\r
+ // but throwing an extra "if" seems\r
+ // just as wasteful.\r
+ \r
+ int b = buffer[ position++ ];\r
+\r
+ if( position >= bufferLength ) {\r
+ position = -1;\r
+ } // end if: end\r
+\r
+ return b & 0xFF; // This is how you "cast" a byte that's\r
+ // intended to be unsigned.\r
+ } // end else\r
+ } // end if: position >= 0\r
+ \r
+ // Else error\r
+ else {\r
+ throw new java.io.IOException( "Error in Base64 code reading stream." );\r
+ } // end else\r
+ } // end read\r
+ \r
+ \r
+ /**\r
+ * Calls {@link #read()} repeatedly until the end of stream\r
+ * is reached or <var>len</var> bytes are read.\r
+ * Returns number of bytes read into array or -1 if\r
+ * end of stream is encountered.\r
+ *\r
+ * @param dest array to hold values\r
+ * @param off offset for array\r
+ * @param len max number of bytes to read into array\r
+ * @return bytes read into array or -1 if end of stream is encountered.\r
+ * @since 1.3\r
+ */\r
+ @Override\r
+ public int read( byte[] dest, int off, int len ) \r
+ throws java.io.IOException {\r
+ int i;\r
+ int b;\r
+ for( i = 0; i < len; i++ ) {\r
+ b = read();\r
+ \r
+ if( b >= 0 ) {\r
+ dest[off + i] = (byte) b;\r
+ }\r
+ else if( i == 0 ) {\r
+ return -1;\r
+ }\r
+ else {\r
+ break; // Out of 'for' loop\r
+ } // Out of 'for' loop\r
+ } // end for: each byte read\r
+ return i;\r
+ } // end read\r
+ \r
+ } // end inner class InputStream\r
+ \r
+ \r
+ \r
+ \r
+ \r
+ \r
+ /* ******** I N N E R C L A S S O U T P U T S T R E A M ******** */\r
+ \r
+ \r
+ \r
+ /**\r
+ * A {@link Base64.OutputStream} will write data to another\r
+ * <tt>java.io.OutputStream</tt>, given in the constructor,\r
+ * and encode/decode to/from Base64 notation on the fly.\r
+ *\r
+ * @see Base64\r
+ * @since 1.3\r
+ */\r
+ public static class OutputStream extends java.io.FilterOutputStream {\r
+ \r
+ private final boolean encode;\r
+ private int position;\r
+ private byte[] buffer;\r
+ private final int bufferLength;\r
+ private int lineLength;\r
+ private final boolean breakLines;\r
+ private final byte[] b4; // Scratch used in a few places\r
+ private boolean suspendEncoding;\r
+ private final int options; // Record for later\r
+ private final byte[] decodabet; // Local copies to avoid extra method calls\r
+ \r
+ /**\r
+ * Constructs a {@link Base64.OutputStream} in ENCODE mode.\r
+ *\r
+ * @param out the <tt>java.io.OutputStream</tt> to which data will be written.\r
+ * @since 1.3\r
+ */\r
+ public OutputStream( java.io.OutputStream out ) {\r
+ this( out, ENCODE );\r
+ } // end constructor\r
+ \r
+ \r
+ /**\r
+ * Constructs a {@link Base64.OutputStream} in\r
+ * either ENCODE or DECODE mode.\r
+ * <p>\r
+ * Valid options:<pre>\r
+ * ENCODE or DECODE: Encode or Decode as data is read.\r
+ * DO_BREAK_LINES: don't break lines at 76 characters\r
+ * (only meaningful when encoding)</i>\r
+ * </pre>\r
+ * <p>\r
+ * Example: <code>new Base64.OutputStream( out, Base64.ENCODE )</code>\r
+ *\r
+ * @param out the <tt>java.io.OutputStream</tt> to which data will be written.\r
+ * @param options Specified options.\r
+ * @see Base64#ENCODE\r
+ * @see Base64#DECODE\r
+ * @see Base64#DO_BREAK_LINES\r
+ * @since 1.3\r
+ */\r
+ public OutputStream( java.io.OutputStream out, int options ) {\r
+ super( out );\r
+ this.breakLines = (options & DO_BREAK_LINES) != 0;\r
+ this.encode = (options & ENCODE) != 0;\r
+ this.bufferLength = encode ? 3 : 4;\r
+ this.buffer = new byte[ bufferLength ];\r
+ this.position = 0;\r
+ this.lineLength = 0;\r
+ this.suspendEncoding = false;\r
+ this.b4 = new byte[4];\r
+ this.options = options;\r
+ this.decodabet = getDecodabet(options);\r
+ } // end constructor\r
+ \r
+ \r
+ /**\r
+ * Writes the byte to the output stream after\r
+ * converting to/from Base64 notation.\r
+ * When encoding, bytes are buffered three\r
+ * at a time before the output stream actually\r
+ * gets a write() call.\r
+ * When decoding, bytes are buffered four\r
+ * at a time.\r
+ *\r
+ * @param theByte the byte to write\r
+ * @since 1.3\r
+ */\r
+ @Override\r
+ public void write(int theByte) \r
+ throws java.io.IOException {\r
+ // Encoding suspended?\r
+ if( suspendEncoding ) {\r
+ this.out.write( theByte );\r
+ return;\r
+ } // end if: supsended\r
+ \r
+ // Encode?\r
+ if( encode ) {\r
+ buffer[ position++ ] = (byte)theByte;\r
+ if( position >= bufferLength ) { // Enough to encode.\r
+ \r
+ this.out.write( encode3to4( b4, buffer, bufferLength, options ) );\r
+\r
+ lineLength += 4;\r
+ if( breakLines && lineLength >= MAX_LINE_LENGTH ) {\r
+ this.out.write( NEW_LINE );\r
+ lineLength = 0;\r
+ } // end if: end of line\r
+\r
+ position = 0;\r
+ } // end if: enough to output\r
+ } // end if: encoding\r
+\r
+ // Else, Decoding\r
+ else {\r
+ // Meaningful Base64 character?\r
+ if( decodabet[ theByte & 0x7f ] > WHITE_SPACE_ENC ) {\r
+ buffer[ position++ ] = (byte)theByte;\r
+ if( position >= bufferLength ) { // Enough to output.\r
+ \r
+ int len = Base64.decode4to3( buffer, 0, b4, 0, options );\r
+ out.write( b4, 0, len );\r
+ position = 0;\r
+ } // end if: enough to output\r
+ } // end if: meaningful base64 character\r
+ else if( decodabet[ theByte & 0x7f ] != WHITE_SPACE_ENC ) {\r
+ throw new java.io.IOException( "Invalid character in Base64 data." );\r
+ } // end else: not white space either\r
+ } // end else: decoding\r
+ } // end write\r
+ \r
+ \r
+ \r
+ /**\r
+ * Calls {@link #write(int)} repeatedly until <var>len</var> \r
+ * bytes are written.\r
+ *\r
+ * @param theBytes array from which to read bytes\r
+ * @param off offset for array\r
+ * @param len max number of bytes to read into array\r
+ * @since 1.3\r
+ */\r
+ @Override\r
+ public void write( byte[] theBytes, int off, int len ) \r
+ throws java.io.IOException {\r
+ // Encoding suspended?\r
+ if( suspendEncoding ) {\r
+ this.out.write( theBytes, off, len );\r
+ return;\r
+ } // end if: supsended\r
+ \r
+ for( int i = 0; i < len; i++ ) {\r
+ write( theBytes[ off + i ] );\r
+ } // end for: each byte written\r
+ \r
+ } // end write\r
+ \r
+ \r
+ \r
+ /**\r
+ * Method added by PHIL. [Thanks, PHIL. -Rob]\r
+ * This pads the buffer without closing the stream.\r
+ * @throws java.io.IOException if there's an error.\r
+ */\r
+ public void flushBase64() throws java.io.IOException {\r
+ if( position > 0 ) {\r
+ if( encode ) {\r
+ out.write( encode3to4( b4, buffer, position, options ) );\r
+ position = 0;\r
+ } // end if: encoding\r
+ else {\r
+ throw new java.io.IOException( "Base64 input not properly padded." );\r
+ } // end else: decoding\r
+ } // end if: buffer partially full\r
+\r
+ } // end flush\r
+\r
+ \r
+ /** \r
+ * Flushes and closes (I think, in the superclass) the stream. \r
+ *\r
+ * @since 1.3\r
+ */\r
+ @Override\r
+ public void close() throws java.io.IOException {\r
+ // 1. Ensure that pending characters are written\r
+ flushBase64();\r
+\r
+ // 2. Actually close the stream\r
+ // Base class both flushes and closes.\r
+ super.close();\r
+ \r
+ buffer = null;\r
+ out = null;\r
+ } // end close\r
+ \r
+ \r
+ \r
+ /**\r
+ * Suspends encoding of the stream.\r
+ * May be helpful if you need to embed a piece of\r
+ * base64-encoded data in a stream.\r
+ *\r
+ * @throws java.io.IOException if there's an error flushing\r
+ * @since 1.5.1\r
+ */\r
+ public void suspendEncoding() throws java.io.IOException {\r
+ flushBase64();\r
+ this.suspendEncoding = true;\r
+ } // end suspendEncoding\r
+ \r
+ \r
+ /**\r
+ * Resumes encoding of the stream.\r
+ * May be helpful if you need to embed a piece of\r
+ * base64-encoded data in a stream.\r
+ *\r
+ * @since 1.5.1\r
+ */\r
+ public void resumeEncoding() {\r
+ this.suspendEncoding = false;\r
+ } // end resumeEncoding\r
+ \r
+ \r
+ \r
+ } // end inner class OutputStream\r
+ \r
+ \r
+} // end class Base64\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.utilities;\r
+\r
+import java.io.File;\r
+import java.security.MessageDigest;\r
+import java.security.NoSuchAlgorithmException;\r
+import java.util.ArrayList;\r
+import java.util.Calendar;\r
+import java.util.GregorianCalendar;\r
+\r
+import com.evernote.edam.type.Data;\r
+import com.evernote.edam.type.Note;\r
+import com.evernote.edam.type.NoteAttributes;\r
+import com.evernote.edam.type.Resource;\r
+import com.evernote.edam.type.ResourceAttributes;\r
+import com.trolltech.qt.core.QByteArray;\r
+import com.trolltech.qt.core.QFile;\r
+import com.trolltech.qt.core.QFileInfo;\r
+import com.trolltech.qt.core.QIODevice;\r
+import com.trolltech.qt.webkit.QWebPage;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.sql.DatabaseConnection;\r
+\r
+\r
+\r
+public class FileImporter {\r
+\r
+ private final ApplicationLogger logger;\r
+ private String fileName;\r
+ private String content;\r
+ private QFileInfo fileInfo;\r
+ private Note newNote;\r
+ private String noteString;\r
+ private final DatabaseConnection conn;\r
+ \r
+ \r
+ public FileImporter(ApplicationLogger l, DatabaseConnection c) {\r
+ logger = l;\r
+ conn = c;\r
+ }\r
+ \r
+ \r
+ //********************************************************\r
+ //* Begin to import the file\r
+ //********************************************************\r
+ public boolean importFile() {\r
+ if (fileInfo.isFile()) {\r
+ if (!validAttachment(fileInfo.completeSuffix()))\r
+ return false;\r
+ if (fileInfo.completeSuffix().equalsIgnoreCase("txt"))\r
+ return importTextFile();\r
+ return importAttachment();\r
+ }\r
+ return false;\r
+ }\r
+ \r
+ //********************************************************\r
+ //* Import text files \r
+ //********************************************************\r
+ public boolean importTextFile() {\r
+ QFile file = new QFile(fileName);\r
+ if (!file.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly))) {\r
+ // If we can't get to the file, it is probably locked. We'll try again later.\r
+ logger.log(logger.LOW, "Unable to save externally edited file - locked. Saving for later.");\r
+ return false;\r
+ }\r
+ QByteArray binData = file.readAll();\r
+ file.close();\r
+ if (binData.size() == 0) {\r
+ // If we can't get to the file, it is probably locked. We'll try again later.\r
+ logger.log(logger.LOW, "Unable to save externally edited file - zero size. Saving for later.");\r
+ return false;\r
+ }\r
+ \r
+ String fileData =binData.toString();\r
+ \r
+ // Fix \r\n & \n and turn inte HTML\r
+ QWebPage page = new QWebPage();\r
+ page.mainFrame().setContent(binData);\r
+ fileData = page.mainFrame().toHtml();\r
+ fileData = fileData.replace("\n", "<br>\n");\r
+\r
+ noteString = new String("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +\r
+ "<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">\n" +\r
+ "<en-note>\n<br clear=\"none\" />"+fileData+"</en-note>");\r
+\r
+ noteString = fileData;\r
+ buildEmptyNote();\r
+ newNote.setAttributes(new NoteAttributes());\r
+ \r
+ return true;\r
+ }\r
+\r
+ //********************************************************\r
+ //* Import an image\r
+ //********************************************************\r
+ public boolean importAttachment() {\r
+ QFile file = new QFile(fileName);\r
+ if (!file.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly))) {\r
+ // If we can't get to the file, it is probably locked. We'll try again later.\r
+ logger.log(logger.LOW, "Unable to save externally edited file - locked. Saving for later.");\r
+ return false;\r
+ }\r
+ QByteArray binData = file.readAll();\r
+ file.close();\r
+ if (binData.size() == 0) {\r
+ // If we can't get to the file, it is probably locked. We'll try again later.\r
+ logger.log(logger.LOW, "Unable to save externally edited file - zero size. Saving for later.");\r
+ return false;\r
+ }\r
+ \r
+ buildEmptyNote();\r
+ newNote.setAttributes(new NoteAttributes());\r
+ \r
+ // Start building the resource itself\r
+ StringBuffer buffer = new StringBuffer();\r
+ buffer.append("<html><head></head><body>\n");\r
+ \r
+ Resource newRes;\r
+ \r
+ // If we have an image\r
+ if (isImage(fileInfo.completeSuffix())) {\r
+ String mimeType = "image/" +fileInfo.completeSuffix();\r
+ if (mimeType.equals("image/jpg"))\r
+ mimeType = "image/jpeg";\r
+ newRes = createResource(mimeType, false);\r
+ \r
+ buffer.append("<img src=\"" +fileName);\r
+ buffer.append("\" en-tag=\"en-media\" type=\"" + mimeType +"\""\r
+ +" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""\r
+ +" guid=\"" +newRes.getGuid() +"\">");\r
+ } else {\r
+ // We have an attachment, not an image.\r
+ \r
+ \r
+ String mimeType = "application/" +fileInfo.completeSuffix();\r
+ newRes = createResource(mimeType, false);\r
+ newRes.getAttributes().setFileName(fileInfo.fileName());\r
+ \r
+ String icon = findIcon(fileInfo.completeSuffix());\r
+ StringBuffer imageBuffer = new StringBuffer();\r
+ String whichOS = System.getProperty("os.name");\r
+ if (whichOS.contains("Windows")) \r
+ imageBuffer.append("file:///" + Global.getDirectoryPath()\r
+ + "images/" + icon);\r
+ else\r
+ imageBuffer.append("file://" + Global.getDirectoryPath()\r
+ + "images/" + icon);\r
+ // Fix stupid Windows file separation characters\r
+ if (whichOS.contains("Windows")) {\r
+ for (int z = imageBuffer.indexOf("\\"); z > 0; \r
+ z = imageBuffer.indexOf("\\")) {\r
+ int w = imageBuffer.indexOf("\\");\r
+ imageBuffer.replace(w, w + 1, "/");\r
+ }\r
+\r
+ }\r
+ buffer.append("<a en-tag=\"en-media\" guid=\"" +newRes.getGuid()+"\" ");\r
+ buffer.append("type=\"" + mimeType + "\" href=\"nnres://" + fileName +"\" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\" >");\r
+ buffer.append("<img src=\"" + imageBuffer.toString()+"\" title=\"" +newRes.getAttributes().getFileName());\r
+ buffer.append("\">");\r
+ buffer.append("</a>");\r
+ }\r
+ buffer.append("</body></html>");\r
+ \r
+ content = buffer.toString();\r
+ noteString = buffer.toString();\r
+ newNote.setContent(content);\r
+ newNote.setResources(new ArrayList<Resource>());\r
+ newNote.getResources().add(newRes);\r
+ newNote.setResourcesIsSet(true);\r
+ \r
+ return true;\r
+ }\r
+ \r
+ //********************************************************\r
+ //* Check if we found a valid file type\r
+ //********************************************************\r
+ // Check if the account supports this type of attachment\r
+ private boolean validAttachment(String type) {\r
+ if (Global.isPremium())\r
+ return true;\r
+ if (type.equalsIgnoreCase("JPG"))\r
+ return true;\r
+ if (type.equalsIgnoreCase("PNG"))\r
+ return true;\r
+ if (type.equalsIgnoreCase("GIF"))\r
+ return true;\r
+ if (type.equalsIgnoreCase("MP3"))\r
+ return true;\r
+ if (type.equalsIgnoreCase("WAV"))\r
+ return true;\r
+ if (type.equalsIgnoreCase("AMR"))\r
+ return true;\r
+ if (type.equalsIgnoreCase("PDF"))\r
+ return true;\r
+ if (type.equalsIgnoreCase("TXT"))\r
+ return true;\r
+ return false;\r
+ }\r
+ \r
+ //********************************************************\r
+ //* Check if we found an image\r
+ //********************************************************\r
+ // Check if the account supports this type of attachment\r
+ private boolean isImage(String type) {\r
+ if (type.equalsIgnoreCase("JPG"))\r
+ return true;\r
+ if (type.equalsIgnoreCase("JPEG"))\r
+ return true;\r
+ if (type.equalsIgnoreCase("PNG"))\r
+ return true;\r
+ if (type.equalsIgnoreCase("GIF"))\r
+ return true;\r
+ if (!Global.isPremium()) \r
+ return false;\r
+ if (type.equalsIgnoreCase("XPM"))\r
+ return true;\r
+ if (type.equalsIgnoreCase("BMP"))\r
+ return true;\r
+\r
+ return false;\r
+ }\r
+\r
+ //********************************************************\r
+ //* Build an empty note\r
+ //********************************************************\r
+ private void buildEmptyNote() {\r
+ Calendar currentTime = new GregorianCalendar();\r
+ String baseNote = new String("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +\r
+ "<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">\n" +\r
+ "<en-note>\n<br clear=\"none\" /></en-note>");\r
+ Long l = new Long(currentTime.getTimeInMillis());\r
+ long prevTime = l;\r
+ while (prevTime==l) {\r
+ currentTime = new GregorianCalendar();\r
+ l=currentTime.getTimeInMillis();\r
+ }\r
+ \r
+ String randint = new String(Long.toString(l));\r
+ \r
+ newNote = new Note();\r
+ newNote.setUpdateSequenceNum(0);\r
+ newNote.setGuid(randint);\r
+ newNote.setTitle(fileName);\r
+ newNote.setContent(baseNote);\r
+ newNote.setDeleted(0);\r
+ int cdate = fileInfo.created().toTime_t();\r
+ int mdate = fileInfo.lastModified().toTime_t();\r
+ newNote.setCreated((long)cdate*1000);\r
+ newNote.setUpdated((long)mdate*1000);\r
+ newNote.setActive(true);\r
+ NoteAttributes na = new NoteAttributes();\r
+ na.setLatitude(0.0);\r
+ na.setLongitude(0.0);\r
+ na.setAltitude(0.0);\r
+ }\r
+ //********************************************************\r
+ //* Check valid file types\r
+ //********************************************************\r
+ public boolean isValidType() {\r
+ if (!checkFileAttachmentSize(fileName))\r
+ return false;\r
+ if (fileInfo.completeSuffix().equalsIgnoreCase("txt"))\r
+ return true;\r
+ if (validAttachment(fileInfo.completeSuffix()))\r
+ return true;\r
+ return false;\r
+ }\r
+ //**************************************************************\r
+ //* Check the file attachment to be sure it isn't over 25 mb\r
+ //**************************************************************\r
+ private boolean checkFileAttachmentSize(String url) {\r
+ QFile resourceFile = new QFile(fileName);\r
+ resourceFile.open(new QIODevice.OpenMode(\r
+ QIODevice.OpenModeFlag.ReadOnly));\r
+ long size = resourceFile.size();\r
+ resourceFile.close();\r
+ size = size / 1024 / 1024;\r
+ if (size < 50 && Global.isPremium())\r
+ return true;\r
+ if (size < 25)\r
+ return true;\r
+ return false;\r
+ }\r
+\r
+ //********************************************************\r
+ //* Build a new resource\r
+ //********************************************************\r
+ private Resource createResource(String mime, boolean attachment) {\r
+ QFile resourceFile;\r
+ resourceFile = new QFile(fileName); \r
+ resourceFile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly));\r
+ byte[] fileData = resourceFile.readAll().toByteArray();\r
+ resourceFile.close();\r
+ if (fileData.length == 0)\r
+ return null;\r
+ MessageDigest md;\r
+ try {\r
+ md = MessageDigest.getInstance("MD5");\r
+ md.update(fileData);\r
+ byte[] hash = md.digest();\r
+ \r
+ Resource r = new Resource();\r
+ Calendar time = new GregorianCalendar();\r
+ Long l = time.getTimeInMillis();\r
+ long prevTime = l;\r
+ while (l==prevTime) {\r
+ time = new GregorianCalendar();\r
+ l=time.getTimeInMillis();\r
+ }\r
+ r.setGuid(new Long(l).toString());\r
+ r.setNoteGuid(newNote.getGuid());\r
+ r.setMime(mime);\r
+ r.setActive(true);\r
+ r.setUpdateSequenceNum(0);\r
+ r.setWidth((short) 0);\r
+ r.setHeight((short) 0);\r
+ r.setDuration((short) 0);\r
+ \r
+ Data d = new Data();\r
+ d.setBody(fileData);\r
+ d.setBodyIsSet(true);\r
+ d.setBodyHash(hash);\r
+ d.setBodyHashIsSet(true);\r
+ r.setData(d);\r
+ d.setSize(fileData.length);\r
+ \r
+ ResourceAttributes a = new ResourceAttributes();\r
+ a.setAltitude(0);\r
+ a.setAltitudeIsSet(false);\r
+ a.setLongitude(0);\r
+ a.setLongitudeIsSet(false);\r
+ a.setLatitude(0);\r
+ a.setLatitudeIsSet(false);\r
+ a.setCameraMake("");\r
+ a.setCameraMakeIsSet(false);\r
+ a.setCameraModel("");\r
+ a.setCameraModelIsSet(false);\r
+ a.setAttachment(attachment);\r
+ a.setAttachmentIsSet(true);\r
+ a.setClientWillIndex(false);\r
+ a.setClientWillIndexIsSet(true);\r
+ a.setRecoType("");\r
+ a.setRecoTypeIsSet(false);\r
+ a.setSourceURLIsSet(false);\r
+ a.setTimestamp(0);\r
+ a.setTimestampIsSet(false);\r
+ a.setFileName(fileInfo.fileName());\r
+ a.setFileNameIsSet(true);\r
+ r.setAttributes(a);\r
+ \r
+ conn.getNoteTable().noteResourceTable.saveNoteResource(r, true);\r
+ return r;\r
+ } catch (NoSuchAlgorithmException e1) {\r
+ e1.printStackTrace();\r
+ }\r
+ return null;\r
+ }\r
+ \r
+ //********************************************************\r
+ //* set file name\r
+ //********************************************************\r
+ public void setFileInfo(QFileInfo f) {\r
+ fileInfo = f; \r
+ }\r
+ //********************************************************\r
+ //* Set file name\r
+ //********************************************************\r
+ public void setFileName(String f) {\r
+ fileName = f;\r
+ }\r
+ //********************************************************\r
+ //* Get file contents\r
+ //********************************************************\r
+ public String getContent() {\r
+ return content;\r
+ }\r
+ //********************************************************\r
+ //* Return the new note\r
+ //********************************************************\r
+ public Note getNote() {\r
+ return newNote;\r
+ }\r
+ //********************************************************\r
+ //* Get just the content of the new note\r
+ //********************************************************\r
+ public String getNoteContent() {\r
+ return noteString;\r
+ }\r
+ //********************************************************\r
+ //* Find an icon for an attachment\r
+ //********************************************************\r
+ // find the appropriate icon for an attachment\r
+ private String findIcon(String appl) {\r
+ appl = appl.toLowerCase();\r
+ File f = new File(Global.getDirectoryPath()+"images"+File.separator +appl +".png");\r
+ if (f.exists())\r
+ return appl+".png";\r
+ return "attachment.png";\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.utilities;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Calendar;\r
+import java.util.Collections;\r
+import java.util.Comparator;\r
+import java.util.GregorianCalendar;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Vector;\r
+\r
+import com.evernote.edam.type.Note;\r
+import com.evernote.edam.type.Notebook;\r
+import com.evernote.edam.type.SavedSearch;\r
+import com.evernote.edam.type.Tag;\r
+import com.trolltech.qt.QThread;\r
+import com.trolltech.qt.core.QDateTime;\r
+import com.trolltech.qt.sql.QSqlQuery;\r
+import com.trolltech.qt.xml.QDomAttr;\r
+import com.trolltech.qt.xml.QDomDocument;\r
+import com.trolltech.qt.xml.QDomElement;\r
+import com.trolltech.qt.xml.QDomNodeList;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.filters.EnSearch;\r
+import cx.fbn.nevernote.filters.NotebookCounter;\r
+import cx.fbn.nevernote.filters.TagCounter;\r
+import cx.fbn.nevernote.signals.NotebookSignal;\r
+import cx.fbn.nevernote.signals.StatusSignal;\r
+import cx.fbn.nevernote.signals.TagSignal;\r
+import cx.fbn.nevernote.signals.ThreadSignal;\r
+import cx.fbn.nevernote.signals.TrashSignal;\r
+import cx.fbn.nevernote.sql.DatabaseConnection;\r
+import cx.fbn.nevernote.sql.runners.NoteTagsRecord;\r
+import cx.fbn.nevernote.threads.CounterRunner;\r
+import cx.fbn.nevernote.threads.SaveRunner;\r
+\r
+\r
+public class ListManager {\r
+\r
+ \r
+ private final ApplicationLogger logger; \r
+ DatabaseConnection conn;\r
+ QSqlQuery deleteWords;\r
+ QSqlQuery insertWords;\r
+ \r
+ private List<Tag> tagIndex;\r
+ private List<Notebook> notebookIndex;\r
+ private List<Notebook> archiveNotebookIndex;\r
+ private List<String> localNotebookIndex;\r
+ private List<Note> noteIndex;\r
+ private List<SavedSearch> searchIndex;\r
+\r
+ private List<String> selectedNotebooks;\r
+ \r
+ private List<Note> masterNoteIndex;\r
+ private List<String> unsynchronizedNotes;\r
+ private List<String> selectedTags;\r
+ private String selectedSearch;\r
+ ThreadSignal signals;\r
+ public StatusSignal status;\r
+ private final CounterRunner notebookCounterRunner;\r
+ private final QThread notebookThread;\r
+ private final CounterRunner tagCounterRunner;\r
+ private final QThread tagThread;\r
+ \r
+ private final CounterRunner trashCounterRunner;\r
+ private final QThread trashThread;\r
+ public TrashSignal trashSignal;\r
+ public HashMap<String,Integer> titleColors;\r
+ \r
+ private List<NotebookCounter> notebookCounter; // count of displayed notes in each notebook\r
+ private List<TagCounter> tagCounter; // count of displayed notes for each tag\r
+ \r
+ private EnSearch enSearch;\r
+ private boolean enSearchChanged;\r
+ public HashMap<String, String> wordMap;\r
+ public TagSignal tagSignal;\r
+ public NotebookSignal notebookSignal;\r
+ private int trashCount;\r
+ private final int id;\r
+ SaveRunner saveRunner; // Thread used to save content. Used because the xml conversion is slowwwww\r
+ QThread saveThread;\r
+ \r
+ // Constructor\r
+ public ListManager(DatabaseConnection d, ApplicationLogger l, int instance_id) {\r
+ conn = d;\r
+ logger = l;\r
+ id = instance_id;\r
+ \r
+ status = new StatusSignal();\r
+ signals = new ThreadSignal();\r
+ \r
+ // setup index locks\r
+ enSearchChanged = false;\r
+ \r
+ // Setup arrays\r
+ masterNoteIndex = null;\r
+ selectedTags = new ArrayList<String>();\r
+\r
+ notebookCounter = new ArrayList<NotebookCounter>();\r
+ tagCounter = new ArrayList<TagCounter>();\r
+ selectedNotebooks = new ArrayList<String>();\r
+ unsynchronizedNotes = new ArrayList<String>();\r
+ \r
+ reloadIndexes();\r
+ \r
+ notebookSignal = new NotebookSignal();\r
+ notebookCounterRunner = new CounterRunner("notebook_counter.log", CounterRunner.NOTEBOOK);\r
+ notebookCounterRunner.setNoteIndex(getNoteIndex());\r
+ notebookCounterRunner.notebookSignal.countsChanged.connect(this, "setNotebookCounter(List)");\r
+ notebookThread = new QThread(notebookCounterRunner, "Notebook Counter Thread");\r
+ notebookThread.start();\r
+ \r
+ tagSignal = new TagSignal();\r
+ tagCounterRunner = new CounterRunner("tag_counter.log", CounterRunner.TAG);\r
+ tagCounterRunner.setNoteIndex(getNoteIndex());\r
+ tagCounterRunner.tagSignal.countsChanged.connect(this, "setTagCounter(List)");\r
+ tagThread = new QThread(tagCounterRunner, "Tag Counter Thread");\r
+ tagThread.start();\r
+ \r
+ trashSignal = new TrashSignal();\r
+ trashCounterRunner = new CounterRunner("trash_counter.log", CounterRunner.TRASH);\r
+ trashCounterRunner.trashSignal.countChanged.connect(this, "trashSignalReceiver(Integer)");\r
+ trashThread = new QThread(trashCounterRunner, "Trash Counter Thread");\r
+ trashThread.start();\r
+ reloadTrashCount();\r
+ \r
+ wordMap = new HashMap<String, String>();\r
+ tagSignal = new TagSignal();\r
+ \r
+ logger.log(logger.EXTREME, "Setting save thread");\r
+ saveRunner = new SaveRunner("saveRunner.log");\r
+ saveThread = new QThread(saveRunner, "Save Runner Thread");\r
+ saveThread.start();\r
+\r
+ loadNoteTitleColors();\r
+ \r
+ }\r
+ \r
+ public void stop() {\r
+ saveRunner.addWork("stop", "");\r
+ tagCounterRunner.release(CounterRunner.EXIT);\r
+ notebookCounterRunner.release(CounterRunner.EXIT);\r
+ trashCounterRunner.release(CounterRunner.EXIT);\r
+ \r
+ logger.log(logger.MEDIUM, "Waiting for notebookCounterThread to stop"); \r
+ try {\r
+ notebookThread.join();\r
+ } catch (InterruptedException e) {\r
+ e.printStackTrace();\r
+ }\r
+ \r
+ logger.log(logger.MEDIUM, "Waiting for tagCounterThread to stop"); \r
+ try {\r
+ tagThread.join();\r
+ } catch (InterruptedException e) {\r
+ e.printStackTrace();\r
+ }\r
+\r
+ logger.log(logger.MEDIUM, "Waiting for trashThread to stop"); \r
+ try {\r
+ trashThread.join();\r
+ } catch (InterruptedException e) {\r
+ e.printStackTrace();\r
+ }\r
+\r
+\r
+ logger.log(logger.MEDIUM, "Waiting for saveThread to stop"); \r
+ try {\r
+ saveThread.join(0);\r
+ } catch (InterruptedException e) {\r
+ e.printStackTrace();\r
+ }\r
+\r
+\r
+ }\r
+\r
+ //***************************************************************\r
+ //***************************************************************\r
+ //* Refresh lists after a db sync\r
+ //***************************************************************\r
+ //***************************************************************\r
+ public void refreshLists(Note n, boolean dirty, String content) {\r
+ if (dirty) {\r
+// conn.getNoteTable().updateNoteContent(n.getGuid(), n.getContent());\r
+ saveRunner.addWork(n.getGuid(), content);\r
+ conn.getNoteTable().updateNoteTitle(n.getGuid(), n.getTitle());\r
+ }\r
+ \r
+ setSavedSearchIndex(conn.getSavedSearchTable().getAll());\r
+ setTagIndex(conn.getTagTable().getAll());\r
+ setNotebookIndex(conn.getNotebookTable().getAll());\r
+ \r
+ List<Notebook> local = conn.getNotebookTable().getAllLocal();\r
+ localNotebookIndex = new ArrayList<String>();\r
+ for (int i=0; i<local.size(); i++)\r
+ localNotebookIndex.add(local.get(i).getGuid());\r
+ \r
+ masterNoteIndex = conn.getNoteTable().getAllNotes();\r
+ // For performance reasons, we didn't get the tags for every note individually. We now need to \r
+ // get them\r
+ List<NoteTagsRecord> noteTags = conn.getNoteTable().noteTagsTable.getAllNoteTags();\r
+ for (int i=0; i<masterNoteIndex.size(); i++) {\r
+ List<String> tags = new ArrayList<String>();\r
+ List<String> names = new ArrayList<String>();\r
+ for (int j=0; j<noteTags.size(); j++) {\r
+ if (masterNoteIndex.get(i).getGuid().equals(noteTags.get(j).noteGuid)) {\r
+ tags.add(noteTags.get(j).tagGuid);\r
+ names.add(getTagNameByGuid(noteTags.get(j).tagGuid));\r
+ }\r
+ }\r
+ \r
+ masterNoteIndex.get(i).setTagGuids(tags);\r
+ masterNoteIndex.get(i).setTagNames(names);\r
+ }\r
+ \r
+ \r
+ setUnsynchronizedNotes(conn.getNoteTable().getUnsynchronizedGUIDs());\r
+ \r
+ enSearchChanged = true;\r
+ }\r
+\r
+ public void reloadIndexes() {\r
+ setUnsynchronizedNotes(conn.getNoteTable().getUnsynchronizedGUIDs());\r
+\r
+ List<Notebook> local = conn.getNotebookTable().getAllLocal();\r
+ localNotebookIndex = new ArrayList<String>();\r
+ for (int i=0; i<local.size(); i++)\r
+ localNotebookIndex.add(local.get(i).getGuid());\r
+ \r
+ // Load tags\r
+ setTagIndex(conn.getTagTable().getAll());\r
+ // Load notebooks\r
+ setNotebookIndex(conn.getNotebookTable().getAll());\r
+ // load archived notebooks (if note using the EN interface)\r
+ setArchiveNotebookIndex(conn.getNotebookTable().getAllArchived());\r
+ // load saved search index\r
+ setSavedSearchIndex(conn.getSavedSearchTable().getAll());\r
+ // Load search helper utility\r
+ enSearch = new EnSearch(id, "", getTagIndex(), Global.getMinimumWordLength(), Global.getRecognitionWeight());\r
+ logger.log(logger.HIGH, "Building note index");\r
+\r
+ if (masterNoteIndex == null) { \r
+ masterNoteIndex = conn.getNoteTable().getAllNotes();\r
+ }\r
+ // For performance reasons, we didn't get the tags for every note individually. We now need to \r
+ // get them\r
+ List<NoteTagsRecord> noteTags = conn.getNoteTable().noteTagsTable.getAllNoteTags();\r
+ for (int i=0; i<masterNoteIndex.size(); i++) {\r
+ List<String> tags = new ArrayList<String>();\r
+ List<String> names = new ArrayList<String>();\r
+ for (int j=0; j<noteTags.size(); j++) {\r
+ if (masterNoteIndex.get(i).getGuid().equals(noteTags.get(j).noteGuid)) {\r
+ tags.add(noteTags.get(j).tagGuid);\r
+ names.add(getTagNameByGuid(noteTags.get(j).tagGuid));\r
+ }\r
+ }\r
+ \r
+ masterNoteIndex.get(i).setTagGuids(tags);\r
+ masterNoteIndex.get(i).setTagNames(names);\r
+ }\r
+ \r
+ setNoteIndex(masterNoteIndex);\r
+\r
+ }\r
+ \r
+ //***************************************************************\r
+ //***************************************************************\r
+ //* selected notebooks\r
+ //***************************************************************\r
+ //***************************************************************\r
+ // Return the selected notebook(s)\r
+ public List<String> getSelectedNotebooks() {\r
+ return selectedNotebooks;\r
+ }\r
+ // Set the current selected notebook(s)\r
+ public void setSelectedNotebooks(List <String> s) {\r
+ if (s == null) \r
+ s = new ArrayList<String>();\r
+ selectedNotebooks = s;\r
+ }\r
+ \r
+ \r
+ //***************************************************************\r
+ //***************************************************************\r
+ //** These functions deal with setting & retrieving the master lists\r
+ //***************************************************************\r
+ //***************************************************************\r
+ // save the saved search index\r
+ private void setSavedSearchIndex(List<SavedSearch> t) {\r
+ searchIndex = t;\r
+ }\r
+ // Retrieve the Tag index\r
+ public List<SavedSearch> getSavedSearchIndex() {\r
+ return searchIndex;\r
+\r
+ }\r
+ // save the tag index\r
+ private void setTagIndex(List<Tag> t) {\r
+ tagIndex = t;\r
+ } \r
+ // Retrieve the Tag index\r
+ public List<Tag> getTagIndex() {\r
+ return tagIndex;\r
+ }\r
+ private void setNotebookIndex(List<Notebook> t) {\r
+ notebookIndex = t;\r
+ }\r
+ private void setArchiveNotebookIndex(List<Notebook> t) {\r
+ archiveNotebookIndex = t;\r
+ }\r
+ // Retrieve the Notebook index\r
+ public List<Notebook> getNotebookIndex() {\r
+ return notebookIndex;\r
+\r
+ }\r
+ public List<Notebook> getArchiveNotebookIndex() {\r
+ return archiveNotebookIndex;\r
+ }\r
+ // Save the current note list\r
+ private void setNoteIndex(List<Note> n) {\r
+ noteIndex = n;\r
+ }\r
+ // Get the note index\r
+ public synchronized List<Note> getNoteIndex() {\r
+ return noteIndex;\r
+ }\r
+ // Save the count of notes per notebook\r
+ public void setNotebookCounter(List<NotebookCounter> n) {\r
+ notebookCounter = n;\r
+ notebookSignal.refreshNotebookTreeCounts.emit(getNotebookIndex(), notebookCounter);\r
+ }\r
+ public List<NotebookCounter> getNotebookCounter() {\r
+ return notebookCounter;\r
+ }\r
+ // Save the count of notes for each tag\r
+ public void setTagCounter(List<TagCounter> n) {\r
+ tagCounter = n;\r
+ tagSignal.refreshTagTreeCounts.emit(tagCounter);\r
+ }\r
+ public List<TagCounter> getTagCounter() {\r
+ return tagCounter;\r
+ }\r
+ public List<String> getLocalNotebooks() {\r
+ return localNotebookIndex;\r
+ }\r
+ // Unsynchronized Note List\r
+ public List<String> getUnsynchronizedNotes() {\r
+ return unsynchronizedNotes;\r
+ }\r
+ public void setUnsynchronizedNotes(List<String> l) {\r
+ unsynchronizedNotes = l;\r
+ }\r
+ // Return a count of items in the trash\r
+ public int getTrashCount() {\r
+ return trashCount;\r
+ }\r
+ // get the EnSearch variable\r
+ public EnSearch getEnSearch() {\r
+ return enSearch;\r
+ }\r
+ public List<Note> getMasterNoteIndex() {\r
+ return masterNoteIndex;\r
+ }\r
+ \r
+ //***************************************************************\r
+ //***************************************************************\r
+ //** These functions deal with setting & retrieving filters\r
+ //***************************************************************\r
+ //***************************************************************\r
+ public void setEnSearch(String t) {\r
+ enSearch = new EnSearch(id, t, getTagIndex(), Global.getMinimumWordLength(), Global.getRecognitionWeight());\r
+ enSearchChanged = true;\r
+ }\r
+ // Save search tags\r
+ public void setSelectedTags(List<String> selectedTags) {\r
+ this.selectedTags = selectedTags;\r
+ }\r
+ // Save seleceted search\r
+ public void setSelectedSavedSearch(String s) {\r
+ this.selectedSearch = s;\r
+ }\r
+ // Get search tags\r
+ public List<String> getSelectedTags() {\r
+ return selectedTags;\r
+ }\r
+ // Get saved search\r
+ public String getSelectedSearch() {\r
+ return selectedSearch;\r
+ }\r
+ \r
+ \r
+ \r
+ \r
+ //***************************************************************\r
+ //***************************************************************\r
+ //** Note functions\r
+ //***************************************************************\r
+ //***************************************************************\r
+ // Save Note Tags\r
+ public void saveNoteTags(String noteGuid, List<String> tags) {\r
+ logger.log(logger.HIGH, "Entering ListManager.saveNoteTags");\r
+ String tagName;\r
+ conn.getNoteTable().noteTagsTable.deleteNoteTag(noteGuid);\r
+ List<String> tagGuids = new ArrayList<String>();\r
+ boolean newTagCreated = false;\r
+ \r
+ for (int i=0; i<tags.size(); i++) {\r
+ tagName = tags.get(i);\r
+ boolean found = false;\r
+ for (int j=0; j<tagIndex.size(); j++) {\r
+ if (tagIndex.get(j).getName().equalsIgnoreCase(tagName)) {\r
+ conn.getNoteTable().noteTagsTable.saveNoteTag(noteGuid, tagIndex.get(j).getGuid());\r
+ tagGuids.add(tagIndex.get(j).getGuid());\r
+ j=tagIndex.size()+1;\r
+ found = true;\r
+ }\r
+ }\r
+ if (!found) {\r
+ Tag nTag = new Tag();\r
+ nTag.setName(tagName);\r
+ Calendar currentTime = new GregorianCalendar();\r
+ Long l = new Long(currentTime.getTimeInMillis());\r
+ long prevTime = l;\r
+ while (l==prevTime) {\r
+ currentTime = new GregorianCalendar();\r
+ l=currentTime.getTimeInMillis();\r
+ }\r
+ String randint = new String(Long.toString(l));\r
+ \r
+ nTag.setUpdateSequenceNum(0);\r
+ nTag.setGuid(randint);\r
+ conn.getTagTable().addTag(nTag, true);\r
+ getTagIndex().add(nTag);\r
+ conn.getNoteTable().noteTagsTable.saveNoteTag(noteGuid, nTag.getGuid());\r
+ tagGuids.add(nTag.getGuid());\r
+ newTagCreated = true;\r
+ }\r
+ }\r
+ \r
+ for (int i=0; i<noteIndex.size(); i++) {\r
+ if (noteIndex.get(i).getGuid().equals(noteGuid)) {\r
+ noteIndex.get(i).setTagNames(tags);\r
+ noteIndex.get(i).setTagGuids(tagGuids);\r
+ i=noteIndex.size()+1;\r
+ }\r
+ }\r
+ if (newTagCreated)\r
+ tagSignal.listChanged.emit();\r
+ logger.log(logger.HIGH, "Leaving ListManager.saveNoteTags");\r
+ }\r
+ // Delete a note\r
+ public void deleteNote(String guid) {\r
+ trashCounterRunner.abortCount = true;\r
+ Calendar currentTime = new GregorianCalendar();\r
+ Long l = new Long(currentTime.getTimeInMillis());\r
+ long prevTime = l;\r
+ while (l==prevTime) {\r
+ currentTime = new GregorianCalendar();\r
+ l=currentTime.getTimeInMillis();\r
+ }\r
+ \r
+ for (int i=0; i<masterNoteIndex.size(); i++) {\r
+ if (masterNoteIndex.get(i).getGuid().equals(guid)) {\r
+ masterNoteIndex.get(i).setActive(false);\r
+ masterNoteIndex.get(i).setDeleted(l);\r
+ i=masterNoteIndex.size();\r
+ }\r
+ }\r
+ for (int i=0; i<getNoteIndex().size(); i++) {\r
+ if (getNoteIndex().get(i).getGuid().equals(guid)) {\r
+ getNoteIndex().get(i).setActive(false);\r
+ getNoteIndex().get(i).setDeleted(l);\r
+ i=getNoteIndex().size();\r
+ }\r
+ }\r
+ conn.getNoteTable().deleteNote(guid);\r
+ reloadTrashCount();\r
+ }\r
+ // Delete a note\r
+ public void restoreNote(String guid) {\r
+ trashCounterRunner.abortCount = true;\r
+ for (int i=0; i<masterNoteIndex.size(); i++) {\r
+ if (masterNoteIndex.get(i).getGuid().equals(guid)) {\r
+ masterNoteIndex.get(i).setActive(true);\r
+ masterNoteIndex.get(i).setDeleted(0);\r
+ i=masterNoteIndex.size();\r
+ }\r
+ }\r
+ for (int i=0; i<getNoteIndex().size(); i++) {\r
+ if (getNoteIndex().get(i).getGuid().equals(guid)) {\r
+ getNoteIndex().get(i).setActive(true);\r
+ getNoteIndex().get(i).setDeleted(0);\r
+ i=getNoteIndex().size();\r
+ }\r
+ }\r
+ conn.getNoteTable().restoreNote(guid);\r
+ reloadTrashCount();\r
+ }\r
+ public void updateNote(Note n) {\r
+ \r
+ for (int i=0; i<masterNoteIndex.size(); i++) {\r
+ if (masterNoteIndex.get(i).getGuid().equals(n.getGuid())) {\r
+ masterNoteIndex.remove(i);\r
+ masterNoteIndex.add(n);\r
+ }\r
+ }\r
+ for (int i=0; i<getNoteIndex().size(); i++) {\r
+ if (getNoteIndex().get(i).getGuid().equals(n.getGuid())) {\r
+ getNoteIndex().get(i).setActive(true);\r
+ getNoteIndex().get(i).setDeleted(0);\r
+ i=getNoteIndex().size();\r
+ }\r
+ }\r
+ conn.getNoteTable().updateNote(n, true);\r
+ }\r
+ // Add a note. \r
+ public void addNote(Note n) {\r
+ getNoteIndex().add(n);\r
+ masterNoteIndex.add(n);\r
+ }\r
+ // Expunge a note\r
+ public void expungeNote(String guid) {\r
+ trashCounterRunner.abortCount = true;\r
+ for (int i=0; i<masterNoteIndex.size(); i++) {\r
+ if (masterNoteIndex.get(i).getGuid().equals(guid)) {\r
+ masterNoteIndex.remove(i);\r
+ i=masterNoteIndex.size();\r
+ }\r
+ }\r
+ for (int i=0; i<getNoteIndex().size(); i++) {\r
+ if (getNoteIndex().get(i).getGuid().equals(guid)) {\r
+ getNoteIndex().remove(i);\r
+ i=getNoteIndex().size();\r
+ }\r
+ }\r
+ conn.getNoteTable().expungeNote(guid, false, true);\r
+ reloadTrashCount();\r
+ }\r
+ // Expunge a note\r
+ public void emptyTrash() {\r
+ trashCounterRunner.abortCount = true; \r
+ for (int i=masterNoteIndex.size()-1; i>=0; i--) {\r
+ if (!masterNoteIndex.get(i).isActive()) {\r
+ masterNoteIndex.remove(i);\r
+ }\r
+ }\r
+ \r
+ for (int i=getNoteIndex().size()-1; i>=0; i--) {\r
+ if (!getNoteIndex().get(i).isActive()) {\r
+ getNoteIndex().remove(i);\r
+ } \r
+ }\r
+\r
+ conn.getNoteTable().expungeAllDeletedNotes();\r
+ reloadTrashCount();\r
+ }\r
+ // The trash counter thread has produced a result\r
+ @SuppressWarnings("unused")\r
+ private void trashSignalReceiver(Integer i) {\r
+ trashCount = i;\r
+ trashSignal.countChanged.emit(i);\r
+ }\r
+ // Update note contents\r
+ public void updateNoteContent(String guid, String content) {\r
+ logger.log(logger.HIGH, "Entering ListManager.updateNoteContent");\r
+// EnmlConverter enml = new EnmlConverter(logger);\r
+// String text = enml.convert(guid, content);\r
+ \r
+ // Update the list tables \r
+/* for (int i=0; i<masterNoteIndex.size(); i++) {\r
+ if (masterNoteIndex.get(i).getGuid().equals(guid)) {\r
+ masterNoteIndex.get(i).setContent(text);\r
+ i = masterNoteIndex.size();\r
+ }\r
+ }\r
+ // Update the list tables \r
+ for (int i=0; i<getNoteIndex().size(); i++) {\r
+ if (getNoteIndex().get(i).getGuid().equals(guid)) {\r
+ getNoteIndex().get(i).setContent(text);\r
+ i = getNoteIndex().size();\r
+ }\r
+ }\r
+*/ \r
+ // Check if any new tags were encountered\r
+/* if (enml.saveInvalidXML) {\r
+ List<String> elements = Global.invalidElements;\r
+ for (int i=0; i<elements.size(); i++) {\r
+ conn.getInvalidXMLTable().addInvalidElement(elements.get(i));\r
+ }\r
+ for (String key : Global.invalidAttributes.keySet()) {\r
+ ArrayList<String> attributes = Global.invalidAttributes.get(key);\r
+ for (int i=0; i<attributes.size(); i++) {\r
+ conn.getInvalidXMLTable().addInvalidAttribute(key, attributes.get(i));\r
+ }\r
+ }\r
+ }\r
+*/\r
+ saveRunner.addWork(guid, content);\r
+// conn.getNoteTable().updateNoteContent(guid, content);\r
+ logger.log(logger.HIGH, "Leaving ListManager.updateNoteContent");\r
+ }\r
+ // Update a note creation date\r
+ public void updateNoteCreatedDate(String guid, QDateTime date) {\r
+ for (int i=0; i<masterNoteIndex.size(); i++) {\r
+ if (masterNoteIndex.get(i).getGuid().equals(guid)) {\r
+ masterNoteIndex.get(i).setCreated(date.toTime_t()*1000);\r
+ i = masterNoteIndex.size();\r
+ } \r
+ }\r
+ // Update the list tables \r
+ for (int i=0; i<getNoteIndex().size(); i++) {\r
+ if (getNoteIndex().get(i).getGuid().equals(guid)) {\r
+ getNoteIndex().get(i).setCreated(date.toTime_t()*1000);\r
+ i = getNoteIndex().size();\r
+ }\r
+ }\r
+ conn.getNoteTable().updateNoteCreatedDate(guid, date);\r
+ }\r
+ // Subject date has been changed\r
+ public void updateNoteSubjectDate(String guid, QDateTime date) {\r
+ for (int i=0; i<masterNoteIndex.size(); i++) {\r
+ if (masterNoteIndex.get(i).getGuid().equals(guid)) {\r
+ masterNoteIndex.get(i).getAttributes().setSubjectDate(date.toTime_t()*1000);\r
+ i = masterNoteIndex.size();\r
+ } \r
+ }\r
+ // Update the list tables \r
+ for (int i=0; i<getNoteIndex().size(); i++) {\r
+ if (getNoteIndex().get(i).getGuid().equals(guid)) {\r
+ getNoteIndex().get(i).setCreated(date.toTime_t()*1000);\r
+ i = getNoteIndex().size();\r
+ }\r
+ }\r
+ conn.getNoteTable().updateNoteSubjectDate(guid, date);\r
+ }\r
+ // Author has changed\r
+ public void updateNoteAuthor(String guid, String author) {\r
+ for (int i=0; i<masterNoteIndex.size(); i++) {\r
+ if (masterNoteIndex.get(i).getGuid().equals(guid)) {\r
+ masterNoteIndex.get(i).getAttributes().setAuthor(author);\r
+ masterNoteIndex.get(i).getAttributes().setAltitudeIsSet(true);\r
+ i = masterNoteIndex.size();\r
+ } \r
+ }\r
+ // Update the list tables \r
+ for (int i=0; i<getNoteIndex().size(); i++) {\r
+ if (getNoteIndex().get(i).getGuid().equals(guid)) {\r
+ getNoteIndex().get(i).getAttributes().setAuthor(author);\r
+ getNoteIndex().get(i).getAttributes().setAuthorIsSet(true);\r
+ i = getNoteIndex().size();\r
+ }\r
+ }\r
+ conn.getNoteTable().updateNoteAuthor(guid, author);\r
+ }\r
+ // Author has changed\r
+ public void updateNoteSourceUrl(String guid, String url) {\r
+ for (int i=0; i<masterNoteIndex.size(); i++) {\r
+ if (masterNoteIndex.get(i).getGuid().equals(guid)) {\r
+ masterNoteIndex.get(i).getAttributes().setSourceURL(url);\r
+ masterNoteIndex.get(i).getAttributes().setSourceURLIsSet(true);\r
+ i = masterNoteIndex.size();\r
+ } \r
+ }\r
+ // Update the list tables \r
+ for (int i=0; i<getNoteIndex().size(); i++) {\r
+ if (getNoteIndex().get(i).getGuid().equals(guid)) {\r
+ getNoteIndex().get(i).getAttributes().setSourceURL(url);\r
+ getNoteIndex().get(i).getAttributes().setSourceURLIsSet(true);\r
+ i = getNoteIndex().size();\r
+ }\r
+ }\r
+ conn.getNoteTable().updateNoteSourceUrl(guid, url);\r
+ }\r
+ // Update a note last changed date\r
+ public void updateNoteAlteredDate(String guid, QDateTime date) {\r
+ for (int i=0; i<masterNoteIndex.size(); i++) {\r
+ if (masterNoteIndex.get(i).getGuid().equals(guid)) {\r
+ masterNoteIndex.get(i).setUpdated(date.toTime_t()*1000);\r
+ i = masterNoteIndex.size();\r
+ } \r
+ }\r
+ // Update the list tables \r
+ for (int i=0; i<getNoteIndex().size(); i++) {\r
+ if (getNoteIndex().get(i).getGuid().equals(guid)) {\r
+ getNoteIndex().get(i).setUpdated(date.toTime_t()*1000);\r
+ i = getNoteIndex().size();\r
+ }\r
+ }\r
+ \r
+ conn.getNoteTable().updateNoteAlteredDate(guid, date);\r
+ }\r
+ // Update a note title\r
+ public void updateNoteTitle(String guid, String title) {\r
+ logger.log(logger.HIGH, "Entering ListManager.updateNoteTitle");\r
+ conn.getNoteTable().updateNoteTitle(guid, title);\r
+ \r
+ for (int i=0; i<masterNoteIndex.size(); i++) {\r
+ if (masterNoteIndex.get(i).getGuid().equals(guid)) {\r
+ masterNoteIndex.get(i).setTitle(title);\r
+ i = masterNoteIndex.size();\r
+ } \r
+ }\r
+ // Update the list tables \r
+ for (int i=0; i<getNoteIndex().size(); i++) {\r
+ if (getNoteIndex().get(i).getGuid().equals(guid)) {\r
+ getNoteIndex().get(i).setTitle(title);\r
+ i = getNoteIndex().size();\r
+ }\r
+ }\r
+ \r
+ logger.log(logger.HIGH, "Leaving ListManager.updateNoteTitle");\r
+ }\r
+ // Update a note's notebook\r
+ public void updateNoteNotebook(String guid, String notebookGuid) {\r
+ logger.log(logger.HIGH, "Entering ListManager.updateNoteNotebook");\r
+ for (int i=0; i<masterNoteIndex.size(); i++) {\r
+ if (masterNoteIndex.get(i).getGuid().equals(guid)) {\r
+ masterNoteIndex.get(i).setNotebookGuid(notebookGuid);\r
+ i=masterNoteIndex.size();\r
+ }\r
+ }\r
+ for (int i=0; i<getNoteIndex().size(); i++) {\r
+ if (getNoteIndex().get(i).getGuid().equals(guid)) {\r
+ getNoteIndex().get(i).setNotebookGuid(notebookGuid);\r
+ i=masterNoteIndex.size();\r
+ }\r
+ }\r
+ conn.getNoteTable().updateNoteNotebook(guid, notebookGuid, true);\r
+ logger.log(logger.HIGH, "Leaving ListManager.updateNoteNotebook");\r
+ }\r
+ // Update a note sequence number\r
+ public void updateNoteSequence(String guid, int sequence) {\r
+ logger.log(logger.HIGH, "Entering ListManager.updateNoteSequence");\r
+\r
+ conn.getNoteTable().updateNoteSequence(guid, sequence);\r
+ \r
+ for (int i=0; i<noteIndex.size(); i++) {\r
+ if (noteIndex.get(i).getGuid().equals(guid)) {\r
+ noteIndex.get(i).setUpdateSequenceNum(sequence);\r
+ i=noteIndex.size()+1;\r
+ }\r
+ }\r
+ logger.log(logger.HIGH, "Leaving ListManager.updateNoteSequence");\r
+ }\r
+ public void updateNoteGuid(String oldGuid, String newGuid, boolean updateDatabase) {\r
+ logger.log(logger.HIGH, "Entering ListManager.updateNoteGuid");\r
+ \r
+ if (updateDatabase) \r
+ conn.getNoteTable().updateNoteGuid(oldGuid, newGuid);\r
+ \r
+ for (int i=0; i<masterNoteIndex.size(); i++) {\r
+ if (masterNoteIndex.get(i).getGuid() != null && masterNoteIndex.get(i).getGuid().equals(oldGuid)) {\r
+ masterNoteIndex.get(i).setGuid(newGuid);\r
+ i=masterNoteIndex.size()+1;\r
+ }\r
+ }\r
+ for (int i=0; i<noteIndex.size(); i++) {\r
+ if (noteIndex.get(i).getGuid() != null && noteIndex.get(i).getGuid().equals(oldGuid)) {\r
+ noteIndex.get(i).setGuid(newGuid);\r
+ i=noteIndex.size()+1;\r
+ }\r
+ }\r
+ logger.log(logger.HIGH, "Leaving ListManager.updateNoteGuid");\r
+\r
+ }\r
+\r
+ \r
+ //************************************************************************************\r
+ //************************************************************************************\r
+ //** Tag functions\r
+ //************************************************************************************\r
+ //************************************************************************************ \r
+ // Update a tag sequence number\r
+ public void updateTagSequence(String guid, int sequence) {\r
+ logger.log(logger.HIGH, "Entering ListManager.updateTagSequence");\r
+\r
+ conn.getTagTable().updateTagSequence(guid, sequence); \r
+ for (int i=0; i<tagIndex.size(); i++) {\r
+ if (tagIndex.get(i).getGuid().equals(guid)) {\r
+ getTagIndex().get(i).setUpdateSequenceNum(sequence);\r
+ i=tagIndex.size()+1;\r
+ }\r
+ }\r
+ logger.log(logger.HIGH, "Leaving ListManager.updateTagSequence");\r
+ }\r
+ // Update a tag guid number\r
+ public void updateTagGuid(String oldGuid, String newGuid) {\r
+ logger.log(logger.HIGH, "Entering ListManager.updateTagGuid");\r
+\r
+ conn.getTagTable().updateTagGuid(oldGuid, newGuid); \r
+ for (int i=0; i<tagIndex.size(); i++) {\r
+ if (tagIndex.get(i).getGuid().equals(oldGuid)) {\r
+ tagIndex.get(i).setGuid(newGuid);\r
+ i=tagIndex.size()+1;\r
+ }\r
+ }\r
+ logger.log(logger.HIGH, "Leaving ListManager.updateTagGuid");\r
+\r
+ }\r
+ // Count tag results\r
+// @SuppressWarnings("unused")\r
+// private void reloadTagCount() {\r
+// tagCounterRunner.threadLock.lock(); \r
+// tagCounterRunner.setNoteIndex(getNoteIndex());\r
+// QThreadPool.globalInstance().tryStart(tagCounterRunner);\r
+// tagCounterRunner.threadLock.unlock();\r
+// }\r
+\r
+ //************************************************************************************\r
+ //************************************************************************************\r
+ //** Notebook functions\r
+ //************************************************************************************\r
+ //************************************************************************************ \r
+ // Delete a notebook\r
+ public void deleteNotebook(String guid) {\r
+ for (int i=0; i<getNotebookIndex().size(); i++) {\r
+ if (getNotebookIndex().get(i).getGuid().equals(guid)) {\r
+ getNotebookIndex().remove(i);\r
+ i=masterNoteIndex.size();\r
+ }\r
+ }\r
+ conn.getNotebookTable().expungeNotebook(guid, true); \r
+ }\r
+ // Update a notebook sequence number\r
+ public void updateNotebookSequence(String guid, int sequence) {\r
+ logger.log(logger.HIGH, "Entering ListManager.updateNotebookSequence");\r
+\r
+ conn.getNotebookTable().updateNotebookSequence(guid, sequence);\r
+ \r
+ for (int i=0; i<notebookIndex.size(); i++) {\r
+ if (notebookIndex.get(i).getGuid().equals(guid)) {\r
+ notebookIndex.get(i).setUpdateSequenceNum(sequence);\r
+ i=notebookIndex.size()+1;\r
+ }\r
+ }\r
+ logger.log(logger.HIGH, "Leaving ListManager.updateNotebookSequence");\r
+\r
+ }\r
+ // Update a notebook Guid number\r
+ public void updateNotebookGuid(String oldGuid, String newGuid) {\r
+ logger.log(logger.HIGH, "Entering ListManager.updateNotebookGuid");\r
+\r
+ conn.getNotebookTable().updateNotebookGuid(oldGuid, newGuid);\r
+ \r
+ for (int i=0; i<notebookIndex.size(); i++) {\r
+ if (notebookIndex.get(i).getGuid().equals(oldGuid)) {\r
+ notebookIndex.get(i).setGuid(newGuid);\r
+ i=notebookIndex.size()+1;\r
+ }\r
+ }\r
+ logger.log(logger.HIGH, "Leaving ListManager.updateNotebookGuid");\r
+\r
+ }\r
+ \r
+ \r
+ //************************************************************************************\r
+ //************************************************************************************\r
+ //** Load and filter the note index\r
+ //************************************************************************************\r
+ //************************************************************************************\r
+// public void clearNoteIndexSearch() {\r
+// setNoteIndex(masterNoteIndex);\r
+// }\r
+ // Load the note index based upon what the user wants.\r
+ public void loadNotesIndex() {\r
+ logger.log(logger.EXTREME, "Entering ListManager.loadNotesIndex()");\r
+ tagCounterRunner.abortCount = true;\r
+ notebookCounterRunner.abortCount = true;\r
+ trashCounterRunner.abortCount = true;\r
+ \r
+ List<Note> index = new ArrayList<Note>();\r
+ \r
+ List<Note> matches;\r
+ if (enSearchChanged || masterNoteIndex == null)\r
+ matches = enSearch.matchWords();\r
+ else\r
+ matches = masterNoteIndex;\r
+ \r
+ if (matches == null)\r
+ matches = masterNoteIndex;\r
+ \r
+ for (int i=0; i<matches.size(); i++) {\r
+ Note n = matches.get(i);\r
+ boolean goodNotebook = false;\r
+ boolean goodTag = false;\r
+ boolean goodAttribute = false;\r
+ boolean goodStatus = false;\r
+ \r
+ // Check note status\r
+ if (!n.isActive() && Global.showDeleted)\r
+ index.add(n);\r
+ else {\r
+ if (n.isActive() && !Global.showDeleted)\r
+ goodStatus = true;\r
+ // Begin filtering results\r
+ if (goodStatus)\r
+ goodNotebook = filterByNotebook(n.getNotebookGuid());\r
+ if (goodNotebook) \r
+ goodTag = filterByTag(n.getTagGuids());\r
+ if (goodTag)\r
+ goodAttribute = conn.getNoteTable().checkAttributeSelection(n);\r
+ if (goodAttribute)\r
+ index.add(n);\r
+ }\r
+\r
+ } \r
+ countNotebookResults(index);\r
+ countTagResults(index);\r
+ enSearchChanged = false;\r
+ setNoteIndex(index);\r
+ reloadTrashCount();\r
+ logger.log(logger.EXTREME, "Leaving ListManager.loadNotesIndex()");\r
+ }\r
+ public void countNotebookResults(List<Note> index) {\r
+ logger.log(logger.EXTREME, "Entering ListManager.countNotebookResults()");\r
+ if (!Global.mimicEvernoteInterface) {\r
+ notebookCounterRunner.setNoteIndex(index);\r
+ notebookCounterRunner.release(CounterRunner.NOTEBOOK);\r
+ } else {\r
+ notebookCounterRunner.setNoteIndex(masterNoteIndex);\r
+ notebookCounterRunner.release(CounterRunner.NOTEBOOK_ALL);\r
+ }\r
+ logger.log(logger.EXTREME, "Leaving ListManager.countNotebookResults()");\r
+ }\r
+ public void countTagResults(List<Note> index) {\r
+ logger.log(logger.EXTREME, "Entering ListManager.countTagResults");\r
+ if (!Global.tagBehavior().equalsIgnoreCase("DoNothing")) {\r
+ tagCounterRunner.setNoteIndex(index);\r
+ tagCounterRunner.release(CounterRunner.TAG);\r
+ } else {\r
+ tagCounterRunner.setNoteIndex(null);\r
+ tagCounterRunner.release(CounterRunner.TAG_ALL);\r
+ }\r
+ logger.log(logger.EXTREME, "Leaving ListManager.countTagResults()");\r
+ }\r
+ // Update the count of items in the trash\r
+ public void reloadTrashCount() {\r
+ logger.log(logger.EXTREME, "Entering ListManager.reloadTrashCount");\r
+ trashCounterRunner.setNoteIndex(getNoteIndex());\r
+ trashCounterRunner.release(CounterRunner.TRASH);\r
+ logger.log(logger.EXTREME, "Leaving ListManager.reloadTrashCount");\r
+ } \r
+ \r
+ private boolean filterByNotebook(String guid) {\r
+ boolean good = false;\r
+ if (selectedNotebooks.size() == 0)\r
+ good = true;\r
+ if (!good && selectedNotebooks.contains(guid)) \r
+ good = true;\r
+\r
+ for (int i=0; i<getArchiveNotebookIndex().size() && good; i++) {\r
+ if (guid.equals(getArchiveNotebookIndex().get(i).getGuid())) {\r
+ good = false;\r
+ return good;\r
+ }\r
+ }\r
+ return good;\r
+ }\r
+ private boolean filterByTag(List<String> noteTags) {\r
+ if (noteTags == null || selectedTags == null)\r
+ return true;\r
+ \r
+ if (selectedTags.size() == 0) \r
+ return true;\r
+ \r
+ for (int i=0; i<selectedTags.size(); i++) {\r
+ String selectedGuid = selectedTags.get(i);\r
+ if (noteTags.contains(selectedGuid))\r
+ return true;\r
+ }\r
+ return false;\r
+ }\r
+\r
+ \r
+ \r
+ public void updateNoteTitleColor(String guid, Integer color) {\r
+ titleColors.remove(guid);\r
+ titleColors.put(guid, color);\r
+ conn.getNoteTable().setNoteTitleColor(guid, color);\r
+ }\r
+ public void loadNoteTitleColors() {\r
+ List<Pair<String,Integer>> colors = conn.getNoteTable().getNoteTitleColors();\r
+ if (titleColors == null)\r
+ titleColors = new HashMap<String,Integer>();\r
+ else\r
+ titleColors.clear();\r
+ for (int i=0; i<colors.size(); i++) {\r
+ titleColors.put(colors.get(i).getFirst(), colors.get(i).getSecond());\r
+ }\r
+ }\r
+ \r
+ //********************************************************************************\r
+ //********************************************************************************\r
+ //* Support signals from the index thread\r
+ //********************************************************************************\r
+ //********************************************************************************\r
+ // Reset a flag if an index is needed\r
+ public void setIndexNeeded(String guid, String type, Boolean b) {\r
+ if (Global.keepRunning && type.equalsIgnoreCase("content"))\r
+ conn.getNoteTable().setIndexNeeded(guid, false);\r
+ if (Global.keepRunning && type.equalsIgnoreCase("resource")) {\r
+ conn.getNoteTable().noteResourceTable.setIndexNeeded(guid, b);\r
+ }\r
+ }\r
+ \r
+ \r
+ \r
+ public boolean threadCheck(int id) {\r
+ if (id == Global.notebookCounterThreadId) \r
+ return notebookThread.isAlive();\r
+ if (id == Global.tagCounterThreadId) \r
+ return tagThread.isAlive();\r
+ if (id == Global.trashCounterThreadId) \r
+ return trashThread.isAlive();\r
+ if (id == Global.saveThreadId) \r
+ return saveThread.isAlive();\r
+ return false;\r
+ }\r
+ \r
+ \r
+ \r
+ //********************************************************************************\r
+ //********************************************************************************\r
+ //* Utility Functions\r
+ //********************************************************************************\r
+ //********************************************************************************\r
+ public void compactDatabase() {\r
+ conn.compactDatabase();\r
+// IndexConnection idx = new IndexConnection(logger, "nevernote-compact");\r
+// idx.dbSetup();\r
+// idx.dbShutdown();\r
+ }\r
+\r
+ // Rebuild the note HTML to something usable\r
+ public List<String> scanNoteForResources(Note n) {\r
+ logger.log(logger.HIGH, "Entering ListManager.scanNoteForResources");\r
+ logger.log(logger.EXTREME, "Note guid: " +n.getGuid());\r
+ QDomDocument doc = new QDomDocument();\r
+ QDomDocument.Result result = doc.setContent(n.getContent());\r
+ if (!result.success) {\r
+ logger.log(logger.MEDIUM, "Parse error when scanning note for resources.");\r
+ logger.log(logger.MEDIUM, "Note guid: " +n.getGuid());\r
+ return null;\r
+ }\r
+ \r
+ List<String> returnArray = new ArrayList<String>();\r
+ QDomNodeList anchors = doc.elementsByTagName("en-media");\r
+ for (int i=0; i<anchors.length(); i++) {\r
+ QDomElement enmedia = anchors.at(i).toElement();\r
+ if (enmedia.hasAttribute("type")) {\r
+ QDomAttr hash = enmedia.attributeNode("hash");\r
+ returnArray.add(hash.value().toString());\r
+ }\r
+ }\r
+ logger.log(logger.HIGH, "Leaving ListManager.scanNoteForResources");\r
+ return returnArray;\r
+ }\r
+ // Given a list of tags, produce a string list of tag names\r
+ public String getTagNamesForNote(Note n) {\r
+ StringBuffer buffer = new StringBuffer(100);\r
+ Vector<String> v = new Vector<String>();\r
+ List<String> guids = n.getTagGuids();\r
+ \r
+ if (guids == null) \r
+ return "";\r
+ \r
+ for (int i=0; i<guids.size(); i++) {\r
+ v.add(getTagNameByGuid(guids.get(i)));\r
+ }\r
+ Comparator<String> comparator = Collections.reverseOrder();\r
+ Collections.sort(v,comparator);\r
+ Collections.reverse(v);\r
+ \r
+ for (int i = 0; i<v.size(); i++) {\r
+ if (i>0) \r
+ buffer.append(", ");\r
+ buffer.append(v.get(i));\r
+ }\r
+ \r
+ return buffer.toString();\r
+ }\r
+ // Get a tag name when given a tag guid\r
+ public String getTagNameByGuid(String guid) {\r
+ for (int i=0; i<getTagIndex().size(); i++) {\r
+ String s = getTagIndex().get(i).getGuid();\r
+ if (s.equals(guid)) { \r
+ return getTagIndex().get(i).getName();\r
+ }\r
+ }\r
+ return "";\r
+ }\r
+ // For a notebook guid, return the name\r
+ public String getNotebookNameByGuid(String guid) {\r
+ if (notebookIndex == null)\r
+ return null;\r
+ for (int i=0; i<notebookIndex.size(); i++) {\r
+ String s = notebookIndex.get(i).getGuid();\r
+ if (s.equals(guid)) { \r
+ return notebookIndex.get(i).getName();\r
+ }\r
+ }\r
+ return "";\r
+ }\r
+ \r
+ \r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.utilities;\r
+\r
+import java.io.DataOutputStream;\r
+import java.io.File;\r
+import java.io.FileNotFoundException;\r
+import java.io.FileOutputStream;\r
+import java.io.FilterOutputStream;\r
+import java.io.IOException;\r
+import java.io.OutputStream;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import cx.fbn.nevernote.Global;\r
+\r
+public class OutStream extends FilterOutputStream {\r
+\r
+ List<String> buffer;\r
+ File file;\r
+ FileOutputStream fos;\r
+ DataOutputStream dos;\r
+ \r
+ public OutStream(OutputStream out, String name) {\r
+ super(out);\r
+ buffer = new ArrayList<String>();\r
+ \r
+ file = new File(Global.getDirectoryPath()+"logs"+File.separatorChar +name);\r
+ try {\r
+ fos = new FileOutputStream(file);\r
+ dos = new DataOutputStream(fos);\r
+ } catch (FileNotFoundException e) {}\r
+ }\r
+ \r
+ \r
+ @Override\r
+ public synchronized void write(byte b[]) throws IOException {\r
+ String aString = new String(b);\r
+ buffer.add(aString);\r
+ dos.writeBytes(aString +"\n");\r
+ }\r
+\r
+ @Override\r
+ public synchronized void write(byte b[], int off, int len) throws IOException {\r
+ String aString = new String(b , off , len);\r
+ buffer.add(aString);\r
+ dos.writeBytes(aString +"\n");\r
+ }\r
+ \r
+ public List<String> getText() {\r
+ return buffer;\r
+ }\r
+\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.utilities;\r
+\r
+public class Pair<T, S>{\r
+\r
+ private T first;\r
+ private S second;\r
+\r
+ public Pair(T f, S s){ \r
+ first = f;\r
+ second = s; \r
+ }\r
+ public Pair() {\r
+ \r
+ }\r
+ public T getFirst(){\r
+ return first;\r
+ }\r
+ \r
+ public S getSecond() {\r
+ return second;\r
+ }\r
+ \r
+ @Override\r
+ public String toString() { \r
+ return "(" + first.toString() + ", " + second.toString() + ")"; \r
+ }\r
+\r
+ public void setFirst(T t) {\r
+ first = t;\r
+ }\r
+ public void setSecond(S s) {\r
+ second = s;\r
+ }\r
+}\r
+
\ No newline at end of file
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.utilities;\r
+\r
+import java.util.HashMap;\r
+\r
+public class StringUtils {\r
+\r
+ private StringUtils() {}\r
+ \r
+ private static HashMap<String,String> htmlEntities;\r
+ static {\r
+ htmlEntities = new HashMap<String,String>();\r
+ htmlEntities.put("<","<") ; htmlEntities.put(">",">");\r
+ htmlEntities.put("&","&") ; htmlEntities.put(""","\"");\r
+ htmlEntities.put("à","à"); htmlEntities.put("à","À");\r
+ htmlEntities.put("â","â") ; htmlEntities.put("ä","ä");\r
+ htmlEntities.put("ä","Ä") ; htmlEntities.put("â","Â");\r
+ htmlEntities.put("å","å") ; htmlEntities.put("å","Å");\r
+ htmlEntities.put("æ","æ") ; htmlEntities.put("&aElig;","Æ" );\r
+ htmlEntities.put("ç","ç"); htmlEntities.put("ç","Ç");\r
+ htmlEntities.put("é","é"); htmlEntities.put("é","É" );\r
+ htmlEntities.put("è","è"); htmlEntities.put("è","È");\r
+ htmlEntities.put("ê","ê") ; htmlEntities.put("ê","Ê");\r
+ htmlEntities.put("ë","ë") ; htmlEntities.put("ë","Ë");\r
+ htmlEntities.put("ï","ï") ; htmlEntities.put("ï","Ï");\r
+ htmlEntities.put("ô","ô") ; htmlEntities.put("ô","Ô");\r
+ htmlEntities.put("ö","ö") ; htmlEntities.put("ö","Ö");\r
+ htmlEntities.put("ø","ø") ; htmlEntities.put("ø","Ø");\r
+ htmlEntities.put("ß","ß") ; htmlEntities.put("ù","ù");\r
+ htmlEntities.put("ù","Ù"); htmlEntities.put("û","û");\r
+ htmlEntities.put("û","Û") ; htmlEntities.put("ü","ü");\r
+ htmlEntities.put("ü","Ü") ; htmlEntities.put(" "," ");\r
+ htmlEntities.put("©","\u00a9"); htmlEntities.put("'", "'");\r
+ htmlEntities.put("®","\u00ae"); htmlEntities.put("¡", "\u00a1");\r
+ htmlEntities.put("€","\u20a0"); htmlEntities.put("¢", "\u00a2");\r
+ htmlEntities.put("£", "\u00a3"); htmlEntities.put("&curen;", "\u00a4");\r
+ htmlEntities.put("¥", "\u00a5"); htmlEntities.put("¦", "\u00a6");\r
+ htmlEntities.put("§", "\u00a7"); htmlEntities.put("¨", "\u00a8");\r
+ htmlEntities.put("©", "\u00a9"); htmlEntities.put("ª", "\u00aa");\r
+ htmlEntities.put("&laqo;", "\u00ab"); htmlEntities.put("¬", "\u00ac");\r
+ htmlEntities.put("®", "\u00ae"); htmlEntities.put("¯", "\u00af");\r
+ }\r
+\r
+\r
+ \r
+ public static final String unescapeHTML(String source, int start){\r
+ int i,j;\r
+\r
+ i = source.indexOf("&", start);\r
+ while (i>-1) {\r
+ j = source.indexOf(";" ,i);\r
+ if (j > i) {\r
+ String entityToLookFor = source.substring(i , j + 1);\r
+ String value = htmlEntities.get(entityToLookFor);\r
+ if (value != null) {\r
+ value = " ";\r
+ source = new StringBuffer().append(source.substring(0 , i).toLowerCase())\r
+ .append(value)\r
+ .append(source.substring(j + 1))\r
+ .toString();\r
+ i = source.indexOf("&", i+1);\r
+ }\r
+ }\r
+ }\r
+ return source;\r
+ }\r
+\r
+ \r
+ public static final String unescapeHTML2(String source, int start){\r
+ int i,j;\r
+\r
+ i = source.indexOf("&", start);\r
+ if (i > -1) {\r
+ j = source.indexOf(";" ,i);\r
+ if (j > i) {\r
+ String entityToLookFor = source.substring(i , j + 1);\r
+ String value = htmlEntities.get(entityToLookFor);\r
+ if (value != null) {\r
+ value = " ";\r
+ source = new StringBuffer().append(source.substring(0 , i).toLowerCase())\r
+ .append(value)\r
+ .append(source.substring(j + 1))\r
+ .toString();\r
+ return unescapeHTML(source, i + 1); // recursive call\r
+ }\r
+ }\r
+ }\r
+ return source;\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+package cx.fbn.nevernote.utilities;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+public class SyncTimes {\r
+ private final List<String> stringTimes;\r
+ private final List<Integer> minuteTimes;\r
+ \r
+ public SyncTimes() {\r
+ stringTimes = new ArrayList<String>();\r
+ minuteTimes = new ArrayList<Integer>();\r
+ \r
+ stringTimes.add("manually");\r
+ minuteTimes.add(0);\r
+ \r
+ stringTimes.add("15 minutes");\r
+ minuteTimes.add(15);\r
+ \r
+ stringTimes.add("30 minutes");\r
+ minuteTimes.add(30);\r
+ \r
+ stringTimes.add("45 minutes");\r
+ minuteTimes.add(45);\r
+ \r
+ stringTimes.add("60 minutes");\r
+ minuteTimes.add(60);\r
+ \r
+ stringTimes.add("120 minutes");\r
+ minuteTimes.add(120);\r
+ \r
+ stringTimes.add("240 minutes");\r
+ minuteTimes.add(240);\r
+ \r
+ stringTimes.add("600 minutes");\r
+ minuteTimes.add(600);\r
+ \r
+ stringTimes.add("Shortly after the end of the world");\r
+ minuteTimes.add(-1);\r
+ }\r
+ \r
+ public List<String> stringValues() {\r
+ return stringTimes;\r
+ }\r
+ \r
+ public int timeValue(String t) {\r
+ for (int i=0; i<stringTimes.size(); i++) \r
+ if (stringTimes.get(i).equalsIgnoreCase(t))\r
+ return minuteTimes.get(i);\r
+ \r
+ return 15;\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.xml;\r
+\r
+import org.xml.sax.SAXParseException;\r
+\r
+public class EnmlException extends SAXParseException {\r
+\r
+ public EnmlException(String message, String publicId, String systemId,\r
+ int lineNumber, int columnNumber, Exception e) {\r
+ super(message, publicId, systemId, lineNumber, columnNumber, e);\r
+ // TODO Auto-generated constructor stub\r
+ }\r
+ public String attribute = null;\r
+ /**\r
+ * \r
+ */\r
+ private static final long serialVersionUID = 6728529537176421409L;\r
+\r
+ \r
+\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.xml;\r
+\r
+import java.util.ArrayList;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.Data;\r
+import com.evernote.edam.type.Note;\r
+import com.evernote.edam.type.NoteAttributes;\r
+import com.evernote.edam.type.Notebook;\r
+import com.evernote.edam.type.Resource;\r
+import com.evernote.edam.type.SavedSearch;\r
+import com.evernote.edam.type.Tag;\r
+import com.trolltech.qt.core.QByteArray;\r
+import com.trolltech.qt.core.QFile;\r
+import com.trolltech.qt.core.QIODevice;\r
+import com.trolltech.qt.xml.QXmlStreamWriter;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.sql.DatabaseConnection;\r
+import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+import cx.fbn.nevernote.utilities.Pair;\r
+\r
+public class ExportData {\r
+ \r
+ private List<Notebook> notebooks;\r
+ private final HashMap<String,String> localNotebooks;\r
+ private final HashMap<String,String> dirtyNotebooks;\r
+ private final ApplicationLogger logger;\r
+ \r
+ private List<SavedSearch> searches;\r
+ private final HashMap<String,String> dirtySearches;\r
+\r
+ private List<Tag> tags;\r
+ private final HashMap<String,String> dirtyTags;\r
+\r
+ private final HashMap<String, String> exportableNotebooks;\r
+ private final HashMap<String, String> exportableTags;\r
+ private List<Note> notes;\r
+ private final HashMap<String,String> dirtyNotes;\r
+ private HashMap<String,Integer> titleColors;\r
+ private final boolean fullBackup;\r
+ private final DatabaseConnection conn;\r
+ private QXmlStreamWriter writer; \r
+ \r
+ private String errorMessage;\r
+ public int lastError;\r
+ \r
+ public ExportData(DatabaseConnection conn2, boolean full) {\r
+ conn = conn2;\r
+ logger = new ApplicationLogger("export.log");\r
+ notebooks = new ArrayList<Notebook>();\r
+ tags = new ArrayList<Tag>();\r
+ notes = new ArrayList<Note>();\r
+ dirtyNotebooks = new HashMap<String,String>();\r
+ localNotebooks = new HashMap<String,String>();\r
+ dirtyTags = new HashMap<String,String>();\r
+ fullBackup = full;\r
+ \r
+ dirtyNotes = new HashMap<String, String>();\r
+ dirtySearches = new HashMap<String, String>();\r
+ searches = new ArrayList<SavedSearch>();\r
+ \r
+ exportableNotebooks = new HashMap<String, String>();\r
+ exportableTags = new HashMap<String, String>();\r
+ }\r
+ \r
+ \r
+ public ExportData(DatabaseConnection conn2, boolean full, List<String> guids) {\r
+ conn = conn2;\r
+ logger = new ApplicationLogger("export.log");\r
+ notebooks = new ArrayList<Notebook>();\r
+ tags = new ArrayList<Tag>();\r
+ notes = new ArrayList<Note>();\r
+ for (int i=0; i<guids.size(); i++) {\r
+ notes.add(conn.getNoteTable().getNote(guids.get(i), true, true, true, true, true));\r
+ }\r
+ dirtyNotebooks = new HashMap<String,String>();\r
+ localNotebooks = new HashMap<String,String>();\r
+ dirtyTags = new HashMap<String,String>();\r
+ fullBackup = full;\r
+ \r
+ dirtyNotes = new HashMap<String, String>();\r
+ dirtySearches = new HashMap<String, String>();\r
+ searches = new ArrayList<SavedSearch>();\r
+ \r
+ exportableNotebooks = new HashMap<String, String>();\r
+ exportableTags = new HashMap<String, String>();\r
+ }\r
+ \r
+ \r
+ public void exportData(String filename) {\r
+ \r
+ notebooks = conn.getNotebookTable().getAll(); \r
+ tags = conn.getTagTable().getAll();\r
+ List<Notebook> books = conn.getNotebookTable().getAllLocal();\r
+ for (int i=0; i<books.size(); i++) {\r
+ localNotebooks.put(books.get(i).getGuid(), "");\r
+ }\r
+ \r
+ books = conn.getNotebookTable().getDirty();\r
+ for (int i=0; i<books.size(); i++) {\r
+ dirtyNotebooks.put(books.get(i).getGuid(), "");\r
+ }\r
+\r
+ List<Tag> d= conn.getTagTable().getDirty();\r
+ for (int i=0; i<d.size(); i++) {\r
+ dirtyTags.put(d.get(i).getGuid(), "");\r
+ }\r
+ \r
+ if (fullBackup)\r
+ notes = conn.getNoteTable().getAllNotes();\r
+ \r
+ List<Note> dn = conn.getNoteTable().getDirty();\r
+ for (int i=0; i<dn.size(); i++) {\r
+ dirtyNotes.put(dn.get(i).getGuid(), "");\r
+ }\r
+ \r
+ List<Pair<String,Integer>> tColors = conn.getNoteTable().getNoteTitleColors();\r
+ titleColors = new HashMap<String,Integer>();\r
+ for (int i=0; i<tColors.size(); i++) {\r
+ titleColors.put(tColors.get(i).getFirst(), tColors.get(i).getSecond());\r
+ }\r
+ \r
+ searches = conn.getSavedSearchTable().getAll();\r
+ \r
+ List<SavedSearch> ds = conn.getSavedSearchTable().getDirty();\r
+ for (int i=0; i<ds.size(); i++) {\r
+ dirtySearches.put(ds.get(i).getGuid(), "");\r
+ }\r
+ \r
+ \r
+ \r
+ lastError = 0;\r
+ errorMessage = "";\r
+ QFile xmlFile = new QFile(filename);\r
+ if (!xmlFile.open(QIODevice.OpenModeFlag.WriteOnly, QIODevice.OpenModeFlag.Truncate)) {\r
+ lastError = 16;\r
+ errorMessage = "Cannot open file.";\r
+ }\r
+ \r
+ writer = new QXmlStreamWriter(xmlFile); \r
+ writer.setAutoFormatting(true);\r
+ writer.setCodec("UTF-8");\r
+ writer.writeStartDocument();\r
+ writer.writeDTD("<!DOCTYPE NeverNote-Export>");\r
+ writer.writeStartElement("nevernote-export");\r
+ writer.writeAttribute("version", "0.86");\r
+ if (fullBackup)\r
+ writer.writeAttribute("exportType", "backup");\r
+ else\r
+ writer.writeAttribute("exportType", "export"); \r
+ writer.writeAttribute("application", "NeverNote");\r
+ writer.writeAttribute("applicationVersion", Global.version);\r
+ if (fullBackup) {\r
+ writer.writeStartElement("Synchronization");\r
+ long sequenceDate = conn.getSyncTable().getLastSequenceDate();\r
+ int number = conn.getSyncTable().getUpdateSequenceNumber();\r
+ createTextNode("UpdateSequenceNumber", new Long(number).toString());\r
+ createTextNode("LastSequenceDate", new Long(sequenceDate).toString());\r
+ writer.writeEndElement();\r
+ }\r
+ \r
+ for (int i=0; i<notes.size(); i++) {\r
+ String guid = notes.get(i).getGuid();\r
+ logger.log(logger.EXTREME, "Getting note " +guid +" : " +notes.get(i).getTitle());\r
+ Note note = conn.getNoteTable().getNote(guid, true, true, true, true, true);\r
+ logger.log(logger.EXTREME, "Writing note XML");\r
+ writeNote(note);\r
+ }\r
+ \r
+ writeNotebooks();\r
+ writeTags();\r
+ writeSavedSearches();\r
+\r
+ \r
+ writer.writeEndElement();\r
+ writer.writeEndDocument();\r
+\r
+ \r
+ \r
+ writer.dispose();\r
+\r
+ \r
+ xmlFile.close();\r
+ xmlFile.dispose();\r
+\r
+ }\r
+ \r
+ \r
+ private void writeSavedSearches() {\r
+ if (!fullBackup)\r
+ return;\r
+ for (int i=0; i<searches.size(); i++) {\r
+ writer.writeStartElement("SavedSearch");\r
+ createTextNode("Guid", searches.get(i).getGuid());\r
+ createTextNode("Name", searches.get(i).getName());\r
+ createTextNode("Query", searches.get(i).getQuery());\r
+ createTextNode("Format", new Integer(searches.get(i).getFormat().getValue()).toString());\r
+ if (dirtySearches.containsKey(searches.get(i).getGuid()))\r
+ createTextNode("Dirty","true");\r
+ else\r
+ createTextNode("Dirty","false");\r
+ writer.writeEndElement();\r
+ }\r
+ }\r
+ \r
+ \r
+ \r
+ private void writeNote(Note note) {\r
+ \r
+ writer.writeStartElement("Note");\r
+ createTextNode("Guid", note.getGuid());\r
+ createTextNode("UpdateSequenceNumber", new Long(note.getUpdateSequenceNum()).toString());\r
+ createTextNode("Title", note.getTitle());\r
+ createTextNode("Created", new Long(note.getCreated()).toString());\r
+ createTextNode("Updated", new Long(note.getUpdated()).toString());\r
+ createTextNode("Deleted", new Long(note.getDeleted()).toString());\r
+ createTextNode("Active", new Boolean(note.isActive()).toString());\r
+ createTextNode("NotebookGuid", note.getNotebookGuid());\r
+ if (dirtyNotes.containsKey(note.getGuid()))\r
+ createTextNode("Dirty", "true");\r
+ else\r
+ createTextNode("Dirty", "false");\r
+ if (titleColors.containsKey(note.getGuid()))\r
+ createTextNode("TitleColor", new String(titleColors.get(note.getGuid()).toString()));\r
+ exportableNotebooks.put(note.getNotebookGuid(), "");\r
+ \r
+ if (note.getTagGuidsSize() > 0) {\r
+ writer.writeStartElement("NoteTags");\r
+ for (int i=0; i<note.getTagGuidsSize(); i++) {\r
+ createTextNode("Guid", note.getTagGuids().get(i));\r
+ exportableTags.put(note.getTagGuids().get(i), "");\r
+ }\r
+ writer.writeEndElement();\r
+ }\r
+ \r
+ NoteAttributes noteAttributes = note.getAttributes();\r
+ if (noteAttributes != null) {\r
+ writer.writeStartElement("NoteAttributes");\r
+ createTextNode("Author", noteAttributes.getAuthor());\r
+ createTextNode("Source", noteAttributes.getSource());\r
+ createTextNode("SourceApplication", noteAttributes.getSourceApplication());\r
+ createTextNode("SourceURL", noteAttributes.getSourceURL());\r
+ createTextNode("Altitude", new Double(noteAttributes.getAltitude()).toString());\r
+ createTextNode("Longitude", new Double(noteAttributes.getLongitude()).toString());\r
+ createTextNode("Latitude", new Double(noteAttributes.getLatitude()).toString());\r
+ createTextNode("SubjectDate", new Long(noteAttributes.getSubjectDate()).toString());\r
+ writer.writeEndElement();\r
+ }\r
+ \r
+// writeResources(conn.getNoteTable().noteResourceTable.getNoteResources(note.getGuid(), true));\r
+ writeResources(note.getResources());\r
+ \r
+ logger.log(logger.EXTREME, "Writing content");\r
+ writer.writeStartElement("Content");\r
+ writer.writeCDATA(conn.getNoteTable().getNoteContentBinary(note.getGuid()));\r
+ writer.writeEndElement();\r
+ writer.writeEndElement();\r
+ }\r
+\r
+ \r
+ private void writeResources(List<Resource> resourceTable) {\r
+ Resource resource;\r
+ if (resourceTable.size() == 0)\r
+ return;\r
+ for (int i=0; i<resourceTable.size(); i++) {\r
+ resource = resourceTable.get(i);\r
+ writer.writeStartElement("NoteResource");\r
+ createTextNode("Guid", resource.getGuid());\r
+ createTextNode("NoteGuid", resource.getNoteGuid());\r
+ createTextNode("UpdateSequenceNumber", new Integer(resource.getUpdateSequenceNum()).toString());\r
+ createTextNode("Mime", resource.getMime());\r
+ createTextNode("Duration", new Integer(resource.getDuration()).toString());\r
+ createTextNode("Height", new Integer(resource.getHeight()).toString());\r
+ createTextNode("Width", new Integer(resource.getWidth()).toString());\r
+ logger.log(logger.EXTREME, "Checking for data node");\r
+ if (resource.getData() != null)\r
+ writeDataNode("Data", resource.getData());\r
+ logger.log(logger.EXTREME, "Checking for alternate data node");\r
+ if (resource.getAlternateData() != null)\r
+ writeDataNode("AlternateData", resource.getAlternateData());\r
+ logger.log(logger.EXTREME, "Checking for recognition");\r
+ if (resource.getRecognition() != null)\r
+ writeRecognitionNode("Recognition", resource.getRecognition());\r
+ if (resource.isActive())\r
+ createTextNode("Active", "true");\r
+ else\r
+ createTextNode("Active", "false");\r
+ logger.log(logger.EXTREME, "Checking resource attributes");\r
+ if (resource.getAttributes() != null) {\r
+ writer.writeStartElement("NoteResourceAttribute");\r
+ createTextNode("CameraMake", resource.getAttributes().getCameraMake());\r
+ createTextNode("CameraModel", resource.getAttributes().getCameraModel());\r
+ createTextNode("FileName", resource.getAttributes().getFileName());\r
+ createTextNode("RecoType", resource.getAttributes().getRecoType());\r
+ createTextNode("SourceURL", resource.getAttributes().getSourceURL());\r
+ createTextNode("Altitude", new Double(resource.getAttributes().getAltitude()).toString());\r
+ createTextNode("Longitude", new Double(resource.getAttributes().getLongitude()).toString());\r
+ createTextNode("Latitude", new Double(resource.getAttributes().getLatitude()).toString());\r
+ createTextNode("Timestamp", new Long(resource.getAttributes().getTimestamp()).toString());\r
+ if (resource.getAttributes().isAttachment())\r
+ createTextNode("Attachment", "true");\r
+ else \r
+ createTextNode("Attachment", "false");\r
+ if (resource.getAttributes().isClientWillIndex())\r
+ createTextNode("ClientWillIndex", "true");\r
+ else\r
+ createTextNode("ClientWillIndex", "false");\r
+ writer.writeEndElement();\r
+ }\r
+ writer.writeEndElement();\r
+ }\r
+ logger.log(logger.EXTREME, "Ending resource node");\r
+// writer.writeEndElement();\r
+ }\r
+ \r
+ \r
+ private void writeDataNode(String name, Data data) {\r
+ writer.writeStartElement(name);\r
+ createTextNode("Size", new Integer(data.getSize()).toString());\r
+ if (data.getBody() != null && data.getBody().length > 0)\r
+ createBinaryNode("Body", new QByteArray(data.getBody()).toHex().toString());\r
+ else\r
+ createBinaryNode("Body", "");\r
+ if (data.getBodyHash() != null && data.getBodyHash().length > 0)\r
+ createTextNode("BodyHash", new QByteArray(data.getBodyHash()).toHex().toString());\r
+ else\r
+ createTextNode("BodyHash", "");\r
+ writer.writeEndElement(); \r
+ }\r
+\r
+ \r
+ \r
+ \r
+ private void writeRecognitionNode(String name, Data data) {\r
+ writer.writeStartElement(name);\r
+ createTextNode("Size", new Integer(data.getSize()).toString());\r
+ if (data.getBody() != null && data.getBody().length > 0) {\r
+ writer.writeStartElement("Body");\r
+ writer.writeCDATA(new QByteArray(data.getBody()).toString());\r
+// writer.writeCDATA(new QByteArray(data.getBody()).toHex().toString());\r
+ writer.writeEndElement();\r
+ } else\r
+ createBinaryNode("Body", "");\r
+ \r
+ if (data.getBodyHash() != null && data.getBodyHash().length > 0)\r
+ createTextNode("BodyHash", new QByteArray(data.getBodyHash()).toHex().toString());\r
+ else\r
+ createTextNode("BodyHash", "");\r
+ writer.writeEndElement(); \r
+ }\r
+\r
+ \r
+ private void writeNotebooks() {\r
+ for (int i=0; i<notebooks.size(); i++) {\r
+ if (exportableNotebooks.containsKey(notebooks.get(i).getGuid()) || fullBackup) {\r
+ writer.writeStartElement("Notebook");\r
+ createTextNode("Guid", notebooks.get(i).getGuid());\r
+ createTextNode("Name", notebooks.get(i).getName());\r
+ createTextNode("UpdateSequenceNumber", new Long(notebooks.get(i).getUpdateSequenceNum()).toString());\r
+ if (notebooks.get(i).isDefaultNotebook())\r
+ createTextNode("DefaultNotebook", "true");\r
+ else\r
+ createTextNode("DefaultNotebook", "false");\r
+ createTextNode("ServiceCreated", new Long(notebooks.get(i).getServiceCreated()).toString());\r
+ createTextNode("ServiceUpdated", new Long(notebooks.get(i).getServiceUpdated()).toString());\r
+ if (localNotebooks.containsKey(notebooks.get(i).getGuid()))\r
+ createTextNode("Local","true");\r
+ else\r
+ createTextNode("Local","false");\r
+ if (dirtyNotebooks.containsKey(notebooks.get(i).getGuid()))\r
+ createTextNode("Dirty","true");\r
+ else\r
+ createTextNode("Dirty","false");\r
+ writer.writeEndElement(); \r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ private void writeTags() {\r
+ for (int i=0; i<tags.size(); i++) {\r
+ if (exportableTags.containsKey(tags.get(i).getGuid()) || fullBackup) {\r
+ writer.writeStartElement("Tag");\r
+ createTextNode("Guid", tags.get(i).getGuid());\r
+ createTextNode("Name", tags.get(i).getName());\r
+ createTextNode("ParentGuid", tags.get(i).getParentGuid());\r
+ createTextNode("UpdateSequenceNumber", new Long(tags.get(i).getUpdateSequenceNum()).toString());\r
+ if (dirtyTags.containsKey(tags.get(i).getGuid()))\r
+ createTextNode("Dirty","true");\r
+ else\r
+ createTextNode("Dirty","false");\r
+ writer.writeEndElement(); \r
+ }\r
+ }\r
+ }\r
+ \r
+ \r
+ private void createTextNode(String nodeName, String value) {\r
+ if (value == null)\r
+ value = "";\r
+ writer.writeTextElement(nodeName, value);\r
+ return;\r
+ }\r
+\r
+ private void createBinaryNode(String nodeName, String value) {\r
+ if (value == null)\r
+ value = "";\r
+ logger.log(logger.EXTREME, "Writing binary node");\r
+ writer.writeStartElement(nodeName);\r
+/* int i=0;\r
+ for (; i<value.length(); i+=80) \r
+ {\r
+ writer.writeCharacters("\n"+value.substring(i,i+80));\r
+ }\r
+ writer.writeCharacters("\n"+value.substring(i)+"\n");\r
+*/ writer.writeCharacters(value);\r
+ writer.writeEndElement();\r
+ return;\r
+ }\r
+\r
+ \r
+ public String getErrorMessage() {\r
+ return errorMessage;\r
+ }\r
+ \r
+ \r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.xml;\r
+\r
+import java.util.ArrayList;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+\r
+import com.evernote.edam.type.Data;\r
+import com.evernote.edam.type.Note;\r
+import com.evernote.edam.type.NoteAttributes;\r
+import com.evernote.edam.type.Notebook;\r
+import com.evernote.edam.type.Resource;\r
+import com.evernote.edam.type.ResourceAttributes;\r
+import com.evernote.edam.type.SavedSearch;\r
+import com.evernote.edam.type.Tag;\r
+import com.trolltech.qt.core.QByteArray;\r
+import com.trolltech.qt.core.QFile;\r
+import com.trolltech.qt.core.QIODevice;\r
+import com.trolltech.qt.xml.QXmlStreamAttributes;\r
+import com.trolltech.qt.xml.QXmlStreamReader;\r
+\r
+import cx.fbn.nevernote.sql.DatabaseConnection;\r
+import cx.fbn.nevernote.utilities.ApplicationLogger;\r
+\r
+public class ImportData {\r
+\r
+ public int lastError;\r
+ private String errorMessage;\r
+ private String fileName;\r
+ DatabaseConnection conn;\r
+ QXmlStreamReader reader;\r
+ private Note note;\r
+ private boolean noteIsDirty;\r
+ private Notebook notebook;\r
+ private boolean notebookIsDirty;\r
+ private boolean notebookIsLocal;\r
+ private Tag tag;\r
+ private boolean tagIsDirty;\r
+ private final HashMap<String,Integer> titleColors;\r
+ private SavedSearch search;\r
+ private boolean searchIsDirty;\r
+ public int highUpdateSequenceNumber;\r
+ public long lastSequenceDate;\r
+ private final ApplicationLogger logger;\r
+ private final boolean backup;\r
+ private String notebookGuid;\r
+ \r
+ public ImportData(DatabaseConnection c, boolean full) {\r
+ logger = new ApplicationLogger("import.log");\r
+ backup = full;\r
+ conn = c;\r
+ titleColors = new HashMap<String,Integer>();\r
+ }\r
+ \r
+ public void importData(String f) {\r
+ fileName = f;\r
+ errorMessage = "";\r
+ \r
+ lastError = 0;\r
+ errorMessage = "";\r
+ QFile xmlFile = new QFile(fileName);\r
+ if (!xmlFile.open(QIODevice.OpenModeFlag.ReadOnly)) {\r
+ lastError = 16;\r
+ errorMessage = "Cannot open file.";\r
+ }\r
+ \r
+ reader = new QXmlStreamReader(xmlFile); \r
+ while (!reader.atEnd()) {\r
+ reader.readNext();\r
+ if (reader.hasError()) {\r
+ errorMessage = reader.errorString();\r
+ logger.log(logger.LOW, "************************* ERROR READING BACKUP " +reader.errorString());\r
+ lastError = 16;\r
+ return;\r
+ }\r
+ if (reader.name().equalsIgnoreCase("nevernote-export") && reader.isStartElement()) {\r
+ QXmlStreamAttributes attributes = reader.attributes();\r
+ String version = attributes.value("version");\r
+ String type = attributes.value("exportType");\r
+ String application = attributes.value("application");\r
+ if (!version.equalsIgnoreCase("0.85") && !version.equalsIgnoreCase("0.86")) {\r
+ lastError = 1;\r
+ errorMessage = "Unknown backup version = " +version;\r
+ return;\r
+ }\r
+ if (!application.equalsIgnoreCase("NeverNote")) {\r
+ lastError = 2;\r
+ errorMessage = "This backup is from an unknown application = " +application;\r
+ return;\r
+ }\r
+ if (!type.equalsIgnoreCase("backup") && backup) {\r
+ lastError = 4;\r
+ errorMessage = "This is an export file, not a backup file";\r
+ return;\r
+ } \r
+ if (type.equalsIgnoreCase("export") && backup) {\r
+ lastError = 5;\r
+ errorMessage = "This is a backup file, not an export file"; \r
+ return;\r
+ }\r
+ \r
+ }\r
+ if (reader.name().equalsIgnoreCase("Synchronization") && reader.isStartElement() && backup) {\r
+ processSynchronizationNode();\r
+ conn.getSyncTable().setLastSequenceDate(lastSequenceDate);\r
+ conn.getSyncTable().setUpdateSequenceNumber(highUpdateSequenceNumber);\r
+// Global.setSequenceDate(lastSequenceDate);\r
+// Global.setUpdateSequenceNumber(highUpdateSequenceNumber);\r
+ }\r
+ if (reader.name().equalsIgnoreCase("note") && reader.isStartElement()) {\r
+ processNoteNode();\r
+ if (backup)\r
+ conn.getNoteTable().addNote(note, noteIsDirty);\r
+ else {\r
+ note.setUpdateSequenceNum(0);\r
+ if (notebookGuid != null) \r
+ note.setNotebookGuid(notebookGuid);\r
+ for (int i=0; i<note.getResourcesSize(); i++) {\r
+ note.getResources().get(i).setUpdateSequenceNum(0);\r
+ }\r
+ conn.getNoteTable().addNote(note, true);\r
+ }\r
+ if (titleColors.containsKey(note.getGuid())) \r
+ conn.getNoteTable().setNoteTitleColor(note.getGuid(), titleColors.get(note.getGuid()));\r
+ }\r
+ if (reader.name().equalsIgnoreCase("notebook") && reader.isStartElement() && backup) {\r
+ processNotebookNode();\r
+ String existingGuid = conn.getNotebookTable().findNotebookByName(notebook.getName());\r
+ if (existingGuid == null)\r
+ conn.getNotebookTable().addNotebook(notebook, notebookIsDirty, notebookIsLocal);\r
+ else \r
+ {\r
+ conn.getNotebookTable().updateNotebookGuid(existingGuid, notebook.getGuid());\r
+ conn.getNotebookTable().updateNotebook(notebook, notebookIsDirty);\r
+ }\r
+\r
+ }\r
+ if (reader.name().equalsIgnoreCase("tag") && reader.isStartElement() && backup) {\r
+ processTagNode();\r
+ String testGuid = conn.getTagTable().findTagByName(tag.getName());\r
+ if (testGuid == null)\r
+ conn.getTagTable().addTag(tag, tagIsDirty);\r
+ else {\r
+ conn.getTagTable().updateTagGuid(testGuid, tag.getGuid());\r
+ conn.getTagTable().updateTag(tag,tagIsDirty);\r
+ }\r
+ }\r
+ if (reader.name().equalsIgnoreCase("savedsearch") && reader.isStartElement() && backup) {\r
+ processSavedSearchNode();\r
+ conn.getSavedSearchTable().addSavedSearch(search, searchIsDirty);\r
+ }\r
+ }\r
+ xmlFile.close();\r
+ }\r
+ \r
+ \r
+ private void processNoteNode() {\r
+ note = new Note();\r
+ note.setResources(new ArrayList<Resource>());\r
+\r
+ boolean atEnd = false;\r
+ while(!atEnd) {\r
+ if (reader.isStartElement()) {\r
+ if (reader.name().equalsIgnoreCase("Guid")) \r
+ note.setGuid(textValue());\r
+ if (reader.name().equalsIgnoreCase("UpdateSequenceNumber")) \r
+ note.setUpdateSequenceNum(intValue());\r
+ if (reader.name().equalsIgnoreCase("Title")) \r
+ note.setTitle(textValue());\r
+ if (reader.name().equalsIgnoreCase("Created")) \r
+ note.setCreated(longValue());\r
+ if (reader.name().equalsIgnoreCase("Updated")) \r
+ note.setUpdated(longValue());\r
+ if (reader.name().equalsIgnoreCase("Deleted")) \r
+ note.setDeleted(longValue());\r
+ if (reader.name().equalsIgnoreCase("Active")) \r
+ note.setActive(booleanValue());\r
+ if (reader.name().equalsIgnoreCase("NotebookGuid") && backup) \r
+ note.setNotebookGuid(textValue());\r
+ if (reader.name().equalsIgnoreCase("Content")) \r
+ note.setContent(textValue());\r
+ if (reader.name().equalsIgnoreCase("NoteTags") && backup) \r
+ note.setTagGuids(processNoteTagList());\r
+ if (reader.name().equalsIgnoreCase("NoteAttributes")) \r
+ note.setAttributes(processNoteAttributes());\r
+ if (reader.name().equalsIgnoreCase("NoteResource")) \r
+ note.getResources().add(processResource());\r
+ if (reader.name().equalsIgnoreCase("Dirty")) {\r
+ if (booleanValue())\r
+ noteIsDirty=true;\r
+ }\r
+ if (reader.name().equalsIgnoreCase("TitleColor")) \r
+ titleColors.put(note.getGuid(), intValue());\r
+ }\r
+ reader.readNext();\r
+ if (reader.name().equalsIgnoreCase("note") && reader.isEndElement())\r
+ atEnd = true;\r
+ }\r
+ \r
+ return;\r
+ \r
+ } \r
+ private Resource processResource() {\r
+ Resource resource = new Resource();\r
+ boolean atEnd = false;\r
+ boolean isDirty = false;\r
+ while(!atEnd) {\r
+ if (reader.isStartElement()) {\r
+ if (reader.name().equalsIgnoreCase("Guid")) \r
+ resource.setGuid(textValue());\r
+ if (reader.name().equalsIgnoreCase("NoteGuid")) \r
+ resource.setNoteGuid(textValue());\r
+ if (reader.name().equalsIgnoreCase("UpdateSequenceNumber")) \r
+ resource.setUpdateSequenceNum(intValue());\r
+ if (reader.name().equalsIgnoreCase("Active")) \r
+ resource.setActive(booleanValue());\r
+ if (reader.name().equalsIgnoreCase("Mime")) \r
+ resource.setMime(textValue());\r
+ if (reader.name().equalsIgnoreCase("Duration")) \r
+ resource.setDuration(shortValue());\r
+ if (reader.name().equalsIgnoreCase("Height")) \r
+ resource.setHeight(shortValue());\r
+ if (reader.name().equalsIgnoreCase("Width")) \r
+ resource.setWidth(shortValue());\r
+ if (reader.name().equalsIgnoreCase("dirty")) \r
+ isDirty = booleanValue();\r
+ if (reader.name().equalsIgnoreCase("Data")) \r
+ resource.setData(processData("Data"));\r
+ if (reader.name().equalsIgnoreCase("AlternateData")) \r
+ resource.setAlternateData(processData("AlternateData"));\r
+ if (reader.name().equalsIgnoreCase("RecognitionData")) \r
+ resource.setRecognition(processData("NoteResourceAttribute"));\r
+ if (reader.name().equalsIgnoreCase("NoteResourceAttribute")) \r
+ resource.setAttributes(processResourceAttributes());\r
+ }\r
+ reader.readNext();\r
+ if (reader.name().equalsIgnoreCase("noteresource") && reader.isEndElement())\r
+ atEnd = true;\r
+ }\r
+ \r
+ conn.getNoteTable().noteResourceTable.saveNoteResource(resource, isDirty);\r
+\r
+ \r
+ return resource;\r
+ }\r
+ \r
+ private Data processData(String nodeName) {\r
+ Data data = new Data();\r
+ boolean atEnd = false;\r
+ while(!atEnd) {\r
+ if (reader.isStartElement()) {\r
+ if (reader.name().equalsIgnoreCase("Size")) \r
+ data.setSize(intValue());\r
+ if (reader.name().equalsIgnoreCase("Body")) {\r
+ byte[] b = textValue().getBytes(); // data binary\r
+ QByteArray hexData = new QByteArray(b);\r
+ QByteArray binData = new QByteArray(QByteArray.fromHex(hexData));\r
+ data.setBody(binData.toByteArray());\r
+ }\r
+ if (reader.name().equalsIgnoreCase("BodyHash")) {\r
+ byte[] b = textValue().getBytes(); // data binary\r
+ QByteArray hexData = new QByteArray(b);\r
+ QByteArray binData = new QByteArray(QByteArray.fromHex(hexData));\r
+ data.setBodyHash(binData.toByteArray());\r
+ }\r
+\r
+ reader.readNext();\r
+ if (reader.name().equalsIgnoreCase("data") && reader.isEndElement())\r
+ atEnd = true;\r
+ }\r
+ reader.readNext();\r
+ if (reader.name().equalsIgnoreCase(nodeName) && reader.isEndElement())\r
+ atEnd = true;\r
+ }\r
+ return data;\r
+ }\r
+\r
+ private ResourceAttributes processResourceAttributes() {\r
+ ResourceAttributes attributes = new ResourceAttributes();\r
+ boolean atEnd = false;\r
+ while(!atEnd) {\r
+ if (reader.isStartElement()) {\r
+ if (reader.name().equalsIgnoreCase("CameraMake")) \r
+ attributes.setCameraMake(textValue()); \r
+ if (reader.name().equalsIgnoreCase("CameraModel")) \r
+ attributes.setCameraModel(textValue()); \r
+ if (reader.name().equalsIgnoreCase("FileName")) \r
+ attributes.setFileName(textValue()); \r
+ if (reader.name().equalsIgnoreCase("RecoType")) \r
+ attributes.setRecoType(textValue()); \r
+ if (reader.name().equalsIgnoreCase("CameraModel")) \r
+ attributes.setCameraMake(textValue()); \r
+ if (reader.name().equalsIgnoreCase("SourceURL")) \r
+ attributes.setSourceURL(textValue()); \r
+ if (reader.name().equalsIgnoreCase("Altitude")) \r
+ attributes.setAltitude(doubleValue()); \r
+ if (reader.name().equalsIgnoreCase("Longitude")) \r
+ attributes.setLongitude(doubleValue()); \r
+ if (reader.name().equalsIgnoreCase("Latitude")) \r
+ attributes.setLatitude(doubleValue()); \r
+ if (reader.name().equalsIgnoreCase("Timestamp")) \r
+ attributes.setTimestamp(longValue()); \r
+ if (reader.name().equalsIgnoreCase("Attachment")) \r
+ attributes.setAttachment(booleanValue()); \r
+ if (reader.name().equalsIgnoreCase("ClientWillIndex")) \r
+ attributes.setClientWillIndex(booleanValue()); \r
+ }\r
+ reader.readNext();\r
+ if (reader.name().equalsIgnoreCase("noteresourceattribute") && reader.isEndElement())\r
+ atEnd = true;\r
+ }\r
+ \r
+ return attributes;\r
+ }\r
+\r
+ \r
+ private List<String> processNoteTagList() {\r
+ List<String> guidList = new ArrayList<String>();\r
+ \r
+\r
+ boolean atEnd = false;\r
+ while(!atEnd) { \r
+ if (reader.isStartElement()) {\r
+ if (reader.name().equalsIgnoreCase("guid")) \r
+ guidList.add(textValue());\r
+ }\r
+ reader.readNext();\r
+ if (reader.name().equalsIgnoreCase("notetags") && reader.isEndElement())\r
+ atEnd = true;\r
+ }\r
+ return guidList;\r
+ }\r
+\r
+\r
+\r
+ private NoteAttributes processNoteAttributes() {\r
+ NoteAttributes attributes = new NoteAttributes();\r
+ \r
+ boolean atEnd = false;\r
+ while(!atEnd) {\r
+ if (reader.isStartElement()) {\r
+ if (reader.name().equalsIgnoreCase("Author")) \r
+ attributes.setAuthor(textValue());\r
+ if (reader.name().equalsIgnoreCase("SourceURL")) \r
+ attributes.setSourceURL(textValue());\r
+ if (reader.name().equalsIgnoreCase("Source")) \r
+ attributes.setSource(textValue());\r
+ if (reader.name().equalsIgnoreCase("SourceApplication")) \r
+ attributes.setSourceApplication(textValue());\r
+ if (reader.name().equalsIgnoreCase("Altitude")) \r
+ attributes.setAltitude(doubleValue());\r
+ if (reader.name().equalsIgnoreCase("Longitude")) \r
+ attributes.setLongitude(doubleValue());\r
+ if (reader.name().equalsIgnoreCase("Latitude")) \r
+ attributes.setLatitude(doubleValue());\r
+ if (reader.name().equalsIgnoreCase("SubjectDate")) \r
+ attributes.setSubjectDate(longValue());\r
+ }\r
+ reader.readNext();\r
+ if (reader.name().equalsIgnoreCase("noteattributes") && reader.isEndElement())\r
+ atEnd = true;\r
+ }\r
+ \r
+ return attributes;\r
+}\r
+\r
+ \r
+ private void processSynchronizationNode() {\r
+ boolean atEnd = false;\r
+ while(!atEnd) {\r
+ if (reader.isStartElement()) {\r
+ if (reader.name().equalsIgnoreCase("UpdateSequenceNumber")) \r
+ highUpdateSequenceNumber = intValue();\r
+ if (reader.name().equalsIgnoreCase("LastSequenceDate")) \r
+ lastSequenceDate = longValue();\r
+ }\r
+ reader.readNext();\r
+ if (reader.name().equalsIgnoreCase("synchronization") && reader.isEndElement())\r
+ atEnd = true;\r
+ } \r
+ }\r
+ \r
+ \r
+ private void processSavedSearchNode() {\r
+ search = new SavedSearch();\r
+ searchIsDirty = false;\r
+ \r
+ boolean atEnd = false;\r
+ while(!atEnd) {\r
+ if (reader.isStartElement()) {\r
+ if (reader.name().equalsIgnoreCase("Guid")) \r
+ search.setGuid(textValue());\r
+ if (reader.name().equalsIgnoreCase("Name")) \r
+ search.setName(textValue());\r
+ if (reader.name().equalsIgnoreCase("UpdateSequenceNumber")) \r
+ search.setUpdateSequenceNum(intValue());\r
+ if (reader.name().equalsIgnoreCase("Query")) \r
+ search.setQuery(textValue());\r
+ if (reader.name().equalsIgnoreCase("Dirty")) {\r
+ if (booleanValue())\r
+ searchIsDirty = true;\r
+ }\r
+ }\r
+ reader.readNext();\r
+ if (reader.name().equalsIgnoreCase("savedsearch") && reader.isEndElement())\r
+ atEnd = true; } \r
+ return;\r
+ }\r
+\r
+\r
+ \r
+ private void processNotebookNode() {\r
+ notebook = new Notebook();\r
+ notebookIsDirty = false;\r
+ notebookIsLocal = false;\r
+ boolean atEnd = false;\r
+ while(!atEnd) {\r
+ if (reader.isStartElement()) {\r
+ if (reader.name().equalsIgnoreCase("Guid")) \r
+ notebook.setGuid(textValue());\r
+ if (reader.name().equalsIgnoreCase("Name")) \r
+ notebook.setName(textValue());\r
+ if (reader.name().equalsIgnoreCase("UpdateSequenceNumber")) \r
+ notebook.setUpdateSequenceNum(intValue());\r
+ if (reader.name().equalsIgnoreCase("ServiceCreated")) \r
+ notebook.setServiceCreated(longValue());\r
+ if (reader.name().equalsIgnoreCase("ServiceUpdated")) \r
+ notebook.setServiceUpdated(longValue());\r
+ if (reader.name().equalsIgnoreCase("DefaultNotebook")) {\r
+ notebook.setDefaultNotebook(booleanValue());\r
+ }\r
+ if (reader.name().equalsIgnoreCase("Dirty")) {\r
+ if (booleanValue())\r
+ notebookIsDirty = true;\r
+ }\r
+ if (reader.name().equalsIgnoreCase("LocalNotebook")) {\r
+ if (booleanValue())\r
+ notebookIsLocal = true;\r
+ } \r
+ }\r
+ reader.readNext();\r
+ if (reader.name().equalsIgnoreCase("notebook") && reader.isEndElement())\r
+ atEnd = true;\r
+ }\r
+ return;\r
+ }\r
+\r
+ \r
+ \r
+ private void processTagNode() {\r
+ tag = new Tag();\r
+ tagIsDirty = false;\r
+ boolean atEnd = false;\r
+ while(!atEnd) {\r
+ if (reader.isStartElement()) { \r
+ if (reader.name().equalsIgnoreCase("Guid")) \r
+ tag.setGuid(textValue());\r
+ if (reader.name().equalsIgnoreCase("Name")) \r
+ tag.setName(textValue());\r
+ if (reader.name().equalsIgnoreCase("UpdateSequenceNumber")) \r
+ tag.setUpdateSequenceNum(intValue());\r
+ if (reader.name().equalsIgnoreCase("ParentGuid")) \r
+ tag.setParentGuid(textValue());\r
+ if (reader.name().equalsIgnoreCase("Dirty")) {\r
+ if (booleanValue())\r
+ tagIsDirty = true;\r
+ }\r
+ }\r
+ reader.readNext();\r
+ if (reader.name().equalsIgnoreCase("tag") && reader.isEndElement())\r
+ atEnd = true;\r
+ }\r
+ return;\r
+ }\r
+ \r
+ \r
+ \r
+ \r
+ private String textValue() {\r
+ return reader.readElementText();\r
+ }\r
+ private int intValue() {\r
+ return new Integer(textValue());\r
+ }\r
+ private long longValue() {\r
+ return new Long(textValue());\r
+ }\r
+ private double doubleValue() {\r
+ return new Double(textValue());\r
+ }\r
+ private boolean booleanValue() {\r
+ String value = textValue();\r
+ if (value.equalsIgnoreCase("true"))\r
+ return true;\r
+ else\r
+ return false;\r
+ }\r
+ private short shortValue() {\r
+ return new Short(textValue());\r
+ }\r
+ \r
+ public void setNotebookGuid(String g) {\r
+ notebookGuid = g;\r
+ }\r
+ \r
+ public String getErrorMessage() {\r
+ return errorMessage;\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.xml;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.trolltech.qt.xml.QDomDocument;\r
+import com.trolltech.qt.xml.QDomElement;\r
+import com.trolltech.qt.xml.QDomNode;\r
+import com.trolltech.qt.xml.QDomNodeList;\r
+import com.trolltech.qt.xml.QDomText;\r
+\r
+import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.evernote.EnCrypt;\r
+\r
+public class XMLCleanup {\r
+ private String content;\r
+ private QDomDocument doc;\r
+ private final List<String> resources;\r
+ \r
+ public XMLCleanup() {\r
+ resources = new ArrayList<String>();\r
+ }\r
+ \r
+ \r
+ public void setValue(String text) {\r
+ content = text;\r
+/* content = content.replace("<HR>", "<hr/>");\r
+ content = content.replace("<hr>", "<hr/>");\r
+ content = content.replace("</HR>", "");\r
+ content = content.replace("</hr>", ""); */\r
+ }\r
+ public String getValue() {\r
+ return content;\r
+ }\r
+ // Validate the contents of the note. Change unsupported things \r
+ public void validate() {\r
+ doc = new QDomDocument();\r
+ int br = content.lastIndexOf("</en-note>");\r
+ content = new String(content.substring(0,br));\r
+ String newContent;\r
+ int k = content.indexOf("<en-note");\r
+\r
+ \r
+ newContent = new String(content.substring(k));\r
+ \r
+ \r
+ // Fix the background color\r
+ \r
+\r
+ newContent = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" \r
+ +"<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">\n"\r
+ +newContent \r
+ +"</en-note>";\r
+\r
+ QDomDocument.Result result = doc.setContent(newContent);\r
+ if (!result.success) {\r
+ System.out.println("DOM error in XMLValidator.validate()");\r
+ System.out.println(newContent);\r
+ System.out.println("Location : Line-"+result.errorLine +" Column-" + result.errorColumn);\r
+ System.out.println("Exiting");\r
+ System.exit(16);\r
+ return;\r
+ }\r
+ \r
+ QDomNodeList noteAnchors = doc.elementsByTagName("en-note");\r
+ int noteCount = noteAnchors.length();\r
+ for (int i=noteCount-1; i>=0; i--) {\r
+ if (noteAnchors.at(i).toElement().hasAttribute("style")) {\r
+ String style = noteAnchors.at(i).toElement().attribute("style");\r
+ int startColor = style.indexOf("background-color:");\r
+ if (startColor > -1) {\r
+ String color = style.substring(startColor+17);\r
+ color = color.substring(0,color.indexOf(";"));\r
+ noteAnchors.at(i).toElement().setAttribute("bgcolor", color);\r
+ }\r
+ }\r
+ }\r
+ \r
+ scanTags();\r
+ \r
+ // Remove invalid elements & attributes\r
+ // Modify en-media tags\r
+ QDomNodeList anchors;\r
+ for (String key : Global.invalidAttributes.keySet()) {\r
+ anchors = doc.elementsByTagName(key);\r
+ int enMediaCount = anchors.length();\r
+ for (int i=enMediaCount-1; i>=0; i--) {\r
+ QDomElement element = anchors.at(i).toElement();\r
+ ArrayList<String> names = Global.invalidAttributes.get(element.nodeName().toLowerCase());\r
+ if (names != null) { \r
+ for (int j=0; j<names.size(); j++) {\r
+ element.removeAttribute(names.get(j));\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ List<String> elements = Global.invalidElements;\r
+ for (int j=0; j<elements.size(); j++) {\r
+ anchors = doc.elementsByTagName(elements.get(j));\r
+ int enMediaCount = anchors.length();\r
+ for (int i=enMediaCount-1; i>=0; i--) {\r
+ QDomElement element = anchors.at(i).toElement();\r
+ element.setTagName("span");\r
+ }\r
+ }\r
+ content = doc.toString();\r
+\r
+ }\r
+ // Start looking through the tree.\r
+ private void scanTags() {\r
+// System.out.println("scanTags start");\r
+// QDomElement element = doc.firstChildElement();\r
+// parseChildren(element.firstChild()); \r
+ \r
+ if (doc.hasChildNodes())\r
+ parseNodes(doc.childNodes());\r
+ return;\r
+ }\r
+ \r
+ private void parseNodes(QDomNodeList nodes) {\r
+ for (int i=0; i<nodes.size(); i++) {\r
+ QDomNode node = nodes.at(i);\r
+ if (node.hasChildNodes())\r
+ parseNodes(node.childNodes());\r
+ fixNode(node);\r
+ }\r
+ }\r
+ \r
+/* \r
+ // Parse through individual nodes\r
+ private void parseChildren(QDomNode node) {\r
+ System.out.println("Starting parseChildren " +node.toElement().nodeName() +" : " +node.toElement().text());\r
+ for(; !node.isNull(); node = node.nextSibling()) {\r
+ if (node.hasChildNodes()) {\r
+ QDomNodeList l = node.childNodes();\r
+ \r
+ for (int i=0; i<l.size(); i++) {\r
+ System.out.println("Child node size: " +l.size() +" " +i);\r
+ parseChildren(l.at(i));\r
+ }\r
+ }\r
+ fixNode(node);\r
+ }\r
+ }\r
+ \r
+*/ \r
+ \r
+ // Fix the contents of the node back to ENML.\r
+ private void fixNode(QDomNode node) {\r
+ QDomElement scanChecked = node.toElement();\r
+ if (scanChecked.hasAttribute("checked")) {\r
+ System.out.println(scanChecked.attribute("checked"));\r
+ if (!scanChecked.attribute("checked").equalsIgnoreCase("true"))\r
+ scanChecked.setAttribute("checked", "false");\r
+ }\r
+ if (node.nodeName().equalsIgnoreCase("#comment") || node.nodeName().equalsIgnoreCase("script")) {\r
+ node.parentNode().removeChild(node);\r
+ }\r
+ if (node.nodeName().equalsIgnoreCase("input")) {\r
+ QDomElement e = node.toElement();\r
+ e.setTagName("en-todo");\r
+ String value = e.attribute("value");\r
+ e.removeAttribute("value");\r
+ e.removeAttribute("unchecked");\r
+ e.setAttribute("checked", value);\r
+ e.removeAttribute("onclick");\r
+ e.removeAttribute("type");\r
+ }\r
+\r
+\r
+ if (node.nodeName().equalsIgnoreCase("a")) {\r
+ QDomElement e = node.toElement();\r
+ String enTag = e.attribute("en-tag");\r
+ if (enTag.equalsIgnoreCase("en-media")) {\r
+ e.setTagName("en-media");\r
+ e.removeAttribute("en-type");\r
+ e.removeAttribute("en-tag");\r
+ e.removeAttribute("en-new");\r
+ resources.add(e.attribute("guid"));\r
+ e.removeAttribute("href");\r
+ e.removeAttribute("guid");\r
+ e.setNodeValue("");\r
+ e.removeChild(e.firstChildElement());\r
+ }\r
+ }\r
+ // Restore image resources\r
+ if (node.nodeName().equalsIgnoreCase("img")) {\r
+ QDomElement e = node.toElement();\r
+ String enType = e.attribute("en-tag");\r
+ \r
+ // Check if we have an en-crypt tag. Change it from an img to en-crypt\r
+ if (enType.equalsIgnoreCase("en-crypt")) {\r
+ \r
+ String encrypted = e.attribute("alt");\r
+ \r
+ QDomText crypt = doc.createTextNode(encrypted);\r
+ e.appendChild(crypt);\r
+ \r
+ e.removeAttribute("v:shapes");\r
+ e.removeAttribute("en-tag");\r
+ e.removeAttribute("contenteditable");\r
+ e.removeAttribute("alt");\r
+ e.removeAttribute("src");\r
+ e.removeAttribute("id");\r
+ e.removeAttribute("onclick");\r
+ e.removeAttribute("onmouseover");\r
+ e.setTagName("en-crypt");\r
+ node.removeChild(e);\r
+ return;\r
+ }\r
+ \r
+ // If we've gotten this far, we have an en-media tag\r
+ e.setTagName(enType);\r
+ resources.add(e.attribute("guid"));\r
+ e.removeAttribute("guid");\r
+ e.removeAttribute("src");\r
+ e.removeAttribute("en-new");\r
+ e.removeAttribute("en-tag");\r
+ }\r
+ \r
+ // Tags like <ul><ul><li>1</li></ul></ul> are technically valid, but Evernote \r
+ // expects that a <ul> tag only has a <li>, so we will need to change them\r
+ // to this: <ul><li><ul><li>1</li></ul></li></ul>\r
+ if (node.nodeName().equalsIgnoreCase("ul")) {\r
+ QDomNode firstChild = node.firstChild();\r
+ QDomElement childElement = firstChild.toElement();\r
+ if (childElement.nodeName().equalsIgnoreCase("ul")) {\r
+ QDomElement newElement = doc.createElement("li");\r
+ node.insertBefore(newElement, firstChild);\r
+ node.removeChild(firstChild);\r
+ newElement.appendChild(firstChild);\r
+ }\r
+ }\r
+ \r
+ if (node.nodeName().equalsIgnoreCase("en-crypt-temp")) {\r
+ QDomElement e = node.toElement();\r
+ String slot = e.attribute("slot");\r
+ e.removeAttribute("slot");\r
+ String password = Global.passwordSafe.get(slot);\r
+ Global.passwordSafe.remove(slot);\r
+ EnCrypt crypt = new EnCrypt();\r
+ String encrypted = crypt.encrypt(e.text(), password, 64); \r
+ \r
+ QDomText newText = doc.createTextNode(encrypted);\r
+ e.appendChild(newText);\r
+ e.removeChild(e.firstChild());\r
+ e.setTagName("en-crypt");\r
+ }\r
+ if (node.nodeName().equalsIgnoreCase("en-hilight")) {\r
+ QDomElement e = node.toElement();\r
+ QDomText newText = doc.createTextNode(e.text());\r
+ e.parentNode().replaceChild(newText,e);\r
+ }\r
+ if (node.nodeName().equalsIgnoreCase("span")) {\r
+ QDomElement e = node.toElement();\r
+ if (e.attribute("class").equalsIgnoreCase("en-hilight") || e.attribute("class").equalsIgnoreCase("en-spell")) {\r
+ QDomText newText = doc.createTextNode(e.text());\r
+ e.parentNode().replaceChild(newText,e);\r
+ }\r
+ if (e.attribute("pdfnavigationtable").equalsIgnoreCase("true")) {\r
+ node.parentNode().removeChild(node);\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ \r
+ // Return old resources we've found\r
+ public List<String> getResources() {\r
+ return resources;\r
+ }\r
+\r
+}\r
+\r
+
\ No newline at end of file
--- /dev/null
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+\r
+package cx.fbn.nevernote.xml;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+import java.util.regex.Matcher;\r
+import java.util.regex.Pattern;\r
+\r
+import com.trolltech.qt.xml.QDomDocument;\r
+import com.trolltech.qt.xml.QDomDocumentFragment;\r
+import com.trolltech.qt.xml.QDomElement;\r
+import com.trolltech.qt.xml.QDomNode;\r
+import com.trolltech.qt.xml.QDomNodeList;\r
+import com.trolltech.qt.xml.QDomText;\r
+\r
+public class XMLInsertHilight {\r
+ private final QDomDocument doc;\r
+ List<String> terms;\r
+ List<QDomNode> oldNodes;\r
+ List<QDomNode> newNodes;\r
+ \r
+ public XMLInsertHilight(QDomDocument d, List<String> t) {\r
+ doc = d;\r
+ terms = t;\r
+ oldNodes = new ArrayList<QDomNode>();\r
+ newNodes = new ArrayList<QDomNode>();\r
+ scanTags();\r
+ }\r
+ public QDomDocument getDoc() {\r
+ for (int i=0; i<oldNodes.size(); i++) {\r
+ oldNodes.get(i).parentNode().replaceChild(newNodes.get(i), oldNodes.get(i));\r
+ }\r
+ return doc;\r
+ }\r
+ // Start looking through the tree.\r
+ private void scanTags() {\r
+// QDomElement element = doc.firstChildElement();\r
+// parseChildren(element.firstChild());\r
+ if (doc.hasChildNodes())\r
+ parseNodes(doc.childNodes());\r
+ return;\r
+ }\r
+ \r
+ private void parseNodes(QDomNodeList nodes) {\r
+ for (int i=0; i<nodes.size(); i++) {\r
+ QDomNode node = nodes.at(i);\r
+ if (node.hasChildNodes()) {\r
+ parseNodes(node.childNodes());\r
+ }\r
+ scanWords(node);\r
+ }\r
+}\r
+ \r
+ \r
+ // Parse through individual nodes\r
+ public void parseChildren(QDomNode node) {\r
+ for(; !node.isNull(); node = node.nextSibling()) {\r
+ if (node.hasChildNodes()) {\r
+ QDomNodeList l = node.childNodes();\r
+ for (int i=0; i<l.size(); i++)\r
+ parseChildren(l.at(i));\r
+ }\r
+ if (node.isText()) {\r
+ scanWords(node);\r
+ }\r
+ }\r
+ }\r
+ \r
+ // We found a text node, so we need to search for things to hilight\r
+ private void scanWords(QDomNode node) {\r
+ String value = node.nodeValue();\r
+ QDomDocumentFragment fragment = doc.createDocumentFragment();\r
+ boolean matchFound = false;\r
+ int previousPosition = 0;\r
+ String valueEnd = "";\r
+ \r
+ String regex = buildRegex();\r
+ \r
+ Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);\r
+ Matcher matcher = pattern.matcher(value);\r
+ \r
+ while (matcher.find()) {\r
+ matchFound = true;\r
+ String valueStart = "";\r
+ int start = matcher.start();\r
+ int end = matcher.end();\r
+ if (value.substring(start).startsWith(" "))\r
+ start++;\r
+ if (value.substring(start, end).endsWith(" "))\r
+ end--;\r
+ \r
+ if (matcher.start() > 0) {\r
+ valueStart = value.substring(previousPosition,start); \r
+ } \r
+ String valueMiddle = value.substring(start, end);\r
+ valueEnd = "";\r
+ if (matcher.end() < value.length()) {\r
+ valueEnd = value.substring(end);\r
+ }\r
+ \r
+ previousPosition = end;\r
+ if (!valueStart.equals("")) {\r
+ QDomText startText = doc.createTextNode(valueStart);\r
+ fragment.appendChild(startText);\r
+ }\r
+ \r
+ QDomElement hilight = doc.createElement("en-hilight");\r
+ hilight.appendChild(doc.createTextNode(valueMiddle));\r
+ fragment.appendChild(hilight);\r
+ }\r
+ if (matchFound) {\r
+ if (previousPosition != value.length()) {\r
+ QDomText endText = doc.createTextNode(valueEnd);\r
+ fragment.appendChild(endText);\r
+ }\r
+ newNodes.add(fragment);\r
+ oldNodes.add(node);\r
+ }\r
+ }\r
+ \r
+ \r
+ private String buildRegex() {\r
+ StringBuffer regex = new StringBuffer();\r
+ \r
+ for (int i=0; i<terms.size(); i++) {\r
+ String term = terms.get(i);\r
+ if (term.indexOf("*") > -1) {\r
+ term = term.replace("*", "");\r
+ } else {\r
+ term = "\\b"+term+"\\b";\r
+ }\r
+ regex.append(term);\r
+ if (i<terms.size()-1)\r
+ regex.append("|"); \r
+ }\r
+ \r
+ return regex.toString();\r
+ }\r
+ \r
+\r
+}\r
--- /dev/null
+/*
+ * This file is part of NeverNote
+ * 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.xml;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.StringReader;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+import cx.fbn.nevernote.Global;
+
+public class XMLNoteRepair {
+ public boolean saveInvalidXML;
+
+ public String parse(String xmlData, boolean validate) {
+ saveInvalidXML = false;
+ InputSource is = new InputSource();
+ is.setCharacterStream(new StringReader(xmlData));
+ XMLNoteRepairHandler handler = new XMLNoteRepairHandler();
+
+ // Replace DTD with local copy in case we are not connected
+ File dtdFile = new File(Global.getDirectoryPath()+"xml/enml2.dtd");
+ String dtd = dtdFile.toURI().toString();
+ xmlData = xmlData.replace("<!DOCTYPE en-note SYSTEM \'http://xml.evernote.com/pub/enml2.dtd'>",
+ "<!DOCTYPE en-note SYSTEM \"" +dtd +"\">");
+ xmlData = xmlData.replace("<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">",
+ "<!DOCTYPE en-note SYSTEM \"" +dtd +"\">");
+
+ handler.setXml(xmlData);
+ is.setCharacterStream(new StringReader(handler.getXml()));
+
+ boolean fixed = false;
+ int i=0;
+ int max = 10;
+ if (validate)
+ max = 10000;
+ while (!fixed && i<max) {
+ try {
+ i++;
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ factory.setValidating(validate);
+ SAXParser parser = factory.newSAXParser();
+ parser.parse(is, handler);
+ fixed = true;
+ } catch (EnmlException e) {
+ String message = e.getMessage();
+ saveInvalidXML = true;
+ //System.out.println("ENML Exception: " +message);
+ boolean found = false;
+ int endAttribute = message.indexOf(" must be declared for element type ");
+ if (message.startsWith("Attribute ") && endAttribute > -1) {
+ String attribute = message.substring(11, endAttribute-1);
+ String element = message.substring(message.indexOf("\"", endAttribute+3));
+ element = element.replace("\"", "");
+ element = element.substring(0,element.length()-1);
+ Global.addInvalidAttribute(element, attribute);
+ handler.stripAttribute(attribute, e.getLineNumber(), e.getColumnNumber());
+ is.setCharacterStream(new StringReader(handler.getXml()));
+ found = true;
+ }
+ int endElement = message.indexOf(" must be declared.");
+ if (message.startsWith("Element type") && endElement > -1) {
+ String element = message.substring(14,endElement-1);
+ Global.addInvalidElement(element);
+ handler.renameElement(element, e.getLineNumber(), e.getColumnNumber());
+ is.setCharacterStream(new StringReader(handler.getXml()));
+ found = true;
+ }
+ if (!found)
+ System.err.println("New enml validation error: " +e.getMessage() +" Line:" +e.getLineNumber() +" Column:" +e.getColumnNumber());
+ } catch (SAXParseException e) {
+ System.err.println("SAXParse Exception - Attempt #"+i +" "+e.getMessage());
+ handler.repair(e.getLineNumber(), e.getColumnNumber());
+ is.setCharacterStream(new StringReader(handler.getXml()));
+ if (validate) {
+ System.err.println("Error validating ENML2 DTD");
+ System.exit(16);
+ }
+ } catch (SAXException e) {
+ System.err.append("SAXException");
+ e.printStackTrace();
+ } catch (ParserConfigurationException e) {
+ System.err.println("Parser Config Error");
+ e.printStackTrace();
+ } catch (IOException e) {
+ System.err.println("IO Exception");
+ e.printStackTrace();
+ }
+ }
+ if (!fixed)
+ return null;
+ else {
+ // Replace DTD with online copy
+ xmlData = handler.getXml();
+ xmlData = xmlData.replace("<!DOCTYPE en-note SYSTEM \"" +dtd +"\">", "<!DOCTYPE en-note SYSTEM \'http://xml.evernote.com/pub/enml2.dtd'>");
+ return xmlData;
+ }
+ }
+}
--- /dev/null
+/*
+ * This file is part of NeverNote
+ * 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.xml;
+
+import java.util.Vector;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.DefaultHandler;
+
+
+public class XMLNoteRepairHandler extends DefaultHandler {
+
+ private final Vector<String> tagQueue;
+ private final Vector<String> xml;
+
+ public XMLNoteRepairHandler() {
+ xml = new Vector<String>();
+ tagQueue = new Vector<String>();
+ }
+
+ public void setXml(String x) {
+ // First, change the <hr> tags. That is usually a problem
+ String val = x.toString().replace("<HR>", "<hr/>");
+ val = val.replace("<hr>", "<hr/>");
+ val = val.replace("</HR>", "");
+ x = val.replace("</hr>", "");
+
+ // Another problem is a bad closing bracket
+ x = x.replace("//>", "/>");
+
+ // Onother oddball is a bad br
+ x = x.replace("<br/></br>", "<br/>");
+
+ int pos = 0;
+ for (; pos > -1;) {
+ String line;
+ pos = x.indexOf('\n');
+ if (pos > -1) {
+ line = new String(x.substring(0,pos));
+ x = x.substring(pos+1);
+ } else
+ line = x;
+ xml.add(line);
+ }
+ }
+
+ public String getXml() {
+ StringBuffer b = new StringBuffer();
+ for (int i=0; i<xml.size(); i++) {
+ b.append(xml.get(i));
+ if (i<xml.size()-1)
+ b.append('\n');
+ }
+ return b.toString();
+ }
+
+ public void reset() {
+ tagQueue.clear();
+ }
+
+ public void stripAttribute(String attribute, int line, int column) {
+ String repair = new String(xml.get(line-1));
+
+ int pos = column-1;
+ String fragment = repair.substring(0,pos);
+ int startPos = fragment.lastIndexOf("<");
+ fragment = fragment.substring(startPos);
+
+
+ // Now we have the fragment, remove the attribute
+ int attributeStart = fragment.indexOf(attribute)-1;
+ int endPos = fragment.indexOf("\"", attributeStart+1);
+ endPos = fragment.indexOf("\"", endPos+1)+1;
+ if (endPos == -1)
+ endPos = fragment.length()-1;
+
+ String repairedFragment = fragment.substring(0,attributeStart) +fragment.substring(endPos);
+ repair = repair.substring(0,startPos)+ repairedFragment+ repair.substring(column-1);
+
+ xml.set(line-1, repair);
+ }
+
+
+ public void renameElement(String element, int line, int column) {
+ for (int i=0; i<xml.size(); i++) {
+ String value = xml.get(i);
+ value = value.replace("<"+element, "<span");
+ value = value.replace("</"+element, "</span");
+ xml.set(i, value);
+ }
+ }
+
+ public String repair(int line, int column) {
+ StringBuffer repair = new StringBuffer(xml.get(line-1));
+ int pos = column-1;
+ if (pos > 0) {
+ for (int i=pos; i>=0; i--) {
+ if (repair.charAt(i) == '<') {
+ pos = i;
+ i = -1;
+ }
+ }
+ if (pos > 0) {
+ repair.insert(pos, "</" +tagQueue.get(tagQueue.size()-1) +">");
+ }
+ xml.remove(line-1);
+ xml.add(line-1, repair.toString());
+ }
+
+
+ return getXml();
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException {
+ tagQueue.add(qName);
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ String endVal = tagQueue.lastElement();
+ if (endVal.equals(qName)) {
+ tagQueue.remove(tagQueue.size()-1);
+ }
+ }
+
+
+ @Override
+ public void error(SAXParseException e)
+ throws EnmlException
+ {
+ Exception exception = new Exception();
+ EnmlException e1 = new EnmlException(e.getMessage(), e.getPublicId(), e.getSystemId(), e.getLineNumber(), e.getColumnNumber(), exception);
+ throw e1;
+ }
+
+ @Override
+ public void warning(SAXParseException e)
+ throws SAXParseException
+ {
+ System.out.println("---------- WARNING ------------- ");
+ throw e;
+ }
+
+
+}