OSDN Git Service

NixNoteのUpgradeDbメソッドを不要部分を削除。
[neighbornote/NeighborNote.git] / src / cx / fbn / nevernote / utilities / ListManager.java
1 /*
2  * This file is part of NixNote/NeighborNote 
3  * Copyright 2009 Randy Baumgarte
4  * Copyright 2013 Yuki Takahashi
5  * 
6  * This file may be licensed under the terms of of the
7  * GNU General Public License Version 2 (the ``GPL'').
8  *
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.
13  *
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.
18  *
19 */
20
21 package cx.fbn.nevernote.utilities;
22
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;
31
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;
46
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;
61
62
63 public class ListManager  {
64
65         
66         private final ApplicationLogger logger;  
67         DatabaseConnection                              conn;
68         QSqlQuery                                               deleteWords;
69         QSqlQuery                                               insertWords;
70         
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;
76
77         private List<SavedSearch>               searchIndex;
78
79         private List<String>                    selectedNotebooks;
80         private final NoteTableModel                    noteModel;
81         
82         
83         private List<String>                    selectedTags;
84         private String                                  selectedSearch;
85         ThreadSignal                                    signals;
86         public StatusSignal                             status;
87         private final CounterRunner             notebookCounterRunner;
88         private final QThread                   notebookThread;
89         private final CounterRunner             tagCounterRunner;
90         private final QThread                   tagThread;
91         
92         private final CounterRunner             trashCounterRunner;
93         private final QThread                   trashThread;
94         public TrashSignal                              trashSignal;
95         
96         private List<NotebookCounter>   notebookCounter;                                // count of displayed notes in each notebook
97         private List<TagCounter>                tagCounter;                                             // count of displayed notes for each tag
98         
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
107     QThread                                                     saveThread;
108         
109 //    private final HashMap<String, QImage> thumbnailList;
110     
111         // Constructor
112         public ListManager(DatabaseConnection d, ApplicationLogger l) {
113                 conn = d;
114                 logger = l;
115                         
116                 conn.getTagTable().cleanupTags();
117         status = new StatusSignal();
118                 signals = new ThreadSignal();
119                 
120                 // setup index locks
121                 enSearchChanged = false;
122                 
123                 // Setup arrays
124                 noteModel = new NoteTableModel(this);
125                 selectedTags = new ArrayList<String>();
126
127                 notebookCounter = new ArrayList<NotebookCounter>();
128                 tagCounter = new ArrayList<TagCounter>();
129                 selectedNotebooks = new ArrayList<String>();
130                                 
131                 reloadIndexes();
132                 
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();
142                 
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");
151                 tagThread.start();
152                 
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");
160                 trashThread.start();
161 //              reloadTrashCount();
162                 
163                 wordMap = new HashMap<String, String>();
164                 tagSignal = new TagSignal();
165                 
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");
172                 saveThread.start();
173                 
174 //              thumbnailList = conn.getNoteTable().getThumbnails();
175 //              thumbnailList = new HashMap<String,QImage>();
176                 
177                 linkedNotebookIndex = conn.getLinkedNotebookTable().getAll();
178                 loadNoteTitleColors();
179                 refreshCounters = true;
180                 refreshCounters();
181                                 
182         }
183         
184         public void stop() {
185                 saveRunner.addWork("stop", "");
186                 tagCounterRunner.release(CounterRunner.EXIT);
187                 notebookCounterRunner.release(CounterRunner.EXIT);
188                 trashCounterRunner.release(CounterRunner.EXIT);
189                 
190                 logger.log(logger.MEDIUM, "Waiting for notebookCounterThread to stop");                         
191                 try {
192                         notebookThread.join();
193                 } catch (InterruptedException e) {
194                         e.printStackTrace();
195                 }
196                 
197                 logger.log(logger.MEDIUM, "Waiting for tagCounterThread to stop");                      
198                 try {
199                         tagThread.join();
200                 } catch (InterruptedException e) {
201                         e.printStackTrace();
202                 }
203
204                 logger.log(logger.MEDIUM, "Waiting for trashThread to stop");                   
205                 try {
206                         trashThread.join();
207                 } catch (InterruptedException e) {
208                         e.printStackTrace();
209                 }
210
211
212                 logger.log(logger.MEDIUM, "Waiting for saveThread to stop");                    
213                 try {
214                         saveThread.join(0);
215                 } catch (InterruptedException e) {
216                         e.printStackTrace();
217                 }
218
219         }
220
221         //***************************************************************
222         //***************************************************************
223         //* Refresh lists after a db sync
224         //***************************************************************
225         //***************************************************************
226         // ICHANGED
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());
233                 }
234         }
235         
236         // ICHANGED
237         public void refreshLists() {
238                 setSavedSearchIndex(conn.getSavedSearchTable().getAll());
239                 setTagIndex(conn.getTagTable().getAll());
240                 setNotebookIndex(conn.getNotebookTable().getAll());
241                 
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());
246                 
247                 noteModel.setMasterNoteIndex(conn.getNoteTable().getAllNotes());
248                 // For performance reasons, we didn't get the tags for every note individually.  We now need to 
249                 // get them
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));
258                                 }
259                         }
260                         
261                         getMasterNoteIndex().get(i).setTagGuids(tags);
262                         getMasterNoteIndex().get(i).setTagNames(names);
263                 }
264                 
265                 
266                 //setUnsynchronizedNotes(conn.getNoteTable().getUnsynchronizedGUIDs());
267                 
268                 linkedNotebookIndex = conn.getLinkedNotebookTable().getAll();
269                 
270                 enSearchChanged = true;
271         }
272
273         public void reloadTagIndex() {
274                 setTagIndex(conn.getTagTable().getAll());       
275         }
276         public void reloadIndexes() {
277                 //setUnsynchronizedNotes(conn.getNoteTable().getUnsynchronizedGUIDs());
278
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());
283                 
284                 reloadTagIndex();
285                 // Load notebooks
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");
294
295 //              if (getMasterNoteIndex() == null) { 
296                         noteModel.setMasterNoteIndex(conn.getNoteTable().getAllNotes());
297 //              }
298                 // For performance reasons, we didn't get the tags for every note individually.  We now need to 
299                 // get them
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));
308                                 }
309                         }
310                         
311                         getMasterNoteIndex().get(i).setTagGuids(tags);
312                         getMasterNoteIndex().get(i).setTagNames(names);
313                 }
314                 
315                 setNoteIndex(getMasterNoteIndex());
316
317         }
318         
319         //***************************************************************
320         //***************************************************************
321         //* selected notebooks
322         //***************************************************************
323         //***************************************************************
324         // Return the selected notebook(s)
325         public List<String> getSelectedNotebooks() {
326                 return selectedNotebooks;
327         }
328         // Set the current selected notebook(s)
329         public void setSelectedNotebooks(List <String> s) {
330                 if (s == null) 
331                         s = new ArrayList<String>();
332                 selectedNotebooks = s;
333         }
334         
335                                 
336     //***************************************************************
337     //***************************************************************
338     //** These functions deal with setting & retrieving the master lists
339     //***************************************************************
340     //***************************************************************
341         // Get the note table model
342         public NoteTableModel getNoteTableModel() {
343                 return noteModel;
344         }
345         // save the saved search index
346         private void setSavedSearchIndex(List<SavedSearch> t) {
347                 searchIndex = t;
348         }
349         // Retrieve the Tag index
350         public List<SavedSearch> getSavedSearchIndex() {
351                 return searchIndex;
352
353         }
354         // save the tag index
355         private void setTagIndex(List<Tag> t) {
356                 tagIndex = t;
357         }       
358         // Retrieve the Tag index
359         public List<Tag> getTagIndex() {
360                 return tagIndex;
361         }
362         private void setNotebookIndex(List<Notebook> t) {
363                 notebookIndex = t;
364         }
365         private void setArchiveNotebookIndex(List<Notebook> t) {
366                 archiveNotebookIndex = t;
367         }
368         // Retrieve the Notebook index
369         public List<Notebook> getNotebookIndex() {
370                 return notebookIndex;
371
372         }
373         public List<LinkedNotebook> getLinkedNotebookIndex() {
374                 return linkedNotebookIndex;
375         }
376         public List<Notebook> getArchiveNotebookIndex() {
377                 return archiveNotebookIndex;
378         }
379         // Save the current note list
380         private void setNoteIndex(List<Note> n) {
381                 noteModel.setNoteIndex(n);
382                 refreshNoteMetadata();
383         }
384         public void refreshNoteMetadata() {
385                 noteModel.setNoteMetadata(conn.getNoteTable().getNotesMetaInformation());
386         }
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);
392         }
393         // Get the note index
394         public synchronized List<Note> getNoteIndex() {
395                 return noteModel.getNoteIndex();
396         }
397         // Save the count of notes per notebook
398         public void setNotebookCounter(List<NotebookCounter> n) {
399                 notebookCounter = n;
400                 notebookSignal.refreshNotebookTreeCounts.emit(getNotebookIndex(), notebookCounter);
401         }
402         public List<NotebookCounter> getNotebookCounter() {
403                 return notebookCounter;
404         }
405         // Save the count of notes for each tag
406         public void setTagCounter(List<TagCounter> n) {
407                 tagCounter = n;
408                 tagSignal.refreshTagTreeCounts.emit(tagCounter);
409         }
410         public List<TagCounter> getTagCounter() {
411                 return tagCounter;
412         }
413         public List<String> getLocalNotebooks() {
414                 return localNotebookIndex;
415         }
416
417 //      public void setUnsynchronizedNotes(List<String> l) {
418 //              noteModel.setUnsynchronizedNotes(l);
419 //      }
420         // Return a count of items in the trash
421         public int getTrashCount() {
422                 return trashCount;
423         }
424         // get the EnSearch variable
425         public EnSearch getEnSearch() {
426                 return enSearch;
427         }
428         public List<Note> getMasterNoteIndex() {
429                 return noteModel.getMasterNoteIndex();
430         }
431         // Thumbnails
432 //      public HashMap<String, QImage> getThumbnails() {
433 //              return thumbnailList;
434 //      }
435         public HashMap<String, NoteMetadata> getNoteMetadata() {
436                 return noteModel.metaData;
437         }
438         public QImage getThumbnail(String guid) {
439 //              if (getThumbnails().containsKey(guid))
440 //                      return getThumbnails().get(guid);
441                 
442                 QImage img = new QImage();
443                 img = QImage.fromData(conn.getNoteTable().getThumbnail(guid));
444                 if (img == null || img.isNull()) 
445                         return null;
446                 //getThumbnails().put(guid, img);
447                 return img;
448         }
449         public QPixmap getThumbnailPixmap(String guid) {
450 //              if (getThumbnails().containsKey(guid))
451 //                      return getThumbnails().get(guid);
452                 
453                 QPixmap img = new QPixmap();
454                 img.loadFromData(conn.getNoteTable().getThumbnail(guid));
455                 if (img == null || img.isNull()) 
456                         return null;
457                 //getThumbnails().put(guid, img);
458                 return img;
459         }
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;
468         }
469         // Save search tags
470         public void setSelectedTags(List<String> selectedTags) {
471                 this.selectedTags = selectedTags;
472         }
473         // Save seleceted search
474         public void setSelectedSavedSearch(String s) {
475                 this.selectedSearch = s;
476         }
477         // Get search tags
478         public List<String> getSelectedTags() {
479                 return selectedTags;
480         }
481         // Get saved search
482         public String getSelectedSearch() {
483                 return selectedSearch;
484         }
485         
486         
487         
488         
489     //***************************************************************
490     //***************************************************************
491     //** Note functions
492     //***************************************************************
493     //***************************************************************
494         // Save Note Tags
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());
503                                 }
504                         }
505                 }
506                 
507                 String tagName;
508                 conn.getNoteTable().noteTagsTable.deleteNoteTag(noteGuid);
509                 List<String> tagGuids = new ArrayList<String>();
510                 boolean newTagCreated = false;
511                 
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());
519                                         j=tagIndex.size()+1;
520                                         found = true;
521                                 }
522                         }
523                         if (!found) {
524                                 Tag nTag = new Tag();
525                                 nTag.setName(tagName);
526                                 Calendar currentTime = new GregorianCalendar();
527                                 Long l = new Long(currentTime.getTimeInMillis());
528                                 long prevTime = l;
529                                 while (l==prevTime) {
530                                         currentTime = new GregorianCalendar();
531                                         l=currentTime.getTimeInMillis();
532                                 }
533                                 String randint = new String(Long.toString(l));
534                         
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;
542                         }
543                 }
544                 
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;
550                         }
551                 }
552                 if (newTagCreated)
553                         tagSignal.listChanged.emit();
554                 logger.log(logger.HIGH, "Leaving ListManager.saveNoteTags");
555         }
556         // Delete a note
557         public void deleteNote(String guid) {
558                 trashCounterRunner.abortCount = true;
559                 Calendar currentTime = new GregorianCalendar();
560                 Long l = new Long(currentTime.getTimeInMillis());
561                 long prevTime = l;
562                 while (l==prevTime) {
563                         currentTime = new GregorianCalendar();
564                         l=currentTime.getTimeInMillis();
565                 }
566                 
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();
572                         }
573                 }
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();
579                         }
580                 }
581                 conn.getNoteTable().deleteNote(guid);
582                 reloadTrashCount();
583         }
584         // Delete a note
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();
592                         }
593                 }
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();
599                         }
600                 }
601                 conn.getNoteTable().restoreNote(guid);
602                 reloadTrashCount();
603         }
604         public void updateNote(Note n) {
605                 
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);
610                         }
611                 }
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();
617                         }
618                 }
619                 conn.getNoteTable().updateNote(n);
620         }
621         // Add a note.  
622         public void addNote(Note n, NoteMetadata meta) {
623                 noteModel.addNote(n, meta);
624                 noteModel.metaData.put(n.getGuid(), meta);
625         }
626         // Expunge a note
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();
633                         }
634                 }
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();
639                         }
640                 }
641                 conn.getNoteTable().expungeNote(guid, false, true);
642                 reloadTrashCount();
643         }
644         // Expunge a note
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);
650                         }
651                 }
652                 
653                 for (int i=getNoteIndex().size()-1; i>=0; i--) {
654                         if (!getNoteIndex().get(i).isActive()) {
655                                 getNoteIndex().remove(i);
656                         } 
657                 }
658
659                 conn.getNoteTable().expungeAllDeletedNotes();
660                 reloadTrashCount();
661         }
662         // The trash counter thread has produced a result
663         @SuppressWarnings("unused")
664         private void trashSignalReceiver(Integer i) {
665                 trashCount = i;
666                 trashSignal.countChanged.emit(i);
667         }
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);
673                 
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();
679                         }
680                 }
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();
686                         }
687                 }
688 */              
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));
694                         }
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));
699                                 }
700                         }
701                 }
702 */
703                 saveRunner.addWork(guid, content);
704 //              conn.getNoteTable().updateNoteContent(guid, content);
705                 logger.log(logger.HIGH, "Leaving ListManager.updateNoteContent");
706         }
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);
711         }
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);
716         }
717         // Author has changed
718         public void updateNoteAuthor(String guid, String author) {
719                 noteModel.updateNoteAuthor(guid, author);
720                 conn.getNoteTable().updateNoteAuthor(guid, author);
721         }
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();
733                         }       
734                 }
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();
745                         }
746                 }
747                 conn.getNoteTable().updateNoteGeoTags(guid, lon, lat, alt);
748         }
749         // Source URL changed
750         public void updateNoteSourceUrl(String guid, String url) {
751                 noteModel.updateNoteSourceUrl(guid, url);
752                 conn.getNoteTable().updateNoteSourceUrl(guid, url);
753         }
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);
758         }
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");
765         }
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");
772         }
773         // Update a note sequence number
774         public void updateNoteSequence(String guid, int sequence) {
775                 logger.log(logger.HIGH, "Entering ListManager.updateNoteSequence");
776
777                 conn.getNoteTable().updateNoteSequence(guid, sequence);
778                 
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;
783                         }
784                 }
785                 
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;
790                         }
791                 }
792                 logger.log(logger.HIGH, "Leaving ListManager.updateNoteSequence");
793         }
794         public void updateNoteGuid(String oldGuid, String newGuid, boolean updateDatabase) {
795                 logger.log(logger.HIGH, "Entering ListManager.updateNoteGuid");
796                 if (updateDatabase) 
797                         conn.getNoteTable().updateNoteGuid(oldGuid, newGuid);
798                 noteModel.updateNoteGuid(oldGuid, newGuid);
799                 logger.log(logger.HIGH, "Leaving ListManager.updateNoteGuid");
800
801         }
802
803         
804         //************************************************************************************
805         //************************************************************************************
806         //**  Tag functions
807         //************************************************************************************
808         //************************************************************************************  
809         // Update a tag sequence number
810         public void updateTagSequence(String guid, int sequence) {
811                 logger.log(logger.HIGH, "Entering ListManager.updateTagSequence");
812
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);
817                                 i=tagIndex.size()+1;
818                         }
819                 }
820                 logger.log(logger.HIGH, "Leaving ListManager.updateTagSequence");
821         }
822         // Update a tag guid number
823         public void updateTagGuid(String oldGuid, String newGuid) {
824                 logger.log(logger.HIGH, "Entering ListManager.updateTagGuid");
825
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);
830                                 i=tagIndex.size()+1;
831                         }
832                 }
833                 logger.log(logger.HIGH, "Leaving ListManager.updateTagGuid");
834
835         }
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);
840         }
841         public List<Tag> findAllChildrenRecursive(String guid, List<Tag> tags) {
842                 
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);
849                         }
850                 }
851                 return tags;
852         }
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()))
861                                         return true;
862                         }
863                 }
864                 return returnValue;
865         }
866
867
868         //************************************************************************************
869         //************************************************************************************
870         //**  Notebook functions
871         //************************************************************************************
872         //************************************************************************************  
873         // Delete a notebook
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();
879                         }
880                 }
881                 conn.getNotebookTable().expungeNotebook(guid, true);            
882         }
883         // Rename a stack
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);
889                         }
890                 }       
891         }
892         // Update a notebook sequence number
893         public void updateNotebookSequence(String guid, int sequence) {
894                 logger.log(logger.HIGH, "Entering ListManager.updateNotebookSequence");
895
896                 conn.getNotebookTable().updateNotebookSequence(guid, sequence);
897                 
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;
902                         }
903                 }
904                 logger.log(logger.HIGH, "Leaving ListManager.updateNotebookSequence");
905
906         }
907         // Update a notebook Guid number
908         public void updateNotebookGuid(String oldGuid, String newGuid) {
909                 logger.log(logger.HIGH, "Entering ListManager.updateNotebookGuid");
910
911                 conn.getNotebookTable().updateNotebookGuid(oldGuid, newGuid);
912                 
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;
917                         }
918                 }
919                 logger.log(logger.HIGH, "Leaving ListManager.updateNotebookGuid");
920
921         }
922         // Update a notebook Guid number
923         public void updateNotebookStack(String oldGuid, String stack) {
924                 logger.log(logger.HIGH, "Entering ListManager.updateNotebookGuid");
925
926                 conn.getNotebookTable().setStack(oldGuid, stack);
927                 
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;
932                         }
933                 }
934                 logger.log(logger.HIGH, "Leaving ListManager.updateNotebookGuid");
935
936         }
937         
938         
939         //************************************************************************************
940         //************************************************************************************
941         //**  Load and filter the note index
942         //************************************************************************************
943         //************************************************************************************
944         
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);
950                                 found = true;
951                                 i=getMasterNoteIndex().size();
952                         }
953                 }
954                 
955                 if (!found)
956                         getMasterNoteIndex().add(n);
957                 
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();
964                         }
965                 }
966                 
967                 if (filterRecord(n))
968                         getNoteIndex().add(n);
969                 
970         }
971         // Check if a note matches the currently selected notebooks, tags, or attribute searches.
972         public boolean filterRecord(Note n) {
973                                 
974                 boolean goodNotebook = false;
975                 boolean goodTag = false;
976                 boolean goodStatus = false;
977                         
978                 // Check note status
979                 if (!n.isActive() && Global.showDeleted)
980                         return true;
981                 else {
982                         if (n.isActive() && !Global.showDeleted)
983                                 goodStatus = true;
984                 }
985                 
986                 // Begin filtering results
987                 if (goodStatus)
988                         goodNotebook = filterByNotebook(n.getNotebookGuid());
989                 if (goodNotebook) 
990                         goodTag = filterByTag(n.getTagGuids());
991                 if (goodTag) {
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;
999                         else
1000                                 goodCreatedBefore = Global.createdBeforeFilter.check(n);
1001                                 
1002                         if (!Global.createdSinceFilter.hasSelection())
1003                                 goodCreatedSince = true;
1004                         else
1005                                 goodCreatedSince = Global.createdSinceFilter.check(n);
1006                                 
1007                         if (!Global.changedBeforeFilter.hasSelection())
1008                                 goodChangedBefore = true;
1009                         else
1010                                 goodChangedBefore = Global.changedBeforeFilter.check(n);
1011                                 if (!Global.changedSinceFilter.hasSelection())
1012                                 goodChangedSince = true;
1013                         else
1014                                 goodChangedSince = Global.changedSinceFilter.check(n);
1015                         if (!Global.containsFilter.hasSelection())
1016                                 goodContains = true;
1017                         else
1018                                 goodContains = Global.containsFilter.check(conn.getNoteTable(), n);
1019                                 
1020                         if (goodCreatedSince && goodCreatedBefore && goodChangedSince && goodChangedBefore && goodContains)
1021                                 return true;
1022                 }       
1023                 return false;
1024         }
1025         
1026         // Trigger a recount of counters
1027         public void refreshCounters() {
1028 //              refreshCounters= false;
1029                 if (!refreshCounters)
1030                         return;
1031                 refreshCounters = false;
1032                 tagCounterRunner.abortCount = true;
1033                 notebookCounterRunner.abortCount = true;
1034                 trashCounterRunner.abortCount = true;
1035                 countNotebookResults(getNoteIndex());
1036                 countTagResults(getNoteIndex());
1037                 reloadTrashCount();
1038
1039         }
1040         // Load the note index based upon what the user wants.
1041         public void loadNotesIndex() {
1042                 logger.log(logger.EXTREME, "Entering ListManager.loadNotesIndex()");
1043                 
1044                 List<Note> matches;
1045                 if (enSearchChanged || getMasterNoteIndex() == null)
1046                         matches = enSearch.matchWords();
1047                 else
1048                         matches = getMasterNoteIndex();
1049                 
1050                 if (matches == null)
1051                         matches = getMasterNoteIndex();
1052                 
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));
1057                 }
1058                 refreshCounters = true;
1059                 enSearchChanged = false;
1060                 logger.log(logger.EXTREME, "Leaving ListManager.loadNotesIndex()");
1061         }
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);
1067                 else 
1068                         notebookCounterRunner.setNoteIndex(getMasterNoteIndex());
1069                 notebookCounterRunner.release(CounterRunner.NOTEBOOK);
1070                 logger.log(logger.EXTREME, "Leaving ListManager.countNotebookResults()");
1071         }
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);
1077                 else
1078                         tagCounterRunner.setNoteIndex(getMasterNoteIndex());
1079                 tagCounterRunner.release(CounterRunner.TAG);
1080                 logger.log(logger.EXTREME, "Leaving ListManager.countTagResults()");
1081         }
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");
1089         }       
1090         
1091         private boolean filterByNotebook(String guid) {
1092                 boolean good = false;
1093                 if (selectedNotebooks.size() == 0)
1094                         good = true;
1095                 if (!good && selectedNotebooks.contains(guid)) 
1096                         good = true;
1097
1098                 for (int i=0; i<getArchiveNotebookIndex().size() && good; i++) {
1099                         if (guid.equals(getArchiveNotebookIndex().get(i).getGuid())) {
1100                                 good = false;
1101                                 return good;
1102                         }
1103                 }
1104                 return good;
1105         }
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)
1110                         return true;
1111                 
1112                 // If there are no tags selected, then any note  is good
1113                 if (selectedTags.size() == 0) 
1114                         return true;
1115                 
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)
1127                                                 return false;
1128                                 } else {
1129                                         // Does this note have a matching tag
1130                                         if (!noteTags.contains(selectedGuid))
1131                                                 return false;
1132                                 }
1133                         }
1134                         return true;
1135                 } else {
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))
1141                                                 return true;
1142                                 // If we have a match with one of the children tags && we should include child tags
1143                                 if (Global.includeTagChildren() && checkNoteForChildTags(selectedGuid, noteTags))
1144                                         return true;
1145                         }
1146                         return false;
1147                 }
1148         }
1149
1150         public void setNoteSynchronized(String guid, boolean value) {
1151                 getNoteTableModel().updateNoteSyncStatus(guid, value);
1152         }
1153         
1154         public void updateNoteTitleColor(String guid, Integer color) {
1155                 NoteMetadata meta = getNoteMetadata().get(guid);
1156                 if (meta != null) {
1157                         noteModel.updateNoteTitleColor(guid, color);
1158                         meta.setColor(color);
1159                         conn.getNoteTable().updateNoteMetadata(meta);
1160                 }
1161         }
1162         public void loadNoteTitleColors() {
1163                 noteModel.setMetaData(getNoteMetadata());
1164         }
1165         
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);
1177                 }
1178         }
1179         
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();
1189                 return false;
1190         }
1191         
1192         
1193         
1194         //********************************************************************************
1195         //********************************************************************************
1196         //* Utility Functions
1197         //********************************************************************************
1198         //********************************************************************************
1199         public void compactDatabase() {
1200                 conn.compactDatabase();
1201 //              IndexConnection idx = new IndexConnection(logger, "nevernote-compact");
1202 //              idx.dbSetup();
1203 //              idx.dbShutdown();
1204         }
1205
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());
1215                         return null;
1216                 }
1217                                 
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());
1225                         }
1226                 }
1227                 logger.log(logger.HIGH, "Leaving ListManager.scanNoteForResources");
1228                 return returnArray;
1229         }
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();
1235                 
1236                 if (guids == null) 
1237                         return "";
1238                 
1239                 for (int i=0; i<guids.size(); i++) {
1240                         v.add(getTagNameByGuid(guids.get(i)));
1241                 }
1242                 Comparator<String> comparator = Collections.reverseOrder();
1243                 Collections.sort(v,comparator);
1244                 Collections.reverse(v);
1245                 
1246                 for (int i = 0; i<v.size(); i++) {
1247                         if (i>0) 
1248                                 buffer.append(", ");
1249                         buffer.append(v.get(i));
1250                 }
1251                 
1252                 return buffer.toString();
1253         }
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();
1260                         }
1261                 }
1262                 return "";
1263         }
1264         // For a notebook guid, return the name
1265         public String getNotebookNameByGuid(String guid) {
1266                 if (notebookIndex == null)
1267                         return 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();
1272                         }
1273                 }
1274                 return "";
1275         }
1276         
1277         
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) {
1281                 
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);
1287                                 }
1288                         }
1289                 }
1290                 
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);
1296                                 }
1297                         }
1298                 }
1299         }
1300         
1301 }