# HG changeset patch # User Ralph Benjamin Ruijs # Parent d0d3244ac3aa243d57729b0aa44f0bb999e37cd3 #215361 - Refactoring Results Filters diff --git a/refactoring.api/apichanges.xml b/refactoring.api/apichanges.xml --- a/refactoring.api/apichanges.xml +++ b/refactoring.api/apichanges.xml @@ -49,6 +49,25 @@ Refactoring API + + + Added an API to support filters of the Find Usages results. + + + + + +

+ This API allows refactoring plugins to add/enable filters to the + results window and refactoring elements to specify if they should + be included in the results. +

+
+ + + + +
Changed access level of #finish() to public. diff --git a/refactoring.api/nbproject/project.properties b/refactoring.api/nbproject/project.properties --- a/refactoring.api/nbproject/project.properties +++ b/refactoring.api/nbproject/project.properties @@ -4,5 +4,5 @@ javadoc.apichanges=${basedir}/apichanges.xml javadoc.title=Refactoring API -spec.version.base=1.28.0 +spec.version.base=1.29.0 test.config.stableBTD.includes=**/*Test.class diff --git a/refactoring.api/src/org/netbeans/modules/refactoring/api/AbstractRefactoring.java b/refactoring.api/src/org/netbeans/modules/refactoring/api/AbstractRefactoring.java --- a/refactoring.api/src/org/netbeans/modules/refactoring/api/AbstractRefactoring.java +++ b/refactoring.api/src/org/netbeans/modules/refactoring/api/AbstractRefactoring.java @@ -61,20 +61,21 @@ import org.netbeans.modules.refactoring.spi.GuardedBlockHandlerFactory; import org.netbeans.modules.refactoring.spi.ProgressProvider; import org.netbeans.modules.refactoring.spi.ReadOnlyFilesHandler; +import org.netbeans.modules.refactoring.spi.RefactoringElementsBag; import org.netbeans.modules.refactoring.spi.RefactoringPlugin; import org.netbeans.modules.refactoring.spi.RefactoringPluginFactory; +import org.netbeans.modules.refactoring.spi.impl.RefactoringPanel; import org.netbeans.modules.refactoring.spi.impl.Util; +import org.netbeans.modules.refactoring.spi.ui.FiltersDescription; +import org.netbeans.modules.refactoring.spi.ui.FiltersDescription.Provider; import org.openide.ErrorManager; import org.openide.filesystems.FileObject; -import org.openide.filesystems.FileUtil; import org.openide.loaders.DataObject; import org.openide.loaders.DataObjectNotFoundException; import org.openide.modules.ModuleInfo; -import org.openide.util.Lookup; -import org.netbeans.modules.refactoring.spi.RefactoringElementsBag; -import org.netbeans.modules.refactoring.spi.impl.RefactoringPanel; import org.openide.modules.Modules; import org.openide.util.Exceptions; +import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.util.Parameters; import org.openide.util.lookup.InstanceContent; @@ -116,6 +117,7 @@ private static final int PLUGIN_STEPS = 30; private ArrayList plugins; + private FiltersDescription filtersDescription; ArrayList pluginsWithProgress; @@ -136,6 +138,7 @@ if (plugins == null) { plugins = new ArrayList(); // get plugins from the lookup + filtersDescription = new FiltersDescription(); Lookup.Result result = Lookup.getDefault().lookup(new Lookup.Template(RefactoringPluginFactory.class)); for (Iterator it = result.allInstances().iterator(); it.hasNext();) { RefactoringPluginFactory factory = (RefactoringPluginFactory) it.next(); @@ -155,12 +158,20 @@ // SafeDeleteRefactoringPlugin. // #65980 plugins.add(plugin); + if(plugin instanceof FiltersDescription.Provider) { + FiltersDescription.Provider prov = (FiltersDescription.Provider) plugin; + prov.addFilters(filtersDescription); + } } } } } return plugins; } + + FiltersDescription getFiltersDescription() { + return filtersDescription; + } Collection getGBHandlers() { if (gbHandlers == null) { @@ -427,8 +438,12 @@ } catch (Throwable t) { problem =createProblemAndLog(problem, t, plugin.getClass()); } - if (problem!=null && problem.isFatal()) + if (problem!=null && problem.isFatal()) { return problem; + } else if(plugin instanceof FiltersDescription.Provider) { + Provider provider = (Provider) plugin; + provider.enableFilters(filtersDescription); + } } //TODO: diff --git a/refactoring.api/src/org/netbeans/modules/refactoring/api/AccessorImpl.java b/refactoring.api/src/org/netbeans/modules/refactoring/api/AccessorImpl.java --- a/refactoring.api/src/org/netbeans/modules/refactoring/api/AccessorImpl.java +++ b/refactoring.api/src/org/netbeans/modules/refactoring/api/AccessorImpl.java @@ -49,6 +49,7 @@ import org.netbeans.modules.refactoring.spi.GuardedBlockHandler; import org.netbeans.modules.refactoring.spi.ProblemDetailsImplementation; import org.netbeans.modules.refactoring.spi.RefactoringElementImplementation; +import org.netbeans.modules.refactoring.spi.ui.FiltersDescription; /** * @@ -96,4 +97,15 @@ public boolean hasChangesInReadOnlyFiles(RefactoringSession session) { return SPIAccessor.DEFAULT.hasChangesInReadOnlyFiles(session.getElementsBag()); } + + @Override + public FiltersDescription getFiltersDescription(AbstractRefactoring refactoring) { + return refactoring.getFiltersDescription(); + } + + @Override + public boolean isFinished(RefactoringSession session) { + return session.isFinished(); + } + } diff --git a/refactoring.api/src/org/netbeans/modules/refactoring/api/RefactoringElement.java b/refactoring.api/src/org/netbeans/modules/refactoring/api/RefactoringElement.java --- a/refactoring.api/src/org/netbeans/modules/refactoring/api/RefactoringElement.java +++ b/refactoring.api/src/org/netbeans/modules/refactoring/api/RefactoringElement.java @@ -44,9 +44,10 @@ package org.netbeans.modules.refactoring.api; import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.modules.refactoring.spi.FiltersManager; +import org.netbeans.modules.refactoring.spi.FiltersManager.Filterable; import org.netbeans.modules.refactoring.spi.RefactoringElementImplementation; import org.netbeans.modules.refactoring.spi.ui.TreeElement; -import org.netbeans.modules.refactoring.spi.ui.TreeElementFactory; import org.openide.filesystems.FileObject; import org.openide.text.PositionBounds; import org.openide.util.Lookup; @@ -180,5 +181,17 @@ return hash; } - + /** + * Indicates if this element should be included in the results. + * @param filtersManager the FiltersManager to use + * @return true if this element should be included + * @since 1.29 + */ + public boolean include(FiltersManager filtersManager) { + if(impl instanceof FiltersManager.Filterable) { + Filterable filterable = (Filterable) impl; + return filterable.filter(filtersManager); + } + return true; + } } diff --git a/refactoring.api/src/org/netbeans/modules/refactoring/api/RefactoringSession.java b/refactoring.api/src/org/netbeans/modules/refactoring/api/RefactoringSession.java --- a/refactoring.api/src/org/netbeans/modules/refactoring/api/RefactoringSession.java +++ b/refactoring.api/src/org/netbeans/modules/refactoring/api/RefactoringSession.java @@ -254,6 +254,10 @@ finished.set(true); } + boolean isFinished() { + return finished.get(); + } + /** * Adds progress listener to this RefactoringSession * @param listener to add diff --git a/refactoring.api/src/org/netbeans/modules/refactoring/api/impl/APIAccessor.java b/refactoring.api/src/org/netbeans/modules/refactoring/api/impl/APIAccessor.java --- a/refactoring.api/src/org/netbeans/modules/refactoring/api/impl/APIAccessor.java +++ b/refactoring.api/src/org/netbeans/modules/refactoring/api/impl/APIAccessor.java @@ -52,6 +52,7 @@ import org.netbeans.modules.refactoring.spi.GuardedBlockHandler; import org.netbeans.modules.refactoring.spi.ProblemDetailsImplementation; import org.netbeans.modules.refactoring.spi.RefactoringElementImplementation; +import org.netbeans.modules.refactoring.spi.ui.FiltersDescription; /** * @@ -77,7 +78,7 @@ public abstract boolean hasPluginsWithProgress(AbstractRefactoring refactoring); public abstract boolean hasChangesInGuardedBlocks(RefactoringSession session); public abstract boolean hasChangesInReadOnlyFiles(RefactoringSession session); - - + public abstract FiltersDescription getFiltersDescription(AbstractRefactoring refactoring); + public abstract boolean isFinished(RefactoringSession session); } diff --git a/refactoring.api/src/org/netbeans/modules/refactoring/spi/FiltersManager.java b/refactoring.api/src/org/netbeans/modules/refactoring/spi/FiltersManager.java new file mode 100644 --- /dev/null +++ b/refactoring.api/src/org/netbeans/modules/refactoring/spi/FiltersManager.java @@ -0,0 +1,80 @@ +/* + * 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.modules.refactoring.spi; + +import org.netbeans.modules.refactoring.api.RefactoringElement; +import org.netbeans.modules.refactoring.spi.ui.FiltersDescription; + +/** + * Handles creation and manipulation with boolean state filters. + * + * @author Ralph Benjamin Ruijs + * @see FiltersDescription + * @since 1.29 + */ +public abstract class FiltersManager { + + /** + * Indicates if a filter is selected. + * + * @param filterName the name of the filter to check + * @return Returns true when given filter is selected, false otherwise. + */ + public abstract boolean isSelected(String filterName); + + /** + * {@code RefactoringElement}s should implement this interface if they + * should be filterable in the results. + * + * @see RefactoringElement#include + */ + public static interface Filterable { + + /** + * Indicates if this element should be included in the results. + * + * @param manager the FiltersManager to use + * @return true if this element should be included + */ + boolean filter(FiltersManager manager); + } +} diff --git a/java.navigation/src/org/netbeans/modules/java/navigation/base/FiltersManager.java b/refactoring.api/src/org/netbeans/modules/refactoring/spi/impl/FiltersManagerImpl.java copy from java.navigation/src/org/netbeans/modules/java/navigation/base/FiltersManager.java copy to refactoring.api/src/org/netbeans/modules/refactoring/spi/impl/FiltersManagerImpl.java --- a/java.navigation/src/org/netbeans/modules/java/navigation/base/FiltersManager.java +++ b/refactoring.api/src/org/netbeans/modules/refactoring/spi/impl/FiltersManagerImpl.java @@ -41,8 +41,7 @@ * Version 2 license, then the option applies only if the new code is * made subject to such option by the copyright holder. */ - -package org.netbeans.modules.java.navigation.base; +package org.netbeans.modules.refactoring.spi.impl; import java.awt.Dimension; import java.awt.Insets; @@ -52,106 +51,129 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.prefs.Preferences; -import javax.swing.BorderFactory; -import javax.swing.Box; -import javax.swing.BoxLayout; import javax.swing.Icon; -import javax.swing.JComponent; import javax.swing.JToggleButton; import javax.swing.JToolBar; import javax.swing.SwingUtilities; -import javax.swing.border.EmptyBorder; import javax.swing.event.ChangeEvent; -import org.netbeans.modules.java.navigation.NoBorderToolBar; +import org.netbeans.modules.refactoring.spi.FiltersManager; +import org.netbeans.modules.refactoring.spi.ui.FiltersDescription; import org.openide.util.Mutex; -import org.openide.util.NbPreferences; -/** Handles creation and manipulation with boolean state filters. +/** + * Handles creation and manipulation with boolean state filters. * * @author Dafe Simomek */ -public final class FiltersManager { - +public final class FiltersManagerImpl extends FiltersManager { + private FiltersComponent comp; - - static FiltersManager create (FiltersDescription descr) { - return new FiltersManager(descr); + + static FiltersManagerImpl create(FiltersDescription descr) { + return new FiltersManagerImpl(descr); } - - /** Returns true when given filter is selected, false otherwise. - * Note that this method is thread safe, can be called from any thread - * (and usually will, as clients will call this from loadContent naturally) + + /** + * Indicates if a filter is selected. + * + * @param filterName the name of the filter to check + * @return Returns true when given filter is selected, false otherwise. */ - public boolean isSelected (String filterName) { + @Override + public boolean isSelected(String filterName) { return comp.isSelected(filterName); } - - /** Sets boolean value of filter with given name. True means filter is - * selected (enabled), false otherwise. Note, must be called from AWT thread. + + /** + * Sets boolean value of filter with given name. True means filter is + * selected (enabled), false otherwise. Note, must be called from AWT + * thread. */ - public void setSelected (String filterName, boolean value) { + public void setSelected(String filterName, boolean value) { comp.setFilterSelected(filterName, value); } - /** @return component instance visually representing filters */ - public JComponent getComponent ( JToggleButton[] sortButtons ) { - comp.addSortButtons( sortButtons ); - return comp; + /** + * @return component instance visually representing filters + */ + public JToolBar getComponent(JToggleButton... additionalButtons) { + if(additionalButtons != null && additionalButtons.length > 0) { + comp.addAdditionalButtons(additionalButtons); + } + return comp.toolbar; } - - /** @return Filters description */ - public FiltersDescription getDescription () { + + /** + * @return Filters description + */ + public FiltersDescription getDescription() { return comp.getDescription(); } - /** Assigns listener for listening to filter changes */ - public void hookChangeListener (FilterChangeListener l) { + /** + * Assigns listener for listening to filter changes + */ + public void hookChangeListener(FilterChangeListener l) { comp.hookFilterChangeListener(l); } - - /** Interface for listening to changes of filter states contained in FIltersPanel + + /** + * Interface for listening to changes of filter states contained in + * FIltersPanel */ public interface FilterChangeListener { - /** Called whenever some changes in state of filters contained in - * filters panel is triggered + + /** + * Called whenever some changes in state of filters contained in filters + * panel is triggered */ public void filterStateChanged(ChangeEvent e); - } // end of FilterChangeListener - - /** Private, creation managed by factory method 'create' */ - private FiltersManager (FiltersDescription descr) { + /** + * Private, creation managed by factory method 'create' + */ + private FiltersManagerImpl(FiltersDescription descr) { comp = new FiltersComponent(descr); } - - /** Swing component representing filters in panel filled with toggle buttons. + + /** + * Swing component representing filters in panel filled with toggle buttons. * Provides thread safe access to the states of filters by copying states * into private map, properly sync'ed. */ - private class FiltersComponent extends Box implements ActionListener { - - /** list of visually representing filters */ + private class FiltersComponent implements ActionListener { + + /** + * list of visually representing filters + */ private List toggles; - /** description of filters */ + /** + * description of filters + */ private final FiltersDescription filtersDesc; - - /** lock for listener */ - private Object L_LOCK = new Object(); - /** listener */ + /** + * lock for listener + */ + private final Object L_LOCK = new Object(); + /** + * listener + */ private FilterChangeListener clientL; - - /** lock for map of filter states */ - private Object STATES_LOCK = new Object(); - /** copy of filter states for accessing outside AWT */ - private Map filterStates; - + /** + * lock for map of filter states + */ + private final Object STATES_LOCK = new Object(); + /** + * copy of filter states for accessing outside AWT + */ + private Map filterStates; private JToolBar toolbar; - /** Returns selected state of given filter, thread safe. + /** + * Returns selected state of given filter, thread safe. */ - public boolean isSelected (String filterName) { + public boolean isSelected(String filterName) { Boolean result; synchronized (STATES_LOCK) { if (filterStates == null) { @@ -165,17 +187,19 @@ } result = filterStates.get(filterName); } - + if (result == null) { throw new IllegalArgumentException("Filter " + filterName + " not found."); } return result.booleanValue(); } - - /** Sets filter value, AWT only */ - public void setFilterSelected (String filterName, boolean value) { + + /** + * Sets filter value, AWT only + */ + public void setFilterSelected(String filterName, boolean value) { assert SwingUtilities.isEventDispatchThread(); - + int index = filterIndexForName(filterName); if (index < 0) { throw new IllegalArgumentException("Filter " + filterName + " not found."); @@ -188,112 +212,113 @@ // notify fireChange(); } - - public void hookFilterChangeListener (FilterChangeListener l) { + + public void hookFilterChangeListener(FilterChangeListener l) { synchronized (L_LOCK) { clientL = l; } } - - public FiltersDescription getDescription () { + + public FiltersDescription getDescription() { return filtersDesc; } - - /** Not public, instances created using factory method createPanel */ + + /** + * Not public, instances created using factory method createPanel + */ FiltersComponent(FiltersDescription descr) { - super(BoxLayout.X_AXIS); this.filtersDesc = descr; // always create swing content in AWT thread - Mutex.EVENT.readAccess(new Runnable () { - public void run () { - initPanel(); + Mutex.EVENT.readAccess(new Runnable() { + @Override + public void run() { + initPanel(); } }); } - /** Called only from AWT */ - private void initPanel () { - setBorder(new EmptyBorder(1, 2, 3, 5)); - + /** + * Called only from AWT + */ + private void initPanel() { // configure toolbar - toolbar = new NoBorderToolBar(JToolBar.HORIZONTAL); + toolbar = new JToolBar(JToolBar.VERTICAL); toolbar.setFloatable(false); toolbar.setRollover(true); - toolbar.setBorderPainted(false); - toolbar.setBorder(BorderFactory.createEmptyBorder()); + toolbar.setBorderPainted(true); + toolbar.setBorder( + javax.swing.BorderFactory.createCompoundBorder( + javax.swing.BorderFactory.createMatteBorder(0, 1, 0, 0, + javax.swing.UIManager.getDefaults().getColor("Separator.foreground")), //NOI18N + javax.swing.BorderFactory.createEmptyBorder(0, 1, 0, 0))); toolbar.setOpaque(false); toolbar.setFocusable(false); // create toggle buttons int filterCount = filtersDesc.getFilterCount(); toggles = new ArrayList(filterCount); - JToggleButton toggleButton = null; - - Map fStates = new HashMap(filterCount * 2); + JToggleButton toggleButton; + + Map fStates = new HashMap(filterCount * 2); for (int i = 0; i < filterCount; i++) { toggleButton = createToggle(fStates, i); toggles.add(toggleButton); } - + // add toggle buttons JToggleButton curToggle; for (int i = 0; i < toggles.size(); i++) { curToggle = toggles.get(i); curToggle.addActionListener(this); toolbar.add(curToggle); - if (i != toggles.size() - 1) { - toolbar.add(new Space()); - } } - - add(toolbar); - + // initialize member states map synchronized (STATES_LOCK) { filterStates = fStates; } } - - private void addSortButtons( JToggleButton[] sortButtons ) { + + private void addAdditionalButtons(JToggleButton[] sortButtons) { Dimension space = new Dimension(3, 0); - for( JToggleButton button : sortButtons ) { - Icon icon = button.getIcon(); - Dimension size = new Dimension(icon.getIconWidth() + 6, icon.getIconHeight() + 4); + for (JToggleButton button : sortButtons) { + Dimension size = new Dimension(21, 21); // 3 less than other buttons + button.setMaximumSize(size); + button.setMinimumSize(size); button.setPreferredSize(size); - button.setMargin(new Insets(2,3,2,3)); +// button.setMargin(new Insets(2, 3, 2, 3)); toolbar.addSeparator(space); - toolbar.add( button ); + toolbar.add(button); } } - - private Preferences getPreferences() { - return NbPreferences.forModule( FiltersManager.class ); - } - - private JToggleButton createToggle (Map fStates, int index) { - boolean isSelected = getPreferences().getBoolean( filtersDesc.getName(index), filtersDesc.isSelected(index) ); - Icon icon = filtersDesc.getSelectedIcon(index); + + private JToggleButton createToggle(Map fStates, int index) { + boolean isSelected = filtersDesc.isSelected(index); + Icon icon = filtersDesc.getIcon(index); // ensure small size, just for the icon JToggleButton result = new JToggleButton(icon, isSelected); - Dimension size = new Dimension(icon.getIconWidth() + 6, icon.getIconHeight() + 4); + Dimension size = new Dimension(21, 21); // 3 less than other buttons + result.setMaximumSize(size); + result.setMinimumSize(size); result.setPreferredSize(size); - result.setMargin(new Insets(2,3,2,3)); + result.setBorderPainted(false); +// result.setMargin(new Insets(2, 3, 2, 3)); result.setToolTipText(filtersDesc.getTooltip(index)); - result.setFocusable(false); - - fStates.put(filtersDesc.getName(index), Boolean.valueOf(isSelected)); - + result.setEnabled(filtersDesc.isEnabled(index)); + fStates.put(filtersDesc.getKey(index), Boolean.valueOf(isSelected)); + return result; } - /** Finds and returns index of filter with given name or -1 if no - * such filter exists. + /** + * Finds and returns index of filter with given name or -1 if no such + * filter exists. */ - private int filterIndexForName (String filterName) { + private int filterIndexForName(String filterName) { int filterCount = filtersDesc.getFilterCount(); String curName; for (int i = 0; i < filterCount; i++) { - curName = filtersDesc.getName(i); + curName = filtersDesc.getKey(i); if (filterName.equals(curName)) { return i; } @@ -301,20 +326,23 @@ return -1; } - /** Reactions to toggle button click, */ + /** + * Reactions to toggle button click, + */ + @Override public void actionPerformed(ActionEvent e) { // copy changed state first - JToggleButton toggle = (JToggleButton)e.getSource(); + JToggleButton toggle = (JToggleButton) e.getSource(); int index = toggles.indexOf(e.getSource()); synchronized (STATES_LOCK) { - filterStates.put(filtersDesc.getName(index), - Boolean.valueOf(toggle.isSelected())); + filterStates.put(filtersDesc.getKey(index), + Boolean.valueOf(toggle.isSelected())); } // notify fireChange(); } - - private void fireChange () { + + private void fireChange() { FilterChangeListener lCopy; synchronized (L_LOCK) { // no listener = no notification @@ -323,41 +351,9 @@ } lCopy = clientL; } - + // notify listener - lCopy.filterStateChanged(new ChangeEvent(FiltersManager.this)); + lCopy.filterStateChanged(new ChangeEvent(FiltersManagerImpl.this)); } - - @Override - public void removeNotify() { - //remember filter settings - if( null != filterStates ) { - Preferences prefs = getPreferences(); - for( String filterName : filterStates.keySet() ) { - prefs.putBoolean( filterName, filterStates.get( filterName ) ); - } - } - super.removeNotify(); - } - } // end of FiltersComponent - - private static class Space extends JComponent { - - private static final Dimension SPACE = new Dimension(3, 3); - - @Override - public Dimension getPreferredSize() { - return getMinimumSize(); - } - @Override - public Dimension getMaximumSize() { - return getMinimumSize(); - } - @Override - public Dimension getMinimumSize() { - return SPACE; - } - } - } diff --git a/refactoring.api/src/org/netbeans/modules/refactoring/spi/impl/RefactoringPanel.java b/refactoring.api/src/org/netbeans/modules/refactoring/spi/impl/RefactoringPanel.java --- a/refactoring.api/src/org/netbeans/modules/refactoring/spi/impl/RefactoringPanel.java +++ b/refactoring.api/src/org/netbeans/modules/refactoring/spi/impl/RefactoringPanel.java @@ -57,12 +57,12 @@ import java.lang.ref.WeakReference; import java.lang.reflect.InvocationTargetException; import java.util.*; -import java.util.Collection; +import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.Map.Entry; import java.util.prefs.Preferences; import javax.swing.*; import javax.swing.border.EmptyBorder; +import javax.swing.event.ChangeEvent; import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.parser.ParserDelegator; import javax.swing.tree.DefaultTreeModel; @@ -73,6 +73,8 @@ import org.netbeans.api.project.*; import org.netbeans.modules.parsing.api.indexing.IndexingManager; import org.netbeans.modules.refactoring.api.*; +import org.netbeans.modules.refactoring.api.impl.APIAccessor; +import org.netbeans.modules.refactoring.spi.ui.FiltersDescription; import org.netbeans.modules.refactoring.spi.ui.RefactoringCustomUI; import org.netbeans.modules.refactoring.spi.ui.RefactoringUI; import org.netbeans.modules.refactoring.spi.ui.TreeElement; @@ -85,8 +87,6 @@ import org.openide.awt.Mnemonics; import org.openide.filesystems.FileObject; import org.openide.loaders.DataObject; -import org.openide.text.CloneableEditorSupport; -import org.openide.text.PositionBounds; import org.openide.util.*; import org.openide.windows.TopComponent; @@ -95,7 +95,7 @@ * * @author Pavel Flaska, Martin Matula */ -public class RefactoringPanel extends JPanel { +public class RefactoringPanel extends JPanel implements FiltersManagerImpl.FilterChangeListener { private static final RequestProcessor RP = new RequestProcessor(RefactoringPanel.class.getName(), 1, false, false); // PRIVATE FIELDS @@ -105,7 +105,6 @@ private transient JButton refreshButton = null; /* button lying in the toolbar allows expansion of all nodes in a tree */ private transient JToggleButton expandButton = null; - private JToolBar toolBar = null; private transient JButton refactorButton = null; private transient JButton cancelButton = null; @@ -118,7 +117,7 @@ private transient boolean isVisible = false; private transient RefactoringSession session = null; private transient ParametersPanel parametersPanel = null; - private transient JScrollPane scrollPane = null; + private transient JScrollPane scrollPane = null; private transient JPanel southPanel; public JSplitPane splitPane; private JPanel left; @@ -141,18 +140,20 @@ private Component customComponent; private AtomicBoolean cancelRequest = new AtomicBoolean(); private int size = 0; - - static Image PACKAGE_BADGE = ImageUtilities.loadImage( "org/netbeans/spi/java/project/support/ui/packageBadge.gif" ); // NOI18N + private FiltersManagerImpl filtersManager; + private JComponent filterBar; + private JPanel toolbars; public RefactoringPanel(RefactoringUI ui) { this(ui,null); } public RefactoringPanel(RefactoringUI ui, TopComponent caller) { - if (caller!=null) + if (caller!=null) { refCallerTC = new WeakReference(caller); + } this.ui = ui; this.isQuery = ui.isQuery(); if (isQuery) { @@ -170,6 +171,7 @@ ui.getRefactoring().addProgressListener(fuListener = new FUListener()); } initialize(); + updateFilters(); refresh(false); } @@ -181,8 +183,9 @@ /* initializes all the ui */ private void initialize() { - if (inited) + if (inited) { return ; + } checkEventThread(); setFocusCycleRoot(true); splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); @@ -197,36 +200,39 @@ splitPane.setBorder(null); // add panel with buttons JButton[] buttons = getButtons(); - //if (buttons.length != 0) { - // there will be at least one button on panel - southPanel = new JPanel(new GridBagLayout()); - for (int i = 0; i < buttons.length; i++) { - GridBagConstraints c = new GridBagConstraints(); - c.gridy = 0; - c.insets = new Insets(5, 5, 5, 0); - southPanel.add(buttons[i], c); - } - JPanel pp = new JPanel(new BorderLayout()); + // there will be at least one button on panel + southPanel = new JPanel(new GridBagLayout()); + for (int i = 0; i < buttons.length; i++) { GridBagConstraints c = new GridBagConstraints(); c.gridy = 0; - c.insets = new Insets(5, 5, 5, 5); - c.weightx = 1; - c.fill = GridBagConstraints.HORIZONTAL; - southPanel.add(pp, c); - - if (!isQuery|| callback != null) { - left.add(southPanel, BorderLayout.SOUTH); - } - //} + c.insets = new Insets(5, 5, 5, 0); + southPanel.add(buttons[i], c); + } + JPanel pp = new JPanel(new BorderLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.gridy = 0; + c.insets = new Insets(5, 5, 5, 5); + c.weightx = 1; + c.fill = GridBagConstraints.HORIZONTAL; + southPanel.add(pp, c); + + if (!isQuery|| callback != null) { + left.add(southPanel, BorderLayout.SOUTH); + } + if ("Aqua".equals(UIManager.getLookAndFeel().getID())) { //NOI18N + southPanel.setBackground(UIManager.getColor("NbExplorerView.background")); + } // put the toolbar to the panel. If the getToolBar() returns null, // suppose the toolbar does not exist. - JToolBar toolBar = getToolBar(); - if ("Aqua".equals(UIManager.getLookAndFeel().getID())) { //NOI18N - toolBar.setBackground(UIManager.getColor("NbExplorerView.background")); - southPanel.setBackground(UIManager.getColor("NbExplorerView.background")); + JToolBar toolbar = getToolBar(); + if (toolbar != null) { + if ("Aqua".equals(UIManager.getLookAndFeel().getID())) { //NOI18N + toolbar.setBackground(UIManager.getColor("NbExplorerView.background")); + } + toolbars = new JPanel(new BorderLayout()); + toolbars.add(toolbar, BorderLayout.WEST); + left.add(toolbars, BorderLayout.WEST); } - if (toolBar != null) - left.add(toolBar, BorderLayout.WEST); validate(); inited=true; } @@ -267,9 +273,6 @@ ); expandButton.setBorderPainted(false); expandButton.addActionListener(getButtonListener()); - // create toolbar - toolBar = new JToolBar(JToolBar.VERTICAL); - toolBar.setFloatable(false); logicalViewButton = new JToggleButton( ImageUtilities.loadImageIcon("org/netbeans/modules/refactoring/api/resources/logical_view.png", false)); @@ -360,19 +363,21 @@ stopButton.setBorderPainted(false); stopButton.addActionListener(getButtonListener()); - - toolBar.add(refreshButton); - toolBar.add(prevMatch); - toolBar.add(nextMatch); - toolBar.add(logicalViewButton); - toolBar.add(physicalViewButton); - toolBar.add(expandButton); + // create toolbar + JToolBar toolbar = new JToolBar(JToolBar.VERTICAL); + toolbar.setFloatable(false); + + toolbar.add(refreshButton); + toolbar.add(stopButton); + toolbar.add(prevMatch); + toolbar.add(nextMatch); + toolbar.add(logicalViewButton); + toolbar.add(physicalViewButton); + toolbar.add(expandButton); if (ui instanceof RefactoringCustomUI) { - toolBar.add(customViewButton); + toolbar.add(customViewButton); } - toolBar.add(stopButton); - - return toolBar; + return toolbar; } /** @@ -381,7 +386,7 @@ * if you want to provide any other buttons with different action to be * performed. * - * @return array of avasilable buttons. + * @return array of available buttons. */ private JButton[] getButtons() { checkEventThread(); @@ -416,8 +421,9 @@ void switchToLogicalView() { logicalViewButton.setSelected(true); - if (currentView == LOGICAL) + if (currentView == LOGICAL) { return ; + } currentView = LOGICAL; physicalViewButton.setSelected(false); if (customViewButton!=null) { @@ -432,8 +438,9 @@ void switchToPhysicalView() { physicalViewButton.setSelected(true); - if (currentView == PHYSICAL) + if (currentView == PHYSICAL) { return ; + } currentView = PHYSICAL; logicalViewButton.setSelected(false); if (customViewButton!=null) { @@ -448,8 +455,9 @@ void switchToCustomView() { customViewButton.setSelected(true); - if (currentView == GRAPHICAL) + if (currentView == GRAPHICAL) { return ; + } currentView = GRAPHICAL; logicalViewButton.setSelected(false); physicalViewButton.setSelected(false); @@ -512,16 +520,6 @@ return node; } - private static final String getString(String key) { - return NbBundle.getMessage(RefactoringPanel.class, key); - } - - /** - * Overrides default ExplorerPanel behaviour. Does nothing now. - */ - protected void updateTitle() { - } - /** * Method is responsible for making changes in sources. */ @@ -699,17 +697,22 @@ final RefactoringPanelContainer cont = isQuery ? RefactoringPanelContainer.getUsagesComponent() : RefactoringPanelContainer.getRefactoringComponent(); cont.makeBusy(true); initialize(); + if(showParametersPanel) { + updateFilters(); + } cancelRequest.set(false); - stopButton.setVisible(isQuery); + stopButton.setVisible(isQuery && showParametersPanel); + refreshButton.setVisible(!isQuery || !showParametersPanel); stopButton.setEnabled(showParametersPanel); final String description = ui.getDescription(); setToolTipText("" + description + ""); // NOI18N final Collection elements = session.getRefactoringElements(); setName(ui.getName()); if (ui instanceof RefactoringCustomUI) { - if (customComponent==null) + if (customComponent==null) { customComponent = ((RefactoringCustomUI) ui).getCustomComponent(elements); + } this.left.remove(customComponent); } final ProgressHandle progressHandle = ProgressHandleFactory.createHandle(NbBundle.getMessage(RefactoringPanel.class, isQuery ? "LBL_PreparingUsagesTree":"LBL_PreparingRefactoringTree")); @@ -727,7 +730,12 @@ RP.post(new Runnable() { @Override public void run() { - setTreeControlsEnabled(false); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + setTreeControlsEnabled(false); + } + }); Set fileObjects = new HashSet(); int errorsNum = 0; if (!isQuery) { @@ -738,7 +746,7 @@ } } } - StringBuffer errorsDesc = getErrorDesc(errorsNum, isQuery?size:elements.size()); + StringBuffer errorsDesc = getErrorDesc(errorsNum, isQuery?size:elements.size(), 0); final CheckNode root = new CheckNode(ui, description + errorsDesc.toString() + "      ",ImageUtilities.loadImageIcon("org/netbeans/modules/refactoring/api/resources/" + (isQuery ? "findusages.png" : "refactoring.gif"), false), isQuery); final Map nodes = new HashMap(); @@ -755,14 +763,18 @@ } int i=0; + int hidden = 0; try { //[retouche] JavaModel.getJavaRepository().beginTrans(false); try { // ui.getRefactoring().setClassPath(); for (Iterator it = elements.iterator(); it.hasNext();i++) { final RefactoringElement e = (RefactoringElement) it.next(); - createNode(TreeElementFactory.getTreeElement(e), nodes, root); - + if(e.include(filtersManager)) { + createNode(TreeElementFactory.getTreeElement(e), nodes, root); + } else { + hidden++; + } if (isQuery && showParametersPanel) { if (cancelRequest.get()) { break; @@ -770,13 +782,15 @@ final boolean last = !it.hasNext(); final int occurrences = i + 1; + final int hiddenOccurrences = hidden; size = occurrences; - if (occurrences % 10 == 0 || last) { + boolean finished = APIAccessor.DEFAULT.isFinished(session); + if ((occurrences % 10 == 0 && !finished) || last) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - root.setNodeLabel(description + getErrorDesc(0, occurrences)); + root.setNodeLabel(description + getErrorDesc(0, occurrences, hiddenOccurrences)); if (last) { tree.repaint(); } @@ -784,7 +798,7 @@ }); } } - PositionBounds pb = e.getPosition(); +// PositionBounds pb = e.getPosition(); fileObjects.add(e.getParentFile()); if (!isQuery) { @@ -808,22 +822,28 @@ } finally { progressHandle.finish(); cont.makeBusy(false); - setTreeControlsEnabled(true); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { + setTreeControlsEnabled(true); stopButton.setEnabled(false); + stopButton.setVisible(false); + refreshButton.setVisible(true); + if(showParametersPanel) { + updateFilters(); + } } }); } if (!(isQuery && showParametersPanel)) { + root.setNodeLabel(description + getErrorDesc(errorsNum, isQuery?size:elements.size(), hidden).toString()); setupTree(root, showParametersPanel, elements.size()); } } - private StringBuffer getErrorDesc(int errorsNum, int occurencesNum) throws MissingResourceException { + private StringBuffer getErrorDesc(int errorsNum, int occurencesNum, int hiddenNum) throws MissingResourceException { StringBuffer errorsDesc = new StringBuffer(); errorsDesc.append(" [").append(occurencesNum); // NOI18N errorsDesc.append(' '); @@ -842,6 +862,14 @@ ); errorsDesc.append(""); // NOI18N } + if (hiddenNum > 0) { + errorsDesc.append(','); + errorsDesc.append(' '); + errorsDesc.append("").append(hiddenNum); // NOI18N + errorsDesc.append(' '); + errorsDesc.append(NbBundle.getMessage(RefactoringPanel.class, "LBL_Hidden")); + errorsDesc.append(""); // NOI18N + } errorsDesc.append(']'); return errorsDesc; } @@ -858,22 +886,18 @@ cont.addPanel(this); isVisible = true; } - if (!isQuery) + if (!isQuery) { setRefactoringEnabled(false, true); + } } private void setTreeControlsEnabled(final boolean b) { - SwingUtilities.invokeLater(new Runnable() { - - @Override - public void run() { - expandButton.setEnabled(b); - logicalViewButton.setEnabled(b); - physicalViewButton.setEnabled(b); - if (customViewButton != null) - customViewButton.setEnabled(b); - } - }); + expandButton.setEnabled(b); + logicalViewButton.setEnabled(b); + physicalViewButton.setEnabled(b); + if (customViewButton != null) { + customViewButton.setEnabled(b); + } } @@ -924,21 +948,21 @@ } } - /** - * @return true if timestamps are OK - */ - private boolean checkTimeStamps() { - Set modified = getModifiedFileObjects(); + /** + * @return true if timestamps are OK + */ + private boolean checkTimeStamps() { + Set modified = getModifiedFileObjects(); for (Entry entry: timeStamps.entrySet()) { if (modified.contains(entry.getKey())) - return false; + return false; if (!entry.getKey().isValid()) return false; if (entry.getKey().lastModified().getTime() != entry.getValue()) return false; - } - return true; - } + } + return true; + } private Set getModifiedFileObjects() { Set result = new HashSet(); @@ -998,8 +1022,9 @@ if (refactorButton != null) { refactorButton.requestFocus(); } else { - if (tree!=null) + if (tree!=null) { tree.requestFocus(); + } } } @@ -1047,13 +1072,15 @@ private int location; public void storeDividerLocation() { - if (splitPane.getRightComponent()!=null) + if (splitPane.getRightComponent()!=null) { location = splitPane.getDividerLocation(); + } } public void restoreDeviderLocation() { - if (splitPane.getRightComponent()!=null) + if (splitPane.getRightComponent()!=null) { splitPane.setDividerLocation(location); + } } private byte getPrefViewType() { @@ -1067,6 +1094,34 @@ prefs.putInt(PREF_VIEW_TYPE, currentView); } + private void updateFilters() { + if(!ui.isQuery()) { + if(filterBar != null) { + toolbars.remove(filterBar); + filterBar = null; + filtersManager = null; + } + return; + } + + if(filtersManager != null) { + toolbars.remove(filterBar); + filterBar = null; + filtersManager = null; + } + final FiltersDescription desc = APIAccessor.DEFAULT.getFiltersDescription(ui.getRefactoring()); + filtersManager = FiltersManagerImpl.create(desc == null? new FiltersDescription() : desc); + filterBar = filtersManager.getComponent(); + toolbars.add(filterBar, BorderLayout.EAST); + filtersManager.hookChangeListener(this); + toolbars.validate(); + } + + @Override + public void filterStateChanged(ChangeEvent e) { + refresh(false); + } + //////////////////////////////////////////////////////////////////////////// // INNER CLASSES //////////////////////////////////////////////////////////////////////////// @@ -1086,10 +1141,11 @@ } // expandAll button selected/deselected else if (o == expandButton && tree != null) { - if (expandButton.isSelected()) + if (expandButton.isSelected()) { expandAll(); - else + } else { collapseAll(); + } } else if (o == refreshButton) { if (callback!=null) { close(); @@ -1117,6 +1173,8 @@ private void stopSearch() { stopButton.setEnabled(false); + stopButton.setVisible(false); + refreshButton.setVisible(true); cancelRequest.set(true); ui.getRefactoring().cancelRequest(); } diff --git a/java.navigation/src/org/netbeans/modules/java/navigation/base/FiltersDescription.java b/refactoring.api/src/org/netbeans/modules/refactoring/spi/ui/FiltersDescription.java copy from java.navigation/src/org/netbeans/modules/java/navigation/base/FiltersDescription.java copy to refactoring.api/src/org/netbeans/modules/refactoring/spi/ui/FiltersDescription.java --- a/java.navigation/src/org/netbeans/modules/java/navigation/base/FiltersDescription.java +++ b/refactoring.api/src/org/netbeans/modules/refactoring/spi/ui/FiltersDescription.java @@ -41,83 +41,186 @@ * Version 2 license, then the option applies only if the new code is * made subject to such option by the copyright holder. */ - -package org.netbeans.modules.java.navigation.base; +package org.netbeans.modules.refactoring.spi.ui; import java.util.ArrayList; import java.util.List; import javax.swing.Icon; +import org.netbeans.api.annotations.common.NonNull; /** - * @author Dafe Simonek + * @author Ralph Benjamin Ruijs + * @since 1.29 */ public final class FiltersDescription { - public static FiltersManager createManager (FiltersDescription descr) { - return FiltersManager.create(descr); - } - - /** List of describing filters properties */ + /** + * List of {@code FilterItem}s describing filters properties + */ private List filters; - /** Creates a new instance of FiltersDescription */ + /** + * Creates a new instance of FiltersDescription + */ public FiltersDescription() { filters = new ArrayList(); } - - public void addFilter (String name, String displayName, String tooltip, - boolean isSelected, Icon selectedIcon, Icon unselectedIcon) { - FilterItem newItem = new FilterItem(name, displayName, tooltip, - isSelected, selectedIcon, unselectedIcon); + + /** + * Add a new filter to the FiltersDescription. Filters are by default + * disabled. {@code FiltersDescription.Provider}s should enable them when + * used. + * + * @param key identifier for the filter + * @param tooltip text to display in the tooltip of the filter button + * @param selected true if the filter should be selected + * @param icon icon to use for the filter button + */ + public void addFilter(@NonNull String key, @NonNull String tooltip, + boolean selected, @NonNull Icon icon) { + FilterItem newItem = new FilterItem(key, tooltip, selected, icon); filters.add(newItem); } - - public int getFilterCount () { + + /** + * Returns the number of filters in this description. + * + * @return the number of filters in this description + */ + public int getFilterCount() { return filters.size(); } - - public String getName (int index) { - return filters.get(index).name; + + /** + * Returns the key of the filter at the supplied index. + * + * @param index the index of the filter + * @return the key + * @throws IndexOutOfBoundsException if the index is out of range + * ({@code index < 0 || index >= size()}) + */ + public @NonNull + String getKey(int index) { + return filters.get(index).key; } - - public String getDisplayName (int index) { - return filters.get(index).displayName; - } - - public String getTooltip (int index) { + + /** + * Returns the tooltip of the filter at the supplied index. + * + * @param index the index of the filter + * @return the tooltip + * @throws IndexOutOfBoundsException if the index is out of range + * ({@code index < 0 || index >= size()}) + */ + public @NonNull + String getTooltip(int index) { return filters.get(index).tooltip; } - - public Icon getSelectedIcon (int index) { - return filters.get(index).selectedIcon; + + /** + * Returns the icon of the filter at the supplied index. + * + * @param index the index of the filter + * @return the icon + * @throws IndexOutOfBoundsException if the index is out of range + * ({@code index < 0 || index >= size()}) + */ + public @NonNull + Icon getIcon(int index) { + return filters.get(index).icon; } - - public Icon getUnselectedIcon (int index) { - return filters.get(index).unselectedIcon; + + /** + * Returns true if the filter at the supplied index is selected. + * + * @param index the index of the filter + * @return true if the filter is selected. + * @throws IndexOutOfBoundsException if the index is out of range + * ({@code index < 0 || index >= size()}) + */ + public boolean isSelected(int index) { + return filters.get(index).selected; } - - public boolean isSelected (int index) { - return filters.get(index).isSelected; + + /** + * Enable the filter at the supplied index. + * + * @param index the index of the filter + * @throws IndexOutOfBoundsException if the index is out of range + * ({@code index < 0 || index >= size()}) + */ + public void enable(int index) { + filters.get(index).enabled = true; } - - static class FilterItem { - String name; - String displayName; + + /** + * Enable the filter with the supplied key. If there is no filter with the + * supplied key, nothing will change. + * + * @param key the key of a filter + */ + public void enable(@NonNull String key) { + for (FilterItem filterItem : filters) { + if (filterItem.key.contentEquals(key)) { + filterItem.enabled = true; + break; + } + } + } + + /** + * Returns true if the filter at the supplied index is enabled. + * + * @param index the index of the filter + * @return true if the filter is enabled. + * @throws IndexOutOfBoundsException if the index is out of range + * ({@code index < 0 || index >= size()}) + */ + public boolean isEnabled(int index) { + return filters.get(index).enabled; + } + + private static class FilterItem { + + String key; String tooltip; - Icon selectedIcon; - Icon unselectedIcon; - boolean isSelected; - - FilterItem (String name, String displayName, String tooltip, - boolean isSelected, Icon selectedIcon, Icon unselectedIcon) { - this.name = name; - this.displayName = displayName; + Icon icon; + boolean selected; + boolean enabled; + + FilterItem(String key, String tooltip, + boolean selected, Icon icon) { + this.key = key; this.tooltip = tooltip; - this.selectedIcon = selectedIcon; - this.unselectedIcon = unselectedIcon; - this.isSelected = isSelected; + this.icon = icon; + this.selected = selected; + this.enabled = false; } - } - + + /** + * {@code RefactoringPlugin}s can implement this interface if they want to + * supply new filters, or enable existing filters. + */ + public static interface Provider { + + /** + * Add filters to the supplied {@code FiltersDescription}. This method + * will be called after the plugin is received from the + * {@code RefactoringPluginFactory}. + * + * @param filtersDescription the {@code FiltersDescription} to add filters to + * @see FiltersDescription#addFilter + */ + void addFilters(FiltersDescription filtersDescription); + + /** + * Enable filters in the supplied {@code FiltersDescription}. This method + * will be called after the plugins {@code RefactoringPlugin#prepare} method is called. + * + * @param filtersDescription the {@code FiltersDescription} to enable filters from + * @see FiltersDescription#enable + */ + void enableFilters(FiltersDescription filtersDescription); + } }