1 19 20 21 package org.netbeans.modules.search.types; 22 23 24 import java.io.*; 25 import java.nio.charset.Charset ; 26 import java.nio.charset.IllegalCharsetNameException ; 27 import java.util.ArrayList ; 28 import java.util.Collection ; 29 import java.util.HashMap ; 30 import java.util.HashSet ; 31 import java.util.Iterator ; 32 import java.util.List ; 33 import java.util.Map ; 34 import java.util.regex.Matcher ; 35 import javax.swing.Action ; 36 37 import org.netbeans.modules.search.SearchDisplayer; 38 import org.openide.ErrorManager; 39 40 import org.openide.filesystems.FileObject; 41 import org.openide.loaders.DataObject; 42 import org.openide.nodes.AbstractNode; 43 import org.openide.nodes.Children; 44 import org.openide.nodes.Node; 45 import org.openide.util.actions.NodeAction; 46 import org.openide.util.actions.SystemAction; 47 import org.openide.util.HelpCtx; 48 import org.openide.util.NbBundle; 49 import org.openide.windows.OutputEvent; 50 import org.openide.windows.OutputListener; 51 import org.openide.xml.XMLUtil; 52 import org.openidex.search.SearchPattern; 53 54 55 61 public class FullTextType extends TextType { 62 63 64 private static final String ATTR_FILE_ENCODING = "Content-Encoding"; 66 private static final long serialVersionUID = 1L; 67 69 70 private static final Collection searchableXMimeTypes; 71 72 static { 73 searchableXMimeTypes = new HashSet (17); 74 searchableXMimeTypes.add("csh"); searchableXMimeTypes.add("httpd-php"); searchableXMimeTypes.add("httpd-php-source"); searchableXMimeTypes.add("javascript"); searchableXMimeTypes.add("latex"); searchableXMimeTypes.add("php"); searchableXMimeTypes.add("sh"); searchableXMimeTypes.add("tcl"); searchableXMimeTypes.add("tex"); searchableXMimeTypes.add("texinfo"); searchableXMimeTypes.add("troff"); } 86 87 88 private String replaceString; 89 100 private transient Map <DataObject, List <TextDetail>> detailsMap; 101 102 106 private static final int MAX_REPORTED_OCCURENCES_ON_LINE = 5; 107 108 112 private static final int MAX_REPORTED_OCCURENCES_IN_FILE = 200; 113 114 120 public String getReplaceString() { 121 return replaceString; 122 } 123 124 131 public void setReplaceString(String replaceString) { 132 if (replaceString == null) { 133 setValid(false); 134 throw new IllegalArgumentException (); 135 } 136 137 if (replaceString.length() == 0) { 138 replaceString = null; 139 } 140 this.replaceString = replaceString; 141 } 142 143 144 public Object clone() { 145 FullTextType clone = (FullTextType) super.clone(); 146 clone.detailsMap = new HashMap <DataObject, List <TextDetail>>(20); 147 clone.replaceString = this.replaceString; 148 return clone; 149 } 150 151 152 public void destroy() { 153 if (detailsMap != null) { 154 detailsMap.clear(); 155 } 156 } 157 158 160 protected String displayName() { 161 166 167 return NbBundle.getMessage(FullTextType.class, 168 "TEXT_FULLTEXT_CRITERION"); } 170 171 172 private Map <DataObject, List <TextDetail>> getDetailsMap() { 173 if (detailsMap != null) { 174 return detailsMap; 175 } 176 177 synchronized(this) { 178 if (detailsMap == null) { 179 detailsMap = new HashMap <DataObject, List <TextDetail>>(20); 180 } 181 } 182 183 return detailsMap; 184 } 185 186 188 public static Charset getCharset(FileObject fileObj) { 189 Object encoding = fileObj.getAttribute(ATTR_FILE_ENCODING); 190 191 Charset charset = null; 192 if (encoding instanceof String ) { 193 String charsetName = (String ) encoding; 194 try { 195 if (Charset.isSupported(charsetName)) { 196 charset = Charset.forName(charsetName); 197 } 198 } catch (IllegalCharsetNameException ex) { 199 200 ErrorManager.getDefault().notify( ErrorManager.WARNING, ex); 201 } 202 } 203 204 if (charset == null) { 205 charset = Charset.defaultCharset(); 206 } 207 208 return charset; 209 } 210 211 216 public LineNumberReader getFileObjectReader(FileObject fileObj) 217 throws FileNotFoundException { 218 InputStream is = fileObj.getInputStream(); Charset charset = getCharset(fileObj); 220 return new LineNumberReader(new InputStreamReader(is, charset)); 221 } 222 223 225 public boolean testDataObject(DataObject dobj) { 226 LineNumberReader reader = null; 227 SearchPattern searchPattern = createSearchPattern(); 228 try { 229 String line = ""; 231 FileObject fo = dobj.getPrimaryFile(); 233 if (fo == null) { 234 return false; 235 } 236 reader = getFileObjectReader(fo); 238 239 ArrayList txtDetails = new ArrayList (5); 240 241 int fileCount = 0; 242 while (fileCount < MAX_REPORTED_OCCURENCES_IN_FILE) { 243 line = reader.readLine(); 244 if (line == null) { 245 break; 246 } 247 if (matchString != null) { 248 249 if (line.length() < matchString.length()) { 250 continue; 251 } 252 253 int lineNum = reader.getLineNumber(); int markLen = matchString.length(); 255 256 String stringToSearch = caseSensitive ? line 257 : line.toUpperCase(); 258 int fromIndex = 1; 259 int fromIndexMax = stringToSearch.length() 260 - matchString.length() + 1; 261 int matchIndex; 262 int lineCount = 0; 263 264 do { 265 matchIndex = matchString(stringToSearch, fromIndex); 266 if (matchIndex > 0) { 267 TextDetail det = new TextDetail(dobj, searchPattern); 268 det.setLine(lineNum); 269 det.setColumn(matchIndex); 270 det.setLineText(line); 271 det.setMarkLength(markLen); 272 273 txtDetails.add(det); 274 275 lineCount++; 276 fileCount++; 277 } 278 fromIndex = Math.abs(matchIndex) + 1; 279 } while ((matchIndex != 0) && (fromIndex <= fromIndexMax) 280 && (lineCount < MAX_REPORTED_OCCURENCES_ON_LINE)); 281 } else if (matchRE(line)) { 282 283 285 TextDetail det = new TextDetail(dobj, searchPattern); 286 det.setLine(reader.getLineNumber()); 287 det.setLineText(line); 288 Matcher matcher = getMatcher(); 289 int start = matcher.start(); 290 int len = matcher.end() - start; 291 det.setColumn(start +1); 292 det.setMarkLength(len); 293 294 txtDetails.add(det); 295 fileCount++; 296 } 297 } 298 299 301 if (txtDetails.isEmpty()) { 302 return false; 303 } 304 305 txtDetails.trimToSize(); 306 getDetailsMap().put(dobj, txtDetails); 307 308 return true; 309 } catch (FileNotFoundException fnfe) { 310 return false; 311 } catch (IOException ioe) { 312 org.openide.ErrorManager.getDefault().notify(org.openide.ErrorManager.INFORMATIONAL, ioe); 313 return false; 314 } finally { 315 if (reader != null) { 316 try { 317 reader.close(); 318 reader = null; 319 } catch (IOException ex) { 320 org.openide.ErrorManager.getDefault().notify( 321 org.openide.ErrorManager.INFORMATIONAL, ex); 322 323 } 324 } 325 } 326 } 327 328 333 protected boolean acceptSearchObject(Object searchObject) { 334 DataObject dataObj = (DataObject) searchObject; 335 FileObject fileObj = dataObj.getPrimaryFile(); 336 String mimeType = fileObj.getMIMEType(); 337 338 if (mimeType.equals("content/unknown") || mimeType.startsWith("text/")) { return true; 341 } 342 if (mimeType.startsWith("application/")) { final String subtype = mimeType.substring(12); 344 return subtype.equals("rtf") || subtype.equals("sgml") || subtype.startsWith("xml-") || subtype.endsWith("+xml") || subtype.startsWith("x-") && searchableXMimeTypes.contains(subtype.substring(2)); 350 } 351 return false; 352 } 353 354 355 362 public Node[] getDetails(Object resultObject) { 363 List <TextDetail> details = getDetailsMap().get(resultObject); 364 365 if(details == null) 366 return null; 367 368 List detailNodes = new ArrayList (details.size()); 369 370 for(Iterator it = details.iterator(); it.hasNext();) { 371 372 TextDetail txtDetail = (TextDetail)it.next(); 373 374 Node detailNode = new DetailNode(txtDetail); 375 detailNodes.add(detailNode); 376 } 377 378 return (Node[])detailNodes.toArray(new Node[detailNodes.size()]); 379 } 380 381 388 public Node[] getDetails(Node node) { 389 DataObject dataObject = (DataObject)node.getCookie(DataObject.class); 390 391 if(dataObject == null) 392 return null; 393 394 return getDetails(dataObject); 395 } 396 397 399 public int getDetailsCount(Object resultObject) { 400 List <TextDetail> details = getDetailsMap().get(resultObject); 401 return (details != null) ? details.size() : 0; 402 } 403 404 406 public List <TextDetail> getTextDetails(Object resultObject) { 407 List <TextDetail> obtained = getDetailsMap().get(resultObject); 408 return (obtained != null) ? new ArrayList <TextDetail>(obtained) : null; 409 } 410 411 public SearchPattern createSearchPattern() { 412 return SearchPattern.create( 413 matchString!=null?matchString:reString, 414 wholeWords, 415 caseSensitive, 416 matchString==null); 417 } 418 419 425 private static class DetailNode extends AbstractNode 426 implements OutputListener { 427 428 429 private TextDetail txtDetail; 430 431 432 433 439 public DetailNode(TextDetail txtDetail) { 440 super(Children.LEAF); 441 442 this.txtDetail = txtDetail; 443 444 setShortDescription(DetailNode.getShortDesc(txtDetail)); 445 setValue(SearchDisplayer.ATTR_OUTPUT_LINE, 446 DetailNode.getFullDesc(txtDetail)); 447 } 448 449 @Override 450 public Action [] getActions(boolean context) { 451 if (!context) { 452 return new Action [] { getPreferredAction() }; 453 } else { 454 return new Action [0]; 455 } 456 } 457 458 @Override 459 public Action getPreferredAction() { 460 return SystemAction.get(GotoDetailAction.class); 461 } 462 463 @Override 464 public boolean equals(Object anotherObj) { 465 return (anotherObj != null) 466 && (anotherObj.getClass() == DetailNode.class) 467 && (((DetailNode) anotherObj).txtDetail.equals(this.txtDetail)); 468 } 469 470 @Override 471 public int hashCode() { 472 return txtDetail.hashCode() + 1; 473 } 474 475 476 public String getName() { 477 return txtDetail.getLineText() + " [" + DetailNode.getName(txtDetail) + "]"; } 479 480 public String getHtmlDisplayName() { 481 String colored; 482 if (txtDetail.getMarkLength() > 0 && txtDetail.getColumn() > 0) { 483 try { 484 StringBuffer bold = new StringBuffer (); 485 String plain = txtDetail.getLineText(); 486 int col0 = txtDetail.getColumn() -1; 488 bold.append(XMLUtil.toElementContent(plain.substring(0, col0))); bold.append("<b>"); int end = col0 + txtDetail.getMarkLength(); 491 bold.append(XMLUtil.toElementContent(plain.substring(col0, end))); 492 bold.append("</b>"); if (txtDetail.getLineText().length() > end) { 494 bold.append(XMLUtil.toElementContent(plain.substring(end))); 495 } 496 colored = bold.toString(); 497 } catch (CharConversionException ex) { 498 return null; 499 } 500 } else { 501 try { 502 colored = XMLUtil.toElementContent( txtDetail.getLineText()); 503 } catch (CharConversionException e) { 504 return null; 505 } 506 } 507 508 try { 509 return colored + " <font color='!controlShadow'>[" + XMLUtil.toElementContent(DetailNode.getName(txtDetail)) + "]"; } catch (CharConversionException e) { 511 return null; 512 } 513 } 514 515 516 private void gotoDetail() { 517 txtDetail.showDetail(TextDetail.DH_GOTO); 518 } 519 520 521 private void showDetail() { 522 txtDetail.showDetail(TextDetail.DH_SHOW); 523 } 524 525 526 public void outputLineSelected (OutputEvent evt) { 527 txtDetail.showDetail(TextDetail.DH_SHOW); 528 } 529 530 531 public void outputLineAction (OutputEvent evt) { 532 txtDetail.showDetail(TextDetail.DH_GOTO); 533 } 534 535 536 public void outputLineCleared (OutputEvent evt) { 537 txtDetail.showDetail(TextDetail.DH_HIDE); 538 } 539 540 546 private static String getName(TextDetail det) { 547 int line = det.getLine(); 548 int col = det.getColumn(); 549 550 if (col > 0) { 551 552 553 return NbBundle.getMessage(FullTextType.class, "TEXT_DETAIL_FMT_NAME1", Integer.toString(line), 555 Integer.toString(col)); 556 } else { 557 558 559 return NbBundle.getMessage(FullTextType.class, "TEXT_DETAIL_FMT_NAME2", Integer.toString(line)); 561 } 562 } 563 564 572 private static String getShortDesc(TextDetail det) { 573 int line = det.getLine(); 574 int col = det.getColumn(); 575 576 if (col > 0) { 577 578 579 return NbBundle.getMessage(FullTextType.class, "TEXT_DETAIL_FMT_SHORT1", new Object [] {Integer.toString(line), 581 Integer.toString(col)}); 582 } else { 583 584 585 return NbBundle.getMessage(FullTextType.class, "TEXT_DETAIL_FMT_SHORT2", Integer.toString(line)); 587 } 588 } 589 590 598 private static String getFullDesc(TextDetail det) { 599 String filename = det.getDataObject().getPrimaryFile().getNameExt(); 600 String lineText = det.getLineText(); 601 int line = det.getLine(); 602 int col = det.getColumn(); 603 604 if (col > 0) { 605 606 607 return NbBundle.getMessage(FullTextType.class, "TEXT_DETAIL_FMT_FULL1", new Object [] {lineText, 609 filename, 610 Integer.toString(line), 611 Integer.toString(col)}); 612 } else { 613 614 615 return NbBundle.getMessage(FullTextType.class, "TEXT_DETAIL_FMT_FULL2", new Object [] {lineText, 617 filename, 618 Integer.toString(line)}); 619 } 620 } 621 622 } 624 625 630 private static class GotoDetailAction extends NodeAction { 631 632 633 public String getName() { 634 return NbBundle.getBundle(FullTextType.class).getString("LBL_GotoDetailAction"); 635 } 636 637 638 public HelpCtx getHelpCtx() { 639 return new HelpCtx(GotoDetailAction.class); 640 } 641 642 647 protected boolean enable(Node[] activatedNodes) { 648 return activatedNodes != null && activatedNodes.length != 0 649 && activatedNodes[0] instanceof DetailNode; 650 } 651 652 657 protected void performAction(Node[] activatedNodes) { 658 if (enable(activatedNodes)) { 659 ((DetailNode)activatedNodes[0]).gotoDetail(); 660 } 661 } 662 663 665 protected boolean asynchronous() { 666 return false; 667 } 668 669 670 } 672 674 public HelpCtx getHelpCtx() { 675 return new HelpCtx(FullTextType.class); 676 } 677 678 } 679 | Popular Tags |