diff --git a/api.search/apichanges.xml b/api.search/apichanges.xml new file mode 100644 --- /dev/null +++ b/api.search/apichanges.xml @@ -0,0 +1,192 @@ + + + + + + + + + + + + + Search in Projects API + + + + + + + + Added class + SearchPatternController + + + + + + +

+ Added method + ComponentUtils.adjustComboForSearchPattern + and class + SearchPatternController, that complements + other controllers for search-related UI components/ +

+
+ + +
+ + + Added class + DefaultSearchResultsDisplayer + + + + + + +

+ Method + SearchResultsDisplayer.createDefault now + returns object of type + DefaultSearchResultsDisplayer + that can be customized, and that let users reuse some features + used in the standard search provider. +

+
+ +
+
+ + + + + + + Change History for the Search API + + + + + + +

Introduction

+ +

+ This document lists changes made to the + Search API. +

+ + + +
+ + + +
+ +

@FOOTER@

+ + +
+
diff --git a/api.search/manifest.mf b/api.search/manifest.mf --- a/api.search/manifest.mf +++ b/api.search/manifest.mf @@ -2,5 +2,5 @@ OpenIDE-Module: org.netbeans.api.search OpenIDE-Module-Install: org/netbeans/api/search/impl/Installer.class OpenIDE-Module-Localizing-Bundle: org/netbeans/api/search/Bundle.properties -OpenIDE-Module-Specification-Version: 1.0 +OpenIDE-Module-Specification-Version: 1.1 diff --git a/api.search/src/org/netbeans/api/search/SearchHistory.java b/api.search/src/org/netbeans/api/search/SearchHistory.java --- a/api.search/src/org/netbeans/api/search/SearchHistory.java +++ b/api.search/src/org/netbeans/api/search/SearchHistory.java @@ -50,6 +50,7 @@ import java.util.Collections; import java.util.List; import java.util.prefs.Preferences; +import org.netbeans.modules.search.FindDialogMemory; import org.openide.util.NbPreferences; /** @@ -207,4 +208,16 @@ } } + /** + * Store last used file name pattern. + */ + public void storeFileNamePattern(String pattern) { + FindDialogMemory mem = FindDialogMemory.getDefault(); + if (pattern == null) { + mem.setFileNamePatternSpecified(false); + } else { + mem.setFileNamePatternSpecified(true); + mem.storeFileNamePattern(pattern); + } + } } diff --git a/api.search/src/org/netbeans/api/search/ui/ComponentUtils.java b/api.search/src/org/netbeans/api/search/ui/ComponentUtils.java --- a/api.search/src/org/netbeans/api/search/ui/ComponentUtils.java +++ b/api.search/src/org/netbeans/api/search/ui/ComponentUtils.java @@ -136,4 +136,20 @@ return new ScopeOptionsController(jPanel, fileNameController, searchAndReplace); } + + /** + * Adjust a {@link JComboBox} to act as component for selecting search text + * pattern, and return a controller object for interacting with it. + * + * You can bind this combo box with some abstract buttons (usually check + * boxes) to set pattern options. + * + * @param jComboBox Freshly created component that will be adjusted. + * @return Controller for modified {@code jComboBox}. + * @since api.search/1.1 + */ + public static @NonNull SearchPatternController adjustComboForSearchPattern( + @NonNull JComboBox comboBox) { + return new SearchPatternController(comboBox); + } } diff --git a/api.search/src/org/netbeans/api/search/ui/SearchPatternController.java b/api.search/src/org/netbeans/api/search/ui/SearchPatternController.java new file mode 100644 --- /dev/null +++ b/api.search/src/org/netbeans/api/search/ui/SearchPatternController.java @@ -0,0 +1,360 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2012 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2012 Sun Microsystems, Inc. + */ +package org.netbeans.api.search.ui; + +import java.awt.Color; +import java.awt.Component; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; +import javax.swing.AbstractButton; +import javax.swing.DefaultComboBoxModel; +import javax.swing.JComboBox; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.JTextComponent; +import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.api.annotations.common.NullAllowed; +import org.netbeans.api.search.SearchHistory; +import org.netbeans.api.search.SearchPattern; +import org.netbeans.modules.search.ui.PatternChangeListener; +import org.netbeans.modules.search.ui.TextFieldFocusListener; +import org.netbeans.modules.search.ui.UiUtils; +import org.openide.util.Parameters; + +/** + * Controller for a combo box for selection and editing of search patterns. + * + * @author jhavlin + * @since api.search/1.1 + */ +public final class SearchPatternController + extends ComponentController { + + private JTextComponent textToFindEditor; + + /** + * Options of search patterns. + */ + public enum Option { + MATCH_CASE, WHOLE_WORDS, REGULAR_EXPRESSION + } + private final Map bindings = + new EnumMap(Option.class); + private final Map options = + new EnumMap(Option.class); + private final ItemListener listener; + private boolean valid; + private Color defaultTextColor = null; + + SearchPatternController(final JComboBox component) { + super(component); + component.setEditable(true); + Component cboxEditorComp = component.getEditor().getEditorComponent(); + textToFindEditor = (JTextComponent) cboxEditorComp; + textToFindEditor.getDocument().addDocumentListener( + new DocumentListener() { + @Override + public void insertUpdate(DocumentEvent e) { + patternChanged(); + } + + @Override + public void removeUpdate(DocumentEvent e) { + patternChanged(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + patternChanged(); + } + }); + initHistory(); + valid = checkValid(); + updateTextPatternColor(); + textToFindEditor.addFocusListener(new TextFieldFocusListener()); + textToFindEditor.getDocument().addDocumentListener( + new TextToFindChangeListener()); + + component.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + Object si = component.getSelectedItem(); + if (si instanceof ModelItem) { + SearchPattern sp = ((ModelItem) si).sp; + for (Map.Entry be : + bindings.entrySet()) { + switch (be.getKey()) { + case MATCH_CASE: + be.getValue().setSelected(sp.isMatchCase()); + break; + case WHOLE_WORDS: + be.getValue().setSelected(sp.isWholeWords()); + break; + case REGULAR_EXPRESSION: + be.getValue().setSelected(sp.isRegExp()); + break; + } + } + options.put(Option.MATCH_CASE, sp.isMatchCase()); + options.put(Option.WHOLE_WORDS, sp.isWholeWords()); + options.put(Option.REGULAR_EXPRESSION, sp.isRegExp()); + } + } + }); + + listener = new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + for (Map.Entry entry : + bindings.entrySet()) { + if (entry.getValue() == e.getSource()) { + setOption(entry.getKey(), + e.getStateChange() == ItemEvent.SELECTED); + break; + } + } + } + }; + } + + private void initHistory() { + final DefaultComboBoxModel model = new DefaultComboBoxModel(); + final List data = + SearchHistory.getDefault().getSearchPatterns(); + + for (SearchPattern sp : data) { + model.addElement(new ModelItem(sp)); + } + + component.setModel(model); + + if (data.size() > 0) { + setSearchPattern(data.get(0)); + } + } + + /** + * Get text currently shown in the combo box editor. + */ + private @NonNull String getText() { + String s = textToFindEditor.getText(); + return s == null ? "" : s; //NOI18N + } + + /** + * Set text to show in combo box editor + * + * @param text Text to show in the component editor. + */ + private void setText(@NullAllowed String text) { + component.setSelectedItem(text == null ? "" : text); //NOI18N + } + + /** + * Request focus in window. Select text in the combo box editor if it is not + * empty. + */ + public boolean requestFocusInWindow() { + if (textToFindEditor.isFocusOwner()) { + return true; + } else { + return textToFindEditor.requestFocusInWindow(); + } + } + + /** + * Get current value of an option of the search pattern. + */ + private boolean getOption(@NonNull Option option) { + Parameters.notNull("option", option); //NOI18N + Boolean b = options.get(option); + if (b == null) { + return false; + } else { + return b.booleanValue(); + } + } + + /** + * Set value of a search pattern option. Bound abstract button will be + * selected or deselected accordingly. + */ + private void setOption(@NonNull Option option, boolean value) { + Parameters.notNull("option", option); //NOI18N + options.put(option, value); + AbstractButton button = bindings.get(option); + if (button != null) { + button.setSelected(value); + } + if (option == Option.REGULAR_EXPRESSION) { + updateValidity(); + } + fireChange(); + } + + /** + * Get search pattern currently represented by this controller. + */ + public @NonNull SearchPattern getSearchPattern() { + return SearchPattern.create(getText(), + getOption(Option.WHOLE_WORDS), + getOption(Option.MATCH_CASE), + getOption(Option.REGULAR_EXPRESSION)); + } + + /** + * Set text and options to represent a search pattern. + */ + public void setSearchPattern(@NonNull SearchPattern searchPattern) { + Parameters.notNull("searchPattern", searchPattern); //NOI18N + setText(searchPattern.getSearchExpression()); + setOption(Option.WHOLE_WORDS, searchPattern.isWholeWords()); + setOption(Option.MATCH_CASE, searchPattern.isMatchCase()); + setOption(Option.REGULAR_EXPRESSION, searchPattern.isRegExp()); + } + + /** + * Bind an abstract button (usually checkbox) to a SearchPattern option. + * + * @param option Option whose value the button should represent. + * @param button Button to control and display the option. + */ + public void bind(@NonNull final Option option, + @NonNull final AbstractButton button) { + Parameters.notNull("option", option); //NOI18N + Parameters.notNull("button", button); //NOI18N + + if (bindings.containsKey(option)) { + throw new IllegalStateException( + "Already binded with option " + option); // NOI18N + } + + bindings.put(option, button); + button.setSelected(getOption(option)); + button.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + setOption(option, button.isSelected()); + } + }); + } + + /** + * Unbind a button from a SearchPattern option. + */ + public void unbind(@NonNull Option option, @NonNull AbstractButton button) { + Parameters.notNull("option", option); //NOI18N + Parameters.notNull("button", button); //NOI18N + bindings.remove(option); + button.removeItemListener(listener); + } + + private class TextToFindChangeListener extends PatternChangeListener { + + @Override + public void handleComboBoxChange(String text) { + patternChanged(); + } + } + + private void patternChanged() { + updateValidity(); + fireChange(); + } + + private void updateValidity() { + boolean wasValid = valid; + valid = checkValid(); + if (valid != wasValid) { + updateTextPatternColor(); + } + } + + private boolean checkValid() { + String expr = getText(); + if (!getOption(Option.REGULAR_EXPRESSION) || expr == null) { + return true; + } else { + try { + Pattern p = Pattern.compile(getText()); + return true; + } catch (PatternSyntaxException p) { + return false; + } + } + } + + /** + * Sets proper color of text pattern. + */ + private void updateTextPatternColor() { + Color dfltColor = getDefaultTextColor(); // need to be here to init + textToFindEditor.setForeground( + valid ? dfltColor : UiUtils.getErrorTextColor()); + } + + private Color getDefaultTextColor() { + if (defaultTextColor == null) { + defaultTextColor = component.getForeground(); + } + return defaultTextColor; + } + + private static class ModelItem { + + final SearchPattern sp; + + public ModelItem(SearchPattern sp) { + this.sp = sp; + } + + @Override + public String toString() { + return sp.getSearchExpression(); + } + } +} diff --git a/api.search/src/org/netbeans/modules/search/BasicSearchForm.java b/api.search/src/org/netbeans/modules/search/BasicSearchForm.java --- a/api.search/src/org/netbeans/modules/search/BasicSearchForm.java +++ b/api.search/src/org/netbeans/modules/search/BasicSearchForm.java @@ -52,7 +52,6 @@ import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; -import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; import javax.swing.*; @@ -66,6 +65,8 @@ import org.netbeans.api.search.ui.FileNameController; import org.netbeans.api.search.ui.ScopeController; import org.netbeans.api.search.ui.ScopeOptionsController; +import org.netbeans.api.search.ui.SearchPatternController; +import org.netbeans.api.search.ui.SearchPatternController.Option; import org.netbeans.modules.search.ui.CheckBoxWithButtonPanel; import org.netbeans.modules.search.ui.FormLayoutHelper; import org.netbeans.modules.search.ui.PatternChangeListener; @@ -125,7 +126,6 @@ } else { initValuesFromHistory(searchAndReplace); } - updateTextPatternColor(); if (searchAndReplace) { updateReplacePatternColor(); } @@ -144,13 +144,16 @@ if (recentPane != null) { String initSearchText = recentPane.getSelectedText(); if (initSearchText != null) { - cboxTextToFind.setSelectedIndex(-1); - textToFindEditor.setText(initSearchText); + cboxTextToFind.setSearchPattern(SearchPattern.create( + initSearchText, false, false, false)); searchCriteria.setTextPattern(initSearchText); + return; } } } } + searchCriteria.setTextPattern( + cboxTextToFind.getSearchPattern().getSearchExpression()); } /** This method is called from within the constructor to @@ -165,9 +168,8 @@ private void initComponents(final boolean searchAndReplace) { lblTextToFind = new JLabel(); - cboxTextToFind = new JComboBox(); - cboxTextToFind.setEditable(true); - lblTextToFind.setLabelFor(cboxTextToFind); + cboxTextToFind = ComponentUtils.adjustComboForSearchPattern(new JComboBox()); + lblTextToFind.setLabelFor(cboxTextToFind.getComponent()); btnTestTextToFind = new JButton(); if (searchAndReplace) { @@ -202,8 +204,6 @@ /* find the editor components of combo-boxes: */ Component cboxEditorComp; - cboxEditorComp = cboxTextToFind.getEditor().getEditorComponent(); - textToFindEditor = (JTextComponent) cboxEditorComp; if (cboxReplacement != null) { cboxEditorComp = cboxReplacement.getEditor().getEditorComponent(); replacementPatternEditor = (JTextComponent) cboxEditorComp; @@ -217,7 +217,7 @@ protected void initFormPanel(boolean searchAndReplace) { formPanel = new SearchFormPanel(); - formPanel.addRow(lblTextToFind, cboxTextToFind); + formPanel.addRow(lblTextToFind, cboxTextToFind.getComponent()); initContainingTextOptionsRow(searchAndReplace); if (searchAndReplace) { formPanel.addRow(lblReplacement, cboxReplacement); @@ -294,15 +294,12 @@ */ private void initValuesFromCriteria(BasicSearchCriteria initialCriteria, boolean searchAndReplace) { - cboxTextToFind.setSelectedItem(initialCriteria.getTextPatternExpr()); + cboxTextToFind.setSearchPattern(initialCriteria.getSearchPattern()); if (cboxReplacement != null) { cboxReplacement.setSelectedItem(initialCriteria.getReplaceExpr()); } selectChk(chkPreserveCase, initialCriteria.isPreserveCase()); - chkWholeWords.setSelected(initialCriteria.isWholeWords()); - chkCaseSensitive.setSelected(initialCriteria.isCaseSensitive()); - chkRegexp.setSelected(initialCriteria.isRegexp()); scopeSettingsPanel.setFileNameRegexp(initialCriteria.isFileNameRegexp()); scopeSettingsPanel.setUseIgnoreList(initialCriteria.isUseIgnoreList()); cboxFileNamePattern.setRegularExpression(initialCriteria.isFileNameRegexp()); @@ -328,21 +325,19 @@ final TextFieldFocusListener focusListener = new TextFieldFocusListener(); - textToFindEditor.addFocusListener(focusListener); if (replacementPatternEditor != null) { replacementPatternEditor.addFocusListener(focusListener); } - textToFindEditor.getDocument().addDocumentListener( - new TextToFindChangeListener()); if (replacementPatternEditor != null) { replacementPatternEditor.getDocument().addDocumentListener( new ReplacementPatternListener()); } chkRegexp.addItemListener(this); - chkCaseSensitive.addItemListener(this); - chkWholeWords.addItemListener(this); + cboxTextToFind.bind(Option.REGULAR_EXPRESSION, chkRegexp); + cboxTextToFind.bind(Option.MATCH_CASE, chkCaseSensitive); + cboxTextToFind.bind(Option.WHOLE_WORDS, chkWholeWords); boolean regexp = chkRegexp.isSelected(); boolean caseSensitive = chkCaseSensitive.isSelected(); @@ -376,6 +371,17 @@ cboxFileNamePattern.isRegularExpression()); } }); + + cboxTextToFind.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + SearchPattern sp = cboxTextToFind.getSearchPattern(); + searchCriteria.setTextPattern(sp.getSearchExpression()); + searchCriteria.setRegexp(sp.isRegExp()); + searchCriteria.setWholeWords(sp.isWholeWords()); + searchCriteria.setCaseSensitive(sp.isMatchCase()); + } + }); initButtonInteraction(); } @@ -392,8 +398,9 @@ private void openTextPatternSandbox() { - String expr = cboxTextToFind.getSelectedItem() == null ? "" // NOI18N - : cboxTextToFind.getSelectedItem().toString(); + SearchPattern sp = cboxTextToFind.getSearchPattern(); + String expr = sp.getSearchExpression() == null ? "" // NOI18N + : sp.getSearchExpression(); boolean matchCase = chkCaseSensitive.isSelected(); PatternSandbox.openDialog(new PatternSandbox.TextPatternSandbox( @@ -401,8 +408,8 @@ @Override protected void onApply(String newExpr, boolean newMatchCase) { - cboxTextToFind.setSelectedItem(newExpr); - chkCaseSensitive.setSelected(newMatchCase); + cboxTextToFind.setSearchPattern(SearchPattern.create( + newExpr, false, newMatchCase, true)); } }, btnTestTextToFind); } @@ -412,15 +419,6 @@ * expressions. The combo-boxes' text-fields remain empty. */ private void initHistory() { - final List patterns - = SearchHistory.getDefault().getSearchPatterns(); - if (!patterns.isEmpty()) { - List itemsList = new ArrayList(patterns.size()); - for (SearchPattern pattern : patterns) { - itemsList.add(pattern.getSearchExpression()); - } - cboxTextToFind.setModel(new ListComboBoxModel(itemsList)); - } FindDialogMemory memory = FindDialogMemory.getDefault(); List entries; @@ -438,10 +436,6 @@ private void initValuesFromHistory(final boolean searchAndReplace) { final FindDialogMemory memory = FindDialogMemory.getDefault(); - if (memory.isTextPatternSpecified() - && (cboxTextToFind.getItemCount() != 0)) { - cboxTextToFind.setSelectedIndex(0); - } if (memory.isFileNamePatternSpecified() && cboxFileNamePattern.getComponent().getItemCount() != 0) { cboxFileNamePattern.getComponent().setSelectedIndex(0); @@ -467,40 +461,7 @@ @Override public boolean requestFocusInWindow() { - assert textToFindEditor != null; - - if (textToFindEditor.isFocusOwner()) { - return true; - } - - int textLength = textToFindEditor.getText().length(); - if (textLength > 0) { - textToFindEditor.setCaretPosition(0); - textToFindEditor.moveCaretPosition(textLength); - } - - return textToFindEditor.requestFocusInWindow(); - } - - /** - * Sets proper color of text pattern. - */ - private void updateTextPatternColor() { - boolean wasInvalid = invalidTextPattern; - invalidTextPattern = searchCriteria.isTextPatternInvalid(); - if (invalidTextPattern != wasInvalid) { - Color dfltColor = getDefaultTextColor(); // need to be here to init - textToFindEditor.setForeground( - invalidTextPattern ? getErrorTextColor() - : dfltColor); - } - } - - private Color getDefaultTextColor() { - if (defaultTextColor == null) { - defaultTextColor = textToFindEditor.getForeground(); - } - return defaultTextColor; + return cboxTextToFind.requestFocusInWindow(); } /** @@ -512,7 +473,7 @@ if (invalidReplacePattern != wasInvalid) { if (defaultTextColor == null) { assert !wasInvalid; - defaultTextColor = textToFindEditor.getForeground(); + defaultTextColor = cboxReplacement.getForeground(); } replacementPatternEditor.setForeground( invalidReplacePattern ? getErrorTextColor() @@ -573,16 +534,10 @@ final ItemSelectable toggle = e.getItemSelectable(); final boolean selected = (e.getStateChange() == ItemEvent.SELECTED); if (toggle == chkRegexp) { - searchCriteria.setRegexp(selected); - updateTextPatternColor(); if (cboxReplacement != null){ updateReplacePatternColor(); } setTextToFindToolTip(); - } else if (toggle == chkCaseSensitive) { - searchCriteria.setCaseSensitive(selected); - } else if (toggle == chkWholeWords) { - searchCriteria.setWholeWords(selected); } else if (toggle == chkPreserveCase) { searchCriteria.setPreserveCase(selected); } else { @@ -598,7 +553,7 @@ t = UiUtils.getText( "BasicSearchForm.cboxTextToFind.tooltip"); //NOI18N } - cboxTextToFind.setToolTipText(t); + cboxTextToFind.getComponent().setToolTipText(t); } /** @@ -653,10 +608,7 @@ * * search string is empty, meaning that the dialog is empty. */ private SearchPattern getCurrentSearchPattern() { - return SearchPattern.create(textToFindEditor.getText(), - chkWholeWords.isSelected(), - chkCaseSensitive.isSelected(), - chkRegexp.isSelected()); + return cboxTextToFind.getSearchPattern(); } /** @@ -714,14 +666,13 @@ private static final Logger watcherLogger = Logger.getLogger( "org.netbeans.modules.search.BasicSearchForm.FileNamePatternWatcher");//NOI18N - private JComboBox cboxTextToFind; + private SearchPatternController cboxTextToFind; private JComboBox cboxReplacement; private FileNameController cboxFileNamePattern; private JCheckBox chkWholeWords; private JCheckBox chkCaseSensitive; private JCheckBox chkRegexp; private JCheckBox chkPreserveCase; - private JTextComponent textToFindEditor; private JTextComponent replacementPatternEditor; protected SearchFormPanel formPanel; private JButton btnTestTextToFind; @@ -850,21 +801,6 @@ } } - private class TextToFindChangeListener extends PatternChangeListener { - - public TextToFindChangeListener() { - } - - @Override - public void handleComboBoxChange(String text) { - searchCriteria.setTextPattern(text); - updateTextPatternColor(); - if (cboxReplacement != null) { - updateReplacePatternColor(); - } - } - } - private class ReplacementPatternListener extends PatternChangeListener { public ReplacementPatternListener() { diff --git a/api.search/src/org/netbeans/modules/search/FindDialogMemory.java b/api.search/src/org/netbeans/modules/search/FindDialogMemory.java --- a/api.search/src/org/netbeans/modules/search/FindDialogMemory.java +++ b/api.search/src/org/netbeans/modules/search/FindDialogMemory.java @@ -257,7 +257,7 @@ * * @param pattern pattern to be stored */ - void storeFileNamePattern(String pattern) { + public void storeFileNamePattern(String pattern) { int index = fileNamePatterns.indexOf(pattern); if (index != -1) { if (index == fileNamePatterns.size() - 1) { @@ -370,7 +370,7 @@ prefs.put(PROP_SCOPE_TYPE_ID, scopeTypeId); } - boolean isTextPatternSpecified() { + public boolean isTextPatternSpecified() { return textPatternSpecified; } @@ -382,7 +382,7 @@ return fileNamePatternSpecified; } - void setFileNamePatternSpecified(boolean specified) { + public void setFileNamePatternSpecified(boolean specified) { fileNamePatternSpecified = specified; prefs.putBoolean(PROP_FILENAME_PATTERN_SPECIFIED, specified); } diff --git a/api.search/src/org/netbeans/modules/search/ui/AbstractSearchResultsPanel.java b/api.search/src/org/netbeans/modules/search/ui/AbstractSearchResultsPanel.java --- a/api.search/src/org/netbeans/modules/search/ui/AbstractSearchResultsPanel.java +++ b/api.search/src/org/netbeans/modules/search/ui/AbstractSearchResultsPanel.java @@ -44,19 +44,35 @@ import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.awt.event.HierarchyEvent; -import java.awt.event.HierarchyListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyVetoException; +import java.util.LinkedList; +import java.util.List; +import java.util.MissingResourceException; import javax.swing.AbstractButton; +import javax.swing.ActionMap; import javax.swing.JButton; import javax.swing.JPanel; +import javax.swing.JToggleButton; import javax.swing.JToolBar; import org.netbeans.api.search.SearchControl; import org.netbeans.modules.search.ResultView; import org.netbeans.spi.search.provider.SearchComposition; import org.netbeans.spi.search.provider.SearchProvider; import org.netbeans.spi.search.provider.SearchProvider.Presenter; +import org.netbeans.swing.outline.Outline; import org.openide.explorer.ExplorerManager; import org.openide.explorer.ExplorerUtils; +import org.openide.explorer.view.OutlineView; +import org.openide.explorer.view.Visualizer; +import org.openide.nodes.AbstractNode; +import org.openide.nodes.Children; +import org.openide.nodes.Node; +import org.openide.nodes.NodeAdapter; +import org.openide.nodes.NodeMemberEvent; +import org.openide.nodes.NodeReorderEvent; +import org.openide.util.Exceptions; import org.openide.util.ImageUtilities; import org.openide.util.Lookup; import org.openide.util.Mutex; @@ -73,10 +89,21 @@ "org/netbeans/modules/search/res/refresh.png"; //NOI18N private static final String STOP_ICON = "org/netbeans/modules/search/res/stop.png"; //NOI18N + private static final String NEXT_ICON = + "org/netbeans/modules/search/res/next.png"; //NOI18N + private static final String PREV_ICON = + "org/netbeans/modules/search/res/prev.png"; //NOI18N + private static final String EXPAND_ICON = + "org/netbeans/modules/search/res/expandTree.png"; //NOI18N + private static final String COLLAPSE_ICON = + "org/netbeans/modules/search/res/colapseTree.png"; //NOI18N private ExplorerManager explorerManager; private SearchComposition searchComposition; protected JButton btnStopRefresh = new JButton(); + protected JButton btnPrev = new JButton(); + protected JButton btnNext = new JButton(); + protected JToggleButton btnExpand = new JToggleButton(); private final Presenter searchProviderPresenter; private Lookup lookup; private volatile boolean btnStopRefreshInRefreshMode = false; @@ -92,15 +119,9 @@ explorerManager = new ExplorerManager(); lookup = ExplorerUtils.createLookup(explorerManager, ResultView.getInstance().getActionMap()); - this.addHierarchyListener(new HierarchyListener() { - @Override - public synchronized void hierarchyChanged(HierarchyEvent e) { - if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0) { - removeHierarchyListener(this); - initToolbar(); - } - } - }); + initActions(); + initToolbar(); + initSelectionListeners(); } /** @@ -156,6 +177,17 @@ toolBar.setRollover(true); toolBar.setFloatable(false); + initStopRefreshButton(); + toolBar.add(btnStopRefresh); + initPrevButton(); + toolBar.add(btnPrev); + initNextButton(); + toolBar.add(btnNext); + initExpandButton(); + toolBar.add(btnExpand); + } + + private void initStopRefreshButton() throws MissingResourceException { sizeButton(btnStopRefresh); btnStopRefresh.addActionListener(new ActionListener() { @Override @@ -167,21 +199,53 @@ } } }); - btnStopRefresh.setToolTipText( UiUtils.getText("TEXT_BUTTON_STOP")); //NOI18N btnStopRefresh.setIcon(ImageUtilities.loadImageIcon(STOP_ICON, true)); - - toolBar.add(btnStopRefresh); - for (AbstractButton b : createButtons()) { - sizeButton(b); - toolBar.add(b); - } btnStopRefresh.getAccessibleContext().setAccessibleDescription( NbBundle.getMessage(ResultView.class, "ACS_TEXT_BUTTON_STOP")); //NOI18N } + private void initExpandButton() { + sizeButton(btnExpand); + btnExpand.setIcon(ImageUtilities.loadImageIcon(EXPAND_ICON, true)); + btnExpand.setSelectedIcon(ImageUtilities.loadImageIcon( + COLLAPSE_ICON, true)); + btnExpand.setToolTipText(UiUtils.getText( + "TEXT_BUTTON_EXPAND")); //NOI18N + btnExpand.setEnabled(false); + btnExpand.setSelected(false); + } + + private void initNextButton() { + sizeButton(btnNext); + btnNext.setIcon(ImageUtilities.loadImageIcon(NEXT_ICON, true)); + btnNext.setToolTipText(UiUtils.getText( + "TEXT_BUTTON_NEXT_MATCH")); //NOI18N + btnNext.setEnabled(false); + btnNext.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + shift(1); + } + }); + } + + private void initPrevButton() { + sizeButton(btnPrev); + btnPrev.setIcon(ImageUtilities.loadImageIcon(PREV_ICON, true)); + btnPrev.setToolTipText(UiUtils.getText( + "TEXT_BUTTON_PREV_MATCH")); //NOI18N + btnPrev.setEnabled(false); + btnPrev.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + shift(-1); + } + }); + } + protected void sizeButton(AbstractButton button) { Dimension dim = new Dimension(24, 24); button.setMinimumSize(dim); @@ -233,12 +297,342 @@ } } + protected void addButton(AbstractButton button) { + toolBar.add(button); + } + + static class RootNode extends AbstractNode { + + Node resultsNode; + Node infoNode; + + public RootNode(Node resultsNode, Node infoNode) { + this(resultsNode, infoNode, + new RootNodeChildren(resultsNode, infoNode)); + } + + private RootNode(Node resultsNode, Node infoNode, + final RootNodeChildren rootNodeChildren) { + super(rootNodeChildren); + this.infoNode = infoNode; + this.resultsNode = resultsNode; + if (infoNode != null) { + setInfoNodeListener(rootNodeChildren); + } + } + + private void setInfoNodeListener( + final RootNodeChildren rootNodeChildren) { + + assert infoNode != null; + + infoNode.getChildren().getNodes(true); + infoNode.addNodeListener(new NodeAdapter() { + private boolean added = false; + + @Override + public synchronized void childrenAdded(NodeMemberEvent ev) { + if (!added) { + rootNodeChildren.showInfoNode(); + infoNode.removeNodeListener(this); + added = true; + } + } + + @Override + public void propertyChange(PropertyChangeEvent ev) { + super.propertyChange(ev); + } + + @Override + public void childrenReordered(NodeReorderEvent ev) { + super.childrenReordered(ev); + } + }); + } + } + + private static class RootNodeChildren extends Children.Keys { + + private Node[] standard; + private Node[] withInfo; + private boolean infoNodeShown = false; + + public RootNodeChildren(Node resultsNode, Node infoNode) { + standard = new Node[] {resultsNode}; + withInfo = new Node[] {resultsNode, infoNode}; + setKeys(standard); + } + + private synchronized void showInfoNode() { + if (!infoNodeShown) { + setKeys(withInfo); + infoNodeShown = true; + } + } + + @Override + protected Node[] createNodes(Node key) { + return new Node[]{key}; + } + } + + protected void toggleExpand(Node root, boolean expand) { + if (expand) { + getOutlineView().expandNode(root); + } + for (Node n : root.getChildren().getNodes()) { + toggleExpand(n, expand); + } + if (!expand) { + getOutlineView().collapseNode(root); + } + } + + protected abstract OutlineView getOutlineView(); + + private void initActions() { + ActionMap map = getActionMap(); + map.put("jumpNext", new PrevNextAction(1)); // NOI18N + map.put("jumpPrev", new PrevNextAction(-1)); // NOI18N + } + + private void initSelectionListeners() { + getExplorerManager().addPropertyChangeListener( + new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals( + "selectedNodes")) { //NOI18N + updateShiftButtons(); + } + } + }); + } + + protected void updateShiftButtons() { + if (btnPrev.isVisible() && btnNext.isVisible()) { + btnPrev.setEnabled( + findShiftNode(-1, getOutlineView(), false) != null); + btnNext.setEnabled( + findShiftNode(1, getOutlineView(), false) != null); + } + } + + private void shift(int direction) { + + Node next = findShiftNode(direction, getOutlineView(), true); + if (next == null) { + return; + } else { + try { + getExplorerManager().setSelectedNodes(new Node[]{next}); + onDetailShift(next); + } catch (PropertyVetoException pve) { + Exceptions.printStackTrace(pve); + } + } + } + /** - * Create custom set of buttons that will be resized and placed between - * "Refresh" and "Stop" buttons. + * Should be called after a matching node was added to update state of + * buttons. */ - protected AbstractButton[] createButtons() { - return new AbstractButton[] {}; + protected void afterMatchingNodeAdded() { + Mutex.EVENT.writeAccess(new Runnable() { + @Override + public void run() { + if (btnNext.isVisible() && !btnNext.isEnabled()) { + updateShiftButtons(); + } + } + }); + } + + /** + * Called when a node is selected by clicking Next or Previous button. + */ + protected void onDetailShift(Node n) { + } + + private Node findShiftNode(int direction, OutlineView outlineView, + boolean canExpand) { + Node[] selected = getExplorerManager().getSelectedNodes(); + Node n = null; + if ((selected == null || selected.length == 0) + /* TODO && getExplorerManager().getRootContext() == resultsOutlineSupport.getRootNode() */) { + n = getExplorerManager().getRootContext(); + } else if (selected.length == 1) { + n = selected[0]; + } + return n == null ? null : findDetailNode(n, direction, outlineView, + canExpand); + } + + Node findDetailNode(Node fromNode, int direction, + OutlineView outlineView, boolean canExpand) { + return findUp(fromNode, direction, + isDetailNode(fromNode) || direction < 0 ? direction : 0, + outlineView, canExpand); + } + + /** + * Start finding for next or previous occurance, from a node or its previous + * or next sibling of node {@code node} + * + * @param node reference node + * @param offset 0 to start from node {@code node}, 1 to start from its next + * sibling, -1 to start from its previous sibling. + * @param dir Direction: 1 for next, -1 for previous. + */ + Node findUp(Node node, int dir, int offset, OutlineView outlineView, + boolean canExpand) { + if (node == null) { + return null; + } + Node parent = node.getParentNode(); + Node[] siblings; + if (parent == null) { + siblings = new Node[]{node}; + } else { + siblings = getChildren(parent, outlineView, canExpand); + } + int nodeIndex = findChildIndex(node, siblings); + if (nodeIndex + offset < 0 || nodeIndex + offset >= siblings.length) { + return findUp(parent, dir, dir, outlineView, canExpand); + } + for (int i = nodeIndex + offset; + i >= 0 && i < siblings.length; i += dir) { + Node found = findDown(siblings[i], siblings, i, dir, outlineView, + canExpand); + return found; + } + return findUp(parent, dir, offset, outlineView, canExpand); + } + + /** + * Find Depth-first search to find a detail node in the subtree. + */ + private Node findDown(Node node, Node[] siblings, int nodeIndex, + int dir, OutlineView outlineView, boolean canExpand) { + + Node[] children = getChildren(node, outlineView, canExpand); + for (int i = dir > 0 ? 0 : children.length - 1; + i >= 0 && i < children.length; i += dir) { + Node found = findDown(children[i], children, i, dir, outlineView, + canExpand); + if (found != null) { + return found; + } + } + for (int i = nodeIndex; i >= 0 && i < siblings.length; i += dir) { + if (isDetailNode(siblings[i])) { + return siblings[i]; + } + } + return null; + } + + protected abstract boolean isDetailNode(Node n); + + private static int findChildIndex(Node selectedNode, Node[] siblings) { + int pos = -1; + for (int i = 0; i < siblings.length; i++) { + if (siblings[i] == selectedNode) { + pos = i; + break; + } + } + return pos; + } + + private static Node[] getChildren(Node n, OutlineView outlineView, + boolean canExpand) { + if (outlineView != null) { + if (!outlineView.isExpanded(n)) { + if (canExpand) { + outlineView.expandNode(n); + } else { + return n.getChildren().getNodes(true); + } + } + return getChildrenInDisplayedOrder(n, outlineView); + } else { + return n.getChildren().getNodes(true); + } + } + + private static Node[] getChildrenInDisplayedOrder(Node parent, + OutlineView outlineView) { + + Outline outline = outlineView.getOutline(); + Node[] unsortedChildren = parent.getChildren().getNodes(true); + int rows = outlineView.getOutline().getRowCount(); + int start = findRowIndexInOutline(parent, outline, rows); + if (start == -1) { + return unsortedChildren; + } + List children = new LinkedList(); + for (int j = start + 1; j < rows; j++) { + int childModelIndex = outline.convertRowIndexToModel(j); + if (childModelIndex == -1) { + continue; + } + Object childObject = outline.getModel().getValueAt( + childModelIndex, 0); + Node childNode = Visualizer.findNode(childObject); + if (childNode.getParentNode() == parent) { + children.add(childNode); + } else if (children.size() == unsortedChildren.length) { + break; + } + } + return children.toArray(new Node[children.size()]); + } + + private static int findRowIndexInOutline(Node node, Outline outline, + int rows) { + + int startRow = Math.max(outline.getSelectedRow(), 0); + int offset = 0; + while (startRow + offset < rows || startRow - offset >= 0) { + int up = startRow + offset + 1; + int down = startRow - offset; + + if (up < rows && testNodeInRow(outline, node, up)) { + return up; + } else if (down >= 0 && testNodeInRow(outline, node, down)) { + return down; + } else { + offset++; + } + } + return -1; + } + + private static boolean testNodeInRow(Outline outline, Node node, int i) { + int modelIndex = outline.convertRowIndexToModel(i); + if (modelIndex != -1) { + Object o = outline.getModel().getValueAt(modelIndex, 0); + Node n = Visualizer.findNode(o); + if (n == node) { + return true; + } + } + return false; + } + + private final class PrevNextAction extends javax.swing.AbstractAction { + + private int direction; + + public PrevNextAction(int direction) { + this.direction = direction; + } + + public void actionPerformed(java.awt.event.ActionEvent actionEvent) { + shift(direction); + } } @Override diff --git a/api.search/src/org/netbeans/modules/search/ui/BasicAbstractResultsPanel.java b/api.search/src/org/netbeans/modules/search/ui/BasicAbstractResultsPanel.java --- a/api.search/src/org/netbeans/modules/search/ui/BasicAbstractResultsPanel.java +++ b/api.search/src/org/netbeans/modules/search/ui/BasicAbstractResultsPanel.java @@ -45,15 +45,10 @@ import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; import java.beans.PropertyVetoException; -import java.util.LinkedList; import java.util.List; import java.util.ResourceBundle; import javax.accessibility.AccessibleContext; -import javax.swing.AbstractButton; -import javax.swing.ActionMap; import javax.swing.JButton; import javax.swing.JToggleButton; import javax.swing.UIManager; @@ -66,15 +61,12 @@ import org.netbeans.modules.search.ResultModel; import org.netbeans.modules.search.ResultView; import org.netbeans.modules.search.TextDetail; -import org.netbeans.swing.outline.Outline; import org.openide.explorer.view.OutlineView; -import org.openide.explorer.view.Visualizer; import org.openide.filesystems.FileObject; import org.openide.nodes.Node; import org.openide.nodes.NodeAdapter; import org.openide.nodes.NodeListener; import org.openide.nodes.NodeMemberEvent; -import org.openide.util.Exceptions; import org.openide.util.ImageUtilities; import org.openide.util.NbBundle; @@ -85,14 +77,6 @@ public abstract class BasicAbstractResultsPanel extends AbstractSearchResultsPanel { - private static final String NEXT_ICON = - "org/netbeans/modules/search/res/next.png"; //NOI18N - private static final String PREV_ICON = - "org/netbeans/modules/search/res/prev.png"; //NOI18N - private static final String EXPAND_ICON = - "org/netbeans/modules/search/res/expandTree.png"; //NOI18N - private static final String COLLAPSE_ICON = - "org/netbeans/modules/search/res/colapseTree.png"; //NOI18N private static final String SHOW_DETAILS_ICON = "org/netbeans/modules/search/res/search.gif"; //NOI18N private static final String FOLDER_VIEW_ICON = @@ -102,11 +86,8 @@ private static final String MODE_FLAT = "flat"; //NOI18N private static final String MODE_TREE = "tree"; //NOI18N protected ResultModel resultModel; - protected JButton nextButton; - protected JButton prevButton; - protected JToggleButton expandButton; - protected JToggleButton treeViewButton; - protected JToggleButton flatViewButton; + protected JToggleButton btnTreeView; + protected JToggleButton btnFlatView; protected JButton showDetailsButton; protected boolean details; protected BasicComposition composition; @@ -129,8 +110,7 @@ this.resultsOutlineSupport = resultsOutlineSupport; getExplorerManager().setRootContext( resultsOutlineSupport.getRootNode()); - initSelectionListeners(); - initActions(); + initButtons(); initResultNodeAdditionListener(); if (MODE_TREE.equals( FindDialogMemory.getDefault().getResultsViewMode())) { @@ -141,28 +121,10 @@ initAccessibility(); } - private void initSelectionListeners() { - getExplorerManager().addPropertyChangeListener( - new PropertyChangeListener() { - @Override - public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals( - "selectedNodes")) { //NOI18N - updateShiftButtons(); - } - } - }); - } - private void initActions() { - ActionMap map = getActionMap(); - - map.put("jumpNext", new PrevNextAction(1)); // NOI18N - map.put("jumpPrev", new PrevNextAction(-1)); // NOI18N - } public void update() { - if (details && expandButton != null && !expandButton.isEnabled()) { - expandButton.setEnabled(resultModel.size() > 0); + if (details && btnExpand.isVisible() && !btnExpand.isEnabled()) { + btnExpand.setEnabled(resultModel.size() > 0); } EventQueue.invokeLater(new Runnable() { @Override @@ -173,82 +135,47 @@ resultsOutlineSupport.update(); } - private void updateShiftButtons() { - if (details && prevButton != null && nextButton != null) { - prevButton.setEnabled( - findShiftNode(-1, getOutlineView(), false) != null); - nextButton.setEnabled( - findShiftNode(1, getOutlineView(), false) != null); - } - } - - @Override - protected AbstractButton[] createButtons() { + protected void initButtons() { final FindDialogMemory memory = FindDialogMemory.getDefault(); - treeViewButton = new JToggleButton(); - treeViewButton.setEnabled(true); - treeViewButton.setIcon(ImageUtilities.loadImageIcon(FOLDER_VIEW_ICON, + btnTreeView = new JToggleButton(); + btnTreeView.setEnabled(true); + btnTreeView.setIcon(ImageUtilities.loadImageIcon(FOLDER_VIEW_ICON, true)); - treeViewButton.setToolTipText(UiUtils.getText( + btnTreeView.setToolTipText(UiUtils.getText( "TEXT_BUTTON_TREE_VIEW")); //NOI18N - treeViewButton.setSelected( + btnTreeView.setSelected( MODE_TREE.equals(memory.getResultsViewMode())); - treeViewButton.addActionListener(new ActionListener() { + btnTreeView.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - toggleView(!treeViewButton.isSelected()); + toggleView(!btnTreeView.isSelected()); } }); - flatViewButton = new JToggleButton(); - flatViewButton.setEnabled(true); - flatViewButton.setIcon(ImageUtilities.loadImageIcon(FLAT_VIEW_ICON, + btnFlatView = new JToggleButton(); + btnFlatView.setEnabled(true); + btnFlatView.setIcon(ImageUtilities.loadImageIcon(FLAT_VIEW_ICON, true)); - flatViewButton.setToolTipText(UiUtils.getText( + btnFlatView.setToolTipText(UiUtils.getText( "TEXT_BUTTON_FLAT_VIEW")); //NOI18N - flatViewButton.setSelected(!treeViewButton.isSelected()); - flatViewButton.addActionListener(new ActionListener() { + btnFlatView.setSelected(!btnTreeView.isSelected()); + btnFlatView.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - toggleView(flatViewButton.isSelected()); + toggleView(btnFlatView.isSelected()); } }); + addButton(btnTreeView); + addButton(btnFlatView); if (!details) { - return new AbstractButton[]{treeViewButton, flatViewButton}; + btnPrev.setVisible(false); + btnNext.setVisible(false); + btnExpand.setVisible(false); + return; } - prevButton = new JButton(); - prevButton.setEnabled(false); - prevButton.setIcon(ImageUtilities.loadImageIcon(PREV_ICON, true)); - prevButton.setToolTipText(UiUtils.getText( - "TEXT_BUTTON_PREV_MATCH")); //NOI18N - prevButton.addActionListener(new ActionListener() { + btnExpand.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - shift(-1); - } - }); - nextButton = new JButton(); - nextButton.setEnabled(false); - nextButton.setIcon(ImageUtilities.loadImageIcon(NEXT_ICON, true)); - nextButton.setToolTipText(UiUtils.getText( - "TEXT_BUTTON_NEXT_MATCH")); //NOI18N - nextButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - shift(1); - } - }); - expandButton = new JToggleButton(); - expandButton.setEnabled(false); - expandButton.setIcon(ImageUtilities.loadImageIcon(EXPAND_ICON, true)); - expandButton.setSelectedIcon(ImageUtilities.loadImageIcon( - COLLAPSE_ICON, true)); - expandButton.setToolTipText(UiUtils.getText( - "TEXT_BUTTON_EXPAND")); //NOI18N - expandButton.setSelected(false); - expandButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - toggleExpandNodeChildren(expandButton.isSelected()); + toggleExpandNodeChildren(btnExpand.isSelected()); } }); showDetailsButton = new JButton(); @@ -263,14 +190,10 @@ fillOutput(); } }); - if (showDetailsButton != null) { - showDetailsButton.getAccessibleContext().setAccessibleDescription( - NbBundle.getMessage(ResultView.class, - "ACS_TEXT_BUTTON_FILL")); //NOI18N - } - return new AbstractButton[]{prevButton, nextButton, - treeViewButton, flatViewButton, expandButton, - showDetailsButton}; + showDetailsButton.getAccessibleContext().setAccessibleDescription( + NbBundle.getMessage(ResultView.class, + "ACS_TEXT_BUTTON_FILL")); //NOI18N + addButton(showDetailsButton); } private void toggleView(boolean flat) { @@ -282,8 +205,8 @@ resultsOutlineSupport.setFolderTreeMode(); memory.setResultsViewMode(MODE_TREE); } - treeViewButton.setSelected(!flat); - flatViewButton.setSelected(flat); + btnTreeView.setSelected(!flat); + btnFlatView.setSelected(flat); try { getExplorerManager().setSelectedNodes(new Node[]{ resultsOutlineSupport.getResultsNode()}); @@ -312,134 +235,6 @@ bundle.getString("ACSD_ResultTree")); //NOI18N } - private void shift(int direction) { - - Node next = findShiftNode(direction, getOutlineView(), true); - if (next == null) { - return; - } - try { - getExplorerManager().setSelectedNodes(new Node[]{next}); - TextDetail textDetail = next.getLookup().lookup( - TextDetail.class); - if (textDetail != null) { - textDetail.showDetail(TextDetail.DH_GOTO); - } - } catch (PropertyVetoException ex) { - Exceptions.printStackTrace(ex); - } - } - - private Node findShiftNode(int direction, OutlineView outlineView, - boolean canExpand) { - Node[] selected = getExplorerManager().getSelectedNodes(); - Node n = null; - if ((selected == null || selected.length == 0) - && getExplorerManager().getRootContext() - == resultsOutlineSupport.getRootNode()) { - n = resultsOutlineSupport.getResultsNode(); - } else if (selected.length == 1) { - n = selected[0]; - } - return n == null ? null : findTextDetailNode(n, direction, outlineView, - canExpand); - } - - static Node findTextDetailNode(Node fromNode, int direction, - OutlineView outlineView, boolean canExpand) { - return findUp(fromNode, direction, - isTextDetailNode(fromNode) || direction < 0 ? direction : 0, - outlineView, canExpand); - } - - /** - * Start finding for next or previous occurance, from a node or its previous - * or next sibling of node {@code node} - * - * @param node reference node - * @param offset 0 to start from node {@code node}, 1 to start from its next - * sibling, -1 to start from its previous sibling. - * @param dir Direction: 1 for next, -1 for previous. - */ - static Node findUp(Node node, int dir, int offset, OutlineView outlineView, - boolean canExpand) { - if (node == null) { - return null; - } - Node parent = node.getParentNode(); - Node[] siblings; - if (parent == null) { - siblings = new Node[]{node}; - } else { - siblings = getChildren(parent, outlineView, canExpand); - } - int nodeIndex = findChildIndex(node, siblings); - if (nodeIndex + offset < 0 || nodeIndex + offset >= siblings.length) { - return findUp(parent, dir, dir, outlineView, canExpand); - } - for (int i = nodeIndex + offset; - i >= 0 && i < siblings.length; i += dir) { - Node found = findDown(siblings[i], siblings, i, dir, outlineView, - canExpand); - return found; - } - return findUp(parent, dir, offset, outlineView, canExpand); - } - - /** - * Find Depth-first search to find TextDetail node in the subtree. - */ - private static Node findDown(Node node, Node[] siblings, int nodeIndex, - int dir, OutlineView outlineView, boolean canExpand) { - - Node[] children = getChildren(node, outlineView, canExpand); - for (int i = dir > 0 ? 0 : children.length - 1; - i >= 0 && i < children.length; i += dir) { - Node found = findDown(children[i], children, i, dir, outlineView, - canExpand); - if (found != null) { - return found; - } - } - for (int i = nodeIndex; i >= 0 && i < siblings.length; i += dir) { - if (isTextDetailNode(siblings[i])) { - return siblings[i]; - } - } - return null; - } - - private static boolean isTextDetailNode(Node n) { - return n.getLookup().lookup(TextDetail.class) != null; - } - - private static int findChildIndex(Node selectedNode, Node[] siblings) { - int pos = -1; - for (int i = 0; i < siblings.length; i++) { - if (siblings[i] == selectedNode) { - pos = i; - break; - } - } - return pos; - } - - private static Node[] getChildren(Node n, OutlineView outlineView, - boolean canExpand) { - if (outlineView != null) { - if (!outlineView.isExpanded(n)) { - if (canExpand) { - outlineView.expandNode(n); - } else { - return n.getChildren().getNodes(true); - } - } - return getChildrenInDisplayedOrder(n, outlineView); - } else { - return n.getChildren().getNodes(true); - } - } - private void toggleExpandNodeChildren(boolean expand) { Node resultsNode = resultsOutlineSupport.getResultsNode(); for (Node n : resultsNode.getChildren().getNodes()) { @@ -447,18 +242,6 @@ } } - public void toggleExpand(Node root, boolean expand) { - if (expand) { - getOutlineView().expandNode(root); - } - for (Node n : root.getChildren().getNodes()) { - toggleExpand(n, expand); - } - if (!expand) { - getOutlineView().collapseNode(root); - } - } - @Override public void searchFinished() { super.searchFinished(); @@ -480,6 +263,7 @@ public void addMatchingObject(MatchingObject mo) { resultsOutlineSupport.addMatchingObject(mo); updateRootNodeText(); + afterMatchingNodeAdded(); } public final OutlineView getOutlineView() { @@ -552,73 +336,13 @@ } } - private static Node[] getChildrenInDisplayedOrder(Node parent, - OutlineView outlineView) { - - Outline outline = outlineView.getOutline(); - Node[] unsortedChildren = parent.getChildren().getNodes(true); - int rows = outlineView.getOutline().getRowCount(); - int start = findRowIndexInOutline(parent, outline, rows); - if (start == -1) { - return unsortedChildren; - } - List children = new LinkedList(); - for (int j = start + 1; j < rows; j++) { - int childModelIndex = outline.convertRowIndexToModel(j); - if (childModelIndex == -1) { - continue; - } - Object childObject = outline.getModel().getValueAt( - childModelIndex, 0); - Node childNode = Visualizer.findNode(childObject); - if (childNode.getParentNode() == parent) { - children.add(childNode); - } else if (children.size() == unsortedChildren.length) { - break; - } - } - return children.toArray(new Node[children.size()]); - } - - private static int findRowIndexInOutline(Node node, Outline outline, - int rows) { - - int startRow = Math.max(outline.getSelectedRow(), 0); - int offset = 0; - while (startRow + offset < rows || startRow - offset >= 0) { - int up = startRow + offset + 1; - int down = startRow - offset; - - if (up < rows && testNodeInRow(outline, node, up)) { - return up; - } else if (down >= 0 && testNodeInRow(outline, node, down)) { - return down; - } else { - offset++; - } - } - return -1; - } - - private static boolean testNodeInRow(Outline outline, Node node, int i) { - int modelIndex = outline.convertRowIndexToModel(i); - if (modelIndex != -1) { - Object o = outline.getModel().getValueAt(modelIndex, 0); - Node n = Visualizer.findNode(o); - if (n == node) { - return true; - } - } - return false; - } - private void initResultNodeAdditionListener() { resultsNodeAdditionListener = new NodeAdapter() { @Override public void childrenAdded(NodeMemberEvent ev) { - if (expandButton != null) { + if (btnExpand != null) { for (final Node n : ev.getDelta()) { - if (expandButton.isSelected()) { + if (btnExpand.isSelected()) { EventQueue.invokeLater(new Runnable() { @Override public void run() { @@ -633,7 +357,7 @@ @Override public void childrenRemoved(NodeMemberEvent ev) { - if (expandButton != null) { + if (btnExpand != null) { for (Node removedChild : ev.getDelta()) { removeChildAdditionListener(removedChild); } @@ -660,21 +384,22 @@ removedNode.removeNodeListener(resultsNodeAdditionListener); } - private final class PrevNextAction extends javax.swing.AbstractAction { - - private int direction; - - public PrevNextAction(int direction) { - this.direction = direction; - } - - public void actionPerformed(java.awt.event.ActionEvent actionEvent) { - shift(direction); - } - } - @Override public boolean requestFocusInWindow() { return getOutlineView().requestFocusInWindow(); } + + @Override + protected boolean isDetailNode(Node n) { + return n.getLookup().lookup(TextDetail.class) != null; + } + + @Override + protected void onDetailShift(Node next) { + TextDetail textDetail = next.getLookup().lookup( + TextDetail.class); + if (textDetail != null) { + textDetail.showDetail(TextDetail.DH_GOTO); + } + } } \ No newline at end of file diff --git a/api.search/src/org/netbeans/modules/search/ui/BasicReplaceResultsPanel.java b/api.search/src/org/netbeans/modules/search/ui/BasicReplaceResultsPanel.java --- a/api.search/src/org/netbeans/modules/search/ui/BasicReplaceResultsPanel.java +++ b/api.search/src/org/netbeans/modules/search/ui/BasicReplaceResultsPanel.java @@ -174,8 +174,8 @@ public void displayIssues(IssuesPanel issuesPanel) { if (issuesPanel != null) { showRefreshButton(); - removeButtons(nextButton, prevButton, treeViewButton, - flatViewButton, expandButton, showDetailsButton); + removeButtons(btnNext, btnPrev, btnFlatView, btnTreeView, + btnExpand, showDetailsButton); Container p = getContentPanel(); p.removeAll(); p.add(issuesPanel); @@ -214,11 +214,11 @@ getExplorerManager().setRootContext(an); getOutlineView().validate(); getOutlineView().repaint(); - nextButton.setEnabled(false); - prevButton.setEnabled(false); - treeViewButton.setEnabled(false); - flatViewButton.setEnabled(false); - expandButton.setEnabled(false); + btnNext.setEnabled(false); + btnPrev.setEnabled(false); + btnTreeView.setEnabled(false); + btnFlatView.setEnabled(false); + btnExpand.setEnabled(false); } }); } diff --git a/api.search/src/org/netbeans/modules/search/ui/DefaultSearchResultsPanel.java b/api.search/src/org/netbeans/modules/search/ui/DefaultSearchResultsPanel.java --- a/api.search/src/org/netbeans/modules/search/ui/DefaultSearchResultsPanel.java +++ b/api.search/src/org/netbeans/modules/search/ui/DefaultSearchResultsPanel.java @@ -41,9 +41,15 @@ */ package org.netbeans.modules.search.ui; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; +import javax.swing.AbstractButton; +import javax.swing.JButton; +import javax.swing.JToggleButton; import org.netbeans.modules.search.Constants; +import org.netbeans.modules.search.ui.AbstractSearchResultsPanel.RootNode; import org.netbeans.spi.search.provider.SearchComposition; import org.netbeans.spi.search.provider.SearchProvider.Presenter; import org.netbeans.spi.search.provider.SearchResultsDisplayer; @@ -63,6 +69,7 @@ private List matchingObjects = new ArrayList(); private final NodeDisplayer nodeDisplayer; private ResultsNode resultsNode; + private OutlineView outlineView; public DefaultSearchResultsPanel( SearchResultsDisplayer.NodeDisplayer nodeDisplayer, @@ -71,16 +78,32 @@ super(searchComposition, searchProviderPresenter); this.resultsNode = new ResultsNode(); - getExplorerManager().setRootContext(resultsNode); this.nodeDisplayer = nodeDisplayer; resultsNode.update(); - getContentPanel().add(new OutlineView(UiUtils.getText( - "BasicSearchResultsPanel.outline.nodes"))); //NOI18N + outlineView = new OutlineView(UiUtils.getText( + "BasicSearchResultsPanel.outline.nodes")); //NOI18N + outlineView.getOutline().setRootVisible(false); + initExpandButton(); + getContentPanel().add(outlineView); + } + + private void initExpandButton() { + btnExpand.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + getOutlineView().expandNode(resultsNode); + for (Node n : resultsNode.getChildren().getNodes(true)) { + toggleExpand(n, btnExpand.isSelected()); + } + } + }); + btnExpand.setEnabled(true); } public void addMatchingObject(T object) { matchingObjects.add(object); resultsNode.update(); + afterMatchingNodeAdded(); } /** @@ -130,4 +153,53 @@ "TEXT_MSG_FOUND_X_NODES", //NOI18N matchingObjects.size())); } + + /** + * Get {@link OutlineView} used for displaying result nodes. + */ + public OutlineView getOutlineView() { + return outlineView; + } + + /** + * Get button for moving to the previous result item. It is hidden by + * default. You can set it visible and add a {@link ActionListener}. + */ + public JButton getButtonPrevious() { + return btnPrev; + } + + /** + * Get button for moving to the next result item. It is hidden by default. + * You can set it visible and add a {@link ActionListener}. + */ + public JButton getButtonNext() { + return btnNext; + } + + /** + * Get button for expanding/collapsing of the result tree. It is hidden by + * default. You can set it visible and add a {@link ActionListener}. + */ + public JToggleButton getButtonExpand() { + return btnExpand; + } + + /** + * Add a custom button to the toolbar. + */ + public void addButton(AbstractButton button) { + super.addButton(button); + } + + public void setInfoNode(Node infoNode) { + Node root = new RootNode(resultsNode, infoNode); + getExplorerManager().setRootContext(root); + getOutlineView().expandNode(resultsNode); + } + + @Override + protected boolean isDetailNode(Node n) { + return true; + } } diff --git a/api.search/src/org/netbeans/modules/search/ui/ResultsOutlineSupport.java b/api.search/src/org/netbeans/modules/search/ui/ResultsOutlineSupport.java --- a/api.search/src/org/netbeans/modules/search/ui/ResultsOutlineSupport.java +++ b/api.search/src/org/netbeans/modules/search/ui/ResultsOutlineSupport.java @@ -71,6 +71,7 @@ import org.netbeans.modules.search.MatchingObject; import org.netbeans.modules.search.ResultModel; import org.netbeans.modules.search.Selectable; +import org.netbeans.modules.search.ui.AbstractSearchResultsPanel.RootNode; import org.netbeans.swing.etable.ETableColumnModel; import org.netbeans.swing.outline.Outline; import org.openide.explorer.view.OutlineView; @@ -83,9 +84,6 @@ import org.openide.nodes.Children; import org.openide.nodes.FilterNode; import org.openide.nodes.Node; -import org.openide.nodes.NodeAdapter; -import org.openide.nodes.NodeMemberEvent; -import org.openide.nodes.NodeReorderEvent; import org.openide.util.Exceptions; import org.openide.util.ImageUtilities; import org.openide.util.datatransfer.PasteType; @@ -124,7 +122,7 @@ this.rootFiles = rootFiles; this.resultsNode = new ResultsNode(); this.infoNode = infoNode; - this.invisibleRoot = new RootNode(); + this.invisibleRoot = new RootNode(resultsNode, infoNode); this.matchingObjectNodes = new LinkedList(); createOutlineView(); } @@ -297,72 +295,6 @@ } } - private class RootNode extends AbstractNode { - - public RootNode() { - this(new RootNodeChildren()); - } - - private RootNode(final RootNodeChildren rootNodeChildren) { - super(rootNodeChildren); - if (infoNode != null) { - setInfoNodeListener(rootNodeChildren); - } - } - } - - private void setInfoNodeListener(final RootNodeChildren rootNodeChildren) { - - assert infoNode != null; - - infoNode.getChildren().getNodes(true); - infoNode.addNodeListener(new NodeAdapter() { - private boolean added = false; - - @Override - public synchronized void childrenAdded(NodeMemberEvent ev) { - if (!added) { - rootNodeChildren.showInfoNode(); - infoNode.removeNodeListener(this); - added = true; - } - } - - @Override - public void propertyChange(PropertyChangeEvent ev) { - super.propertyChange(ev); - } - - @Override - public void childrenReordered(NodeReorderEvent ev) { - super.childrenReordered(ev); - } - }); - } - - private class RootNodeChildren extends Children.Keys { - - private Node[] standard = new Node[]{resultsNode}; - private Node[] withInfo = new Node[]{resultsNode, infoNode}; - private boolean infoNodeShown = false; - - public RootNodeChildren() { - setKeys(standard); - } - - private synchronized void showInfoNode() { - if (!infoNodeShown) { - setKeys(withInfo); - infoNodeShown = true; - } - } - - @Override - protected Node[] createNodes(Node key) { - return new Node[]{key}; - } - } - /** * Class for representation of the root node. */ diff --git a/api.search/src/org/netbeans/spi/search/provider/DefaultSearchResultsDisplayer.java b/api.search/src/org/netbeans/spi/search/provider/DefaultSearchResultsDisplayer.java new file mode 100644 --- /dev/null +++ b/api.search/src/org/netbeans/spi/search/provider/DefaultSearchResultsDisplayer.java @@ -0,0 +1,230 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2012 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2012 Sun Microsystems, Inc. + */ +package org.netbeans.spi.search.provider; + +import javax.swing.AbstractButton; +import javax.swing.JComponent; +import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.modules.search.ui.DefaultSearchResultsPanel; +import org.netbeans.spi.search.provider.SearchProvider.Presenter; +import org.openide.explorer.view.OutlineView; +import org.openide.nodes.Node; +import org.openide.util.Parameters; + +/** + * Default search results displayer. + * + * @author jhavlin + * @since api.search/1.1 + */ +public final class DefaultSearchResultsDisplayer + extends SearchResultsDisplayer { + + private static final ResultNodeShiftSupport DEFAULT_NODE_SHIFT_SUPPORT = + new TrivialResultNodeShiftSupport(); + private final SearchResultsDisplayer.NodeDisplayer helper; + private final SearchComposition searchComposition; + private final Presenter presenter; + private final String title; + private ResultNodeShiftSupport shiftSupport = DEFAULT_NODE_SHIFT_SUPPORT; + private DefaultSearchResultsPanel panel = null; + + DefaultSearchResultsDisplayer( + SearchResultsDisplayer.NodeDisplayer helper, + SearchComposition searchComposition, + Presenter presenter, String title) { + this.helper = helper; + this.searchComposition = searchComposition; + this.presenter = presenter; + this.title = title; + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized JComponent getVisualComponent() { + if (panel == null) { + panel = new DefaultSearchResultsPanel(helper, + searchComposition, presenter) { + @Override + protected void onDetailShift(Node n) { + shiftSupport.relevantNodeSelected(n); + } + + @Override + protected boolean isDetailNode(Node n) { + return shiftSupport.isRelevantNode(n); + } + }; + } + return panel; + } + + private DefaultSearchResultsPanel getPanel() { + if (panel == null) { + getVisualComponent(); + } + return panel; + } + + /** + * {@inheritDoc} + */ + @Override + public void addMatchingObject(U object) { + Parameters.notNull("object", object); + panel.addMatchingObject(object); + } + + /** + * {@inheritDoc} + */ + @Override + public String getTitle() { + return title; + } + + /** + * {@inheritDoc} + */ + @Override + public void searchStarted() { + super.searchStarted(); + panel.searchStarted(); + } + + /** + * {@inheritDoc} + */ + @Override + public void searchFinished() { + super.searchFinished(); + panel.searchFinished(); + } + + /** + * Get outline view. You can alter it to display additional node properties, + * or set custom cell renderer. + * + * @return OutlineView used in the results displayer. + */ + public @NonNull OutlineView getOutlineView() { + return panel.getOutlineView(); + } + + /** + * {@inheritDoc} + */ + @Override + public void setInfoNode(Node infoNode) { + getPanel().setInfoNode(infoNode); + } + + /** + * Set a custom {@link ResultNodeShiftSupport} for this displayer. + */ + public void setResultNodeShiftSupport( + ResultNodeShiftSupport resultNodeShiftSupport) { + this.shiftSupport = resultNodeShiftSupport; + } + + /** + * Add a button to the results displayer toolbar. It will be shown right + * above the stop button. + * + * @param button Button to add. + */ + public void addButton(@NonNull AbstractButton button) { + Parameters.notNull("button", button); + getPanel().addButton(button); + } + + /** + * Class definining which nodes should be selected when Previous or Next + * button is pressed and what action should be performed. + */ + public static abstract class ResultNodeShiftSupport { + + /** + * Method that checks whether a node should be selected when Next or + * Previous button is pressed. + * + * @param node Node to check. + * @return True if {@code node} is a node that Next and Previous buttons + * should consider, false it if is structural or informational node + * only. + */ + public abstract boolean isRelevantNode(Node node); + + /** + * This method is called when a relevant node is selected by pressing + * Next or Previous button. + * + * Clients should implement this method to perform an appropriate + * action, e.g. to show the relevant part of found file in editor. + * + * @param node Node that has been just selected. + */ + public abstract void relevantNodeSelected(Node node); + } + + /** + * Trivial implementation of {@link ResultNodeShiftSupport} that consider + * only leaf nodes as relevant and that do nothing when a relevant node is + * selected. + */ + private static class TrivialResultNodeShiftSupport + extends ResultNodeShiftSupport { + + @Override + public boolean isRelevantNode(Node node) { + Node parent = node.getParentNode(); + return node.isLeaf() && node != null + && parent.getParentNode() != null; + } + + @Override + public void relevantNodeSelected(Node node) { + } + } +} diff --git a/api.search/src/org/netbeans/spi/search/provider/SearchResultsDisplayer.java b/api.search/src/org/netbeans/spi/search/provider/SearchResultsDisplayer.java --- a/api.search/src/org/netbeans/spi/search/provider/SearchResultsDisplayer.java +++ b/api.search/src/org/netbeans/spi/search/provider/SearchResultsDisplayer.java @@ -44,7 +44,6 @@ import javax.swing.JComponent; import org.netbeans.api.annotations.common.NonNull; import org.netbeans.api.annotations.common.NullAllowed; -import org.netbeans.modules.search.ui.DefaultSearchResultsPanel; import org.openide.nodes.Node; /** @@ -96,46 +95,14 @@ * @param title Title that will be shown in the tab of search results * window. */ - public static SearchResultsDisplayer createDefault( - @NonNull final NodeDisplayer helper, - @NonNull final SearchComposition searchComposition, - @NullAllowed final SearchProvider.Presenter presenter, - @NonNull final String title) { + public static DefaultSearchResultsDisplayer createDefault( + @NonNull NodeDisplayer helper, + @NonNull SearchComposition searchComposition, + @NullAllowed SearchProvider.Presenter presenter, + @NonNull String title) { - return new SearchResultsDisplayer() { - private DefaultSearchResultsPanel panel = null; - - @Override - public synchronized JComponent getVisualComponent() { - if (panel == null) { - panel = new DefaultSearchResultsPanel(helper, - searchComposition, presenter); - } - return panel; - } - - @Override - public void addMatchingObject(U object) { - panel.addMatchingObject(object); - } - - @Override - public String getTitle() { - return title; - } - - @Override - public void searchStarted() { - super.searchStarted(); - panel.searchStarted(); - } - - @Override - public void searchFinished() { - super.searchFinished(); - panel.searchFinished(); - } - }; + return new DefaultSearchResultsDisplayer(helper, searchComposition, + presenter, title); } /** diff --git a/api.search/test/unit/src/org/netbeans/modules/search/MatchingObjectTest.java b/api.search/test/unit/src/org/netbeans/modules/search/MatchingObjectTest.java --- a/api.search/test/unit/src/org/netbeans/modules/search/MatchingObjectTest.java +++ b/api.search/test/unit/src/org/netbeans/modules/search/MatchingObjectTest.java @@ -57,14 +57,12 @@ import org.netbeans.modules.search.MatchingObject.Def; import org.netbeans.modules.search.matcher.AbstractMatcher; import org.netbeans.modules.search.matcher.DefaultMatcher; -import org.netbeans.modules.search.ui.BasicReplaceResultsPanel; import org.netbeans.spi.queries.FileEncodingQueryImplementation; import org.netbeans.spi.search.SearchScopeDefinition; import org.netbeans.spi.search.provider.SearchComposition; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileSystem; import org.openide.filesystems.FileUtil; -import org.openide.nodes.Node; /** * @author jhavlin @@ -170,7 +168,6 @@ new DefaultMatcher(bsc.getSearchPattern()), bsc, null); EventQueue.invokeAndWait(new Runnable() { - @Override public void run() { sc.getSearchResultsDisplayer().getVisualComponent(); // initialize model @@ -216,7 +213,6 @@ @Override public SearchInfo getSearchInfo() { return new SearchInfo() { - @Override public boolean canSearch() { return true; diff --git a/api.search/test/unit/src/org/netbeans/modules/search/ui/BasicSearchResultsPanelTest.java b/api.search/test/unit/src/org/netbeans/modules/search/ui/BasicSearchResultsPanelTest.java --- a/api.search/test/unit/src/org/netbeans/modules/search/ui/BasicSearchResultsPanelTest.java +++ b/api.search/test/unit/src/org/netbeans/modules/search/ui/BasicSearchResultsPanelTest.java @@ -47,6 +47,7 @@ import org.junit.Before; import org.junit.Test; import org.netbeans.modules.search.TextDetail; +import org.openide.explorer.view.OutlineView; import org.openide.nodes.AbstractNode; import org.openide.nodes.Children; import org.openide.nodes.Node; @@ -66,6 +67,8 @@ private Node c3; private RootNode rootNode; + private AbstractSearchResultsPanel resultsPanel; + @Before public void setUp() { rootNode = new RootNode(); @@ -75,6 +78,18 @@ a1 = a.getChildren().getNodeAt(0); b2 = b.getChildren().getNodeAt(1); c3 = c.getChildren().getNodeAt(2); + resultsPanel = new AbstractSearchResultsPanel(null, null) { + + @Override + protected OutlineView getOutlineView() { + return null; + } + + @Override + protected boolean isDetailNode(Node n) { + return n.getLookup().lookup(TextDetail.class) != null; + } + }; } @Test @@ -107,12 +122,12 @@ } private Node next(Node fromNode) { - return BasicAbstractResultsPanel.findTextDetailNode(fromNode, 1, null, + return resultsPanel.findDetailNode(fromNode, 1, null, false); } private Node prev(Node fromNode) { - return BasicAbstractResultsPanel.findTextDetailNode(fromNode, -1, null, + return resultsPanel.findDetailNode(fromNode, -1, null, false); }