StructureView: selectIn fixed after tree had beed made asynchronous
authorKirill Kalishev <kirill.kalishev@jetbrains.com>
Wed, 3 Mar 2010 14:21:18 +0000 (17:21 +0300)
committerKirill Kalishev <kirill.kalishev@jetbrains.com>
Wed, 3 Mar 2010 14:21:18 +0000 (17:21 +0300)
platform/lang-impl/src/com/intellij/ide/impl/StructureViewWrapperImpl.java
platform/lang-impl/src/com/intellij/ide/structureView/impl/StructureViewComposite.java
platform/lang-impl/src/com/intellij/ide/structureView/newStructureView/StructureViewComponent.java
platform/platform-api/src/com/intellij/ide/structureView/StructureView.java
platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java
platform/platform-api/src/com/intellij/util/ui/update/MergingUpdateQueue.java
xml/dom-impl/src/com/intellij/util/xml/structure/DomStructureViewBuilder.java

index 386c9276fe35c0d563aa84fdffc287c046b45c7c..52c6bc49fb2c9f5a53216402dcfd7c9b28ffcba2 100644 (file)
@@ -43,7 +43,6 @@ import com.intellij.openapi.wm.ToolWindowId;
 import com.intellij.openapi.wm.ToolWindowManager;
 import com.intellij.openapi.wm.ex.IdeFocusTraversalPolicy;
 import com.intellij.psi.PsiDocumentManager;
-import com.intellij.util.Alarm;
 import com.intellij.util.ui.UIUtil;
 import com.intellij.util.ui.update.MergingUpdateQueue;
 import com.intellij.util.ui.update.Update;
@@ -74,6 +73,8 @@ public class StructureViewWrapperImpl implements StructureViewWrapper, Disposabl
   // Constructor
   // -------------------------------------------------------------------------
 
+  private Runnable myPendingSelection;
+
   public StructureViewWrapperImpl(Project project) {
     myProject = project;
     myPanel = new ContentPanel();
@@ -140,17 +141,34 @@ public class StructureViewWrapperImpl implements StructureViewWrapper, Disposabl
     rebuild();
   }
 
-  public boolean selectCurrentElement(FileEditor fileEditor, VirtualFile file, boolean requestFocus) {
-    if (myStructureView != null) {
-      if (!Comparing.equal(myStructureView.getFileEditor(), fileEditor)) {
-        myFile = file;
-        rebuild();
+  public boolean selectCurrentElement(final FileEditor fileEditor, final VirtualFile file, final boolean requestFocus) {
+    //todo [kirillk]
+    // this is dirty hack since some bright minds decided to used different TreeUi every time, so selection may be followed
+    // by rebuild on completely different instance of TreeUi
+
+    Runnable runnable = new Runnable() {
+      public void run() {
+        if (myStructureView != null) {
+          if (!Comparing.equal(myStructureView.getFileEditor(), fileEditor)) {
+            myFile = file;
+            rebuild();
+          }
+          myStructureView.navigateToSelectedElement(requestFocus);
+        }
       }
-      return myStructureView.navigateToSelectedElement(requestFocus);
-    }
-    else {
-      return false;
+    };
+
+    if (isStructureViewShowing()) {
+      if (myUpdateQueue.isEmpty()) {
+        runnable.run();
+      } else {
+        myPendingSelection = runnable;
+      }
+    } else {
+      myPendingSelection = runnable;
     }
+
+    return true;
   }
 
   private void scheduleRebuild() {
@@ -243,6 +261,12 @@ public class StructureViewWrapperImpl implements StructureViewWrapper, Disposabl
 
     myPanel.validate();
     myPanel.repaint();
+
+    if (myPendingSelection != null) {
+      Runnable selection = myPendingSelection;
+      myPendingSelection = null;
+      selection.run();
+    }
   }
 
   @Nullable
index 9bde0747f51659c508ccc375044a7ffe70f635a3..2928ac34fcce87a66fa1b215f2b6fc33eb14400b 100644 (file)
@@ -114,4 +114,5 @@ public class StructureViewComposite implements StructureView {
   public StructureViewModel getTreeModel() {
     return getSelectedStructureView().getTreeModel();
   }
+
 }
index a85871cbb7328f90f95af775099e4e6c347a4ab0..3bf98933699384ecc839e1cb52b0c0c4dd83fb63 100644 (file)
@@ -24,7 +24,6 @@ import com.intellij.ide.structureView.*;
 import com.intellij.ide.structureView.impl.StructureViewFactoryImpl;
 import com.intellij.ide.structureView.impl.StructureViewState;
 import com.intellij.ide.structureView.impl.common.PsiTreeElementBase;
-import com.intellij.ide.ui.customization.CustomActionsSchema;
 import com.intellij.ide.ui.customization.CustomizationUtil;
 import com.intellij.ide.util.treeView.*;
 import com.intellij.ide.util.treeView.smartTree.*;
@@ -37,10 +36,8 @@ import com.intellij.openapi.fileEditor.FileEditor;
 import com.intellij.openapi.fileEditor.FileEditorManager;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.ui.SimpleToolWindowPanel;
-import com.intellij.openapi.util.Comparing;
-import com.intellij.openapi.util.Disposer;
-import com.intellij.openapi.util.Key;
-import com.intellij.openapi.util.ModificationTracker;
+import com.intellij.openapi.util.*;
+import com.intellij.openapi.wm.IdeFocusManager;
 import com.intellij.pom.Navigatable;
 import com.intellij.psi.PsiDocumentManager;
 import com.intellij.psi.PsiElement;
@@ -402,59 +399,40 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
     return myFileEditor;
   }
 
-  public DefaultMutableTreeNode expandPathToElement(Object element) {
-    if (myAbstractTreeBuilder == null) return null;
+  public AsyncResult<AbstractTreeNode> expandPathToElement(Object element) {
+    if (myAbstractTreeBuilder == null) return new AsyncResult.Rejected<AbstractTreeNode>();
 
     ArrayList<AbstractTreeNode> pathToElement = getPathToElement(element);
+    if (pathToElement.isEmpty()) return new AsyncResult.Rejected<AbstractTreeNode>();
 
-    if (pathToElement.isEmpty()) return null;
-
-    JTree tree = myAbstractTreeBuilder.getTree();
-
-    if (pathToElement.size() == 1) {
-      return (DefaultMutableTreeNode)tree.getModel().getRoot();
-    }
-
-    DefaultMutableTreeNode currentTreeNode = (DefaultMutableTreeNode)tree.getModel().getRoot();
-    pathToElement.remove(0);
-    DefaultMutableTreeNode result = null;
-    while (currentTreeNode != null) {
-      AbstractTreeNode topPathElement;
-      if (!pathToElement.isEmpty()) {
-        topPathElement = pathToElement.get(0);
-        pathToElement.remove(0);
-      }
-      else {
-        topPathElement = null;
+    final AsyncResult<AbstractTreeNode> result = new AsyncResult<AbstractTreeNode>();
+    final AbstractTreeNode toExpand = pathToElement.get(pathToElement.size() - 1);
+    myAbstractTreeBuilder.expand(toExpand, new Runnable() {
+      public void run() {
+        result.setDone(toExpand);
       }
-      TreePath treePath = new TreePath(currentTreeNode.getPath());
-      if (!tree.isExpanded(treePath)) {
-        tree.expandPath(treePath);
-      }
-      if (topPathElement != null) {
-        currentTreeNode = findInChildren(currentTreeNode, topPathElement);
-        result = currentTreeNode;
-      }
-      else {
-        currentTreeNode = null;
-      }
-    }
+    });
+
     return result;
   }
 
-  public boolean select(Object element, boolean requestFocus) {
-    DefaultMutableTreeNode currentTreeNode = expandPathToElement(element);
-
-    if (currentTreeNode != null) {
-      TreeUtil.selectInTree(currentTreeNode, requestFocus, getTree());
-      myAutoScrollToSourceHandler.setShouldAutoScroll(false);
-      TreePath path = new TreePath(currentTreeNode.getPath());
-      TreeUtil.showRowCentered(getTree(), getTree().getRowForPath(path), false);
-      myAutoScrollToSourceHandler.setShouldAutoScroll(true);
-      centerSelectedRow();
-      return true;
-    }
-    return false;
+  public boolean select(final Object element, final boolean requestFocus) {
+    myAbstractTreeBuilder.getReady(this).doWhenDone(new Runnable() {
+      public void run() {
+        expandPathToElement(element).doWhenDone(new AsyncResult.Handler<AbstractTreeNode>() {
+          public void run(AbstractTreeNode abstractTreeNode) {
+            myAbstractTreeBuilder.select(abstractTreeNode, new Runnable() {
+              public void run() {
+                if (requestFocus) {
+                  IdeFocusManager.getInstance(myProject).requestFocus(myAbstractTreeBuilder.getTree(), false);
+                }
+              }
+            });
+          }
+        });
+      }
+    });
+    return true;
   }
 
   private ArrayList<AbstractTreeNode> getPathToElement(Object element) {
@@ -826,4 +804,5 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
   public String getHelpID() {
     return ourHelpID;
   }
+
 }
index ac0f529b4f08b8ee8c9975277faa7619726639fe..647dfc0691facecefe46360fa21fdf45e34013ee 100644 (file)
@@ -17,6 +17,7 @@ package com.intellij.ide.structureView;
 
 import com.intellij.openapi.Disposable;
 import com.intellij.openapi.fileEditor.FileEditor;
+import com.intellij.openapi.util.ActionCallback;
 
 import javax.swing.*;
 
index aa2d7465ce496e22efeb70c22db521e4238fe6db..bc1e7a6378a5f24d1d18d2d2567c2cd66ca7bf86 100644 (file)
@@ -1562,7 +1562,8 @@ public class AbstractTreeUi {
       }
 
       if (myInitialized.isDone()) {
-        for (ActionCallback each : getReadyCallbacks(true)) {
+        ActionCallback[] ready = getReadyCallbacks(true);
+        for (ActionCallback each : ready) {
           each.setDone();
         }
       }
index 674f0df320bf16ae44c17cb50c4ebd8511d62419..adc6e75c718017d4a411c2c5a5817d549e0de50f 100644 (file)
@@ -117,6 +117,9 @@ public class MergingUpdateQueue implements Runnable, Disposable, Activatable {
 
   public void cancelAllUpdates() {
     synchronized (myScheduledUpdates) {
+      for (Update each : myScheduledUpdates.keySet()) {
+        each.setRejected();
+      }
       myScheduledUpdates.clear();
     }
   }
@@ -317,6 +320,7 @@ public class MergingUpdateQueue implements Runnable, Disposable, Activatable {
       }
       if (update.canEat(eachInQueue)) {
         myScheduledUpdates.remove(eachInQueue);
+        eachInQueue.setRejected();
       }
     }
     return false;
index c1fe629ef4d503f6e4503d76d23be242e26c2fd6..94ccf53e6414c4692f0edf5bfc9d3e9ea3b97e60 100644 (file)
@@ -20,8 +20,10 @@ import com.intellij.ide.structureView.StructureView;
 import com.intellij.ide.structureView.StructureViewModel;
 import com.intellij.ide.structureView.TreeBasedStructureViewBuilder;
 import com.intellij.ide.structureView.newStructureView.StructureViewComponent;
+import com.intellij.ide.util.treeView.AbstractTreeNode;
 import com.intellij.openapi.fileEditor.FileEditor;
 import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.AsyncResult;
 import com.intellij.psi.util.PsiTreeUtil;
 import com.intellij.psi.xml.XmlElement;
 import com.intellij.psi.xml.XmlTag;
@@ -32,8 +34,6 @@ import com.intellij.util.xml.DomManager;
 import com.intellij.util.xml.DomService;
 import org.jetbrains.annotations.NotNull;
 
-import javax.swing.tree.DefaultMutableTreeNode;
-
 public class DomStructureViewBuilder extends TreeBasedStructureViewBuilder {
   private final Function<DomElement, DomService.StructureViewMode> myDescriptor;
   private final XmlFile myFile;
@@ -55,7 +55,7 @@ public class DomStructureViewBuilder extends TreeBasedStructureViewBuilder {
   @NotNull
   public StructureView createStructureView(final FileEditor fileEditor, final Project project) {
     return new StructureViewComponent(fileEditor, createStructureViewModel(), project) {
-      public DefaultMutableTreeNode expandPathToElement(final Object element) {
+      public AsyncResult<AbstractTreeNode> expandPathToElement(final Object element) {
         if (element instanceof XmlElement) {
           final XmlElement xmlElement = (XmlElement)element;
           XmlTag tag = PsiTreeUtil.getParentOfType(xmlElement, XmlTag.class, false);