1 19 20 package org.netbeans.modules.search; 21 22 import java.awt.BorderLayout ; 23 import java.awt.CardLayout ; 24 import java.awt.event.ActionEvent ; 25 import java.awt.event.ActionListener ; 26 import java.awt.EventQueue ; 27 import java.awt.event.ItemEvent ; 28 import java.awt.event.ItemListener ; 29 import java.text.MessageFormat ; 30 import java.util.ArrayList ; 31 import java.util.Iterator ; 32 import java.util.List ; 33 import java.util.ResourceBundle ; 34 import java.lang.ref.WeakReference ; 35 import javax.accessibility.AccessibleContext ; 36 import javax.swing.BorderFactory ; 37 import javax.swing.Box ; 38 import javax.swing.BoxLayout ; 39 import javax.swing.ImageIcon ; 40 import javax.swing.JButton ; 41 import javax.swing.JPanel ; 42 import javax.swing.JScrollPane ; 43 import javax.swing.JSplitPane ; 44 import javax.swing.JToggleButton ; 45 import javax.swing.JToolBar ; 46 import javax.swing.JTree ; 47 import javax.swing.SwingConstants ; 48 import javax.swing.tree.TreePath ; 49 import org.openide.awt.Mnemonics; 50 import org.openide.nodes.Node; 51 import org.openide.util.NbBundle; 52 import org.openide.util.Utilities; 53 import org.openide.windows.Mode; 54 import org.openide.windows.TopComponent; 55 import org.openide.windows.WindowManager; 56 import org.openidex.search.SearchType; 57 import static java.lang.Thread.NORM_PRIORITY ; 58 59 67 final class ResultView extends TopComponent { 68 69 70 private static final boolean SHOW_CONTEXT_BY_DEFAULT = true; 71 72 private static final String RESULTS_CARD = "results"; 74 private static final String ISSUES_CARD = "issues"; 76 77 private boolean contextViewEnabled = SHOW_CONTEXT_BY_DEFAULT; 78 79 private boolean contextViewVisible = false; 80 81 private double dividerLocation = -1.0d; 82 83 private boolean ignoreContextButtonToggle = false; 84 85 private boolean hasResults = false; 87 private int objectsCount = 0; 89 private volatile boolean hasDetails = false; 90 91 private volatile boolean searchInProgress = false; 92 93 94 private static final String ID = "search-results"; 96 101 private static WeakReference instance = null; 102 103 106 private final JScrollPane treeView; 107 108 109 private ResultModel resultModel = null; 110 111 private ResultTreeModel treeModel = null; 112 113 114 private final JTree tree; 115 116 private final NodeListener nodeListener; 117 118 119 private Node[] lastSearchNodes; 120 121 private List lastEnabledSearchTypes; 122 123 124 private MessageFormat nodeCountFormat; 125 129 private MessageFormat nodeCountFormatFullText; 130 131 136 static synchronized ResultView getInstance() { 137 ResultView view; 138 view = (ResultView) WindowManager.getDefault().findTopComponent(ID); 139 if (view == null) { 140 view = getDefault(); 141 } 142 return view; 143 } 144 145 155 public static synchronized ResultView getDefault() { 156 ResultView view; 157 if (instance == null) { 158 view = new ResultView(); 159 instance = new WeakReference (view); 160 } else { 161 view = (ResultView) instance.get(); 162 if (view == null) { 163 view = new ResultView(); 164 instance = new WeakReference (view); 165 } 166 } 167 return view; 168 } 169 170 private final CardLayout contentCards; 171 private final CardLayout resultViewCards; 172 private final JPanel mainPanel; 173 private final JPanel resultsPanel; 174 private final JButton btnReplace; 175 private final JButton btnModifySearch; 176 private final JButton btnShowDetails; 177 private final JButton btnStop; 178 private final JButton btnPrev; 179 private final JButton btnNext; 180 private final JToggleButton btnDisplayContext; 181 182 private JSplitPane splitPane; 183 private ContextView contextView; 184 private IssuesPanel issuesPanel; 185 186 187 private ResultView() { 188 JToolBar toolBar = new JToolBar (SwingConstants.VERTICAL); 190 btnDisplayContext = new JToggleButton (); 191 btnDisplayContext.setIcon(new ImageIcon (Utilities.loadImage( 192 "org/netbeans/modules/search/res/context.gif", true))); btnDisplayContext.setToolTipText( 194 NbBundle.getMessage(getClass(), "TOOLTIP_ShowContext")); btnDisplayContext.getAccessibleContext().setAccessibleDescription( 196 NbBundle.getMessage(getClass(), "ACSD_ShowContext")); btnDisplayContext.setSelected(SHOW_CONTEXT_BY_DEFAULT); 198 btnPrev = new JButton (); 199 btnPrev.setIcon(new ImageIcon (Utilities.loadImage( 200 "org/netbeans/modules/search/res/prev.png", true))); btnNext = new JButton (); 202 btnNext.setIcon(new ImageIcon (Utilities.loadImage( 203 "org/netbeans/modules/search/res/next.png", true))); toolBar.add(btnDisplayContext); 205 toolBar.add(new JToolBar.Separator ()); 206 toolBar.add(btnPrev); 207 toolBar.add(btnNext); 208 toolBar.setRollover(true); 209 toolBar.setFloatable(false); 210 211 treeModel = createTreeModel(); 212 tree = createTree(treeModel, nodeListener = new NodeListener()); 213 treeView = new JScrollPane (tree); 214 treeView.getAccessibleContext().setAccessibleDescription( 215 NbBundle.getMessage(ResultView.class, "ACS_TREEVIEW")); treeView.setBorder(BorderFactory.createEmptyBorder()); 217 218 resultsPanel = new JPanel (resultViewCards = new CardLayout ()); 219 220 btnShowDetails = new JButton (); 221 btnModifySearch = new JButton (); 222 btnStop = new JButton (); 223 btnReplace = new JButton (); 224 225 226 ButtonListener buttonListener = new ButtonListener(); 227 btnShowDetails.addActionListener(buttonListener); 228 btnModifySearch.addActionListener(buttonListener); 229 btnStop.addActionListener(buttonListener); 230 btnReplace.addActionListener(buttonListener); 231 btnPrev.addActionListener(buttonListener); 232 btnNext.addActionListener(buttonListener); 233 btnDisplayContext.addItemListener(buttonListener); 234 235 Mnemonics.setLocalizedText( 236 btnStop, 237 NbBundle.getMessage(getClass(), "TEXT_BUTTON_STOP")); Mnemonics.setLocalizedText( 239 btnShowDetails, 240 NbBundle.getMessage(getClass(), "TEXT_BUTTON_FILL")); Mnemonics.setLocalizedText( 242 btnReplace, 243 NbBundle.getMessage(getClass(), "TEXT_BUTTON_REPLACE")); Mnemonics.setLocalizedText( 245 btnModifySearch, 246 NbBundle.getMessage(getClass(), 247 "TEXT_BUTTON_CUSTOMIZE")); 249 btnStop.setEnabled(false); 250 btnShowDetails.setEnabled(false); 251 252 btnReplace.setVisible(false); 253 254 JPanel buttonsPanel = new JPanel (); 255 buttonsPanel.setLayout(new BoxLayout (buttonsPanel, BoxLayout.X_AXIS)); 256 buttonsPanel.add(btnReplace); 257 buttonsPanel.add(Box.createHorizontalGlue()); 258 buttonsPanel.add(btnShowDetails); 259 buttonsPanel.add(btnModifySearch); 260 buttonsPanel.add(btnStop); 261 262 mainPanel = new JPanel (); 263 mainPanel.setLayout(new BorderLayout (0, 5)); 264 mainPanel.add(toolBar, BorderLayout.WEST); 265 mainPanel.add(resultsPanel, BorderLayout.CENTER); 266 mainPanel.add(buttonsPanel, BorderLayout.SOUTH); 267 mainPanel.setOpaque(true); 269 mainPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 2, 0)); 270 271 setLayout(contentCards = new CardLayout ()); 272 add(mainPanel, RESULTS_CARD); 273 274 setName("Search Results"); setDisplayName(NbBundle.getMessage(ResultView.class, 276 "TITLE_SEARCH_RESULTS")); setToolTipText(NbBundle.getMessage(ResultView.class, 278 "TOOLTIP_SEARCH_RESULTS")); setIcon(Utilities.loadImage( 280 "org/netbeans/modules/search/res/find.gif")); 282 initAccessibility(); 283 284 resultModelChanged(); 285 } 286 287 289 private static ResultTreeModel createTreeModel() { 290 ResultTreeModel treeModel = new ResultTreeModel(null); 291 treeModel.setRootDisplayName(getInitialRootNodeText()); 292 return treeModel; 293 } 294 295 297 private static JTree createTree(ResultTreeModel treeModel, 298 NodeListener nodeListener) { 299 JTree tree = new JTree (treeModel); 300 tree.setCellRenderer(new NodeRenderer(false)); 301 tree.putClientProperty("JTree.lineStyle", "Angled"); 303 tree.addMouseListener(nodeListener); 304 tree.addKeyListener(nodeListener); 305 tree.addTreeWillExpandListener(nodeListener); 306 tree.addTreeExpansionListener(nodeListener); 307 308 tree.setToggleClickCount(0); 309 310 return tree; 311 } 312 313 315 private static String getInitialRootNodeText() { 316 return NbBundle.getMessage(ResultView.class, 317 "TEXT_Search_in_filesystems"); } 319 320 322 @Override 323 public int getPersistenceType() { 324 return TopComponent.PERSISTENCE_ALWAYS; } 326 327 328 @Override 329 public Object writeReplace() { 330 return new ResolvableHelper(); 331 } 332 333 final public static class ResolvableHelper implements java.io.Serializable { 334 static final long serialVersionUID = 7398708142639457544L; 335 public Object readResolve() { 336 return ResultView.getDefault(); 337 } 338 } 339 340 346 private Object readResolve() throws java.io.ObjectStreamException { 347 return ResultView.getDefault(); 348 } 349 350 private void initAccessibility() { 351 ResourceBundle bundle = NbBundle.getBundle(ResultView.class); 352 getAccessibleContext ().setAccessibleName (bundle.getString ("ACSN_ResultViewTopComponent")); getAccessibleContext ().setAccessibleDescription (bundle.getString ("ACSD_ResultViewTopComponent")); 355 AccessibleContext accessCtx; 356 357 accessCtx = treeView.getHorizontalScrollBar().getAccessibleContext(); 358 accessCtx.setAccessibleName( 359 bundle.getString("ACSN_HorizontalScrollbar")); 361 accessCtx = treeView.getVerticalScrollBar().getAccessibleContext(); 362 accessCtx.setAccessibleName( 363 bundle.getString("ACSN_VerticalScrollbar")); 365 accessCtx = treeView.getAccessibleContext(); 366 accessCtx.setAccessibleName( 367 bundle.getString("ACSN_ResultTree")); accessCtx.setAccessibleDescription( 369 bundle.getString("ACSD_ResultTree")); 371 btnReplace.getAccessibleContext().setAccessibleDescription(bundle.getString("ACS_TEXT_BUTTON_REPLACE")); btnModifySearch.getAccessibleContext().setAccessibleDescription(bundle.getString("ACS_TEXT_BUTTON_CUSTOMIZE")); btnShowDetails.getAccessibleContext().setAccessibleDescription(bundle.getString("ACS_TEXT_BUTTON_FILL")); btnStop.getAccessibleContext().setAccessibleDescription(bundle.getString("ACS_TEXT_BUTTON_STOP")); } 376 377 382 void closeResults() { 383 close(); 384 } 385 386 387 public void fillOutput() { 388 btnShowDetails.setEnabled(false); 389 Manager.getInstance() 390 .schedulePrintingDetails(resultModel.getFoundObjects(), 391 resultModel.getSearchGroup()); 392 } 393 394 396 private void setRootDisplayName(String displayName) { 397 treeModel.setRootDisplayName(displayName); 398 } 399 400 @Override 401 protected void componentOpened() { 402 assert EventQueue.isDispatchThread(); 403 404 Manager.getInstance().searchWindowOpened(); 405 406 setRootDisplayName(getInitialRootNodeText()); 407 408 if (lastSearchNodes == null) { 409 btnModifySearch.setEnabled(false); 410 } 411 } 412 413 @Override 414 protected void componentClosed() { 415 assert EventQueue.isDispatchThread(); 416 417 rememberInput(null, null); 418 Manager.getInstance().searchWindowClosed(); 419 420 if (contextView != null) { 421 contextView.unbindFromTreeSelection(tree); 422 contextView = null; 423 } 424 if (splitPane != null) { 425 rememberDividerLocation(); 426 resultsPanel.remove(splitPane); 427 splitPane = null; 428 } 429 if (issuesPanel != null) { 430 removeIssuesPanel(); 431 } 432 contextViewVisible = false; 433 contextViewEnabled = SHOW_CONTEXT_BY_DEFAULT; 434 } 435 436 446 void notifySearchPending(final int blockingTask) { 447 assert EventQueue.isDispatchThread(); 448 449 removeIssuesPanel(); 450 451 String msgKey = null; 452 switch (blockingTask) { 453 case Manager.SEARCHING: 454 msgKey = "TEXT_FINISHING_PREV_SEARCH"; break; 456 case Manager.CLEANING_RESULT: 457 msgKey = "TEXT_CLEANING_RESULT"; break; 459 case Manager.PRINTING_DETAILS: 460 msgKey = "TEXT_PRINTING_DETAILS"; break; 462 default: 463 assert false; 464 } 465 setRootDisplayName(NbBundle.getMessage(ResultView.class, msgKey)); 466 btnStop.setEnabled(true); 467 btnReplace.setEnabled(false); 468 } 469 470 472 void searchTaskStateChanged(final int changeType) { 473 switch (changeType) { 474 case Manager.EVENT_SEARCH_STARTED: 475 searchStarted(); 476 break; 477 case Manager.EVENT_SEARCH_FINISHED: 478 searchFinished(); 479 break; 480 case Manager.EVENT_SEARCH_INTERRUPTED: 481 searchInterrupted(); 482 break; 483 case Manager.EVENT_SEARCH_CANCELLED: 484 searchCancelled(); 485 break; 486 default: 487 assert false; 488 } 489 } 490 491 493 void showAllDetailsFinished() { 494 assert EventQueue.isDispatchThread(); 495 496 updateShowAllDetailsBtn(); 497 } 498 499 501 private void searchStarted() { 502 assert EventQueue.isDispatchThread(); 503 504 removeIssuesPanel(); 505 506 setRootDisplayName(NbBundle.getMessage(ResultView.class, 507 "TEXT_SEARCHING___")); nodeCountFormat = new MessageFormat ( 509 NbBundle.getMessage(getClass(), 510 "TXT_RootSearchedNodes")); nodeCountFormatFullText = new MessageFormat ( 512 NbBundle.getMessage(getClass(), 513 "TXT_RootSearchedNodesFulltext")); 515 searchInProgress = true; 516 updateShowAllDetailsBtn(); 517 btnModifySearch.setEnabled(true); 518 btnStop.setEnabled(true); 519 btnReplace.setEnabled(false); 520 } 521 522 524 private void searchFinished() { 525 assert EventQueue.isDispatchThread(); 526 527 setFinalRootNodeText(); 528 529 searchInProgress = false; 530 hasDetails = (resultModel != null) ? resultModel.hasDetails() : false; 531 updateShowAllDetailsBtn(); 532 btnStop.setEnabled(false); 533 btnReplace.setEnabled(true); 534 } 535 536 538 private void searchInterrupted() { 539 assert EventQueue.isDispatchThread(); 540 541 searchFinished(); 542 } 543 544 546 private void searchCancelled() { 547 assert EventQueue.isDispatchThread(); 548 549 setRootDisplayName(NbBundle.getMessage(ResultView.class, 550 "TEXT_TASK_CANCELLED")); 552 searchInProgress = true; 553 updateShowAllDetailsBtn(); 554 btnStop.setEnabled(false); 555 btnReplace.setEnabled(true); 556 } 557 558 560 private void setFinalRootNodeText() { 561 assert EventQueue.isDispatchThread(); 562 563 int resultSize = resultModel.size(); 564 565 if (resultModel.wasLimitReached()) { 566 setRootDisplayName( 567 NbBundle.getMessage(ResultView.class, 568 "TEXT_MSG_FOUND_X_NODES_LIMIT", new Integer (resultSize))); 570 return; 571 } 572 573 String baseMsg; 574 if (resultSize == 0) { 575 baseMsg = NbBundle.getMessage(ResultView.class, 576 "TEXT_MSG_NO_NODE_FOUND"); } else { 578 String bundleKey; 579 Object [] args; 580 if (resultModel.searchAndReplace) { 581 bundleKey = "TEXT_MSG_FOUND_X_NODES_REPLACE"; args = new Object [4]; 583 } else if (resultModel.fullTextOnly) { 584 bundleKey = "TEXT_MSG_FOUND_X_NODES_FULLTEXT"; args = new Object [2]; 586 } else { 587 bundleKey = "TEXT_MSG_FOUND_X_NODES"; args = new Object [1]; 589 } 590 args[0] = new Integer (objectsCount); 591 if (args.length > 1) { 592 args[1] = new Integer (resultModel.getTotalDetailsCount()); 593 } 594 if (args.length > 2) { 595 args[2] = resultModel.fullTextSearchType.getMatchTemplateDescr(); 596 args[3] = resultModel.fullTextSearchType.getReplaceString(); 597 } 598 baseMsg = NbBundle.getMessage(getClass(), bundleKey, args); 599 } 600 String exMsg = resultModel.getExceptionMsg(); 601 String msg = exMsg == null ? baseMsg 602 : baseMsg + " (" + exMsg + ")"; setRootDisplayName(msg); 604 } 605 606 608 private void updateShowAllDetailsBtn() { 609 assert EventQueue.isDispatchThread(); 610 611 btnShowDetails.setEnabled(hasResults 612 && !searchInProgress 613 && hasDetails); 614 } 615 616 617 void setResultModel(final ResultModel resultModel) { 618 assert EventQueue.isDispatchThread(); 619 620 if ((this.resultModel == null) && (resultModel == null)) { 621 return; 622 } 623 624 boolean hadCheckBoxes = (this.resultModel != null) 625 && this.resultModel.searchAndReplace; 626 boolean hasCheckBoxes = (resultModel != null) 627 && resultModel.searchAndReplace; 628 629 this.resultModel = resultModel; 631 tree.setModel(treeModel = new ResultTreeModel(resultModel)); 632 if (hasCheckBoxes != hadCheckBoxes) { 633 tree.setCellRenderer(new NodeRenderer(hasCheckBoxes)); 634 btnReplace.setVisible(hasCheckBoxes); 635 } 636 if (resultModel != null) { 637 hasResults = !resultModel.isEmpty(); 638 hasDetails = hasResults && resultModel.hasDetails(); 639 resultModel.setObserver(this); 640 } else { 641 hasResults = false; 642 hasDetails = false; 643 } 644 645 resultModelChanged(); 646 647 updateShowAllDetailsBtn(); 648 } 649 650 652 private void resultModelChanged() { 653 updateDisplayContextButton(); 654 updateContextViewVisibility(); 655 if (contextView != null) { 656 contextView.setResultModel(resultModel); 657 } 658 nodeListener.setSelectionChangeEnabled(true); 659 660 btnPrev.setEnabled(resultModel != null); 661 btnNext.setEnabled(resultModel != null); 662 resetMatchingObjIndexCache(); 663 664 objectsCount = 0; 665 } 666 667 674 private boolean isSearchAndReplace() { 675 return (resultModel != null) && resultModel.searchAndReplace; 676 } 677 678 684 private void updateDisplayContextButton() { 685 boolean searchAndReplace = isSearchAndReplace(); 686 btnDisplayContext.setEnabled(searchAndReplace); 687 688 ignoreContextButtonToggle = true; 689 try { 690 btnDisplayContext.setSelected(searchAndReplace 691 && contextViewEnabled); 692 } finally { 693 ignoreContextButtonToggle = false; 694 } 695 } 696 697 703 private void updateContextViewVisibility() { 704 setContextViewVisible(isSearchAndReplace() && contextViewEnabled); 705 } 706 707 710 private void setContextViewVisible(boolean visible) { 711 assert EventQueue.isDispatchThread(); 712 assert (splitPane == null) == (contextView == null); 713 714 final int componentCount = resultsPanel.getComponentCount(); 715 if ((visible == contextViewVisible) && (componentCount != 0)) { 716 return; 717 } 718 719 this.contextViewVisible = visible; 720 721 final String cardName; 722 if (visible == false) { 723 cardName = "tree only"; 733 assert componentCount < 2; 734 738 resultsPanel.add(treeView, cardName); 739 if (contextView != null) { 740 contextView.unbindFromTreeSelection(tree); 741 rememberDividerLocation(); 742 } 743 } else { 744 assert resultModel != null; 745 746 cardName = "tree and context"; if (splitPane == null) { 748 contextView = new ContextView(resultModel); 749 splitPane = new JSplitPane (JSplitPane.HORIZONTAL_SPLIT, 750 true, treeView, contextView); splitPane.setBorder(BorderFactory.createEmptyBorder()); 754 splitPane.setResizeWeight(0.4d); 755 resultsPanel.add(splitPane, cardName); 756 } else { 757 761 splitPane.setLeftComponent(treeView); 762 } 763 setDividerLocation(); 764 contextView.bindToTreeSelection(tree); 765 } 766 775 resultViewCards.show(resultsPanel, cardName); 776 treeView.setVisible(true); 777 } 778 779 781 private void rememberDividerLocation() { 782 if (splitPane == null) { 783 return; 784 } 785 786 dividerLocation 787 = (double) splitPane.getDividerLocation() 788 / (double) (splitPane.getWidth() - splitPane.getDividerSize()); 789 } 790 791 793 private void setDividerLocation() { 794 assert splitPane != null; 795 796 if (dividerLocation != -1.0d) { 797 splitPane.setDividerLocation(dividerLocation); 798 } 799 } 800 801 803 void objectFound(Object foundObject, final int totalDetailsCount) { 804 assert !EventQueue.isDispatchThread(); 805 806 EventQueue.invokeLater(new Runnable () { 807 public void run() { 808 updateObjectsCount(totalDetailsCount); 809 } 810 }); 811 } 812 813 816 private void updateObjectsCount(final int totalDetailsCount) { 817 assert EventQueue.isDispatchThread(); 818 819 objectsCount++; 820 hasResults = true; 821 822 setRootDisplayName( 823 resultModel.fullTextOnly 824 ? nodeCountFormatFullText.format( 825 new Object [] {new Integer (objectsCount), 826 new Integer (totalDetailsCount)}) 827 : nodeCountFormat.format( 828 new Object [] {new Integer (objectsCount)})); 829 } 830 831 833 void removeIssuesPanel() { 834 if (issuesPanel != null) { 835 remove(issuesPanel); 836 issuesPanel = null; 837 } 838 contentCards.show(this, RESULTS_CARD); 839 } 840 841 848 private void goToNext(final boolean forward) { 849 assert EventQueue.isDispatchThread(); 850 assert resultModel != null; 851 852 if (!hasResults) { 853 return; 854 } 855 856 TreePath leadPath = tree.getLeadSelectionPath(); 857 if (leadPath == null) { 858 leadPath = new TreePath (tree.getModel().getRoot()); 859 } 860 861 final TreePath nextPath = findNextPath(leadPath, forward); 862 863 if (nextPath != null) { 864 870 tree.expandPath(nextPath.getParentPath()); 871 872 tree.setSelectionPath(nextPath); 873 tree.scrollRectToVisible(tree.getPathBounds(nextPath)); 874 } 875 } 876 877 879 private TreePath findNextPath(final TreePath forPath, 880 final boolean forward) { 881 TreePath nextPath; 882 883 Object root; 884 TreePath parentPath = forPath.getParentPath(); 885 if (parentPath == null) { root = forPath.getLastPathComponent(); 887 nextPath = forward ? getNextDetail(root, null, -1, forward) : null; 888 } else { 889 MatchingObject matchingObj; 890 Object lastComp = forPath.getLastPathComponent(); 891 if (lastComp.getClass() == MatchingObject.class) { 892 root = parentPath.getLastPathComponent(); 893 matchingObj = (MatchingObject) lastComp; 894 nextPath = getNextDetail(root, matchingObj, -1, forward); 895 } else { 896 root = parentPath.getParentPath().getLastPathComponent(); 897 Object parentComp = parentPath.getLastPathComponent(); 898 assert parentComp.getClass() == MatchingObject.class; 899 matchingObj = (MatchingObject) parentComp; 900 901 int parentPathRow = tree.getRowForPath(parentPath); 902 int row = tree.getRowForPath(forPath); 903 int index = row - parentPathRow - 1; 904 nextPath = getNextDetail(root, matchingObj, index, forward); 905 } 906 } 907 908 return nextPath; 909 } 910 911 927 private TreePath getNextDetail(final Object root, 928 final MatchingObject matchingObj, 929 final int detailIndex, 930 final boolean forward) { 931 if (matchingObj != null) { 932 int nextDetailIndex = forward ? detailIndex + 1 933 : detailIndex - 1; 934 if ((nextDetailIndex >= 0) 935 && (nextDetailIndex < resultModel.getDetailsCount( 936 matchingObj))) { 937 return new TreePath (new Object [] { 938 root, 939 matchingObj, 940 resultModel.getDetails(matchingObj)[nextDetailIndex]}); 941 } 942 } else if (!forward) { 943 return null; 944 } 945 946 final MatchingObject[] matchingObjs = resultModel.getMatchingObjects(); 947 int currMatchingObjIndex = getMatchingObjIndex(matchingObjs, 948 matchingObj, 949 forward); 950 MatchingObject nextMatchingObj; 951 int i; 952 953 if (forward) { 954 for (i = currMatchingObjIndex + 1; i < matchingObjs.length; i++) { 955 nextMatchingObj = matchingObjs[i]; 956 if (resultModel.hasDetails(nextMatchingObj)) { 957 return new TreePath (new Object [] { 958 root, 959 nextMatchingObj, 960 resultModel.getDetails(nextMatchingObj)[0]}); 961 } 962 } 963 } else { 964 for (i = currMatchingObjIndex - 1; i >= 0; i--) { 965 nextMatchingObj = matchingObjs[i]; 966 if (resultModel.hasDetails(nextMatchingObj)) { 967 Node[] details = resultModel.getDetails(nextMatchingObj); 968 return new TreePath (new Object [] { 969 root, 970 nextMatchingObj, 971 details[details.length - 1]}); 972 } 973 } 974 } 975 return null; 976 } 977 978 private MatchingObject matchingObjIndexCacheObj = null; 979 private int matchingObjIndexCacheIndex = -1; 980 981 983 private void resetMatchingObjIndexCache() { 984 matchingObjIndexCacheObj = null; 985 matchingObjIndexCacheIndex = -1; 986 } 987 988 990 private int getMatchingObjIndex(final MatchingObject[] matchingObjs, 991 final MatchingObject matchingObj, 992 final boolean forward) { 993 if (matchingObj == null) { 994 return -1; 995 } 996 997 if (matchingObj == matchingObjIndexCacheObj) { 998 assert (matchingObjIndexCacheIndex != -1); 999 return matchingObjIndexCacheIndex; 1000 } 1001 1002 int foundIndex = -1; 1003 1004 1005 if (matchingObjIndexCacheIndex != -1) { 1006 final int quickSearchRange = 3; 1007 int startIndex; 1008 int endIndex; 1009 int i; 1010 if (forward) { 1011 startIndex = Math.min(matchingObjIndexCacheIndex + 1, 1012 matchingObjs.length - 1); 1013 endIndex = Math.min( 1014 matchingObjIndexCacheIndex + quickSearchRange, 1015 matchingObjs.length - 1); 1016 for (i = startIndex; i <= endIndex; i++) { 1017 if (matchingObjs[i] == matchingObj) { 1018 foundIndex = i; 1019 break; 1020 } 1021 } 1022 if ((foundIndex == -1) && (matchingObjIndexCacheIndex > 0)) { 1023 if (matchingObjs[i = matchingObjIndexCacheIndex - 1] 1024 == matchingObj) { 1025 foundIndex = i; 1026 } 1027 } 1028 } else { 1029 startIndex = Math.max(matchingObjIndexCacheIndex - 1, 0); 1030 endIndex = Math.max( 1031 matchingObjIndexCacheIndex - quickSearchRange, 1032 0); 1033 for (i = startIndex; i >= endIndex; i--) { 1034 if (matchingObjs[i] == matchingObj) { 1035 foundIndex = i; 1036 break; 1037 } 1038 } 1039 if ((foundIndex == -1) 1040 && (matchingObjIndexCacheIndex < matchingObjs.length - 1)) { 1041 if (matchingObjs[i = matchingObjIndexCacheIndex + 1] 1042 == matchingObj) { 1043 foundIndex = i; 1044 } 1045 } 1046 } 1047 } 1048 1049 1050 if (foundIndex == -1) { 1051 for (int i = 0; i < matchingObjs.length; i++) { 1052 if (matchingObj == matchingObjs[i]) { 1053 foundIndex = i; 1054 break; 1055 } 1056 } 1057 } 1058 1059 1060 if (foundIndex != -1) { 1061 matchingObjIndexCacheObj = matchingObj; 1062 matchingObjIndexCacheIndex = foundIndex; 1063 } 1064 1065 return foundIndex; 1066 } 1067 1068 1070 void rememberInput(Node[] nodes, 1071 List enabledSearchTypes) { 1072 lastSearchNodes = nodes; 1073 lastEnabledSearchTypes = enabledSearchTypes; 1074 } 1075 1076 1077 private void customizeCriteria() { 1078 assert EventQueue.isDispatchThread(); 1079 1080 Node[] nodesToSearch; 1081 List searchTypes; 1082 1083 assert (lastSearchNodes != null); 1084 nodesToSearch = lastSearchNodes; 1085 searchTypes = lastEnabledSearchTypes; 1086 1087 1098 1099 1100 List searchTypesClone = new ArrayList (searchTypes.size()); 1101 for (Iterator it = searchTypes.iterator(); it.hasNext(); ) { 1102 searchTypesClone.add(((SearchType) it.next()).clone()); 1103 } 1104 1105 lastEnabledSearchTypes = searchTypesClone; 1106 1107 SearchPanel searchPanel = new SearchPanel(searchTypesClone, true); 1108 searchPanel.showDialog(); 1109 1110 if (searchPanel.getReturnStatus() != SearchPanel.RET_OK) { 1111 return; 1112 } 1113 1114 rememberInput(nodesToSearch, 1115 Utils.cloneSearchTypes(searchTypesClone)); 1116 1117 Manager.getInstance().scheduleSearchTask( 1118 new SearchTask(nodesToSearch, 1119 searchTypesClone, 1120 searchPanel.getCustomizedSearchTypes())); 1121 } 1122 1123 1126 private void replaceMatches() { 1127 assert EventQueue.isDispatchThread(); 1128 1129 nodeListener.setSelectionChangeEnabled(false); 1130 btnReplace.setEnabled(false); 1131 1132 Manager.getInstance().scheduleReplaceTask( 1133 new ReplaceTask(resultModel.getMatchingObjects())); 1134 } 1135 1136 1138 void closeAndSendFocusToEditor() { 1139 assert EventQueue.isDispatchThread(); 1140 1141 close(); 1142 1143 Mode m = WindowManager.getDefault().findMode("editor"); if (m != null) { 1145 TopComponent tc = m.getSelectedTopComponent(); 1146 if (tc != null) { 1147 tc.requestActive(); 1148 } 1149 } 1150 } 1151 1152 1154 void displayIssuesToUser(String title, String [] problems, boolean reqAtt) { 1155 assert EventQueue.isDispatchThread(); 1156 assert issuesPanel == null; 1157 1158 issuesPanel = new IssuesPanel(title, problems); 1159 add(issuesPanel, ISSUES_CARD); 1160 contentCards.show(this, ISSUES_CARD); 1161 1162 if (!isOpened()) { 1163 open(); 1164 } 1165 if (reqAtt) { 1166 requestAttention(true); 1167 } 1168 } 1169 1170 1172 void rescan() { 1173 assert EventQueue.isDispatchThread(); 1174 1175 removeIssuesPanel(); 1176 Manager.getInstance().scheduleSearchTaskRerun(); 1177 } 1178 1179 @Override 1180 protected String preferredID() { 1181 return getClass().getName(); 1182 } 1183 1184 1186 private class ButtonListener implements ActionListener , ItemListener { 1187 1188 public void actionPerformed(ActionEvent e) { 1189 Object source = e.getSource(); 1190 if (source == btnStop) { 1191 Manager.getInstance().stopSearching(); 1192 } else if (source == btnModifySearch) { 1193 customizeCriteria(); 1194 } else if (source == btnShowDetails) { 1195 fillOutput(); 1196 } else if (source == btnReplace) { 1197 replaceMatches(); 1198 } else if (source == btnPrev) { 1199 goToNext(false); 1200 } else if (source == btnNext) { 1201 goToNext(true); 1202 } else { 1203 assert false; 1204 } 1205 } 1206 1207 1210 public void itemStateChanged(ItemEvent e) { 1211 assert e.getSource() == btnDisplayContext; 1212 if (!ignoreContextButtonToggle) { 1213 contextViewEnabled = (e.getStateChange() == ItemEvent.SELECTED); 1214 updateContextViewVisibility(); 1215 } 1216 } 1217 1218 } 1219 1220} | Popular Tags |