OSDN Git Service

Add notebook specific sorting and alter some NeverNote labels to say NixNote.
[neighbornote/NeighborNote.git] / src / cx / fbn / nevernote / sql / NoteTable.java
1 /*\r
2  * This file is part of NixNote \r
3  * Copyright 2009 Randy Baumgarte\r
4  * \r
5  * This file may be licensed under the terms of of the\r
6  * GNU General Public License Version 2 (the ``GPL'').\r
7  *\r
8  * Software distributed under the License is distributed\r
9  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
10  * express or implied. See the GPL for the specific language\r
11  * governing rights and limitations.\r
12  *\r
13  * You should have received a copy of the GPL along with this\r
14  * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
15  * or write to the Free Software Foundation, Inc.,\r
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
17  *\r
18 */\r
19 \r
20 \r
21 package cx.fbn.nevernote.sql;\r
22 \r
23 import java.text.DateFormat;\r
24 import java.text.ParseException;\r
25 import java.text.SimpleDateFormat;\r
26 import java.util.ArrayList;\r
27 import java.util.HashMap;\r
28 import java.util.List;\r
29 \r
30 import org.apache.commons.lang.StringEscapeUtils;\r
31 \r
32 import com.evernote.edam.type.Note;\r
33 import com.evernote.edam.type.NoteAttributes;\r
34 import com.evernote.edam.type.Resource;\r
35 import com.evernote.edam.type.Tag;\r
36 import com.trolltech.qt.core.QByteArray;\r
37 import com.trolltech.qt.core.QDateTime;\r
38 import com.trolltech.qt.core.QTextCodec;\r
39 import com.trolltech.qt.gui.QPixmap;\r
40 \r
41 import cx.fbn.nevernote.Global;\r
42 import cx.fbn.nevernote.evernote.EnmlConverter;\r
43 import cx.fbn.nevernote.sql.driver.NSqlQuery;\r
44 import cx.fbn.nevernote.utilities.ApplicationLogger;\r
45 import cx.fbn.nevernote.utilities.Pair;\r
46 \r
47 public class NoteTable {\r
48         private final ApplicationLogger                 logger;\r
49         public final NoteTagsTable                              noteTagsTable;\r
50         public NoteResourceTable                                noteResourceTable;\r
51         private final DatabaseConnection                db;\r
52         int id;\r
53 \r
54         // Prepared Queries to improve speed\r
55         private NSqlQuery                                               getQueryWithContent;\r
56         private NSqlQuery                                               getQueryWithoutContent;\r
57         private NSqlQuery                                               getAllQueryWithoutContent;\r
58         \r
59         // Constructor\r
60         public NoteTable(ApplicationLogger l, DatabaseConnection d) {\r
61                 logger = l;\r
62                 db = d;\r
63                 id = 0;\r
64                 noteResourceTable = new NoteResourceTable(logger, db);\r
65                 noteTagsTable = new NoteTagsTable(logger, db);\r
66                 getQueryWithContent = null;\r
67                 getQueryWithoutContent = null;\r
68         }\r
69         // Create the table\r
70         public void createTable() {\r
71                 //getQueryWithContent = new NSqlQuery(db.getConnection());\r
72                 //getQueryWithoutContent = new NSqlQuery(db.getConnection());\r
73                 NSqlQuery query = new NSqlQuery(db.getConnection());\r
74         logger.log(logger.HIGH, "Creating table Note...");\r
75         if (!query.exec("Create table Note (guid varchar primary key, " +\r
76                         "updateSequenceNumber integer, title varchar, content varchar, contentHash varchar, "+\r
77                         "contentLength integer, created timestamp, updated timestamp, deleted timestamp, " \r
78                         +"active integer, notebookGuid varchar, attributeSubjectDate timestamp, "+\r
79                         "attributeLatitude double, attributeLongitude double, attributeAltitude double,"+\r
80                         "attributeAuthor varchar, attributeSource varchar, attributeSourceUrl varchar, "+\r
81                         "attributeSourceApplication varchar, indexNeeded boolean, isExpunged boolean, " +\r
82                         "isDirty boolean)"))                    \r
83                 logger.log(logger.HIGH, "Table Note creation FAILED!!!");    \r
84         if (!query.exec("CREATE INDEX unindexed_notess on note (indexneeded desc, guid);"))\r
85                 logger.log(logger.HIGH, "Note unindexed_notes index creation FAILED!!!");\r
86         if (!query.exec("CREATE INDEX unsynchronized_notes on note (isDirty desc, guid);"))\r
87                 logger.log(logger.HIGH, "note unsynchronized_notes index creation FAILED!!!");  \r
88         noteTagsTable.createTable();\r
89 //        noteResourceTable.createTable();     \r
90         }\r
91         // Drop the table\r
92         public void dropTable() {\r
93                 NSqlQuery query = new NSqlQuery(db.getConnection());\r
94                 query.exec("Drop table Note");\r
95                 noteTagsTable.dropTable();\r
96                 noteResourceTable.dropTable();\r
97         }\r
98         // Save Note List from Evernote \r
99         public void addNote(Note n, boolean isDirty) {\r
100                 logger.log(logger.EXTREME, "Inside addNote");\r
101                 if (n == null)\r
102                         return;\r
103                 \r
104                 SimpleDateFormat simple = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");\r
105 \r
106                 NSqlQuery query = new NSqlQuery(db.getConnection());                    \r
107                 query.prepare("Insert Into Note ("\r
108                                 +"guid, updateSequenceNumber, title, content, "\r
109                                 +"contentHash, contentLength, created, updated, deleted, active, notebookGuid, "\r
110                                 +"attributeSubjectDate, attributeLatitude, attributeLongitude, attributeAltitude, "\r
111                                 +"attributeAuthor, attributeSource, attributeSourceUrl, attributeSourceApplication, "\r
112                                 +"indexNeeded, isExpunged, isDirty, titlecolor, thumbnailneeded" \r
113                                 +") Values("\r
114                                 +":guid, :updateSequenceNumber, :title, :content, "\r
115                                 +":contentHash, :contentLength, :created, :updated, :deleted, :active, :notebookGuid, "\r
116                                 +":attributeSubjectDate, :attributeLatitude, :attributeLongitude, :attributeAltitude, "\r
117                                 +":attributeAuthor, :attributeSource, :attributeSourceUrl, :attributeSourceApplication, "\r
118                                 +":indexNeeded, :isExpunged, :isDirty, -1, true) ");\r
119 \r
120                 StringBuilder created = new StringBuilder(simple.format(n.getCreated()));                       \r
121                 StringBuilder updated = new StringBuilder(simple.format(n.getUpdated()));                       \r
122                 StringBuilder deleted = new StringBuilder(simple.format(n.getDeleted()));\r
123 \r
124                 \r
125                 \r
126                 query.bindValue(":guid", n.getGuid());\r
127                 query.bindValue(":updateSequenceNumber", n.getUpdateSequenceNum());\r
128                 query.bindValue(":title", n.getTitle());\r
129                 if (isDirty) {\r
130                         EnmlConverter enml = new EnmlConverter(logger);\r
131                         query.bindValue(":content", enml.fixEnXMLCrap(enml.fixEnMediaCrap(n.getContent())));\r
132                 }\r
133                 else\r
134                         query.bindValue(":content", n.getContent());\r
135                 query.bindValue(":contentHash", n.getContentHash());\r
136                 query.bindValue(":contentLength", n.getContentLength());\r
137                 query.bindValue(":created", created.toString());\r
138                 query.bindValue(":updated", updated.toString());\r
139                 query.bindValue(":deleted", deleted.toString());\r
140                 query.bindValue(":active", n.isActive());\r
141                 query.bindValue(":notebookGuid", n.getNotebookGuid());\r
142                 \r
143                 if (n.getAttributes() != null) {\r
144                         created = new StringBuilder(simple.format(n.getAttributes().getSubjectDate()));\r
145                         query.bindValue(":attributeSubjectDate", created.toString());\r
146                         query.bindValue(":attributeLatitude", n.getAttributes().getLatitude());\r
147                         query.bindValue(":attributeLongitude", n.getAttributes().getLongitude());\r
148                         query.bindValue(":attributeAltitude", n.getAttributes().getAltitude());\r
149                         query.bindValue(":attributeAuthor", n.getAttributes().getAuthor());\r
150                         query.bindValue(":attributeSource", n.getAttributes().getSource());\r
151                         query.bindValue(":attributeSourceUrl", n.getAttributes().getSourceURL());\r
152                         query.bindValue(":attributeSourceApplication", n.getAttributes().getSourceApplication());\r
153                 }\r
154                 query.bindValue(":indexNeeded", true);\r
155                 query.bindValue(":isExpunged", false);\r
156                 query.bindValue(":isDirty", isDirty);\r
157 \r
158                 \r
159                 if (!query.exec())\r
160                         logger.log(logger.MEDIUM, query.lastError());\r
161                 \r
162                 // Save the note tags\r
163                 if (n.getTagGuids() != null) {\r
164                         for (int i=0; i<n.getTagGuids().size(); i++) \r
165                                 noteTagsTable.saveNoteTag(n.getGuid(), n.getTagGuids().get(i));\r
166                 }\r
167                 logger.log(logger.EXTREME, "Leaving addNote");\r
168         } \r
169         // Setup queries for get to save time later\r
170         private void prepareQueries() {\r
171                 if (getQueryWithContent == null) {\r
172                         getQueryWithContent = new NSqlQuery(db.getConnection());\r
173                         if (!getQueryWithContent.prepare("Select "\r
174                                         +"guid, updateSequenceNumber, title, "\r
175                                         +"created, updated, deleted, active, notebookGuid, "\r
176                                         +"attributeSubjectDate, attributeLatitude, attributeLongitude, attributeAltitude, "\r
177                                         +"attributeAuthor, attributeSource, attributeSourceUrl, attributeSourceApplication, "\r
178                                         +"content, contentHash, contentLength"\r
179                                         +" from Note where guid=:guid and isExpunged=false")) {\r
180                                                 logger.log(logger.EXTREME, "Note SQL select prepare with content has failed.");\r
181                                                 logger.log(logger.MEDIUM, getQueryWithContent.lastError());\r
182                         }\r
183                 }\r
184                 \r
185                 if (getQueryWithoutContent == null) {\r
186                         getQueryWithoutContent = new NSqlQuery(db.getConnection());\r
187                         if (!getQueryWithoutContent.prepare("Select "\r
188                                         +"guid, updateSequenceNumber, title, "\r
189                                         +"created, updated, deleted, active, notebookGuid, "\r
190                                         +"attributeSubjectDate, attributeLatitude, attributeLongitude, attributeAltitude, "\r
191                                         +"attributeAuthor, attributeSource, attributeSourceUrl, attributeSourceApplication "\r
192                                         +" from Note where guid=:guid and isExpunged=false")) {\r
193                                                 logger.log(logger.EXTREME, "Note SQL select prepare without content has failed.");\r
194                                                 logger.log(logger.MEDIUM, getQueryWithoutContent.lastError());\r
195                         }\r
196                 }\r
197                         \r
198                 if (getAllQueryWithoutContent == null) {\r
199                         getAllQueryWithoutContent = new NSqlQuery(db.getConnection());\r
200                 \r
201                         if (!getAllQueryWithoutContent.prepare("Select "\r
202                                 +"guid, updateSequenceNumber, title, "\r
203                                 +"created, updated, deleted, active, notebookGuid, "\r
204                                 +"attributeSubjectDate, attributeLatitude, attributeLongitude, attributeAltitude, "\r
205                                 +"attributeAuthor, attributeSource, attributeSourceUrl, attributeSourceApplication "\r
206                                 +" from Note where isExpunged = false")) {\r
207                                 logger.log(logger.EXTREME, "Note SQL select prepare without content has failed.");\r
208                                         logger.log(logger.MEDIUM, getQueryWithoutContent.lastError());\r
209                         }\r
210                 }\r
211         }\r
212 \r
213         // Get a note's content in raw, binary format for the sync.\r
214         public String getNoteContentBinary(String guid) {\r
215                 NSqlQuery query = new NSqlQuery(db.getConnection());\r
216                 query.prepare("Select content from note where guid=:guid");\r
217                 query.bindValue(":guid", guid);\r
218                 query.exec();           \r
219                 query.next();\r
220                 return query.valueString(0);\r
221         }\r
222         // Get a note's content in blob format for index.\r
223         public String getNoteContentNoUTFConversion(String guid) {\r
224                 NSqlQuery query = new NSqlQuery(db.getConnection());\r
225                 query.prepare("Select content from note where guid=:guid");\r
226                 query.bindValue(":guid", guid);\r
227                 query.exec();           \r
228                 query.next();\r
229                 return query.valueString(0);\r
230         }\r
231         // Get a note by Guid\r
232         public Note getNote(String noteGuid, boolean loadContent, boolean loadResources, boolean loadRecognition, boolean loadBinary, boolean loadTags) {\r
233                 if (noteGuid == null)\r
234                         return null;\r
235                 if (noteGuid.trim().equals(""))\r
236                         return null;\r
237 \r
238                 prepareQueries();\r
239                 NSqlQuery query;\r
240                 if (loadContent) {\r
241                         query = getQueryWithContent;\r
242                 } else {\r
243                         query = getQueryWithoutContent;\r
244                 }\r
245                 \r
246                 query.bindValue(":guid", noteGuid);\r
247                 if (!query.exec()) {\r
248                         logger.log(logger.EXTREME, "Note SQL select exec has failed.");\r
249                         logger.log(logger.MEDIUM, query.lastError());\r
250                         return null;\r
251                 }\r
252                 if (!query.next()) {\r
253                         logger.log(logger.EXTREME, "SQL Retrieve failed for note guid " +noteGuid + " in getNote()");\r
254                         logger.log(logger.EXTREME, " -> " +query.lastError().toString());\r
255                         logger.log(logger.EXTREME, " -> " +query.lastError());\r
256                         return null;\r
257                 }\r
258                 Note n = mapNoteFromQuery(query, loadContent, loadResources, loadRecognition, loadBinary, loadTags);\r
259                 n.setContent(fixCarriageReturn(n.getContent()));\r
260                 return n;\r
261         }\r
262         // Get a note by Guid\r
263         public Note mapNoteFromQuery(NSqlQuery query, boolean loadContent, boolean loadResources, boolean loadRecognition, boolean loadBinary, boolean loadTags) {\r
264                 DateFormat indfm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");\r
265 //              indfm = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy");\r
266 \r
267                 Note n = new Note();\r
268                 NoteAttributes na = new NoteAttributes();\r
269                 n.setAttributes(na);\r
270                 \r
271                 n.setGuid(query.valueString(0));\r
272                 n.setUpdateSequenceNum(new Integer(query.valueString(1)));\r
273                 n.setTitle(query.valueString(2));\r
274 \r
275                 try {\r
276                         n.setCreated(indfm.parse(query.valueString(3)).getTime());\r
277                         n.setUpdated(indfm.parse(query.valueString(4)).getTime());\r
278                         n.setDeleted(indfm.parse(query.valueString(5)).getTime());\r
279                 } catch (ParseException e) {\r
280                         e.printStackTrace();\r
281                 }\r
282 \r
283                 n.setActive(query.valueBoolean(6,true));\r
284                 n.setNotebookGuid(query.valueString(7));\r
285                 \r
286                 try {\r
287                         String attributeSubjectDate = query.valueString(8);\r
288                         if (!attributeSubjectDate.equals(""))\r
289                                 na.setSubjectDate(indfm.parse(attributeSubjectDate).getTime());\r
290                 } catch (ParseException e) {\r
291                         e.printStackTrace();\r
292                 }\r
293                 na.setLatitude(new Float(query.valueString(9)));\r
294                 na.setLongitude(new Float(query.valueString(10)));\r
295                 na.setAltitude(new Float(query.valueString(11)));\r
296                 na.setAuthor(query.valueString(12));\r
297                 na.setSource(query.valueString(13));\r
298                 na.setSourceURL(query.valueString(14));\r
299                 na.setSourceApplication(query.valueString(15));\r
300                 \r
301                 if (loadTags) {\r
302                         n.setTagGuids(noteTagsTable.getNoteTags(n.getGuid()));\r
303                         List<String> tagNames = new ArrayList<String>();\r
304                         TagTable tagTable = db.getTagTable();\r
305                         for (int i=0; i<n.getTagGuids().size(); i++) {\r
306                                 String currentGuid = n.getTagGuids().get(i);\r
307                                 Tag tag = tagTable.getTag(currentGuid);\r
308                                 tagNames.add(tag.getName());\r
309                         }\r
310                         n.setTagNames(tagNames);\r
311                 }\r
312                 \r
313                 if (loadContent) {\r
314                         QTextCodec codec = QTextCodec.codecForLocale();\r
315                         codec = QTextCodec.codecForName("UTF-8");\r
316                 String unicode =  codec.fromUnicode(query.valueString(16)).toString();\r
317 \r
318                 // This is a hack.  Basically I need to convert HTML Entities to "normal" text, but if I\r
319                 // convert the &lt; character to < it will mess up the XML parsing.  So, to get around this\r
320                 // I am "bit stuffing" the &lt; to &&lt; so StringEscapeUtils doesn't unescape it.  After\r
321                 // I'm done I convert it back.\r
322                 StringBuffer buffer = new StringBuffer(unicode);\r
323                 if (Global.enableHTMLEntitiesFix && unicode.indexOf("&#") > 0) {\r
324                         unicode = query.valueString(16);\r
325                         //System.out.println(unicode);\r
326                         //unicode = unicode.replace("&lt;", "&_lt;");\r
327                         //unicode = codec.fromUnicode(StringEscapeUtils.unescapeHtml(unicode)).toString();\r
328                         //unicode = unicode.replace("&_lt;", "&lt;");\r
329                         //System.out.println("************************");\r
330                         int j=1;\r
331                         for (int i=buffer.indexOf("&#"); i != -1 && buffer.indexOf("&#", i)>0; i=buffer.indexOf("&#",i+1)) {\r
332                                 j = buffer.indexOf(";",i)+1;\r
333                                 if (i<j) {\r
334                                         String entity = buffer.substring(i,j).toString();\r
335                                         int len = entity.length()-1;\r
336                                         String tempEntity = entity.substring(2, len);\r
337                                         try {\r
338                                                 Integer.parseInt(tempEntity);\r
339                                                 entity = codec.fromUnicode(StringEscapeUtils.unescapeHtml(entity)).toString();\r
340                                                 buffer.delete(i, j);\r
341                                                 buffer.insert(i, entity);\r
342                                         } catch (Exception e){ }\r
343                                         \r
344                                 }\r
345                         } \r
346                 } \r
347                         \r
348                 n.setContent(unicode);\r
349 //                      n.setContent(query.valueString(16).toString());\r
350                         \r
351                         String contentHash = query.valueString(17);\r
352                         if (contentHash != null)\r
353                                 n.setContentHash(contentHash.getBytes());\r
354                         n.setContentLength(new Integer(query.valueString(18)));\r
355                 }\r
356                 if (loadResources)\r
357                         n.setResources(noteResourceTable.getNoteResources(n.getGuid(), loadBinary));\r
358                 if (loadRecognition) {\r
359                         if (n.getResources() == null) {\r
360                                 List<Resource> resources = noteResourceTable.getNoteResourcesRecognition(n.getGuid());\r
361                                 n.setResources(resources);\r
362                         } else {\r
363                                 // We need to merge the recognition resources with the note resources retrieved earlier\r
364                                 for (int i=0; i<n.getResources().size(); i++) {\r
365                                         Resource r = noteResourceTable.getNoteResourceRecognition(n.getResources().get(i).getGuid());\r
366                                         n.getResources().get(i).setRecognition(r.getRecognition());\r
367                                 }\r
368                         }\r
369                 }\r
370                 n.setContent(fixCarriageReturn(n.getContent()));\r
371                 return n;\r
372         }\r
373         // Update a note's title\r
374         public void updateNoteTitle(String guid, String title) {\r
375                 NSqlQuery query = new NSqlQuery(db.getConnection());\r
376                 boolean check = query.prepare("Update Note set title=:title, isDirty=true where guid=:guid");\r
377                 if (!check) {\r
378                         logger.log(logger.EXTREME, "Update note title sql prepare has failed.");\r
379                         logger.log(logger.MEDIUM, query.lastError());\r
380                 }\r
381                 query.bindValue(":title", title);\r
382                 query.bindValue(":guid", guid);\r
383                 check = query.exec();\r
384                 if (!check) {\r
385                         logger.log(logger.EXTREME, "Update note title has failed.");\r
386                         logger.log(logger.MEDIUM, query.lastError());\r
387                 }\r
388         }\r
389         // Update a note's creation date\r
390         public void updateNoteCreatedDate(String guid, QDateTime date) {\r
391                 NSqlQuery query = new NSqlQuery(db.getConnection());\r
392                 boolean check = query.prepare("Update Note set created=:created, isDirty=true where guid=:guid");\r
393                 if (!check) {\r
394                         logger.log(logger.EXTREME, "Update note creation update sql prepare has failed.");\r
395                         logger.log(logger.MEDIUM, query.lastError());\r
396                 }\r
397                 \r
398                 query.bindValue(":created", date.toString("yyyy-MM-dd HH:mm:ss"));\r
399                 query.bindValue(":guid", guid);\r
400                 \r
401                 check = query.exec();\r
402                 if (!check) {\r
403                         logger.log(logger.EXTREME, "Update note creation date has failed.");\r
404                         logger.log(logger.MEDIUM, query.lastError());\r
405                 }\r
406         }\r
407         // Update a note's creation date\r
408         public void updateNoteAlteredDate(String guid, QDateTime date) {\r
409                 NSqlQuery query = new NSqlQuery(db.getConnection());\r
410                 boolean check = query.prepare("Update Note set updated=:altered, isDirty=true where guid=:guid");\r
411                 if (!check) {\r
412                         logger.log(logger.EXTREME, "Update note altered sql prepare has failed.");\r
413                         logger.log(logger.MEDIUM, query.lastError());\r
414                 }\r
415                 \r
416                 query.bindValue(":altered", date.toString("yyyy-MM-dd HH:mm:ss"));\r
417                 query.bindValue(":guid", guid);\r
418                 \r
419                 check = query.exec();\r
420                 if (!check) {\r
421                         logger.log(logger.EXTREME, "Update note altered date has failed.");\r
422                         logger.log(logger.MEDIUM, query.lastError());\r
423                 }\r
424         }\r
425         // Update a note's creation date\r
426         public void updateNoteSubjectDate(String guid, QDateTime date) {\r
427                 NSqlQuery query = new NSqlQuery(db.getConnection());\r
428                 boolean check = query.prepare("Update Note set attributeSubjectDate=:altered, isDirty=true where guid=:guid");\r
429                 if (!check) {\r
430                         logger.log(logger.EXTREME, "Update note subject date sql prepare has failed.");\r
431                         logger.log(logger.MEDIUM, query.lastError());\r
432                 }\r
433         \r
434                 query.bindValue(":altered", date.toString("yyyy-MM-dd HH:mm:ss"));\r
435                 query.bindValue(":guid", guid);\r
436                 \r
437                 check = query.exec();\r
438                 if (!check) {\r
439                         logger.log(logger.EXTREME, "Update note subject date date has failed.");\r
440                         logger.log(logger.MEDIUM, query.lastError());\r
441                 }\r
442         }\r
443         // Update a note's creation date\r
444         public void updateNoteAuthor(String guid, String author) {\r
445                 NSqlQuery query = new NSqlQuery(db.getConnection());\r
446                 boolean check = query.prepare("Update Note set attributeAuthor=:author, isDirty=true where guid=:guid");\r
447                 if (!check) {\r
448                         logger.log(logger.EXTREME, "Update note author sql prepare has failed.");\r
449                         logger.log(logger.MEDIUM, query.lastError());\r
450                 }\r
451 \r
452                 query.bindValue(":author", author);\r
453                 query.bindValue(":guid", guid);\r
454 \r
455                 check = query.exec();\r
456                 if (!check) {\r
457                         logger.log(logger.EXTREME, "Update note author has failed.");\r
458                         logger.log(logger.MEDIUM, query.lastError());\r
459                 }\r
460                 \r
461         }\r
462         // Update a note's geo tags\r
463         public void updateNoteGeoTags(String guid, Double lon, Double lat, Double alt) {\r
464                 NSqlQuery query = new NSqlQuery(db.getConnection());\r
465                 boolean check = query.prepare("Update Note set attributeLongitude=:longitude, "+\r
466                                 "attributeLatitude=:latitude, attributeAltitude=:altitude, isDirty=true where guid=:guid");\r
467                 if (!check) {\r
468                         logger.log(logger.EXTREME, "Update note author sql prepare has failed.");\r
469                         logger.log(logger.MEDIUM, query.lastError());\r
470                 }\r
471 \r
472                 query.bindValue(":longitude", lon);\r
473                 query.bindValue(":latitude", lat);\r
474                 query.bindValue(":altitude", alt);\r
475                 query.bindValue(":guid", guid);\r
476 \r
477                 check = query.exec();\r
478                 if (!check) {\r
479                         logger.log(logger.EXTREME, "Update note geo tag has failed.");\r
480                         logger.log(logger.MEDIUM, query.lastError());\r
481                 }\r
482                 \r
483         }\r
484         // Update a note's creation date\r
485         public void updateNoteSourceUrl(String guid, String url) {\r
486                 NSqlQuery query = new NSqlQuery(db.getConnection());\r
487                 boolean check = query.prepare("Update Note set attributeSourceUrl=:url, isDirty=true where guid=:guid");\r
488                 if (!check) {\r
489                         logger.log(logger.EXTREME, "Update note url sql prepare has failed.");\r
490                         logger.log(logger.MEDIUM, query.lastError());\r
491                 }\r
492                 \r
493                 query.bindValue(":url", url);\r
494                 query.bindValue(":guid", guid);\r
495 \r
496                 check = query.exec();\r
497                 if (!check) {\r
498                         logger.log(logger.EXTREME, "Update note url has failed.");\r
499                         logger.log(logger.MEDIUM, query.lastError());\r
500                 }\r
501                 \r
502         }\r
503         // Update the notebook that a note is assigned to\r
504         public void updateNoteNotebook(String guid, String notebookGuid, boolean expungeFromRemote) {\r
505                 String currentNotebookGuid = new String("");\r
506                 \r
507                 \r
508                 // If we are going from a synchronized notebook to a local notebook, we\r
509                 // need to tell Evernote to purge the note online.  However, if this is  \r
510                 // conflicting change we move it to the local notebook without deleting it \r
511                 // or it would then delete the copy on the remote server.\r
512                 NotebookTable notebookTable = new NotebookTable(logger, db);\r
513                 DeletedTable deletedTable = new DeletedTable(logger, db);\r
514                 if (expungeFromRemote) {\r
515                         if (!notebookTable.isNotebookLocal(currentNotebookGuid) & notebookTable.isNotebookLocal(notebookGuid)) {\r
516                                 deletedTable.addDeletedItem(guid, "NOTE");\r
517                         }\r
518                 }\r
519                 \r
520                 NSqlQuery query = new NSqlQuery(db.getConnection());\r
521                 boolean check = query.prepare("Update Note set notebookGuid=:notebook, isDirty=true where guid=:guid");\r
522                 if (!check) {\r
523                         logger.log(logger.EXTREME, "Update note notebook sql prepare has failed.");\r
524                         logger.log(logger.MEDIUM, query.lastError());\r
525                 }\r
526                 query.bindValue(":notebook", notebookGuid);\r
527                 query.bindValue(":guid", guid);\r
528                 \r
529                 check = query.exec();\r
530                 if (!check) {\r
531                         logger.log(logger.EXTREME, "Update note notebook has failed.");\r
532                         logger.log(logger.MEDIUM, query.lastError());\r
533                 };\r
534         }\r
535         // Update a note's title\r
536         public void updateNoteContent(String guid, String content) {\r
537                 NSqlQuery query = new NSqlQuery(db.getConnection());\r
538                 boolean check = query.prepare("Update Note set content=:content, updated=CURRENT_TIMESTAMP(), isDirty=true, indexNeeded=true, " +\r
539                                 " thumbnailneeded=true where guid=:guid");\r
540                 if (!check) {\r
541                         logger.log(logger.EXTREME, "Update note content sql prepare has failed.");\r
542                         logger.log(logger.MEDIUM, query.lastError());\r
543                 }\r
544                 \r
545                 query.bindValue(":content", content);\r
546                 query.bindValue(":guid", guid);\r
547 \r
548                 check = query.exec();\r
549                 if (!check) {\r
550                         logger.log(logger.EXTREME, "Update note content has failed.");\r
551                         logger.log(logger.MEDIUM, query.lastError());\r
552                 }\r
553         }\r
554 \r
555         // Delete a note\r
556         public void deleteNote(String guid) {\r
557         NSqlQuery query = new NSqlQuery(db.getConnection());\r
558         query.prepare("Update Note set deleted=CURRENT_TIMESTAMP(), active=false, isDirty=true where guid=:guid");\r
559                 query.bindValue(":guid", guid);\r
560                 if (!query.exec()) {\r
561                         logger.log(logger.MEDIUM, "Note delete failed.");\r
562                         logger.log(logger.MEDIUM, query.lastError());\r
563                 }\r
564         }\r
565         public void restoreNote(String guid) {\r
566         NSqlQuery query = new NSqlQuery(db.getConnection());\r
567                 query.prepare("Update Note set deleted='1969-12-31 19.00.00', active=true, isDirty=true where guid=:guid");\r
568 //              query.prepare("Update Note set deleted=0, active=true, isDirty=true where guid=:guid");\r
569                 query.bindValue(":guid", guid);\r
570                 if (!query.exec()) {\r
571                         logger.log(logger.MEDIUM, "Note restore failed.");\r
572                         logger.log(logger.MEDIUM, query.lastError());\r
573                 }\r
574         }\r
575         // Purge a note (actually delete it instead of just marking it deleted)\r
576         public void expungeNote(String guid, boolean permanentExpunge, boolean needsSync) {\r
577                 \r
578                 if (!permanentExpunge) {\r
579                         hideExpungedNote(guid, needsSync);\r
580                         return;\r
581                 }\r
582                 \r
583                 \r
584         NSqlQuery note = new NSqlQuery(db.getConnection());\r
585         NSqlQuery resources = new NSqlQuery(db.getResourceConnection());\r
586         NSqlQuery tags = new NSqlQuery(db.getConnection());\r
587         NSqlQuery words = new NSqlQuery(db.getIndexConnection());\r
588         \r
589         note.prepare("Delete from Note where guid=:guid");\r
590                 resources.prepare("Delete from NoteResources where noteGuid=:guid");\r
591                 tags.prepare("Delete from NoteTags where noteGuid=:guid");\r
592                 words.prepare("Delete from words where guid=:guid");\r
593 \r
594                 note.bindValue(":guid", guid);\r
595                 resources.bindValue(":guid", guid);\r
596                 tags.bindValue(":guid", guid);\r
597                 words.bindValue(":guid", guid);\r
598         \r
599                 // Start purging notes.\r
600                 if (!note.exec()) {\r
601                         logger.log(logger.MEDIUM, "Purge from note failed.");\r
602                         logger.log(logger.MEDIUM, note.lastError());\r
603                 }\r
604                 if (!resources.exec()) {\r
605                                 logger.log(logger.MEDIUM, "Purge from resources failed.");\r
606                         logger.log(logger.MEDIUM, resources.lastError());\r
607                 }\r
608                 if (!tags.exec()) {\r
609                         logger.log(logger.MEDIUM, "Note tags delete failed.");\r
610                         logger.log(logger.MEDIUM, tags.lastError());\r
611                 }\r
612 \r
613                 if (!words.exec()) {\r
614                         logger.log(logger.MEDIUM, "Word delete failed.");\r
615                         logger.log(logger.MEDIUM, words.lastError());\r
616                 }\r
617                 if (needsSync) {\r
618                         DeletedTable deletedTable = new DeletedTable(logger, db);\r
619                         deletedTable.addDeletedItem(guid, "Note");\r
620                 }\r
621 \r
622         }\r
623         // Purge a bunch of notes based upon the notebook\r
624         public void expungeNotesByNotebook(String notebookGuid, boolean permanentExpunge, boolean needsSync) {\r
625                 List<String> notes = getNotesByNotebook(notebookGuid);\r
626                 for (int i=0; i<notes.size(); i++) {\r
627                         expungeNote(notes.get(i), permanentExpunge, needsSync);\r
628                 }\r
629         }\r
630 \r
631         // Purge a note (actually delete it instead of just marking it deleted)\r
632         public void hideExpungedNote(String guid, boolean needsSync) {\r
633         NSqlQuery note = new NSqlQuery(db.getConnection());\r
634         NSqlQuery resources = new NSqlQuery(db.getResourceConnection());\r
635         NSqlQuery tags = new NSqlQuery(db.getConnection());\r
636         NSqlQuery words = new NSqlQuery(db.getIndexConnection());\r
637         \r
638         note.prepare("Update Note set isExpunged=true where guid=:guid");\r
639                 resources.prepare("Delete from NoteResources where noteGuid=:guid");\r
640                 tags.prepare("Delete from NoteTags where noteGuid=:guid");\r
641 //              words.prepare("Delete from words where guid=:guid");\r
642 \r
643                 note.bindValue(":guid", guid);\r
644                 resources.bindValue(":guid", guid);\r
645                 tags.bindValue(":guid", guid);\r
646                 words.bindValue(":guid", guid);\r
647 \r
648                 // Start purging notes.\r
649                 if (!note.exec()) {\r
650                         logger.log(logger.MEDIUM, "Purge from note failed.");\r
651                         logger.log(logger.MEDIUM, note.lastError());\r
652                 }\r
653                 if (!resources.exec()) {\r
654                                 logger.log(logger.MEDIUM, "Purge from resources failed.");\r
655                         logger.log(logger.MEDIUM, resources.lastError());\r
656                 }\r
657                 if (!tags.exec()) {\r
658                         logger.log(logger.MEDIUM, "Note tags delete failed.");\r
659                         logger.log(logger.MEDIUM, tags.lastError());\r
660                 }\r
661 //              System.out.println("Hiding Note: Deleting words");\r
662 //              if (!words.exec()) {\r
663 //                      logger.log(logger.MEDIUM, "Word delete failed.");\r
664 //                      logger.log(logger.MEDIUM, words.lastError());\r
665 //              }\r
666                 if (needsSync) {\r
667                         DeletedTable deletedTable = new DeletedTable(logger, db);\r
668                         deletedTable.addDeletedItem(guid, "Note");\r
669                 }\r
670         }\r
671 \r
672                 \r
673         // Purge all deleted notes;\r
674         public void expungeAllDeletedNotes() {\r
675                 NSqlQuery query = new NSqlQuery(db.getConnection());\r
676                 query.exec("select guid, updateSequenceNumber from note where active = false");\r
677                 List<String> guids = new ArrayList<String>();\r
678                 List<Integer> usns = new ArrayList<Integer>();\r
679                 while (query.next()) {\r
680                         guids.add(query.valueString(0));\r
681                         Integer usn = new Integer(query.valueString(1));\r
682                         usns.add(usn);\r
683                 }\r
684                 \r
685                 for (int i=0; i<guids.size(); i++) {\r
686                         Integer usn = usns.get(i);\r
687                         String guid = guids.get(i);\r
688                         if (usn == 0)\r
689                                 expungeNote(guid, true, false);\r
690                         else\r
691                                 expungeNote(guid, false, true);\r
692                 }\r
693         }\r
694         // Update the note sequence number\r
695         public void updateNoteSequence(String guid, int sequence) {\r
696                 boolean check;\r
697         NSqlQuery query = new NSqlQuery(db.getConnection());\r
698                 check = query.prepare("Update Note set updateSequenceNumber=:sequence where guid=:guid");\r
699 \r
700                 query.bindValue(":sequence", sequence);\r
701                 query.bindValue(":guid", guid);\r
702                 \r
703                 query.exec();\r
704                 if (!check) {\r
705                         logger.log(logger.MEDIUM, "Note sequence update failed.");\r
706                         logger.log(logger.MEDIUM, query.lastError());\r
707                 } \r
708         }\r
709         // Update the note Guid\r
710         public void updateNoteGuid(String oldGuid, String newGuid) {\r
711                 boolean check;\r
712         NSqlQuery query = new NSqlQuery(db.getConnection());\r
713         NSqlQuery resQuery = new NSqlQuery(db.getResourceConnection());\r
714         NSqlQuery wordQuery = new NSqlQuery(db.getIndexConnection());\r
715                 query.prepare("Update Note set guid=:newGuid, original_guid=:original_guid where guid=:oldGuid");\r
716 \r
717                 query.bindValue(":original_guid", oldGuid);\r
718                 query.bindValue(":newGuid", newGuid);\r
719                 query.bindValue(":oldGuid", oldGuid);\r
720 \r
721                 check = query.exec();\r
722                 if (!check) {\r
723                         logger.log(logger.MEDIUM, "Note Guid update failed.");\r
724                         logger.log(logger.MEDIUM, query.lastError());\r
725                 } \r
726                 \r
727                 query.prepare("Update NoteTags set noteGuid=:newGuid where noteGuid=:oldGuid");\r
728                 query.bindValue(":newGuid", newGuid);\r
729                 query.bindValue(":oldGuid", oldGuid);\r
730                 check = query.exec();\r
731                 if (!check) {\r
732                         logger.log(logger.MEDIUM, "Note guid update failed for NoteTags.");\r
733                         logger.log(logger.MEDIUM, query.lastError());\r
734                 }\r
735                 \r
736                 wordQuery.prepare("Update words set guid=:newGuid where guid=:oldGuid");\r
737                 wordQuery.bindValue(":newGuid", newGuid);\r
738                 wordQuery.bindValue(":oldGuid", oldGuid);\r
739                 wordQuery.exec();\r
740                 if (!check) {\r
741                         logger.log(logger.MEDIUM, "Note guid update failed for Words.");\r
742                         logger.log(logger.MEDIUM, wordQuery.lastError());\r
743                 }\r
744                 resQuery.prepare("Update noteresources set noteguid=:newGuid where noteguid=:oldGuid");\r
745                 resQuery.bindValue(":newGuid", newGuid);\r
746                 resQuery.bindValue(":oldGuid", oldGuid);\r
747                 resQuery.exec();\r
748                 if (!check) {\r
749                         logger.log(logger.MEDIUM, "Note guid update failed for noteresources.");\r
750                         logger.log(logger.MEDIUM, resQuery.lastError());\r
751                 }\r
752         }\r
753         // Update a note\r
754         public void updateNote(Note n, boolean isNew) {\r
755                 int titleColor = getNoteTitleColor(n.getGuid());\r
756                 String originalGuid = findAlternateGuid(n.getGuid());\r
757                 expungeNote(n.getGuid(), true, false);\r
758                 addNote(n, false);\r
759                 if (titleColor != -1)\r
760                         setNoteTitleColor(n.getGuid(), titleColor);\r
761                 if (originalGuid != null) {\r
762                         updateNoteGuid(n.getGuid(), originalGuid);\r
763                         updateNoteGuid(originalGuid, n.getGuid());\r
764                 }\r
765         }\r
766         // Does a note exist?\r
767         public boolean exists(String guid) {\r
768                 if (guid == null)\r
769                         return false;\r
770                 if (guid.trim().equals(""))\r
771                         return false;\r
772                 NSqlQuery query = new NSqlQuery(db.getConnection());\r
773                 query.prepare("Select guid from note where guid=:guid");\r
774                 query.bindValue(":guid", guid);\r
775                 if (!query.exec())\r
776                         logger.log(logger.EXTREME, "note.exists SQL retrieve has failed.");\r
777                 boolean retVal = query.next();\r
778                 return retVal;\r
779         }\r
780         // Does a note exist?\r
781         public boolean isNoteExpunged(String guid) {\r
782                 if (guid == null)\r
783                         return false;\r
784                 if (guid.trim().equals(""))\r
785                         return false;\r
786                 NSqlQuery query = new NSqlQuery(db.getConnection());\r
787                 query.prepare("Select isExpunged from note where guid=:guid and isExpunged = true");\r
788                 query.bindValue(":guid", guid);\r
789                 if (!query.exec())\r
790                         logger.log(logger.EXTREME, "note.isNoteExpunged SQL retrieve has failed.");\r
791                 boolean retVal = query.next();\r
792                 return retVal;\r
793         }\r
794         // This is a convience method to check if a tag exists & update/create based upon it\r
795         public void syncNote(Note tag, boolean isDirty) {\r
796                 if (exists(tag.getGuid()))\r
797                         updateNote(tag, isDirty);\r
798                 else\r
799                         addNote(tag, isDirty);\r
800         }\r
801         // Get a list of notes that need to be updated\r
802         public List <Note> getDirty() {\r
803                 String guid;\r
804                 Note tempNote;\r
805                 List<Note> notes = new ArrayList<Note>();\r
806                 List<String> index = new ArrayList<String>();\r
807                 \r
808                 boolean check;                  \r
809         NSqlQuery query = new NSqlQuery(db.getConnection());\r
810                                         \r
811                 check = query.exec("Select guid from Note where isDirty = true and isExpunged = false and notebookGuid not in (select guid from notebook where local = true or linked = true)");\r
812                 if (!check) \r
813                         logger.log(logger.EXTREME, "Note SQL retrieve has failed: " +query.lastError().toString());\r
814                 \r
815                 // Get a list of the notes\r
816                 while (query.next()) {\r
817                         guid = new String();\r
818                         guid = query.valueString(0);\r
819                         index.add(guid); \r
820                 }       \r
821                 \r
822                 // Start getting notes\r
823                 for (int i=0; i<index.size(); i++) {\r
824                         tempNote = getNote(index.get(i), true,true,false,true,true);\r
825                         notes.add(tempNote);\r
826                 }\r
827                 return notes;   \r
828         }\r
829         // Get a list of notes that need to be updated\r
830         public List <Note> getDirtyLinkedNotes() {\r
831                 String guid;\r
832                 Note tempNote;\r
833                 List<Note> notes = new ArrayList<Note>();\r
834                 List<String> index = new ArrayList<String>();\r
835                 \r
836                 boolean check;                  \r
837         NSqlQuery query = new NSqlQuery(db.getConnection());\r
838                                         \r
839                 check = query.exec("Select guid from Note where isDirty = true and isExpunged = false and notebookGuid in (select guid from notebook where linked = true)");\r
840                 if (!check) \r
841                         logger.log(logger.EXTREME, "Note SQL retrieve has failed: " +query.lastError().toString());\r
842                 \r
843                 // Get a list of the notes\r
844                 while (query.next()) {\r
845                         guid = new String();\r
846                         guid = query.valueString(0);\r
847                         index.add(guid); \r
848                 }       \r
849                 \r
850                 // Start getting notes\r
851                 for (int i=0; i<index.size(); i++) {\r
852                         tempNote = getNote(index.get(i), true,true,false,true,true);\r
853                         notes.add(tempNote);\r
854                 }\r
855                 return notes;   \r
856         }\r
857         // Get a list of notes that need to be updated\r
858         public List <Note> getDirtyLinked(String notebookGuid) {\r
859                 String guid;\r
860                 Note tempNote;\r
861                 List<Note> notes = new ArrayList<Note>();\r
862                 List<String> index = new ArrayList<String>();\r
863                 \r
864                 boolean check;                  \r
865         NSqlQuery query = new NSqlQuery(db.getConnection());\r
866                                         \r
867                 query.prepare("Select guid from Note where isDirty = true and isExpunged = false and notebookGuid=:notebookGuid");\r
868                 query.bindValue(":notebookGuid", notebookGuid);\r
869                 check = query.exec();\r
870                 if (!check) \r
871                         logger.log(logger.EXTREME, "Note SQL retrieve has failed getting dirty linked notes: " +query.lastError().toString());\r
872                 \r
873                 // Get a list of the notes\r
874                 while (query.next()) {\r
875                         guid = new String();\r
876                         guid = query.valueString(0);\r
877                         index.add(guid); \r
878                 }       \r
879                 \r
880                 // Start getting notes\r
881                 for (int i=0; i<index.size(); i++) {\r
882                         tempNote = getNote(index.get(i), true,true,false,true,true);\r
883                         notes.add(tempNote);\r
884                 }\r
885                 return notes;   \r
886         }\r
887         // Get a list of notes that need to be updated\r
888         public List <String> getNotesByNotebook(String notebookGuid) {\r
889                 List<String> notes = new ArrayList<String>();\r
890                 List<String> index = new ArrayList<String>();\r
891                 \r
892                 boolean check;                  \r
893         NSqlQuery query = new NSqlQuery(db.getConnection());\r
894                                         \r
895                 check = query.prepare("Select guid from Note where notebookguid=:notebookguid");\r
896                 if (!check) \r
897                         logger.log(logger.EXTREME, "Note SQL retrieve has failed: " +query.lastError().toString());\r
898                 query.bindValue(":notebookguid", notebookGuid);\r
899                 query. exec();\r
900                 \r
901                 // Get a list of the notes\r
902                 while (query.next()) {\r
903                         index.add(query.valueString(0)); \r
904                 }       \r
905                 \r
906                 return notes;   \r
907         }\r
908         // Get a list of notes that need to be updated\r
909         public boolean isNoteDirty(String guid) {\r
910                 \r
911                 boolean check;                  \r
912         NSqlQuery query = new NSqlQuery(db.getConnection());\r
913                                         \r
914                 check = query.prepare("Select guid from Note where isDirty = true and guid=:guid");\r
915                 query.bindValue(":guid", guid);\r
916                 check = query.exec();\r
917                 if (!check) \r
918                         logger.log(logger.EXTREME, "Note SQL retrieve has failed: " +query.lastError().toString());\r
919                 \r
920                 boolean returnValue;\r
921                 // Get a list of the notes\r
922                 if (query.next()) \r
923                         returnValue = true; \r
924                 else\r
925                         returnValue = false;\r
926 \r
927                 return returnValue;     \r
928         }\r
929         // Get a list of notes that need to be updated\r
930         public List <String> getUnsynchronizedGUIDs() {\r
931                 String guid;\r
932                 List<String> index = new ArrayList<String>();\r
933                 \r
934                 boolean check;                  \r
935         NSqlQuery query = new NSqlQuery(db.getConnection());\r
936                                         \r
937                 check = query.exec("Select guid from Note where isDirty=true");\r
938                 if (!check) \r
939                         logger.log(logger.EXTREME, "Note SQL retrieve has failed: " +query.lastError().toString());\r
940                 \r
941                 // Get a list of the notes\r
942                 while (query.next()) {\r
943                         guid = new String();\r
944                         guid = query.valueString(0);\r
945                         index.add(guid); \r
946                 }       \r
947                 return index;   \r
948         }\r
949         // Reset the dirty bit\r
950         public void  resetDirtyFlag(String guid) {\r
951                 NSqlQuery query = new NSqlQuery(db.getConnection());\r
952                 \r
953                 query.prepare("Update note set isdirty=false where guid=:guid");\r
954                 query.bindValue(":guid", guid);\r
955                 if (!query.exec())\r
956                         logger.log(logger.EXTREME, "Error resetting note dirty field.");\r
957         }\r
958         // Get all notes\r
959         public List<String> getAllGuids() {\r
960                 List<String> notes = new ArrayList<String>();\r
961                 \r
962                 boolean check;                                  \r
963         NSqlQuery query = new NSqlQuery(db.getConnection());\r
964                                         \r
965                 check = query.exec("Select guid from Note");\r
966                 if (!check)\r
967                         logger.log(logger.EXTREME, "Notebook SQL retrieve has failed: "+query.lastError());\r
968 \r
969                 // Get a list of the notes\r
970                 while (query.next()) {\r
971                         notes.add(new String(query.valueString(0))); \r
972                 }\r
973                 return notes;\r
974         }\r
975         // Get all notes\r
976         public List<Note> getAllNotes() {\r
977                 List<Note> notes = new ArrayList<Note>();\r
978                 prepareQueries();\r
979                 boolean check;  \r
980                 if (getAllQueryWithoutContent == null) \r
981                         prepareQueries();\r
982         NSqlQuery query = getAllQueryWithoutContent;\r
983                 check = query.exec();\r
984                 if (!check)\r
985                         logger.log(logger.EXTREME, "Notebook SQL retrieve has failed: "+query.lastError());\r
986                 // Get a list of the notes\r
987                 while (query.next()) {\r
988                         notes.add(mapNoteFromQuery(query, false, false, false, false, true));\r
989                 }\r
990                 return notes;\r
991         }\r
992         // Count unindexed notes\r
993         public int getUnindexedCount() {\r
994         NSqlQuery query = new NSqlQuery(db.getConnection());\r
995                 query.exec("select count(*) from note where indexneeded=true and isExpunged = false");\r
996                 query.next(); \r
997                 int returnValue = new Integer(query.valueString(0));\r
998                 return returnValue;\r
999         }\r
1000         // Count unsynchronized notes\r
1001         public int getDirtyCount() {\r
1002         NSqlQuery query = new NSqlQuery(db.getConnection());\r
1003                 query.exec("select count(guid) from note where isDirty=true and isExpunged = false");\r
1004                 query.next(); \r
1005                 int returnValue = new Integer(query.valueString(0));\r
1006                 return returnValue;\r
1007         }\r
1008         // Count notes\r
1009         public int getNoteCount() {\r
1010         NSqlQuery query = new NSqlQuery(db.getConnection());\r
1011                 query.exec("select count(*) from note where isExpunged = false");\r
1012                 query.next(); \r
1013                 int returnValue = new Integer(query.valueString(0));\r
1014                 return returnValue;\r
1015         }\r
1016         // Count deleted notes\r
1017         public int getDeletedCount() {\r
1018         NSqlQuery query = new NSqlQuery(db.getConnection());\r
1019                 query.exec("select count(*) from note where isExpunged = false and active = false");\r
1020                 if (!query.next()) \r
1021                         return 0;\r
1022                 int returnValue = new Integer(query.valueString(0));\r
1023                 return returnValue;\r
1024         }\r
1025         // Reset a note sequence number to zero.  This is useful for moving conflicting notes\r
1026         public void resetNoteSequence(String guid) {\r
1027                 NSqlQuery query = new NSqlQuery(db.getConnection());\r
1028                 boolean check = query.prepare("Update Note set updateSequenceNumber=0, isDirty=true where guid=:guid");\r
1029                 if (!check) {\r
1030                         logger.log(logger.EXTREME, "Update note ResetSequence sql prepare has failed.");\r
1031                         logger.log(logger.MEDIUM, query.lastError());\r
1032                 }\r
1033                 query.bindValue(":guid", guid);\r
1034                 check = query.exec();\r
1035                 if (!check) {\r
1036                         logger.log(logger.EXTREME, "Update note sequence number has failed.");\r
1037                         logger.log(logger.MEDIUM, query.lastError());\r
1038                 }\r
1039         }\r
1040         \r
1041         \r
1042         // Update a note resource by the hash\r
1043         public void updateNoteResourceGuidbyHash(String noteGuid, String resGuid, String hash) {\r
1044                 NSqlQuery query = new NSqlQuery(db.getResourceConnection());\r
1045 /*              query.prepare("Select guid from NoteResources where noteGuid=:noteGuid and datahash=:hex");\r
1046                 query.bindValue(":noteGuid", noteGuid);\r
1047                 query.bindValue(":hex", hash);\r
1048                 query.exec();\r
1049                 if (!query.next()) {\r
1050                         logger.log(logger.LOW, "Error finding note resource in RNoteTable.updateNoteResourceGuidbyHash.  GUID="+noteGuid +" resGuid="+ resGuid+" hash="+hash);\r
1051                         return;\r
1052                 }\r
1053                 String guid = query.valueString(0);\r
1054 */              \r
1055                 query.prepare("update noteresources set guid=:guid where noteGuid=:noteGuid and datahash=:hex");\r
1056                 query.bindValue(":guid", resGuid);\r
1057                 query.bindValue(":noteGuid", noteGuid);\r
1058                 query.bindValue(":hex", hash);\r
1059                 if (!query.exec()) {\r
1060                         logger.log(logger.EXTREME, "Note Resource Update by Hash failed");\r
1061                         logger.log(logger.EXTREME, query.lastError().toString());\r
1062                 }\r
1063         }\r
1064 \r
1065         // Fix CRLF problem that is on some notes\r
1066         private String fixCarriageReturn(String note) {\r
1067                 if (note == null || !Global.enableCarriageReturnFix)\r
1068                         return note;\r
1069                 QByteArray a0Hex = new QByteArray("a0");\r
1070                 String a0 = QByteArray.fromHex(a0Hex).toString();\r
1071                 note = note.replace("<div>"+a0+"</div>", "<div>&nbsp;</div>");\r
1072                 return note.replace("<div/>", "<div>&nbsp;</div>");\r
1073         }\r
1074         \r
1075         // Expunge notes that we don't want to synchronize\r
1076         public List<String> expungeIgnoreSynchronizedNotes(List<String> notebooks, List<String>tags, List<String> linked) {\r
1077                 \r
1078                 List<String> noteGuids = new ArrayList<String>();\r
1079                 for (int i=0; i<notebooks.size(); i++) {\r
1080                         List<String> notes = findNotesByNotebook(notebooks.get(i));\r
1081                         for (int j=0; j<notes.size(); j++) {\r
1082                                 if (!isNoteDirty(notes.get(j))) {\r
1083                                         expungeNote(notes.get(j), true, false);\r
1084                                         noteGuids.add(notes.get(j));\r
1085                                 }\r
1086                         }\r
1087                 }\r
1088                 \r
1089                 for (int i=0; i<tags.size(); i++) {\r
1090                         List<String> notes = findNotesByTag(tags.get(i));\r
1091                         for (int j=0; j<notes.size(); j++) {\r
1092                                 if (!isNoteDirty(notes.get(j))) {\r
1093                                         expungeNote(notes.get(j), true, false);\r
1094                                         noteGuids.add(notes.get(j));\r
1095                                 }\r
1096                         }\r
1097                 }\r
1098                 \r
1099                 for (int i=0; i<linked.size(); i++) {\r
1100                         String notebookGuid = db.getLinkedNotebookTable().getNotebookGuid(linked.get(i));\r
1101                         if (notebookGuid != null && !notebookGuid.trim().equals("")) {\r
1102                                 List<Tag> linkedTags = db.getTagTable().getTagsForNotebook(notebookGuid);\r
1103                                 for (int j=0; j<linkedTags.size(); j++)\r
1104                                         db.getTagTable().expungeTag(linkedTags.get(j).getGuid(), false);\r
1105                                 \r
1106                                 List<String> notes = findNotesByNotebook(notebookGuid);\r
1107                                 for (int j=0; j<notes.size(); j++) {\r
1108                                         if (!isNoteDirty(notes.get(j))) {\r
1109                                                 expungeNote(notes.get(j), true, false);\r
1110                                                 noteGuids.add(notes.get(j));\r
1111                                         }\r
1112                                 }\r
1113                         }\r
1114                 }\r
1115                 return noteGuids;\r
1116         }\r
1117         \r
1118         // Find a note by its notebook\r
1119         // Expunge notes that we don't want to synchronize\r
1120         public List<String> findNotesByNotebook(String notebook) {\r
1121                 List<String> values = new ArrayList<String>();\r
1122                 NSqlQuery query = new NSqlQuery(db.getConnection());\r
1123                 query.prepare("Select guid from note where notebookguid=:notebook");\r
1124 \r
1125                 query.bindValue(":notebook", notebook);\r
1126                 query.exec();\r
1127                 while (query.next()) {\r
1128                         values.add(query.valueString(0));\r
1129                 }\r
1130                 return values;\r
1131         }\r
1132         \r
1133         public List<String> findNotesByTag(String tag) {\r
1134                 List<String> values = new ArrayList<String>();\r
1135                 NSqlQuery query = new NSqlQuery(db.getConnection());\r
1136                 query.prepare("Select distinct noteguid from notetags where tagguid=:tag");\r
1137 \r
1138                 query.bindValue(":tag", tag);\r
1139                 query.exec();\r
1140                 while (query.next()) {\r
1141                         values.add(query.valueString(0));\r
1142                 }\r
1143                 return values;\r
1144         }\r
1145         \r
1146         \r
1147         \r
1148         //********************************************************************************\r
1149         //********************************************************************************\r
1150         //* Indexing Functions\r
1151         //********************************************************************************\r
1152         //********************************************************************************\r
1153         // set/unset a note to be reindexed\r
1154         public void setIndexNeeded(String guid, Boolean flag) {\r
1155                 NSqlQuery query = new NSqlQuery(db.getConnection());\r
1156                 query.prepare("Update Note set indexNeeded=:flag where guid=:guid");\r
1157 \r
1158                 if (flag)\r
1159                         query.bindValue(":flag", 1);\r
1160                 else\r
1161                         query.bindValue(":flag", 0);\r
1162                 query.bindValue(":guid", guid);\r
1163                 if (!query.exec()) {\r
1164                         logger.log(logger.MEDIUM, "Note indexNeeded update failed.");\r
1165                         logger.log(logger.MEDIUM, query.lastError());\r
1166                 } \r
1167                 List<Resource> r = noteResourceTable.getNoteResources(guid, false);\r
1168                 for (int i=0; r!= null && i<r.size(); i++) {\r
1169                         noteResourceTable.setIndexNeeded(r.get(i).getGuid(), true);\r
1170                 }\r
1171         }\r
1172         // Set all notes to be reindexed\r
1173         public void reindexAllNotes() {\r
1174                 NSqlQuery query = new NSqlQuery(db.getConnection());\r
1175                 if (!query.exec("Update Note set indexNeeded=true")) {\r
1176                         logger.log(logger.MEDIUM, "Note reindexAllNotes update failed.");\r
1177                         logger.log(logger.MEDIUM, query.lastError());\r
1178                 } \r
1179         }\r
1180 \r
1181         // Get all unindexed notes\r
1182         public List <String> getUnindexed() {\r
1183                 String guid;\r
1184                 List<String> index = new ArrayList<String>();\r
1185         NSqlQuery query = new NSqlQuery(db.getConnection());\r
1186                                         \r
1187                 if (!query.exec("Select guid from Note where isExpunged = false and indexNeeded = true and DATEDIFF('MINUTE',updated,CURRENT_TIMESTAMP)>5"))\r
1188                         logger.log(logger.EXTREME, "Note SQL retrieve has failed on getUnindexed().");\r
1189 \r
1190                 // Get a list of the notes\r
1191                 while (query.next()) {\r
1192                         guid = new String();\r
1193                         guid = query.valueString(0);\r
1194                         index.add(guid); \r
1195                 }       \r
1196                 return index;   \r
1197         }\r
1198         public List<String> getNextUnindexed(int limit) {\r
1199                 List<String> guids = new ArrayList<String>();\r
1200                         \r
1201         NSqlQuery query = new NSqlQuery(db.getConnection());\r
1202                                         \r
1203                 if (!query.exec("Select guid from Note where isExpunged = false and indexNeeded = true and DATEDIFF('MINUTE',Updated,CURRENT_TIMESTAMP)>5 limit " +limit))\r
1204                         logger.log(logger.EXTREME, "Note SQL retrieve has failed on getUnindexed().");\r
1205                 \r
1206                 // Get a list of the notes\r
1207                 String guid;\r
1208                 while (query.next()) {\r
1209                         guid = new String();\r
1210                         guid = query.valueString(0);\r
1211                         guids.add(guid);\r
1212                 }       \r
1213                 return guids;   \r
1214         }\r
1215         \r
1216         \r
1217         //**********************************************************************************\r
1218         //* Title color functions\r
1219         //**********************************************************************************\r
1220         // Get the title color of all notes\r
1221         public List<Pair<String, Integer>> getNoteTitleColors() {\r
1222                 List<Pair<String,Integer>> returnValue = new ArrayList<Pair<String,Integer>>();\r
1223         NSqlQuery query = new NSqlQuery(db.getConnection());\r
1224                 \r
1225                 if (!query.exec("Select guid,titleColor from Note where titleColor != -1"))\r
1226                         logger.log(logger.EXTREME, "Note SQL retrieve has failed on getUnindexed().");\r
1227 \r
1228                 String guid;\r
1229                 Integer color;\r
1230                 \r
1231                 // Get a list of the notes\r
1232                 while (query.next()) {\r
1233                         Pair<String, Integer> pair = new Pair<String,Integer>();\r
1234                         guid = query.valueString(0);\r
1235                         color = query.valueInteger(1);\r
1236                         pair.setFirst(guid);\r
1237                         pair.setSecond(color);\r
1238                         returnValue.add(pair); \r
1239                 }       \r
1240 \r
1241                 return returnValue;\r
1242         }\r
1243         // Set a title color\r
1244         public void  setNoteTitleColor(String guid, int color) {\r
1245                 NSqlQuery query = new NSqlQuery(db.getConnection());\r
1246                 \r
1247                 query.prepare("Update note set titlecolor=:color where guid=:guid");\r
1248                 query.bindValue(":guid", guid);\r
1249                 query.bindValue(":color", color);\r
1250                 if (!query.exec())\r
1251                         logger.log(logger.EXTREME, "Error updating title color.");\r
1252         }\r
1253         // Get in individual note's title color\r
1254         // Get the title color of all notes\r
1255         public Integer getNoteTitleColor(String guid) {\r
1256                 List<Pair<String,Integer>> returnValue = new ArrayList<Pair<String,Integer>>();\r
1257         NSqlQuery query = new NSqlQuery(db.getConnection());\r
1258                 \r
1259         query.prepare("Select titleColor from Note where titleColor != -1 and guid=:guid");\r
1260         query.bindValue(":guid", guid);\r
1261                 if (!query.exec())\r
1262                         logger.log(logger.EXTREME, "Note SQL retrieve has failed on getNoteTitleColor(guid).");\r
1263 \r
1264                 Integer color = -1;\r
1265                 \r
1266                 // Get a list of the notes\r
1267                 while (query.next()) {\r
1268                         Pair<String, Integer> pair = new Pair<String,Integer>();\r
1269                         guid = query.valueString(0);\r
1270                         color = query.valueInteger(1);\r
1271                         pair.setFirst(guid);\r
1272                         pair.setSecond(color);\r
1273                         returnValue.add(pair); \r
1274                 }       \r
1275 \r
1276                 \r
1277                 return color;\r
1278         }\r
1279         \r
1280         \r
1281         //**********************************************************************************\r
1282         //* Thumbnail functions\r
1283         //**********************************************************************************\r
1284         // Set if a new thumbnail is needed\r
1285         public void setThumbnailNeeded(String guid, boolean needed) {\r
1286                 \r
1287                 boolean check;                  \r
1288         NSqlQuery query = new NSqlQuery(db.getConnection());\r
1289                                         \r
1290                 check = query.prepare("Update note set thumbnailneeded = :needed where guid=:guid");\r
1291                 query.bindValue(":guid", guid);\r
1292                 query.bindValue(":needed", needed);\r
1293                 check = query.exec();\r
1294                 if (!check) \r
1295                         logger.log(logger.EXTREME, "Note SQL set thumbail needed failed: " +query.lastError().toString());\r
1296 \r
1297         }\r
1298         // Is a thumbail needed for this guid?\r
1299         public boolean isThumbnailNeeded(String guid) {\r
1300                 \r
1301                 boolean check;                  \r
1302         NSqlQuery query = new NSqlQuery(db.getConnection());\r
1303                                         \r
1304                 check = query.prepare("select thumbnailneeded from note where guid=:guid");\r
1305                 query.bindValue(":guid", guid);\r
1306                 check = query.exec();\r
1307                 if (!check) \r
1308                         logger.log(logger.EXTREME, "Note SQL isThumbnailNeeded query failed: " +query.lastError().toString());\r
1309                 \r
1310                 boolean returnValue;\r
1311                 // Get a list of the notes\r
1312                 if (query.next()) \r
1313                         returnValue = query.valueBoolean(0, false); \r
1314                 else\r
1315                         returnValue = false;\r
1316 \r
1317                 return returnValue;     \r
1318         }\r
1319         // Set if a new thumbnail is needed\r
1320         public void setThumbnail(String guid, QByteArray thumbnail) {\r
1321                 \r
1322                 boolean check;                  \r
1323         NSqlQuery query = new NSqlQuery(db.getConnection());\r
1324                                         \r
1325                 check = query.prepare("Update note set thumbnail = :thumbnail where guid=:guid");\r
1326                 query.bindValue(":guid", guid);\r
1327                 query.bindValue(":thumbnail", thumbnail.toByteArray());\r
1328                 check = query.exec();\r
1329                 if (!check) \r
1330                         logger.log(logger.EXTREME, "Note SQL set thumbail failed: " +query.lastError().toString());\r
1331 \r
1332         }\r
1333         // Set if a new thumbnail is needed\r
1334         public QByteArray getThumbnail(String guid) {\r
1335                 \r
1336                 boolean check;                  \r
1337         NSqlQuery query = new NSqlQuery(db.getConnection());\r
1338                                         \r
1339                 check = query.prepare("Select thumbnail from note where guid=:guid");\r
1340                 query.bindValue(":guid", guid);\r
1341                 check = query.exec();\r
1342                 if (!check) \r
1343                         logger.log(logger.EXTREME, "Note SQL get thumbail failed: " +query.lastError().toString());\r
1344                 // Get a list of the notes\r
1345                 if (query.next())  {\r
1346                         try {\r
1347                                 if (query.getBlob(0) != null) {\r
1348                                         return new QByteArray(query.getBlob(0)); \r
1349                                 }\r
1350                         } catch (java.lang.IllegalArgumentException e) {\r
1351                                 return null;\r
1352                         }\r
1353                 }\r
1354                 return null;\r
1355         }\r
1356         // Get all thumbnails\r
1357         public HashMap<String, QPixmap> getThumbnails() {\r
1358                 boolean check;                  \r
1359         NSqlQuery query = new NSqlQuery(db.getConnection());\r
1360         HashMap<String, QPixmap> map = new HashMap<String,QPixmap>();\r
1361                                         \r
1362                 check = query.prepare("Select guid,thumbnail from note where thumbnailneeded=false and isExpunged=false");\r
1363                 check = query.exec();\r
1364                 if (!check) \r
1365                         logger.log(logger.EXTREME, "Note SQL get thumbail failed: " +query.lastError().toString());\r
1366                 // Get a list of the notes\r
1367                 while (query.next())  {\r
1368                         try {\r
1369                                 if (query.getBlob(1) != null) {\r
1370                                         QByteArray data = new QByteArray(query.getBlob(1));\r
1371                                         QPixmap img = new QPixmap();\r
1372                                         if (img.loadFromData(data)) {\r
1373                                                 img = img.scaled(Global.largeThumbnailSize);\r
1374                                                 map.put(query.valueString(0), img);\r
1375                                         }\r
1376                                 }       \r
1377                         } catch (java.lang.IllegalArgumentException e) {\r
1378                                 logger.log(logger.HIGH, "Error retrieving thumbnail " +e.getMessage());\r
1379                         }\r
1380                 }\r
1381                 return map;\r
1382         }\r
1383         // Get a list of notes that need thumbnails\r
1384         public List<String> findThumbnailsNeeded() {\r
1385                 \r
1386                 boolean check;\r
1387         NSqlQuery query = new NSqlQuery(db.getConnection());\r
1388                                         \r
1389                 check = query.prepare("select guid from note where thumbnailneeded=true and isExpunged=false and DATEDIFF('MINUTE',updated,CURRENT_TIMESTAMP)>5 limit 5");\r
1390                 check = query.exec();\r
1391                 if (!check) \r
1392                         logger.log(logger.EXTREME, "Note SQL findThumbnailsNeeded query failed: " +query.lastError().toString());\r
1393                 \r
1394 \r
1395                 // Get a list of the notes\r
1396                 List<String> values = new ArrayList<String>();\r
1397                 while (query.next()) {\r
1398                         values.add(query.valueString(0)); \r
1399                 }\r
1400 \r
1401                 return values;  \r
1402         }\r
1403         // Get a count of thumbnails needed\r
1404         public int getThumbnailNeededCount() {\r
1405                 \r
1406                 boolean check;\r
1407         NSqlQuery query = new NSqlQuery(db.getConnection());\r
1408                                         \r
1409                 check = query.prepare("select count(guid) from note where thumbnailneeded=true and isExpunged=false and DATEDIFF('MINUTE',updated,CURRENT_TIMESTAMP)>5 limit 2");\r
1410                 check = query.exec();\r
1411                 if (!check) \r
1412                         logger.log(logger.EXTREME, "Note SQL findThumbnailNeededCount query failed: " +query.lastError().toString());\r
1413                 \r
1414                 if (query.next()) {\r
1415                         return query.valueInteger(0); \r
1416                 }\r
1417 \r
1418                 return 0;       \r
1419         }\r
1420 \r
1421         //***********************************************************************************\r
1422         public String findAlternateGuid(String guid) {\r
1423                 boolean check;\r
1424         NSqlQuery query = new NSqlQuery(db.getConnection());\r
1425                                         \r
1426                 check = query.prepare("select guid from note where original_guid=:guid");\r
1427                 query.bindValue(":guid", guid);\r
1428                 check = query.exec();\r
1429                 if (!check) \r
1430                         logger.log(logger.EXTREME, "Note SQL findAlternateguid query failed: " +query.lastError().toString());\r
1431                 \r
1432                 if (query.next()) {\r
1433                         return query.valueString(0); \r
1434                 }\r
1435 \r
1436                 return null;    \r
1437         }\r
1438         \r
1439         //* Check if a note guid exists\r
1440         public boolean guidExists(String guid) {\r
1441                 boolean check;\r
1442         NSqlQuery query = new NSqlQuery(db.getConnection());\r
1443                                         \r
1444                 check = query.prepare("select guid from note where guid=:guid");\r
1445                 query.bindValue(":guid", guid);\r
1446                 check = query.exec();\r
1447                 if (!check) \r
1448                         logger.log(logger.EXTREME, "Note SQL guidExists query failed: " +query.lastError().toString());\r
1449                 \r
1450                 if (query.next()) {\r
1451                         return true; \r
1452                 }\r
1453 \r
1454                 return false;                   \r
1455         }\r
1456         \r
1457         // Update a note content's hash.  This happens if a resource is edited outside of NN\r
1458         public void updateResourceContentHash(String guid, String oldHash, String newHash) {\r
1459                 Note n = getNote(guid, true, false, false, false,false);\r
1460                 int position = n.getContent().indexOf("<en-media");\r
1461                 int endPos;\r
1462                 for (;position>-1;) {\r
1463                         endPos = n.getContent().indexOf(">", position+1);\r
1464                         String oldSegment = n.getContent().substring(position,endPos);\r
1465                         int hashPos = oldSegment.indexOf("hash=\"");\r
1466                         int hashEnd = oldSegment.indexOf("\"", hashPos+7);\r
1467                         String hash = oldSegment.substring(hashPos+6, hashEnd);\r
1468                         if (hash.equalsIgnoreCase(oldHash)) {\r
1469                                 String newSegment = oldSegment.replace(oldHash, newHash);\r
1470                                 String content = n.getContent().substring(0,position) +\r
1471                                                  newSegment +\r
1472                                                  n.getContent().substring(endPos);\r
1473                                 NSqlQuery query = new NSqlQuery(db.getConnection());\r
1474                                 query.prepare("update note set isdirty=true, thumbnailneeded=true, content=:content where guid=:guid");\r
1475                                 query.bindValue(":content", content);\r
1476                                 query.bindValue(":guid", n.getGuid());\r
1477                                 query.exec();\r
1478                         }\r
1479                         \r
1480                         position = n.getContent().indexOf("<en-media", position+1);\r
1481                 }\r
1482         }\r
1483 \r
1484 }       \r
1485 \r
1486 \r
1487 \r
1488 \r