2 * This file is part of NixNote
3 * Copyright 2009 Randy Baumgarte
5 * This file may be licensed under the terms of of the
6 * GNU General Public License Version 2 (the ``GPL'').
8 * Software distributed under the License is distributed
9 * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
10 * express or implied. See the GPL for the specific language
11 * governing rights and limitations.
13 * You should have received a copy of the GPL along with this
14 * program. If not, go to http://www.gnu.org/licenses/gpl.html
15 * or write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 package cx.fbn.nevernote.utilities;
22 import java.util.ArrayList;
23 import java.util.Calendar;
24 import java.util.Collections;
25 import java.util.Comparator;
26 import java.util.GregorianCalendar;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Vector;
31 import com.evernote.edam.type.LinkedNotebook;
32 import com.evernote.edam.type.Note;
33 import com.evernote.edam.type.Notebook;
34 import com.evernote.edam.type.SavedSearch;
35 import com.evernote.edam.type.Tag;
36 import com.trolltech.qt.QThread;
37 import com.trolltech.qt.core.QDateTime;
38 import com.trolltech.qt.gui.QImage;
39 import com.trolltech.qt.gui.QPixmap;
40 import com.trolltech.qt.sql.QSqlQuery;
41 import com.trolltech.qt.xml.QDomAttr;
42 import com.trolltech.qt.xml.QDomDocument;
43 import com.trolltech.qt.xml.QDomElement;
44 import com.trolltech.qt.xml.QDomNodeList;
46 import cx.fbn.nevernote.Global;
47 import cx.fbn.nevernote.evernote.NoteMetadata;
48 import cx.fbn.nevernote.filters.EnSearch;
49 import cx.fbn.nevernote.filters.NotebookCounter;
50 import cx.fbn.nevernote.filters.TagCounter;
51 import cx.fbn.nevernote.gui.NoteTableModel;
52 import cx.fbn.nevernote.signals.NotebookSignal;
53 import cx.fbn.nevernote.signals.StatusSignal;
54 import cx.fbn.nevernote.signals.TagSignal;
55 import cx.fbn.nevernote.signals.ThreadSignal;
56 import cx.fbn.nevernote.signals.TrashSignal;
57 import cx.fbn.nevernote.sql.DatabaseConnection;
58 import cx.fbn.nevernote.threads.CounterRunner;
59 import cx.fbn.nevernote.threads.SaveRunner;
62 public class ListManager {
65 private final ApplicationLogger logger;
66 DatabaseConnection conn;
67 QSqlQuery deleteWords;
68 QSqlQuery insertWords;
70 private List<Tag> tagIndex;
71 private List<Notebook> notebookIndex;
72 private List<Notebook> archiveNotebookIndex;
73 private List<String> localNotebookIndex;
74 private List<LinkedNotebook> linkedNotebookIndex;
76 private List<SavedSearch> searchIndex;
78 private List<String> selectedNotebooks;
79 private final NoteTableModel noteModel;
82 private List<String> selectedTags;
83 private String selectedSearch;
85 public StatusSignal status;
86 private final CounterRunner notebookCounterRunner;
87 private final QThread notebookThread;
88 private final CounterRunner tagCounterRunner;
89 private final QThread tagThread;
91 private final CounterRunner trashCounterRunner;
92 private final QThread trashThread;
93 public TrashSignal trashSignal;
95 private List<NotebookCounter> notebookCounter; // count of displayed notes in each notebook
96 private List<TagCounter> tagCounter; // count of displayed notes for each tag
98 private EnSearch enSearch;
99 private boolean enSearchChanged;
100 public HashMap<String, String> wordMap;
101 public TagSignal tagSignal;
102 public NotebookSignal notebookSignal;
103 public boolean refreshCounters; // Used to control when to recount lists
104 private int trashCount;
105 public SaveRunner saveRunner; // Thread used to save content. Used because the xml conversion is slowwwww
108 // private final HashMap<String, QImage> thumbnailList;
111 public ListManager(DatabaseConnection d, ApplicationLogger l) {
115 conn.getTagTable().cleanupTags();
116 status = new StatusSignal();
117 signals = new ThreadSignal();
120 enSearchChanged = false;
123 noteModel = new NoteTableModel(this);
124 selectedTags = new ArrayList<String>();
126 notebookCounter = new ArrayList<NotebookCounter>();
127 tagCounter = new ArrayList<TagCounter>();
128 selectedNotebooks = new ArrayList<String>();
132 notebookSignal = new NotebookSignal();
133 // ICHANGED Global.getBehaviorDatabaseUrl()を追加
134 notebookCounterRunner = new CounterRunner("notebook_counter.log", CounterRunner.NOTEBOOK,
135 Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(), Global.getBehaviorDatabaseUrl(),
136 Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
137 notebookCounterRunner.setNoteIndex(getNoteIndex());
138 notebookCounterRunner.notebookSignal.countsChanged.connect(this, "setNotebookCounter(List)");
139 notebookThread = new QThread(notebookCounterRunner, "Notebook Counter Thread");
140 notebookThread.start();
142 tagSignal = new TagSignal();
143 // ICHANGED Global.getBehaviorDatabaseUrl()を追加
144 tagCounterRunner = new CounterRunner("tag_counter.log", CounterRunner.TAG,
145 Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(), Global.getBehaviorDatabaseUrl(),
146 Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
147 tagCounterRunner.setNoteIndex(getNoteIndex());
148 tagCounterRunner.tagSignal.countsChanged.connect(this, "setTagCounter(List)");
149 tagThread = new QThread(tagCounterRunner, "Tag Counter Thread");
152 trashSignal = new TrashSignal();
153 // ICHANGED Global.getBehaviorDatabaseUrl()を追加
154 trashCounterRunner = new CounterRunner("trash_counter.log", CounterRunner.TRASH,
155 Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(), Global.getBehaviorDatabaseUrl(),
156 Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
157 trashCounterRunner.trashSignal.countChanged.connect(this, "trashSignalReceiver(Integer)");
158 trashThread = new QThread(trashCounterRunner, "Trash Counter Thread");
160 // reloadTrashCount();
162 wordMap = new HashMap<String, String>();
163 tagSignal = new TagSignal();
165 logger.log(logger.EXTREME, "Setting save thread");
166 // ICHANGED Global.getBehaviorDatabaseUrl()を追加
167 saveRunner = new SaveRunner("saveRunner.log",
168 Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(), Global.getBehaviorDatabaseUrl(),
169 Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
170 saveThread = new QThread(saveRunner, "Save Runner Thread");
173 // thumbnailList = conn.getNoteTable().getThumbnails();
174 // thumbnailList = new HashMap<String,QImage>();
176 linkedNotebookIndex = conn.getLinkedNotebookTable().getAll();
177 loadNoteTitleColors();
178 refreshCounters = true;
184 saveRunner.addWork("stop", "");
185 tagCounterRunner.release(CounterRunner.EXIT);
186 notebookCounterRunner.release(CounterRunner.EXIT);
187 trashCounterRunner.release(CounterRunner.EXIT);
189 logger.log(logger.MEDIUM, "Waiting for notebookCounterThread to stop");
191 notebookThread.join();
192 } catch (InterruptedException e) {
196 logger.log(logger.MEDIUM, "Waiting for tagCounterThread to stop");
199 } catch (InterruptedException e) {
203 logger.log(logger.MEDIUM, "Waiting for trashThread to stop");
206 } catch (InterruptedException e) {
211 logger.log(logger.MEDIUM, "Waiting for saveThread to stop");
214 } catch (InterruptedException e) {
220 //***************************************************************
221 //***************************************************************
222 //* Refresh lists after a db sync
223 //***************************************************************
224 //***************************************************************
225 public void refreshLists(Note n, boolean dirty, String content) {
227 // conn.getNoteTable().updateNoteContent(n.getGuid(), n.getContent());
228 saveRunner.addWork(n.getGuid(), content);
229 conn.getNoteTable().updateNoteTitle(n.getGuid(), n.getTitle());
232 setSavedSearchIndex(conn.getSavedSearchTable().getAll());
233 setTagIndex(conn.getTagTable().getAll());
234 setNotebookIndex(conn.getNotebookTable().getAll());
236 List<Notebook> local = conn.getNotebookTable().getAllLocal();
237 localNotebookIndex = new ArrayList<String>();
238 for (int i=0; i<local.size(); i++)
239 localNotebookIndex.add(local.get(i).getGuid());
241 noteModel.setMasterNoteIndex(conn.getNoteTable().getAllNotes());
242 // For performance reasons, we didn't get the tags for every note individually. We now need to
244 List<cx.fbn.nevernote.sql.NoteTagsRecord> noteTags = conn.getNoteTable().noteTagsTable.getAllNoteTags();
245 for (int i=0; i<getMasterNoteIndex().size(); i++) {
246 List<String> tags = new ArrayList<String>();
247 List<String> names = new ArrayList<String>();
248 for (int j=0; j<noteTags.size(); j++) {
249 if (getMasterNoteIndex().get(i).getGuid().equals(noteTags.get(j).noteGuid)) {
250 tags.add(noteTags.get(j).tagGuid);
251 names.add(getTagNameByGuid(noteTags.get(j).tagGuid));
255 getMasterNoteIndex().get(i).setTagGuids(tags);
256 getMasterNoteIndex().get(i).setTagNames(names);
260 //setUnsynchronizedNotes(conn.getNoteTable().getUnsynchronizedGUIDs());
262 linkedNotebookIndex = conn.getLinkedNotebookTable().getAll();
264 enSearchChanged = true;
267 public void reloadTagIndex() {
268 setTagIndex(conn.getTagTable().getAll());
270 public void reloadIndexes() {
271 //setUnsynchronizedNotes(conn.getNoteTable().getUnsynchronizedGUIDs());
273 List<Notebook> local = conn.getNotebookTable().getAllLocal();
274 localNotebookIndex = new ArrayList<String>();
275 for (int i=0; i<local.size(); i++)
276 localNotebookIndex.add(local.get(i).getGuid());
280 setNotebookIndex(conn.getNotebookTable().getAll());
281 // load archived notebooks (if note using the EN interface)
282 setArchiveNotebookIndex(conn.getNotebookTable().getAllArchived());
283 // load saved search index
284 setSavedSearchIndex(conn.getSavedSearchTable().getAll());
285 // Load search helper utility
286 enSearch = new EnSearch(conn, logger, "", getTagIndex(), Global.getRecognitionWeight());
287 logger.log(logger.HIGH, "Building note index");
289 // if (getMasterNoteIndex() == null) {
290 noteModel.setMasterNoteIndex(conn.getNoteTable().getAllNotes());
292 // For performance reasons, we didn't get the tags for every note individually. We now need to
294 List<cx.fbn.nevernote.sql.NoteTagsRecord> noteTags = conn.getNoteTable().noteTagsTable.getAllNoteTags();
295 for (int i=0; i<getMasterNoteIndex().size(); i++) {
296 List<String> tags = new ArrayList<String>();
297 List<String> names = new ArrayList<String>();
298 for (int j=0; j<noteTags.size(); j++) {
299 if (getMasterNoteIndex().get(i).getGuid().equals(noteTags.get(j).noteGuid)) {
300 tags.add(noteTags.get(j).tagGuid);
301 names.add(getTagNameByGuid(noteTags.get(j).tagGuid));
305 getMasterNoteIndex().get(i).setTagGuids(tags);
306 getMasterNoteIndex().get(i).setTagNames(names);
309 setNoteIndex(getMasterNoteIndex());
313 //***************************************************************
314 //***************************************************************
315 //* selected notebooks
316 //***************************************************************
317 //***************************************************************
318 // Return the selected notebook(s)
319 public List<String> getSelectedNotebooks() {
320 return selectedNotebooks;
322 // Set the current selected notebook(s)
323 public void setSelectedNotebooks(List <String> s) {
325 s = new ArrayList<String>();
326 selectedNotebooks = s;
330 //***************************************************************
331 //***************************************************************
332 //** These functions deal with setting & retrieving the master lists
333 //***************************************************************
334 //***************************************************************
335 // Get the note table model
336 public NoteTableModel getNoteTableModel() {
339 // save the saved search index
340 private void setSavedSearchIndex(List<SavedSearch> t) {
343 // Retrieve the Tag index
344 public List<SavedSearch> getSavedSearchIndex() {
348 // save the tag index
349 private void setTagIndex(List<Tag> t) {
352 // Retrieve the Tag index
353 public List<Tag> getTagIndex() {
356 private void setNotebookIndex(List<Notebook> t) {
359 private void setArchiveNotebookIndex(List<Notebook> t) {
360 archiveNotebookIndex = t;
362 // Retrieve the Notebook index
363 public List<Notebook> getNotebookIndex() {
364 return notebookIndex;
367 public List<LinkedNotebook> getLinkedNotebookIndex() {
368 return linkedNotebookIndex;
370 public List<Notebook> getArchiveNotebookIndex() {
371 return archiveNotebookIndex;
373 // Save the current note list
374 private void setNoteIndex(List<Note> n) {
375 noteModel.setNoteIndex(n);
376 refreshNoteMetadata();
378 public void refreshNoteMetadata() {
379 noteModel.setNoteMetadata(conn.getNoteTable().getNotesMetaInformation());
381 // Update a note's meta data
382 public void updateNoteMetadata(NoteMetadata meta) {
383 noteModel.metaData.remove(meta);
384 noteModel.metaData.put(meta.getGuid(), meta);
385 conn.getNoteTable().updateNoteMetadata(meta);
387 // Get the note index
388 public synchronized List<Note> getNoteIndex() {
389 return noteModel.getNoteIndex();
391 // Save the count of notes per notebook
392 public void setNotebookCounter(List<NotebookCounter> n) {
394 notebookSignal.refreshNotebookTreeCounts.emit(getNotebookIndex(), notebookCounter);
396 public List<NotebookCounter> getNotebookCounter() {
397 return notebookCounter;
399 // Save the count of notes for each tag
400 public void setTagCounter(List<TagCounter> n) {
402 tagSignal.refreshTagTreeCounts.emit(tagCounter);
404 public List<TagCounter> getTagCounter() {
407 public List<String> getLocalNotebooks() {
408 return localNotebookIndex;
411 // public void setUnsynchronizedNotes(List<String> l) {
412 // noteModel.setUnsynchronizedNotes(l);
414 // Return a count of items in the trash
415 public int getTrashCount() {
418 // get the EnSearch variable
419 public EnSearch getEnSearch() {
422 public List<Note> getMasterNoteIndex() {
423 return noteModel.getMasterNoteIndex();
426 // public HashMap<String, QImage> getThumbnails() {
427 // return thumbnailList;
429 public HashMap<String, NoteMetadata> getNoteMetadata() {
430 return noteModel.metaData;
432 public QImage getThumbnail(String guid) {
433 // if (getThumbnails().containsKey(guid))
434 // return getThumbnails().get(guid);
436 QImage img = new QImage();
437 img = QImage.fromData(conn.getNoteTable().getThumbnail(guid));
438 if (img == null || img.isNull())
440 //getThumbnails().put(guid, img);
443 public QPixmap getThumbnailPixmap(String guid) {
444 // if (getThumbnails().containsKey(guid))
445 // return getThumbnails().get(guid);
447 QPixmap img = new QPixmap();
448 img.loadFromData(conn.getNoteTable().getThumbnail(guid));
449 if (img == null || img.isNull())
451 //getThumbnails().put(guid, img);
454 //***************************************************************
455 //***************************************************************
456 //** These functions deal with setting & retrieving filters
457 //***************************************************************
458 //***************************************************************
459 public void setEnSearch(String t) {
460 enSearch = new EnSearch(conn,logger, t, getTagIndex(), Global.getRecognitionWeight());
461 enSearchChanged = true;
464 public void setSelectedTags(List<String> selectedTags) {
465 this.selectedTags = selectedTags;
467 // Save seleceted search
468 public void setSelectedSavedSearch(String s) {
469 this.selectedSearch = s;
472 public List<String> getSelectedTags() {
476 public String getSelectedSearch() {
477 return selectedSearch;
483 //***************************************************************
484 //***************************************************************
486 //***************************************************************
487 //***************************************************************
489 public void saveNoteTags(String noteGuid, List<String> tags, boolean isDirty) {
\r
490 logger.log(logger.HIGH, "Entering ListManager.saveNoteTags");
491 // ICHANGED 同じタグが付けられた履歴を記録(必ずdeleteNoteTagの前にやる)
492 for (int i = 0; i < tags.size(); i++) {
493 String tagName = tags.get(i);
494 for (int j = 0; j < tagIndex.size(); j++) {
495 if (tagIndex.get(j).getName().equalsIgnoreCase(tagName)) {
496 conn.getHistoryTable().addSameTagHistory(noteGuid, tagIndex.get(j).getGuid());
502 conn.getNoteTable().noteTagsTable.deleteNoteTag(noteGuid);
503 List<String> tagGuids = new ArrayList<String>();
504 boolean newTagCreated = false;
506 for (int i=0; i<tags.size(); i++) {
507 tagName = tags.get(i);
508 boolean found = false;
509 for (int j=0; j<tagIndex.size(); j++) {
510 if (tagIndex.get(j).getName().equalsIgnoreCase(tagName)) {
511 conn.getNoteTable().noteTagsTable.saveNoteTag(noteGuid, tagIndex.get(j).getGuid(), isDirty);
\r
512 tagGuids.add(tagIndex.get(j).getGuid());
518 Tag nTag = new Tag();
519 nTag.setName(tagName);
520 Calendar currentTime = new GregorianCalendar();
521 Long l = new Long(currentTime.getTimeInMillis());
523 while (l==prevTime) {
524 currentTime = new GregorianCalendar();
525 l=currentTime.getTimeInMillis();
527 String randint = new String(Long.toString(l));
529 nTag.setUpdateSequenceNum(0);
530 nTag.setGuid(randint);
531 conn.getTagTable().addTag(nTag, true);
532 getTagIndex().add(nTag);
533 conn.getNoteTable().noteTagsTable.saveNoteTag(noteGuid, nTag.getGuid(), isDirty);
\r
534 tagGuids.add(nTag.getGuid());
535 newTagCreated = true;
539 for (int i=0; i<getNoteIndex().size(); i++) {
540 if (getNoteIndex().get(i).getGuid().equals(noteGuid)) {
541 getNoteIndex().get(i).setTagNames(tags);
542 getNoteIndex().get(i).setTagGuids(tagGuids);
543 i=getNoteIndex().size()+1;
547 tagSignal.listChanged.emit();
548 logger.log(logger.HIGH, "Leaving ListManager.saveNoteTags");
551 public void deleteNote(String guid) {
552 trashCounterRunner.abortCount = true;
553 Calendar currentTime = new GregorianCalendar();
554 Long l = new Long(currentTime.getTimeInMillis());
556 while (l==prevTime) {
557 currentTime = new GregorianCalendar();
558 l=currentTime.getTimeInMillis();
561 for (int i=0; i<getMasterNoteIndex().size(); i++) {
562 if (getMasterNoteIndex().get(i).getGuid().equals(guid)) {
563 getMasterNoteIndex().get(i).setActive(false);
564 getMasterNoteIndex().get(i).setDeleted(l);
565 i=getMasterNoteIndex().size();
568 for (int i=0; i<getNoteIndex().size(); i++) {
569 if (getNoteIndex().get(i).getGuid().equals(guid)) {
570 getNoteIndex().get(i).setActive(false);
571 getNoteIndex().get(i).setDeleted(l);
572 i=getNoteIndex().size();
575 conn.getNoteTable().deleteNote(guid);
579 public void restoreNote(String guid) {
580 trashCounterRunner.abortCount = true;
581 for (int i=0; i<getMasterNoteIndex().size(); i++) {
582 if (getMasterNoteIndex().get(i).getGuid().equals(guid)) {
583 getMasterNoteIndex().get(i).setActive(true);
584 getMasterNoteIndex().get(i).setDeleted(0);
585 i=getMasterNoteIndex().size();
588 for (int i=0; i<getNoteIndex().size(); i++) {
589 if (getNoteIndex().get(i).getGuid().equals(guid)) {
590 getNoteIndex().get(i).setActive(true);
591 getNoteIndex().get(i).setDeleted(0);
592 i=getNoteIndex().size();
595 conn.getNoteTable().restoreNote(guid);
598 public void updateNote(Note n) {
600 for (int i=0; i<getMasterNoteIndex().size(); i++) {
601 if (getMasterNoteIndex().get(i).getGuid().equals(n.getGuid())) {
602 getMasterNoteIndex().remove(i);
603 getMasterNoteIndex().add(n);
606 for (int i=0; i<getNoteIndex().size(); i++) {
607 if (getNoteIndex().get(i).getGuid().equals(n.getGuid())) {
608 getNoteIndex().get(i).setActive(true);
609 getNoteIndex().get(i).setDeleted(0);
610 i=getNoteIndex().size();
613 conn.getNoteTable().updateNote(n);
616 public void addNote(Note n, NoteMetadata meta) {
617 noteModel.addNote(n, meta);
618 noteModel.metaData.put(n.getGuid(), meta);
621 public void expungeNote(String guid) {
622 trashCounterRunner.abortCount = true;
623 for (int i=0; i<getMasterNoteIndex().size(); i++) {
624 if (getMasterNoteIndex().get(i).getGuid().equals(guid)) {
625 getMasterNoteIndex().remove(i);
626 i=getMasterNoteIndex().size();
629 for (int i=0; i<getNoteIndex().size(); i++) {
630 if (getNoteIndex().get(i).getGuid().equals(guid)) {
631 getNoteIndex().remove(i);
632 i=getNoteIndex().size();
635 conn.getNoteTable().expungeNote(guid, false, true);
639 public void emptyTrash() {
640 trashCounterRunner.abortCount = true;
641 for (int i=getMasterNoteIndex().size()-1; i>=0; i--) {
642 if (!getMasterNoteIndex().get(i).isActive()) {
643 getMasterNoteIndex().remove(i);
647 for (int i=getNoteIndex().size()-1; i>=0; i--) {
648 if (!getNoteIndex().get(i).isActive()) {
649 getNoteIndex().remove(i);
653 conn.getNoteTable().expungeAllDeletedNotes();
656 // The trash counter thread has produced a result
657 @SuppressWarnings("unused")
658 private void trashSignalReceiver(Integer i) {
660 trashSignal.countChanged.emit(i);
662 // Update note contents
663 public void updateNoteContent(String guid, String content) {
664 logger.log(logger.HIGH, "Entering ListManager.updateNoteContent");
665 // EnmlConverter enml = new EnmlConverter(logger);
666 // String text = enml.convert(guid, content);
668 // Update the list tables
669 /* for (int i=0; i<masterNoteIndex.size(); i++) {
670 if (masterNoteIndex.get(i).getGuid().equals(guid)) {
671 masterNoteIndex.get(i).setContent(text);
672 i = masterNoteIndex.size();
675 // Update the list tables
676 for (int i=0; i<getNoteIndex().size(); i++) {
677 if (getNoteIndex().get(i).getGuid().equals(guid)) {
678 getNoteIndex().get(i).setContent(text);
679 i = getNoteIndex().size();
683 // Check if any new tags were encountered
684 /* if (enml.saveInvalidXML) {
685 List<String> elements = Global.invalidElements;
686 for (int i=0; i<elements.size(); i++) {
687 conn.getInvalidXMLTable().addInvalidElement(elements.get(i));
689 for (String key : Global.invalidAttributes.keySet()) {
690 ArrayList<String> attributes = Global.invalidAttributes.get(key);
691 for (int i=0; i<attributes.size(); i++) {
692 conn.getInvalidXMLTable().addInvalidAttribute(key, attributes.get(i));
697 saveRunner.addWork(guid, content);
698 // conn.getNoteTable().updateNoteContent(guid, content);
699 logger.log(logger.HIGH, "Leaving ListManager.updateNoteContent");
701 // Update a note creation date
702 public void updateNoteCreatedDate(String guid, QDateTime date) {
703 noteModel.updateNoteCreatedDate(guid, date);
704 conn.getNoteTable().updateNoteCreatedDate(guid, date);
706 // Subject date has been changed
707 public void updateNoteSubjectDate(String guid, QDateTime date) {
708 noteModel.updateNoteSubjectDate(guid, date);
709 conn.getNoteTable().updateNoteSubjectDate(guid, date);
711 // Author has changed
712 public void updateNoteAuthor(String guid, String author) {
713 noteModel.updateNoteAuthor(guid, author);
714 conn.getNoteTable().updateNoteAuthor(guid, author);
716 // Author has changed
717 public void updateNoteGeoTag(String guid, Double lon, Double lat, Double alt) {
718 for (int i=0; i<getMasterNoteIndex().size(); i++) {
719 if (getMasterNoteIndex().get(i).getGuid().equals(guid)) {
720 getMasterNoteIndex().get(i).getAttributes().setLongitude(lon);
721 getMasterNoteIndex().get(i).getAttributes().setLongitudeIsSet(true);
722 getMasterNoteIndex().get(i).getAttributes().setLatitude(lat);
723 getMasterNoteIndex().get(i).getAttributes().setLatitudeIsSet(true);
724 getMasterNoteIndex().get(i).getAttributes().setAltitude(alt);
725 getMasterNoteIndex().get(i).getAttributes().setAltitudeIsSet(true);
726 i = getMasterNoteIndex().size();
729 // Update the list tables
730 for (int i=0; i<getNoteIndex().size(); i++) {
731 if (getNoteIndex().get(i).getGuid().equals(guid)) {
732 getNoteIndex().get(i).getAttributes().setLongitude(lon);
733 getNoteIndex().get(i).getAttributes().setLongitudeIsSet(true);
734 getNoteIndex().get(i).getAttributes().setLatitude(lat);
735 getNoteIndex().get(i).getAttributes().setLatitudeIsSet(true);
736 getNoteIndex().get(i).getAttributes().setAltitude(alt);
737 getNoteIndex().get(i).getAttributes().setAltitudeIsSet(true);
738 i = getNoteIndex().size();
741 conn.getNoteTable().updateNoteGeoTags(guid, lon, lat, alt);
743 // Source URL changed
744 public void updateNoteSourceUrl(String guid, String url) {
745 noteModel.updateNoteSourceUrl(guid, url);
746 conn.getNoteTable().updateNoteSourceUrl(guid, url);
748 // Update a note last changed date
749 public void updateNoteAlteredDate(String guid, QDateTime date) {
750 noteModel.updateNoteChangedDate(guid, date);
751 conn.getNoteTable().updateNoteAlteredDate(guid, date);
753 // Update a note title
754 public void updateNoteTitle(String guid, String title) {
755 logger.log(logger.HIGH, "Entering ListManager.updateNoteTitle");
756 conn.getNoteTable().updateNoteTitle(guid, title);
757 noteModel.updateNoteTitle(guid, title);
758 logger.log(logger.HIGH, "Leaving ListManager.updateNoteTitle");
760 // Update a note's notebook
761 public void updateNoteNotebook(String guid, String notebookGuid) {
762 logger.log(logger.HIGH, "Entering ListManager.updateNoteNotebook");
763 noteModel.updateNoteNotebook(guid, notebookGuid);
764 conn.getNoteTable().updateNoteNotebook(guid, notebookGuid, true);
765 logger.log(logger.HIGH, "Leaving ListManager.updateNoteNotebook");
767 // Update a note sequence number
768 public void updateNoteSequence(String guid, int sequence) {
769 logger.log(logger.HIGH, "Entering ListManager.updateNoteSequence");
771 conn.getNoteTable().updateNoteSequence(guid, sequence);
773 for (int i=0; i<noteModel.getMasterNoteIndex().size(); i++) {
774 if (noteModel.getMasterNoteIndex().get(i).getGuid().equals(guid)) {
775 noteModel.getMasterNoteIndex().get(i).setUpdateSequenceNum(sequence);
776 i=noteModel.getMasterNoteIndex().size()+1;
780 for (int i=0; i<getNoteIndex().size(); i++) {
781 if (getNoteIndex().get(i).getGuid().equals(guid)) {
782 getNoteIndex().get(i).setUpdateSequenceNum(sequence);
783 i=getNoteIndex().size()+1;
786 logger.log(logger.HIGH, "Leaving ListManager.updateNoteSequence");
788 public void updateNoteGuid(String oldGuid, String newGuid, boolean updateDatabase) {
789 logger.log(logger.HIGH, "Entering ListManager.updateNoteGuid");
791 conn.getNoteTable().updateNoteGuid(oldGuid, newGuid);
792 noteModel.updateNoteGuid(oldGuid, newGuid);
793 logger.log(logger.HIGH, "Leaving ListManager.updateNoteGuid");
798 //************************************************************************************
799 //************************************************************************************
801 //************************************************************************************
802 //************************************************************************************
803 // Update a tag sequence number
804 public void updateTagSequence(String guid, int sequence) {
805 logger.log(logger.HIGH, "Entering ListManager.updateTagSequence");
807 conn.getTagTable().updateTagSequence(guid, sequence);
808 for (int i=0; i<tagIndex.size(); i++) {
809 if (tagIndex.get(i).getGuid().equals(guid)) {
810 getTagIndex().get(i).setUpdateSequenceNum(sequence);
814 logger.log(logger.HIGH, "Leaving ListManager.updateTagSequence");
816 // Update a tag guid number
817 public void updateTagGuid(String oldGuid, String newGuid) {
818 logger.log(logger.HIGH, "Entering ListManager.updateTagGuid");
820 conn.getTagTable().updateTagGuid(oldGuid, newGuid);
821 for (int i=0; i<tagIndex.size(); i++) {
822 if (tagIndex.get(i).getGuid().equals(oldGuid)) {
823 tagIndex.get(i).setGuid(newGuid);
827 logger.log(logger.HIGH, "Leaving ListManager.updateTagGuid");
830 // Find all children for a tag
831 public List<Tag> findAllChildren(String guid) {
832 List<Tag> tags = new ArrayList<Tag>();
833 return findAllChildrenRecursive(guid, tags);
835 public List<Tag> findAllChildrenRecursive(String guid, List<Tag> tags) {
837 // Start looping through the tags. If we find a tag which has a parent that
838 // matches guid, then we add it to the list of tags & search for its children.
839 for (int i=0; i<getTagIndex().size(); i++) {
840 if (getTagIndex().get(i).getParentGuid() != null && getTagIndex().get(i).getParentGuid().equals(guid)) {
841 tags.add(getTagIndex().get(i));
842 tags = findAllChildrenRecursive(getTagIndex().get(i).getGuid(), tags);
847 // Give a list of tags, does any of them match a child tag?
848 public boolean checkNoteForChildTags(String guid, List<String> noteTags) {
849 boolean returnValue = false;
850 List<Tag> children = findAllChildren(guid);
851 for (int i=0; i<noteTags.size(); i++) {
852 String noteTag = noteTags.get(i);
853 for (int j=0; j<children.size(); j++) {
854 if (noteTag.equals(children.get(j).getGuid()))
862 //************************************************************************************
863 //************************************************************************************
864 //** Notebook functions
865 //************************************************************************************
866 //************************************************************************************
868 public void deleteNotebook(String guid) {
869 for (int i=0; i<getNotebookIndex().size(); i++) {
870 if (getNotebookIndex().get(i).getGuid().equals(guid)) {
871 getNotebookIndex().remove(i);
872 i=getMasterNoteIndex().size();
875 conn.getNotebookTable().expungeNotebook(guid, true);
878 public void renameStack(String oldName, String newName) {
879 for (int i=0; i<getNotebookIndex().size(); i++) {
880 if (getNotebookIndex().get(i).getStack() != null &&
881 getNotebookIndex().get(i).getStack().equalsIgnoreCase(oldName)) {
882 getNotebookIndex().get(i).setStack(newName);
886 // Update a notebook sequence number
887 public void updateNotebookSequence(String guid, int sequence) {
888 logger.log(logger.HIGH, "Entering ListManager.updateNotebookSequence");
890 conn.getNotebookTable().updateNotebookSequence(guid, sequence);
892 for (int i=0; i<notebookIndex.size(); i++) {
893 if (notebookIndex.get(i).getGuid().equals(guid)) {
894 notebookIndex.get(i).setUpdateSequenceNum(sequence);
895 i=notebookIndex.size()+1;
898 logger.log(logger.HIGH, "Leaving ListManager.updateNotebookSequence");
901 // Update a notebook Guid number
902 public void updateNotebookGuid(String oldGuid, String newGuid) {
903 logger.log(logger.HIGH, "Entering ListManager.updateNotebookGuid");
905 conn.getNotebookTable().updateNotebookGuid(oldGuid, newGuid);
907 for (int i=0; i<notebookIndex.size(); i++) {
908 if (notebookIndex.get(i).getGuid().equals(oldGuid)) {
909 notebookIndex.get(i).setGuid(newGuid);
910 i=notebookIndex.size()+1;
913 logger.log(logger.HIGH, "Leaving ListManager.updateNotebookGuid");
916 // Update a notebook Guid number
917 public void updateNotebookStack(String oldGuid, String stack) {
918 logger.log(logger.HIGH, "Entering ListManager.updateNotebookGuid");
920 conn.getNotebookTable().setStack(oldGuid, stack);
922 for (int i=0; i<notebookIndex.size(); i++) {
923 if (notebookIndex.get(i).getGuid().equals(oldGuid)) {
924 notebookIndex.get(i).setStack(stack);
925 i=notebookIndex.size()+1;
928 logger.log(logger.HIGH, "Leaving ListManager.updateNotebookGuid");
933 //************************************************************************************
934 //************************************************************************************
935 //** Load and filter the note index
936 //************************************************************************************
937 //************************************************************************************
939 public void noteDownloaded(Note n) {
940 boolean found = false;
941 for (int i=0; i<getMasterNoteIndex().size(); i++) {
942 if (getMasterNoteIndex().get(i).getGuid().equals(n.getGuid())) {
943 getMasterNoteIndex().set(i,n);
945 i=getMasterNoteIndex().size();
950 getMasterNoteIndex().add(n);
952 for (int i=0; i<getNoteIndex().size(); i++) {
953 if (getNoteIndex().get(i).getGuid().equals(n.getGuid())) {
954 if (filterRecord(getNoteIndex().get(i)))
955 getNoteIndex().add(n);
956 getNoteIndex().remove(i);
957 i=getNoteIndex().size();
962 getNoteIndex().add(n);
965 // Check if a note matches the currently selected notebooks, tags, or attribute searches.
966 public boolean filterRecord(Note n) {
968 boolean goodNotebook = false;
969 boolean goodTag = false;
970 boolean goodStatus = false;
973 if (!n.isActive() && Global.showDeleted)
976 if (n.isActive() && !Global.showDeleted)
980 // Begin filtering results
982 goodNotebook = filterByNotebook(n.getNotebookGuid());
984 goodTag = filterByTag(n.getTagGuids());
986 boolean goodCreatedBefore = false;
987 boolean goodCreatedSince = false;
988 boolean goodChangedBefore = false;
989 boolean goodChangedSince = false;
990 boolean goodContains = false;
991 if (!Global.createdBeforeFilter.hasSelection())
992 goodCreatedBefore = true;
994 goodCreatedBefore = Global.createdBeforeFilter.check(n);
996 if (!Global.createdSinceFilter.hasSelection())
997 goodCreatedSince = true;
999 goodCreatedSince = Global.createdSinceFilter.check(n);
1001 if (!Global.changedBeforeFilter.hasSelection())
1002 goodChangedBefore = true;
1004 goodChangedBefore = Global.changedBeforeFilter.check(n);
1005 if (!Global.changedSinceFilter.hasSelection())
1006 goodChangedSince = true;
1008 goodChangedSince = Global.changedSinceFilter.check(n);
1009 if (!Global.containsFilter.hasSelection())
1010 goodContains = true;
1012 goodContains = Global.containsFilter.check(conn.getNoteTable(), n);
1014 if (goodCreatedSince && goodCreatedBefore && goodChangedSince && goodChangedBefore && goodContains)
1020 // Trigger a recount of counters
1021 public void refreshCounters() {
1022 // refreshCounters= false;
1023 if (!refreshCounters)
1025 refreshCounters = false;
1026 tagCounterRunner.abortCount = true;
1027 notebookCounterRunner.abortCount = true;
1028 trashCounterRunner.abortCount = true;
1029 countNotebookResults(getNoteIndex());
1030 countTagResults(getNoteIndex());
1034 // Load the note index based upon what the user wants.
1035 public void loadNotesIndex() {
1036 logger.log(logger.EXTREME, "Entering ListManager.loadNotesIndex()");
1039 if (enSearchChanged || getMasterNoteIndex() == null)
1040 matches = enSearch.matchWords();
1042 matches = getMasterNoteIndex();
1044 if (matches == null)
1045 matches = getMasterNoteIndex();
1047 setNoteIndex(new ArrayList<Note>());
1048 for (int i=0; i<matches.size(); i++) {
1049 if (filterRecord(matches.get(i)))
1050 getNoteIndex().add(matches.get(i));
1052 refreshCounters = true;
1053 enSearchChanged = false;
1054 logger.log(logger.EXTREME, "Leaving ListManager.loadNotesIndex()");
1056 public void countNotebookResults(List<Note> index) {
1057 logger.log(logger.EXTREME, "Entering ListManager.countNotebookResults()");
1058 notebookCounterRunner.abortCount = true;
1059 if (!Global.mimicEvernoteInterface)
1060 notebookCounterRunner.setNoteIndex(index);
1062 notebookCounterRunner.setNoteIndex(getMasterNoteIndex());
1063 notebookCounterRunner.release(CounterRunner.NOTEBOOK);
1064 logger.log(logger.EXTREME, "Leaving ListManager.countNotebookResults()");
1066 public void countTagResults(List<Note> index) {
1067 logger.log(logger.EXTREME, "Entering ListManager.countTagResults");
1068 trashCounterRunner.abortCount = true;
1069 if (!Global.tagBehavior().equalsIgnoreCase("DoNothing"))
1070 tagCounterRunner.setNoteIndex(index);
1072 tagCounterRunner.setNoteIndex(getMasterNoteIndex());
1073 tagCounterRunner.release(CounterRunner.TAG);
1074 logger.log(logger.EXTREME, "Leaving ListManager.countTagResults()");
1076 // Update the count of items in the trash
1077 public void reloadTrashCount() {
1078 logger.log(logger.EXTREME, "Entering ListManager.reloadTrashCount");
1079 trashCounterRunner.abortCount = true;
1080 trashCounterRunner.setNoteIndex(getMasterNoteIndex());
1081 trashCounterRunner.release(CounterRunner.TRASH);
1082 logger.log(logger.EXTREME, "Leaving ListManager.reloadTrashCount");
1085 private boolean filterByNotebook(String guid) {
1086 boolean good = false;
1087 if (selectedNotebooks.size() == 0)
1089 if (!good && selectedNotebooks.contains(guid))
1092 for (int i=0; i<getArchiveNotebookIndex().size() && good; i++) {
1093 if (guid.equals(getArchiveNotebookIndex().get(i).getGuid())) {
1100 private boolean filterByTag(List<String> noteTags) {
1101 // If either the note has no tags or there are
1102 // no selected tags, then any note is good.
1103 if (noteTags == null || selectedTags == null)
1106 // If there are no tags selected, then any note is good
1107 if (selectedTags.size() == 0)
1110 // If ALL tags must be matched, then check ALL note tags,
1111 // otherwise we match on any criteria.
1112 if (!Global.anyTagSelectionMatch()) {
1113 for (int i=0; i<selectedTags.size(); i++) {
1114 String selectedGuid = selectedTags.get(i);
1115 boolean childMatch = false;
1116 // If we should include children in the results
1117 if (Global.includeTagChildren()) {
1118 childMatch = checkNoteForChildTags(selectedGuid, noteTags);
1119 // Do we have a match with this tag or any children
1120 if (!noteTags.contains(selectedGuid)&& !childMatch)
1123 // Does this note have a matching tag
1124 if (!noteTags.contains(selectedGuid))
1130 // Any match is displayed.
1131 for (int i=0; i<selectedTags.size(); i++) {
1132 String selectedGuid = selectedTags.get(i);
1133 // If we have a simple match, then we're good
1134 if (noteTags.contains(selectedGuid))
1136 // If we have a match with one of the children tags && we should include child tags
1137 if (Global.includeTagChildren() && checkNoteForChildTags(selectedGuid, noteTags))
1144 public void setNoteSynchronized(String guid, boolean value) {
1145 getNoteTableModel().updateNoteSyncStatus(guid, value);
1148 public void updateNoteTitleColor(String guid, Integer color) {
1149 NoteMetadata meta = getNoteMetadata().get(guid);
1151 noteModel.updateNoteTitleColor(guid, color);
1152 meta.setColor(color);
1153 conn.getNoteTable().updateNoteMetadata(meta);
1156 public void loadNoteTitleColors() {
1157 noteModel.setMetaData(getNoteMetadata());
1160 //********************************************************************************
1161 //********************************************************************************
1162 //* Support signals from the index thread
1163 //********************************************************************************
1164 //********************************************************************************
1165 // Reset a flag if an index is needed
1166 public void setIndexNeeded(String guid, String type, Boolean b) {
1167 if (Global.keepRunning && type.equalsIgnoreCase("content"))
1168 conn.getNoteTable().setIndexNeeded(guid, false);
1169 if (Global.keepRunning && type.equalsIgnoreCase("resource")) {
1170 conn.getNoteTable().noteResourceTable.setIndexNeeded(guid, b);
1174 public boolean threadCheck(int id) {
1175 if (id == Global.notebookCounterThreadId)
1176 return notebookThread.isAlive();
1177 if (id == Global.tagCounterThreadId)
1178 return tagThread.isAlive();
1179 if (id == Global.trashCounterThreadId)
1180 return trashThread.isAlive();
1181 if (id == Global.saveThreadId)
1182 return saveThread.isAlive();
1188 //********************************************************************************
1189 //********************************************************************************
1190 //* Utility Functions
1191 //********************************************************************************
1192 //********************************************************************************
1193 public void compactDatabase() {
1194 conn.compactDatabase();
1195 // IndexConnection idx = new IndexConnection(logger, "nevernote-compact");
1197 // idx.dbShutdown();
1200 // Rebuild the note HTML to something usable
1201 public List<String> scanNoteForResources(Note n) {
1202 logger.log(logger.HIGH, "Entering ListManager.scanNoteForResources");
1203 logger.log(logger.EXTREME, "Note guid: " +n.getGuid());
1204 QDomDocument doc = new QDomDocument();
1205 QDomDocument.Result result = doc.setContent(n.getContent());
1206 if (!result.success) {
1207 logger.log(logger.MEDIUM, "Parse error when scanning note for resources.");
1208 logger.log(logger.MEDIUM, "Note guid: " +n.getGuid());
1212 List<String> returnArray = new ArrayList<String>();
1213 QDomNodeList anchors = doc.elementsByTagName("en-media");
1214 for (int i=0; i<anchors.length(); i++) {
1215 QDomElement enmedia = anchors.at(i).toElement();
1216 if (enmedia.hasAttribute("type")) {
1217 QDomAttr hash = enmedia.attributeNode("hash");
1218 returnArray.add(hash.value().toString());
1221 logger.log(logger.HIGH, "Leaving ListManager.scanNoteForResources");
1224 // Given a list of tags, produce a string list of tag names
1225 public String getTagNamesForNote(Note n) {
1226 StringBuffer buffer = new StringBuffer(100);
1227 Vector<String> v = new Vector<String>();
1228 List<String> guids = n.getTagGuids();
1233 for (int i=0; i<guids.size(); i++) {
1234 v.add(getTagNameByGuid(guids.get(i)));
1236 Comparator<String> comparator = Collections.reverseOrder();
1237 Collections.sort(v,comparator);
1238 Collections.reverse(v);
1240 for (int i = 0; i<v.size(); i++) {
1242 buffer.append(", ");
1243 buffer.append(v.get(i));
1246 return buffer.toString();
1248 // Get a tag name when given a tag guid
1249 public String getTagNameByGuid(String guid) {
1250 for (int i=0; i<getTagIndex().size(); i++) {
1251 String s = getTagIndex().get(i).getGuid();
1252 if (s.equals(guid)) {
1253 return getTagIndex().get(i).getName();
1258 // For a notebook guid, return the name
1259 public String getNotebookNameByGuid(String guid) {
1260 if (notebookIndex == null)
1262 for (int i=0; i<notebookIndex.size(); i++) {
1263 String s = notebookIndex.get(i).getGuid();
1264 if (s.equals(guid)) {
1265 return notebookIndex.get(i).getName();
1272 // Reload the note's tag names. This is called when a tag's name changes by
1273 // the user. It updates all notes with that tag to the new tag name.
1274 public void reloadNoteTagNames(String tagGuid, String newName) {
1276 // Set the master index
1277 for (int i=0; i<getMasterNoteIndex().size(); i++) {
1278 for (int j=0; j<getMasterNoteIndex().get(i).getTagGuids().size(); j++) {
1279 if (getMasterNoteIndex().get(i).getTagGuids().get(j).equals(tagGuid)) {
1280 getMasterNoteIndex().get(i).getTagNames().set(j, newName);
1285 // Set the current index
1286 for (int i=0; i<getNoteIndex().size(); i++) {
1287 for (int j=0; j<getNoteIndex().get(i).getTagGuids().size(); j++) {
1288 if (getNoteIndex().get(i).getTagGuids().get(j).equals(tagGuid)) {
1289 getNoteIndex().get(i).getTagNames().set(j, newName);