OSDN Git Service

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