OSDN Git Service

- Correct issue with importing when not a premium member.
[neighbornote/NeighborNote.git] / src / cx / fbn / nevernote / sql / NoteTable.java
index 1d12b07..f19deee 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
- * This file is part of NeverNote \r
+ * This file is part of NixNote \r
  * Copyright 2009 Randy Baumgarte\r
  * \r
  * This file may be licensed under the terms of of the\r
@@ -27,6 +27,8 @@ import java.util.ArrayList;
 import java.util.HashMap;\r
 import java.util.List;\r
 \r
+import org.apache.commons.lang3.StringEscapeUtils;\r
+\r
 import com.evernote.edam.type.Note;\r
 import com.evernote.edam.type.NoteAttributes;\r
 import com.evernote.edam.type.Resource;\r
@@ -38,6 +40,7 @@ import com.trolltech.qt.gui.QPixmap;
 \r
 import cx.fbn.nevernote.Global;\r
 import cx.fbn.nevernote.evernote.EnmlConverter;\r
+import cx.fbn.nevernote.evernote.NoteMetadata;\r
 import cx.fbn.nevernote.sql.driver.NSqlQuery;\r
 import cx.fbn.nevernote.utilities.ApplicationLogger;\r
 import cx.fbn.nevernote.utilities.Pair;\r
@@ -63,12 +66,11 @@ public class NoteTable {
                noteTagsTable = new NoteTagsTable(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
+               //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
@@ -85,7 +87,7 @@ public class NoteTable {
         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
+//        noteResourceTable.createTable();     \r
        }\r
        // Drop the table\r
        public void dropTable() {\r
@@ -128,7 +130,6 @@ public class NoteTable {
                if (isDirty) {\r
                        EnmlConverter enml = new EnmlConverter(logger);\r
                        query.bindValue(":content", enml.fixEnXMLCrap(enml.fixEnMediaCrap(n.getContent())));\r
-                       enml = null;\r
                }\r
                else\r
                        query.bindValue(":content", n.getContent());\r
@@ -150,6 +151,16 @@ public class NoteTable {
                        query.bindValue(":attributeSource", n.getAttributes().getSource());\r
                        query.bindValue(":attributeSourceUrl", n.getAttributes().getSourceURL());\r
                        query.bindValue(":attributeSourceApplication", n.getAttributes().getSourceApplication());\r
+               } else {\r
+                       created = new StringBuilder(simple.format(n.getCreated()));     \r
+                       query.bindValue(":attributeSubjectDate", created.toString());\r
+                       query.bindValue(":attributeLatitude", 0.0);\r
+                       query.bindValue(":attributeLongitude", 0.0);\r
+                       query.bindValue(":attributeAltitude", 0.0);\r
+                       query.bindValue(":attributeAuthor", "");\r
+                       query.bindValue(":attributeSource", "");\r
+                       query.bindValue(":attributeSourceUrl", "");\r
+                       query.bindValue(":attributeSourceApplication", "");\r
                }\r
                query.bindValue(":indexNeeded", true);\r
                query.bindValue(":isExpunged", false);\r
@@ -164,60 +175,56 @@ public class NoteTable {
                        for (int i=0; i<n.getTagGuids().size(); i++) \r
                                noteTagsTable.saveNoteTag(n.getGuid(), n.getTagGuids().get(i));\r
                }\r
-               created = null;\r
-               updated = null;\r
-               deleted = null;\r
-               query = null;\r
-               simple = null;\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
+               if (getQueryWithContent == null) {\r
+                       getQueryWithContent = new NSqlQuery(db.getConnection());\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
+                                       +"attributeContentClass, "\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
                \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
+               if (getQueryWithoutContent == null) {\r
+                       getQueryWithoutContent = new NSqlQuery(db.getConnection());\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
+                                       +"attributeContentClass"\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
                }\r
-               if (!getAllQueryWithoutContent.prepare("Select "\r
+                       \r
+               if (getAllQueryWithoutContent == null) {\r
+                       getAllQueryWithoutContent = new NSqlQuery(db.getConnection());\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
+                               +"attributeAuthor, attributeSource, attributeSourceUrl, attributeSourceApplication, "\r
+                               +"attributeContentClass "\r
                                +" from Note where isExpunged = false")) {\r
-                                       logger.log(logger.EXTREME, "Note SQL select prepare without content has failed.");\r
+                               logger.log(logger.EXTREME, "Note SQL select prepare without content has failed.");\r
                                        logger.log(logger.MEDIUM, getQueryWithoutContent.lastError());\r
+                       }\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
-               query.next();\r
-               return query.valueString(0);\r
-       }\r
+\r
        // Get a note's content in blob format for index.\r
        public String getNoteContentNoUTFConversion(String guid) {\r
                NSqlQuery query = new NSqlQuery(db.getConnection());\r
@@ -229,6 +236,8 @@ public class NoteTable {
        }\r
        // Get a note by Guid\r
        public Note getNote(String noteGuid, boolean loadContent, boolean loadResources, boolean loadRecognition, boolean loadBinary, boolean loadTags) {\r
+\r
+//             extractMetadata("otherKey:{values};baumgarte:{titleColor=fff;pinned=true;};finalKey:{values1);");\r
                if (noteGuid == null)\r
                        return null;\r
                if (noteGuid.trim().equals(""))\r
@@ -256,6 +265,7 @@ public class NoteTable {
                }\r
                Note n = mapNoteFromQuery(query, loadContent, loadResources, loadRecognition, loadBinary, loadTags);\r
                n.setContent(fixCarriageReturn(n.getContent()));\r
+               n.getAttributes().setContentClassIsSet(false);\r
                return n;\r
        }\r
        // Get a note by Guid\r
@@ -263,7 +273,6 @@ public class NoteTable {
                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
@@ -297,31 +306,67 @@ public class NoteTable {
                na.setSource(query.valueString(13));\r
                na.setSourceURL(query.valueString(14));\r
                na.setSourceApplication(query.valueString(15));\r
+               na.setContentClass(query.valueString(16));\r
                \r
                if (loadTags) {\r
-                       n.setTagGuids(noteTagsTable.getNoteTags(n.getGuid()));\r
+                       List<String> tagGuids = noteTagsTable.getNoteTags(n.getGuid());\r
                        List<String> tagNames = new ArrayList<String>();\r
-                       TagTable tagTable = new TagTable(logger, db);\r
-                       for (int i=0; i<n.getTagGuids().size(); i++) {\r
-                               String currentGuid = n.getTagGuids().get(i);\r
+                       TagTable tagTable = db.getTagTable();\r
+                       for (int i=0; i<tagGuids.size(); i++) {\r
+                               String currentGuid = tagGuids.get(i);\r
                                Tag tag = tagTable.getTag(currentGuid);\r
-                               tagNames.add(tag.getName());\r
+                               if (tag.getName() != null)\r
+                                       tagNames.add(tag.getName());\r
+                               else\r
+                                       tagNames.add("");\r
                        }\r
+\r
                        n.setTagNames(tagNames);\r
+                       n.setTagGuids(tagGuids);                \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
+               String unicode =  codec.fromUnicode(query.valueString(17)).toString();\r
+\r
+               // This is a hack.  Basically I need to convert HTML Entities to "normal" text, but if I\r
+               // convert the &lt; character to < it will mess up the XML parsing.  So, to get around this\r
+               // I am "bit stuffing" the &lt; to &&lt; so StringEscapeUtils doesn't unescape it.  After\r
+               // I'm done I convert it back.\r
+               StringBuffer buffer = new StringBuffer(unicode);\r
+               if (Global.enableHTMLEntitiesFix && unicode.indexOf("&#") > 0) {\r
+                       unicode = query.valueString(17);\r
+                       //System.out.println(unicode);\r
+                       //unicode = unicode.replace("&lt;", "&_lt;");\r
+                       //unicode = codec.fromUnicode(StringEscapeUtils.unescapeHtml(unicode)).toString();\r
+                       //unicode = unicode.replace("&_lt;", "&lt;");\r
+                       //System.out.println("************************");\r
+                       int j=1;\r
+                       for (int i=buffer.indexOf("&#"); i != -1 && buffer.indexOf("&#", i)>0; i=buffer.indexOf("&#",i+1)) {\r
+                               j = buffer.indexOf(";",i)+1;\r
+                               if (i<j) {\r
+                                       String entity = buffer.substring(i,j).toString();\r
+                                       int len = entity.length()-1;\r
+                                       String tempEntity = entity.substring(2, len);\r
+                                       try {\r
+                                               Integer.parseInt(tempEntity);\r
+                                               entity = codec.fromUnicode(StringEscapeUtils.unescapeHtml4(entity)).toString();\r
+                                               buffer.delete(i, j);\r
+                                               buffer.insert(i, entity);\r
+                                       } catch (Exception e){ }\r
+                                       \r
+                               }\r
+                       } \r
+               } \r
+                       \r
+               n.setContent(unicode);\r
 //                     n.setContent(query.valueString(16).toString());\r
                        \r
-                       String contentHash = query.valueString(17);\r
+                       String contentHash = query.valueString(18);\r
                        if (contentHash != null)\r
                                n.setContentHash(contentHash.getBytes());\r
-                       n.setContentLength(new Integer(query.valueString(18)));\r
+                       n.setContentLength(new Integer(query.valueString(19)));\r
                }\r
                if (loadResources)\r
                        n.setResources(noteResourceTable.getNoteResources(n.getGuid(), loadBinary));\r
@@ -342,6 +387,7 @@ public class NoteTable {
        }\r
        // Update a note's title\r
        public void updateNoteTitle(String guid, String title) {\r
+               logger.log(logger.HIGH, "Entering NoteTable.updateNoteTitle");\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
@@ -355,9 +401,11 @@ public class NoteTable {
                        logger.log(logger.EXTREME, "Update note title has failed.");\r
                        logger.log(logger.MEDIUM, query.lastError());\r
                }\r
+               logger.log(logger.HIGH, "Leaving NoteTable.updateNoteTitle");\r
        }\r
        // Update a note's creation date\r
        public void updateNoteCreatedDate(String guid, QDateTime date) {\r
+               logger.log(logger.HIGH, "Entering NoteTable.updateNoteCreatedDate");\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
@@ -373,9 +421,11 @@ public class NoteTable {
                        logger.log(logger.EXTREME, "Update note creation date has failed.");\r
                        logger.log(logger.MEDIUM, query.lastError());\r
                }\r
+               logger.log(logger.HIGH, "Leaving NoteTable.updateNoteCreatedDate");\r
        }\r
        // Update a note's creation date\r
        public void updateNoteAlteredDate(String guid, QDateTime date) {\r
+               logger.log(logger.HIGH, "Entering NoteTable.updateNoteAlteredDate");\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
@@ -391,9 +441,11 @@ public class NoteTable {
                        logger.log(logger.EXTREME, "Update note altered date has failed.");\r
                        logger.log(logger.MEDIUM, query.lastError());\r
                }\r
+               logger.log(logger.HIGH, "Leaving NoteTable.updateNoteAlteredDate");\r
        }\r
        // Update a note's creation date\r
        public void updateNoteSubjectDate(String guid, QDateTime date) {\r
+               logger.log(logger.HIGH, "Entering NoteTable.updateNoteSubjectDate");\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
@@ -409,9 +461,11 @@ public class NoteTable {
                        logger.log(logger.EXTREME, "Update note subject date date has failed.");\r
                        logger.log(logger.MEDIUM, query.lastError());\r
                }\r
+               logger.log(logger.HIGH, "Leaving NoteTable.updateNoteSubjectDate");\r
        }\r
        // Update a note's creation date\r
        public void updateNoteAuthor(String guid, String author) {\r
+               logger.log(logger.HIGH, "Entering NoteTable.updateNoteSubject");\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
@@ -427,10 +481,11 @@ public class NoteTable {
                        logger.log(logger.EXTREME, "Update note author has failed.");\r
                        logger.log(logger.MEDIUM, query.lastError());\r
                }\r
-               \r
+               logger.log(logger.HIGH, "Leaving NoteTable.updateNoteSubject");\r
        }\r
        // Update a note's geo tags\r
        public void updateNoteGeoTags(String guid, Double lon, Double lat, Double alt) {\r
+               logger.log(logger.HIGH, "Entering NoteTable.updateNoteGeoTags");\r
                NSqlQuery query = new NSqlQuery(db.getConnection());\r
                boolean check = query.prepare("Update Note set attributeLongitude=:longitude, "+\r
                                "attributeLatitude=:latitude, attributeAltitude=:altitude, isDirty=true where guid=:guid");\r
@@ -449,10 +504,12 @@ public class NoteTable {
                        logger.log(logger.EXTREME, "Update note geo tag has failed.");\r
                        logger.log(logger.MEDIUM, query.lastError());\r
                }\r
+               logger.log(logger.HIGH, "Leaving NoteTable.updateNoteGeoTags");\r
                \r
        }\r
        // Update a note's creation date\r
        public void updateNoteSourceUrl(String guid, String url) {\r
+               logger.log(logger.HIGH, "Entering NoteTable.updateNoteSourceUrl");\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
@@ -468,10 +525,11 @@ public class NoteTable {
                        logger.log(logger.EXTREME, "Update note url has failed.");\r
                        logger.log(logger.MEDIUM, query.lastError());\r
                }\r
-               \r
+               logger.log(logger.HIGH, "Leaving NoteTable.updateNoteSourceUrl");\r
        }\r
        // Update the notebook that a note is assigned to\r
        public void updateNoteNotebook(String guid, String notebookGuid, boolean expungeFromRemote) {\r
+               logger.log(logger.HIGH, "Entering NoteTable.updateNoteNotebook");\r
                String currentNotebookGuid = new String("");\r
                \r
                \r
@@ -500,10 +558,12 @@ public class NoteTable {
                if (!check) {\r
                        logger.log(logger.EXTREME, "Update note notebook has failed.");\r
                        logger.log(logger.MEDIUM, query.lastError());\r
-               };\r
+               }\r
+               logger.log(logger.HIGH, "Leaving NoteTable.updateNoteNotebook");\r
        }\r
        // Update a note's title\r
        public void updateNoteContent(String guid, String content) {\r
+               logger.log(logger.HIGH, "Entering NoteTable.updateNoteContent");\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
                                " thumbnailneeded=true where guid=:guid");\r
@@ -512,6 +572,9 @@ public class NoteTable {
                        logger.log(logger.MEDIUM, query.lastError());\r
                }\r
                \r
+//             QTextCodec codec = QTextCodec.codecForLocale();\r
+//             codec = QTextCodec.codecForName("UTF-8");\r
+//             query.bindValue(":content", codec.fromUnicode(content).toString());\r
                query.bindValue(":content", content);\r
                query.bindValue(":guid", guid);\r
 \r
@@ -520,10 +583,12 @@ public class NoteTable {
                        logger.log(logger.EXTREME, "Update note content has failed.");\r
                        logger.log(logger.MEDIUM, query.lastError());\r
                }\r
+               logger.log(logger.HIGH, "Leaving NoteTable.updateNoteContent");\r
        }\r
 \r
        // Delete a note\r
        public void deleteNote(String guid) {\r
+               logger.log(logger.HIGH, "Entering NoteTable.deleteNote");\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
@@ -531,12 +596,14 @@ public class NoteTable {
                        logger.log(logger.MEDIUM, "Note delete failed.");\r
                        logger.log(logger.MEDIUM, query.lastError());\r
                }\r
+               logger.log(logger.HIGH, "Leaving NoteTable.deleteNote");\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=:reset, 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
+               query.bindValue(":reset", "1969-12-31 19:00:00");\r
                if (!query.exec()) {\r
                        logger.log(logger.MEDIUM, "Note restore failed.");\r
                        logger.log(logger.MEDIUM, query.lastError());\r
@@ -544,6 +611,7 @@ public class NoteTable {
        }\r
        // Purge a note (actually delete it instead of just marking it deleted)\r
        public void expungeNote(String guid, boolean permanentExpunge, boolean needsSync) {\r
+               logger.log(logger.HIGH, "Entering NoteTable.expungeNote");\r
                \r
                if (!permanentExpunge) {\r
                        hideExpungedNote(guid, needsSync);\r
@@ -552,9 +620,9 @@ public class NoteTable {
                \r
                \r
         NSqlQuery note = new NSqlQuery(db.getConnection());\r
-        NSqlQuery resources = new NSqlQuery(db.getConnection());\r
+        NSqlQuery resources = new NSqlQuery(db.getResourceConnection());\r
         NSqlQuery tags = new NSqlQuery(db.getConnection());\r
-        NSqlQuery words = new NSqlQuery(db.getConnection());\r
+        NSqlQuery words = new NSqlQuery(db.getIndexConnection());\r
         \r
                note.prepare("Delete from Note where guid=:guid");\r
                resources.prepare("Delete from NoteResources where noteGuid=:guid");\r
@@ -579,6 +647,7 @@ public class NoteTable {
                        logger.log(logger.MEDIUM, "Note tags delete failed.");\r
                        logger.log(logger.MEDIUM, tags.lastError());\r
                }\r
+\r
                if (!words.exec()) {\r
                        logger.log(logger.MEDIUM, "Word delete failed.");\r
                        logger.log(logger.MEDIUM, words.lastError());\r
@@ -587,19 +656,27 @@ public class NoteTable {
                        DeletedTable deletedTable = new DeletedTable(logger, db);\r
                        deletedTable.addDeletedItem(guid, "Note");\r
                }\r
-\r
+               logger.log(logger.HIGH, "Leaving NoteTable.expungeNote");\r
        }\r
+       // Purge a bunch of notes based upon the notebook\r
+       public void expungeNotesByNotebook(String notebookGuid, boolean permanentExpunge, boolean needsSync) {\r
+               List<String> notes = getNotesByNotebook(notebookGuid);\r
+               for (int i=0; i<notes.size(); i++) {\r
+                       expungeNote(notes.get(i), permanentExpunge, needsSync);\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 resources = new NSqlQuery(db.getResourceConnection());\r
         NSqlQuery tags = new NSqlQuery(db.getConnection());\r
-        NSqlQuery words = new NSqlQuery(db.getConnection());\r
+        NSqlQuery words = new NSqlQuery(db.getIndexConnection());\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
+//             words.prepare("Delete from words where guid=:guid");\r
 \r
                note.bindValue(":guid", guid);\r
                resources.bindValue(":guid", guid);\r
@@ -619,10 +696,11 @@ public class NoteTable {
                        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
+//             System.out.println("Hiding Note: Deleting words");\r
+//             if (!words.exec()) {\r
+//                     logger.log(logger.MEDIUM, "Word delete failed.");\r
+//                     logger.log(logger.MEDIUM, words.lastError());\r
+//             }\r
                if (needsSync) {\r
                        DeletedTable deletedTable = new DeletedTable(logger, db);\r
                        deletedTable.addDeletedItem(guid, "Note");\r
@@ -632,19 +710,30 @@ public class NoteTable {
                \r
        // Purge all deleted notes;\r
        public void expungeAllDeletedNotes() {\r
+               logger.log(logger.HIGH, "Entering NoteTable.expungeAllDeletedNotes");\r
                NSqlQuery query = new NSqlQuery(db.getConnection());\r
                query.exec("select guid, updateSequenceNumber from note where active = false");\r
+               List<String> guids = new ArrayList<String>();\r
+               List<Integer> usns = new ArrayList<Integer>();\r
                while (query.next()) {\r
-                       String guid = query.valueString(0);\r
+                       guids.add(query.valueString(0));\r
                        Integer usn = new Integer(query.valueString(1));\r
+                       usns.add(usn);\r
+               }\r
+               \r
+               for (int i=0; i<guids.size(); i++) {\r
+                       Integer usn = usns.get(i);\r
+                       String guid = guids.get(i);\r
                        if (usn == 0)\r
                                expungeNote(guid, true, false);\r
                        else\r
                                expungeNote(guid, false, true);\r
                }\r
+               logger.log(logger.HIGH, "Leaving NoteTable.expungeAllDeletedNotes");\r
        }\r
        // Update the note sequence number\r
        public void updateNoteSequence(String guid, int sequence) {\r
+               logger.log(logger.HIGH, "Entering NoteTable.updateNoteSequence");\r
                boolean check;\r
         NSqlQuery query = new NSqlQuery(db.getConnection());\r
                check = query.prepare("Update Note set updateSequenceNumber=:sequence where guid=:guid");\r
@@ -657,13 +746,18 @@ public class NoteTable {
                        logger.log(logger.MEDIUM, "Note sequence update failed.");\r
                        logger.log(logger.MEDIUM, query.lastError());\r
                } \r
+               logger.log(logger.HIGH, "Leaving NoteTable.updateNoteSequence");\r
        }\r
        // Update the note Guid\r
        public void updateNoteGuid(String oldGuid, String newGuid) {\r
+               logger.log(logger.HIGH, "Entering NoteTable.updateNoteGuid");\r
                boolean check;\r
         NSqlQuery query = new NSqlQuery(db.getConnection());\r
-               query.prepare("Update Note set guid=:newGuid where guid=:oldGuid");\r
+        NSqlQuery resQuery = new NSqlQuery(db.getResourceConnection());\r
+        NSqlQuery wordQuery = new NSqlQuery(db.getIndexConnection());\r
+               query.prepare("Update Note set guid=:newGuid, original_guid=:original_guid where guid=:oldGuid");\r
 \r
+               query.bindValue(":original_guid", oldGuid);\r
                query.bindValue(":newGuid", newGuid);\r
                query.bindValue(":oldGuid", oldGuid);\r
 \r
@@ -682,31 +776,39 @@ public class NoteTable {
                        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
+               wordQuery.prepare("Update words set guid=:newGuid where guid=:oldGuid");\r
+               wordQuery.bindValue(":newGuid", newGuid);\r
+               wordQuery.bindValue(":oldGuid", oldGuid);\r
+               wordQuery.exec();\r
                if (!check) {\r
                        logger.log(logger.MEDIUM, "Note guid update failed for Words.");\r
-                       logger.log(logger.MEDIUM, query.lastError());\r
+                       logger.log(logger.MEDIUM, wordQuery.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
+               resQuery.prepare("Update noteresources set noteguid=:newGuid where noteguid=:oldGuid");\r
+               resQuery.bindValue(":newGuid", newGuid);\r
+               resQuery.bindValue(":oldGuid", oldGuid);\r
+               resQuery.exec();\r
                if (!check) {\r
                        logger.log(logger.MEDIUM, "Note guid update failed for noteresources.");\r
-                       logger.log(logger.MEDIUM, query.lastError());\r
+                       logger.log(logger.MEDIUM, resQuery.lastError());\r
                }\r
+               logger.log(logger.HIGH, "Leaving NoteTable.updateNoteGuid");\r
        }\r
        // Update a note\r
-       public void updateNote(Note n, boolean isNew) {\r
-               boolean isExpunged = isNoteExpunged(n.getGuid());\r
-               int titleColor = getNoteTitleColor(n.getGuid());\r
-               expungeNote(n.getGuid(), !isExpunged, false);\r
+       public void updateNote(Note n) {\r
+               logger.log(logger.HIGH, "Entering NoteTable.updateNote");\r
+               NoteMetadata meta = getNoteMetaInformation(n.getGuid());\r
+               String originalGuid = findAlternateGuid(n.getGuid());\r
+               expungeNote(n.getGuid(), true, false);\r
                addNote(n, false);\r
-               if (titleColor != -1)\r
-                       setNoteTitleColor(n.getGuid(), titleColor);\r
+               if (n!=null) {\r
+                       updateNoteMetadata(meta);\r
+               }\r
+               if (originalGuid != null) {\r
+                       updateNoteGuid(n.getGuid(), originalGuid);\r
+                       updateNoteGuid(originalGuid, n.getGuid());\r
+               }\r
+               logger.log(logger.HIGH, "Leaving NoteTable.updateNote");\r
        }\r
        // Does a note exist?\r
        public boolean exists(String guid) {\r
@@ -736,12 +838,31 @@ public class NoteTable {
                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
+       // This is a convience method to check if a note exists & update/create based upon it\r
+       public void syncNote(Note note) {\r
+               logger.log(logger.HIGH, "Entering NoteTable.syncNote");\r
+               // If we got the note from Evernote we use its \r
+               // metadata instead of the local copy.\r
+               NoteMetadata meta = null;\r
+               if (note.getAttributes() != null && note.getAttributes().getSourceApplication() != null) {\r
+                       meta = extractMetadata(note.getAttributes().getSourceApplication());\r
+               } else \r
+                       meta = getNoteMetaInformation(note.getGuid());\r
+               \r
+               // Now, if the note exists we simply update it.  Otherwise we\r
+               // add a new note.\r
+               if (exists(note.getGuid())) {\r
+                       updateNote(note);\r
+               }\r
                else\r
-                       addNote(tag, isDirty);\r
+                       addNote(note, false);\r
+               \r
+               // If we have metadata, we write it out.\r
+               if (meta != null) {\r
+                       meta.setGuid(note.getGuid());\r
+                       updateNoteMetadata(meta);\r
+               }\r
+               logger.log(logger.HIGH, "Leaving NoteTable.syncNote");\r
        }\r
        // Get a list of notes that need to be updated\r
        public List <Note> getDirty() {\r
@@ -769,6 +890,7 @@ public class NoteTable {
                        tempNote = getNote(index.get(i), true,true,false,true,true);\r
                        notes.add(tempNote);\r
                }\r
+               logger.log(logger.LOW, "Dirty local notes: " +new Integer(notes.size()).toString());\r
                return notes;   \r
        }\r
        // Get a list of notes that need to be updated\r
@@ -797,6 +919,7 @@ public class NoteTable {
                        tempNote = getNote(index.get(i), true,true,false,true,true);\r
                        notes.add(tempNote);\r
                }\r
+               logger.log(logger.LOW, "Dirty linked local notes: " +new Integer(notes.size()).toString());\r
                return notes;   \r
        }\r
        // Get a list of notes that need to be updated\r
@@ -827,6 +950,7 @@ public class NoteTable {
                        tempNote = getNote(index.get(i), true,true,false,true,true);\r
                        notes.add(tempNote);\r
                }\r
+               logger.log(logger.LOW, "Dirty local notes for notebook " +notebookGuid +": " +new Integer(notes.size()).toString());\r
                return notes;   \r
        }\r
        // Get a list of notes that need to be updated\r
@@ -871,28 +995,10 @@ public class NoteTable {
 \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
+\r
        // Reset the dirty bit\r
        public void  resetDirtyFlag(String guid) {\r
+               logger.log(logger.LOW, "Resetting dirty flag for " +guid);\r
                NSqlQuery query = new NSqlQuery(db.getConnection());\r
                \r
                query.prepare("Update note set isdirty=false where guid=:guid");\r
@@ -921,7 +1027,9 @@ public class NoteTable {
        public List<Note> getAllNotes() {\r
                List<Note> notes = new ArrayList<Note>();\r
                prepareQueries();\r
-               boolean check;                                  \r
+               boolean check;  \r
+               if (getAllQueryWithoutContent == null) \r
+                       prepareQueries();\r
         NSqlQuery query = getAllQueryWithoutContent;\r
                check = query.exec();\r
                if (!check)\r
@@ -946,6 +1054,42 @@ public class NoteTable {
                query.exec("select count(guid) from note where isDirty=true and isExpunged = false");\r
                query.next(); \r
                int returnValue = new Integer(query.valueString(0));\r
+               logger.log(logger.LOW, "dirty count: " +returnValue);\r
+               //query.exec("select count(guid) from note where isDirty=true and Active = 0 and isExpunged = false");\r
+               //query.next(); \r
+               //logger.log(logger.LOW, "dirty count (active only): " +query.valueString(0));\r
+               //query.exec("Select count(guid) from Note where isDirty = true and isExpunged = false and notebookGuid not in (select guid from notebook where local = true or linked = true)");\r
+               //query.next(); \r
+               //logger.log(logger.LOW, "dirty count (no l&l notebooks): " +query.valueString(0));\r
+               //logger.log(logger.LOW, "Beginning stack trace");\r
+               //logger.log(logger.LOW, Thread.currentThread().getStackTrace());\r
+\r
+               //logger.log(logger.LOW, "*************************");\r
+               //logger.log(logger.LOW, "*** DIRTY RECORD DUMP ***");\r
+               //logger.log(logger.LOW, "*************************");\r
+               //List<Note> recs = getDirty();\r
+               //for (int i=0; i<recs.size(); i++) {\r
+                       //Note n = getNote(recs.get(i).getGuid(), true, true, true, false, true);\r
+                       //logger.log(logger.LOW, "-- Begin Record ---");\r
+                       //logger.log(logger.LOW, "Guid: " +n.getGuid());\r
+                       //logger.log(logger.LOW, "Title: " +n.getTitle());\r
+                       //logger.log(logger.LOW, "Active: " +n.isActive());\r
+                       //logger.log(logger.LOW, "USN: " +n.getUpdateSequenceNum());\r
+                       //logger.log(logger.LOW, "Date Created: " +n.getCreated());\r
+                       //logger.log(logger.LOW, "Date Updated: " +n.getUpdated());\r
+                       //logger.log(logger.LOW, "Date Deleted: " +n.getDeleted());\r
+                       //logger.log(logger.LOW, "Resource Count: " +n.getResourcesSize());\r
+                       //for (int j=0; j<n.getResourcesSize(); j++) {\r
+                               //Resource r = n.getResources().get(j);\r
+                               //logger.log(logger.LOW, "Resource " +j +": " +r.getGuid());\r
+                               //logger.log(logger.LOW, "Active: " +r.isActive());\r
+                               //logger.log(logger.LOW, "USN: " +r.getUpdateSequenceNum());\r
+                       //}\r
+                       //logger.log(logger.LOW, "-- End Record ---");\r
+               //}\r
+               //logger.log(logger.LOW, "*****************************");\r
+               //logger.log(logger.LOW, "*** End DIRTY RECORD DUMP ***");\r
+               //logger.log(logger.LOW, "*****************************");\r
                return returnValue;\r
        }\r
        // Count notes\r
@@ -984,7 +1128,7 @@ public class NoteTable {
        \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
+               NSqlQuery query = new NSqlQuery(db.getResourceConnection());\r
 /*             query.prepare("Select guid from NoteResources where noteGuid=:noteGuid and datahash=:hex");\r
                query.bindValue(":noteGuid", noteGuid);\r
                query.bindValue(":hex", hash);\r
@@ -1086,6 +1230,28 @@ public class NoteTable {
                return values;\r
        }\r
        \r
+       // Find a note based upon its title.\r
+       public List<Pair<String,String>> findNotesByTitle(String text) {\r
+               List<Pair<String,String>> results = new ArrayList<Pair<String,String>>();\r
+               boolean check;                  \r
+        NSqlQuery query = new NSqlQuery(db.getConnection());\r
+                                       \r
+               check = query.prepare("Select guid,title from Note where lower(title) like :title");\r
+               if (!check) \r
+                       logger.log(logger.EXTREME, "Note SQL prepare for search by title has failed: " +query.lastError().toString());\r
+               \r
+               query.bindValue(":title", "%"+text.toLowerCase()+"%");\r
+               query.exec();\r
+               // Get a list of the notes\r
+               while (query.next()) {\r
+                       Pair<String,String> p = new Pair<String,String>();\r
+                       p.setFirst(query.valueString(0));\r
+                       p.setSecond(query.valueString(1));                      \r
+                       results.add(p); \r
+               }       \r
+               return results;\r
+       }\r
+\r
        \r
        \r
        //********************************************************************************\r
@@ -1155,69 +1321,68 @@ public class NoteTable {
                }       \r
                return guids;   \r
        }\r
+\r
        \r
+       // Get note meta information\r
+       public void updateNoteMetadata(NoteMetadata meta) {\r
+        NSqlQuery query = new NSqlQuery(db.getConnection());\r
+               if (!query.prepare("Update Note set titleColor=:color, pinned=:pinned, attributeSourceApplication=:metaString where guid=:guid"))\r
+                       logger.log(logger.EXTREME, "Note SQL prepare has failed on updateNoteMetadata.");\r
+               query.bindValue(":color", meta.getColor());\r
+               query.bindValue(":pinned", meta.isPinned());\r
+               query.bindValue(":guid", meta.getGuid());\r
+               query.bindValue(":metaString", buildMetadataString(meta));\r
+               if (!query.exec()) \r
+                       logger.log(logger.EXTREME, "Note SQL exec has failed on updateNoteMetadata.");\r
+               return;\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
+       // Get all note meta information\r
+       public HashMap<String, NoteMetadata> getNotesMetaInformation() {\r
+               HashMap<String, NoteMetadata> returnValue = new HashMap<String, NoteMetadata>();\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
+               if (!query.exec("Select guid,titleColor, isDirty, pinned from Note"))\r
+                       logger.log(logger.EXTREME, "Note SQL retrieve has failed on getNoteMetaInformation.");\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
+                       NoteMetadata note = new NoteMetadata();\r
+                       note.setGuid(query.valueString(0));\r
+                       note.setColor(query.valueInteger(1));\r
+                       note.setDirty(query.valueBoolean(2, false));\r
+                       int pinned = query.valueInteger(3);\r
+                       if (pinned > 0) \r
+                               note.setPinned(true);\r
+                       returnValue.put(note.getGuid(), note); \r
                }       \r
 \r
                return returnValue;\r
        }\r
-       // Set a title color\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
-       // Get in individual note's title color\r
-       // Get the title color of all notes\r
-       public Integer getNoteTitleColor(String guid) {\r
-               List<Pair<String,Integer>> returnValue = new ArrayList<Pair<String,Integer>>();\r
+       // Get note meta information\r
+       public NoteMetadata getNoteMetaInformation(String guid) {\r
         NSqlQuery query = new NSqlQuery(db.getConnection());\r
                \r
-        query.prepare("Select titleColor from Note where titleColor != -1 and guid=:guid");\r
-        query.bindValue(":guid", guid);\r
-               if (!query.exec())\r
-                       logger.log(logger.EXTREME, "Note SQL retrieve has failed on getNoteTitleColor(guid).");\r
+               if (!query.prepare("Select guid,titleColor, isDirty, pinned from Note where guid=:guid")) {\r
+                       logger.log(logger.EXTREME, "Note SQL retrieve has failed on getNoteMetaInformation.");\r
+                       return null;\r
+               }\r
+               query.bindValue(":guid", guid);\r
+               query.exec();\r
 \r
-               Integer color = -1;\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
+                       NoteMetadata note = new NoteMetadata();\r
+                       note.setGuid(query.valueString(0));\r
+                       note.setColor(query.valueInteger(1));\r
+                       note.setDirty(query.valueBoolean(2, false));\r
+                       int pinned = query.valueInteger(3);\r
+                       if (pinned > 0) \r
+                               note.setPinned(true);\r
+                       return note;\r
                }       \r
 \r
-               \r
-               return color;\r
+               return null;\r
        }\r
        \r
        \r
@@ -1361,6 +1526,41 @@ public class NoteTable {
                return 0;       \r
        }\r
 \r
+       //***********************************************************************************\r
+       public String findAlternateGuid(String guid) {\r
+               boolean check;\r
+        NSqlQuery query = new NSqlQuery(db.getConnection());\r
+                                       \r
+               check = query.prepare("select guid from note where original_guid=:guid");\r
+               query.bindValue(":guid", guid);\r
+               check = query.exec();\r
+               if (!check) \r
+                       logger.log(logger.EXTREME, "Note SQL findAlternateguid query failed: " +query.lastError().toString());\r
+               \r
+               if (query.next()) {\r
+                       return query.valueString(0); \r
+               }\r
+\r
+               return null;    \r
+       }\r
+       \r
+       //* Check if a note guid exists\r
+       public boolean guidExists(String guid) {\r
+               boolean check;\r
+        NSqlQuery query = new NSqlQuery(db.getConnection());\r
+                                       \r
+               check = query.prepare("select guid from note where guid=:guid");\r
+               query.bindValue(":guid", guid);\r
+               check = query.exec();\r
+               if (!check) \r
+                       logger.log(logger.EXTREME, "Note SQL guidExists query failed: " +query.lastError().toString());\r
+               \r
+               if (query.next()) {\r
+                       return true; \r
+               }\r
+\r
+               return false;                   \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
@@ -1388,4 +1588,109 @@ public class NoteTable {
                        position = n.getContent().indexOf("<en-media", position+1);\r
                }\r
        }\r
+\r
+       // Extract metadata from a note's Note.attributes.sourceApplication\r
+       private NoteMetadata extractMetadata(String sourceApplication) {\r
+               String consumerKey = "baumgarte:{";\r
+               int startPos = sourceApplication.indexOf(consumerKey);\r
+               if (startPos < 0 )\r
+                               return null;\r
+               \r
+               NoteMetadata meta = new NoteMetadata();\r
+               startPos = startPos+consumerKey.length();\r
+               \r
+//             String startString = sourceApplication.substring(0,startPos);\r
+               String metaString = sourceApplication.substring(startPos);\r
+//             String endString = metaString.substring(metaString.indexOf("};"));\r
+               int endPos = metaString.indexOf("};");\r
+               if (endPos > 0)\r
+                       metaString = metaString.substring(0,endPos);\r
+               \r
+               String value = parseMetaString(metaString, "titleColor");\r
+               if (value != null)\r
+                       meta.setColor(Integer.parseInt(value));\r
+               \r
+               value = parseMetaString(metaString, "pinned");\r
+               if (value != null && value.equals(true))\r
+                       meta.setPinned(true);\r
+                               \r
+               return meta;\r
+       }\r
+       \r
+       // Given a metadata string from attribute.sourceApplication, we\r
+       // extract the information for a given key.\r
+       private String parseMetaString(String metaString, String key) {\r
+               int startPos = metaString.indexOf(key);\r
+               if (startPos < 0)\r
+                       return null;\r
+               \r
+               String value = metaString.substring(startPos+key.length()+1);\r
+               int endPos = value.indexOf(";");\r
+               if (endPos > 0)\r
+                       value = value.substring(0,endPos);\r
+               \r
+               return value;\r
+       }\r
+       \r
+       // Given a set of metadata, we build a string that can be inserted\r
+       // into the attribute.sourceApplication string.\r
+       private String buildMetadataString(NoteMetadata meta) {\r
+               StringBuffer value = new StringBuffer(removeExistingMetaString(meta.getGuid()));\r
+               StringBuffer metaString = new StringBuffer();\r
+               \r
+               if (meta.isPinned()) {\r
+                       metaString.append("pinned=true;");\r
+               }\r
+               if (meta.getColor() != -1) {\r
+                       metaString.append("titleColor=" +new Integer(meta.getColor()).toString()+";");\r
+               }\r
+               if (metaString.length()>0) {\r
+                       \r
+                       // Adda any missing ";" or " " at the end of the existing \r
+                       // string.\r
+                       if (value.length()>1 && (!value.toString().trim().endsWith(";") || !value.toString().trim().endsWith(";")))   \r
+                               value.append("; ");\r
+                       \r
+                       value.append("baumgarte:{");\r
+                       value.append(metaString);\r
+                       value.append("};");\r
+                       return value.toString();\r
+               }\r
+               return null;\r
+       }\r
+\r
+       // This will remove the existing metadata string from the attribute.sourceApplication string.\r
+       private String removeExistingMetaString(String guid) {\r
+        NSqlQuery query = new NSqlQuery(db.getConnection());\r
+               \r
+               if (!query.prepare("Select attributeSourceApplication from Note where guid=:guid")) {\r
+                       logger.log(logger.EXTREME, "Note SQL retrieve has failed in removeExistingMetaString.");\r
+                       return null;\r
+               }\r
+               query.bindValue(":guid", guid);\r
+               query.exec();\r
+\r
+               // Get the application source string\r
+               String sourceApplication = null;\r
+               while (query.next()) {\r
+                       sourceApplication = query.valueString(0);\r
+               }\r
+               if (sourceApplication == null) \r
+                       return "";\r
+               \r
+               String consumerKey = "baumgarte:{";\r
+               int startPos = sourceApplication.indexOf(consumerKey);\r
+               if (startPos < 0 )\r
+                               return sourceApplication;\r
+               String startString = sourceApplication.substring(0,startPos);\r
+               String metaString = sourceApplication.substring(startPos);\r
+               String endString = metaString.substring(metaString.indexOf("};")+2);\r
+\r
+               return startString+endString;\r
+       }\r
+\r
 }      \r
+\r
+\r
+\r
+\r