OSDN Git Service

Move index scanning to separate thread to increase performance.
[neighbornote/NeighborNote.git] / src / cx / fbn / nevernote / threads / IndexRunner.java
1 /*\r
2  * This file is part of NeverNote \r
3  * Copyright 2009 Randy Baumgarte\r
4  * \r
5  * This file may be licensed under the terms of of the\r
6  * GNU General Public License Version 2 (the ``GPL'').\r
7  *\r
8  * Software distributed under the License is distributed\r
9  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
10  * express or implied. See the GPL for the specific language\r
11  * governing rights and limitations.\r
12  *\r
13  * You should have received a copy of the GPL along with this\r
14  * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
15  * or write to the Free Software Foundation, Inc.,\r
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
17  *\r
18 */\r
19 \r
20 package cx.fbn.nevernote.threads;\r
21 \r
22 import java.io.ByteArrayInputStream;\r
23 import java.io.ByteArrayOutputStream;\r
24 import java.io.File;\r
25 import java.io.FileInputStream;\r
26 import java.io.FileNotFoundException;\r
27 import java.io.IOException;\r
28 import java.io.InputStream;\r
29 import java.util.List;\r
30 import java.util.concurrent.LinkedBlockingQueue;\r
31 \r
32 import org.apache.commons.lang.StringEscapeUtils;\r
33 import org.apache.tika.exception.TikaException;\r
34 import org.apache.tika.metadata.Metadata;\r
35 import org.apache.tika.parser.ParseContext;\r
36 import org.apache.tika.parser.microsoft.OfficeParser;\r
37 import org.apache.tika.parser.microsoft.ooxml.OOXMLParser;\r
38 import org.apache.tika.parser.odf.OpenDocumentParser;\r
39 import org.apache.tika.parser.pdf.PDFParser;\r
40 import org.apache.tika.parser.rtf.RTFParser;\r
41 import org.apache.tika.sax.BodyContentHandler;\r
42 import org.w3c.tidy.Tidy;\r
43 import org.xml.sax.ContentHandler;\r
44 import org.xml.sax.SAXException;\r
45 \r
46 import com.evernote.edam.type.Data;\r
47 import com.evernote.edam.type.Note;\r
48 import com.evernote.edam.type.Resource;\r
49 import com.trolltech.qt.core.QByteArray;\r
50 import com.trolltech.qt.core.QIODevice.OpenModeFlag;\r
51 import com.trolltech.qt.core.QObject;\r
52 import com.trolltech.qt.core.QTemporaryFile;\r
53 import com.trolltech.qt.xml.QDomDocument;\r
54 import com.trolltech.qt.xml.QDomElement;\r
55 import com.trolltech.qt.xml.QDomNodeList;\r
56 \r
57 import cx.fbn.nevernote.Global;\r
58 import cx.fbn.nevernote.signals.IndexSignal;\r
59 import cx.fbn.nevernote.signals.NoteResourceSignal;\r
60 import cx.fbn.nevernote.signals.NoteSignal;\r
61 import cx.fbn.nevernote.sql.DatabaseConnection;\r
62 import cx.fbn.nevernote.utilities.ApplicationLogger;\r
63 \r
64 public class IndexRunner extends QObject implements Runnable {\r
65         \r
66         private final ApplicationLogger         logger;\r
67         private String                                          guid;\r
68         private QByteArray                                      resourceBinary;\r
69         public volatile NoteSignal                      noteSignal;\r
70         public volatile NoteResourceSignal      resourceSignal;\r
71         private int                                                     indexType;\r
72         public final int                                        SCAN=1; \r
73         public final int                                        REINDEXALL=2;\r
74         public final int                                        REINDEXNOTE=3;\r
75         public boolean                                          keepRunning;\r
76         private final QDomDocument                      doc;\r
77         private static String                           regex = Global.getWordRegex();\r
78         private final DatabaseConnection        conn;\r
79         private volatile LinkedBlockingQueue<String> workQueue;\r
80         private static int MAX_QUEUED_WAITING = 1000;\r
81         public boolean interrupt;\r
82         public boolean idle;\r
83         public volatile IndexSignal                     signal;\r
84 \r
85         \r
86         public IndexRunner(String logname, String u, String uid, String pswd, String cpswd) {\r
87                 logger = new ApplicationLogger(logname);\r
88                 conn = new DatabaseConnection(logger, u, uid, pswd, cpswd);\r
89                 indexType = SCAN;\r
90                 guid = null;\r
91                 keepRunning = true;\r
92                 doc = new QDomDocument();\r
93                 workQueue=new LinkedBlockingQueue<String>(MAX_QUEUED_WAITING);  \r
94         }\r
95         \r
96         public void setIndexType(int t) {\r
97                 indexType = t;\r
98         }\r
99         \r
100         \r
101         @Override\r
102         public void run() {\r
103                 thread().setPriority(Thread.MIN_PRIORITY);\r
104                 noteSignal = new NoteSignal();\r
105                 resourceSignal = new NoteResourceSignal();\r
106                 signal = new IndexSignal();\r
107                 logger.log(logger.EXTREME, "Starting index thread ");\r
108                 while (keepRunning) {\r
109                         idle=true;\r
110                         try {\r
111                                 String work = workQueue.take();\r
112                                 idle=false;\r
113                                 if (work.startsWith("SCAN")) {\r
114                                         guid=null;\r
115                                         interrupt = false;\r
116                                         indexType = SCAN;\r
117                                 }\r
118                                 if (work.startsWith("REINDEXALL")) {\r
119                                         guid = null;\r
120                                         indexType=REINDEXALL;\r
121                                 }\r
122                                 if (work.startsWith("REINDEXNOTE")) {\r
123                                         work = work.replace("REINDEXNOTE ", "");\r
124                                         guid = work;\r
125                                         indexType = REINDEXNOTE;\r
126                                 }\r
127                                 if (work.startsWith("STOP")) {\r
128                                         keepRunning = false;\r
129                                         guid = null;\r
130                                 }\r
131                                 logger.log(logger.EXTREME, "Type:" +indexType);\r
132                                 if (indexType == SCAN && keepRunning) {\r
133                                         logger.log(logger.MEDIUM, "Scanning for unindexed notes & resources");\r
134                                         scanUnindexed();\r
135                                         setIndexType(0);\r
136                                 }\r
137                                 if (indexType == REINDEXALL && keepRunning) {\r
138                                         logger.log(logger.MEDIUM, "Marking all for reindex");\r
139                                         reindexAll();\r
140                                         setIndexType(0);\r
141                                 }\r
142                                 if (indexType == REINDEXNOTE && keepRunning) {\r
143                                         reindexNote();\r
144                                 }\r
145                         } catch (InterruptedException e) {\r
146                                 // TODO Auto-generated catch block\r
147                                 e.printStackTrace();\r
148                         }\r
149                 }\r
150                 conn.dbShutdown();\r
151         }\r
152         \r
153         // Reindex a note\r
154         public void indexNoteContent() {\r
155                 \r
156 //              if (wordMap.size() > 0)\r
157 //                      wordMap.clear();\r
158                 logger.log(logger.EXTREME, "Entering indexRunner.indexNoteContent()");\r
159                 \r
160                 logger.log(logger.EXTREME, "Getting note content");\r
161                 Note n = conn.getNoteTable().getNote(guid,true,false,true,true, true);\r
162                 String data = n.getContent();\r
163                 \r
164                 logger.log(logger.EXTREME, "Removing any encrypted data");\r
165                 data = removeEnCrypt(data);\r
166                 logger.log(logger.EXTREME, "Removing xml markups");\r
167                 Tidy tidy = new Tidy();\r
168                 tidy.getStderr().close();  // the listener will capture messages\r
169                 tidy.setXmlTags(true);\r
170                 byte html[] = data.getBytes();\r
171                 ByteArrayInputStream is = new ByteArrayInputStream(html);\r
172                 ByteArrayOutputStream os = new ByteArrayOutputStream();\r
173                 tidy.parse(is, os);\r
174                 String text =  StringEscapeUtils.unescapeHtml(os.toString().replaceAll("\\<.*?\\>", "")) +" "+\r
175                 n.getTitle();\r
176                                 \r
177                 logger.log(logger.EXTREME, "Splitting words");\r
178                 String[] result = text.toString().split(regex);\r
179                 logger.log(logger.EXTREME, "Deleting existing words for note from index");\r
180                 conn.getWordsTable().expungeFromWordIndex(guid, "CONTENT");\r
181                 \r
182                 logger.log(logger.EXTREME, "Number of words found: " +result.length);\r
183                 for (int j=0; j<result.length && keepRunning; j++) {\r
184                         logger.log(logger.EXTREME, "Result word: " +result[j]);\r
185                         addToIndex(guid, result[j], "CONTENT");\r
186                 }\r
187                 // If we were interrupted, we will reindex this note next time\r
188                 if (Global.keepRunning) {\r
189                         logger.log(logger.EXTREME, "Resetting note guid needed");\r
190                         conn.getNoteTable().setIndexNeeded(guid, false);\r
191                 }\r
192                 logger.log(logger.EXTREME, "Leaving indexRunner.indexNoteContent()");\r
193         }\r
194 \r
195         \r
196         public synchronized boolean addWork(String request) {\r
197                 if (workQueue.size() == 0) {\r
198                         workQueue.offer(request);\r
199                         return true;\r
200                 }\r
201                 return false;\r
202         }\r
203         \r
204         public synchronized int getWorkQueueSize() {\r
205                 return workQueue.size();\r
206         }\r
207         \r
208         public void indexResource() {\r
209                 \r
210                 if (guid == null)\r
211                         return;\r
212                 \r
213                 Resource r = conn.getNoteTable().noteResourceTable.getNoteResourceRecognition(guid);\r
214                 if (r == null || r.getRecognition() == null || r.getRecognition().getBody() == null || r.getRecognition().getBody().length == 0) \r
215                         resourceBinary = new QByteArray(" ");\r
216                 else\r
217                         resourceBinary = new QByteArray(r.getRecognition().getBody());\r
218                 \r
219                 conn.getWordsTable().expungeFromWordIndex(r.getNoteGuid(), "RESOURCE");\r
220                 // This is due to an old bug & can be removed at some point in the future 11/23/2010\r
221                 conn.getWordsTable().expungeFromWordIndex(guid, "RESOURCE");   \r
222                         \r
223                 doc.setContent(resourceBinary);\r
224                 QDomElement docElem = doc.documentElement();\r
225                         \r
226                 // look for text tags\r
227                 QDomNodeList anchors = docElem.elementsByTagName("t");\r
228                 for (int i=0; i<anchors.length() && keepRunning; i++) {\r
229                         QDomElement enmedia = anchors.at(i).toElement();\r
230                         String weight = new String(enmedia.attribute("w"));\r
231                         String text = new String(enmedia.text()).toLowerCase();\r
232                         if (!text.equals("")) {\r
233                                 conn.getWordsTable().addWordToNoteIndex(r.getNoteGuid(), text, "RESOURCE", new Integer(weight));\r
234                         }\r
235                 }\r
236                 \r
237                 if (Global.keepRunning) {\r
238                         indexResourceContent(guid);\r
239                 }\r
240                 \r
241                 if (Global.keepRunning)\r
242                         conn.getNoteTable().noteResourceTable.setIndexNeeded(guid,false);\r
243         }\r
244         \r
245         private void indexResourceContent(String guid) {\r
246                 Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);\r
247                 if (r.getMime().equalsIgnoreCase("application/pdf")) {\r
248                         indexResourcePDF(r);\r
249                         return;\r
250                 }\r
251                 if (r.getMime().equalsIgnoreCase("application/docx") || \r
252                         r.getMime().equalsIgnoreCase("application/xlsx") || \r
253                         r.getMime().equalsIgnoreCase("application/pptx")) {\r
254                         indexResourceOOXML(r);\r
255                         return;\r
256                 }\r
257                 if (r.getMime().equalsIgnoreCase("application/vsd") ||\r
258                         r.getMime().equalsIgnoreCase("application/ppt") ||\r
259                         r.getMime().equalsIgnoreCase("application/xls") ||\r
260                         r.getMime().equalsIgnoreCase("application/msg") ||\r
261                         r.getMime().equalsIgnoreCase("application/doc")) {\r
262                                 indexResourceOffice(r);\r
263                                 return;\r
264                 }\r
265                 if (r.getMime().equalsIgnoreCase("application/rtf")) {\r
266                                         indexResourceRTF(r);\r
267                                         return;\r
268                 }\r
269                 if (r.getMime().equalsIgnoreCase("application/odf") ||\r
270                         r.getMime().equalsIgnoreCase("application/odt") ||\r
271                         r.getMime().equalsIgnoreCase("application/odp") ||\r
272                         r.getMime().equalsIgnoreCase("application/odg") ||\r
273                         r.getMime().equalsIgnoreCase("application/odb") ||\r
274                         r.getMime().equalsIgnoreCase("application/ods")) {\r
275                         indexResourceODF(r);\r
276                         return;\r
277                 }\r
278         }\r
279 \r
280 \r
281         private void indexResourceRTF(Resource r) {\r
282 \r
283                 QTemporaryFile f = writeResource(r.getData());\r
284                 if (!keepRunning) {\r
285                         return;\r
286                 }\r
287                 \r
288                 InputStream input;\r
289                 try {\r
290                         input = new FileInputStream(new File(f.fileName()));\r
291                         ContentHandler textHandler = new BodyContentHandler(-1);\r
292                         Metadata metadata = new Metadata();\r
293                         RTFParser parser = new RTFParser();     \r
294                         ParseContext context = new ParseContext();\r
295                         parser.parse(input, textHandler, metadata, context);\r
296                         String[] result = textHandler.toString().split(regex);\r
297                         for (int i=0; i<result.length && keepRunning; i++) {\r
298                                 addToIndex(r.getNoteGuid(), result[i], "RESOURCE");\r
299                         }\r
300                         input.close();\r
301                 \r
302                         f.close();\r
303                 } catch (java.lang.ClassCastException e) {\r
304                         logger.log(logger.LOW, "Cast exception: " +e.getMessage());\r
305                 } catch (FileNotFoundException e) {\r
306                         // TODO Auto-generated catch block\r
307                         e.printStackTrace();\r
308                 } catch (IOException e) {\r
309                         // TODO Auto-generated catch block\r
310                         e.printStackTrace();\r
311                 } catch (SAXException e) {\r
312                         // TODO Auto-generated catch block\r
313                         e.printStackTrace();\r
314                 } catch (TikaException e) {\r
315                         // TODO Auto-generated catch block\r
316                         e.printStackTrace();\r
317                 } catch (Exception e) {\r
318                         e.printStackTrace();\r
319                 }\r
320         }\r
321 \r
322         \r
323         private void indexResourceODF(Resource r) {\r
324 \r
325                 QTemporaryFile f = writeResource(r.getData());\r
326                 if (!keepRunning) {\r
327                         return;\r
328                 }\r
329                 \r
330                 InputStream input;\r
331                 try {\r
332                         input = new FileInputStream(new File(f.fileName()));\r
333                         ContentHandler textHandler = new BodyContentHandler(-1);\r
334                         Metadata metadata = new Metadata();\r
335                         OpenDocumentParser parser = new OpenDocumentParser();   \r
336                         ParseContext context = new ParseContext();\r
337                         parser.parse(input, textHandler, metadata, context);\r
338                         String[] result = textHandler.toString().split(regex);\r
339                         for (int i=0; i<result.length && keepRunning; i++) {\r
340                                 addToIndex(r.getNoteGuid(), result[i], "RESOURCE");\r
341                         }\r
342                         input.close();\r
343                 \r
344                         f.close();\r
345                 } catch (java.lang.ClassCastException e) {\r
346                         logger.log(logger.LOW, "Cast exception: " +e.getMessage());\r
347                 } catch (FileNotFoundException e) {\r
348                         // TODO Auto-generated catch block\r
349                         e.printStackTrace();\r
350                 } catch (IOException e) {\r
351                         // TODO Auto-generated catch block\r
352                         e.printStackTrace();\r
353                 } catch (SAXException e) {\r
354                         // TODO Auto-generated catch block\r
355                         e.printStackTrace();\r
356                 } catch (TikaException e) {\r
357                         // TODO Auto-generated catch block\r
358                         e.printStackTrace();\r
359                 } catch (Exception e) {\r
360                         e.printStackTrace();\r
361                 }\r
362         }\r
363 \r
364         \r
365         private void indexResourceOffice(Resource r) {\r
366 \r
367                 QTemporaryFile f = writeResource(r.getData());\r
368                 if (!keepRunning) {\r
369                         return;\r
370                 }\r
371                 \r
372                 InputStream input;\r
373                 try {\r
374                         input = new FileInputStream(new File(f.fileName()));\r
375                         ContentHandler textHandler = new BodyContentHandler(-1);\r
376                         Metadata metadata = new Metadata();\r
377                         OfficeParser parser = new OfficeParser();       \r
378                         ParseContext context = new ParseContext();\r
379                         parser.parse(input, textHandler, metadata, context);\r
380                         String[] result = textHandler.toString().split(regex);\r
381                         for (int i=0; i<result.length && keepRunning; i++) {\r
382                                 addToIndex(r.getNoteGuid(), result[i], "RESOURCE");\r
383                         }\r
384                         input.close();\r
385                 \r
386                         f.close();\r
387                 } catch (java.lang.ClassCastException e) {\r
388                         logger.log(logger.LOW, "Cast exception: " +e.getMessage());\r
389                 } catch (FileNotFoundException e) {\r
390                         // TODO Auto-generated catch block\r
391                         e.printStackTrace();\r
392                 } catch (IOException e) {\r
393                         // TODO Auto-generated catch block\r
394                         e.printStackTrace();\r
395                 } catch (SAXException e) {\r
396                         // TODO Auto-generated catch block\r
397                         e.printStackTrace();\r
398                 } catch (TikaException e) {\r
399                         // TODO Auto-generated catch block\r
400                         e.printStackTrace();\r
401                 } catch (Exception e) {\r
402                         e.printStackTrace();\r
403                 }\r
404         }\r
405 \r
406         \r
407         \r
408         private void indexResourcePDF(Resource r) {\r
409 \r
410                 QTemporaryFile f = writeResource(r.getData());\r
411                 if (!keepRunning) {\r
412                         return;\r
413                 }\r
414                 \r
415                 InputStream input;\r
416                 try {                   \r
417                         input = new FileInputStream(new File(f.fileName()));\r
418                         ContentHandler textHandler = new BodyContentHandler(-1);\r
419                         Metadata metadata = new Metadata();\r
420                         PDFParser parser = new PDFParser();     \r
421                         ParseContext context = new ParseContext();\r
422                         parser.parse(input, textHandler, metadata, context);\r
423                         String[] result = textHandler.toString().split(regex);\r
424                         for (int i=0; i<result.length && keepRunning; i++) {\r
425                                 addToIndex(r.getNoteGuid(), result[i], "RESOURCE");\r
426                         }\r
427                         input.close();\r
428                 \r
429                         f.close();\r
430                 } catch (java.lang.ClassCastException e) {\r
431                         logger.log(logger.LOW, "Cast exception: " +e.getMessage());\r
432                 } catch (FileNotFoundException e) {\r
433                         e.printStackTrace();\r
434                 } catch (IOException e) {\r
435                         e.printStackTrace();\r
436                 } catch (SAXException e) {\r
437                         e.printStackTrace();\r
438                 } catch (TikaException e) {\r
439                         e.printStackTrace();\r
440                 } catch (Exception e) {\r
441                         e.printStackTrace();\r
442                 }\r
443         }\r
444         \r
445         \r
446         private void indexResourceOOXML(Resource r) {\r
447 \r
448                 QTemporaryFile f = writeResource(r.getData());\r
449                 if (!keepRunning) {\r
450                         return;\r
451                 }\r
452                 \r
453                 InputStream input;\r
454                 try {\r
455                         input = new FileInputStream(new File(f.fileName()));\r
456                         ContentHandler textHandler = new BodyContentHandler(-1);\r
457                         Metadata metadata = new Metadata();\r
458                         OOXMLParser parser = new OOXMLParser(); \r
459                         ParseContext context = new ParseContext();\r
460                         parser.parse(input, textHandler, metadata, context);\r
461                         String[] result = textHandler.toString().split(regex);\r
462                         for (int i=0; i<result.length && keepRunning; i++) {\r
463                                 addToIndex(r.getNoteGuid(), result[i], "RESOURCE");\r
464                         }\r
465                         input.close();\r
466                 \r
467                         f.close();\r
468                 } catch (java.lang.ClassCastException e) {\r
469                         logger.log(logger.LOW, "Cast exception: " +e.getMessage());\r
470                 } catch (FileNotFoundException e) {\r
471                         // TODO Auto-generated catch block\r
472                         e.printStackTrace();\r
473                 } catch (IOException e) {\r
474                         // TODO Auto-generated catch block\r
475                         e.printStackTrace();\r
476                 } catch (SAXException e) {\r
477                         // TODO Auto-generated catch block\r
478                         e.printStackTrace();\r
479                 } catch (TikaException e) {\r
480                         // TODO Auto-generated catch block\r
481                         e.printStackTrace();\r
482                 } catch (Exception e) {\r
483                         e.printStackTrace();\r
484                 }\r
485         }\r
486         \r
487 \r
488         \r
489         private QTemporaryFile writeResource(Data d) {\r
490                 QTemporaryFile newFile = new QTemporaryFile();\r
491                 newFile.open(OpenModeFlag.WriteOnly);\r
492                 newFile.write(d.getBody());\r
493                 newFile.close();\r
494                 return newFile;\r
495         }\r
496 \r
497         \r
498         private String removeEnCrypt(String content) {\r
499                 int index = content.indexOf("<en-crypt");\r
500                 int endPos;\r
501                 boolean tagFound = true;\r
502                 while (tagFound && keepRunning) {\r
503                         endPos = content.indexOf("</en-crypt>", index)+11;\r
504                         if (endPos > -1 && index > -1) {\r
505                                 content = content.substring(0,index)+content.substring(endPos);\r
506                                 index = content.indexOf("<en-crypt");\r
507                         } else {\r
508                                 tagFound = false;\r
509                         }\r
510                 }\r
511                 return content;\r
512         }\r
513 \r
514         \r
515         private void addToIndex(String guid, String word, String type) {\r
516                 if (word.length() > 0) {\r
517                         // We have a good word, now let's trim off junk at the beginning or end\r
518                         StringBuffer buffer = new StringBuffer(word.toLowerCase());\r
519                         for (int x = buffer.length()-1; x>=0; x--) {\r
520                                 if (!Character.isLetterOrDigit(buffer.charAt(x)))\r
521                                         buffer = buffer.deleteCharAt(x);\r
522                                 else\r
523                                         x=-1;\r
524                         }\r
525                         // Things have been trimmed off the end, so reverse the string & repeat.\r
526                         buffer = buffer.reverse();\r
527                         for (int x = buffer.length()-1; x>=0 && keepRunning; x--) {\r
528                                 if (!Character.isLetterOrDigit(buffer.charAt(x)))\r
529                                         buffer = buffer.deleteCharAt(x);\r
530                                 else\r
531                                         x=-1;\r
532                         }\r
533                         // Restore the string back to the proper order.\r
534                         buffer = buffer.reverse();\r
535                 \r
536                         if (buffer.length()>=Global.minimumWordCount) {\r
537                                 conn.getWordsTable().addWordToNoteIndex(guid, buffer.toString(), type, 100);\r
538                         }\r
539                 }\r
540                 return;\r
541         }\r
542         \r
543         private void scanUnindexed() {\r
544                 List<String> notes = conn.getNoteTable().getUnindexed();\r
545                 guid = null;\r
546                 boolean started = false;\r
547                 if (notes.size() > 0) {\r
548                         signal.indexStarted.emit();\r
549                         started = true;\r
550                 }\r
551                 for (int i=0; i<notes.size() && !interrupt && keepRunning; i++) {\r
552                         guid = notes.get(i);\r
553                         if (guid != null && keepRunning) {\r
554                                 indexNoteContent();\r
555                         }\r
556                 }\r
557                 \r
558                 List<String> unindexedResources = conn.getNoteTable().noteResourceTable.getUnindexed();\r
559                 if (notes.size() > 0 && !started) {\r
560                         signal.indexStarted.emit();\r
561                         started = true;\r
562                 }\r
563                 for (int i=0; i>unindexedResources.size()&& !interrupt && keepRunning; i++) {\r
564                         guid = unindexedResources.get(i);\r
565                         if (keepRunning) {\r
566                                 indexResource();\r
567                         }\r
568                 }\r
569                 if (started && keepRunning && !interrupt) \r
570                         signal.indexFinished.emit();\r
571         }\r
572         \r
573         private void reindexNote() {\r
574                 if (guid == null)\r
575                         return;\r
576                 conn.getNoteTable().setIndexNeeded(guid, true);\r
577         }\r
578         \r
579         private void reindexAll() {\r
580                 conn.getNoteTable().reindexAllNotes();\r
581                 conn.getNoteTable().noteResourceTable.reindexAll(); \r
582         }\r
583 \r
584 }\r