--- a/refactoring.api/apichanges.xml +++ a/refactoring.api/apichanges.xml @@ -49,6 +49,26 @@ Refactoring API + + + Added support for Scope Providers and ExpandableTreeElements. + + + + + +

+ Added an ExpandableTreeElement and a declarative way to add new scopes. +

+
+ + + + + + + +
Added an API to support filters of the Find Usages results. --- a/refactoring.api/nbproject/project.properties +++ a/refactoring.api/nbproject/project.properties @@ -4,5 +4,5 @@ javadoc.apichanges=${basedir}/apichanges.xml javadoc.title=Refactoring API -spec.version.base=1.29.0 +spec.version.base=1.30.0 test.config.stableBTD.includes=**/*Test.class --- a/refactoring.api/src/org/netbeans/modules/refactoring/spi/impl/Bundle.properties +++ a/refactoring.api/src/org/netbeans/modules/refactoring/spi/impl/Bundle.properties @@ -78,8 +78,9 @@ LBL_InReadOnlyFile=Error: this occurrence is in a read-only file and cannot be refactored. LBL_CannotRefactorGuardedBlock=Read-only block of text cannot be refactored. LBL_CannotRefactorReadOnlyFile=Read-only files cannot be refactored. -LBL_Occurence=occurrence -LBL_Occurences=occurrences +# "There {0,choice,0#are no files|1#is one file|1 subelements = new ArrayList(); + + for (TreeElement el : ((ExpandableTreeElement) userObject)) { + subelements.add(el); + } + + SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { + for (TreeElement el : subelements) { + insert(new CheckNode(el, el.getText(/*XXX:*/true), el.getIcon(), isQuery), getChildCount() - 1); + } + int[] added = new int[getChildCount() - 1]; + for (int i = 0; i < added.length; i++) { + added[i] = i; + } + model.nodesWereInserted(CheckNode.this, added); + int childCount = getChildCount(); + Object last = getChildAt(childCount - 1); + int index = model.getIndexOfChild(CheckNode.this, last); + remove(index); //remove the please wait node + model.nodesWereRemoved(CheckNode.this, new int[] {index}, new Object[] {last}); + } + }); + } + }); + } + } + } } --- a/refactoring.api/src/org/netbeans/modules/refactoring/spi/impl/RefactoringPanel.java +++ a/refactoring.api/src/org/netbeans/modules/refactoring/spi/impl/RefactoringPanel.java @@ -63,10 +63,13 @@ import java.util.prefs.Preferences; import javax.swing.*; import javax.swing.border.EmptyBorder; +import javax.swing.event.TreeExpansionEvent; +import javax.swing.event.TreeWillExpandListener; import javax.swing.event.ChangeEvent; import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.parser.ParserDelegator; import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.ExpandVetoException; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import org.netbeans.api.progress.ProgressHandle; @@ -75,6 +78,7 @@ 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.ExpandableTreeElement; import org.netbeans.modules.refactoring.spi.ui.FiltersDescription; import org.netbeans.modules.refactoring.spi.ui.RefactoringCustomUI; import org.netbeans.modules.refactoring.spi.ui.RefactoringUI; @@ -699,6 +703,7 @@ final RefactoringPanelContainer cont = isQuery ? RefactoringPanelContainer.getUsagesComponent() : RefactoringPanelContainer.getRefactoringComponent(); cont.makeBusy(true); final AtomicInteger size = new AtomicInteger(); + final AtomicBoolean sizeIsApproximate = new AtomicBoolean(); initialize(); if(showParametersPanel) { updateFilters(); @@ -749,8 +754,8 @@ } } } - StringBuffer errorsDesc = getErrorDesc(errorsNum, isQuery?size.get():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); + StringBuffer errorsDesc = getErrorDesc(errorsNum, isQuery?size.get():elements.size(), 0, isQuery && sizeIsApproximate.get()); + 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(); if (isQuery && showParametersPanel) { @@ -773,14 +778,17 @@ // ui.getRefactoring().setClassPath(); for (Iterator it = elements.iterator(); it.hasNext();i++) { final RefactoringElement e = (RefactoringElement) it.next(); + TreeElement treeElement = null; if(e.include(filtersManager)) { - createNode(TreeElementFactory.getTreeElement(e), nodes, root); + treeElement = TreeElementFactory.getTreeElement(e); + createNode(treeElement, nodes, root); } else { hidden++; } - final int occurrences = i + 1; + final int occurrences = i + (treeElement instanceof ExpandableTreeElement ? ((ExpandableTreeElement) treeElement).estimateChildCount() : 1); final int hiddenOccurrences = hidden; size.set(occurrences); + sizeIsApproximate.compareAndSet(false, treeElement instanceof ExpandableTreeElement); if (isQuery && showParametersPanel) { if (cancelRequest.get()) { break; @@ -791,7 +799,7 @@ SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - root.setNodeLabel(description + getErrorDesc(0, occurrences, hiddenOccurrences)); + root.setNodeLabel(description + getErrorDesc(0, occurrences, hiddenOccurrences, isQuery && sizeIsApproximate.get())); if (last) { tree.repaint(); } @@ -838,19 +846,18 @@ } if (!(isQuery && showParametersPanel)) { - root.setNodeLabel(description + getErrorDesc(errorsNum, isQuery ? size.get() : elements.size(), hidden).toString()); + root.setNodeLabel(description + getErrorDesc(errorsNum, isQuery ? size.get() : elements.size(), hidden, isQuery && sizeIsApproximate.get()).toString()); setupTree(root, showParametersPanel, elements.size()); } } - private StringBuffer getErrorDesc(int errorsNum, int occurencesNum, int hiddenNum) throws MissingResourceException { + private StringBuffer getErrorDesc(int errorsNum, int occurencesNum, int hiddenNum, boolean occurencesNumApproximate) throws MissingResourceException { StringBuffer errorsDesc = new StringBuffer(); - errorsDesc.append(" [").append(occurencesNum); // NOI18N - errorsDesc.append(' '); - errorsDesc.append(occurencesNum == 1 ? - NbBundle.getMessage(RefactoringPanel.class, "LBL_Occurence") : - NbBundle.getMessage(RefactoringPanel.class, "LBL_Occurences") + errorsDesc.append(" ["); // NOI18N + errorsDesc.append(occurencesNumApproximate ? + NbBundle.getMessage(RefactoringPanel.class, "LBL_OccurencesApproximate", occurencesNum) : + NbBundle.getMessage(RefactoringPanel.class, "LBL_Occurences", occurencesNum) ); if (errorsNum > 0) { errorsDesc.append(','); @@ -1003,6 +1010,18 @@ tree.setModel(new DefaultTreeModel(root)); } tree.setRowHeight((int) ((CheckRenderer) tree.getCellRenderer()).getPreferredSize().getHeight()); + + this.tree.addTreeWillExpandListener(new TreeWillExpandListener() { + @Override public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException { + Object last = event.getPath().getLastPathComponent(); + + if (last instanceof CheckNode) { + ((CheckNode) last).ensureChildrenFilled((DefaultTreeModel) RefactoringPanel.this.tree.getModel()); + } + } + + @Override public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException { } + }); } private void setupInstantTree(final CheckNode root, final boolean showParametersPanel) { @@ -1236,6 +1255,7 @@ protected void closeNotify() { if (fuListener!=null) { + stopSearch(); ui.getRefactoring().removeProgressListener(fuListener); } timeStamps.clear(); --- a/refactoring.api/src/org/netbeans/modules/refactoring/spi/impl/ScopeAnnotationProcessor.java +++ a/refactoring.api/src/org/netbeans/modules/refactoring/spi/impl/ScopeAnnotationProcessor.java @@ -0,0 +1,160 @@ +/* + * 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.impl; + +import java.util.List; +import java.util.Set; +import javax.annotation.processing.Processor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Types; +import javax.tools.Diagnostic; +import org.netbeans.modules.refactoring.spi.ui.ScopeDescription; +import org.netbeans.modules.refactoring.spi.ui.ScopeReference; +import org.netbeans.modules.refactoring.spi.ui.ScopeReferences; +import org.openide.filesystems.annotations.LayerBuilder; +import org.openide.filesystems.annotations.LayerGeneratingProcessor; +import org.openide.filesystems.annotations.LayerGenerationException; +import org.openide.util.lookup.ServiceProvider; + +/** + * + * @author Ralph Benjamin Ruijs + */ +@SupportedSourceVersion(SourceVersion.RELEASE_6) +@SupportedAnnotationTypes({"org.netbeans.modules.refactoring.spi.ui.ScopeDescription", +"org.netbeans.modules.refactoring.spi.ui.ScopeReference", +"org.netbeans.modules.refactoring.spi.ui.ScopeReferences"}) +@ServiceProvider(service = Processor.class) +public class ScopeAnnotationProcessor extends LayerGeneratingProcessor { + + @Override + protected boolean handleProcess(Set annotations, RoundEnvironment roundEnv) throws LayerGenerationException { + if (!roundEnv.processingOver()) { + generateTypeList(roundEnv); + } + + return false; + } + + private void generateTypeList(RoundEnvironment roundEnv) throws LayerGenerationException { + TypeElement scopeDescription = processingEnv.getElementUtils().getTypeElement("org.netbeans.modules.refactoring.spi.ui.ScopeDescription"); + TypeElement scopeReference = processingEnv.getElementUtils().getTypeElement("org.netbeans.modules.refactoring.spi.ui.ScopeReference"); + TypeElement scopeReferences = processingEnv.getElementUtils().getTypeElement("org.netbeans.modules.refactoring.spi.ui.ScopeReferences"); + TypeMirror customProvider = processingEnv.getElementUtils().getTypeElement("org.netbeans.modules.refactoring.spi.ui.ScopeProvider.CustomScopeProvider").asType(); + TypeMirror provider = processingEnv.getElementUtils().getTypeElement("org.netbeans.modules.refactoring.spi.ui.ScopeProvider").asType(); + if (scopeDescription == null || scopeReference == null || scopeReferences == null) { + return; + } + Types typeUtils = processingEnv.getTypeUtils(); + + for (Element annotated : roundEnv.getElementsAnnotatedWith(scopeDescription)) { + boolean custom; + if (typeUtils.isSubtype(annotated.asType(), customProvider)) { + custom = true; + } else if (typeUtils.isSubtype(annotated.asType(), provider)) { + custom = false; + } else { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, ERR_SUPER_TYPE, annotated); + continue; + } + ScopeDescription ar = annotated.getAnnotation(ScopeDescription.class); + LayerBuilder builder = layer(annotated); + LayerBuilder.File f = builder.file("Scopes/ScopeDescriptions/" + ar.id() + ".instance"); + f.bundlevalue("displayName", ar.displayName(), ar, "displayName"); + f.stringvalue("id", ar.id()); + f.stringvalue("iconBase", ar.iconBase()); + f.intvalue("position", ar.position()); + f.newvalue("delegate", getFQN((TypeElement) annotated)); + + if (custom) { + f.stringvalue("instanceClass", "org.netbeans.modules.refactoring.spi.ui.ScopeProvider"); + f.methodvalue("instanceCreate", "org.netbeans.modules.refactoring.spi.impl.Scopes", "createCustom"); + } else { + f.stringvalue("instanceClass", "org.netbeans.modules.refactoring.spi.ui.ScopeProvider"); + f.methodvalue("instanceCreate", "org.netbeans.modules.refactoring.spi.impl.Scopes", "create"); + } + f.write(); + } + for (Element annotated : roundEnv.getElementsAnnotatedWith(ScopeReferences.class)) { + final LayerBuilder builder = layer(annotated); + ScopeReferences refs = annotated.getAnnotation(ScopeReferences.class); + if (refs == null) { + continue; + } + for (ScopeReference ar : refs.value()) { + processReference(ar, annotated, builder); + } + } + + for (Element annotated : roundEnv.getElementsAnnotatedWith(scopeReference)) { + ScopeReference ar = annotated.getAnnotation(ScopeReference.class); + processReference(ar, annotated, layer(annotated)); + } + } + private static final String ERR_SUPER_TYPE = "The class must extend org.netbeans.modules.refactoring.api.AbstractAnnotatedRefactoring"; + private static final String ERR_ID_NEEDED = "This annotation needs to be used together with ScopeDescription, or you need to specify the id."; + + private String getFQN(TypeElement clazz) { + return processingEnv.getElementUtils().getBinaryName(clazz).toString(); + } + + private void processReference(ScopeReference ar, Element annotated, LayerBuilder builder) { + String id = ar.id(); + if (id.isEmpty()) { + ScopeDescription desc = annotated.getAnnotation(ScopeDescription.class); + if (desc == null) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, ERR_ID_NEEDED, annotated); + } else { + id = desc.id(); + } + } + LayerBuilder.File f = builder.file("Scopes/" + ar.path() + "/" + id + ".shadow"); + f.stringvalue("originalFile", "Scopes/ScopeDescriptions/" + id + ".instance"); + f.write(); + } +} --- a/refactoring.api/src/org/netbeans/modules/refactoring/spi/impl/Scopes.java +++ a/refactoring.api/src/org/netbeans/modules/refactoring/spi/impl/Scopes.java @@ -0,0 +1,223 @@ +/* + * 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.impl; + +import java.awt.Image; +import java.awt.Toolkit; +import java.net.URL; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; +import javax.swing.Icon; +import org.netbeans.modules.refactoring.api.Scope; +import org.netbeans.modules.refactoring.spi.ui.ScopeProvider; +import org.openide.util.ImageUtilities; +import org.openide.util.Lookup; + +/** + * + * @author Ralph Benjamin Ruijs + */ +public class Scopes { + + public static ScopeProvider create(Map m) { + return new ScopeProviderImpl(m); + } + + public static ScopeProvider.CustomScopeProvider createCustom(Map m) { + return new CustomScopeProviderImpl(m); + } + + public static class ScopeProviderImpl extends ScopeProvider implements ScopeInformation { + + private final String displayName; + private final Icon icon; + private final ScopeProvider delegate; + private final String id; + private final Integer position; + + public ScopeProviderImpl(Map m) { + displayName = (String) m.get("displayName"); // NOI18N + id = (String) m.get("id"); // NOI18N + position = (Integer) m.get("position"); // NOI18N + icon = resolveIcon(m.get("iconBase")); // NOI18N + Object scopeProvider = m.get("delegate"); + if (!(scopeProvider instanceof ScopeProvider)) { + throw new NullPointerException("No 'delegate' in " + m); + } + delegate = (ScopeProvider) scopeProvider; + } + + @Override + public String getId() { + return id; + } + + @Override + public int getPosition() { + return position; + } + + @Override + public Icon getIcon() { + Icon delegateIcon = delegate.getIcon(); + return delegateIcon == null ? this.icon : delegateIcon; + } + + @Override + public String getDisplayName() { + return displayName; + } + + @Override + public String getDetail() { + return delegate.getDetail(); + } + + @Override + public boolean initialize(Lookup context, AtomicBoolean cancel) { + return delegate.initialize(context, cancel); + } + + @Override + public Scope getScope() { + return delegate.getScope(); + } + } + + public static class CustomScopeProviderImpl extends ScopeProvider.CustomScopeProvider implements ScopeInformation { + private final String displayName; + private final Icon icon; + private final CustomScopeProvider delegate; + private final String id; + private final Integer position; + + private CustomScopeProviderImpl(Map m) { + displayName = (String) m.get("displayName"); // NOI18N + id = (String) m.get("id"); // NOI18N + position = (Integer) m.get("position"); // NOI18N + icon = resolveIcon(m.get("iconBase")); // NOI18N + Object scopeProvider = m.get("delegate"); + if (!(scopeProvider instanceof CustomScopeProvider)) { + throw new NullPointerException("No 'delegate' in " + m); + } + delegate = (CustomScopeProvider) scopeProvider; + } + + @Override + public String getId() { + return id; + } + + @Override + public int getPosition() { + return position; + } + + @Override + public Icon getIcon() { + Icon delegateIcon = delegate.getIcon(); + return delegateIcon == null ? this.icon : delegateIcon; + } + + @Override + public String getDisplayName() { + return displayName; + } + + @Override + public String getDetail() { + return delegate.getDetail(); + } + + @Override + public void setScope(Scope value) { + delegate.setScope(value); + } + + @Override + public boolean showCustomizer() { + return delegate.showCustomizer(); + } + + @Override + public boolean initialize(Lookup context, AtomicBoolean cancel) { + return delegate.initialize(context, cancel); + } + + @Override + public Scope getScope() { + return delegate.getScope(); + } + } + + private static Icon resolveIcon(Object icon) { + if (icon instanceof Icon) { + return (Icon) icon; + } + if (icon instanceof URL) { + icon = Toolkit.getDefaultToolkit().getImage((URL) icon); + } + if (icon instanceof Image) { + return ImageUtilities.image2Icon((Image) icon); + } + if (icon instanceof String) { + return ImageUtilities.loadImageIcon((String) icon, true); + } + return null; + } + + public static interface ScopeInformation { + public String getDisplayName(); + + public int getPosition(); + + public String getId(); + + public String getDetail(); + + public Icon getIcon(); + + public boolean initialize(Lookup context, AtomicBoolean cancel); + + public Scope getScope(); + } +} --- a/refactoring.api/src/org/netbeans/modules/refactoring/spi/ui/Bundle.properties +++ a/refactoring.api/src/org/netbeans/modules/refactoring/spi/ui/Bundle.properties @@ -0,0 +1,1 @@ +LBL_Scope=Sco&pe: --- a/refactoring.api/src/org/netbeans/modules/refactoring/spi/ui/ExpandableTreeElement.java +++ a/refactoring.api/src/org/netbeans/modules/refactoring/spi/ui/ExpandableTreeElement.java @@ -0,0 +1,67 @@ +/* + * 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.ui; + +import org.openide.util.Cancellable; + +/** + * ExpandableTreeElements are shown in the Find Usages results. + * ExpandableTreeElement allows a TreeElement to have children. It will be + * iterated when the TreeElement is expanded. The iterator is allowed to block, + * it will be called from outside of AWT. + * + * @author Jan Lahoda + * @author Ralph Benjamin Ruijs + * @see TreeElement + * @since 1.30 + */ +public interface ExpandableTreeElement extends TreeElement, Iterable, Cancellable { + + /** + * Gives an estimate of the amount of children this element has. + * The estimatedChildCount will be used to give the user a rough count + * of found occurrences. + * @return the estimated child count + */ + public int estimateChildCount(); + +} --- a/refactoring.api/src/org/netbeans/modules/refactoring/spi/ui/ScopeDescription.java +++ a/refactoring.api/src/org/netbeans/modules/refactoring/spi/ui/ScopeDescription.java @@ -0,0 +1,86 @@ +/* + * 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.ui; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * @author Jan Lahoda + * @author Ralph Benjamin Ruijs + * @since 1.30 + */ +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.SOURCE) +public @interface ScopeDescription { + + /** + * The unique ID of the scope description. + * + * @return unique id + */ + String id(); + + /** + * Display name. Usually prefixed with '#' to reference value from a + * Bundle.properties file in the same package. + * + * @return display name for the scope + */ + String displayName(); + + /** + * Path to image representing the scope's icon. + * + * @return "org/myproject/mypkg/Icon.png" + */ + String iconBase() default ""; + + /** + * Position in the location. Negative numbers can be used for scopes that + * should be higher in the list, but not selected by default. + */ + int position() default Integer.MAX_VALUE; +} --- a/refactoring.api/src/org/netbeans/modules/refactoring/spi/ui/ScopePanel.form +++ a/refactoring.api/src/org/netbeans/modules/refactoring/spi/ui/ScopePanel.form @@ -0,0 +1,58 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
--- a/refactoring.api/src/org/netbeans/modules/refactoring/spi/ui/ScopePanel.java +++ a/refactoring.api/src/org/netbeans/modules/refactoring/spi/ui/ScopePanel.java @@ -0,0 +1,359 @@ +/* + * 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.ui; + +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.prefs.Preferences; +import javax.swing.AbstractAction; +import javax.swing.ComboBoxModel; +import javax.swing.DefaultComboBoxModel; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.ListCellRenderer; +import javax.swing.SwingUtilities; +import javax.swing.plaf.UIResource; +import org.netbeans.api.annotations.common.CheckForNull; +import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.modules.refactoring.api.Scope; +import org.netbeans.modules.refactoring.spi.impl.Scopes; +import org.openide.util.Lookup; +import org.openide.util.lookup.Lookups; + +/** + * ScopePanel provides a component to use for scope selection. A customize + * button (a JButton with ellipses) will be displayed when any of the registered + * scopes is customizable. + * + * @author Ralph Benjamin Ruijs + * @since 1.30 + */ +public class ScopePanel extends javax.swing.JPanel { + + private static final String ELLIPSIS = "\u2026"; //NOI18N + private static final int SCOPE_COMBOBOX_COLUMNS = 14; + private final String id; + private final Preferences preferences; + private final String preferencesKey; + + /** + * Creates new form ScopePanel. + * + * @deprecated do not use this constructor. Only available for the Matisse + * GUI-builder. + */ + @Deprecated + public ScopePanel() { + this(null, null, null); + } + + /** + * Creates a new ScopePanel. The supplied id will be used to only get the + * Scopes registered for a specific set of Scopes. The preferences and + * preferencesKey will be used to store the user's selection. + * + * @param id the id for which the scopes are registered + * @param preferences a preferences object to store user's selection + * @param preferencesKey a key to use to store user's selection + */ + public ScopePanel(String id, Preferences preferences, String preferencesKey) { + this.id = id; + this.preferences = preferences; + this.preferencesKey = preferencesKey; + initComponents(); + } + + /** + * Initializes the Combobox and customize button of this ScopePanel. The + * context will be passed to the different ScopeProviders initialize method. + * This method will return false if there are no available scopes and this + * panel should not be available to the user. + * + * @param context the Lookup to pass to the ScopeProviders + * @return true if there is at least one Scope available, false otherwise + */ + public boolean initialize(Lookup context, AtomicBoolean cancel) { + final List scopes = new ArrayList(); + Collection scopeProviders = Lookups.forPath("Scopes" + "/" + id).lookupAll(ScopeProvider.class); + final AtomicBoolean customizable = new AtomicBoolean(); + for (ScopeProvider provider : scopeProviders) { + if(provider.initialize(context, new AtomicBoolean())) { + scopes.add((Scopes.ScopeInformation)provider); + if(provider instanceof ScopeProvider.CustomScopeProvider) { + customizable.set(true); + } + } + } + + Collections.sort(scopes, new Comparator() { + @Override public int compare(Scopes.ScopeInformation o1, Scopes.ScopeInformation o2) { + return (o1.getPosition()//GEN-BEGIN:initComponents + private void initComponents() { + + btnCustomScope = new javax.swing.JButton(); + scopeCombobox = new javax.swing.JComboBox(); + + btnCustomScope.setAction(new ScopeAction(scopeCombobox)); + org.openide.awt.Mnemonics.setLocalizedText(btnCustomScope, "..."); // NOI18N + + scopeCombobox.setRenderer(new ScopeDescriptionRenderer()); + ((javax.swing.JTextField) scopeCombobox.getEditor().getEditorComponent()).setColumns(SCOPE_COMBOBOX_COLUMNS); + scopeCombobox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + scopeComboboxActionPerformed(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(scopeCombobox, 0, 343, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnCustomScope)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btnCustomScope) + .addComponent(scopeCombobox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + ); + }// //GEN-END:initComponents + + private void scopeComboboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scopeComboboxActionPerformed + preferences.putInt(preferencesKey, scopeCombobox.getSelectedIndex()); + }//GEN-LAST:event_scopeComboboxActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton btnCustomScope; + private javax.swing.JComboBox scopeCombobox; + // End of variables declaration//GEN-END:variables + + /** + * Change the selected scope to one with the specified id. If the id does + * not exist, nothing is changed. When the id is from a CustomScopeProvider + * and it returns an empty scope, the preferred scope is selected. + * + * @see ScopeProvider.CustomScopeProvider + * + * @param id the id of the scope to select + */ + public void selectScopeById(@NonNull String id) { + ComboBoxModel m = scopeCombobox.getModel(); + + for (int i = 0; i < m.getSize(); i++) { + Scopes.ScopeInformation sd = (Scopes.ScopeInformation) m.getElementAt(i); + + if (sd.getId().equals(id)) { + if (sd instanceof ScopeProvider.CustomScopeProvider) { + Scope s = sd.getScope(); + if (s !=null && + s.getFiles().isEmpty() && + s.getFolders().isEmpty() && + s.getSourceRoots().isEmpty()) { + selectPreferredScope(); + return; + } + } + scopeCombobox.setSelectedItem(sd); + return ; + } + } + } + + private void selectPreferredScope() { + ComboBoxModel m = scopeCombobox.getModel(); + + for (int i = 0; i < m.getSize(); i++) { + Scopes.ScopeInformation sd = (Scopes.ScopeInformation) m.getElementAt(i); + + if (sd.getPosition() >= 0) { + scopeCombobox.setSelectedItem(sd); + return; + } + } + } + + private class ScopeAction extends AbstractAction { + private final JComboBox scopeCombobox; + + private ScopeAction(JComboBox scopeCombobox) { + this.scopeCombobox = scopeCombobox; + this.putValue(NAME, ELLIPSIS); + } + + @Override + public void actionPerformed(ActionEvent e) { + ComboBoxModel m = this.scopeCombobox.getModel(); + ScopeProvider selectedScope = (ScopeProvider) scopeCombobox.getSelectedItem(); + Scope scope = selectedScope.getScope(); + if (selectedScope instanceof ScopeProvider.CustomScopeProvider) { + showCustomizer((Scopes.CustomScopeProviderImpl)selectedScope, scope); + } else { + for (int i = 0; i < m.getSize(); i++) { + ScopeProvider sd = (ScopeProvider) m.getElementAt(i); + + if (sd instanceof Scopes.CustomScopeProviderImpl) { + showCustomizer((Scopes.CustomScopeProviderImpl)sd, scope); + break; + } + } + } + } + + private void showCustomizer(Scopes.CustomScopeProviderImpl csd, Scope scope) { + csd.setScope(scope); + if (csd.showCustomizer()) { + selectScopeById(csd.getId()); + } + } + } + + private static class ScopeDescriptionRenderer extends JLabel implements ListCellRenderer, UIResource { + public ScopeDescriptionRenderer () { + setOpaque(true); + } + @Override + public Component getListCellRendererComponent( + JList list, + Object value, + int index, + boolean isSelected, + boolean cellHasFocus) { + + // #89393: GTK needs name to render cell renderer "natively" + setName("ComboBox.listRenderer"); // NOI18N + Scopes.ScopeInformation scopeDescription = null; + if(value instanceof Scopes.ScopeInformation) { + scopeDescription = (Scopes.ScopeInformation)value; + } + if ( scopeDescription != null ) { + String detail = scopeDescription.getDetail(); + String displayName = scopeDescription.getDisplayName(); + setText(detail == null ? displayName : displayName + " (" + detail + ")"); + setIcon(scopeDescription.getIcon()); + } + + if ( isSelected ) { + setBackground(list.getSelectionBackground()); + setForeground(list.getSelectionForeground()); + } else { + setBackground(list.getBackground()); + setForeground(list.getForeground()); + } + + return this; + } + + // #89393: GTK needs name to render cell renderer "natively" + @Override + public String getName() { + String name = super.getName(); + return name == null ? "ComboBox.renderer" : name; // NOI18N + } + } + +} --- a/refactoring.api/src/org/netbeans/modules/refactoring/spi/ui/ScopeProvider.java +++ a/refactoring.api/src/org/netbeans/modules/refactoring/spi/ui/ScopeProvider.java @@ -0,0 +1,145 @@ +/* + * 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.ui; + +import java.util.concurrent.atomic.AtomicBoolean; +import javax.swing.Icon; +import org.netbeans.api.annotations.common.CheckForNull; +import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.api.annotations.common.NullAllowed; +import org.netbeans.modules.refactoring.api.Scope; +import org.openide.util.Lookup; + +/** + * ScopeProvider is used to add a scope to the {@link ScopePanel}. + * + * @see ScopePanel + * @see ScopeDescription + * @see ScopeReference + * + * @author Jan Lahoda + * @author Ralph Benjamin Ruijs + * + * @since 1.30 + */ +public abstract class ScopeProvider { + + /** + * Initialize this scope provider with the supplied context. + * + * @param context a Lookup defining the context + * @param cancel set to true if initialization should be canceled + * @return true if this scope is usable for the supplied context, false + * otherwise + */ + public abstract boolean initialize(@NonNull Lookup context, @NonNull AtomicBoolean cancel); + + /** + * Get this provider's scope. The scope can be null if this provider is not + * yet initialized, or this provider is not usable for the supplied context. + * + * @see ScopeProvider#initialize(org.openide.util.Lookup, + * java.util.concurrent.atomic.AtomicBoolean) + * @return the Scope + */ + @CheckForNull + public abstract Scope getScope(); + + /** + * Override this method if the icon should be different depending on the + * context. + * + * @see ScopeProvider#initialize(org.openide.util.Lookup, + * java.util.concurrent.atomic.AtomicBoolean) + * @see ScopeDescription + * @return an icon for the Scope, or null if the default should be used. + */ + @CheckForNull + public Icon getIcon() { + return null; + } + + /** + * Override this method if an explaining string should be displayed behind + * the scope's name. This is used for scopes like "- Current File + * (Filename.java)". + * + * @return an explaining string, or null of nothing should be displayed. + */ + @CheckForNull + public String getDetail() { + return null; + } + + /** + * The CustomScopeProvider extends the normal scope provider to support + * scopes which can be customized by the user. + * + * @see ScopePanel + * @see ScopeDescription + * @see ScopeReference + * + * @author Jan Lahoda + * @author Ralph Benjamin Ruijs + * + * @since 1.30 + */ + public static abstract class CustomScopeProvider extends ScopeProvider { + + /** + * Set the scope to be customized. This method will be called right + * before the provider is asked to show the customizer, with the + * currently selected scope. + * + * @param currentScope the Scope currently selected + */ + public abstract void setScope(@NullAllowed Scope currentScope); + + /** + * Show a Dialog to customize the scope. + * + * @return true if the user succesfully specified a scope, false + * otherwise (ie. clicked cancel) + */ + public abstract boolean showCustomizer(); + } +} --- a/refactoring.api/src/org/netbeans/modules/refactoring/spi/ui/ScopeReference.java +++ a/refactoring.api/src/org/netbeans/modules/refactoring/spi/ui/ScopeReference.java @@ -0,0 +1,72 @@ +/* + * 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.ui; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * A reference to a Scope Description to be used by a {@link ScopePanel} + * + * @author Ralph Benjamin Ruijs + * @since 1.30 + */ +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.SOURCE) +public @interface ScopeReference { + + /** + * Into which location one wants to place the reference? Translates to + * {@link FileUtil#getConfigFile(java.lang.String)}. + */ + String path(); + + /** + * Identification of the scope this reference shall point to. Usually this + * is specified as {@link ScopeDescription} peer annotation, but in case one + * was to create references to scopes defined by someone else, one can + * specify the id() here. + */ + String id() default ""; +} --- a/refactoring.api/src/org/netbeans/modules/refactoring/spi/ui/ScopeReferences.java +++ a/refactoring.api/src/org/netbeans/modules/refactoring/spi/ui/ScopeReferences.java @@ -0,0 +1,59 @@ +/* + * 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.ui; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Allows registration of multiple {@link ScopeReference}s for a single type. + * + * @author Ralph Benjamin Ruijs + */ +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.SOURCE) +public @interface ScopeReferences { + + ScopeReference[] value(); +} --- a/refactoring.java/src/org/netbeans/modules/refactoring/java/api/ui/JavaScopeBuilder.java +++ a/refactoring.java/src/org/netbeans/modules/refactoring/java/api/ui/JavaScopeBuilder.java @@ -45,7 +45,7 @@ import java.awt.event.ActionListener; import java.util.concurrent.atomic.AtomicBoolean; import org.netbeans.modules.refactoring.api.Scope; -import org.netbeans.modules.refactoring.java.ui.CustomScopePanel; +import org.netbeans.modules.refactoring.java.ui.scope.CustomScopePanel; import org.openide.DialogDescriptor; import org.openide.DialogDisplayer; import org.openide.util.HelpCtx; --- a/refactoring.java/src/org/netbeans/modules/refactoring/java/ui/Bundle.properties +++ a/refactoring.java/src/org/netbeans/modules/refactoring/java/ui/Bundle.properties @@ -49,12 +49,6 @@ LBL_IntroduceParameter=Introduce Parameter DSC_Rename=Rename {0} to {1} -LBL_CustomScope=Custom Scope... -DLG_CustomScope=Custom Scope -LBL_CurrentFile=Current File ({0}) -LBL_CurrentPackage=Current Package ({0}) -LBL_CurrentProject=Current Project ({0}) -LBL_WaitNode=Please Wait... LBL_EncapsulateFieldsAction=Encapsula&te Fields... LBL_EncapsulateFields=Encapsulate Fields @@ -418,9 +412,6 @@ LBL_chngsigdecl=Change {0} parameters of {1} -LBL_Scope=Sco&pe\: -LBL_AllProjects=Open Projects - ExtractSuperclassPanel.nameLabel.AccessibleContext.accessibleDescription=N/A ExtractSuperclassPanel.chooseLabel.AccessibleContext.accessibleDescription=N/A @@ -496,3 +487,4 @@ ReplaceConstructorWithBuilder.jLabel1.text=&Builder Class Name: ReplaceConstructorWithBuilderName=Replace Constructor With Builder ReplaceConstructorWithBuilderDescription=Replace Constructor {0} with Builder {1} +WhereUsedPanel.jLabel1.text=Sco&pe: --- a/refactoring.java/src/org/netbeans/modules/refactoring/java/ui/WhereUsedPanel.form +++ a/refactoring.java/src/org/netbeans/modules/refactoring/java/ui/WhereUsedPanel.form @@ -20,93 +20,46 @@ - - + + + + + + + + - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + --- a/refactoring.java/src/org/netbeans/modules/refactoring/java/ui/WhereUsedPanel.java +++ a/refactoring.java/src/org/netbeans/modules/refactoring/java/ui/WhereUsedPanel.java @@ -43,46 +43,26 @@ */ package org.netbeans.modules.refactoring.java.ui; -import com.sun.source.tree.ExpressionTree; -import com.sun.source.util.TreePath; import java.awt.BorderLayout; import java.awt.Component; -import java.awt.event.ActionEvent; -import java.beans.BeanInfo; import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; import java.util.Arrays; -import java.util.LinkedList; import java.util.List; -import java.util.Set; -import java.util.prefs.BackingStoreException; -import java.util.prefs.Preferences; +import java.util.concurrent.atomic.AtomicBoolean; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.Modifier; import javax.swing.*; import javax.swing.event.ChangeListener; -import javax.swing.plaf.UIResource; -import org.netbeans.api.fileinfo.NonRecursiveFolder; -import org.netbeans.api.java.project.JavaProjectConstants; import org.netbeans.api.java.source.*; import org.netbeans.api.java.source.JavaSource.Phase; -import org.netbeans.api.project.*; import org.netbeans.modules.refactoring.api.Scope; import org.netbeans.modules.refactoring.java.Pair; -import org.netbeans.modules.refactoring.java.RefactoringModule; -import org.netbeans.modules.refactoring.java.api.ui.JavaScopeBuilder; import org.netbeans.modules.refactoring.spi.ui.CustomRefactoringPanel; import org.openide.filesystems.FileObject; -import org.openide.filesystems.FileStateInvalidException; -import org.openide.filesystems.URLMapper; -import org.openide.loaders.DataObject; -import org.openide.loaders.DataObjectNotFoundException; -import org.openide.util.Exceptions; -import org.openide.util.ImageUtilities; import org.openide.util.NbBundle; import org.openide.util.NbPreferences; +import org.openide.util.lookup.Lookups; /** @@ -91,14 +71,8 @@ */ public class WhereUsedPanel extends JPanel implements CustomRefactoringPanel { - private static final String PREF_SCOPE = "FindUsages-Scope"; - private static final String PACKAGE = "org/netbeans/spi/java/project/support/ui/package.gif"; // NOI18N private final transient TreePathHandle element; private final transient ChangeListener parent; -// private static final int MAX_NAME = 50; - private static final int SCOPE_COMBOBOX_COLUMNS = 14; - public static final String ELLIPSIS = "\u2026"; //NOI18N - private Scope customScope; private boolean enableScope; private final WhereUsedInnerPanel panel; @@ -111,7 +85,6 @@ this.enableScope = true; this.panel = panel; initComponents(); - btnCustomScope.setAction(new ScopeAction(scope)); } public static WhereUsedPanel create(String name, TreePathHandle e, ElementKind kind, List, TreePathHandle>> classes, ChangeListener parent) { @@ -145,38 +118,15 @@ public Scope getCustomScope() { FileObject file = WhereUsedPanel.this.element.getFileObject(); - Scope value = null; if(!enableScope) { return Scope.create(null, null, Arrays.asList(file)); } - switch (scope.getSelectedIndex()) { - case 1: - value = Scope.create(Arrays.asList(projectSources), null, null); - break; - case 2: - NonRecursiveFolder nonRecursiveFolder = new NonRecursiveFolder() { - @Override - public FileObject getFolder() { - return packageFolder; - } - }; - value = Scope.create(null, Arrays.asList(nonRecursiveFolder), null); - break; - case 3: - value = Scope.create(null, null, Arrays.asList(file)); - break; - case 4: - value = WhereUsedPanel.this.customScope; - break; - } - return value; + return scope.getSelectedScope(); } private boolean initialized = false; - private FileObject packageFolder = null; - private FileObject[] projectSources = null; String getMethodDeclaringClass() { if(panel instanceof WhereUsedPanelMethod) { @@ -192,7 +142,6 @@ return; } JavaSource source = JavaSource.forFileObject(element.getFileObject()); - final Project p = FileOwnerQuery.getOwner(element.getFileObject()); CancellableTask task =new CancellableTask() { @Override public void cancel() { @@ -206,50 +155,11 @@ final Element element = WhereUsedPanel.this.element.resolveElement(info); panel.initialize(element, info); - TreePath path = WhereUsedPanel.this.element.resolve(info); - final ExpressionTree packageName1 = path.getCompilationUnit().getPackageName(); - final String packageName = packageName1 == null? "" : packageName1.toString(); //NOI18N - if(packageName1 == null) { - packageFolder = info.getClasspathInfo().getClassPath(ClasspathInfo.PathKind.SOURCE).findOwnerRoot(WhereUsedPanel.this.element.getFileObject()); - } else { - packageFolder = info.getClasspathInfo().getClassPath(ClasspathInfo.PathKind.SOURCE).findResource(packageName.replaceAll("\\.", "/")); //NOI18N - } - - final JLabel customScope; - final JLabel currentFile; - final JLabel currentPackage; - final JLabel currentProject; - final JLabel allProjects; - if (p != null) { - ProjectInformation pi = ProjectUtils.getInformation(FileOwnerQuery.getOwner(WhereUsedPanel.this.element.getFileObject())); - - SourceGroup[] sources = ProjectUtils.getSources(pi.getProject()).getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA); - projectSources = new FileObject[sources.length]; - for (int i = 0; i < sources.length; i++) { - projectSources[i] = sources[i].getRootFolder(); - } - - DataObject currentFileDo = null; - try { - currentFileDo = DataObject.find(WhereUsedPanel.this.element.getFileObject()); - } catch (DataObjectNotFoundException ex) { - } // Not important, only for Icon. - customScope = new JLabel(NbBundle.getMessage(WhereUsedPanel.class, "LBL_CustomScope"), pi.getIcon(), SwingConstants.LEFT); //NOI18N - currentFile = new JLabel(NbBundle.getMessage(WhereUsedPanel.class, "LBL_CurrentFile", WhereUsedPanel.this.element.getFileObject().getNameExt()), currentFileDo != null ? new ImageIcon(currentFileDo.getNodeDelegate().getIcon(BeanInfo.ICON_COLOR_16x16)) : pi.getIcon(), SwingConstants.LEFT); //NOI18N - currentPackage = new JLabel(NbBundle.getMessage(WhereUsedPanel.class, "LBL_CurrentPackage", packageName), ImageUtilities.loadImageIcon(PACKAGE, false), SwingConstants.LEFT); //NOI18N - currentProject = new JLabel(NbBundle.getMessage(WhereUsedPanel.class, "LBL_CurrentProject", pi.getDisplayName()), pi.getIcon(), SwingConstants.LEFT); //NOI18N - allProjects = new JLabel(NbBundle.getMessage(WhereUsedPanel.class, "LBL_AllProjects"), pi.getIcon(), SwingConstants.LEFT); //NOI18N - } else { - customScope = null; - currentFile = null; - currentPackage = null; - currentProject = null; - allProjects = null; - } - if((element.getKind().equals(ElementKind.LOCAL_VARIABLE) || element.getKind().equals(ElementKind.PARAMETER)) || element.getModifiers().contains(Modifier.PRIVATE)) { enableScope = false; + } else { + enableScope = scope.initialize(Lookups.fixed(WhereUsedPanel.this.element.getFileObject(), WhereUsedPanel.this.element.resolve(info)), new AtomicBoolean()); } SwingUtilities.invokeLater(new Runnable() { @@ -258,23 +168,7 @@ innerPanel.removeAll(); innerPanel.add(panel, BorderLayout.CENTER); panel.setVisible(true); - - if(enableScope && currentProject!=null) { - scope.setModel(new DefaultComboBoxModel(new Object[]{allProjects, currentProject, currentPackage, currentFile, customScope })); - int defaultItem = (Integer) RefactoringModule.getOption("whereUsed.scope", 0); // NOI18N - WhereUsedPanel.this.customScope = readScope(); - if(defaultItem == 4 && WhereUsedPanel.this.customScope !=null && - WhereUsedPanel.this.customScope.getFiles().isEmpty() && - WhereUsedPanel.this.customScope.getFolders().isEmpty() && - WhereUsedPanel.this.customScope.getSourceRoots().isEmpty()) { - scope.setSelectedIndex(0); - } else { - scope.setSelectedIndex(defaultItem); - } - scope.setRenderer(new JLabelRenderer()); - } else { - scopePanel.setVisible(false); - } + scope.setVisible(enableScope); } }); }}; @@ -285,142 +179,11 @@ } initialized = true; } - private static class JLabelRenderer extends JLabel implements ListCellRenderer, UIResource { - public JLabelRenderer () { - setOpaque(true); - } - @Override - public Component getListCellRendererComponent( - JList list, - Object value, - int index, - boolean isSelected, - boolean cellHasFocus) { - - // #89393: GTK needs name to render cell renderer "natively" - setName("ComboBox.listRenderer"); // NOI18N - - if ( value != null ) { - setText(((JLabel)value).getText()); - setIcon(((JLabel)value).getIcon()); - } - - if ( isSelected ) { - setBackground(list.getSelectionBackground()); - setForeground(list.getSelectionForeground()); - } else { - setBackground(list.getBackground()); - setForeground(list.getForeground()); - } - - return this; - } - - // #89393: GTK needs name to render cell renderer "natively" - @Override - public String getName() { - String name = super.getName(); - return name == null ? "ComboBox.renderer" : name; // NOI18N - } - } static abstract class WhereUsedInnerPanel extends JPanel { abstract boolean isSearchInComments(); abstract void initialize(Element element, CompilationController info); } - - private class ScopeAction extends AbstractAction { - private final JComboBox scope; - - private ScopeAction(JComboBox scope) { - this.scope = scope; - this.putValue(NAME, ELLIPSIS); - } - - @Override - public void actionPerformed(ActionEvent e) { - Scope customScope = getCustomScope(); - - customScope = JavaScopeBuilder.open(NbBundle.getMessage(WhereUsedPanel.class, "DLG_CustomScope"), customScope); //NOI18N - if (customScope != null) { - WhereUsedPanel.this.customScope = customScope; - scope.setSelectedIndex(4); - storeScope(customScope); - } - } - } - - private void storeScope(Scope customScope) { - try { - storeFileList(customScope.getSourceRoots(), "sourceRoot" ); //NOI18N - storeFileList(customScope.getFolders(), "folder" ); //NOI18N - storeFileList(customScope.getFiles(), "file" ); //NOI18N - } catch (BackingStoreException ex) { - Exceptions.printStackTrace(ex); - } - } - - private Scope readScope() { - try { - if (NbPreferences.forModule(JavaScopeBuilder.class).nodeExists(PREF_SCOPE)) { //NOI18N - return Scope.create( - loadFileList("sourceRoot", FileObject.class), //NOI18N - loadFileList("folder", NonRecursiveFolder.class), //NOI18N - loadFileList("file", FileObject.class)); //NOI18N - } - } catch (BackingStoreException ex) { - Exceptions.printStackTrace(ex); - } - return null; - } - - private List loadFileList(String basekey, Class type) throws BackingStoreException { - Preferences pref = NbPreferences.forModule(JavaScopeBuilder.class).node(PREF_SCOPE).node(basekey); - List toRet = new LinkedList(); - for (String key : pref.keys()) { - final String url = pref.get(key, null); - if (url != null && !url.isEmpty()) { - try { - final FileObject f = URLMapper.findFileObject(new URL(url)); - if (f != null && f.isValid()) { - if (type.isAssignableFrom(FileObject.class)) { - toRet.add((T) f); - } else { - toRet.add((T) new NonRecursiveFolder() { - - @Override - public FileObject getFolder() { - return f; - } - }); - } - } - } catch (MalformedURLException ex) { - Exceptions.printStackTrace(ex); - } - } - } - return toRet; - } - - private void storeFileList(Set files, String basekey) throws BackingStoreException { - Preferences pref = NbPreferences.forModule(WhereUsedPanel.class).node(PREF_SCOPE).node(basekey); - assert files != null; - pref.clear(); - int count = 0; - for (Object next : files) { - try { - if (next instanceof FileObject) { - pref.put(basekey + count++, ((FileObject) next).getURL().toExternalForm()); - } else { - pref.put(basekey + count++, ((NonRecursiveFolder) next).getFolder().getURL().toExternalForm()); - } - } catch (FileStateInvalidException ex) { - Exceptions.printStackTrace(ex); - } - } - pref.flush(); - } // static String getHeader(Element call, CompilationInfo info) { // String result = ElementHeaders.getHeader(call, info, ElementHeaders.NAME + ElementHeaders.PARAMETERS); @@ -452,82 +215,43 @@ private void initComponents() { buttonGroup = new javax.swing.ButtonGroup(); - scopePanel = new javax.swing.JPanel(); - scopeLabel = new javax.swing.JLabel(); - scope = new javax.swing.JComboBox(); - btnCustomScope = new javax.swing.JButton(); innerPanel = new javax.swing.JPanel(); - - scopeLabel.setLabelFor(scope); - org.openide.awt.Mnemonics.setLocalizedText(scopeLabel, org.openide.util.NbBundle.getMessage(WhereUsedPanel.class, "LBL_Scope")); // NOI18N - - ((javax.swing.JTextField) scope.getEditor().getEditorComponent()).setColumns(SCOPE_COMBOBOX_COLUMNS); - scope.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - scopeActionPerformed(evt); - } - }); - - btnCustomScope.setText(ELLIPSIS); - - javax.swing.GroupLayout scopePanelLayout = new javax.swing.GroupLayout(scopePanel); - scopePanel.setLayout(scopePanelLayout); - scopePanelLayout.setHorizontalGroup( - scopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(scopePanelLayout.createSequentialGroup() - .addContainerGap() - .addComponent(scopeLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(scope, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnCustomScope) - .addContainerGap()) - ); - scopePanelLayout.setVerticalGroup( - scopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(scopePanelLayout.createSequentialGroup() - .addContainerGap() - .addGroup(scopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(scopePanelLayout.createSequentialGroup() - .addGap(6, 6, 6) - .addComponent(scopeLabel)) - .addGroup(scopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(btnCustomScope) - .addComponent(scope, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addContainerGap()) - ); - - scope.getAccessibleContext().setAccessibleDescription("N/A"); + scope = new org.netbeans.modules.refactoring.spi.ui.ScopePanel(WhereUsedPanel.class.getCanonicalName().replace('.', '-'), NbPreferences.forModule(WhereUsedPanel.class), "whereUsed.scope"); + jLabel1 = new javax.swing.JLabel(); innerPanel.setLayout(new java.awt.BorderLayout()); + jLabel1.setText(org.openide.util.NbBundle.getMessage(WhereUsedPanel.class, "WhereUsedPanel.jLabel1.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(scopePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(innerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 361, Short.MAX_VALUE) + .addComponent(innerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(scope, javax.swing.GroupLayout.DEFAULT_SIZE, 487, Short.MAX_VALUE) + .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(innerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 45, Short.MAX_VALUE) + .addComponent(innerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 169, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(scopePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(scope, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) ); }// //GEN-END:initComponents -private void scopeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scopeActionPerformed - RefactoringModule.setOption("whereUsed.scope", scope.getSelectedIndex()); // NOI18N -}//GEN-LAST:event_scopeActionPerformed - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JButton btnCustomScope; private javax.swing.ButtonGroup buttonGroup; private javax.swing.JPanel innerPanel; - private javax.swing.JComboBox scope; - private javax.swing.JLabel scopeLabel; - private javax.swing.JPanel scopePanel; + private javax.swing.JLabel jLabel1; + private org.netbeans.modules.refactoring.spi.ui.ScopePanel scope; // End of variables declaration//GEN-END:variables public boolean isMethodFromBaseClass() { @@ -587,4 +311,3 @@ return this; } } - --- a/refactoring.java/src/org/netbeans/modules/refactoring/java/ui/scope/Bundle.properties +++ a/refactoring.java/src/org/netbeans/modules/refactoring/java/ui/scope/Bundle.properties @@ -0,0 +1,43 @@ +# 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. + +ScopePanel.scopeLabel.text=Sco&pe: + +LBL_WaitNode=Please Wait... --- a/refactoring.java/src/org/netbeans/modules/refactoring/java/ui/scope/CurrentFileScopeProvider.java +++ a/refactoring.java/src/org/netbeans/modules/refactoring/java/ui/scope/CurrentFileScopeProvider.java @@ -0,0 +1,105 @@ +/* + * 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.java.ui.scope; + +import java.beans.BeanInfo; +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicBoolean; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import org.netbeans.modules.refactoring.api.Scope; +import org.netbeans.modules.refactoring.spi.ui.ScopeDescription; +import org.netbeans.modules.refactoring.spi.ui.ScopeProvider; +import org.netbeans.modules.refactoring.spi.ui.ScopeReference; +import org.openide.filesystems.FileObject; +import org.openide.loaders.DataObject; +import org.openide.loaders.DataObjectNotFoundException; +import org.openide.util.Lookup; +import org.openide.util.NbBundle.Messages; + +/** + * + * @author Ralph Benjamin Ruijs + */ +@ScopeDescription(displayName = "#LBL_CurrentFile", id = "current-file", position = 400, iconBase = "org/netbeans/modules/refactoring/java/resources/newFile.png") +@ScopeReference(path="org-netbeans-modules-refactoring-java-ui-WhereUsedPanel") +@Messages(value = {"# {0} - Filename", "LBL_CurrentFile=Current File"}) +public final class CurrentFileScopeProvider extends ScopeProvider { + + private Scope scope; + private ImageIcon icon; + private String detail; + + @Override + public boolean initialize(Lookup context, AtomicBoolean cancel) { + FileObject file = context.lookup(FileObject.class); + if (file == null || file.isFolder()) { + return false; + } + + DataObject currentFileDo = null; + try { + currentFileDo = DataObject.find(file); + } catch (DataObjectNotFoundException ex) { + } // Not important, only for Icon. + icon = currentFileDo != null ? new ImageIcon(currentFileDo.getNodeDelegate().getIcon(BeanInfo.ICON_COLOR_16x16)) : null; + detail = file.getNameExt(); + scope = Scope.create(null, null, Arrays.asList(file)); + + return true; + } + + @Override + public Scope getScope() { + return scope; + } + + @Override + public Icon getIcon() { + return icon != null ? icon : super.getIcon(); + } + + @Override + public String getDetail() { + return detail; + } +} --- a/refactoring.java/src/org/netbeans/modules/refactoring/java/ui/scope/CurrentJavaProjectScopeProvider.java +++ a/refactoring.java/src/org/netbeans/modules/refactoring/java/ui/scope/CurrentJavaProjectScopeProvider.java @@ -0,0 +1,127 @@ +/* + * 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.java.ui.scope; + +import java.util.Arrays; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; +import javax.swing.Icon; +import org.netbeans.api.java.classpath.ClassPath; +import org.netbeans.api.java.project.JavaProjectConstants; +import org.netbeans.api.project.FileOwnerQuery; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.ProjectInformation; +import org.netbeans.api.project.ProjectUtils; +import org.netbeans.api.project.SourceGroup; +import org.netbeans.modules.refactoring.api.Scope; +import org.netbeans.modules.refactoring.spi.ui.ScopeDescription; +import org.netbeans.modules.refactoring.spi.ui.ScopeProvider; +import org.netbeans.modules.refactoring.spi.ui.ScopeReference; +import org.openide.filesystems.FileObject; +import org.openide.loaders.DataFolder; +import org.openide.util.Lookup; +import org.openide.util.NbBundle.Messages; + +/** + * + * @author Ralph Benjamin Ruijs + */ +@ScopeDescription(id = "current-project", displayName = "#LBL_CurrentProject", position = 200) +@ScopeReference(path = "org-netbeans-modules-refactoring-java-ui-WhereUsedPanel") +@Messages({"LBL_CurrentProject=Current Project"}) +public final class CurrentJavaProjectScopeProvider extends ScopeProvider { + + private String detail; + private Scope scope; + private Icon icon; + + @Override + public boolean initialize(Lookup context, AtomicBoolean cancel) { + FileObject file = context.lookup(FileObject.class); + Project selected = null; + if (file != null) { + selected = FileOwnerQuery.getOwner(file); + } + if (selected == null) { + selected = context.lookup(Project.class); + if (selected == null) { + SourceGroup sg = context.lookup(SourceGroup.class); + if (sg != null) { + selected = FileOwnerQuery.getOwner(sg.getRootFolder()); + } + } + if (selected == null) { + DataFolder df = context.lookup(DataFolder.class); + if (df != null) { + selected = FileOwnerQuery.getOwner(df.getPrimaryFile()); + } + } + } + if (selected == null) { + return false; + } + + ProjectInformation pi = ProjectUtils.getInformation(selected); + + Map> projects2RegisteredContent = OpenProjectsScopeProvider.projects2RegisteredContent(cancel); + scope = OpenProjectsScopeProvider.addProjectToScope(pi.getProject(), Scope.create(null, null, null), cancel, projects2RegisteredContent); + + detail = pi.getDisplayName(); + icon = pi.getIcon(); + return true; + } + + @Override + public String getDetail() { + return detail; + } + + @Override + public Icon getIcon() { + return icon; + } + + @Override + public Scope getScope() { + return scope; + } +} --- a/refactoring.java/src/org/netbeans/modules/refactoring/java/ui/scope/CurrentPackageScopeProvider.java +++ a/refactoring.java/src/org/netbeans/modules/refactoring/java/ui/scope/CurrentPackageScopeProvider.java @@ -0,0 +1,121 @@ +/* + * 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.java.ui.scope; + +import com.sun.source.tree.ExpressionTree; +import com.sun.source.util.TreePath; +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicBoolean; +import javax.swing.Icon; +import org.netbeans.api.fileinfo.NonRecursiveFolder; +import org.netbeans.api.java.classpath.ClassPath; +import org.netbeans.modules.refactoring.api.Scope; +import org.netbeans.modules.refactoring.spi.ui.ScopeDescription; +import org.netbeans.modules.refactoring.spi.ui.ScopeProvider; +import org.netbeans.modules.refactoring.spi.ui.ScopeReference; +import org.openide.filesystems.FileObject; +import org.openide.util.Lookup; +import org.openide.util.NbBundle.Messages; + +/** + * + * @author Ralph Benjamin Ruijs + */ +@Messages({"LBL_CurrentPackage=Current Package"}) +@ScopeDescription(id = "current-package", displayName = "#LBL_CurrentPackage", position = 300, iconBase = "org/netbeans/spi/java/project/support/ui/package.gif") +@ScopeReference(path="org-netbeans-modules-refactoring-java-ui-WhereUsedPanel") +public final class CurrentPackageScopeProvider extends ScopeProvider { + + private String detail; + private Scope scope; + + @Override + public boolean initialize(Lookup context, AtomicBoolean cancel) { + FileObject file = context.lookup(FileObject.class); + if (file == null) { + return false; + } + final FileObject packageFolder; + final String packageName; + ClassPath sourceCP = ClassPath.getClassPath(file, ClassPath.SOURCE); + if (sourceCP != null) { + TreePath path = context.lookup(TreePath.class); + if (path != null) { + final ExpressionTree packageName1 = path.getCompilationUnit().getPackageName(); + packageName = packageName1 == null ? "" : packageName1.toString(); //NOI18N + if (packageName1 == null) { + packageFolder = sourceCP.findOwnerRoot(file); + } else { + packageFolder = sourceCP.findResource(packageName.replaceAll("\\.", "/")); //NOI18N + } + } else { + packageFolder = file.isFolder()? file : file.getParent(); + packageName = sourceCP.getResourceName(packageFolder, '.', false); + } + } else { + packageFolder = null; + packageName = null; + } + + if (packageFolder != null) { + detail = packageName; + scope = Scope.create(null, Arrays.asList(new NonRecursiveFolder() { + @Override + public FileObject getFolder() { + return packageFolder; + } + }), null); + return true; + } + return false; + } + + @Override + public Scope getScope() { + return scope; + } + + @Override + public String getDetail() { + return detail; + } +} --- a/refactoring.java/src/org/netbeans/modules/refactoring/java/ui/CustomScopePanel.java +++ a/refactoring.java/src/org/netbeans/modules/refactoring/java/ui/CustomScopePanel.java @@ -45,7 +45,7 @@ * * Created on Jun 13, 2011, 9:51:30 AM */ -package org.netbeans.modules.refactoring.java.ui; +package org.netbeans.modules.refactoring.java.ui.scope; import java.awt.*; import java.awt.image.BufferedImage; @@ -92,6 +92,7 @@ * * @author Ralph Ruijs */ +@NbBundle.Messages({"DLG_CustomScope=Custom Scope"}) public class CustomScopePanel extends javax.swing.JPanel implements ExplorerManager.Provider { private static final Image PACKAGEBADGE = ImageUtilities.loadImage("org/netbeans/spi/java/project/support/ui/packageBadge.gif"); // NOI18N --- a/refactoring.java/src/org/netbeans/modules/refactoring/java/ui/scope/CustomScopeProvider.java +++ a/refactoring.java/src/org/netbeans/modules/refactoring/java/ui/scope/CustomScopeProvider.java @@ -0,0 +1,174 @@ +/* + * 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.java.ui.scope; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.prefs.BackingStoreException; +import java.util.prefs.Preferences; +import javax.swing.Icon; +import org.netbeans.api.fileinfo.NonRecursiveFolder; +import org.netbeans.modules.refactoring.api.Scope; +import org.netbeans.modules.refactoring.spi.ui.ScopeDescription; +import org.netbeans.modules.refactoring.spi.ui.ScopeProvider; +import org.netbeans.modules.refactoring.java.api.ui.JavaScopeBuilder; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.URLMapper; +import org.openide.util.Exceptions; +import org.openide.util.Lookup; +import org.openide.util.NbPreferences; +import static org.netbeans.modules.refactoring.java.ui.scope.Bundle.*; +import org.netbeans.modules.refactoring.spi.ui.ScopeReference; +import org.openide.util.NbBundle.Messages; + +/** + * + * @author Ralph Benjamin Ruijs + */ +@Messages("LBL_CustomScope=Custom Scope...") +@ScopeDescription(id = "custom-scope", displayName = "#LBL_CustomScope", position = 900, iconBase = "org/netbeans/modules/refactoring/java/resources/filter.png") +@ScopeReference(path="org-netbeans-modules-refactoring-java-ui-WhereUsedPanel") +public final class CustomScopeProvider extends ScopeProvider.CustomScopeProvider { + + private static final String PREF_SCOPE = "FindUsages-Scope"; + private Scope customScope; + + @Override + public boolean initialize(Lookup context, AtomicBoolean cancel) { + return true; + } + + @Override + public void setScope(Scope value) { + customScope = value != null ? Scope.create(value.getSourceRoots(), value.getFolders(), value.getFiles()) : null; + } + + @Override + @Messages("TTL_CustomScope=Custom Scope") + public boolean showCustomizer() { + Scope nue = JavaScopeBuilder.open(TTL_CustomScope(), customScope); //NOI18N + if (nue != null) { + storeScope(customScope = nue); + } + + return nue != null; + } + + @Override + public Scope getScope() { + if (customScope == null) { + customScope = readScope(); + } + return customScope; + } + + private void storeScope(Scope customScope) { + try { + storeFileList(customScope.getSourceRoots(), "sourceRoot"); //NOI18N + storeFileList(customScope.getFolders(), "folder"); //NOI18N + storeFileList(customScope.getFiles(), "file"); //NOI18N + } catch (BackingStoreException ex) { + Exceptions.printStackTrace(ex); + } + } + + private Scope readScope() { + try { + if (NbPreferences.forModule(JavaScopeBuilder.class).nodeExists(PREF_SCOPE)) { //NOI18N + return Scope.create( + loadFileList("sourceRoot", FileObject.class), //NOI18N + loadFileList("folder", NonRecursiveFolder.class), //NOI18N + loadFileList("file", FileObject.class)); //NOI18N + } + } catch (BackingStoreException ex) { + Exceptions.printStackTrace(ex); + } + return null; + } + + private List loadFileList(String basekey, Class type) throws BackingStoreException { + Preferences pref = NbPreferences.forModule(JavaScopeBuilder.class).node(PREF_SCOPE).node(basekey); + List toRet = new LinkedList(); + for (String key : pref.keys()) { + final String url = pref.get(key, null); + if (url != null && !url.isEmpty()) { + try { + final FileObject f = URLMapper.findFileObject(new URL(url)); + if (f != null && f.isValid()) { + if (type.isAssignableFrom(FileObject.class)) { + toRet.add((T) f); + } else { + toRet.add((T) new NonRecursiveFolder() { + @Override + public FileObject getFolder() { + return f; + } + }); + } + } + } catch (MalformedURLException ex) { + Exceptions.printStackTrace(ex); + } + } + } + return toRet; + } + + private void storeFileList(Set files, String basekey) throws BackingStoreException { + Preferences pref = NbPreferences.forModule(CustomScopeProvider.class).node(PREF_SCOPE).node(basekey); + assert files != null; + pref.clear(); + int count = 0; + for (Object next : files) { + if (next instanceof FileObject) { + pref.put(basekey + count++, ((FileObject) next).toURL().toExternalForm()); + } else { + pref.put(basekey + count++, ((NonRecursiveFolder) next).getFolder().toURL().toExternalForm()); + } + } + pref.flush(); + } +} --- a/refactoring.java/src/org/netbeans/modules/refactoring/java/ui/scope/OpenProjectsScopeProvider.java +++ a/refactoring.java/src/org/netbeans/modules/refactoring/java/ui/scope/OpenProjectsScopeProvider.java @@ -0,0 +1,180 @@ +/* + * 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.java.ui.scope; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.api.annotations.common.NullAllowed; +import org.netbeans.api.fileinfo.NonRecursiveFolder; +import org.netbeans.api.java.classpath.ClassPath; +import org.netbeans.api.java.classpath.GlobalPathRegistry; +import org.netbeans.api.project.FileOwnerQuery; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.ui.OpenProjects; +import org.netbeans.modules.parsing.spi.indexing.PathRecognizer; +import org.netbeans.modules.refactoring.api.Scope; +import org.netbeans.modules.refactoring.spi.ui.ScopeDescription; +import org.netbeans.modules.refactoring.spi.ui.ScopeProvider; +import org.netbeans.modules.refactoring.spi.ui.ScopeReference; +import org.openide.filesystems.FileObject; +import org.openide.util.Lookup; +import org.openide.util.NbBundle; + +/** + * + * @author Ralph Benjamin Ruijs + */ +@NbBundle.Messages("LBL_AllProjects=Open Projects") +@ScopeDescription(id = "all-projects", displayName = "#LBL_AllProjects", position = 100, iconBase = "org/netbeans/modules/refactoring/java/resources/all_projects.png") +@ScopeReference(path = "org-netbeans-modules-refactoring-java-ui-WhereUsedPanel") +public class OpenProjectsScopeProvider extends ScopeProvider { + + private Scope scope; + + @Override + public boolean initialize(Lookup context, AtomicBoolean cancel) { + Map> projects2RegisteredContent = projects2RegisteredContent(cancel); + + scope = Scope.create(null, null, null); + + if (cancel.get()) { + return false; + } + + for (Project p : OpenProjects.getDefault().getOpenProjects()) { + scope = addProjectToScope(p, scope, cancel, projects2RegisteredContent); + } + + return true; + } + + @Override + public Scope getScope() { + return scope; + } + + static Map> projects2RegisteredContent(AtomicBoolean cancel) { + Set sourceIds = new HashSet(); + + for (PathRecognizer pr : Lookup.getDefault().lookupAll(PathRecognizer.class)) { + Set ids = pr.getSourcePathIds(); + + if (ids == null) { + continue; + } + + sourceIds.addAll(ids); + } + + Map> sourceRoots = new IdentityHashMap>(); + + for (String id : sourceIds) { + for (ClassPath sCP : GlobalPathRegistry.getDefault().getPaths(id)) { + for (FileObject root : sCP.getRoots()) { + if (cancel.get()) { + return null; + } + Project owner = FileOwnerQuery.getOwner(root); + + if (owner != null) { + Map projectSources = sourceRoots.get(owner); + + if (projectSources == null) { + sourceRoots.put(owner, projectSources = new HashMap()); + } + + projectSources.put(root, sCP); + } + } + } + } + + return sourceRoots; + } + + static Scope addProjectToScope(Project p, Scope target, AtomicBoolean cancel, Map> projects2RegisteredContent) { + Scope projectScope = p.getLookup().lookup(Scope.class); + + if (projectScope != null) { + return augment(target, projectScope.getSourceRoots(), projectScope.getFolders(), projectScope.getFiles()); + } + + Map roots = projects2RegisteredContent.get(p); + + if (roots != null) { + for (Map.Entry e : roots.entrySet()) { + if (cancel.get()) { + return null; + } + target = augment(target, Collections.singletonList(e.getKey()), null, null); + } + } + + return target; + } + + private static @NonNull + Scope augment(@NonNull Scope source, @NullAllowed Collection sourceRoots, + @NullAllowed Collection folders, + @NullAllowed Collection files) { + Collection sourceRootsSet = new HashSet(source.getSourceRoots()); + if (sourceRoots != null) { + sourceRootsSet.addAll(sourceRoots); + } + Collection filesSet = new HashSet(source.getFiles()); + if (files != null) { + filesSet.addAll(files); + } + Collection foldersSet = new HashSet(source.getFolders()); + if (folders != null) { + foldersSet.addAll(folders); + } + return Scope.create(sourceRootsSet, foldersSet, filesSet); + } +}