1 /* Scilab ( http://www.scilab.org/ ) - This file is part of Scilab 2 * Copyright (C) 2009 - DIGITEO - Bernard HUGUENEY 3 * Copyright (C) 2010 - Calixte DENIZET 4 * 5 * Copyright (C) 2012 - 2016 - Scilab Enterprises 6 * 7 * This file is hereby licensed under the terms of the GNU GPL v2.0, 8 * pursuant to article 5.3.4 of the CeCILL v.2.1. 9 * This file was originally licensed under the terms of the CeCILL v2.1, 10 * and continues to be available under such terms. 11 * For more information, see the COPYING file which you should have received 12 * along with this program. 13 * 14 */ 15 16 package org.scilab.modules.scinotes; 17 18 import java.io.BufferedReader; 19 import java.io.BufferedWriter; 20 import java.io.File; 21 import java.io.FilenameFilter; 22 import java.io.IOException; 23 import java.io.InputStreamReader; 24 import java.io.FileInputStream; 25 import java.nio.charset.Charset; 26 import java.util.ArrayList; 27 import java.util.Arrays; 28 import java.util.List; 29 import java.util.Scanner; 30 import java.util.regex.Matcher; 31 import java.util.regex.Pattern; 32 33 import javax.swing.Icon; 34 import javax.swing.ImageIcon; 35 import javax.swing.SwingWorker; 36 import javax.swing.text.BadLocationException; 37 import javax.swing.text.Document; 38 import javax.swing.tree.DefaultMutableTreeNode; 39 40 import org.scilab.modules.commons.gui.FindIconHelper; 41 import org.scilab.modules.commons.xml.ScilabXMLUtilities; 42 import org.scilab.modules.scinotes.utils.SciNotesMessages; 43 import org.w3c.dom.Element; 44 import org.w3c.dom.NodeList; 45 46 /** 47 * Class SearchManager 48 * @author Sylvestre Koumar 49 * @author Calixte DENIZET 50 */ 51 public class SearchManager { 52 53 private static final ImageIcon FILEIMAGE = new ImageIcon(FindIconHelper.findIcon("stock_search")); 54 private static final ImageIcon SCILABFILEIMAGE = new ImageIcon(FindIconHelper.findIcon("scilab_search")); 55 private static final ImageIcon FOLDERIMAGE = new ImageIcon(FindIconHelper.findIcon("folder-saved-search")); 56 private static final ImageIcon LINEICON = new ImageIcon(FindIconHelper.findIcon("line-found")); 57 58 /** 59 * FIND AND REPLACE START 60 * @param scilabDocument document 61 * @param word string 62 * @param start int 63 * @param end int 64 * @param caseSensitive boolean 65 * @param wholeWord boolean 66 * @param useRegexp boolean 67 * @return List 68 */ findWord(Document scilabDocument, String word, int start, int end, boolean caseSensitive, boolean wholeWord, boolean useRegexp)69 public static List<Integer[]> findWord(Document scilabDocument, String word, 70 int start, int end, 71 boolean caseSensitive, boolean wholeWord, boolean useRegexp) { 72 String fullText = ""; 73 try { 74 fullText = scilabDocument.getText(start, end - start + 1); 75 } catch (BadLocationException ex) { 76 ex.printStackTrace(); 77 } 78 79 if (fullText.length() == 0) { 80 return null; 81 } 82 83 List<Integer[]> offsetList = new ArrayList<Integer[]>(); 84 85 //If we don't give any word to find 86 if (word != null && !word.equals("")) { 87 Pattern pattern = generatePattern(word, caseSensitive, wholeWord, useRegexp); 88 Matcher matcher = pattern.matcher(fullText); 89 90 while (matcher.find()) { 91 if (matcher.start() != matcher.end()) { 92 offsetList.add(new Integer[] {matcher.start() + start, matcher.end() + start}); 93 } 94 } 95 } 96 97 return offsetList; 98 } 99 100 /** 101 * FIND AND REPLACE START 102 * @param scilabDocument document 103 * @param word string 104 * @param start int 105 * @param end int 106 * @param caseSensitive boolean 107 * @param wholeWord boolean 108 * @param useRegexp boolean 109 * @return List 110 */ findToken(ScilabDocument scilabDocument, int token, ScilabLexer lexer, Pattern pat)111 public static List<Integer[]> findToken(ScilabDocument scilabDocument, int token, ScilabLexer lexer, Pattern pat) { 112 String fullText = scilabDocument.getText(); 113 114 if (fullText.length() == 0) { 115 return null; 116 } 117 118 List<Integer[]> offsetList = new ArrayList<Integer[]>(); 119 120 //If we don't give any word to find 121 Matcher matcher = pat.matcher(fullText); 122 123 while (matcher.find()) { 124 int start = matcher.start(); 125 int end = matcher.end(); 126 if (token == -1 || token == lexer.getKeyword(start, false)) { 127 offsetList.add(new Integer[] {start, end}); 128 } 129 } 130 131 return offsetList; 132 } 133 134 /** 135 * Generate the good pattern according to the differents boolean 136 * @param exp the searched expression 137 * @param caseSensitive boolean 138 * @param wholeWord boolean 139 * @param useRegexp boolean 140 * @return the pattern 141 */ generatePattern(String exp, boolean caseSensitive, boolean wholeWord, boolean useRegexp)142 public static Pattern generatePattern(String exp, boolean caseSensitive, boolean wholeWord, boolean useRegexp) { 143 String word = exp; 144 if (word != null && !word.equals("")) { 145 if (!useRegexp) { 146 word = word.replace("\\E", "\\E\\\\E\\Q"); 147 word = "\\Q" + word + "\\E"; 148 if (wholeWord && exp.matches("\\b.*\\b")) { 149 word = "\\b" + word + "\\b"; 150 } 151 } 152 153 if (!caseSensitive) { 154 word = "(?i)" + word; 155 } 156 157 if (useRegexp) { 158 word = "(?m)" + word; 159 } 160 161 return Pattern.compile(word); 162 } else { 163 return Pattern.compile(""); 164 } 165 } 166 167 /** 168 * Search a word (with a pattern) in files selected according to their name. 169 * @param base the base directory 170 * @param recursive, if true then a recursive search is made 171 * @param ignoreCR, if true then the read file is considered as one line and regex pattern can include \n 172 * @param filePattern the pattern to use to select the files. * is equivalent to .* and ? to .? 173 * @param fileCaseSensitive, if true then the file pattern is case sensitive 174 * @param wordPattern the pattern of the word to search 175 * @param wordCaseSensitive, if true then the word pattern is case sensitive 176 * @param wholeWord, if true only whole word will be matched, e.g. in "foobar foo bar", if the pattern is "foo", then only the second "foo" will be matched 177 * @param regexp, if true the word pattern is considered as a regex 178 * @return infos with the matching positions 179 */ searchInFiles(final BackgroundSearch bgs, String base, final boolean recursive, final boolean ignoreCR, String filePattern, boolean fileCaseSensitive, String wordPattern, boolean wordCaseSensitive, boolean wholeWord, boolean regexp)180 public static MatchingPositions searchInFiles(final BackgroundSearch bgs, String base, final boolean recursive, final boolean ignoreCR, 181 String filePattern, boolean fileCaseSensitive, 182 String wordPattern, boolean wordCaseSensitive, boolean wholeWord, boolean regexp) { 183 final File dir = new File(base); 184 Pattern word = null; 185 if (wordPattern != null && wordPattern.length() != 0) { 186 word = generatePattern(wordPattern, wordCaseSensitive, wholeWord, regexp); 187 } 188 filePattern = filePattern.replace(".", "\\.").replace("*", ".*").replace("?", ".?"); 189 final Pattern file = generatePattern(filePattern, fileCaseSensitive, false, true); 190 191 final boolean[] killed = new boolean[] {false}; 192 if (bgs == null) { 193 return searchInFiles(killed, dir, recursive, ignoreCR, file, word); 194 } else { 195 final Pattern fword = word; 196 SwingWorker worker = new SwingWorker<Object, Object>() { 197 @Override 198 public Object doInBackground() { 199 long begin = System.currentTimeMillis(); 200 bgs.setResults(searchInFiles(killed, dir, recursive, ignoreCR, file, fword)); 201 long end = System.currentTimeMillis(); 202 bgs.setElapsedTime(end - begin); 203 return null; 204 } 205 206 @Override 207 public void done() { 208 bgs.done(); 209 } 210 }; 211 bgs.setKilled(killed); 212 bgs.setSwingWorker(worker); 213 worker.execute(); 214 return null; 215 } 216 } 217 218 /** 219 * Search a word (with a pattern) in files selected according to their name. 220 * @param base the base directory 221 * @param recursive, if true then a recursive search is made 222 * @param ignoreCR, if true then the read file is considered as one line and regex pattern can include \n 223 * @param filePattern the pattern to use to select the files. * is equivalent to .* and ? to .? 224 * @param word the pattern of the word to search 225 * @param killed a boolean array with more than one element. It is used as a reference on a boolean set to true if the process is killed. 226 * @return infos with the matching positions 227 */ searchInFiles(boolean[] killed, File base, boolean recursive, boolean ignoreCR, final Pattern file, final Pattern word)228 public static MatchingPositions searchInFiles(boolean[] killed, File base, boolean recursive, boolean ignoreCR, final Pattern file, final Pattern word) { 229 MatchingPositions pos = null; 230 if (base.exists() && base.isDirectory() && base.canRead() && !killed[0]) { 231 List<MatchingPositions> list = new ArrayList<MatchingPositions>(); 232 pos = new MatchingPositions(base.getAbsolutePath(), list); 233 int occurences = 0; 234 File[] files = base.listFiles(new FilenameFilter() { 235 @Override 236 public boolean accept(File dir, String name) { 237 File f = new File(dir, name); 238 return f.isFile() && f.canRead() && file.matcher(name).matches(); 239 } 240 }); 241 Arrays.sort(files); 242 243 if (word != null) { 244 for (int i = 0; i < files.length && !killed[0]; i++) { 245 MatchingPositions wpos; 246 if (!ignoreCR) { 247 wpos = searchWordInFile(files[i], word); 248 } else { 249 wpos = searchWordInFileIgnoringCR(files[i], word); 250 } 251 if (wpos != null && wpos.getOccurences() != 0) { 252 list.add(wpos); 253 occurences += wpos.getOccurences(); 254 } 255 } 256 } else { 257 for (int i = 0; i < files.length && !killed[0]; i++) { 258 list.add(new MatchingPositions(files[i].getAbsolutePath())); 259 } 260 occurences += files.length; 261 } 262 263 if (recursive) { 264 files = base.listFiles(new FilenameFilter() { 265 @Override 266 public boolean accept(File dir, String name) { 267 File d = new File(dir, name); 268 return d.isDirectory() && d.canRead(); 269 } 270 }); 271 Arrays.sort(files); 272 273 for (int i = 0; i < files.length && !killed[0]; i++) { 274 MatchingPositions rpos = searchInFiles(killed, files[i], true, ignoreCR, file, word); 275 if (rpos != null) { 276 list.add(rpos); 277 occurences += rpos.getOccurences(); 278 } 279 } 280 } 281 282 pos.setOccurences(occurences); 283 284 if (list.isEmpty()) { 285 return null; 286 } 287 } 288 289 return pos; 290 } 291 292 /** 293 * Search a word (with a pattern) in a file. The search is made line by line. 294 * @param file the file where to search 295 * @param pat the pattern of the word to search 296 * @return infos with the matching positions 297 */ searchWordInFile(File f, Pattern pat)298 public static MatchingPositions searchWordInFile(File f, Pattern pat) { 299 if (f.exists() && f.canRead()) { 300 MatchingPositions pos = new MatchingPositions(f.getAbsolutePath()); 301 String charset; 302 try { 303 charset = ScilabEditorKit.tryToGuessEncoding(f).name(); 304 } catch (Exception e) { 305 charset = Charset.defaultCharset().name(); 306 } 307 308 try { 309 Scanner scanner = new Scanner(f, charset); 310 int occ = 0; 311 int line = 0; 312 while (scanner.hasNextLine()) { 313 line++; 314 String str = scanner.nextLine(); 315 Matcher matcher = pat.matcher(str); 316 int socc = occ; 317 while (matcher.find()) { 318 occ++; 319 } 320 if (occ != socc) { 321 pos.addLine(line, str, pat); 322 } 323 } 324 scanner.close(); 325 326 pos.setOccurences(occ); 327 return pos; 328 } catch (Exception e) { } 329 } 330 331 return null; 332 } 333 334 /** 335 * Search a word (with a pattern) in a file. The file content is considered as one line (useful to search "...\n...") 336 * @param file the file where to search 337 * @param pat the pattern of the word to search 338 * @return infos with the matching positions 339 */ searchWordInFileIgnoringCR(File f, Pattern pat)340 public static MatchingPositions searchWordInFileIgnoringCR(File f, Pattern pat) { 341 if (f.exists() && f.canRead()) { 342 MatchingPositions pos = new MatchingPositions(f.getAbsolutePath()); 343 String charset; 344 try { 345 charset = ScilabEditorKit.tryToGuessEncoding(f).name(); 346 } catch (Exception e) { 347 charset = Charset.defaultCharset().name(); 348 } 349 350 try { 351 Scanner scanner = new Scanner(f, charset); 352 int occ = 0; 353 while (scanner.findWithinHorizon(pat, 0) != null) { 354 occ++; 355 } 356 pos.setOccurences(occ); 357 scanner.close(); 358 359 return pos; 360 } catch (Exception e) { } 361 } 362 363 return null; 364 } 365 366 /** 367 * Count the file having a name corresponding to a pattern 368 * @param base the base directory 369 * @param pat the file name pattern 370 * @return the number of files 371 */ countFiles(File base, Pattern pat)372 public static int countFiles(File base, Pattern pat) { 373 if (!base.isDirectory() || !base.canRead()) { 374 return -1; 375 } 376 377 int[] count = new int[] {0}; 378 countFiles(base, pat, count); 379 380 return count[0]; 381 } 382 383 /** 384 * Count files in a recursive way 385 */ countFiles(File base, final Pattern pat, final int[] count)386 private static void countFiles(File base, final Pattern pat, final int[] count) { 387 File[] files = base.listFiles(new FilenameFilter() { 388 @Override 389 public boolean accept(File dir, String name) { 390 File f = new File(dir, name); 391 if (f.isFile() && f.canRead() && pat.matcher(name).matches()) { 392 count[0]++; 393 } else if (f.isDirectory() && f.canRead()) { 394 countFiles(f, pat, count); 395 } 396 return false; 397 } 398 }); 399 } 400 401 /** 402 * @param file the file to test 403 * @return true if it is a binary file 404 */ isBinaryFile(File f)405 public static boolean isBinaryFile(File f) { 406 try ( BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(f), "UTF-8")) ) { 407 char[] buffer = new char[8192]; 408 int len = reader.read(buffer, 0, 8192); 409 410 int i = 0; 411 if (len != -1) { 412 for (; i < len && buffer[i] != '\0'; i++) { 413 ; 414 } 415 } 416 417 return len != -1 && i != len; 418 } catch (IOException e) { 419 e.printStackTrace(); 420 return false; 421 } 422 } 423 indent(BufferedWriter buffer, int level)424 private static void indent(BufferedWriter buffer, int level) throws IOException { 425 for (int i = 0; i < level; i++) { 426 buffer.append(" "); 427 } 428 } 429 430 /** 431 * MatchingPositions: inner class to store the results of a search in a file or in a directory 432 */ 433 public static class MatchingPositions implements Iconable { 434 435 private final String file; 436 private boolean isRoot; 437 private Icon icon; 438 private int occurences; 439 private List<MatchingPositions> children; 440 private final List<Line> lines = new ArrayList<Line>(); 441 442 /** 443 * Constructor 444 * @param file the file where to search is made 445 * @param children the list of the file in the directory 446 */ MatchingPositions(String file, List<MatchingPositions> children)447 public MatchingPositions(String file, List<MatchingPositions> children) { 448 this.file = file; 449 this.children = children; 450 setIcon(); 451 } 452 453 /** 454 * Constructor 455 * @param file the file where to search is made 456 */ MatchingPositions(String file)457 public MatchingPositions(String file) { 458 this(file, null); 459 } 460 461 /** 462 * @param root the xml Element representing a MatchingPositions 463 */ MatchingPositions(Element root)464 public MatchingPositions(Element root) { 465 this.file = root.getAttribute("file"); 466 this.isRoot = Boolean.parseBoolean(root.getAttribute("isRoot")); 467 this.occurences = Integer.parseInt(root.getAttribute("occurences")); 468 if (root.hasChildNodes()) { 469 NodeList nodeList = root.getChildNodes(); 470 Element e = (Element) nodeList.item(1); 471 if (e.getTagName().equals("Position")) { 472 this.children = new ArrayList<MatchingPositions>(); 473 for (int i = 0; i < nodeList.getLength(); i++) { 474 if (nodeList.item(i) instanceof Element) { 475 e = (Element) nodeList.item(i); 476 this.children.add(new MatchingPositions(e)); 477 } 478 } 479 } else { 480 for (int i = 0; i < nodeList.getLength(); i++) { 481 if (nodeList.item(i) instanceof Element) { 482 e = (Element) nodeList.item(i); 483 this.lines.add(new Line(e)); 484 } 485 } 486 } 487 } 488 setIcon(); 489 } 490 setIcon()491 private void setIcon() { 492 if (children != null) { 493 this.icon = FOLDERIMAGE; 494 } else if (file.endsWith(".sce") || file.endsWith(".sci")) { 495 this.icon = SCILABFILEIMAGE; 496 } else { 497 this.icon = FILEIMAGE; 498 } 499 } 500 501 /** 502 * Set this as the root directory 503 */ setRoot()504 public void setRoot() { 505 isRoot = true; 506 } 507 508 /** 509 * Set the number of matches in the file or in the directory 510 * @param occ the number of matches 511 */ setOccurences(int occ)512 public void setOccurences(int occ) { 513 occurences = occ; 514 } 515 516 /** 517 * @return the number of matches 518 */ getOccurences()519 public int getOccurences() { 520 return occurences; 521 } 522 523 /** 524 * Add a line where the searched word has been found 525 * @param number the line number 526 * @param line the line content 527 * @param pat the pattern used 528 */ addLine(int number, String line, Pattern pat)529 public void addLine(int number, String line, Pattern pat) { 530 this.lines.add(new Line(number, line, pat)); 531 } 532 533 /** 534 * @return the file name 535 */ getFileName()536 public String getFileName() { 537 return file; 538 } 539 540 /** 541 * @return true if we are in a directory 542 */ isDirectory()543 public boolean isDirectory() { 544 return children != null; 545 } 546 547 /** 548 * {@inheritDoc} 549 */ 550 @Override getIcon()551 public Icon getIcon() { 552 return icon; 553 } 554 555 /** 556 * @return true if the file have matching lines 557 */ hasLines()558 public boolean hasLines() { 559 return !lines.isEmpty(); 560 } 561 562 /** 563 * @return the file present in this directory 564 */ getChildren()565 public List<MatchingPositions> getChildren() { 566 return children; 567 } 568 569 /** 570 * Convert this MatchingPositions and its children (if they are) in a DefaultMutableTreeNode 571 * @return the coirresponding DefaultMutableTreeNode 572 */ toDefaultMutableTreeNode()573 public DefaultMutableTreeNode toDefaultMutableTreeNode() { 574 DefaultMutableTreeNode root = new DefaultMutableTreeNode(this); 575 if (children != null && !children.isEmpty()) { 576 for (int i = 0; i < children.size(); i++) { 577 root.add(children.get(i).toDefaultMutableTreeNode()); 578 } 579 } else if (!lines.isEmpty()) { 580 for (Line l : lines) { 581 root.add(new DefaultMutableTreeNode(l)); 582 } 583 } 584 585 return root; 586 } 587 588 /** 589 * @param buffer the buffer where to write the XML 590 * @param level the indentation level 591 */ toXML(BufferedWriter buffer, int level)592 public void toXML(BufferedWriter buffer, int level) throws IOException { 593 indent(buffer, level); 594 buffer.append("<Position file=\"" + ScilabXMLUtilities.getXMLString(file) + "\" isRoot=\"" + isRoot + "\" occurences=\"" + occurences + "\""); 595 if (children != null && !children.isEmpty()) { 596 buffer.append(">\n"); 597 for (int i = 0; i < children.size(); i++) { 598 children.get(i).toXML(buffer, level + 1); 599 } 600 indent(buffer, level); 601 buffer.append("</Position>\n"); 602 } else if (!lines.isEmpty()) { 603 buffer.append(">\n"); 604 for (Line l : lines) { 605 l.toXML(buffer, level + 1); 606 } 607 indent(buffer, level); 608 buffer.append("</Position>\n"); 609 } else { 610 buffer.append("/>\n"); 611 } 612 } 613 614 /** 615 * {@inheritDoc} 616 */ 617 @Override toString()618 public String toString() { 619 String occ = SciNotesMessages.MATCHES; 620 if (occurences <= 1) { 621 occ = SciNotesMessages.MATCH; 622 } 623 624 String filename; 625 if ((!isDirectory() && occurences != 0)) { 626 filename = new File(getFileName()).getName(); 627 } else if (isRoot) { 628 filename = getFileName(); 629 } else { 630 filename = new File(getFileName()).getName(); 631 } 632 633 if (occurences == 0 && !isRoot) { 634 return filename; 635 } 636 637 filename = filename.replace("&", "&").replace("/", "/").replace("\\", "\").replace("<", "<").replace(">", ">"); 638 return String.format(occ, filename, occurences); 639 } 640 } 641 642 /** 643 * Line: inner class to store a line number and line content 644 */ 645 public static class Line implements Iconable { 646 647 private final int number; 648 private String content; 649 650 /** 651 * Constructor 652 * @param number the line number 653 * @param content the line content 654 * @param pattern the used pattern 655 */ Line(int number, String content, Pattern pattern)656 public Line(int number, String content, Pattern pattern) { 657 this.number = number; 658 Matcher matcher = pattern.matcher(content); 659 if (content.length() > 128) { 660 content = content.substring(0, 128) + "..."; 661 } 662 StringBuffer sb = new StringBuffer(); 663 while (matcher.find()) { 664 /* 665 TODO: Find a better way to handle <b> and </b> around the pattern. 666 If HTML entities are put before the loop the pattern should be updated (not a funky task...). 667 Actually, it could have a bad rendering on binary files (which probably contains \0...) 668 */ 669 matcher.appendReplacement(sb, "\0"); 670 sb.append(matcher.group()); 671 sb.append("\0\0"); 672 } 673 matcher.appendTail(sb); 674 this.content = sb.toString(); 675 this.content = this.content.replace("&", "&").replace("/", "/").replace("\\", "\").replace("<", "<").replace(">", ">").replace("\0\0", "</b>").replace("\0", "<b>"); 676 } 677 678 /** 679 * @param root the xml Element representing a Line 680 */ Line(Element root)681 public Line(Element root) { 682 this.number = Integer.parseInt(root.getAttribute("number")); 683 this.content = root.getAttribute("content"); 684 } 685 686 /** 687 * @return the line number 688 */ getNumber()689 public int getNumber() { 690 return number; 691 } 692 693 /** 694 * @return the line content as HTML 695 */ getContent()696 public String getContent() { 697 return content; 698 } 699 700 /** 701 * {@inheritDoc} 702 */ 703 @Override getIcon()704 public Icon getIcon() { 705 return LINEICON; 706 } 707 708 /** 709 * @param buffer the buffer where to write the XML 710 * @param level the indentation level 711 */ toXML(BufferedWriter buffer, int level)712 public void toXML(BufferedWriter buffer, int level) throws IOException { 713 indent(buffer, level); 714 buffer.append("<Line content=\"" + ScilabXMLUtilities.getXMLString(content) + "\" number=\"" + number + "\"/>\n"); 715 } 716 717 /** 718 * {@inheritDoc} 719 */ 720 @Override toString()721 public String toString() { 722 return "<html><u>line " + number + "</u> : " + content + "</html>"; 723 } 724 } 725 726 /** 727 * Inner interface for the JTree representation 728 */ 729 public static interface Iconable { 730 731 /** 732 * @return the icon used in the JTree representation 733 */ getIcon()734 public Icon getIcon(); 735 } 736 737 /** 738 * Inner class to allow a background search 739 */ 740 public static abstract class BackgroundSearch { 741 742 private MatchingPositions pos; 743 private SwingWorker worker; 744 private long time; 745 private boolean[] killed; 746 747 /** 748 * Default Constructor 749 */ BackgroundSearch()750 public BackgroundSearch() { } 751 752 /** 753 * Stop this search 754 */ stop()755 public void stop() { 756 if (worker != null && !isDone()) { 757 worker.cancel(true); 758 worker = null; 759 if (killed != null && killed.length >= 1) { 760 killed[0] = true; 761 } 762 } 763 } 764 765 /** 766 * Called when the work is done 767 */ done()768 public abstract void done(); 769 770 /** 771 * @return true if the search is finished 772 */ isDone()773 public boolean isDone() { 774 if (worker != null) { 775 return worker.isDone(); 776 } 777 return true; 778 } 779 780 /** 781 * Get the results 782 * @return the results 783 */ getResults()784 public MatchingPositions getResults() { 785 if (isDone()) { 786 worker = null; 787 return pos; 788 } 789 return null; 790 } 791 792 /** 793 * Set the elapsed time for this search 794 */ setElapsedTime(long t)795 public void setElapsedTime(long t) { 796 this.time = t; 797 } 798 799 /** 800 * @return the elapsed time of this search 801 */ getElapsedTime()802 public long getElapsedTime() { 803 return time; 804 } 805 806 /** 807 * Set the SwingWorker we work with 808 * @param worker the SwingWorker 809 */ setSwingWorker(SwingWorker worker)810 private void setSwingWorker(SwingWorker worker) { 811 this.worker = worker; 812 } 813 814 /** 815 * @param killed a reference on a boolean to inform the main loop that the process has been killed 816 */ setKilled(boolean[] killed)817 private void setKilled(boolean[] killed) { 818 this.killed = killed; 819 } 820 821 /** 822 * @param pos the results to set 823 */ setResults(MatchingPositions pos)824 private void setResults(MatchingPositions pos) { 825 this.pos = pos; 826 } 827 } 828 } 829