Running the computation of remote usages on background, workarounding too broad events from the NbProject causing troubles in finding correct nodes inside the PackageView
1.1 --- a/remoting/ide/usages/nbproject/genfiles.properties Tue Jun 28 16:04:04 2011 +0200
1.2 +++ b/remoting/ide/usages/nbproject/genfiles.properties Wed Jun 29 14:57:07 2011 +0200
1.3 @@ -1,8 +1,8 @@
1.4 -build.xml.data.CRC32=1b87e477
1.5 +build.xml.data.CRC32=6f03c856
1.6 build.xml.script.CRC32=58a6b47a
1.7 build.xml.stylesheet.CRC32=a56c6a5b@1.47
1.8 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
1.9 # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
1.10 -nbproject/build-impl.xml.data.CRC32=1b87e477
1.11 +nbproject/build-impl.xml.data.CRC32=6f03c856
1.12 nbproject/build-impl.xml.script.CRC32=583fd407
1.13 nbproject/build-impl.xml.stylesheet.CRC32=238281d1@1.47
2.1 --- a/remoting/ide/usages/nbproject/project.xml Tue Jun 28 16:04:04 2011 +0200
2.2 +++ b/remoting/ide/usages/nbproject/project.xml Wed Jun 29 14:57:07 2011 +0200
2.3 @@ -58,6 +58,15 @@
2.4 </run-dependency>
2.5 </dependency>
2.6 <dependency>
2.7 + <code-name-base>org.netbeans.modules.project.ant</code-name-base>
2.8 + <build-prerequisite/>
2.9 + <compile-dependency/>
2.10 + <run-dependency>
2.11 + <release-version>1</release-version>
2.12 + <specification-version>1.43</specification-version>
2.13 + </run-dependency>
2.14 + </dependency>
2.15 + <dependency>
2.16 <code-name-base>org.netbeans.modules.projectapi</code-name-base>
2.17 <build-prerequisite/>
2.18 <compile-dependency/>
2.19 @@ -101,6 +110,14 @@
2.20 </run-dependency>
2.21 </dependency>
2.22 <dependency>
2.23 + <code-name-base>org.openide.dialogs</code-name-base>
2.24 + <build-prerequisite/>
2.25 + <compile-dependency/>
2.26 + <run-dependency>
2.27 + <specification-version>7.21</specification-version>
2.28 + </run-dependency>
2.29 + </dependency>
2.30 + <dependency>
2.31 <code-name-base>org.openide.explorer</code-name-base>
2.32 <build-prerequisite/>
2.33 <compile-dependency/>
3.1 --- a/remoting/ide/usages/src/org/netbeans/modules/jackpot30/ide/usages/Nodes.java Tue Jun 28 16:04:04 2011 +0200
3.2 +++ b/remoting/ide/usages/src/org/netbeans/modules/jackpot30/ide/usages/Nodes.java Wed Jun 29 14:57:07 2011 +0200
3.3 @@ -48,13 +48,16 @@
3.4 import com.sun.source.util.SourcePositions;
3.5 import com.sun.source.util.TreePathScanner;
3.6 import java.awt.Image;
3.7 +import java.beans.PropertyChangeEvent;
3.8 import java.io.IOException;
3.9 +import java.lang.reflect.Field;
3.10 import java.util.ArrayList;
3.11 import java.util.Collection;
3.12 import java.util.HashMap;
3.13 import java.util.LinkedList;
3.14 import java.util.List;
3.15 import java.util.Map;
3.16 +import java.util.concurrent.Callable;
3.17 import java.util.concurrent.atomic.AtomicBoolean;
3.18 import java.util.logging.Level;
3.19 import java.util.logging.Logger;
3.20 @@ -65,6 +68,7 @@
3.21 import javax.lang.model.element.TypeElement;
3.22 import javax.lang.model.type.TypeKind;
3.23 import javax.swing.Action;
3.24 +import javax.swing.SwingUtilities;
3.25 import org.netbeans.api.java.classpath.ClassPath;
3.26 import org.netbeans.api.java.classpath.GlobalPathRegistry;
3.27 import org.netbeans.api.java.source.CompilationController;
3.28 @@ -79,6 +83,7 @@
3.29 import org.netbeans.api.project.FileOwnerQuery;
3.30 import org.netbeans.api.project.Project;
3.31 import org.netbeans.api.project.ProjectUtils;
3.32 +import org.netbeans.spi.project.support.ant.PropertyEvaluator;
3.33 import org.netbeans.spi.project.ui.LogicalViewProvider;
3.34 import org.openide.actions.OpenAction;
3.35 import org.openide.cookies.EditorCookie;
3.36 @@ -93,7 +98,11 @@
3.37 import org.openide.nodes.Children;
3.38 import org.openide.nodes.FilterNode;
3.39 import org.openide.nodes.Node;
3.40 +import org.openide.nodes.NodeEvent;
3.41 +import org.openide.nodes.NodeListener;
3.42 +import org.openide.nodes.NodeMemberEvent;
3.43 import org.openide.nodes.NodeOp;
3.44 +import org.openide.nodes.NodeReorderEvent;
3.45 import org.openide.text.Line;
3.46 import org.openide.util.Exceptions;
3.47 import org.openide.util.ImageUtilities;
3.48 @@ -124,6 +133,9 @@
3.49 }
3.50
3.51 projectFiles.add(file);
3.52 +
3.53 + //XXX: workarounding NbProject's Evaluator, which is too stupid to fire meaningfull property events, which leads to PackageView rebuilding inadvertedly itself due to virtual CONTAINERSHIP change:
3.54 + ClassPath.getClassPath(file, ClassPath.COMPILE).getRoots();
3.55 }
3.56
3.57 projects.remove(null);//XXX!!!XXX
3.58 @@ -137,8 +149,8 @@
3.59 return new AbstractNode(new DirectChildren(nodes));
3.60 }
3.61
3.62 - private static Node constructSemiLogicalView(final Project p, Iterable<? extends FileObject> files, ElementHandle<?> eh) {
3.63 - LogicalViewProvider lvp = p.getLookup().lookup(LogicalViewProvider.class);
3.64 + private static Node constructSemiLogicalView(final Project p, final Iterable<? extends FileObject> files, ElementHandle<?> eh) {
3.65 + final LogicalViewProvider lvp = p.getLookup().lookup(LogicalViewProvider.class);
3.66 final Node view;
3.67
3.68 if (lvp != null) {
3.69 @@ -152,38 +164,7 @@
3.70 }
3.71 }
3.72
3.73 - Collection<Node> fileNodes = new ArrayList<Node>();
3.74 -
3.75 - for (FileObject file : files) {
3.76 - Node foundChild = locateChild(view, lvp, file);
3.77 -
3.78 - if (foundChild == null) {
3.79 - Node n = new AbstractNode(Children.LEAF) {
3.80 - @Override
3.81 - public Image getIcon(int type) {
3.82 - return ImageUtilities.icon2Image(ProjectUtils.getInformation(p).getIcon());
3.83 - }
3.84 - @Override
3.85 - public Image getOpenedIcon(int type) {
3.86 - return getIcon(type);
3.87 - }
3.88 - @Override
3.89 - public String getHtmlDisplayName() {
3.90 - return view.getHtmlDisplayName() != null ? NbBundle.getMessage(Nodes.class, "ERR_ProjectNotSupported", view.getHtmlDisplayName()) : null;
3.91 - }
3.92 - @Override
3.93 - public String getDisplayName() {
3.94 - return NbBundle.getMessage(Nodes.class, "ERR_ProjectNotSupported", view.getDisplayName());
3.95 - }
3.96 - };
3.97 -
3.98 - return n;
3.99 - }
3.100 -
3.101 - fileNodes.add(foundChild);
3.102 - }
3.103 -
3.104 - return new Wrapper(view, fileNodes, eh);
3.105 + return new Wrapper(view, new ComputeNodes(files, view, lvp, p), eh);
3.106 }
3.107
3.108 private static Node locateChild(Node parent, LogicalViewProvider lvp, FileObject file) {
3.109 @@ -196,7 +177,7 @@
3.110
3.111 private static class Wrapper extends FilterNode {
3.112
3.113 - public Wrapper(Node orig, Collection<? extends Node> fileNodes, ElementHandle<?> eh) {
3.114 + public Wrapper(Node orig, ComputeNodes fileNodes, ElementHandle<?> eh) {
3.115 super(orig, new WrapperChildren(orig, fileNodes, eh));
3.116 }
3.117
3.118 @@ -224,10 +205,10 @@
3.119 private static class WrapperChildren extends Children.Keys<Node> {
3.120
3.121 private final Node orig;
3.122 - private final Collection<? extends Node> fileNodes;
3.123 + private final ComputeNodes fileNodes;
3.124 private final ElementHandle<?> eh;
3.125
3.126 - public WrapperChildren(Node orig, Collection<? extends Node> fileNodes, ElementHandle<?> eh) {
3.127 + public WrapperChildren(Node orig, ComputeNodes fileNodes, ElementHandle<?> eh) {
3.128 this.orig = orig;
3.129 this.fileNodes = fileNodes;
3.130 this.eh = eh;
3.131 @@ -245,7 +226,7 @@
3.132 List<Node> toSet = new LinkedList<Node>();
3.133
3.134 OUTER: for (Node n : nodes) {
3.135 - for (Node c : fileNodes) {
3.136 + for (Node c : fileNodes.compute()) {
3.137 if (n == c || isParent(n, c)) {
3.138 toSet.add(n);
3.139 continue OUTER;
3.140 @@ -258,7 +239,7 @@
3.141
3.142 @Override
3.143 protected Node[] createNodes(Node key) {
3.144 - if (fileNodes.contains(key)) {
3.145 + if (fileNodes.compute().contains(key)) {
3.146 FileObject file = key.getLookup().lookup(FileObject.class);
3.147 Children c = file != null ? Children.create(new UsagesChildren(file, eh), true) : Children.LEAF;
3.148
3.149 @@ -475,4 +456,56 @@
3.150
3.151 return input;
3.152 }
3.153 +
3.154 + private static class ComputeNodes {
3.155 +
3.156 + private final Iterable<? extends FileObject> files;
3.157 + private final Node view;
3.158 + private final LogicalViewProvider lvp;
3.159 + private final Project p;
3.160 +
3.161 + public ComputeNodes(Iterable<? extends FileObject> files, Node view, LogicalViewProvider lvp, Project p) {
3.162 + this.files = files;
3.163 + this.view = view;
3.164 + this.lvp = lvp;
3.165 + this.p = p;
3.166 + }
3.167 +
3.168 + private Collection<Node> result;
3.169 +
3.170 + public synchronized Collection<Node> compute() {
3.171 + if (result != null) return result;
3.172 +
3.173 + Collection<Node> fileNodes = new ArrayList<Node>();
3.174 +
3.175 + for (FileObject file : files) {
3.176 + Node foundChild = locateChild(view, lvp, file);
3.177 +
3.178 + if (foundChild == null) {
3.179 + foundChild = new AbstractNode(Children.LEAF) {
3.180 + @Override
3.181 + public Image getIcon(int type) {
3.182 + return ImageUtilities.icon2Image(ProjectUtils.getInformation(p).getIcon());
3.183 + }
3.184 + @Override
3.185 + public Image getOpenedIcon(int type) {
3.186 + return getIcon(type);
3.187 + }
3.188 + @Override
3.189 + public String getHtmlDisplayName() {
3.190 + return view.getHtmlDisplayName() != null ? NbBundle.getMessage(Nodes.class, "ERR_ProjectNotSupported", view.getHtmlDisplayName()) : null;
3.191 + }
3.192 + @Override
3.193 + public String getDisplayName() {
3.194 + return NbBundle.getMessage(Nodes.class, "ERR_ProjectNotSupported", view.getDisplayName());
3.195 + }
3.196 + };
3.197 + }
3.198 +
3.199 + fileNodes.add(foundChild);
3.200 + }
3.201 +
3.202 + return result = fileNodes;
3.203 + }
3.204 + }
3.205 }
4.1 --- a/remoting/ide/usages/src/org/netbeans/modules/jackpot30/ide/usages/RemoteUsages.java Tue Jun 28 16:04:04 2011 +0200
4.2 +++ b/remoting/ide/usages/src/org/netbeans/modules/jackpot30/ide/usages/RemoteUsages.java Wed Jun 29 14:57:07 2011 +0200
4.3 @@ -42,6 +42,7 @@
4.4 package org.netbeans.modules.jackpot30.ide.usages;
4.5
4.6 import com.sun.source.util.TreePath;
4.7 +import java.awt.Dialog;
4.8 import java.awt.event.ActionEvent;
4.9 import java.awt.event.ActionListener;
4.10 import java.io.File;
4.11 @@ -52,6 +53,7 @@
4.12 import java.util.ArrayList;
4.13 import java.util.List;
4.14 import javax.lang.model.element.Element;
4.15 +import javax.swing.SwingUtilities;
4.16 import javax.swing.text.JTextComponent;
4.17 import org.netbeans.api.editor.EditorRegistry;
4.18 import org.netbeans.api.java.source.CompilationController;
4.19 @@ -61,14 +63,20 @@
4.20 import org.netbeans.modules.editor.NbEditorUtilities;
4.21 import org.netbeans.modules.jackpot30.remoting.api.RemoteIndex;
4.22 import org.netbeans.modules.jackpot30.remoting.api.WebUtilities;
4.23 +import org.openide.DialogDescriptor;
4.24 +import org.openide.DialogDisplayer;
4.25 +import org.openide.NotifyDescriptor;
4.26 +import org.openide.NotifyDescriptor.Message;
4.27 import org.openide.awt.ActionRegistration;
4.28 import org.openide.awt.ActionReference;
4.29 import org.openide.awt.ActionReferences;
4.30 import org.openide.awt.ActionID;
4.31 import org.openide.filesystems.FileObject;
4.32 import org.openide.filesystems.FileUtil;
4.33 +import org.openide.nodes.Node;
4.34 import org.openide.util.Exceptions;
4.35 import org.openide.util.NbBundle.Messages;
4.36 +import org.openide.util.RequestProcessor;
4.37
4.38 @ActionID(category = "Refactoring",
4.39 id = "org.netbeans.modules.jackpot30.ide.usages.RemoteUsages")
4.40 @@ -79,51 +87,74 @@
4.41 @Messages("CTL_RemoteUsages=Find Remote Usages...")
4.42 public final class RemoteUsages implements ActionListener {
4.43
4.44 + private final RequestProcessor WORKER = new RequestProcessor(RemoteUsages.class.getName(), 1, false, false);
4.45 +
4.46 public void actionPerformed(ActionEvent e) {
4.47 JTextComponent comp = EditorRegistry.lastFocusedComponent(); //XXX
4.48
4.49 if (comp == null) return;
4.50
4.51 - FileObject file = NbEditorUtilities.getFileObject(comp.getDocument());
4.52 + final FileObject file = NbEditorUtilities.getFileObject(comp.getDocument());
4.53 final int pos = comp.getCaretPosition();
4.54
4.55 - try {
4.56 - final ElementHandle<?>[] handle = new ElementHandle<?>[1];
4.57 - final String[] serialized = new String[1];
4.58 -
4.59 - JavaSource.forFileObject(file).runUserActionTask(new Task<CompilationController>() {
4.60 - @Override public void run(CompilationController parameter) throws Exception {
4.61 - parameter.toPhase(JavaSource.Phase.RESOLVED);
4.62 + DialogDescriptor dd = new DialogDescriptor("Querying remote server(s), please wait", "Please Wait", true, new Object[0], null, DialogDescriptor.DEFAULT_ALIGN, null, null);
4.63 + final Dialog d = DialogDisplayer.getDefault().createDialog(dd);
4.64
4.65 - TreePath tp = parameter.getTreeUtilities().pathFor(pos);
4.66 - Element el = parameter.getTrees().getElement(tp);
4.67 + WORKER.post(new Runnable() {
4.68 + @Override public void run() {
4.69 + try {
4.70 + final ElementHandle<?>[] handle = new ElementHandle<?>[1];
4.71 + final String[] serialized = new String[1];
4.72
4.73 - if (el != null && Common.SUPPORTED_KINDS.contains(el.getKind())) {
4.74 - serialized[0] = serialize(handle[0] = ElementHandle.create(el));
4.75 + JavaSource.forFileObject(file).runUserActionTask(new Task<CompilationController>() {
4.76 + @Override public void run(CompilationController parameter) throws Exception {
4.77 + parameter.toPhase(JavaSource.Phase.RESOLVED);
4.78 +
4.79 + TreePath tp = parameter.getTreeUtilities().pathFor(pos);
4.80 + Element el = parameter.getTrees().getElement(tp);
4.81 +
4.82 + if (el != null && Common.SUPPORTED_KINDS.contains(el.getKind())) {
4.83 + serialized[0] = serialize(handle[0] = ElementHandle.create(el));
4.84 + }
4.85 + }
4.86 + }, true);
4.87 +
4.88 + if (serialized[0] == null) return ; //XXX: warn user!
4.89 +
4.90 + List<FileObject> result = new ArrayList<FileObject>();
4.91 +
4.92 + for (RemoteIndex idx : RemoteIndex.loadIndices()) {
4.93 + URI resolved = new URI(idx.remote.toExternalForm() + "/usages/search?path=" + WebUtilities.escapeForQuery(idx.remoteSegment) + "&signatures=" + WebUtilities.escapeForQuery(serialized[0]));
4.94 +
4.95 + for (String path : WebUtilities.requestStringArrayResponse(resolved)) {
4.96 + File f = new File(idx.folder, path);
4.97 +
4.98 + result.add(FileUtil.toFileObject(f));
4.99 + }
4.100 }
4.101 - }
4.102 - }, true);
4.103
4.104 - if (serialized[0] == null) return ; //XXX: warn user!
4.105 + final Node view = Nodes.constructSemiLogicalView(result, handle[0]);
4.106
4.107 - List<FileObject> result = new ArrayList<FileObject>();
4.108 -
4.109 - for (RemoteIndex idx : RemoteIndex.loadIndices()) {
4.110 - URI resolved = new URI(idx.remote.toExternalForm() + "/usages/search?path=" + WebUtilities.escapeForQuery(idx.remoteSegment) + "&signatures=" + WebUtilities.escapeForQuery(serialized[0]));
4.111 -
4.112 - for (String path : WebUtilities.requestStringArrayResponse(resolved)) {
4.113 - File f = new File(idx.folder, path);
4.114 -
4.115 - result.add(FileUtil.toFileObject(f));
4.116 + SwingUtilities.invokeLater(new Runnable() {
4.117 + @Override public void run() {
4.118 + RemoteUsagesWindowTopComponent.openFor(view);
4.119 + }
4.120 + });
4.121 + } catch (URISyntaxException ex) {
4.122 + Exceptions.printStackTrace(ex);
4.123 + } catch (IOException ex) {
4.124 + Exceptions.printStackTrace(ex);
4.125 + } finally {
4.126 + SwingUtilities.invokeLater(new Runnable() {
4.127 + @Override public void run() {
4.128 + d.setVisible(false);
4.129 + }
4.130 + });
4.131 }
4.132 }
4.133 + });
4.134
4.135 - RemoteUsagesWindowTopComponent.openFor(Nodes.constructSemiLogicalView(result, handle[0]));
4.136 - } catch (URISyntaxException ex) {
4.137 - Exceptions.printStackTrace(ex);
4.138 - } catch (IOException ex) {
4.139 - Exceptions.printStackTrace(ex);
4.140 - }
4.141 + d.setVisible(true);
4.142 }
4.143
4.144 //XXX: