2 * This file is part of NixNote/NeighborNote
3 * Copyright 2009 Randy Baumgarte
4 * Copyright 2013 Yuki Takahashi
6 * This file may be licensed under the terms of of the
7 * GNU General Public License Version 2 (the ``GPL'').
9 * Software distributed under the License is distributed
10 * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
11 * express or implied. See the GPL for the specific language
12 * governing rights and limitations.
14 * You should have received a copy of the GPL along with this
15 * program. If not, go to http://www.gnu.org/licenses/gpl.html
16 * or write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 package cx.fbn.nevernote.sql;
24 import java.text.DateFormat;
25 import java.text.ParseException;
26 import java.text.SimpleDateFormat;
27 import java.util.ArrayList;
28 import java.util.HashMap;
29 import java.util.List;
31 import org.apache.commons.lang3.StringEscapeUtils;
33 import com.evernote.edam.type.Note;
34 import com.evernote.edam.type.NoteAttributes;
35 import com.evernote.edam.type.Resource;
36 import com.evernote.edam.type.Tag;
37 import com.trolltech.qt.core.QByteArray;
38 import com.trolltech.qt.core.QDateTime;
39 import com.trolltech.qt.core.QTextCodec;
40 import com.trolltech.qt.gui.QPixmap;
42 import cx.fbn.nevernote.Global;
43 import cx.fbn.nevernote.evernote.EnmlConverter;
44 import cx.fbn.nevernote.evernote.NoteMetadata;
45 import cx.fbn.nevernote.sql.driver.NSqlQuery;
46 import cx.fbn.nevernote.utilities.ApplicationLogger;
47 import cx.fbn.nevernote.utilities.Pair;
49 public class NoteTable {
50 private final ApplicationLogger logger;
51 public final NoteTagsTable noteTagsTable;
52 public NoteResourceTable noteResourceTable;
53 private final DatabaseConnection db;
56 // Prepared Queries to improve speed
57 private NSqlQuery getQueryWithContent;
58 private NSqlQuery getQueryWithoutContent;
59 private NSqlQuery getAllQueryWithoutContent;
62 public NoteTable(ApplicationLogger l, DatabaseConnection d) {
66 noteResourceTable = new NoteResourceTable(logger, db);
67 noteTagsTable = new NoteTagsTable(logger, db);
68 getQueryWithContent = null;
69 getQueryWithoutContent = null;
72 public void createTable() {
73 //getQueryWithContent = new NSqlQuery(db.getConnection());
74 //getQueryWithoutContent = new NSqlQuery(db.getConnection());
75 NSqlQuery query = new NSqlQuery(db.getConnection());
76 logger.log(logger.HIGH, "Creating table Note...");
77 if (!query.exec("Create table Note (guid varchar primary key, " +
78 "updateSequenceNumber integer, title varchar, content varchar, contentHash varchar, "+
79 "contentLength integer, created timestamp, updated timestamp, deleted timestamp, "
80 +"active integer, notebookGuid varchar, attributeSubjectDate timestamp, "+
81 "attributeLatitude double, attributeLongitude double, attributeAltitude double,"+
82 "attributeAuthor varchar, attributeSource varchar, attributeSourceUrl varchar, "+
83 "attributeSourceApplication varchar, indexNeeded boolean, isExpunged boolean, " +
85 logger.log(logger.HIGH, "Table Note creation FAILED!!!");
86 if (!query.exec("CREATE INDEX unindexed_notess on note (indexneeded desc, guid);"))
87 logger.log(logger.HIGH, "Note unindexed_notes index creation FAILED!!!");
88 if (!query.exec("CREATE INDEX unsynchronized_notes on note (isDirty desc, guid);"))
89 logger.log(logger.HIGH, "note unsynchronized_notes index creation FAILED!!!");
90 noteTagsTable.createTable();
91 // noteResourceTable.createTable();
94 public void dropTable() {
95 NSqlQuery query = new NSqlQuery(db.getConnection());
96 query.exec("Drop table Note");
97 noteTagsTable.dropTable();
98 noteResourceTable.dropTable();
100 // Save Note List from Evernote
101 public void addNote(Note n, boolean isDirty) {
102 logger.log(logger.EXTREME, "Inside addNote");
106 SimpleDateFormat simple = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
108 NSqlQuery query = new NSqlQuery(db.getConnection());
109 query.prepare("Insert Into Note ("
110 +"guid, updateSequenceNumber, title, content, "
111 +"contentHash, contentLength, created, updated, deleted, active, notebookGuid, "
112 +"attributeSubjectDate, attributeLatitude, attributeLongitude, attributeAltitude, "
113 +"attributeAuthor, attributeSource, attributeSourceUrl, attributeSourceApplication, "
114 +"indexNeeded, isExpunged, isDirty, titlecolor, thumbnailneeded"
116 +":guid, :updateSequenceNumber, :title, :content, "
117 +":contentHash, :contentLength, :created, :updated, :deleted, :active, :notebookGuid, "
118 +":attributeSubjectDate, :attributeLatitude, :attributeLongitude, :attributeAltitude, "
119 +":attributeAuthor, :attributeSource, :attributeSourceUrl, :attributeSourceApplication, "
120 +":indexNeeded, :isExpunged, :isDirty, -1, true) ");
122 StringBuilder created = new StringBuilder(simple.format(n.getCreated()));
123 StringBuilder updated = new StringBuilder(simple.format(n.getUpdated()));
124 StringBuilder deleted = new StringBuilder(simple.format(n.getDeleted()));
128 query.bindValue(":guid", n.getGuid());
129 query.bindValue(":updateSequenceNumber", n.getUpdateSequenceNum());
130 query.bindValue(":title", n.getTitle());
132 EnmlConverter enml = new EnmlConverter(logger);
133 query.bindValue(":content", enml.fixEnXMLCrap(enml.fixEnMediaCrap(n.getContent())));
136 query.bindValue(":content", n.getContent());
137 query.bindValue(":contentHash", n.getContentHash());
138 query.bindValue(":contentLength", n.getContentLength());
139 query.bindValue(":created", created.toString());
140 query.bindValue(":updated", updated.toString());
141 query.bindValue(":deleted", deleted.toString());
142 query.bindValue(":active", n.isActive());
143 query.bindValue(":notebookGuid", n.getNotebookGuid());
145 if (n.getAttributes() != null) {
146 created = new StringBuilder(simple.format(n.getAttributes().getSubjectDate()));
147 query.bindValue(":attributeSubjectDate", created.toString());
148 query.bindValue(":attributeLatitude", n.getAttributes().getLatitude());
149 query.bindValue(":attributeLongitude", n.getAttributes().getLongitude());
150 query.bindValue(":attributeAltitude", n.getAttributes().getAltitude());
151 query.bindValue(":attributeAuthor", n.getAttributes().getAuthor());
152 query.bindValue(":attributeSource", n.getAttributes().getSource());
153 query.bindValue(":attributeSourceUrl", n.getAttributes().getSourceURL());
154 query.bindValue(":attributeSourceApplication", n.getAttributes().getSourceApplication());
156 created = new StringBuilder(simple.format(n.getCreated()));
157 query.bindValue(":attributeSubjectDate", created.toString());
158 query.bindValue(":attributeLatitude", 0.0);
159 query.bindValue(":attributeLongitude", 0.0);
160 query.bindValue(":attributeAltitude", 0.0);
161 query.bindValue(":attributeAuthor", "");
162 query.bindValue(":attributeSource", "");
163 query.bindValue(":attributeSourceUrl", "");
164 query.bindValue(":attributeSourceApplication", "");
166 query.bindValue(":indexNeeded", true);
167 query.bindValue(":isExpunged", false);
168 query.bindValue(":isDirty", isDirty);
172 logger.log(logger.MEDIUM, query.lastError());
174 // Save the note tags
175 if (n.getTagGuids() != null) {
176 for (int i=0; i<n.getTagGuids().size(); i++)
177 noteTagsTable.saveNoteTag(n.getGuid(), n.getTagGuids().get(i), isDirty);
\r
179 logger.log(logger.EXTREME, "Leaving addNote");
181 // Setup queries for get to save time later
182 private void prepareQueries() {
183 if (getQueryWithContent == null) {
184 getQueryWithContent = new NSqlQuery(db.getConnection());
185 if (!getQueryWithContent.prepare("Select "
186 +"guid, updateSequenceNumber, title, "
187 +"created, updated, deleted, active, notebookGuid, "
188 +"attributeSubjectDate, attributeLatitude, attributeLongitude, attributeAltitude, "
189 +"attributeAuthor, attributeSource, attributeSourceUrl, attributeSourceApplication, "
190 +"attributeContentClass, "
191 +"content, contentHash, contentLength"
192 +" from Note where guid=:guid and isExpunged=false")) {
193 logger.log(logger.EXTREME, "Note SQL select prepare with content has failed.");
194 logger.log(logger.MEDIUM, getQueryWithContent.lastError());
198 if (getQueryWithoutContent == null) {
199 getQueryWithoutContent = new NSqlQuery(db.getConnection());
200 if (!getQueryWithoutContent.prepare("Select "
201 +"guid, updateSequenceNumber, title, "
202 +"created, updated, deleted, active, notebookGuid, "
203 +"attributeSubjectDate, attributeLatitude, attributeLongitude, attributeAltitude, "
204 +"attributeAuthor, attributeSource, attributeSourceUrl, attributeSourceApplication, "
205 +"attributeContentClass"
206 +" from Note where guid=:guid and isExpunged=false")) {
207 logger.log(logger.EXTREME, "Note SQL select prepare without content has failed.");
208 logger.log(logger.MEDIUM, getQueryWithoutContent.lastError());
212 if (getAllQueryWithoutContent == null) {
213 getAllQueryWithoutContent = new NSqlQuery(db.getConnection());
215 if (!getAllQueryWithoutContent.prepare("Select "
216 +"guid, updateSequenceNumber, title, "
217 +"created, updated, deleted, active, notebookGuid, "
218 +"attributeSubjectDate, attributeLatitude, attributeLongitude, attributeAltitude, "
219 +"attributeAuthor, attributeSource, attributeSourceUrl, attributeSourceApplication, "
220 +"attributeContentClass "
221 +" from Note where isExpunged = false")) {
222 logger.log(logger.EXTREME, "Note SQL select prepare without content has failed.");
223 logger.log(logger.MEDIUM, getQueryWithoutContent.lastError());
229 // Get a note's content in blob format for index.
230 public String getNoteContentNoUTFConversion(String guid) {
231 NSqlQuery query = new NSqlQuery(db.getConnection());
232 query.prepare("Select content from note where guid=:guid");
233 query.bindValue(":guid", guid);
236 return query.valueString(0);
238 // Get a note by Guid
239 public Note getNote(String noteGuid, boolean loadContent, boolean loadResources, boolean loadRecognition, boolean loadBinary, boolean loadTags) {
242 // extractMetadata("otherKey:{values};kimaira792:{titleColor=fff;pinned=true;};finalKey:{values1);");
243 if (noteGuid == null)
245 if (noteGuid.trim().equals(""))
251 query = getQueryWithContent;
253 query = getQueryWithoutContent;
256 query.bindValue(":guid", noteGuid);
258 logger.log(logger.EXTREME, "Note SQL select exec has failed.");
259 logger.log(logger.MEDIUM, query.lastError());
263 logger.log(logger.EXTREME, "SQL Retrieve failed for note guid " +noteGuid + " in getNote()");
264 logger.log(logger.EXTREME, " -> " +query.lastError().toString());
265 logger.log(logger.EXTREME, " -> " +query.lastError());
268 Note n = mapNoteFromQuery(query, loadContent, loadResources, loadRecognition, loadBinary, loadTags);
269 n.setContent(fixCarriageReturn(n.getContent()));
270 n.getAttributes().setContentClassIsSet(false);
273 // Get a note by Guid
274 public Note mapNoteFromQuery(NSqlQuery query, boolean loadContent, boolean loadResources, boolean loadRecognition, boolean loadBinary, boolean loadTags) {
275 DateFormat indfm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");
276 // indfm = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy");
279 NoteAttributes na = new NoteAttributes();
282 n.setGuid(query.valueString(0));
283 n.setUpdateSequenceNum(new Integer(query.valueString(1)));
284 n.setTitle(query.valueString(2));
287 n.setCreated(indfm.parse(query.valueString(3)).getTime());
288 n.setUpdated(indfm.parse(query.valueString(4)).getTime());
289 n.setDeleted(indfm.parse(query.valueString(5)).getTime());
290 } catch (ParseException e) {
294 n.setActive(query.valueBoolean(6,true));
295 n.setNotebookGuid(query.valueString(7));
298 String attributeSubjectDate = query.valueString(8);
299 if (!attributeSubjectDate.equals(""))
300 na.setSubjectDate(indfm.parse(attributeSubjectDate).getTime());
301 } catch (ParseException e) {
304 na.setLatitude(new Float(query.valueString(9)));
305 na.setLongitude(new Float(query.valueString(10)));
306 na.setAltitude(new Float(query.valueString(11)));
307 na.setAuthor(query.valueString(12));
308 na.setSource(query.valueString(13));
309 na.setSourceURL(query.valueString(14));
310 na.setSourceApplication(query.valueString(15));
311 na.setContentClass(query.valueString(16));
314 List<String> tagGuids = noteTagsTable.getNoteTags(n.getGuid());
315 List<String> tagNames = new ArrayList<String>();
316 TagTable tagTable = db.getTagTable();
317 for (int i=0; i<tagGuids.size(); i++) {
318 String currentGuid = tagGuids.get(i);
319 Tag tag = tagTable.getTag(currentGuid);
320 if (tag.getName() != null)
321 tagNames.add(tag.getName());
326 n.setTagNames(tagNames);
327 n.setTagGuids(tagGuids);
331 QTextCodec codec = QTextCodec.codecForLocale();
332 codec = QTextCodec.codecForName("UTF-8");
333 String unicode = codec.fromUnicode(query.valueString(17)).toString();
335 // This is a hack. Basically I need to convert HTML Entities to "normal" text, but if I
336 // convert the < character to < it will mess up the XML parsing. So, to get around this
337 // I am "bit stuffing" the < to &< so StringEscapeUtils doesn't unescape it. After
338 // I'm done I convert it back.
339 StringBuffer buffer = new StringBuffer(unicode);
340 if (Global.enableHTMLEntitiesFix && unicode.indexOf("&#") > 0) {
341 unicode = query.valueString(17);
342 //System.out.println(unicode);
343 //unicode = unicode.replace("<", "&_lt;");
344 //unicode = codec.fromUnicode(StringEscapeUtils.unescapeHtml(unicode)).toString();
345 //unicode = unicode.replace("&_lt;", "<");
346 //System.out.println("************************");
348 for (int i=buffer.indexOf("&#"); i != -1 && buffer.indexOf("&#", i)>0; i=buffer.indexOf("&#",i+1)) {
349 j = buffer.indexOf(";",i)+1;
351 String entity = buffer.substring(i,j).toString();
352 int len = entity.length()-1;
353 String tempEntity = entity.substring(2, len);
355 Integer.parseInt(tempEntity);
356 entity = codec.fromUnicode(StringEscapeUtils.unescapeHtml4(entity)).toString();
358 buffer.insert(i, entity);
359 } catch (Exception e){ }
365 n.setContent(unicode);
366 // n.setContent(query.valueString(16).toString());
368 String contentHash = query.valueString(18);
369 if (contentHash != null)
370 n.setContentHash(contentHash.getBytes());
371 n.setContentLength(new Integer(query.valueString(19)));
374 n.setResources(noteResourceTable.getNoteResources(n.getGuid(), loadBinary));
375 if (loadRecognition) {
376 if (n.getResources() == null) {
377 List<Resource> resources = noteResourceTable.getNoteResourcesRecognition(n.getGuid());
378 n.setResources(resources);
380 // We need to merge the recognition resources with the note resources retrieved earlier
381 for (int i=0; i<n.getResources().size(); i++) {
382 Resource r = noteResourceTable.getNoteResourceRecognition(n.getResources().get(i).getGuid());
383 n.getResources().get(i).setRecognition(r.getRecognition());
387 n.setContent(fixCarriageReturn(n.getContent()));
390 // Update a note's title
391 public void updateNoteTitle(String guid, String title) {
392 logger.log(logger.HIGH, "Entering NoteTable.updateNoteTitle");
393 NSqlQuery query = new NSqlQuery(db.getConnection());
394 boolean check = query.prepare("Update Note set title=:title, isDirty=true where guid=:guid");
396 logger.log(logger.EXTREME, "Update note title sql prepare has failed.");
397 logger.log(logger.MEDIUM, query.lastError());
399 query.bindValue(":title", title);
400 query.bindValue(":guid", guid);
401 check = query.exec();
403 logger.log(logger.EXTREME, "Update note title has failed.");
404 logger.log(logger.MEDIUM, query.lastError());
406 logger.log(logger.HIGH, "Leaving NoteTable.updateNoteTitle");
408 // Update a note's creation date
409 public void updateNoteCreatedDate(String guid, QDateTime date) {
410 logger.log(logger.HIGH, "Entering NoteTable.updateNoteCreatedDate");
411 NSqlQuery query = new NSqlQuery(db.getConnection());
412 boolean check = query.prepare("Update Note set created=:created, isDirty=true where guid=:guid");
414 logger.log(logger.EXTREME, "Update note creation update sql prepare has failed.");
415 logger.log(logger.MEDIUM, query.lastError());
418 query.bindValue(":created", date.toString("yyyy-MM-dd HH:mm:ss"));
419 query.bindValue(":guid", guid);
421 check = query.exec();
423 logger.log(logger.EXTREME, "Update note creation date has failed.");
424 logger.log(logger.MEDIUM, query.lastError());
426 logger.log(logger.HIGH, "Leaving NoteTable.updateNoteCreatedDate");
428 // Update a note's creation date
429 public void updateNoteAlteredDate(String guid, QDateTime date) {
430 logger.log(logger.HIGH, "Entering NoteTable.updateNoteAlteredDate");
431 NSqlQuery query = new NSqlQuery(db.getConnection());
432 boolean check = query.prepare("Update Note set updated=:altered, isDirty=true where guid=:guid");
434 logger.log(logger.EXTREME, "Update note altered sql prepare has failed.");
435 logger.log(logger.MEDIUM, query.lastError());
438 query.bindValue(":altered", date.toString("yyyy-MM-dd HH:mm:ss"));
439 query.bindValue(":guid", guid);
441 check = query.exec();
443 logger.log(logger.EXTREME, "Update note altered date has failed.");
444 logger.log(logger.MEDIUM, query.lastError());
446 logger.log(logger.HIGH, "Leaving NoteTable.updateNoteAlteredDate");
448 // Update a note's creation date
449 public void updateNoteSubjectDate(String guid, QDateTime date) {
450 logger.log(logger.HIGH, "Entering NoteTable.updateNoteSubjectDate");
451 NSqlQuery query = new NSqlQuery(db.getConnection());
452 boolean check = query.prepare("Update Note set attributeSubjectDate=:altered, isDirty=true where guid=:guid");
454 logger.log(logger.EXTREME, "Update note subject date sql prepare has failed.");
455 logger.log(logger.MEDIUM, query.lastError());
458 query.bindValue(":altered", date.toString("yyyy-MM-dd HH:mm:ss"));
459 query.bindValue(":guid", guid);
461 check = query.exec();
463 logger.log(logger.EXTREME, "Update note subject date date has failed.");
464 logger.log(logger.MEDIUM, query.lastError());
466 logger.log(logger.HIGH, "Leaving NoteTable.updateNoteSubjectDate");
468 // Update a note's creation date
469 public void updateNoteAuthor(String guid, String author) {
470 logger.log(logger.HIGH, "Entering NoteTable.updateNoteSubject");
471 NSqlQuery query = new NSqlQuery(db.getConnection());
472 boolean check = query.prepare("Update Note set attributeAuthor=:author, isDirty=true where guid=:guid");
474 logger.log(logger.EXTREME, "Update note author sql prepare has failed.");
475 logger.log(logger.MEDIUM, query.lastError());
478 query.bindValue(":author", author);
479 query.bindValue(":guid", guid);
481 check = query.exec();
483 logger.log(logger.EXTREME, "Update note author has failed.");
484 logger.log(logger.MEDIUM, query.lastError());
486 logger.log(logger.HIGH, "Leaving NoteTable.updateNoteSubject");
488 // Update a note's geo tags
489 public void updateNoteGeoTags(String guid, Double lon, Double lat, Double alt) {
490 logger.log(logger.HIGH, "Entering NoteTable.updateNoteGeoTags");
491 NSqlQuery query = new NSqlQuery(db.getConnection());
492 boolean check = query.prepare("Update Note set attributeLongitude=:longitude, "+
493 "attributeLatitude=:latitude, attributeAltitude=:altitude, isDirty=true where guid=:guid");
495 logger.log(logger.EXTREME, "Update note author sql prepare has failed.");
496 logger.log(logger.MEDIUM, query.lastError());
499 query.bindValue(":longitude", lon);
500 query.bindValue(":latitude", lat);
501 query.bindValue(":altitude", alt);
502 query.bindValue(":guid", guid);
504 check = query.exec();
506 logger.log(logger.EXTREME, "Update note geo tag has failed.");
507 logger.log(logger.MEDIUM, query.lastError());
509 logger.log(logger.HIGH, "Leaving NoteTable.updateNoteGeoTags");
512 // Update a note's creation date
513 public void updateNoteSourceUrl(String guid, String url) {
514 logger.log(logger.HIGH, "Entering NoteTable.updateNoteSourceUrl");
515 NSqlQuery query = new NSqlQuery(db.getConnection());
516 boolean check = query.prepare("Update Note set attributeSourceUrl=:url, isDirty=true where guid=:guid");
518 logger.log(logger.EXTREME, "Update note url sql prepare has failed.");
519 logger.log(logger.MEDIUM, query.lastError());
522 query.bindValue(":url", url);
523 query.bindValue(":guid", guid);
525 check = query.exec();
527 logger.log(logger.EXTREME, "Update note url has failed.");
528 logger.log(logger.MEDIUM, query.lastError());
530 logger.log(logger.HIGH, "Leaving NoteTable.updateNoteSourceUrl");
532 // Update the notebook that a note is assigned to
533 public void updateNoteNotebook(String guid, String notebookGuid, boolean expungeFromRemote) {
534 logger.log(logger.HIGH, "Entering NoteTable.updateNoteNotebook");
535 String currentNotebookGuid = new String("");
538 // If we are going from a synchronized notebook to a local notebook, we
539 // need to tell Evernote to purge the note online. However, if this is
540 // conflicting change we move it to the local notebook without deleting it
541 // or it would then delete the copy on the remote server.
542 NotebookTable notebookTable = new NotebookTable(logger, db);
543 DeletedTable deletedTable = new DeletedTable(logger, db);
544 if (expungeFromRemote) {
545 if (!notebookTable.isNotebookLocal(currentNotebookGuid) & notebookTable.isNotebookLocal(notebookGuid)) {
546 deletedTable.addDeletedItem(guid, "NOTE");
550 NSqlQuery query = new NSqlQuery(db.getConnection());
551 boolean check = query.prepare("Update Note set notebookGuid=:notebook, isDirty=true where guid=:guid");
553 logger.log(logger.EXTREME, "Update note notebook sql prepare has failed.");
554 logger.log(logger.MEDIUM, query.lastError());
556 query.bindValue(":notebook", notebookGuid);
557 query.bindValue(":guid", guid);
559 check = query.exec();
561 logger.log(logger.EXTREME, "Update note notebook has failed.");
562 logger.log(logger.MEDIUM, query.lastError());
564 logger.log(logger.HIGH, "Leaving NoteTable.updateNoteNotebook");
566 // Update a note's title
567 public void updateNoteContent(String guid, String content) {
568 logger.log(logger.HIGH, "Entering NoteTable.updateNoteContent");
569 NSqlQuery query = new NSqlQuery(db.getConnection());
570 boolean check = query.prepare("Update Note set content=:content, updated=CURRENT_TIMESTAMP(), isDirty=true, indexNeeded=true, " +
571 " thumbnailneeded=true where guid=:guid");
573 logger.log(logger.EXTREME, "Update note content sql prepare has failed.");
574 logger.log(logger.MEDIUM, query.lastError());
577 // QTextCodec codec = QTextCodec.codecForLocale();
578 // codec = QTextCodec.codecForName("UTF-8");
579 // query.bindValue(":content", codec.fromUnicode(content).toString());
580 query.bindValue(":content", content);
581 query.bindValue(":guid", guid);
583 check = query.exec();
585 logger.log(logger.EXTREME, "Update note content has failed.");
586 logger.log(logger.MEDIUM, query.lastError());
588 logger.log(logger.HIGH, "Leaving NoteTable.updateNoteContent");
592 public void deleteNote(String guid) {
593 logger.log(logger.HIGH, "Entering NoteTable.deleteNote");
594 NSqlQuery query = new NSqlQuery(db.getConnection());
595 query.prepare("Update Note set deleted=CURRENT_TIMESTAMP(), active=false, isDirty=true where guid=:guid");
596 query.bindValue(":guid", guid);
598 logger.log(logger.MEDIUM, "Note delete failed.");
599 logger.log(logger.MEDIUM, query.lastError());
601 logger.log(logger.HIGH, "Leaving NoteTable.deleteNote");
603 public void restoreNote(String guid) {
604 NSqlQuery query = new NSqlQuery(db.getConnection());
605 query.prepare("Update Note set deleted=:reset, active=true, isDirty=true where guid=:guid");
606 // query.prepare("Update Note set deleted=0, active=true, isDirty=true where guid=:guid");
607 query.bindValue(":guid", guid);
608 query.bindValue(":reset", "1969-12-31 19:00:00");
610 logger.log(logger.MEDIUM, "Note restore failed.");
611 logger.log(logger.MEDIUM, query.lastError());
614 // Purge a note (actually delete it instead of just marking it deleted)
615 public void expungeNote(String guid, boolean permanentExpunge, boolean needsSync) {
616 logger.log(logger.HIGH, "Entering NoteTable.expungeNote");
618 if (!permanentExpunge) {
619 hideExpungedNote(guid, needsSync);
624 NSqlQuery note = new NSqlQuery(db.getConnection());
625 NSqlQuery resources = new NSqlQuery(db.getResourceConnection());
626 NSqlQuery tags = new NSqlQuery(db.getConnection());
627 NSqlQuery words = new NSqlQuery(db.getIndexConnection());
629 note.prepare("Delete from Note where guid=:guid");
630 resources.prepare("Delete from NoteResources where noteGuid=:guid");
631 tags.prepare("Delete from NoteTags where noteGuid=:guid");
632 words.prepare("Delete from words where guid=:guid");
634 note.bindValue(":guid", guid);
635 resources.bindValue(":guid", guid);
636 tags.bindValue(":guid", guid);
637 words.bindValue(":guid", guid);
639 // Start purging notes.
641 logger.log(logger.MEDIUM, "Purge from note failed.");
642 logger.log(logger.MEDIUM, note.lastError());
644 if (!resources.exec()) {
645 logger.log(logger.MEDIUM, "Purge from resources failed.");
646 logger.log(logger.MEDIUM, resources.lastError());
649 logger.log(logger.MEDIUM, "Note tags delete failed.");
650 logger.log(logger.MEDIUM, tags.lastError());
654 logger.log(logger.MEDIUM, "Word delete failed.");
655 logger.log(logger.MEDIUM, words.lastError());
658 DeletedTable deletedTable = new DeletedTable(logger, db);
659 deletedTable.addDeletedItem(guid, "Note");
661 logger.log(logger.HIGH, "Leaving NoteTable.expungeNote");
663 // Purge a bunch of notes based upon the notebook
664 public void expungeNotesByNotebook(String notebookGuid, boolean permanentExpunge, boolean needsSync) {
665 List<String> notes = getNotesByNotebook(notebookGuid);
666 for (int i=0; i<notes.size(); i++) {
667 expungeNote(notes.get(i), permanentExpunge, needsSync);
671 // Purge a note (actually delete it instead of just marking it deleted)
672 public void hideExpungedNote(String guid, boolean needsSync) {
673 NSqlQuery note = new NSqlQuery(db.getConnection());
674 NSqlQuery resources = new NSqlQuery(db.getResourceConnection());
675 NSqlQuery tags = new NSqlQuery(db.getConnection());
676 NSqlQuery words = new NSqlQuery(db.getIndexConnection());
678 note.prepare("Update Note set isExpunged=true where guid=:guid");
679 resources.prepare("Delete from NoteResources where noteGuid=:guid");
680 tags.prepare("Delete from NoteTags where noteGuid=:guid");
681 // words.prepare("Delete from words where guid=:guid");
683 note.bindValue(":guid", guid);
684 resources.bindValue(":guid", guid);
685 tags.bindValue(":guid", guid);
686 words.bindValue(":guid", guid);
688 // Start purging notes.
690 logger.log(logger.MEDIUM, "Purge from note failed.");
691 logger.log(logger.MEDIUM, note.lastError());
693 if (!resources.exec()) {
694 logger.log(logger.MEDIUM, "Purge from resources failed.");
695 logger.log(logger.MEDIUM, resources.lastError());
698 logger.log(logger.MEDIUM, "Note tags delete failed.");
699 logger.log(logger.MEDIUM, tags.lastError());
701 // System.out.println("Hiding Note: Deleting words");
702 // if (!words.exec()) {
703 // logger.log(logger.MEDIUM, "Word delete failed.");
704 // logger.log(logger.MEDIUM, words.lastError());
707 DeletedTable deletedTable = new DeletedTable(logger, db);
708 deletedTable.addDeletedItem(guid, "Note");
713 // Purge all deleted notes;
714 public void expungeAllDeletedNotes() {
715 logger.log(logger.HIGH, "Entering NoteTable.expungeAllDeletedNotes");
716 NSqlQuery query = new NSqlQuery(db.getConnection());
717 query.exec("select guid, updateSequenceNumber from note where active = false");
718 List<String> guids = new ArrayList<String>();
719 List<Integer> usns = new ArrayList<Integer>();
720 while (query.next()) {
721 guids.add(query.valueString(0));
722 Integer usn = new Integer(query.valueString(1));
726 for (int i=0; i<guids.size(); i++) {
727 Integer usn = usns.get(i);
728 String guid = guids.get(i);
730 expungeNote(guid, true, false);
732 expungeNote(guid, false, true);
734 logger.log(logger.HIGH, "Leaving NoteTable.expungeAllDeletedNotes");
736 // Update the note sequence number
737 public void updateNoteSequence(String guid, int sequence) {
738 logger.log(logger.HIGH, "Entering NoteTable.updateNoteSequence");
740 NSqlQuery query = new NSqlQuery(db.getConnection());
741 check = query.prepare("Update Note set updateSequenceNumber=:sequence where guid=:guid");
743 query.bindValue(":sequence", sequence);
744 query.bindValue(":guid", guid);
748 logger.log(logger.MEDIUM, "Note sequence update failed.");
749 logger.log(logger.MEDIUM, query.lastError());
751 logger.log(logger.HIGH, "Leaving NoteTable.updateNoteSequence");
753 // Update the note Guid
754 public void updateNoteGuid(String oldGuid, String newGuid) {
755 logger.log(logger.HIGH, "Entering NoteTable.updateNoteGuid");
757 NSqlQuery query = new NSqlQuery(db.getConnection());
758 NSqlQuery resQuery = new NSqlQuery(db.getResourceConnection());
759 NSqlQuery wordQuery = new NSqlQuery(db.getIndexConnection());
761 query.prepare("Update Note set guid=:newGuid, original_guid=:original_guid where guid=:oldGuid");
763 query.bindValue(":original_guid", oldGuid);
764 query.bindValue(":newGuid", newGuid);
765 query.bindValue(":oldGuid", oldGuid);
767 check = query.exec();
769 logger.log(logger.MEDIUM, "Note Guid update failed.");
770 logger.log(logger.MEDIUM, query.lastError());
773 query.prepare("Update NoteTags set noteGuid=:newGuid where noteGuid=:oldGuid");
774 query.bindValue(":newGuid", newGuid);
775 query.bindValue(":oldGuid", oldGuid);
776 check = query.exec();
778 logger.log(logger.MEDIUM, "Note guid update failed for NoteTags.");
779 logger.log(logger.MEDIUM, query.lastError());
782 wordQuery.prepare("Update words set guid=:newGuid where guid=:oldGuid");
783 wordQuery.bindValue(":newGuid", newGuid);
784 wordQuery.bindValue(":oldGuid", oldGuid);
785 // IFIXED check = が抜けていたので修正
786 check = wordQuery.exec();
788 logger.log(logger.MEDIUM, "Note guid update failed for Words.");
789 logger.log(logger.MEDIUM, wordQuery.lastError());
791 resQuery.prepare("Update noteresources set noteguid=:newGuid where noteguid=:oldGuid");
792 resQuery.bindValue(":newGuid", newGuid);
793 resQuery.bindValue(":oldGuid", oldGuid);
794 // IFIXED check = が抜けていたので修正
795 check = resQuery.exec();
797 logger.log(logger.MEDIUM, "Note guid update failed for noteresources.");
798 logger.log(logger.MEDIUM, resQuery.lastError());
801 // ICHANGED 操作履歴テーブルのguidを更新
802 db.getHistoryTable().updateHistoryGuid(newGuid, oldGuid);
804 // ICHANGED 除外ノートテーブルのguidを更新
805 db.getExcludedTable().updateExcludedNoteGuid(newGuid, oldGuid);
807 // ICHANGED スター付きノートテーブルのguidを更新
808 db.getStaredTable().updateStaredNoteGuid(newGuid, oldGuid);
811 public void updateNote(Note n) {
812 logger.log(logger.HIGH, "Entering NoteTable.updateNote");
813 NoteMetadata meta = getNoteMetaInformation(n.getGuid());
814 String originalGuid = findAlternateGuid(n.getGuid());
815 expungeNote(n.getGuid(), true, false);
818 updateNoteMetadata(meta);
820 if (originalGuid != null) {
821 updateNoteGuid(n.getGuid(), originalGuid);
822 updateNoteGuid(originalGuid, n.getGuid());
824 logger.log(logger.HIGH, "Leaving NoteTable.updateNote");
826 // Does a note exist?
827 public boolean exists(String guid) {
830 if (guid.trim().equals(""))
832 NSqlQuery query = new NSqlQuery(db.getConnection());
833 query.prepare("Select guid from note where guid=:guid");
834 query.bindValue(":guid", guid);
836 logger.log(logger.EXTREME, "note.exists SQL retrieve has failed.");
837 boolean retVal = query.next();
840 // Does a note exist?
841 public boolean isNoteExpunged(String guid) {
844 if (guid.trim().equals(""))
846 NSqlQuery query = new NSqlQuery(db.getConnection());
847 query.prepare("Select isExpunged from note where guid=:guid and isExpunged = true");
848 query.bindValue(":guid", guid);
850 logger.log(logger.EXTREME, "note.isNoteExpunged SQL retrieve has failed.");
851 boolean retVal = query.next();
854 // This is a convenience method to check if a note exists & update/create based upon it
855 public void syncNote(Note note) {
856 logger.log(logger.HIGH, "Entering NoteTable.syncNote");
857 // If we got the note from Evernote we use its
858 // metadata instead of the local copy.
859 NoteMetadata meta = null;
860 if (note.getAttributes() != null && note.getAttributes().getSourceApplication() != null) {
861 meta = extractMetadata(note.getAttributes().getSourceApplication());
863 meta = getNoteMetaInformation(note.getGuid());
865 // Now, if the note exists we simply update it. Otherwise we
867 if (exists(note.getGuid())) {
871 addNote(note, false);
873 // If we have metadata, we write it out.
875 meta.setGuid(note.getGuid());
876 updateNoteMetadata(meta);
878 logger.log(logger.HIGH, "Leaving NoteTable.syncNote");
880 // Get a list of notes that need to be updated
881 public List <Note> getDirty() {
884 List<Note> notes = new ArrayList<Note>();
885 List<String> index = new ArrayList<String>();
888 NSqlQuery query = new NSqlQuery(db.getConnection());
890 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)");
892 logger.log(logger.EXTREME, "Note SQL retrieve has failed: " +query.lastError().toString());
894 // Get a list of the notes
895 while (query.next()) {
897 guid = query.valueString(0);
901 // Start getting notes
902 for (int i=0; i<index.size(); i++) {
903 tempNote = getNote(index.get(i), true,true,false,true,true);
906 logger.log(logger.LOW, "Dirty local notes: " +new Integer(notes.size()).toString());
909 // Get a list of notes that need to be updated
910 public List <Note> getDirtyLinkedNotes() {
913 List<Note> notes = new ArrayList<Note>();
914 List<String> index = new ArrayList<String>();
917 NSqlQuery query = new NSqlQuery(db.getConnection());
919 check = query.exec("Select guid from Note where isDirty = true and isExpunged = false and notebookGuid in (select guid from notebook where linked = true)");
921 logger.log(logger.EXTREME, "Note SQL retrieve has failed: " +query.lastError().toString());
923 // Get a list of the notes
924 while (query.next()) {
926 guid = query.valueString(0);
930 // Start getting notes
931 for (int i=0; i<index.size(); i++) {
932 tempNote = getNote(index.get(i), true,true,false,true,true);
935 logger.log(logger.LOW, "Dirty linked local notes: " +new Integer(notes.size()).toString());
938 // Get a list of notes that need to be updated
939 public List <Note> getDirtyLinked(String notebookGuid) {
942 List<Note> notes = new ArrayList<Note>();
943 List<String> index = new ArrayList<String>();
946 NSqlQuery query = new NSqlQuery(db.getConnection());
948 query.prepare("Select guid from Note where isDirty = true and isExpunged = false and notebookGuid=:notebookGuid");
949 query.bindValue(":notebookGuid", notebookGuid);
950 check = query.exec();
952 logger.log(logger.EXTREME, "Note SQL retrieve has failed getting dirty linked notes: " +query.lastError().toString());
954 // Get a list of the notes
955 while (query.next()) {
957 guid = query.valueString(0);
961 // Start getting notes
962 for (int i=0; i<index.size(); i++) {
963 tempNote = getNote(index.get(i), true,true,false,true,true);
966 logger.log(logger.LOW, "Dirty local notes for notebook " +notebookGuid +": " +new Integer(notes.size()).toString());
969 // Get a list of notes that need to be updated
970 // IFIXED バグで空のリストを返すだけのメソッドになっていたのを修正
971 public List <String> getNotesByNotebook(String notebookGuid) {
972 List<String> notes = new ArrayList<String>();
973 // IFIXED List<String> index = new ArrayList<String>();
976 NSqlQuery query = new NSqlQuery(db.getConnection());
978 check = query.prepare("Select guid from Note where notebookguid=:notebookguid");
980 logger.log(logger.EXTREME, "Note SQL retrieve has failed: " +query.lastError().toString());
981 query.bindValue(":notebookguid", notebookGuid);
984 // Get a list of the notes
985 while (query.next()) {
986 // IFIXED index.add(query.valueString(0));
987 notes.add(query.valueString(0));
992 // Get a list of notes that need to be updated
993 public boolean isNoteDirty(String guid) {
996 NSqlQuery query = new NSqlQuery(db.getConnection());
998 check = query.prepare("Select guid from Note where isDirty = true and guid=:guid");
999 query.bindValue(":guid", guid);
1000 check = query.exec();
1002 logger.log(logger.EXTREME, "Note SQL retrieve has failed: " +query.lastError().toString());
1004 boolean returnValue;
1005 // Get a list of the notes
1009 returnValue = false;
1014 // Reset the dirty bit
1015 public void resetDirtyFlag(String guid) {
1016 logger.log(logger.LOW, "Resetting dirty flag for " +guid);
1017 NSqlQuery query = new NSqlQuery(db.getConnection());
1019 query.prepare("Update note set isdirty=false where guid=:guid");
1020 query.bindValue(":guid", guid);
1022 logger.log(logger.EXTREME, "Error resetting note dirty field.");
1025 public List<String> getAllGuids() {
1026 List<String> notes = new ArrayList<String>();
1029 NSqlQuery query = new NSqlQuery(db.getConnection());
1031 check = query.exec("Select guid from Note");
1033 logger.log(logger.EXTREME, "Notebook SQL retrieve has failed: "+query.lastError());
1035 // Get a list of the notes
1036 while (query.next()) {
1037 notes.add(new String(query.valueString(0)));
1042 public List<Note> getAllNotes() {
1043 List<Note> notes = new ArrayList<Note>();
1046 if (getAllQueryWithoutContent == null)
1048 NSqlQuery query = getAllQueryWithoutContent;
1049 check = query.exec();
1051 logger.log(logger.EXTREME, "Notebook SQL retrieve has failed: "+query.lastError());
1052 // Get a list of the notes
1053 while (query.next()) {
1054 notes.add(mapNoteFromQuery(query, false, false, false, false, true));
1058 // Count unindexed notes
1059 public int getUnindexedCount() {
1060 NSqlQuery query = new NSqlQuery(db.getConnection());
1061 query.exec("select count(*) from note where indexneeded=true and isExpunged = false");
1063 int returnValue = new Integer(query.valueString(0));
1066 // Count unsynchronized notes
1067 public int getDirtyCount() {
1068 NSqlQuery query = new NSqlQuery(db.getConnection());
1069 query.exec("select count(guid) from note where isDirty=true and isExpunged = false");
1071 int returnValue = new Integer(query.valueString(0));
1072 logger.log(logger.LOW, "dirty count: " +returnValue);
1073 //query.exec("select count(guid) from note where isDirty=true and Active = 0 and isExpunged = false");
1075 //logger.log(logger.LOW, "dirty count (active only): " +query.valueString(0));
1076 //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)");
1078 //logger.log(logger.LOW, "dirty count (no l&l notebooks): " +query.valueString(0));
1079 //logger.log(logger.LOW, "Beginning stack trace");
1080 //logger.log(logger.LOW, Thread.currentThread().getStackTrace());
1082 //logger.log(logger.LOW, "*************************");
1083 //logger.log(logger.LOW, "*** DIRTY RECORD DUMP ***");
1084 //logger.log(logger.LOW, "*************************");
1085 //List<Note> recs = getDirty();
1086 //for (int i=0; i<recs.size(); i++) {
1087 //Note n = getNote(recs.get(i).getGuid(), true, true, true, false, true);
1088 //logger.log(logger.LOW, "-- Begin Record ---");
1089 //logger.log(logger.LOW, "Guid: " +n.getGuid());
1090 //logger.log(logger.LOW, "Title: " +n.getTitle());
1091 //logger.log(logger.LOW, "Active: " +n.isActive());
1092 //logger.log(logger.LOW, "USN: " +n.getUpdateSequenceNum());
1093 //logger.log(logger.LOW, "Date Created: " +n.getCreated());
1094 //logger.log(logger.LOW, "Date Updated: " +n.getUpdated());
1095 //logger.log(logger.LOW, "Date Deleted: " +n.getDeleted());
1096 //logger.log(logger.LOW, "Resource Count: " +n.getResourcesSize());
1097 //for (int j=0; j<n.getResourcesSize(); j++) {
1098 //Resource r = n.getResources().get(j);
1099 //logger.log(logger.LOW, "Resource " +j +": " +r.getGuid());
1100 //logger.log(logger.LOW, "Active: " +r.isActive());
1101 //logger.log(logger.LOW, "USN: " +r.getUpdateSequenceNum());
1103 //logger.log(logger.LOW, "-- End Record ---");
1105 //logger.log(logger.LOW, "*****************************");
1106 //logger.log(logger.LOW, "*** End DIRTY RECORD DUMP ***");
1107 //logger.log(logger.LOW, "*****************************");
1111 public int getNoteCount() {
1112 NSqlQuery query = new NSqlQuery(db.getConnection());
1113 query.exec("select count(*) from note where isExpunged = false");
1115 int returnValue = new Integer(query.valueString(0));
1118 // Count deleted notes
1119 public int getDeletedCount() {
1120 NSqlQuery query = new NSqlQuery(db.getConnection());
1121 query.exec("select count(*) from note where isExpunged = false and active = false");
1124 int returnValue = new Integer(query.valueString(0));
1127 // Reset a note sequence number to zero. This is useful for moving conflicting notes
1128 public void resetNoteSequence(String guid) {
1129 NSqlQuery query = new NSqlQuery(db.getConnection());
1130 boolean check = query.prepare("Update Note set updateSequenceNumber=0, isDirty=true where guid=:guid");
1132 logger.log(logger.EXTREME, "Update note ResetSequence sql prepare has failed.");
1133 logger.log(logger.MEDIUM, query.lastError());
1135 query.bindValue(":guid", guid);
1136 check = query.exec();
1138 logger.log(logger.EXTREME, "Update note sequence number has failed.");
1139 logger.log(logger.MEDIUM, query.lastError());
1144 // Update a note resource by the hash
1145 public void updateNoteResourceGuidbyHash(String noteGuid, String resGuid, String hash) {
1146 NSqlQuery query = new NSqlQuery(db.getResourceConnection());
1147 /* query.prepare("Select guid from NoteResources where noteGuid=:noteGuid and datahash=:hex");
1148 query.bindValue(":noteGuid", noteGuid);
1149 query.bindValue(":hex", hash);
1151 if (!query.next()) {
1152 logger.log(logger.LOW, "Error finding note resource in RNoteTable.updateNoteResourceGuidbyHash. GUID="+noteGuid +" resGuid="+ resGuid+" hash="+hash);
1155 String guid = query.valueString(0);
1157 query.prepare("update noteresources set guid=:guid where noteGuid=:noteGuid and datahash=:hex");
1158 query.bindValue(":guid", resGuid);
1159 query.bindValue(":noteGuid", noteGuid);
1160 query.bindValue(":hex", hash);
1161 if (!query.exec()) {
1162 logger.log(logger.EXTREME, "Note Resource Update by Hash failed");
1163 logger.log(logger.EXTREME, query.lastError().toString());
1167 // Fix CRLF problem that is on some notes
1168 private String fixCarriageReturn(String note) {
1169 if (note == null || !Global.enableCarriageReturnFix)
1171 QByteArray a0Hex = new QByteArray("a0");
1172 String a0 = QByteArray.fromHex(a0Hex).toString();
1173 note = note.replace("<div>"+a0+"</div>", "<div> </div>");
1174 return note.replace("<div/>", "<div> </div>");
1177 // Expunge notes that we don't want to synchronize
1178 public List<String> expungeIgnoreSynchronizedNotes(List<String> notebooks, List<String>tags, List<String> linked) {
1180 List<String> noteGuids = new ArrayList<String>();
1181 for (int i=0; i<notebooks.size(); i++) {
1182 List<String> notes = findNotesByNotebook(notebooks.get(i));
1183 for (int j=0; j<notes.size(); j++) {
1184 if (!isNoteDirty(notes.get(j))) {
1185 expungeNote(notes.get(j), true, false);
1186 noteGuids.add(notes.get(j));
1191 for (int i=0; i<tags.size(); i++) {
1192 List<String> notes = findNotesByTag(tags.get(i));
1193 for (int j=0; j<notes.size(); j++) {
1194 if (!isNoteDirty(notes.get(j))) {
1195 expungeNote(notes.get(j), true, false);
1196 noteGuids.add(notes.get(j));
1201 for (int i=0; i<linked.size(); i++) {
1202 String notebookGuid = db.getLinkedNotebookTable().getNotebookGuid(linked.get(i));
1203 if (notebookGuid != null && !notebookGuid.trim().equals("")) {
1204 List<Tag> linkedTags = db.getTagTable().getTagsForNotebook(notebookGuid);
1205 for (int j=0; j<linkedTags.size(); j++)
1206 db.getTagTable().expungeTag(linkedTags.get(j).getGuid(), false);
1208 List<String> notes = findNotesByNotebook(notebookGuid);
1209 for (int j=0; j<notes.size(); j++) {
1210 if (!isNoteDirty(notes.get(j))) {
1211 expungeNote(notes.get(j), true, false);
1212 noteGuids.add(notes.get(j));
1220 // Find a note by its notebook
1221 // Expunge notes that we don't want to synchronize
1222 public List<String> findNotesByNotebook(String notebook) {
1223 List<String> values = new ArrayList<String>();
1224 NSqlQuery query = new NSqlQuery(db.getConnection());
1225 query.prepare("Select guid from note where notebookguid=:notebook");
1227 query.bindValue(":notebook", notebook);
1229 while (query.next()) {
1230 values.add(query.valueString(0));
1235 public List<String> findNotesByTag(String tag) {
1236 List<String> values = new ArrayList<String>();
1237 NSqlQuery query = new NSqlQuery(db.getConnection());
1238 query.prepare("Select distinct noteguid from notetags where tagguid=:tag");
1240 query.bindValue(":tag", tag);
1242 while (query.next()) {
1243 values.add(query.valueString(0));
1248 // Find a note based upon its title.
1249 public List<Pair<String,String>> findNotesByTitle(String text) {
1250 List<Pair<String,String>> results = new ArrayList<Pair<String,String>>();
1252 NSqlQuery query = new NSqlQuery(db.getConnection());
1254 check = query.prepare("Select guid,title from Note where lower(title) like :title");
1256 logger.log(logger.EXTREME, "Note SQL prepare for search by title has failed: " +query.lastError().toString());
1258 query.bindValue(":title", "%"+text.toLowerCase()+"%");
1260 // Get a list of the notes
1261 while (query.next()) {
1262 Pair<String,String> p = new Pair<String,String>();
1263 p.setFirst(query.valueString(0));
1264 p.setSecond(query.valueString(1));
1272 //********************************************************************************
1273 //********************************************************************************
1274 //* Indexing Functions
1275 //********************************************************************************
1276 //********************************************************************************
1277 // set/unset a note to be reindexed
1278 public void setIndexNeeded(String guid, Boolean flag) {
1279 NSqlQuery query = new NSqlQuery(db.getConnection());
1280 query.prepare("Update Note set indexNeeded=:flag where guid=:guid");
1283 query.bindValue(":flag", 1);
1285 query.bindValue(":flag", 0);
1286 query.bindValue(":guid", guid);
1287 if (!query.exec()) {
1288 logger.log(logger.MEDIUM, "Note indexNeeded update failed.");
1289 logger.log(logger.MEDIUM, query.lastError());
1291 List<Resource> r = noteResourceTable.getNoteResources(guid, false);
1292 for (int i=0; r!= null && i<r.size(); i++) {
1293 noteResourceTable.setIndexNeeded(r.get(i).getGuid(), true);
1296 // Set all notes to be reindexed
1297 public void reindexAllNotes() {
1298 NSqlQuery query = new NSqlQuery(db.getConnection());
1299 if (!query.exec("Update Note set indexNeeded=true")) {
1300 logger.log(logger.MEDIUM, "Note reindexAllNotes update failed.");
1301 logger.log(logger.MEDIUM, query.lastError());
1305 // Get all unindexed notes
1306 public List <String> getUnindexed() {
1308 List<String> index = new ArrayList<String>();
1309 NSqlQuery query = new NSqlQuery(db.getConnection());
1311 if (!query.exec("Select guid from Note where isExpunged = false and indexNeeded = true and DATEDIFF('MINUTE',updated,CURRENT_TIMESTAMP)>5"))
1312 logger.log(logger.EXTREME, "Note SQL retrieve has failed on getUnindexed().");
1314 // Get a list of the notes
1315 while (query.next()) {
1316 guid = new String();
1317 guid = query.valueString(0);
1322 public List<String> getNextUnindexed(int limit) {
1323 List<String> guids = new ArrayList<String>();
1325 NSqlQuery query = new NSqlQuery(db.getConnection());
1327 if (!query.exec("Select guid from Note where isExpunged = false and indexNeeded = true and DATEDIFF('MINUTE',Updated,CURRENT_TIMESTAMP)>5 limit " +limit))
1328 logger.log(logger.EXTREME, "Note SQL retrieve has failed on getUnindexed().");
1330 // Get a list of the notes
1332 while (query.next()) {
1333 guid = new String();
1334 guid = query.valueString(0);
1341 // Get note meta information
1342 public void updateNoteMetadata(NoteMetadata meta) {
1343 NSqlQuery query = new NSqlQuery(db.getConnection());
1344 if (!query.prepare("Update Note set titleColor=:color, pinned=:pinned, attributeSourceApplication=:metaString, isDirty=true where guid=:guid"))
1345 logger.log(logger.EXTREME, "Note SQL prepare has failed on updateNoteMetadata.");
1346 query.bindValue(":color", meta.getColor());
1347 query.bindValue(":pinned", meta.isPinned());
1348 query.bindValue(":guid", meta.getGuid());
1349 query.bindValue(":metaString", buildMetadataString(meta));
1351 logger.log(logger.EXTREME, "Note SQL exec has failed on updateNoteMetadata.");
1355 // Get all note meta information
1356 public HashMap<String, NoteMetadata> getNotesMetaInformation() {
1357 HashMap<String, NoteMetadata> returnValue = new HashMap<String, NoteMetadata>();
1358 NSqlQuery query = new NSqlQuery(db.getConnection());
1360 if (!query.exec("Select guid,titleColor, isDirty, pinned from Note"))
1361 logger.log(logger.EXTREME, "Note SQL retrieve has failed on getNoteMetaInformation.");
1363 // Get a list of the notes
1364 while (query.next()) {
1365 NoteMetadata note = new NoteMetadata();
1366 note.setGuid(query.valueString(0));
1367 note.setColor(query.valueInteger(1));
1368 note.setDirty(query.valueBoolean(2, false));
1369 int pinned = query.valueInteger(3);
1371 note.setPinned(true);
1372 returnValue.put(note.getGuid(), note);
1377 // Get note meta information
1378 public NoteMetadata getNoteMetaInformation(String guid) {
1379 NSqlQuery query = new NSqlQuery(db.getConnection());
1381 if (!query.prepare("Select guid,titleColor, isDirty, pinned from Note where guid=:guid")) {
1382 logger.log(logger.EXTREME, "Note SQL retrieve has failed on getNoteMetaInformation.");
1385 query.bindValue(":guid", guid);
1388 // Get a list of the notes
1389 while (query.next()) {
1390 NoteMetadata note = new NoteMetadata();
1391 note.setGuid(query.valueString(0));
1392 note.setColor(query.valueInteger(1));
1393 note.setDirty(query.valueBoolean(2, false));
1394 int pinned = query.valueInteger(3);
1396 note.setPinned(true);
1404 //**********************************************************************************
1405 //* Thumbnail functions
1406 //**********************************************************************************
1407 // Set if a new thumbnail is needed
1408 public void setThumbnailNeeded(String guid, boolean needed) {
1411 NSqlQuery query = new NSqlQuery(db.getConnection());
1413 check = query.prepare("Update note set thumbnailneeded = :needed where guid=:guid");
1414 query.bindValue(":guid", guid);
1415 query.bindValue(":needed", needed);
1416 check = query.exec();
1418 logger.log(logger.EXTREME, "Note SQL set thumbail needed failed: " +query.lastError().toString());
1421 // Is a thumbail needed for this guid?
1422 public boolean isThumbnailNeeded(String guid) {
1425 NSqlQuery query = new NSqlQuery(db.getConnection());
1427 check = query.prepare("select thumbnailneeded from note where guid=:guid");
1428 query.bindValue(":guid", guid);
1429 check = query.exec();
1431 logger.log(logger.EXTREME, "Note SQL isThumbnailNeeded query failed: " +query.lastError().toString());
1433 boolean returnValue;
1434 // Get a list of the notes
1436 returnValue = query.valueBoolean(0, false);
1438 returnValue = false;
1442 // Set if a new thumbnail is needed
1443 public void setThumbnail(String guid, QByteArray thumbnail) {
1446 NSqlQuery query = new NSqlQuery(db.getConnection());
1448 check = query.prepare("Update note set thumbnail = :thumbnail where guid=:guid");
1449 query.bindValue(":guid", guid);
1450 query.bindValue(":thumbnail", thumbnail.toByteArray());
1451 check = query.exec();
1453 logger.log(logger.EXTREME, "Note SQL set thumbail failed: " +query.lastError().toString());
1456 // Set if a new thumbnail is needed
1457 public QByteArray getThumbnail(String guid) {
1460 NSqlQuery query = new NSqlQuery(db.getConnection());
1462 check = query.prepare("Select thumbnail from note where guid=:guid");
1463 query.bindValue(":guid", guid);
1464 check = query.exec();
1466 logger.log(logger.EXTREME, "Note SQL get thumbail failed: " +query.lastError().toString());
1467 // Get a list of the notes
1470 if (query.getBlob(0) != null) {
1471 return new QByteArray(query.getBlob(0));
1473 } catch (java.lang.IllegalArgumentException e) {
1479 // Get all thumbnails
1480 public HashMap<String, QPixmap> getThumbnails() {
1482 NSqlQuery query = new NSqlQuery(db.getConnection());
1483 HashMap<String, QPixmap> map = new HashMap<String,QPixmap>();
1485 check = query.prepare("Select guid,thumbnail from note where thumbnailneeded=false and isExpunged=false");
1486 check = query.exec();
1488 logger.log(logger.EXTREME, "Note SQL get thumbail failed: " +query.lastError().toString());
1489 // Get a list of the notes
1490 while (query.next()) {
1492 if (query.getBlob(1) != null) {
1493 QByteArray data = new QByteArray(query.getBlob(1));
1494 QPixmap img = new QPixmap();
1495 if (img.loadFromData(data)) {
1496 img = img.scaled(Global.largeThumbnailSize);
1497 map.put(query.valueString(0), img);
1500 } catch (java.lang.IllegalArgumentException e) {
1501 logger.log(logger.HIGH, "Error retrieving thumbnail " +e.getMessage());
1506 // Get a list of notes that need thumbnails
1507 public List<String> findThumbnailsNeeded() {
1510 NSqlQuery query = new NSqlQuery(db.getConnection());
1512 check = query.prepare("select guid from note where thumbnailneeded=true and isExpunged=false and DATEDIFF('MINUTE',updated,CURRENT_TIMESTAMP)>5 limit 5");
1513 check = query.exec();
1515 logger.log(logger.EXTREME, "Note SQL findThumbnailsNeeded query failed: " +query.lastError().toString());
1518 // Get a list of the notes
1519 List<String> values = new ArrayList<String>();
1520 while (query.next()) {
1521 values.add(query.valueString(0));
1526 // Get a count of thumbnails needed
1527 public int getThumbnailNeededCount() {
1530 NSqlQuery query = new NSqlQuery(db.getConnection());
1532 check = query.prepare("select count(guid) from note where thumbnailneeded=true and isExpunged=false and DATEDIFF('MINUTE',updated,CURRENT_TIMESTAMP)>5 limit 2");
1533 check = query.exec();
1535 logger.log(logger.EXTREME, "Note SQL findThumbnailNeededCount query failed: " +query.lastError().toString());
1538 return query.valueInteger(0);
1544 //***********************************************************************************
1545 public String findAlternateGuid(String guid) {
1547 NSqlQuery query = new NSqlQuery(db.getConnection());
1549 check = query.prepare("select guid from note where original_guid=:guid");
1550 query.bindValue(":guid", guid);
1551 check = query.exec();
1553 logger.log(logger.EXTREME, "Note SQL findAlternateguid query failed: " +query.lastError().toString());
1556 return query.valueString(0);
1562 //* Check if a note guid exists
1563 public boolean guidExists(String guid) {
1565 NSqlQuery query = new NSqlQuery(db.getConnection());
1567 check = query.prepare("select guid from note where guid=:guid");
1568 query.bindValue(":guid", guid);
1569 check = query.exec();
1571 logger.log(logger.EXTREME, "Note SQL guidExists query failed: " +query.lastError().toString());
1580 // Update a note content's hash. This happens if a resource is edited outside of NN
1581 public void updateResourceContentHash(String guid, String oldHash, String newHash) {
1582 Note n = getNote(guid, true, false, false, false,false);
1583 int position = n.getContent().indexOf("<en-media");
1585 for (;position>-1;) {
1586 endPos = n.getContent().indexOf(">", position+1);
1587 String oldSegment = n.getContent().substring(position,endPos);
1588 int hashPos = oldSegment.indexOf("hash=\"");
1589 int hashEnd = oldSegment.indexOf("\"", hashPos+7);
1590 String hash = oldSegment.substring(hashPos+6, hashEnd);
1591 if (hash.equalsIgnoreCase(oldHash)) {
1592 String newSegment = oldSegment.replace(oldHash, newHash);
1593 String content = n.getContent().substring(0,position) +
1595 n.getContent().substring(endPos);
1596 NSqlQuery query = new NSqlQuery(db.getConnection());
1597 query.prepare("update note set isdirty=true, thumbnailneeded=true, content=:content where guid=:guid");
1598 query.bindValue(":content", content);
1599 query.bindValue(":guid", n.getGuid());
1603 position = n.getContent().indexOf("<en-media", position+1);
1607 // Extract metadata from a note's Note.attributes.sourceApplication
1608 private NoteMetadata extractMetadata(String sourceApplication) {
1609 // ICHANGED 自分のキーに変更
1610 String consumerKey = "kimaira792:{";
1612 int startPos = sourceApplication.indexOf(consumerKey);
1616 NoteMetadata meta = new NoteMetadata();
1617 startPos = startPos+consumerKey.length();
1619 // String startString = sourceApplication.substring(0,startPos);
1620 String metaString = sourceApplication.substring(startPos);
1621 // String endString = metaString.substring(metaString.indexOf("};"));
1622 int endPos = metaString.indexOf("};");
1624 metaString = metaString.substring(0,endPos);
1626 String value = parseMetaString(metaString, "titleColor");
1628 meta.setColor(Integer.parseInt(value));
1630 value = parseMetaString(metaString, "pinned");
1631 if (value != null && value.equals(true))
1632 meta.setPinned(true);
1637 // Given a metadata string from attribute.sourceApplication, we
1638 // extract the information for a given key.
1639 private String parseMetaString(String metaString, String key) {
1640 int startPos = metaString.indexOf(key);
1644 String value = metaString.substring(startPos+key.length()+1);
1645 int endPos = value.indexOf(";");
1647 value = value.substring(0,endPos);
1652 // Given a set of metadata, we build a string that can be inserted
1653 // into the attribute.sourceApplication string.
1654 private String buildMetadataString(NoteMetadata meta) {
1655 StringBuffer value = new StringBuffer(removeExistingMetaString(meta.getGuid()));
1656 StringBuffer metaString = new StringBuffer();
1658 if (meta.isPinned()) {
1659 metaString.append("pinned=true;");
1661 if (meta.getColor() != -1) {
1662 metaString.append("titleColor=" +new Integer(meta.getColor()).toString()+";");
1664 if (metaString.length()>0) {
1666 // Adda any missing ";" or " " at the end of the existing
1668 if (value.length()>1 && (!value.toString().trim().endsWith(";") || !value.toString().trim().endsWith(";")))
1671 // ICHANGED 自分のキーに変更
1672 value.append("kimaira792:{");
1673 value.append(metaString);
1675 return value.toString();
1680 // This will remove the existing metadata string from the attribute.sourceApplication string.
1681 private String removeExistingMetaString(String guid) {
1682 NSqlQuery query = new NSqlQuery(db.getConnection());
1684 if (!query.prepare("Select attributeSourceApplication from Note where guid=:guid")) {
1685 logger.log(logger.EXTREME, "Note SQL retrieve has failed in removeExistingMetaString.");
1688 query.bindValue(":guid", guid);
1691 // Get the application source string
1692 String sourceApplication = null;
1693 while (query.next()) {
1694 sourceApplication = query.valueString(0);
1696 if (sourceApplication == null)
1699 // ICHANGED 自分のキーに変更
1700 String consumerKey = "kimaira792:{";
1701 int startPos = sourceApplication.indexOf(consumerKey);
1703 return sourceApplication;
1704 String startString = sourceApplication.substring(0,startPos);
1705 String metaString = sourceApplication.substring(startPos);
1706 String endString = metaString.substring(metaString.indexOf("};")+2);
1708 return startString+endString;
1711 public void dumpDirtyNotes() {
\r
1712 logger.log(logger.LOW, "Dirty Notes: ");
\r
1713 List<Note> noteList = this.getDirty();
\r
1714 for (int i=0; i<noteList.size();i++) {
\r
1715 logger.log(logger.LOW, i +" : " +noteList.get(i).getGuid() + " : " +noteList.get(i).getTitle() );
\r
1720 // guidからノートのタイトルをゲット
1721 public String getNoteTitle(String noteGuid) {
1723 if (noteGuid == null)
1725 if (noteGuid.trim().equals(""))
1728 NSqlQuery query = new NSqlQuery(db.getConnection());
1729 query.prepare("Select title from Note where guid=:guid and isExpunged=false");
1730 query.bindValue(":guid", noteGuid);
1731 if (!query.exec()) {
1732 logger.log(logger.MEDIUM, "Noteテーブルからタイトルの取得失敗");
1733 logger.log(logger.MEDIUM, query.lastError());
1736 if (!query.next()) {
1737 logger.log(logger.EXTREME, "SQL Retrieve failed for note guid "
1738 + noteGuid + " in getNoteTitle()");
1739 logger.log(logger.EXTREME, " -> " + query.lastError().toString());
1740 logger.log(logger.EXTREME, " -> " + query.lastError());
1744 String noteTitle = query.valueString(0);
1750 * // ICHANGED // ノートがアクティブかどうか調べる public boolean isNoteActive(String guid){
1751 * if(guid == null) return false; if(guid.trim().equals("")) return false;
1753 * NSqlQuery query = new NSqlQuery(db.getConnection());
1754 * query.prepare("Select active from Note where guid=:guid");
1755 * query.bindValue(":guid", guid); if(!query.exec()){
1756 * logger.log(logger.EXTREME, "note.isNoteActive SQL retrieve has failed.");
1757 * return false; } if(!query.next()){ logger.log(logger.EXTREME,
1758 * "SQL Retrieve failed for note guid " +guid + " in isNoteActive()");
1761 * boolean retVal = query.valueBoolean(0, false); return retVal; }