diff --git a/java.sourceui/src/org/netbeans/modules/java/source/ui/JavaSymbolDescriptor.java b/java.sourceui/src/org/netbeans/modules/java/source/ui/AsyncJavaSymbolDescriptor.java rename from java.sourceui/src/org/netbeans/modules/java/source/ui/JavaSymbolDescriptor.java rename to java.sourceui/src/org/netbeans/modules/java/source/ui/AsyncJavaSymbolDescriptor.java --- a/java.sourceui/src/org/netbeans/modules/java/source/ui/JavaSymbolDescriptor.java +++ b/java.sourceui/src/org/netbeans/modules/java/source/ui/AsyncJavaSymbolDescriptor.java @@ -42,200 +42,198 @@ package org.netbeans.modules.java.source.ui; -import java.io.File; import java.io.IOException; -import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; +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.lang.model.element.TypeElement; 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.api.java.classpath.ClassPath; import org.netbeans.api.java.source.ClasspathInfo; +import org.netbeans.api.java.source.CompilationController; import org.netbeans.api.java.source.ElementHandle; -import org.netbeans.api.java.source.SourceUtils; -import org.netbeans.api.java.source.ui.ElementOpen; +import org.netbeans.api.java.source.JavaSource; +import org.netbeans.api.java.source.Task; import org.netbeans.api.project.Project; -import org.netbeans.api.project.ProjectInformation; -import org.netbeans.api.project.ProjectUtils; -import org.netbeans.modules.java.source.parsing.FileObjects; +import org.netbeans.modules.java.source.indexing.TransactionContext; +import org.netbeans.modules.java.source.parsing.FileManagerTransaction; +import org.netbeans.modules.java.source.parsing.ProcessorGenerated; import org.netbeans.modules.java.source.usages.ClassIndexImpl; -import org.netbeans.modules.java.ui.Icons; -import org.netbeans.spi.java.classpath.support.ClassPathSupport; +import org.netbeans.modules.java.source.usages.ClasspathInfoAccessor; +import org.netbeans.spi.jumpto.support.AsyncDescriptor; +import org.netbeans.spi.jumpto.support.DescriptorChangeEvent; +import org.netbeans.spi.jumpto.support.DescriptorChangeListener; import org.netbeans.spi.jumpto.symbol.SymbolDescriptor; import org.openide.filesystems.FileObject; -import org.openide.filesystems.FileUtil; import org.openide.util.Exceptions; +import org.openide.util.Pair; +import org.openide.util.Parameters; +import org.openide.util.RequestProcessor; /** * * @author Tomas Zezula */ -public class JavaSymbolDescriptor extends SymbolDescriptor { +final class AsyncJavaSymbolDescriptor extends JavaSymbolDescriptorBase implements AsyncDescriptor { - private final String simpleName; - private final String simpleNameSuffix; - private final ElementHandle owner; - private final ElementHandle me; - private final ElementKind kind; - private final Set modifiers; - private final FileObject root; - private final Project project; - private final ClassIndexImpl ci; - private FileObject cachedFo; - private volatile String cachedPath; + private static final RequestProcessor WORKER = new RequestProcessor(AsyncJavaSymbolDescriptor.class); + private static final String INIT = ""; //NOI18N - public JavaSymbolDescriptor ( - @NonNull final String simpleName, - @NullAllowed final String simpleNameSuffix, - @NonNull final ElementKind kind, - @NonNull final Set modifiers, - @NonNull final ElementHandle owner, - @NonNull final ElementHandle me, + private final String ident; + private final List> listeners; + private final AtomicBoolean initialized; + + AsyncJavaSymbolDescriptor ( @NullAllowed final Project project, @NonNull final FileObject root, - @NonNull final ClassIndexImpl ci) { - assert simpleName != null; - assert kind != null; - assert modifiers != null; - assert owner != null; - assert me != null; - assert root != null; - assert ci != null; - this.simpleName = simpleName; - this.simpleNameSuffix = simpleNameSuffix; - this.kind = kind; - this.modifiers = modifiers; - this.owner = owner; - this.me = me; - this.root = root; - this.project = project; - this.ci = ci; + @NonNull final ClassIndexImpl ci, + @NonNull final ElementHandle owner, + @NonNull final String ident) { + super(owner, project, root, ci); + assert ident != null; + this.ident = ident; + this.listeners = new CopyOnWriteArrayList<>(); + this.initialized = new AtomicBoolean(); } @Override public Icon getIcon() { - return Icons.getElementIcon(kind, modifiers); + initialize(); + return null; } @Override public String getSymbolName() { - return simpleNameSuffix == null ? - simpleName : - simpleName + simpleNameSuffix; + initialize(); + return ident; } @Override public String getSimpleName() { - return simpleName; + return ident; } @Override - public String getOwnerName() { - return owner.getQualifiedName(); + public void open() { + final Collection symbols = resolve(); + if (!symbols.isEmpty()) { + symbols.iterator().next().open(); + } } - - @Override - public FileObject getFileObject() { - if (cachedFo == null) { - final ClasspathInfo cpInfo = ClasspathInfo.create(ClassPath.EMPTY, - ClassPath.EMPTY, ClassPathSupport.createClassPath(root)); - cachedFo = SourceUtils.getFile(owner, cpInfo); - } - return cachedFo; - } - - @Override - @NonNull - public String getFileDisplayPath() { - String res = cachedPath; - if (res == null) { - final File rootFile = FileUtil.toFile(root); - if (rootFile != null) { - try { - final String binaryName = owner.getBinaryName(); - String relativePath = ci.getSourceName(binaryName); - if (relativePath == null) { - relativePath = binaryName; - int lastDot = relativePath.lastIndexOf('.'); //NOI18N - int csIndex = relativePath.indexOf('$', lastDot); //NOI18N - if (csIndex > 0 && csIndex < relativePath.length()-1) { - relativePath = binaryName.substring(0, csIndex); - } - relativePath = String.format( - "%s.%s", //NOI18N - FileObjects.convertPackage2Folder(relativePath, File.separatorChar), - FileObjects.JAVA); - } - res = new File (rootFile, relativePath).getAbsolutePath(); - } catch (IOException | InterruptedException e) { - Exceptions.printStackTrace(e); + private void initialize() { + if (initialized.compareAndSet(false, true)) { + final Runnable action = new Runnable() { + @Override + public void run() { + final Collection symbols = resolve(); + fireDescriptorChange(symbols); } - } - if (res == null) { - final FileObject fo = getFileObject(); - res = fo == null ? - "" : //NOI18N - FileUtil.getFileDisplayName(fo); - } - cachedPath = res; - } - return res; - } - - - - @Override - public void open() { - FileObject file = getFileObject(); - if (file != null) { - ClasspathInfo cpInfo = ClasspathInfo.create(file); - - ElementOpen.open(cpInfo, me); + }; + WORKER.execute(action); } } @Override - public String getProjectName() { - final ProjectInformation info = getProjectInfo(); - return info == null ? - "" : //NOI18N - info.getDisplayName(); + public void addDescriptorChangeListener(@NonNull final DescriptorChangeListener listener) { + Parameters.notNull("listener", listener); + listeners.add(listener); } @Override - public Icon getProjectIcon() { - final ProjectInformation info = getProjectInfo(); - return info == null ? - null : - info.getIcon(); + public void removeDescriptorChangeListener(@NonNull final DescriptorChangeListener listener) { + Parameters.notNull("listener", listener); + listeners.remove(listener); } - @Override - public int getOffset() { - //todo: fixme - return -1; + private void fireDescriptorChange(Collection replacement) { + final DescriptorChangeEvent event = new DescriptorChangeEvent<>( + this, + replacement); + for (DescriptorChangeListener l : listeners) { + l.descriptorChanged(event); + } } @NonNull - public ElementKind getElementKind() { - return kind; + private Collection resolve() { + try { + final List symbols = new ArrayList<>(); + TransactionContext. + beginTrans(). + register(FileManagerTransaction.class, FileManagerTransaction.read()). + register(ProcessorGenerated.class, ProcessorGenerated.nullWrite()); + try { + final ClasspathInfo cpInfo = ClasspathInfoAccessor.getINSTANCE().create(getRoot(),null,true,true,false,false); + final JavaSource js = JavaSource.create(cpInfo); + js.runUserActionTask(new Task() { + @Override + public void run (final CompilationController controller) { + final TypeElement te = getOwner().resolve(controller); + if (te != null) { + if (ident.equals(getSimpleName(te, null)) /*TODO && matchesRestrictions(te, restriction)*/) { + final String simpleName = te.getSimpleName().toString(); + final String simpleNameSuffix = null; + final ElementKind kind = te.getKind(); + final Set modifiers = te.getModifiers(); + final ElementHandle me = ElementHandle.create(te); + symbols.add(new ResolvedJavaSymbolDescriptor( + AsyncJavaSymbolDescriptor.this, + simpleName, + simpleNameSuffix, + kind, + modifiers, + me)); + } + for (Element ne : te.getEnclosedElements()) { + if (ident.equals(getSimpleName(ne, te)) /*TODO && matchesRestrictions(ne, restriction)*/) { + final Pair name = JavaSymbolProvider.getDisplayName(ne, te); + final String simpleName = name.first(); + final String simpleNameSuffix = name.second(); + final ElementKind kind = ne.getKind(); + final Set modifiers = ne.getModifiers(); + final ElementHandle me = ElementHandle.create(ne); + symbols.add(new ResolvedJavaSymbolDescriptor( + AsyncJavaSymbolDescriptor.this, + simpleName, + simpleNameSuffix, + kind, + modifiers, + me)); + } + } + } + } + }, true); + }finally { + TransactionContext.get().commit(); + } + return symbols; + } catch (IOException e) { + Exceptions.printStackTrace(e); + return Collections.emptyList(); + } } @NonNull - public Set getModifiers() { - return modifiers; + private static String getSimpleName ( + @NonNull final Element element, + @NullAllowed final Element enclosingElement) { + String result = element.getSimpleName().toString(); + if (enclosingElement != null && INIT.equals(result)) { + result = enclosingElement.getSimpleName().toString(); + } +//TODO if (!caseSensitive) { + result = result.toLowerCase(); +// } + return result; } - - @CheckForNull - private ProjectInformation getProjectInfo() { - return project == null ? - null : - project.getLookup().lookup(ProjectInformation.class); //Intentionally does not use ProjectUtils.getInformation() it does project icon annotation which is expensive - } - } diff --git a/java.sourceui/src/org/netbeans/modules/java/source/ui/JavaSymbolDescriptorBase.java b/java.sourceui/src/org/netbeans/modules/java/source/ui/JavaSymbolDescriptorBase.java new file mode 100644 --- /dev/null +++ b/java.sourceui/src/org/netbeans/modules/java/source/ui/JavaSymbolDescriptorBase.java @@ -0,0 +1,198 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 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 2015 Sun Microsystems, Inc. + */ +package org.netbeans.modules.java.source.ui; + +import java.io.File; +import java.io.IOException; +import javax.lang.model.element.TypeElement; +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.api.java.classpath.ClassPath; +import org.netbeans.api.java.source.ClasspathInfo; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.api.java.source.SourceUtils; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.ProjectInformation; +import org.netbeans.modules.java.source.parsing.FileObjects; +import org.netbeans.modules.java.source.usages.ClassIndexImpl; +import org.netbeans.spi.java.classpath.support.ClassPathSupport; +import org.netbeans.spi.jumpto.symbol.SymbolDescriptor; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.util.Exceptions; + +/** + * + * @author Tomas Zezula + */ +abstract class JavaSymbolDescriptorBase extends SymbolDescriptor { + + private final ElementHandle owner; + private final Project project; + private final FileObject root; + private final ClassIndexImpl ci; + private volatile FileObject cachedFo; + private volatile String cachedPath; + + JavaSymbolDescriptorBase( + @NonNull final ElementHandle owner, + @NullAllowed final Project project, + @NonNull final FileObject root, + @NonNull final ClassIndexImpl ci) { + assert owner != null; + assert root != null; + assert ci != null; + this.owner = owner; + this.project = project; + this.root = root; + this.ci = ci; + } + + JavaSymbolDescriptorBase( + @NonNull final JavaSymbolDescriptorBase other) { + this.owner = other.owner; + this.project = other.project; + this.root = other.root; + this.ci = other.ci; + this.cachedFo = other.cachedFo; + this.cachedPath = other.cachedPath; + } + + @Override + @NonNull + public final String getOwnerName() { + return owner.getQualifiedName(); + } + + @Override + @CheckForNull + public final FileObject getFileObject() { + FileObject res = cachedFo; + if (res == null) { + final ClasspathInfo cpInfo = ClasspathInfo.create(ClassPath.EMPTY, + ClassPath.EMPTY, ClassPathSupport.createClassPath(root)); + res = cachedFo = SourceUtils.getFile(owner, cpInfo); + } + return res; + } + + @Override + @NonNull + public final String getFileDisplayPath() { + String res = cachedPath; + if (res == null) { + final File rootFile = FileUtil.toFile(root); + if (rootFile != null) { + try { + final String binaryName = owner.getBinaryName(); + String relativePath = ci.getSourceName(binaryName); + if (relativePath == null) { + relativePath = binaryName; + int lastDot = relativePath.lastIndexOf('.'); //NOI18N + int csIndex = relativePath.indexOf('$', lastDot); //NOI18N + if (csIndex > 0 && csIndex < relativePath.length()-1) { + relativePath = binaryName.substring(0, csIndex); + } + relativePath = String.format( + "%s.%s", //NOI18N + FileObjects.convertPackage2Folder(relativePath, File.separatorChar), + FileObjects.JAVA); + } + res = new File (rootFile, relativePath).getAbsolutePath(); + } catch (IOException | InterruptedException e) { + Exceptions.printStackTrace(e); + } + } + if (res == null) { + final FileObject fo = getFileObject(); + res = fo == null ? + "" : //NOI18N + FileUtil.getFileDisplayName(fo); + } + cachedPath = res; + } + return res; + } + + @Override + @NonNull + public final String getProjectName() { + final ProjectInformation info = getProjectInfo(); + return info == null ? + "" : //NOI18N + info.getDisplayName(); + } + + @Override + @CheckForNull + public final Icon getProjectIcon() { + final ProjectInformation info = getProjectInfo(); + return info == null ? + null : + info.getIcon(); + } + + @Override + public final int getOffset() { + //todo: fixme + return -1; + } + + @NonNull + final FileObject getRoot() { + return root; + } + + @NonNull + final ElementHandle getOwner() { + return owner; + } + + @CheckForNull + private ProjectInformation getProjectInfo() { + return project == null ? + null : + project.getLookup().lookup(ProjectInformation.class); //Intentionally does not use ProjectUtils.getInformation() it does project icon annotation which is expensive + } +} diff --git a/java.sourceui/src/org/netbeans/modules/java/source/ui/JavaSymbolProvider.java b/java.sourceui/src/org/netbeans/modules/java/source/ui/JavaSymbolProvider.java --- a/java.sourceui/src/org/netbeans/modules/java/source/ui/JavaSymbolProvider.java +++ b/java.sourceui/src/org/netbeans/modules/java/source/ui/JavaSymbolProvider.java @@ -230,68 +230,11 @@ final Map,Set> r = new HashMap<>(); impl.getDeclaredElements(ident, kind, DocumentUtil.elementHandleConvertor(),r); if (!r.isEmpty()) { - //Needs FileManagerTransaction as it creates CPI with backgroundCompilation == true - TransactionContext. - beginTrans(). - register(FileManagerTransaction.class, FileManagerTransaction.read()). - register(ProcessorGenerated.class, ProcessorGenerated.nullWrite()); - try { - final ClasspathInfo cpInfo = ClasspathInfoAccessor.getINSTANCE().create(root,null,true,true,false,false); - final JavaSource js = JavaSource.create(cpInfo); - js.runUserActionTask(new Task() { - @Override - public void run (final CompilationController controller) { - for (final Map.Entry,Set> p : r.entrySet()) { - final ElementHandle owner = p.getKey(); - final TypeElement te = owner.resolve(controller); - final Set idents = p.getValue(); - if (te != null) { - if (idents.contains(getSimpleName(te, null)) && matchesRestrictions(te, restriction)) { - result.addResult(new JavaSymbolDescriptor( - te.getSimpleName().toString(), - null, - te.getKind(), - te.getModifiers(), - owner, - ElementHandle.create(te), - project, - root, - impl)); - } - for (Element ne : te.getEnclosedElements()) { - if (idents.contains(getSimpleName(ne, te)) && matchesRestrictions(ne, restriction)) { - final Pair name = getDisplayName(ne, te); - result.addResult(new JavaSymbolDescriptor( - name.first(), - name.second(), - ne.getKind(), - ne.getModifiers(), - owner, - ElementHandle.create(ne), - project, - root, - impl)); - } - } - } - } - } - - private String getSimpleName ( - @NonNull final Element element, - @NullAllowed final Element enclosingElement) { - String result = element.getSimpleName().toString(); - if (enclosingElement != null && INIT.equals(result)) { - result = enclosingElement.getSimpleName().toString(); - } - if (!caseSensitive) { - result = result.toLowerCase(); - } - return result; - } - },true); - } finally { - TransactionContext.get().commit(); + for (final Map.Entry,Set> p : r.entrySet()) { + final ElementHandle owner = p.getKey(); + for (String symbol : p.getValue()) { + result.addResult(new AsyncJavaSymbolDescriptor(project, root, impl, owner, symbol)); + } } } @@ -352,7 +295,7 @@ } @NonNull - private static Pair getDisplayName ( + static Pair getDisplayName ( @NonNull final Element e, @NonNull final Element enclosingElement) { assert e != null; diff --git a/java.sourceui/src/org/netbeans/modules/java/source/ui/JavaSymbolDescriptor.java b/java.sourceui/src/org/netbeans/modules/java/source/ui/ResolvedJavaSymbolDescriptor.java copy from java.sourceui/src/org/netbeans/modules/java/source/ui/JavaSymbolDescriptor.java copy to java.sourceui/src/org/netbeans/modules/java/source/ui/ResolvedJavaSymbolDescriptor.java --- a/java.sourceui/src/org/netbeans/modules/java/source/ui/JavaSymbolDescriptor.java +++ b/java.sourceui/src/org/netbeans/modules/java/source/ui/ResolvedJavaSymbolDescriptor.java @@ -42,78 +42,47 @@ package org.netbeans.modules.java.source.ui; -import java.io.File; -import java.io.IOException; -import java.net.URL; import java.util.Set; import javax.lang.model.element.ElementKind; import javax.lang.model.element.Modifier; -import javax.lang.model.element.TypeElement; 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.api.java.classpath.ClassPath; import org.netbeans.api.java.source.ClasspathInfo; import org.netbeans.api.java.source.ElementHandle; -import org.netbeans.api.java.source.SourceUtils; import org.netbeans.api.java.source.ui.ElementOpen; -import org.netbeans.api.project.Project; -import org.netbeans.api.project.ProjectInformation; -import org.netbeans.api.project.ProjectUtils; -import org.netbeans.modules.java.source.parsing.FileObjects; -import org.netbeans.modules.java.source.usages.ClassIndexImpl; import org.netbeans.modules.java.ui.Icons; -import org.netbeans.spi.java.classpath.support.ClassPathSupport; -import org.netbeans.spi.jumpto.symbol.SymbolDescriptor; import org.openide.filesystems.FileObject; -import org.openide.filesystems.FileUtil; -import org.openide.util.Exceptions; /** * * @author Tomas Zezula */ -public class JavaSymbolDescriptor extends SymbolDescriptor { +final class ResolvedJavaSymbolDescriptor extends JavaSymbolDescriptorBase { private final String simpleName; private final String simpleNameSuffix; - private final ElementHandle owner; private final ElementHandle me; private final ElementKind kind; private final Set modifiers; - private final FileObject root; - private final Project project; - private final ClassIndexImpl ci; - private FileObject cachedFo; - private volatile String cachedPath; - public JavaSymbolDescriptor ( + ResolvedJavaSymbolDescriptor ( + @NonNull final JavaSymbolDescriptorBase base, @NonNull final String simpleName, @NullAllowed final String simpleNameSuffix, @NonNull final ElementKind kind, @NonNull final Set modifiers, - @NonNull final ElementHandle owner, - @NonNull final ElementHandle me, - @NullAllowed final Project project, - @NonNull final FileObject root, - @NonNull final ClassIndexImpl ci) { + @NonNull final ElementHandle me) { + super(base); assert simpleName != null; assert kind != null; assert modifiers != null; - assert owner != null; assert me != null; - assert root != null; - assert ci != null; this.simpleName = simpleName; this.simpleNameSuffix = simpleNameSuffix; this.kind = kind; this.modifiers = modifiers; - this.owner = owner; this.me = me; - this.root = root; - this.project = project; - this.ci = ci; } @Override @@ -134,62 +103,6 @@ } @Override - public String getOwnerName() { - return owner.getQualifiedName(); - } - - - @Override - public FileObject getFileObject() { - if (cachedFo == null) { - final ClasspathInfo cpInfo = ClasspathInfo.create(ClassPath.EMPTY, - ClassPath.EMPTY, ClassPathSupport.createClassPath(root)); - cachedFo = SourceUtils.getFile(owner, cpInfo); - } - return cachedFo; - } - - @Override - @NonNull - public String getFileDisplayPath() { - String res = cachedPath; - if (res == null) { - final File rootFile = FileUtil.toFile(root); - if (rootFile != null) { - try { - final String binaryName = owner.getBinaryName(); - String relativePath = ci.getSourceName(binaryName); - if (relativePath == null) { - relativePath = binaryName; - int lastDot = relativePath.lastIndexOf('.'); //NOI18N - int csIndex = relativePath.indexOf('$', lastDot); //NOI18N - if (csIndex > 0 && csIndex < relativePath.length()-1) { - relativePath = binaryName.substring(0, csIndex); - } - relativePath = String.format( - "%s.%s", //NOI18N - FileObjects.convertPackage2Folder(relativePath, File.separatorChar), - FileObjects.JAVA); - } - res = new File (rootFile, relativePath).getAbsolutePath(); - } catch (IOException | InterruptedException e) { - Exceptions.printStackTrace(e); - } - } - if (res == null) { - final FileObject fo = getFileObject(); - res = fo == null ? - "" : //NOI18N - FileUtil.getFileDisplayName(fo); - } - cachedPath = res; - } - return res; - } - - - - @Override public void open() { FileObject file = getFileObject(); if (file != null) { @@ -198,44 +111,4 @@ ElementOpen.open(cpInfo, me); } } - - @Override - public String getProjectName() { - final ProjectInformation info = getProjectInfo(); - return info == null ? - "" : //NOI18N - info.getDisplayName(); - } - - @Override - public Icon getProjectIcon() { - final ProjectInformation info = getProjectInfo(); - return info == null ? - null : - info.getIcon(); - } - - @Override - public int getOffset() { - //todo: fixme - return -1; - } - - @NonNull - public ElementKind getElementKind() { - return kind; - } - - @NonNull - public Set getModifiers() { - return modifiers; - } - - @CheckForNull - private ProjectInformation getProjectInfo() { - return project == null ? - null : - project.getLookup().lookup(ProjectInformation.class); //Intentionally does not use ProjectUtils.getInformation() it does project icon annotation which is expensive - } - } diff --git a/jumpto/src/org/netbeans/modules/jumpto/symbol/ContentProviderImpl.java b/jumpto/src/org/netbeans/modules/jumpto/symbol/ContentProviderImpl.java --- a/jumpto/src/org/netbeans/modules/jumpto/symbol/ContentProviderImpl.java +++ b/jumpto/src/org/netbeans/modules/jumpto/symbol/ContentProviderImpl.java @@ -48,7 +48,6 @@ import java.util.Collection; import java.util.Collections; import java.util.IdentityHashMap; -import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.concurrent.Callable; @@ -65,12 +64,13 @@ import javax.swing.SwingUtilities; 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.jumpto.common.AbstractModelFilter; import org.netbeans.modules.jumpto.common.CurrentSearch; +import org.netbeans.modules.jumpto.common.Factory; import org.netbeans.modules.jumpto.common.ItemRenderer; import org.netbeans.modules.jumpto.common.Models; import org.netbeans.modules.jumpto.common.Utils; +import org.netbeans.spi.jumpto.support.AsyncDescriptor; import org.netbeans.spi.jumpto.symbol.SymbolDescriptor; import org.netbeans.spi.jumpto.symbol.SymbolProvider; import org.netbeans.spi.jumpto.type.SearchType; @@ -272,7 +272,8 @@ @Override public String getHighlightText(@NonNull final SymbolDescriptor item) { - return SymbolProviderAccessor.DEFAULT.getHighlightText(item); + return SymbolProviderAccessor.DEFAULT.getHighlightText( + RefreshableSymbolDescriptor.unwrap(item)); } @Override @@ -362,9 +363,12 @@ lastSize = newSize[0]; lastProvCount = newProvCount; Collections.sort(mergedSymbols, new SymbolComparator()); - final ListModel fmodel = Models.fromList( - mergedSymbols, - currentSearch.resetFilter()); + final ListModel fmodel = Models.refreshable( + Models.fromList( + mergedSymbols, + currentSearch.resetFilter()), + new AsyncConvertor() + ); if ( isCanceled ) { LOG.log( Level.FINE, @@ -498,7 +502,7 @@ } } - private static class Result { + private static final class Result { final List symbols; final int retry; final Collection nonFinishedProviders; @@ -516,4 +520,14 @@ this.nonFinishedProviders.isEmpty(); } } + + private static final class AsyncConvertor implements Factory> { + @Override + public SymbolDescriptor create(Pair p) { + if (p.first() instanceof AsyncDescriptor) { + return new RefreshableSymbolDescriptor(p.first(), p.second()); + } + return p.first(); + } + } } diff --git a/jumpto/src/org/netbeans/modules/jumpto/symbol/RefreshableSymbolDescriptor.java b/jumpto/src/org/netbeans/modules/jumpto/symbol/RefreshableSymbolDescriptor.java new file mode 100644 --- /dev/null +++ b/jumpto/src/org/netbeans/modules/jumpto/symbol/RefreshableSymbolDescriptor.java @@ -0,0 +1,150 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 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 2015 Sun Microsystems, Inc. + */ +package org.netbeans.modules.jumpto.symbol; + +import java.util.Collection; +import javax.swing.Icon; +import javax.swing.SwingUtilities; +import org.netbeans.api.annotations.common.CheckForNull; +import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.api.annotations.common.NullAllowed; +import org.netbeans.spi.jumpto.support.AsyncDescriptor; +import org.netbeans.spi.jumpto.support.DescriptorChangeEvent; +import org.netbeans.spi.jumpto.support.DescriptorChangeListener; +import org.netbeans.spi.jumpto.symbol.SymbolDescriptor; +import org.openide.filesystems.FileObject; + +/** + * + * @author Tomas Zezula + */ +final class RefreshableSymbolDescriptor extends SymbolDescriptor implements DescriptorChangeListener { + + private final Runnable refreshCallback; + private volatile SymbolDescriptor delegate; + + RefreshableSymbolDescriptor( + @NonNull final SymbolDescriptor delegate, + @NonNull final Runnable refreshCallback) { + assert delegate != null; + assert refreshCallback != null; + this.delegate = delegate; + this.refreshCallback = refreshCallback; + if (delegate instanceof AsyncDescriptor) { + ((AsyncDescriptor)delegate).addDescriptorChangeListener(this); + } else { + throw new IllegalArgumentException(String.format( + "The delegate: %s is not an AsyncDescriptor", //NOI18N + delegate)); + } + } + + @Override + public Icon getIcon() { + return delegate.getIcon(); + } + + @Override + public String getSimpleName() { + return delegate.getSimpleName(); + } + + @Override + public String getSymbolName() { + return delegate.getSymbolName(); + } + + @Override + public String getOwnerName() { + return delegate.getOwnerName(); + } + + @Override + public String getProjectName() { + return delegate.getProjectName(); + } + + @Override + public Icon getProjectIcon() { + return delegate.getProjectIcon(); + } + + @Override + public FileObject getFileObject() { + return delegate.getFileObject(); + } + + @Override + public int getOffset() { + return delegate.getOffset(); + } + + @Override + public void open() { + delegate.open(); + } + + @Override + public void descriptorChanged(@NonNull final DescriptorChangeEvent event) { + final Collection symbols = event.getReplacement(); + if (!symbols.isEmpty()) { + //Todo: fixme - size = 0 or size > 1 + delegate = symbols.iterator().next(); + runInEDT(this.refreshCallback); + } + } + + @CheckForNull + static SymbolDescriptor unwrap (@NullAllowed final SymbolDescriptor desc) { + return desc == null || desc.getClass() != RefreshableSymbolDescriptor.class ? + desc : + ((RefreshableSymbolDescriptor)desc).delegate; + } + + private static void runInEDT(@NonNull final Runnable r) { + if (SwingUtilities.isEventDispatchThread()) { + r.run(); + } else { + SwingUtilities.invokeLater(r); + } + } +} diff --git a/jumpto/src/org/netbeans/modules/jumpto/symbol/SymbolComparator.java b/jumpto/src/org/netbeans/modules/jumpto/symbol/SymbolComparator.java --- a/jumpto/src/org/netbeans/modules/jumpto/symbol/SymbolComparator.java +++ b/jumpto/src/org/netbeans/modules/jumpto/symbol/SymbolComparator.java @@ -42,6 +42,7 @@ package org.netbeans.modules.jumpto.symbol; +import org.netbeans.api.annotations.common.NonNull; import org.netbeans.modules.jumpto.EntityComparator; import org.netbeans.spi.jumpto.symbol.SymbolDescriptor; @@ -89,7 +90,7 @@ return result; // e1projectName NOT equals to e2projectName } // here: e1projectName equals to e2projectName - result = compare(e1.getSymbolName(), e2.getSymbolName()); + result = compare(getSortName(e1), getSortName(e2)); if ( result != 0 ) { return result; } @@ -97,4 +98,12 @@ return compare(e1.getOwnerName(), e2.getOwnerName()); } + @NonNull + private static String getSortName(@NonNull final SymbolDescriptor d) { + String res = d.getSimpleName(); + if (res == null) { + res = d.getSymbolName(); + } + return res; + } } diff --git a/jumpto/src/org/netbeans/spi/jumpto/support/AsyncDescriptor.java b/jumpto/src/org/netbeans/spi/jumpto/support/AsyncDescriptor.java new file mode 100644 --- /dev/null +++ b/jumpto/src/org/netbeans/spi/jumpto/support/AsyncDescriptor.java @@ -0,0 +1,53 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 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 2015 Sun Microsystems, Inc. + */ +package org.netbeans.spi.jumpto.support; + +import org.netbeans.api.annotations.common.NonNull; + +/** + * + * @author Tomas Zezula + */ +public interface AsyncDescriptor { + void addDescriptorChangeListener(@NonNull DescriptorChangeListener listener); + void removeDescriptorChangeListener(@NonNull DescriptorChangeListener listener); +} diff --git a/jumpto/src/org/netbeans/spi/jumpto/support/DescriptorChangeEvent.java b/jumpto/src/org/netbeans/spi/jumpto/support/DescriptorChangeEvent.java new file mode 100644 --- /dev/null +++ b/jumpto/src/org/netbeans/spi/jumpto/support/DescriptorChangeEvent.java @@ -0,0 +1,70 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 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 2015 Sun Microsystems, Inc. + */ +package org.netbeans.spi.jumpto.support; + +import java.util.Collection; +import java.util.Collections; +import java.util.EventObject; +import org.netbeans.api.annotations.common.NonNull; +import org.openide.util.Parameters; + +/** + * + * @author Tomas Zezula + */ +public final class DescriptorChangeEvent extends EventObject { + + private final Collection replacement; + + public DescriptorChangeEvent( + @NonNull final T source, + @NonNull final Collection replacement) { + super(source); + Parameters.notNull("descriptors", replacement); //NOI18N + this.replacement = Collections.unmodifiableCollection(replacement); + } + + @NonNull + public Collection getReplacement() { + return replacement; + } +} diff --git a/jumpto/src/org/netbeans/spi/jumpto/support/DescriptorChangeListener.java b/jumpto/src/org/netbeans/spi/jumpto/support/DescriptorChangeListener.java new file mode 100644 --- /dev/null +++ b/jumpto/src/org/netbeans/spi/jumpto/support/DescriptorChangeListener.java @@ -0,0 +1,53 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 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 2015 Sun Microsystems, Inc. + */ +package org.netbeans.spi.jumpto.support; + +import java.util.EventListener; +import org.netbeans.api.annotations.common.NonNull; + +/** + * + * @author Tomas Zezula + */ +public interface DescriptorChangeListener extends EventListener { + void descriptorChanged(@NonNull DescriptorChangeEvent event); +}