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.
21 package cx.fbn.nevernote.utilities;
23 import java.util.ArrayList;
24 import java.util.Calendar;
25 import java.util.Collections;
26 import java.util.Comparator;
27 import java.util.GregorianCalendar;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Vector;
32 import com.evernote.edam.type.LinkedNotebook;
33 import com.evernote.edam.type.Note;
34 import com.evernote.edam.type.Notebook;
35 import com.evernote.edam.type.SavedSearch;
36 import com.evernote.edam.type.Tag;
37 import com.trolltech.qt.QThread;
38 import com.trolltech.qt.core.QDateTime;
39 import com.trolltech.qt.gui.QImage;
40 import com.trolltech.qt.gui.QPixmap;
41 import com.trolltech.qt.sql.QSqlQuery;
42 import com.trolltech.qt.xml.QDomAttr;
43 import com.trolltech.qt.xml.QDomDocument;
44 import com.trolltech.qt.xml.QDomElement;
45 import com.trolltech.qt.xml.QDomNodeList;
47 import cx.fbn.nevernote.Global;
48 import cx.fbn.nevernote.evernote.NoteMetadata;
49 import cx.fbn.nevernote.filters.EnSearch;
50 import cx.fbn.nevernote.filters.NotebookCounter;
51 import cx.fbn.nevernote.filters.TagCounter;
52 import cx.fbn.nevernote.gui.NoteTableModel;
53 import cx.fbn.nevernote.signals.NotebookSignal;
54 import cx.fbn.nevernote.signals.StatusSignal;
55 import cx.fbn.nevernote.signals.TagSignal;
56 import cx.fbn.nevernote.signals.ThreadSignal;
57 import cx.fbn.nevernote.signals.TrashSignal;
58 import cx.fbn.nevernote.sql.DatabaseConnection;
59 import cx.fbn.nevernote.threads.CounterRunner;
60 import cx.fbn.nevernote.threads.SaveRunner;
63 public class ListManager {
66 private final ApplicationLogger logger;
67 DatabaseConnection conn;
68 QSqlQuery deleteWords;
69 QSqlQuery insertWords;
71 private List<Tag> tagIndex;
72 private List<Notebook> notebookIndex;
73 private List<Notebook> archiveNotebookIndex;
74 private List<String> localNotebookIndex;
75 private List<LinkedNotebook> linkedNotebookIndex;
77 private List<SavedSearch> searchIndex;
79 private List<String> selectedNotebooks;
80 private final NoteTableModel noteModel;
83 private List<String> selectedTags;
84 private String selectedSearch;
86 public StatusSignal status;
87 private final CounterRunner notebookCounterRunner;
88 private final QThread notebookThread;
89 private final CounterRunner tagCounterRunner;
90 private final QThread tagThread;
92 private final CounterRunner trashCounterRunner;
93 private final QThread trashThread;
94 public TrashSignal trashSignal;
96 private List<NotebookCounter> notebookCounter; // count of displayed notes in each notebook
97 private List<TagCounter> tagCounter; // count of displayed notes for each tag
99 private EnSearch enSearch;
100 private boolean enSearchChanged;
101 public HashMap<String, String> wordMap;
102 public TagSignal tagSignal;
103 public NotebookSignal notebookSignal;
104 public boolean refreshCounters; // Used to control when to recount lists
105 private int trashCount;
106 public SaveRunner saveRunner; // Thread used to save content. Used because the xml conversion is slowwwww
109 // private final HashMap<String, QImage> thumbnailList;
112 public ListManager(DatabaseConnection d, ApplicationLogger l) {
116 conn.getTagTable().cleanupTags();
117 status = new StatusSignal();
118 signals = new ThreadSignal();
121 enSearchChanged = false;
124 noteModel = new NoteTableModel(this);
125 selectedTags = new ArrayList<String>();
127 notebookCounter = new ArrayList<NotebookCounter>();
128 tagCounter = new ArrayList<TagCounter>();
129 selectedNotebooks = new ArrayList<String>();
133 notebookSignal = new NotebookSignal();
134 // ICHANGED Global.getBehaviorDatabaseUrl()を追加
135 notebookCounterRunner = new CounterRunner("notebook_counter.log", CounterRunner.NOTEBOOK,
136 Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(), Global.getBehaviorDatabaseUrl(),
137 Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
138 notebookCounterRunner.setNoteIndex(getNoteIndex());
139 notebookCounterRunner.notebookSignal.countsChanged.connect(this, "setNotebookCounter(List)");
140 notebookThread = new QThread(notebookCounterRunner, "Notebook Counter Thread");
141 notebookThread.start();
143 tagSignal = new TagSignal();
144 // ICHANGED Global.getBehaviorDatabaseUrl()を追加
145 tagCounterRunner = new CounterRunner("tag_counter.log", CounterRunner.TAG,
146 Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(), Global.getBehaviorDatabaseUrl(),
147 Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
148 tagCounterRunner.setNoteIndex(getNoteIndex());
149 tagCounterRunner.tagSignal.countsChanged.connect(this, "setTagCounter(List)");
150 tagThread = new QThread(tagCounterRunner, "Tag Counter Thread");
153 trashSignal = new TrashSignal();
154 // ICHANGED Global.getBehaviorDatabaseUrl()を追加
155 trashCounterRunner = new CounterRunner("trash_counter.log", CounterRunner.TRASH,
156 Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(), Global.getBehaviorDatabaseUrl(),
157 Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
158 trashCounterRunner.trashSignal.countChanged.connect(this, "trashSignalReceiver(Integer)");
159 trashThread = new QThread(trashCounterRunner, "Trash Counter Thread");
161 // reloadTrashCount();
163 wordMap = new HashMap<String, String>();
164 tagSignal = new TagSignal();
166 logger.log(logger.EXTREME, "Setting save thread");
167 // ICHANGED Global.getBehaviorDatabaseUrl()を追加
168 saveRunner = new SaveRunner("saveRunner.log",
169 Global.getDatabaseUrl(), Global.getIndexDatabaseUrl(), Global.getResourceDatabaseUrl(), Global.getBehaviorDatabaseUrl(),
170 Global.getDatabaseUserid(), Global.getDatabaseUserPassword(), Global.cipherPassword);
171 saveThread = new QThread(saveRunner, "Save Runner Thread");
174 // thumbnailList = conn.getNoteTable().getThumbnails();
175 // thumbnailList = new HashMap<String,QImage>();
177 linkedNotebookIndex = conn.getLinkedNotebookTable().getAll();
178 loadNoteTitleColors();
179 refreshCounters = true;
185 saveRunner.addWork("stop", "");
186 tagCounterRunner.release(CounterRunner.EXIT);
187 notebookCounterRunner.release(CounterRunner.EXIT);
188 trashCounterRunner.release(CounterRunner.EXIT);
190 logger.log(logger.MEDIUM, "Waiting for notebookCounterThread to stop");
192 notebookThread.join();
193 } catch (InterruptedException e) {
197 logger.log(logger.MEDIUM, "Waiting for tagCounterThread to stop");
200 } catch (InterruptedException e) {
204 logger.log(logger.MEDIUM, "Waiting for trashThread to stop");
207 } catch (InterruptedException e) {
212 logger.log(logger.MEDIUM, "Waiting for saveThread to stop");
215 } catch (InterruptedException e) {
221 //***************************************************************
222 //***************************************************************
223 //* Refresh lists after a db sync
224 //***************************************************************
225 //***************************************************************
227 public void saveUpdatedNotes(HashMap<Integer, Note> notes, HashMap<Integer, String> contents) {
228 for (int i = 0; i < notes.size(); i++) {
229 Note n = notes.get(i);
230 String content = contents.get(i);
231 saveRunner.addWork(n.getGuid(), content);
232 conn.getNoteTable().updateNoteTitle(n.getGuid(), n.getTitle());
237 public void refreshLists() {
238 setSavedSearchIndex(conn.getSavedSearchTable().getAll());
239 setTagIndex(conn.getTagTable().getAll());
240 setNotebookIndex(conn.getNotebookTable().getAll());
242 List<Notebook> local = conn.getNotebookTable().getAllLocal();
243 localNotebookIndex = new ArrayList<String>();
244 for (int i=0; i<local.size(); i++)
245 localNotebookIndex.add(local.get(i).getGuid());
247 noteModel.setMasterNoteIndex(conn.getNoteTable().getAllNotes());
248 // For performance reasons, we didn't get the tags for every note individually. We now need to
250 List<cx.fbn.nevernote.sql.NoteTagsRecord> noteTags = conn.getNoteTable().noteTagsTable.getAllNoteTags();
251 for (int i=0; i<getMasterNoteIndex().size(); i++) {
252 List<String> tags = new ArrayList<String>();
253 List<String> names = new ArrayList<String>();
254 for (int j=0; j<noteTags.size(); j++) {
255 if (getMasterNoteIndex().get(i).getGuid().equals(noteTags.get(j).noteGuid)) {
256 tags.add(noteTags.get(j).tagGuid);
257 names.add(getTagNameByGuid(noteTags.get(j).tagGuid));
261 getMasterNoteIndex().get(i).setTagGuids(tags);
262 getMasterNoteIndex().get(i).setTagNames(names);
266 //setUnsynchronizedNotes(conn.getNoteTable().getUnsynchronizedGUIDs());
268 linkedNotebookIndex = conn.getLinkedNotebookTable().getAll();
270 enSearchChanged = true;
273 public void reloadTagIndex() {
274 setTagIndex(conn.getTagTable().getAll());
276 public void reloadIndexes() {
277 //setUnsynchronizedNotes(conn.getNoteTable().getUnsynchronizedGUIDs());
279 List<Notebook> local = conn.getNotebookTable().getAllLocal();
280 localNotebookIndex = new ArrayList<String>();
281 for (int i=0; i<local.size(); i++)
282 localNotebookIndex.add(local.get(i).getGuid());
286 setNotebookIndex(conn.getNotebookTable().getAll());
287 // load archived notebooks (if note using the EN interface)
288 setArchiveNotebookIndex(conn.getNotebookTable().getAllArchived());
289 // load saved search index
290 setSavedSearchIndex(conn.getSavedSearchTable().getAll());
291 // Load search helper utility
292 enSearch = new EnSearch(conn, logger, "", getTagIndex(), Global.getRecognitionWeight());
293 logger.log(logger.HIGH, "Building note index");
295 // if (getMasterNoteIndex() == null) {
296 noteModel.setMasterNoteIndex(conn.getNoteTable().getAllNotes());
298 // For performance reasons, we didn't get the tags for every note individually. We now need to
300 List<cx.fbn.nevernote.sql.NoteTagsRecord> noteTags = conn.getNoteTable().noteTagsTable.getAllNoteTags();
301 for (int i=0; i<getMasterNoteIndex().size(); i++) {
302 List<String> tags = new ArrayList<String>();
303 List<String> names = new ArrayList<String>();
304 for (int j=0; j<noteTags.size(); j++) {
305 if (getMasterNoteIndex().get(i).getGuid().equals(noteTags.get(j).noteGuid)) {
306 tags.add(noteTags.get(j).tagGuid);
307 names.add(getTagNameByGuid(noteTags.get(j).tagGuid));
311 getMasterNoteIndex().get(i).setTagGuids(tags);
312 getMasterNoteIndex().get(i).setTagNames(names);
315 setNoteIndex(getMasterNoteIndex());
319 //***************************************************************
320 //***************************************************************
321 //* selected notebooks
322 //***************************************************************
323 //***************************************************************
324 // Return the selected notebook(s)
325 public List<String> getSelectedNotebooks() {
326 return selectedNotebooks;
328 // Set the current selected notebook(s)
329 public void setSelectedNotebooks(List <String> s) {
331 s = new ArrayList<String>();
332 selectedNotebooks = s;
336 //***************************************************************
337 //***************************************************************
338 //** These functions deal with setting & retrieving the master lists
339 //***************************************************************
340 //***************************************************************
341 // Get the note table model
342 public NoteTableModel getNoteTableModel() {
345 // save the saved search index
346 private void setSavedSearchIndex(List<SavedSearch> t) {
349 // Retrieve the Tag index
350 public List<SavedSearch> getSavedSearchIndex() {
354 // save the tag index
355 private void setTagIndex(List<Tag> t) {
358 // Retrieve the Tag index
359 public List<Tag> getTagIndex() {
362 private void setNotebookIndex(List<Notebook> t) {
365 private void setArchiveNotebookIndex(List<Notebook> t) {
366 archiveNotebookIndex = t;
368 // Retrieve the Notebook index
369 public List<Notebook> getNotebookIndex() {
370 return notebookIndex;
373 public List<LinkedNotebook> getLinkedNotebookIndex() {
374 return linkedNotebookIndex;
376 public List<Notebook> getArchiveNotebookIndex() {
377 return archiveNotebookIndex;
379 // Save the current note list
380 private void setNoteIndex(List<Note> n) {
381 noteModel.setNoteIndex(n);
382 refreshNoteMetadata();
384 public void refreshNoteMetadata() {
385 noteModel.setNoteMetadata(conn.getNoteTable().getNotesMetaInformation());
387 // Update a note's meta data
388 public void updateNoteMetadata(NoteMetadata meta) {
389 noteModel.metaData.remove(meta);
390 noteModel.metaData.put(meta.getGuid(), meta);
391 conn.getNoteTable().updateNoteMetadata(meta);
393 // Get the note index
394 public synchronized List<Note> getNoteIndex() {
395 return noteModel.getNoteIndex();
397 // Save the count of notes per notebook
398 public void setNotebookCounter(List<NotebookCounter> n) {
400 notebookSignal.refreshNotebookTreeCounts.emit(getNotebookIndex(), notebookCounter);
402 public List<NotebookCounter> getNotebookCounter() {
403 return notebookCounter;
405 // Save the count of notes for each tag
406 public void setTagCounter(List<TagCounter> n) {
408 tagSignal.refreshTagTreeCounts.emit(tagCounter);
410 public List<TagCounter> getTagCounter() {
413 public List<String> getLocalNotebooks() {
414 return localNotebookIndex;
417 // public void setUnsynchronizedNotes(List<String> l) {
418 // noteModel.setUnsynchronizedNotes(l);
420 // Return a count of items in the trash
421 public int getTrashCount() {
424 // get the EnSearch variable
425 public EnSearch getEnSearch() {
428 public List<Note> getMasterNoteIndex() {
429 return noteModel.getMasterNoteIndex();
432 // public HashMap<String, QImage> getThumbnails() {
433 // return thumbnailList;
435 public HashMap<String, NoteMetadata> getNoteMetadata() {
436 return noteModel.metaData;
438 public QImage getThumbnail(String guid) {
439 // if (getThumbnails().containsKey(guid))
440 // return getThumbnails().get(guid);
442 QImage img = new QImage();
443 img = QImage.fromData(conn.getNoteTable().getThumbnail(guid));
444 if (img == null || img.isNull())
446 //getThumbnails().put(guid, img);
449 public QPixmap getThumbnailPixmap(String guid) {
450 // if (getThumbnails().containsKey(guid))
451 // return getThumbnails().get(guid);
453 QPixmap img = new QPixmap();
454 img.loadFromData(conn.getNoteTable().getThumbnail(guid));
455 if (img == null || img.isNull())
457 //getThumbnails().put(guid, img);
460 //***************************************************************
461 //***************************************************************
462 //** These functions deal with setting & retrieving filters
463 //***************************************************************
464 //***************************************************************
465 public void setEnSearch(String t) {
466 enSearch = new EnSearch(conn,logger, t, getTagIndex(), Global.getRecognitionWeight());
467 enSearchChanged = true;
470 public void setSelectedTags(List<String> selectedTags) {
471 this.selectedTags = selectedTags;
473 // Save seleceted search
474 public void setSelectedSavedSearch(String s) {
475 this.selectedSearch = s;
478 public List<String> getSelectedTags() {
482 public String getSelectedSearch() {
483 return selectedSearch;
489 //***************************************************************
490 //***************************************************************
492 //***************************************************************
493 //***************************************************************
495 public void saveNoteTags(String noteGuid, List<String> tags, boolean isDirty) {
\r
496 logger.log(logger.HIGH, "Entering ListManager.saveNoteTags");
497 // ICHANGED 同じタグが付けられた履歴を記録(必ずdeleteNoteTagの前にやる)
498 for (int i = 0; i < tags.size(); i++) {
499 String tagName = tags.get(i);
500 for (int j = 0; j < tagIndex.size(); j++) {
501 if (tagIndex.get(j).getName().equalsIgnoreCase(tagName)) {
502 conn.getHistoryTable().addSameTagHistory(noteGuid, tagIndex.get(j).getGuid());
508 conn.getNoteTable().noteTagsTable.deleteNoteTag(noteGuid);
509 List<String> tagGuids = new ArrayList<String>();
510 boolean newTagCreated = false;
512 for (int i=0; i<tags.size(); i++) {
513 tagName = tags.get(i);
514 boolean found = false;
515 for (int j=0; j<tagIndex.size(); j++) {
516 if (tagIndex.get(j).getName().equalsIgnoreCase(tagName)) {
517 conn.getNoteTable().noteTagsTable.saveNoteTag(noteGuid, tagIndex.get(j).getGuid(), isDirty);
\r
518 tagGuids.add(tagIndex.get(j).getGuid());
524 Tag nTag = new Tag();
525 nTag.setName(tagName);
526 Calendar currentTime = new GregorianCalendar();
527 Long l = new Long(currentTime.getTimeInMillis());
529 while (l==prevTime) {
530 currentTime = new GregorianCalendar();
531 l=currentTime.getTimeInMillis();
533 String randint = new String(Long.toString(l));
535 nTag.setUpdateSequenceNum(0);
536 nTag.setGuid(randint);
537 conn.getTagTable().addTag(nTag, true);
538 getTagIndex().add(nTag);
539 conn.getNoteTable().noteTagsTable.saveNoteTag(noteGuid, nTag.getGuid(), isDirty);
\r
540 tagGuids.add(nTag.getGuid());
541 newTagCreated = true;
545 for (int i=0; i<getNoteIndex().size(); i++) {
546 if (getNoteIndex().get(i).getGuid().equals(noteGuid)) {
547 getNoteIndex().get(i).setTagNames(tags);
548 getNoteIndex().get(i).setTagGuids(tagGuids);
549 i=getNoteIndex().size()+1;
553 tagSignal.listChanged.emit();
554 logger.log(logger.HIGH, "Leaving ListManager.saveNoteTags");
557 public void deleteNote(String guid) {
558 trashCounterRunner.abortCount = true;
559 Calendar currentTime = new GregorianCalendar();
560 Long l = new Long(currentTime.getTimeInMillis());
562 while (l==prevTime) {
563 currentTime = new GregorianCalendar();
564 l=currentTime.getTimeInMillis();
567 for (int i=0; i<getMasterNoteIndex().size(); i++) {
568 if (getMasterNoteIndex().get(i).getGuid().equals(guid)) {
569 getMasterNoteIndex().get(i).setActive(false);
570 getMasterNoteIndex().get(i).setDeleted(l);
571 i=getMasterNoteIndex().size();
574 for (int i=0; i<getNoteIndex().size(); i++) {
575 if (getNoteIndex().get(i).getGuid().equals(guid)) {
576 getNoteIndex().get(i).setActive(false);
577 getNoteIndex().get(i).setDeleted(l);
578 i=getNoteIndex().size();
581 conn.getNoteTable().deleteNote(guid);
585 public void restoreNote(String guid) {
586 trashCounterRunner.abortCount = true;
587 for (int i=0; i<getMasterNoteIndex().size(); i++) {
588 if (getMasterNoteIndex().get(i).getGuid().equals(guid)) {
589 getMasterNoteIndex().get(i).setActive(true);
590 getMasterNoteIndex().get(i).setDeleted(0);
591 i=getMasterNoteIndex().size();
594 for (int i=0; i<getNoteIndex().size(); i++) {
595 if (getNoteIndex().get(i).getGuid().equals(guid)) {
596 getNoteIndex().get(i).setActive(true);
597 getNoteIndex().get(i).setDeleted(0);
598 i=getNoteIndex().size();
601 conn.getNoteTable().restoreNote(guid);
604 public void updateNote(Note n) {
606 for (int i=0; i<getMasterNoteIndex().size(); i++) {
607 if (getMasterNoteIndex().get(i).getGuid().equals(n.getGuid())) {
608 getMasterNoteIndex().remove(i);
609 getMasterNoteIndex().add(n);
612 for (int i=0; i<getNoteIndex().size(); i++) {
613 if (getNoteIndex().get(i).getGuid().equals(n.getGuid())) {
614 getNoteIndex().get(i).setActive(true);
615 getNoteIndex().get(i).setDeleted(0);
616 i=getNoteIndex().size();
619 conn.getNoteTable().updateNote(n);
622 public void addNote(Note n, NoteMetadata meta) {
623 noteModel.addNote(n, meta);
624 noteModel.metaData.put(n.getGuid(), meta);
627 public void expungeNote(String guid) {
628 trashCounterRunner.abortCount = true;
629 for (int i=0; i<getMasterNoteIndex().size(); i++) {
630 if (getMasterNoteIndex().get(i).getGuid().equals(guid)) {
631 getMasterNoteIndex().remove(i);
632 i=getMasterNoteIndex().size();
635 for (int i=0; i<getNoteIndex().size(); i++) {
636 if (getNoteIndex().get(i).getGuid().equals(guid)) {
637 getNoteIndex().remove(i);
638 i=getNoteIndex().size();
641 conn.getNoteTable().expungeNote(guid, false, true);
645 public void emptyTrash() {
646 trashCounterRunner.abortCount = true;
647 for (int i=getMasterNoteIndex().size()-1; i>=0; i--) {
648 if (!getMasterNoteIndex().get(i).isActive()) {
649 getMasterNoteIndex().remove(i);
653 for (int i=getNoteIndex().size()-1; i>=0; i--) {
654 if (!getNoteIndex().get(i).isActive()) {
655 getNoteIndex().remove(i);
659 conn.getNoteTable().expungeAllDeletedNotes();
662 // The trash counter thread has produced a result
663 @SuppressWarnings("unused")
664 private void trashSignalReceiver(Integer i) {
666 trashSignal.countChanged.emit(i);
668 // Update note contents
669 public void updateNoteContent(String guid, String content) {
670 logger.log(logger.HIGH, "Entering ListManager.updateNoteContent");
671 // EnmlConverter enml = new EnmlConverter(logger);
672 // String text = enml.convert(guid, content);
674 // Update the list tables
675 /* for (int i=0; i<masterNoteIndex.size(); i++) {
676 if (masterNoteIndex.get(i).getGuid().equals(guid)) {
677 masterNoteIndex.get(i).setContent(text);
678 i = masterNoteIndex.size();
681 // Update the list tables
682 for (int i=0; i<getNoteIndex().size(); i++) {
683 if (getNoteIndex().get(i).getGuid().equals(guid)) {
684 getNoteIndex().get(i).setContent(text);
685 i = getNoteIndex().size();
689 // Check if any new tags were encountered
690 /* if (enml.saveInvalidXML) {
691 List<String> elements = Global.invalidElements;
692 for (int i=0; i<elements.size(); i++) {
693 conn.getInvalidXMLTable().addInvalidElement(elements.get(i));
695 for (String key : Global.invalidAttributes.keySet()) {
696 ArrayList<String> attributes = Global.invalidAttributes.get(key);
697 for (int i=0; i<attributes.size(); i++) {
698 conn.getInvalidXMLTable().addInvalidAttribute(key, attributes.get(i));
703 saveRunner.addWork(guid, content);
704 // conn.getNoteTable().updateNoteContent(guid, content);
705 logger.log(logger.HIGH, "Leaving ListManager.updateNoteContent");
707 // Update a note creation date
708 public void updateNoteCreatedDate(String guid, QDateTime date) {
709 noteModel.updateNoteCreatedDate(guid, date);
710 conn.getNoteTable().updateNoteCreatedDate(guid, date);
712 // Subject date has been changed
713 public void updateNoteSubjectDate(String guid, QDateTime date) {
714 noteModel.updateNoteSubjectDate(guid, date);
715 conn.getNoteTable().updateNoteSubjectDate(guid, date);
717 // Author has changed
718 public void updateNoteAuthor(String guid, String author) {
719 noteModel.updateNoteAuthor(guid, author);
720 conn.getNoteTable().updateNoteAuthor(guid, author);
722 // Author has changed
723 public void updateNoteGeoTag(String guid, Double lon, Double lat, Double alt) {
724 for (int i=0; i<getMasterNoteIndex().size(); i++) {
725 if (getMasterNoteIndex().get(i).getGuid().equals(guid)) {
726 getMasterNoteIndex().get(i).getAttributes().setLongitude(lon);
727 getMasterNoteIndex().get(i).getAttributes().setLongitudeIsSet(true);
728 getMasterNoteIndex().get(i).getAttributes().setLatitude(lat);
729 getMasterNoteIndex().get(i).getAttributes().setLatitudeIsSet(true);
730 getMasterNoteIndex().get(i).getAttributes().setAltitude(alt);
731 getMasterNoteIndex().get(i).getAttributes().setAltitudeIsSet(true);
732 i = getMasterNoteIndex().size();
735 // Update the list tables
736 for (int i=0; i<getNoteIndex().size(); i++) {
737 if (getNoteIndex().get(i).getGuid().equals(guid)) {
738 getNoteIndex().get(i).getAttributes().setLongitude(lon);
739 getNoteIndex().get(i).getAttributes().setLongitudeIsSet(true);
740 getNoteIndex().get(i).getAttributes().setLatitude(lat);
741 getNoteIndex().get(i).getAttributes().setLatitudeIsSet(true);
742 getNoteIndex().get(i).getAttributes().setAltitude(alt);
743 getNoteIndex().get(i).getAttributes().setAltitudeIsSet(true);
744 i = getNoteIndex().size();
747 conn.getNoteTable().updateNoteGeoTags(guid, lon, lat, alt);
749 // Source URL changed
750 public void updateNoteSourceUrl(String guid, String url) {
751 noteModel.updateNoteSourceUrl(guid, url);
752 conn.getNoteTable().updateNoteSourceUrl(guid, url);
754 // Update a note last changed date
755 public void updateNoteAlteredDate(String guid, QDateTime date) {
756 noteModel.updateNoteChangedDate(guid, date);
757 conn.getNoteTable().updateNoteAlteredDate(guid, date);
759 // Update a note title
760 public void updateNoteTitle(String guid, String title) {
761 logger.log(logger.HIGH, "Entering ListManager.updateNoteTitle");
762 conn.getNoteTable().updateNoteTitle(guid, title);
763 noteModel.updateNoteTitle(guid, title);
764 logger.log(logger.HIGH, "Leaving ListManager.updateNoteTitle");
766 // Update a note's notebook
767 public void updateNoteNotebook(String guid, String notebookGuid) {
768 logger.log(logger.HIGH, "Entering ListManager.updateNoteNotebook");
769 noteModel.updateNoteNotebook(guid, notebookGuid);
770 conn.getNoteTable().updateNoteNotebook(guid, notebookGuid, true);
771 logger.log(logger.HIGH, "Leaving ListManager.updateNoteNotebook");
773 // Update a note sequence number
774 public void updateNoteSequence(String guid, int sequence) {
775 logger.log(logger.HIGH, "Entering ListManager.updateNoteSequence");
777 conn.getNoteTable().updateNoteSequence(guid, sequence);
779 for (int i=0; i<noteModel.getMasterNoteIndex().size(); i++) {
780 if (noteModel.getMasterNoteIndex().get(i).getGuid().equals(guid)) {
781 noteModel.getMasterNoteIndex().get(i).setUpdateSequenceNum(sequence);
782 i=noteModel.getMasterNoteIndex().size()+1;
786 for (int i=0; i<getNoteIndex().size(); i++) {
787 if (getNoteIndex().get(i).getGuid().equals(guid)) {
788 getNoteIndex().get(i).setUpdateSequenceNum(sequence);
789 i=getNoteIndex().size()+1;
792 logger.log(logger.HIGH, "Leaving ListManager.updateNoteSequence");
794 public void updateNoteGuid(String oldGuid, String newGuid, boolean updateDatabase) {
795 logger.log(logger.HIGH, "Entering ListManager.updateNoteGuid");
797 conn.getNoteTable().updateNoteGuid(oldGuid, newGuid);
798 noteModel.updateNoteGuid(oldGuid, newGuid);
799 logger.log(logger.HIGH, "Leaving ListManager.updateNoteGuid");
804 //************************************************************************************
805 //************************************************************************************
807 //************************************************************************************
808 //************************************************************************************
809 // Update a tag sequence number
810 public void updateTagSequence(String guid, int sequence) {
811 logger.log(logger.HIGH, "Entering ListManager.updateTagSequence");
813 conn.getTagTable().updateTagSequence(guid, sequence);
814 for (int i=0; i<tagIndex.size(); i++) {
815 if (tagIndex.get(i).getGuid().equals(guid)) {
816 getTagIndex().get(i).setUpdateSequenceNum(sequence);
820 logger.log(logger.HIGH, "Leaving ListManager.updateTagSequence");
822 // Update a tag guid number
823 public void updateTagGuid(String oldGuid, String newGuid) {
824 logger.log(logger.HIGH, "Entering ListManager.updateTagGuid");
826 conn.getTagTable().updateTagGuid(oldGuid, newGuid);
827 for (int i=0; i<tagIndex.size(); i++) {
828 if (tagIndex.get(i).getGuid().equals(oldGuid)) {
829 tagIndex.get(i).setGuid(newGuid);
833 logger.log(logger.HIGH, "Leaving ListManager.updateTagGuid");
836 // Find all children for a tag
837 public List<Tag> findAllChildren(String guid) {
838 List<Tag> tags = new ArrayList<Tag>();
839 return findAllChildrenRecursive(guid, tags);
841 public List<Tag> findAllChildrenRecursive(String guid, List<Tag> tags) {
843 // Start looping through the tags. If we find a tag which has a parent that
844 // matches guid, then we add it to the list of tags & search for its children.
845 for (int i=0; i<getTagIndex().size(); i++) {
846 if (getTagIndex().get(i).getParentGuid() != null && getTagIndex().get(i).getParentGuid().equals(guid)) {
847 tags.add(getTagIndex().get(i));
848 tags = findAllChildrenRecursive(getTagIndex().get(i).getGuid(), tags);
853 // Give a list of tags, does any of them match a child tag?
854 public boolean checkNoteForChildTags(String guid, List<String> noteTags) {
855 boolean returnValue = false;
856 List<Tag> children = findAllChildren(guid);
857 for (int i=0; i<noteTags.size(); i++) {
858 String noteTag = noteTags.get(i);
859 for (int j=0; j<children.size(); j++) {
860 if (noteTag.equals(children.get(j).getGuid()))
868 //************************************************************************************
869 //************************************************************************************
870 //** Notebook functions
871 //************************************************************************************
872 //************************************************************************************
874 public void deleteNotebook(String guid) {
875 for (int i=0; i<getNotebookIndex().size(); i++) {
876 if (getNotebookIndex().get(i).getGuid().equals(guid)) {
877 getNotebookIndex().remove(i);
878 i=getMasterNoteIndex().size();
881 conn.getNotebookTable().expungeNotebook(guid, true);
884 public void renameStack(String oldName, String newName) {
885 for (int i=0; i<getNotebookIndex().size(); i++) {
886 if (getNotebookIndex().get(i).getStack() != null &&
887 getNotebookIndex().get(i).getStack().equalsIgnoreCase(oldName)) {
888 getNotebookIndex().get(i).setStack(newName);
892 // Update a notebook sequence number
893 public void updateNotebookSequence(String guid, int sequence) {
894 logger.log(logger.HIGH, "Entering ListManager.updateNotebookSequence");
896 conn.getNotebookTable().updateNotebookSequence(guid, sequence);
898 for (int i=0; i<notebookIndex.size(); i++) {
899 if (notebookIndex.get(i).getGuid().equals(guid)) {
900 notebookIndex.get(i).setUpdateSequenceNum(sequence);
901 i=notebookIndex.size()+1;
904 logger.log(logger.HIGH, "Leaving ListManager.updateNotebookSequence");
907 // Update a notebook Guid number
908 public void updateNotebookGuid(String oldGuid, String newGuid) {
909 logger.log(logger.HIGH, "Entering ListManager.updateNotebookGuid");
911 conn.getNotebookTable().updateNotebookGuid(oldGuid, newGuid);
913 for (int i=0; i<notebookIndex.size(); i++) {
914 if (notebookIndex.get(i).getGuid().equals(oldGuid)) {
915 notebookIndex.get(i).setGuid(newGuid);
916 i=notebookIndex.size()+1;
919 logger.log(logger.HIGH, "Leaving ListManager.updateNotebookGuid");
922 // Update a notebook Guid number
923 public void updateNotebookStack(String oldGuid, String stack) {
924 logger.log(logger.HIGH, "Entering ListManager.updateNotebookGuid");
926 conn.getNotebookTable().setStack(oldGuid, stack);
928 for (int i=0; i<notebookIndex.size(); i++) {
929 if (notebookIndex.get(i).getGuid().equals(oldGuid)) {
930 notebookIndex.get(i).setStack(stack);
931 i=notebookIndex.size()+1;
934 logger.log(logger.HIGH, "Leaving ListManager.updateNotebookGuid");
939 //************************************************************************************
940 //************************************************************************************
941 //** Load and filter the note index
942 //************************************************************************************
943 //************************************************************************************
945 public void noteDownloaded(Note n) {
946 boolean found = false;
947 for (int i=0; i<getMasterNoteIndex().size(); i++) {
948 if (getMasterNoteIndex().get(i).getGuid().equals(n.getGuid())) {
949 getMasterNoteIndex().set(i,n);
951 i=getMasterNoteIndex().size();
956 getMasterNoteIndex().add(n);
958 for (int i=0; i<getNoteIndex().size(); i++) {
959 if (getNoteIndex().get(i).getGuid().equals(n.getGuid())) {
960 if (filterRecord(getNoteIndex().get(i)))
961 getNoteIndex().add(n);
962 getNoteIndex().remove(i);
963 i=getNoteIndex().size();
968 getNoteIndex().add(n);
971 // Check if a note matches the currently selected notebooks, tags, or attribute searches.
972 public boolean filterRecord(Note n) {
974 boolean goodNotebook = false;
975 boolean goodTag = false;
976 boolean goodStatus = false;
979 if (!n.isActive() && Global.showDeleted)
982 if (n.isActive() && !Global.showDeleted)
986 // Begin filtering results
988 goodNotebook = filterByNotebook(n.getNotebookGuid());
990 goodTag = filterByTag(n.getTagGuids());
992 boolean goodCreatedBefore = false;
993 boolean goodCreatedSince = false;
994 boolean goodChangedBefore = false;
995 boolean goodChangedSince = false;
996 boolean goodContains = false;
997 if (!Global.createdBeforeFilter.hasSelection())
998 goodCreatedBefore = true;
1000 goodCreatedBefore = Global.createdBeforeFilter.check(n);
1002 if (!Global.createdSinceFilter.hasSelection())
1003 goodCreatedSince = true;
1005 goodCreatedSince = Global.createdSinceFilter.check(n);
1007 if (!Global.changedBeforeFilter.hasSelection())
1008 goodChangedBefore = true;
1010 goodChangedBefore = Global.changedBeforeFilter.check(n);
1011 if (!Global.changedSinceFilter.hasSelection())
1012 goodChangedSince = true;
1014 goodChangedSince = Global.changedSinceFilter.check(n);
1015 if (!Global.containsFilter.hasSelection())
1016 goodContains = true;
1018 goodContains = Global.containsFilter.check(conn.getNoteTable(), n);
1020 if (goodCreatedSince && goodCreatedBefore && goodChangedSince && goodChangedBefore && goodContains)
1026 // Trigger a recount of counters
1027 public void refreshCounters() {
1028 // refreshCounters= false;
1029 if (!refreshCounters)
1031 refreshCounters = false;
1032 tagCounterRunner.abortCount = true;
1033 notebookCounterRunner.abortCount = true;
1034 trashCounterRunner.abortCount = true;
1035 countNotebookResults(getNoteIndex());
1036 countTagResults(getNoteIndex());
1040 // Load the note index based upon what the user wants.
1041 public void loadNotesIndex() {
1042 logger.log(logger.EXTREME, "Entering ListManager.loadNotesIndex()");
1045 if (enSearchChanged || getMasterNoteIndex() == null)
1046 matches = enSearch.matchWords();
1048 matches = getMasterNoteIndex();
1050 if (matches == null)
1051 matches = getMasterNoteIndex();
1053 setNoteIndex(new ArrayList<Note>());
1054 for (int i=0; i<matches.size(); i++) {
1055 if (filterRecord(matches.get(i)))
1056 getNoteIndex().add(matches.get(i));
1058 refreshCounters = true;
1059 enSearchChanged = false;
1060 logger.log(logger.EXTREME, "Leaving ListManager.loadNotesIndex()");
1062 public void countNotebookResults(List<Note> index) {
1063 logger.log(logger.EXTREME, "Entering ListManager.countNotebookResults()");
1064 notebookCounterRunner.abortCount = true;
1065 if (!Global.mimicEvernoteInterface)
1066 notebookCounterRunner.setNoteIndex(index);
1068 notebookCounterRunner.setNoteIndex(getMasterNoteIndex());
1069 notebookCounterRunner.release(CounterRunner.NOTEBOOK);
1070 logger.log(logger.EXTREME, "Leaving ListManager.countNotebookResults()");
1072 public void countTagResults(List<Note> index) {
1073 logger.log(logger.EXTREME, "Entering ListManager.countTagResults");
1074 trashCounterRunner.abortCount = true;
1075 if (!Global.tagBehavior().equalsIgnoreCase("DoNothing"))
1076 tagCounterRunner.setNoteIndex(index);
1078 tagCounterRunner.setNoteIndex(getMasterNoteIndex());
1079 tagCounterRunner.release(CounterRunner.TAG);
1080 logger.log(logger.EXTREME, "Leaving ListManager.countTagResults()");
1082 // Update the count of items in the trash
1083 public void reloadTrashCount() {
1084 logger.log(logger.EXTREME, "Entering ListManager.reloadTrashCount");
1085 trashCounterRunner.abortCount = true;
1086 trashCounterRunner.setNoteIndex(getMasterNoteIndex());
1087 trashCounterRunner.release(CounterRunner.TRASH);
1088 logger.log(logger.EXTREME, "Leaving ListManager.reloadTrashCount");
1091 private boolean filterByNotebook(String guid) {
1092 boolean good = false;
1093 if (selectedNotebooks.size() == 0)
1095 if (!good && selectedNotebooks.contains(guid))
1098 for (int i=0; i<getArchiveNotebookIndex().size() && good; i++) {
1099 if (guid.equals(getArchiveNotebookIndex().get(i).getGuid())) {
1106 private boolean filterByTag(List<String> noteTags) {
1107 // If either the note has no tags or there are
1108 // no selected tags, then any note is good.
1109 if (noteTags == null || selectedTags == null)
1112 // If there are no tags selected, then any note is good
1113 if (selectedTags.size() == 0)
1116 // If ALL tags must be matched, then check ALL note tags,
1117 // otherwise we match on any criteria.
1118 if (!Global.anyTagSelectionMatch()) {
1119 for (int i=0; i<selectedTags.size(); i++) {
1120 String selectedGuid = selectedTags.get(i);
1121 boolean childMatch = false;
1122 // If we should include children in the results
1123 if (Global.includeTagChildren()) {
1124 childMatch = checkNoteForChildTags(selectedGuid, noteTags);
1125 // Do we have a match with this tag or any children
1126 if (!noteTags.contains(selectedGuid)&& !childMatch)
1129 // Does this note have a matching tag
1130 if (!noteTags.contains(selectedGuid))
1136 // Any match is displayed.
1137 for (int i=0; i<selectedTags.size(); i++) {
1138 String selectedGuid = selectedTags.get(i);
1139 // If we have a simple match, then we're good
1140 if (noteTags.contains(selectedGuid))
1142 // If we have a match with one of the children tags && we should include child tags
1143 if (Global.includeTagChildren() && checkNoteForChildTags(selectedGuid, noteTags))
1150 public void setNoteSynchronized(String guid, boolean value) {
1151 getNoteTableModel().updateNoteSyncStatus(guid, value);
1154 public void updateNoteTitleColor(String guid, Integer color) {
1155 NoteMetadata meta = getNoteMetadata().get(guid);
1157 noteModel.updateNoteTitleColor(guid, color);
1158 meta.setColor(color);
1159 conn.getNoteTable().updateNoteMetadata(meta);
1162 public void loadNoteTitleColors() {
1163 noteModel.setMetaData(getNoteMetadata());
1166 //********************************************************************************
1167 //********************************************************************************
1168 //* Support signals from the index thread
1169 //********************************************************************************
1170 //********************************************************************************
1171 // Reset a flag if an index is needed
1172 public void setIndexNeeded(String guid, String type, Boolean b) {
1173 if (Global.keepRunning && type.equalsIgnoreCase("content"))
1174 conn.getNoteTable().setIndexNeeded(guid, false);
1175 if (Global.keepRunning && type.equalsIgnoreCase("resource")) {
1176 conn.getNoteTable().noteResourceTable.setIndexNeeded(guid, b);
1180 public boolean threadCheck(int id) {
1181 if (id == Global.notebookCounterThreadId)
1182 return notebookThread.isAlive();
1183 if (id == Global.tagCounterThreadId)
1184 return tagThread.isAlive();
1185 if (id == Global.trashCounterThreadId)
1186 return trashThread.isAlive();
1187 if (id == Global.saveThreadId)
1188 return saveThread.isAlive();
1194 //********************************************************************************
1195 //********************************************************************************
1196 //* Utility Functions
1197 //********************************************************************************
1198 //********************************************************************************
1199 public void compactDatabase() {
1200 conn.compactDatabase();
1201 // IndexConnection idx = new IndexConnection(logger, "nevernote-compact");
1203 // idx.dbShutdown();
1206 // Rebuild the note HTML to something usable
1207 public List<String> scanNoteForResources(Note n) {
1208 logger.log(logger.HIGH, "Entering ListManager.scanNoteForResources");
1209 logger.log(logger.EXTREME, "Note guid: " +n.getGuid());
1210 QDomDocument doc = new QDomDocument();
1211 QDomDocument.Result result = doc.setContent(n.getContent());
1212 if (!result.success) {
1213 logger.log(logger.MEDIUM, "Parse error when scanning note for resources.");
1214 logger.log(logger.MEDIUM, "Note guid: " +n.getGuid());
1218 List<String> returnArray = new ArrayList<String>();
1219 QDomNodeList anchors = doc.elementsByTagName("en-media");
1220 for (int i=0; i<anchors.length(); i++) {
1221 QDomElement enmedia = anchors.at(i).toElement();
1222 if (enmedia.hasAttribute("type")) {
1223 QDomAttr hash = enmedia.attributeNode("hash");
1224 returnArray.add(hash.value().toString());
1227 logger.log(logger.HIGH, "Leaving ListManager.scanNoteForResources");
1230 // Given a list of tags, produce a string list of tag names
1231 public String getTagNamesForNote(Note n) {
1232 StringBuffer buffer = new StringBuffer(100);
1233 Vector<String> v = new Vector<String>();
1234 List<String> guids = n.getTagGuids();
1239 for (int i=0; i<guids.size(); i++) {
1240 v.add(getTagNameByGuid(guids.get(i)));
1242 Comparator<String> comparator = Collections.reverseOrder();
1243 Collections.sort(v,comparator);
1244 Collections.reverse(v);
1246 for (int i = 0; i<v.size(); i++) {
1248 buffer.append(", ");
1249 buffer.append(v.get(i));
1252 return buffer.toString();
1254 // Get a tag name when given a tag guid
1255 public String getTagNameByGuid(String guid) {
1256 for (int i=0; i<getTagIndex().size(); i++) {
1257 String s = getTagIndex().get(i).getGuid();
1258 if (s.equals(guid)) {
1259 return getTagIndex().get(i).getName();
1264 // For a notebook guid, return the name
1265 public String getNotebookNameByGuid(String guid) {
1266 if (notebookIndex == null)
1268 for (int i=0; i<notebookIndex.size(); i++) {
1269 String s = notebookIndex.get(i).getGuid();
1270 if (s.equals(guid)) {
1271 return notebookIndex.get(i).getName();
1278 // Reload the note's tag names. This is called when a tag's name changes by
1279 // the user. It updates all notes with that tag to the new tag name.
1280 public void reloadNoteTagNames(String tagGuid, String newName) {
1282 // Set the master index
1283 for (int i=0; i<getMasterNoteIndex().size(); i++) {
1284 for (int j=0; j<getMasterNoteIndex().get(i).getTagGuids().size(); j++) {
1285 if (getMasterNoteIndex().get(i).getTagGuids().get(j).equals(tagGuid)) {
1286 getMasterNoteIndex().get(i).getTagNames().set(j, newName);
1291 // Set the current index
1292 for (int i=0; i<getNoteIndex().size(); i++) {
1293 for (int j=0; j<getNoteIndex().get(i).getTagGuids().size(); j++) {
1294 if (getNoteIndex().get(i).getTagGuids().get(j).equals(tagGuid)) {
1295 getNoteIndex().get(i).getTagNames().set(j, newName);