Merge branch 'master' of git@git.labs.intellij.net:idea/community
authorKirill Kalishev <kirill.kalishev@jetbrains.com>
Tue, 1 Dec 2009 13:25:05 +0000 (16:25 +0300)
committerKirill Kalishev <kirill.kalishev@jetbrains.com>
Tue, 1 Dec 2009 13:25:05 +0000 (16:25 +0300)
platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java
platform/platform-api/src/com/intellij/ide/util/treeView/UpdaterTreeState.java
platform/platform-resources-en/src/misc/registry.properties

index b670e0812c13d492643f9cfb675932e0368a6025..cc464273d97627743f6ad84116b3525b4ce54f5e 100644 (file)
@@ -152,6 +152,9 @@ public class AbstractTreeUi {
   private boolean myPassthroughMode = false;
 
 
+  private Set<Object> myAutoExpandRoots = new HashSet<Object>();
+  private final RegistryValue myAutoExpandDepth = Registry.get("ide.tree.autoExpandMaxDepth");
+
   protected void init(AbstractTreeBuilder builder,
                       JTree tree,
                       DefaultTreeModel treeModel,
@@ -582,14 +585,43 @@ public class AbstractTreeUi {
       autoExpand = getBuilder().isAutoExpandNode(descriptor);
     }
 
+    Object element = getElementFromDescriptor(descriptor);
+    autoExpand = validateAutoExpand(autoExpand, element);
+
     if (!autoExpand && !myTree.isRootVisible()) {
-      Object element = getElementFromDescriptor(descriptor);
       if (element != null && element.equals(getTreeStructure().getRootElement())) return true;
     }
 
     return autoExpand;
   }
 
+  private boolean validateAutoExpand(boolean autoExpand, Object element) {
+    if (autoExpand) {
+      int distance = getDistanceToAutoExpandRoot(element);
+      if (distance < 0) {
+        myAutoExpandRoots.add(element);
+      } else {
+        if (distance >= myAutoExpandDepth.asInteger() - 1) {
+          autoExpand = false;
+        }
+      }
+    }
+    return autoExpand;
+  }
+
+  private int getDistanceToAutoExpandRoot(Object element) {
+    int distance = 0;
+
+    Object eachParent = element;
+    while (eachParent != null) {
+      if (myAutoExpandRoots.contains(eachParent)) break;
+      eachParent = getTreeStructure().getParentElement(eachParent);
+      distance++;
+    }
+
+    return eachParent != null ? distance : -1;
+  }
+
   private boolean isAutoExpand(DefaultMutableTreeNode node) {
     return isAutoExpand(getDescriptorFrom(node));
   }
@@ -931,7 +963,7 @@ public class AbstractTreeUi {
           addSelectionPath(getPathFor(node), true, Condition.TRUE, null);
         }
 
-        doWithUpdaterState(new Runnable() {
+        processInnerChange(new Runnable() {
           public void run() {
             for (TreeNode each : children) {
               removeNodeFromParent((MutableTreeNode)each, true);
@@ -1866,16 +1898,23 @@ public class AbstractTreeUi {
 
 
   private boolean canSmartExpand(DefaultMutableTreeNode node, boolean canSmartExpand) {
-    return !myNotForSmartExpand.contains(node) && canSmartExpand;
+    if (!getBuilder().isSmartExpand()) return false;
+
+    boolean smartExpand = !myNotForSmartExpand.contains(node) && canSmartExpand;
+    return smartExpand ? validateAutoExpand(smartExpand, getElementFor(node)) : false;
   }
 
-  private void processSmartExpand(final DefaultMutableTreeNode node, final boolean canSmartExpand) {
-    if (!getBuilder().isSmartExpand() || !canSmartExpand(node, canSmartExpand)) return;
+  private void processSmartExpand(final DefaultMutableTreeNode node, final boolean canSmartExpand, boolean forced) {
+    if (!getBuilder().isSmartExpand()) return;
+
+    boolean can = canSmartExpand(node, canSmartExpand);
+
+    if (!can && !forced) return;
 
-    if (isNodeBeingBuilt(node)) {
+    if (isNodeBeingBuilt(node) && !forced) {
       addNodeAction(getElementFor(node), new NodeAction() {
         public void onReady(DefaultMutableTreeNode node) {
-          processSmartExpand(node, canSmartExpand);
+          processSmartExpand(node, canSmartExpand, true);
         }
       }, true);
     }
@@ -1883,7 +1922,11 @@ public class AbstractTreeUi {
       TreeNode child = getChildForSmartExpand(node);
       if (child != null) {
         final TreePath childPath = new TreePath(node.getPath()).pathByAddingChild(child);
-        myTree.expandPath(childPath);
+        processInnerChange(new Runnable() {
+          public void run() {
+            myTree.expandPath(childPath);
+          }
+        });
       }
     }
   }
@@ -2147,7 +2190,7 @@ public class AbstractTreeUi {
   }
 
   private void addSelectionPath(final TreePath path, final boolean isAdjustedSelection, final Condition isExpiredAdjustement, @Nullable final Object adjustmentCause) {
-    doWithUpdaterState(new Runnable() {
+    processInnerChange(new Runnable() {
       public void run() {
         TreePath toSelect = null;
 
@@ -2196,7 +2239,7 @@ public class AbstractTreeUi {
 
 
   private void removeNodeFromParent(final MutableTreeNode node, final boolean willAdjustSelection) {
-    doWithUpdaterState(new Runnable() {
+    processInnerChange(new Runnable() {
       public void run() {
         if (willAdjustSelection) {
           final TreePath path = getPathFor(node);
@@ -2211,7 +2254,7 @@ public class AbstractTreeUi {
   }
 
   private void expandPath(final TreePath path, final boolean canSmartExpand) {
-    doWithUpdaterState(new Runnable() {
+    processInnerChange(new Runnable() {
       public void run() {
         if (path.getLastPathComponent() instanceof DefaultMutableTreeNode) {
           DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
@@ -2222,7 +2265,7 @@ public class AbstractTreeUi {
             try {
               myRequestedExpand = path;
               myTree.expandPath(path);
-              processSmartExpand(node, canSmartExpand);
+              processSmartExpand(node, canSmartExpand, false);
             }
             finally {
               myNotForSmartExpand.remove(node);
@@ -2237,13 +2280,16 @@ public class AbstractTreeUi {
     });
   }
 
-  private void doWithUpdaterState(Runnable runnable) {
-    if (myUpdaterState != null) {
-      myUpdaterState.process(runnable);
-    }
-    else {
-      runnable.run();
+  private void processInnerChange(Runnable runnable) {
+    if (myUpdaterState == null) {
+      setUpdaterState(new UpdaterTreeState(this));
     }
+
+    myUpdaterState.process(runnable);
+  }
+
+  private boolean isInnerChange() {
+    return myUpdaterState != null && myUpdaterState.isProcessingNow();
   }
 
   protected boolean doUpdateNodeDescriptor(final NodeDescriptor descriptor) {
@@ -2517,7 +2563,7 @@ public class AbstractTreeUi {
 
       sortChildren(parentNode, all, true, false);
       if (!before.equals(all)) {
-        doWithUpdaterState(new Runnable() {
+        processInnerChange(new Runnable() {
           public void run() {
             parentNode.removeAllChildren();
             for (TreeNode each : all) {
@@ -2564,6 +2610,7 @@ public class AbstractTreeUi {
     if (descriptor == null) return;
     final Object element = getElementFromDescriptor(descriptor);
     removeMapping(element, node, null);
+    myAutoExpandRoots.remove(element);
     node.setUserObject(null);
     node.removeAllChildren();
   }
@@ -3204,8 +3251,9 @@ public class AbstractTreeUi {
   }
 
   private void dropUpdaterStateIfExternalChange() {
-   if (myUpdaterState != null && !myUpdaterState.isProcessingNow()) {
-      clearUpdaterState();
+   if (!isInnerChange()) {
+     clearUpdaterState();
+     myAutoExpandRoots.clear();
     }
   }
 
@@ -3427,7 +3475,7 @@ public class AbstractTreeUi {
         getBuilder().expandNodeChildren(node);
       }
 
-      processSmartExpand(node, canSmartExpand(node, true));
+      processSmartExpand(node, canSmartExpand(node, true), false);
       processNodeActionsIfReady(node);
     }
 
index 885d45b5e4a327015dd1af87bf5ab2bf76066b2e..5e61c53e07fd6c29c681947bde6b3d2559e289d6 100644 (file)
@@ -40,11 +40,17 @@ public class UpdaterTreeState {
   private WeakHashMap<Object, Object> myAdjustmentCause2Adjustment = new WeakHashMap<Object, Object>();
 
   public UpdaterTreeState(AbstractTreeUi ui) {
+    this(ui, false);
+  }
+
+  public UpdaterTreeState(AbstractTreeUi ui, boolean isEmpty) {
     myUi = ui;
 
-    final JTree tree = myUi.getTree();
-    putAll(addPaths(tree.getSelectionPaths()), myToSelect);
-    putAll(addPaths(tree.getExpandedDescendants(new TreePath(tree.getModel().getRoot()))), myToExpand);
+    if (!isEmpty) {
+      final JTree tree = myUi.getTree();
+      putAll(addPaths(tree.getSelectionPaths()), myToSelect);
+      putAll(addPaths(tree.getExpandedDescendants(new TreePath(tree.getModel().getRoot()))), myToExpand);
+    }
   }
 
   private static void putAll(final Set<Object> source, final Map<Object, Object> target) {
index 07e4cfea1f86a3119d34c5ff25be661887876ab6..625b0f97e46894a33f3cfa6d2c130e90440a9c8d 100644 (file)
@@ -31,6 +31,7 @@ ide.tree.waitForReadyTimout=250
 ide.tree.clearOnHideTime=120000
 ide.tree.autoscrollToVCenter=true
 ide.tree.ensureSelectionOnFocusGained=true
+ide.tree.autoExpandMaxDepth=5
 
 ide.tabbedPane.bufferedPaint=true