diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/ConfigureTasksActivationDialog.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/ConfigureTasksActivationDialog.java index 0c265487d92f..ff8cb1d5c682 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/ConfigureTasksActivationDialog.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/ConfigureTasksActivationDialog.java @@ -27,7 +27,6 @@ import com.intellij.openapi.externalSystem.model.ExternalProjectInfo; import com.intellij.openapi.externalSystem.model.ProjectKeys; import com.intellij.openapi.externalSystem.model.ProjectSystemId; import com.intellij.openapi.externalSystem.model.project.ModuleData; -import com.intellij.openapi.externalSystem.model.task.TaskData; import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator; import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator.Phase; import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; @@ -45,7 +44,6 @@ import com.intellij.openapi.ui.popup.ListPopupStep; import com.intellij.openapi.ui.popup.PopupStep; import com.intellij.openapi.ui.popup.util.BaseListPopupStep; import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; import com.intellij.ui.*; import com.intellij.ui.awt.RelativePoint; @@ -395,13 +393,7 @@ public class ConfigureTasksActivationDialog extends DialogWrapper { cleanUpEmptyNodes(node); } - TreeState treeState = new TreeState(); - try { - treeState.readExternal(treeStateElement); - treeState.applyTo(myTree); - } - catch (InvalidDataException ignore) { - } + TreeState.createFrom(treeStateElement).applyTo(myTree); } private void cleanUpEmptyNodes(@NotNull CachingSimpleNode node) { diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalProjectsViewImpl.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalProjectsViewImpl.java index dd60c3225fa7..163c20b982c2 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalProjectsViewImpl.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalProjectsViewImpl.java @@ -41,7 +41,6 @@ import com.intellij.openapi.externalSystem.util.ExternalSystemUiUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.SimpleToolWindowPanel; import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; @@ -524,16 +523,7 @@ public class ExternalProjectsViewImpl extends SimpleToolWindowPanel implements D } private void restoreTreeState() { - if (myState.treeState != null) { - TreeState treeState = new TreeState(); - try { - treeState.readExternal(myState.treeState); - treeState.applyTo(myTree); - } - catch (InvalidDataException e) { - LOG.info(e); - } - } + TreeState.createFrom(myState.treeState).applyTo(myTree); } private List getSelectedNodes(Class aClass) { diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java index ea641a23c22e..83e5637262ec 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java @@ -439,9 +439,10 @@ public abstract class AbstractProjectViewPane implements DataProvider, Disposabl List subPanes = element.getChildren(ELEMENT_SUBPANE); for (Element subPane : subPanes) { String subId = subPane.getAttributeValue(ATTRIBUTE_SUBID); - TreeState treeState = new TreeState(); - treeState.readExternal(subPane); - if (!treeState.isEmpty()) myReadTreeState.put(subId, treeState); + TreeState treeState = TreeState.createFrom(subPane); + if (!treeState.isEmpty()) { + myReadTreeState.put(subId, treeState); + } } } @@ -461,13 +462,17 @@ public abstract class AbstractProjectViewPane implements DataProvider, Disposabl protected void saveExpandedPaths() { if (myTree != null) { TreeState treeState = TreeState.createOn(myTree); - if (!treeState.isEmpty()) myReadTreeState.put(getSubId(), treeState); + if (!treeState.isEmpty()) { + myReadTreeState.put(getSubId(), treeState); + } } } public final void restoreExpandedPaths(){ TreeState treeState = myReadTreeState.get(getSubId()); - if (treeState != null && !treeState.isEmpty()) treeState.applyTo(myTree); + if (treeState != null && !treeState.isEmpty()) { + treeState.applyTo(myTree); + } } public void installComparator() { diff --git a/platform/lang-impl/src/com/intellij/ide/scopeView/ScopeTreeViewPanel.java b/platform/lang-impl/src/com/intellij/ide/scopeView/ScopeTreeViewPanel.java index 91265159efaf..192989dd0e18 100644 --- a/platform/lang-impl/src/com/intellij/ide/scopeView/ScopeTreeViewPanel.java +++ b/platform/lang-impl/src/com/intellij/ide/scopeView/ScopeTreeViewPanel.java @@ -346,7 +346,7 @@ public class ScopeTreeViewPanel extends JPanel implements Disposable { myBuilder.setTree(myTree); myTree.getEmptyText().setText("Loading..."); myActionCallback = new ActionCallback(); - myTree.putClientProperty(TreeState.CALLBACK, new WeakReference<>(myActionCallback)); + UIUtil.putClientProperty(myTree, TreeState.CALLBACK, new WeakReference<>(myActionCallback)); myTree.setModel(myBuilder.build(myProject, true, () -> { myTree.setPaintBusy(false); myTree.getEmptyText().setText(UIBundle.message("message.nothingToShow")); diff --git a/platform/platform-api/src/com/intellij/ide/util/treeView/TreeState.java b/platform/platform-api/src/com/intellij/ide/util/treeView/TreeState.java index aadc765b3edf..c589c6607dc7 100644 --- a/platform/platform-api/src/com/intellij/ide/util/treeView/TreeState.java +++ b/platform/platform-api/src/com/intellij/ide/util/treeView/TreeState.java @@ -16,83 +16,80 @@ package com.intellij.ide.util.treeView; import com.intellij.navigation.NavigationItem; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.EmptyProgressIndicator; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.Progressive; import com.intellij.openapi.util.*; +import com.intellij.openapi.util.text.StringHash; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.reference.SoftReference; +import com.intellij.util.ExceptionUtil; +import com.intellij.util.ObjectUtils; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.tree.TreeUtil; +import com.intellij.util.xmlb.XmlSerializer; +import com.intellij.util.xmlb.annotations.Attribute; +import com.intellij.util.xmlb.annotations.Tag; import org.jdom.Element; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.TreeNode; +import javax.swing.tree.TreeModel; import javax.swing.tree.TreePath; +import java.io.IOException; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; /** - * @see #createOn(javax.swing.JTree) - * @see #createOn(javax.swing.JTree, javax.swing.tree.DefaultMutableTreeNode) + * @see #createOn(JTree) + * @see #createOn(JTree, DefaultMutableTreeNode) * - * @see #applyTo(javax.swing.JTree) - * @see #applyTo(javax.swing.JTree, javax.swing.tree.DefaultMutableTreeNode) + * @see #applyTo(JTree) + * @see #applyTo(JTree, Object) */ public class TreeState implements JDOMExternalizable { - @NonNls private static final String PATH = "PATH"; - @NonNls private static final String SELECTED = "SELECTED"; - @NonNls private static final String PATH_ELEMENT = "PATH_ELEMENT"; - @NonNls private static final String USER_OBJECT = "USER_OBJECT"; - @NonNls public static final String CALLBACK = "Callback"; + private static final Logger LOG = Logger.getInstance(TreeState.class); + public static final Key> CALLBACK = Key.create("Callback"); + + private static final String EXPAND_TAG = "expand"; + private static final String SELECT_TAG = "select"; + private static final String PATH_TAG = "path"; + + @Tag("item") static class PathElement { - public String myItemId; - public String myItemType; + @Attribute("name") + public String id; + @Attribute("type") + public String type; + @Attribute("user") + public String userStr; - private final int myItemIndex; - private Object myUserObject; + Object userObject; + final int index; - public PathElement(final String itemId, final String itemType, final int itemIndex, Object userObject) { - myItemId = itemId; - myItemType = itemType; - - myItemIndex = itemIndex; - myUserObject = userObject; + /** @noinspection unused*/ + PathElement() { + this(null, null, -1, null); } - public PathElement() { - myItemIndex = -1; - myUserObject = null; + PathElement(String itemId, String itemType, int itemIndex, Object userObject) { + id = itemId; + type = itemType; + + index = itemIndex; + userStr = userObject instanceof String ? (String)userObject : null; + this.userObject = userObject; } @Override public String toString() { - return myItemId + ":" + myItemType; - } - - public boolean matchedWith(NodeDescriptor nodeDescriptor) { - return Comparing.equal(myItemId, getDescriptorKey(nodeDescriptor)) && - Comparing.equal(myItemType, getDescriptorType(nodeDescriptor)); - } - - public boolean matchedWithByObject(Object object) { - return myUserObject != null && myUserObject.equals(object); - } - - public void readExternal(Element element) throws InvalidDataException { - DefaultJDOMExternalizer.readExternal(this, element); - myUserObject = element.getAttributeValue(USER_OBJECT); - } - - public void writeExternal(Element element) throws WriteExternalException { - DefaultJDOMExternalizer.writeExternal(this, element); - if (myUserObject instanceof String){ - element.setAttribute(USER_OBJECT, (String)myUserObject); - } + return id + ": " + type; } } @@ -106,181 +103,124 @@ public class TreeState implements JDOMExternalizable { myScrollToSelection = true; } - public TreeState() { - this(new ArrayList<>(), new ArrayList<>()); - } - public boolean isEmpty() { return myExpandedPaths.isEmpty() && mySelectedPaths.isEmpty(); } @Override public void readExternal(Element element) throws InvalidDataException { - readExternal(element, myExpandedPaths, PATH); - readExternal(element, mySelectedPaths, SELECTED); + readExternal(element, myExpandedPaths, EXPAND_TAG); + readExternal(element, mySelectedPaths, SELECT_TAG); } - private static void readExternal(Element element, List> list, String name) throws InvalidDataException { + private static void readExternal(Element root, List> list, String name) throws InvalidDataException { list.clear(); - final List paths = element.getChildren(name); - for (final Object path : paths) { - Element xmlPathElement = (Element)path; - list.add(readPath(xmlPathElement)); + for (Element element : root.getChildren(name)) { + for (Element child : element.getChildren(PATH_TAG)) { + PathElement[] path = XmlSerializer.deserialize(child, PathElement[].class); + list.add(ContainerUtil.immutableList(path)); + } } } - private static List readPath(final Element xmlPathElement) throws InvalidDataException { - final ArrayList result = new ArrayList<>(); - final List elements = xmlPathElement.getChildren(PATH_ELEMENT); - for (final Object element : elements) { - Element xmlPathElementElement = (Element)element; - final PathElement pathElement = new PathElement(); - pathElement.readExternal(xmlPathElementElement); - result.add(pathElement); - } - return result; - } - + @NotNull public static TreeState createOn(JTree tree, final DefaultMutableTreeNode treeNode) { - return new TreeState(createExpandedPaths(tree, treeNode), createSelectedPaths(tree, treeNode)); + return new TreeState(createPaths(tree, TreeUtil.collectExpandedPaths(tree, new TreePath(treeNode.getPath()))), + createPaths(tree, TreeUtil.collectSelectedPaths(tree, new TreePath(treeNode.getPath())))); } + @NotNull public static TreeState createOn(@NotNull JTree tree) { - return new TreeState(createPaths(tree), new ArrayList<>()); + return new TreeState(createPaths(tree, TreeUtil.collectExpandedPaths(tree)), new ArrayList<>()); + } + + @NotNull + public static TreeState createFrom(@Nullable Element element) { + TreeState state = new TreeState(new ArrayList<>(), new ArrayList<>()); + try { + if (element != null) { + state.readExternal(element); + } + } + catch (InvalidDataException e) { + LOG.warn(e); + } + return state; } @Override public void writeExternal(Element element) throws WriteExternalException { - writeExternal(element, myExpandedPaths, PATH); - writeExternal(element, mySelectedPaths, SELECTED); + writeExternal(element, myExpandedPaths, EXPAND_TAG); + writeExternal(element, mySelectedPaths, SELECT_TAG); } private static void writeExternal(Element element, List> list, String name) throws WriteExternalException { + Element root = new Element(name); for (List path : list) { - final Element pathElement = new Element(name); - writeExternal(pathElement, path); - element.addContent(pathElement); + Element e = XmlSerializer.serialize(path.toArray()); + e.setName(PATH_TAG); + root.addContent(e); } - } - - private static void writeExternal(final Element pathXmlElement, final List path) throws WriteExternalException { - for (final PathElement aPath : path) { - final Element pathXmlElementElement = new Element(PATH_ELEMENT); - aPath.writeExternal(pathXmlElementElement); - pathXmlElement.addContent(pathXmlElementElement); - } - } - - private static List> createPaths(final JTree tree) { - final List expandedPaths = TreeUtil.collectExpandedPaths(tree); - return createPaths(tree, expandedPaths); - } - - private static List> createExpandedPaths(JTree tree, final DefaultMutableTreeNode treeNode) { - final List expandedPaths = TreeUtil.collectExpandedPaths(tree, new TreePath(treeNode.getPath())); - return createPaths(tree, expandedPaths); - } - - private static List> createSelectedPaths(JTree tree, final DefaultMutableTreeNode treeNode) { - final List selectedPaths - = TreeUtil.collectSelectedPaths(tree, new TreePath(treeNode.getPath())); - return createPaths(tree, selectedPaths); + element.addContent(root); } private static List> createPaths(JTree tree, List paths) { ArrayList> result = new ArrayList<>(); for (TreePath path : paths) { if (tree.isRootVisible() || path.getPathCount() > 1) { - List list = createPath(path); - if (list != null) result.add(list); + ContainerUtil.addIfNotNull(result, createPath(tree.getModel(), path)); } } return result; } - private static List createPath(final TreePath treePath) { - final ArrayList result = new ArrayList<>(); + @NotNull + private static List createPath(@NotNull TreeModel model, @NotNull TreePath treePath) { + ArrayList result = new ArrayList<>(); + Object prev = null; for (int i = 0; i < treePath.getPathCount(); i++) { - final Object pathComponent = treePath.getPathComponent(i); - if (pathComponent instanceof DefaultMutableTreeNode) { - final DefaultMutableTreeNode node = (DefaultMutableTreeNode)pathComponent; - final TreeNode parent = node.getParent(); - - final int childIndex = parent != null ? parent.getIndex(node) : 0; - final Object userObject = node.getUserObject(); - if (userObject instanceof NodeDescriptor) { - final NodeDescriptor nodeDescriptor = (NodeDescriptor)userObject; - //nodeDescriptor.update(); - result.add(new PathElement(getDescriptorKey(nodeDescriptor), getDescriptorType(nodeDescriptor), childIndex, nodeDescriptor)); - } - else { - result.add(new PathElement("", "", childIndex, userObject)); - } - } - else { - return null; - } + Object cur = treePath.getPathComponent(i); + Object userObject = TreeUtil.getUserObject(cur); + int childIndex = prev == null ? 0 : model.getIndexOfChild(prev, cur); + PathElement pe = new PathElement(calcId(userObject), calcType(userObject), childIndex, userObject); + result.add(pe); + prev = cur; } return result; } - private static String getDescriptorKey(final NodeDescriptor nodeDescriptor) { - if (nodeDescriptor instanceof AbstractTreeNode) { - Object value; - if (nodeDescriptor instanceof NodeDescriptorProvidingKey) { - value = ((NodeDescriptorProvidingKey)nodeDescriptor).getKey(); + private static String calcId(Object userObject) { + Object value = + userObject instanceof NodeDescriptorProvidingKey ? ((NodeDescriptorProvidingKey)userObject).getKey() : + userObject instanceof AbstractTreeNode ? ((AbstractTreeNode)userObject).getValue() : + userObject; + if (value instanceof NavigationItem) { + try { + String name = ((NavigationItem)value).getName(); + return name != null ? name : value.toString(); } - else { - value = ((AbstractTreeNode)nodeDescriptor).getValue(); - } - - if (value instanceof NavigationItem) { - try { - final String name = ((NavigationItem)value).getName(); - return name != null ? name : value.toString(); - } - catch (Exception e) { - //ignore for invalid psi element - } + catch (Exception ignored) { } } - return nodeDescriptor.toString(); + return userObject.toString(); } - private static String getDescriptorType(final NodeDescriptor nodeDescriptor) { - return nodeDescriptor.getClass().getName(); + private static String calcType(Object userObject) { + String name = userObject.getClass().getName(); + return Integer.toHexString(StringHash.murmur(name, 31)) + ":" + StringUtil.getShortName(name); } - public void applyTo(JTree tree) { - applyTo(tree, (DefaultMutableTreeNode)tree.getModel().getRoot()); + public void applyTo(@NotNull JTree tree) { + applyTo(tree, tree.getModel().getRoot()); } - private void applyExpanded(TreeFacade tree, Object root, ProgressIndicator indicator) { - indicator.checkCanceled(); - - if (!(root instanceof DefaultMutableTreeNode)) { - return; - } - final DefaultMutableTreeNode nodeRoot = (DefaultMutableTreeNode)root; - final TreeNode[] nodePath = nodeRoot.getPath(); - if (nodePath.length > 0) { - for (final List path : myExpandedPaths) { - applyTo(nodePath.length - 1,path, root, tree, indicator); - } - } - } - - public void applyTo(final JTree tree, final DefaultMutableTreeNode node) { - final TreeFacade facade = getFacade(tree); + public void applyTo(@NotNull JTree tree, @Nullable Object root) { + if (root == null) return; + TreeFacade facade = TreeFacade.getFacade(tree); ActionCallback callback = facade.getInitialized().doWhenDone(new TreeRunnable("TreeState.applyTo: on done facade init") { @Override public void perform() { - facade.batch(new Progressive() { - @Override - public void run(@NotNull ProgressIndicator indicator) { - applyExpanded(facade, node, indicator); - } - }); + facade.batch(indicator -> applyExpandedTo(facade, new TreePath(root), indicator)); } }); if (tree.getSelectionCount() == 0) { @@ -288,158 +228,134 @@ public class TreeState implements JDOMExternalizable { @Override public void perform() { if (tree.getSelectionCount() == 0) { - applySelected(tree, node); + applySelectedTo(tree); } } }); } } - private void applySelected(final JTree tree, final DefaultMutableTreeNode node) { - TreeUtil.unselect(tree, node); - List selectionPaths = new ArrayList<>(); - for (List pathElements : mySelectedPaths) { - applySelectedTo(pathElements, tree.getModel().getRoot(), tree, selectionPaths, myScrollToSelection); - } + private void applyExpandedTo(@NotNull TreeFacade tree, @NotNull TreePath rootPath, @NotNull ProgressIndicator indicator) { + indicator.checkCanceled(); + if (rootPath.getPathCount() <= 0) return; - if (selectionPaths.size() > 1) { - for (TreePath path : selectionPaths) { - tree.addSelectionPath(path); + for (List path : myExpandedPaths) { + if (path.isEmpty()) continue; + int index = rootPath.getPathCount() - 1; + if (!pathMatches(path.get(index), rootPath.getPathComponent(index))) continue; + expandImpl(0, path, rootPath, tree, indicator); + } + } + + private void applySelectedTo(@NotNull JTree tree) { + List selection = new ArrayList<>(); + for (List path : mySelectedPaths) { + TreeModel model = tree.getModel(); + TreePath treePath = new TreePath(model.getRoot()); + for (int i = 1; treePath != null && i < path.size(); i++) { + treePath = findMatchedChild(model, treePath, path.get(i)); } + ContainerUtil.addIfNotNull(selection, treePath); + } + if (selection.isEmpty()) return; + for (TreePath treePath : selection) { + tree.setSelectionPath(treePath); + } + if (myScrollToSelection) { + TreeUtil.showRowCentered(tree, tree.getRowForPath(selection.get(0)), true, true); } } @Nullable - private static DefaultMutableTreeNode findMatchedChild(DefaultMutableTreeNode parent, PathElement pathElement) { - - for (int j = 0; j < parent.getChildCount(); j++) { - final TreeNode child = parent.getChildAt(j); - if (!(child instanceof DefaultMutableTreeNode)) continue; - final DefaultMutableTreeNode childNode = (DefaultMutableTreeNode)child; - final Object userObject = childNode.getUserObject(); - if (pathElement.matchedWithByObject(userObject)) return childNode; + private static TreePath findMatchedChild(@NotNull TreeModel model, @NotNull TreePath treePath, @NotNull PathElement pathElement) { + Object parent = treePath.getLastPathComponent(); + int childCount = model.getChildCount(parent); + for (int j = 0; j < childCount; j++) { + Object child = model.getChild(parent, j); + if (pathMatches(pathElement, child)) { + return treePath.pathByAddingChild(child); + } } - for (int j = 0; j < parent.getChildCount(); j++) { - final TreeNode child = parent.getChildAt(j); - if (!(child instanceof DefaultMutableTreeNode)) continue; - final DefaultMutableTreeNode childNode = (DefaultMutableTreeNode)child; - final Object userObject = childNode.getUserObject(); - if (!(userObject instanceof NodeDescriptor)) continue; - final NodeDescriptor nodeDescriptor = (NodeDescriptor)userObject; - if (pathElement.matchedWith(nodeDescriptor)) return childNode; - } - - if (parent.getChildCount() > 0) { - int index = pathElement.myItemIndex; - if (index >= parent.getChildCount()) { - index = parent.getChildCount()-1; - } - index = Math.max(0, index); - final TreeNode child = parent.getChildAt(index); - if (child instanceof DefaultMutableTreeNode) { - return (DefaultMutableTreeNode) child; - } + if (childCount > 0) { + int index = Math.max(0, Math.min(pathElement.index, childCount - 1)); + Object child = model.getChild(parent, index); + return treePath.pathByAddingChild(child); } return null; } - private static boolean applyTo(final int positionInPath, - final List path, - final Object root, - final TreeFacade tree, - final ProgressIndicator indicator) { - if (!(root instanceof DefaultMutableTreeNode)) return false; + private static boolean pathMatches(@NotNull PathElement pe, Object child) { + Object userObject = TreeUtil.getUserObject(child); + if (pe.userObject != null && pe.userObject.equals(userObject)) return true; + return Comparing.equal(pe.id, calcId(userObject)) && + Comparing.equal(pe.type, calcType(userObject)); + } - final DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)root; - - final Object userObject = treeNode.getUserObject(); - final PathElement pathElement = path.get(positionInPath); - - if (userObject instanceof NodeDescriptor) { - if (!pathElement.matchedWith((NodeDescriptor)userObject)) return false; - } - else { - if (!pathElement.matchedWithByObject(userObject)) return false; - } - - tree.expand(treeNode).doWhenDone(new TreeRunnable("TreeState.applyTo") { + private static void expandImpl(int positionInPath, + List path, + TreePath treePath, + TreeFacade tree, + ProgressIndicator indicator) { + tree.expand(treePath).doWhenDone(new TreeRunnable("TreeState.applyTo") { @Override public void perform() { indicator.checkCanceled(); - if (positionInPath == path.size() - 1) { - return; - } + PathElement next = positionInPath == path.size() - 1 ? null : path.get(positionInPath + 1); + if (next == null) return; - for (int j = 0; j < treeNode.getChildCount(); j++) { - final TreeNode child = treeNode.getChildAt(j); - final boolean resultFromChild = applyTo(positionInPath + 1, path, child, tree, indicator); - if (resultFromChild) { + Object parent = treePath.getLastPathComponent(); + TreeModel model = tree.tree.getModel(); + int childCount = model.getChildCount(parent); + for (int j = 0; j < childCount; j++) { + Object child = tree.tree.getModel().getChild(parent, j); + if (pathMatches(next, child)) { + expandImpl(positionInPath + 1, path, treePath.pathByAddingChild(child), tree, indicator); break; } } } }); - - - return true; } - private static void applySelectedTo(final List path, - Object root, - JTree tree, - final List outSelectionPaths, final boolean scrollToSelection) { + static abstract class TreeFacade { - for (int i = 1; i < path.size(); i++) { - if (!(root instanceof DefaultMutableTreeNode)) return; + final JTree tree; - root = findMatchedChild((DefaultMutableTreeNode)root, path.get(i)); + TreeFacade(@NotNull JTree tree) {this.tree = tree;} + + abstract ActionCallback getInitialized(); + + abstract ActionCallback expand(TreePath treePath); + + abstract void batch(Progressive progressive); + + static TreeFacade getFacade(JTree tree) { + AbstractTreeBuilder builder = AbstractTreeBuilder.getBuilderFor(tree); + return builder != null ? new BuilderFacade(builder) : new JTreeFacade(tree); } - if (!(root instanceof DefaultMutableTreeNode)) return; - - final TreePath pathInNewTree = new TreePath(((DefaultMutableTreeNode) root).getPath()); - if (scrollToSelection) { - TreeUtil.selectPath(tree, pathInNewTree); - } else { - tree.setSelectionPath(pathInNewTree); - } - outSelectionPaths.add(pathInNewTree); } - interface TreeFacade { - ActionCallback getInitialized(); - ActionCallback expand(DefaultMutableTreeNode node); - - void batch(Progressive progressive); - } - - private static TreeFacade getFacade(JTree tree) { - final AbstractTreeBuilder builder = AbstractTreeBuilder.getBuilderFor(tree); - return builder != null ? new BuilderFacade(builder) : new JTreeFacade(tree); - } - - public static class JTreeFacade implements TreeFacade { - - private final JTree myTree; + static class JTreeFacade extends TreeFacade { JTreeFacade(JTree tree) { - myTree = tree; + super(tree); } @Override - public ActionCallback expand(DefaultMutableTreeNode node) { - myTree.expandPath(new TreePath(node.getPath())); + public ActionCallback expand(@NotNull TreePath treePath) { + tree.expandPath(treePath); return ActionCallback.DONE; } @Override public ActionCallback getInitialized() { - final WeakReference ref = (WeakReference)myTree.getClientProperty(CALLBACK); - final ActionCallback callback = SoftReference.dereference(ref); + WeakReference ref = UIUtil.getClientProperty(tree, CALLBACK); + ActionCallback callback = SoftReference.dereference(ref); if (callback != null) return callback; return ActionCallback.DONE; } @@ -450,11 +366,12 @@ public class TreeState implements JDOMExternalizable { } } - static class BuilderFacade implements TreeFacade { + static class BuilderFacade extends TreeFacade { private final AbstractTreeBuilder myBuilder; BuilderFacade(AbstractTreeBuilder builder) { + super(ObjectUtils.notNull(builder.getTree())); myBuilder = builder; } @@ -469,16 +386,13 @@ public class TreeState implements JDOMExternalizable { } @Override - public ActionCallback expand(DefaultMutableTreeNode node) { - final Object userObject = node.getUserObject(); + public ActionCallback expand(TreePath treePath) { + Object userObject = TreeUtil.getUserObject(treePath.getLastPathComponent()); if (!(userObject instanceof NodeDescriptor)) return ActionCallback.REJECTED; NodeDescriptor desc = (NodeDescriptor)userObject; - - final Object element = myBuilder.getTreeStructureElement(desc); - - final ActionCallback result = new ActionCallback(); - + Object element = myBuilder.getTreeStructureElement(desc); + ActionCallback result = new ActionCallback(); myBuilder.expand(element, result.createSetDoneRunnable()); return result; @@ -491,36 +405,16 @@ public class TreeState implements JDOMExternalizable { @Override public String toString() { - StringBuilder sb = new StringBuilder("TreeState(").append(myScrollToSelection).append(")"); - append(sb, " expanded:", myExpandedPaths); - append(sb, " selected:", mySelectedPaths); - return sb.toString(); - } - - private static void append(StringBuilder sb, String prefix, Object object) { - if (prefix != null) { - sb.append(prefix); + Element st = new Element("TreeState"); + String content; + try { + writeExternal(st); + content = JDOMUtil.writeChildren(st, "\n"); } - if (object instanceof List) { - appendList(sb, (List)object); - } - else { - sb.append(object); - } - } - - private static void appendList(StringBuilder sb, List list) { - if (list.isEmpty()) { - sb.append("{}"); - } - else { - String prefix = "{"; - for (Object object : list) { - append(sb, prefix, object); - prefix = ", "; - } - sb.append("}"); + catch (IOException e) { + content = ExceptionUtil.getThrowableText(e); } + return "TreeState(" + myScrollToSelection + ")\n" + content; } } diff --git a/platform/platform-api/src/com/intellij/ui/treeStructure/Tree.java b/platform/platform-api/src/com/intellij/ui/treeStructure/Tree.java index b59ff3f167ea..ff28a5105166 100644 --- a/platform/platform-api/src/com/intellij/ui/treeStructure/Tree.java +++ b/platform/platform-api/src/com/intellij/ui/treeStructure/Tree.java @@ -25,6 +25,7 @@ import com.intellij.openapi.util.SystemInfo; import com.intellij.ui.*; import com.intellij.util.ReflectionUtil; import com.intellij.util.ui.*; +import com.intellij.util.ui.tree.TreeUtil; import com.intellij.util.ui.tree.WideSelectionTreeUI; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -338,7 +339,7 @@ public class Tree extends JTree implements ComponentWithEmptyText, ComponentWith component = pathObjects[pathObjects.length - 2]; } - Color color = getFileColorFor((DefaultMutableTreeNode)component); + Color color = getFileColorFor(TreeUtil.getUserObject(component)); if (color != null) { g.setColor(color); g.fillRect(0, bounds.y, getWidth(), bounds.height); diff --git a/platform/platform-api/src/com/intellij/util/ui/tree/TreeUtil.java b/platform/platform-api/src/com/intellij/util/ui/tree/TreeUtil.java index 0d82428fb81e..38ed6af8ab07 100644 --- a/platform/platform-api/src/com/intellij/util/ui/tree/TreeUtil.java +++ b/platform/platform-api/src/com/intellij/util/ui/tree/TreeUtil.java @@ -722,7 +722,7 @@ public final class TreeUtil { } } - public static void collapseAll(@NotNull final JTree tree, final int keepSelectionLevel) { + public static void collapseAll(@NotNull JTree tree, final int keepSelectionLevel) { final TreePath leadSelectionPath = tree.getLeadSelectionPath(); // Collapse all int row = tree.getRowCount() - 1; @@ -730,8 +730,10 @@ public final class TreeUtil { tree.collapseRow(row); row--; } - final DefaultMutableTreeNode root = (DefaultMutableTreeNode)tree.getModel().getRoot(); - tree.expandPath(new TreePath(root)); + Object root = tree.getModel().getRoot(); + if (root != null) { + tree.expandPath(new TreePath(root)); + } if (leadSelectionPath != null) { final Object[] path = leadSelectionPath.getPath(); final Object[] pathToSelect = new Object[path.length > keepSelectionLevel && keepSelectionLevel >= 0 ? keepSelectionLevel : path.length]; @@ -883,14 +885,14 @@ public final class TreeUtil { return result; } - public static void unselect(@NotNull JTree tree, @NotNull final DefaultMutableTreeNode node) { - final TreePath rootPath = new TreePath(node.getPath()); - final TreePath[] selectionPaths = tree.getSelectionPaths(); - if (selectionPaths != null) { - for (TreePath selectionPath : selectionPaths) { - if (selectionPath.getPathCount() > rootPath.getPathCount() && rootPath.isDescendant(selectionPath)) { - tree.removeSelectionPath(selectionPath); - } + public static void unselectPath(@NotNull JTree tree, @Nullable TreePath path) { + if (path == null) return; + TreePath[] selectionPaths = tree.getSelectionPaths(); + if (selectionPaths == null) return; + + for (TreePath selectionPath : selectionPaths) { + if (selectionPath.getPathCount() > path.getPathCount() && path.isDescendant(selectionPath)) { + tree.removeSelectionPath(selectionPath); } } } @@ -984,6 +986,11 @@ public final class TreeUtil { } } + @Nullable + public static Object getUserObject(@Nullable Object node) { + return node instanceof DefaultMutableTreeNode ? ((DefaultMutableTreeNode)node).getUserObject() : node; + } + @FunctionalInterface public interface Traverse{ boolean accept(Object node); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/tree/BreakpointItemsTreeController.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/tree/BreakpointItemsTreeController.java index 86ed994d86e3..f230cc6207e8 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/tree/BreakpointItemsTreeController.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/tree/BreakpointItemsTreeController.java @@ -28,7 +28,6 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; -import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; @@ -229,11 +228,11 @@ public class BreakpointItemsTreeController implements BreakpointsCheckboxTree.De if (paths == null) return; final List breakpoints = getSelectedBreakpoints(true); for (TreePath path : paths) { - final Object node = path.getLastPathComponent(); + Object node = path.getLastPathComponent(); if (node instanceof BreakpointItemNode) { final BreakpointItem item = ((BreakpointItemNode)node).getBreakpointItem(); if (!item.allowedToRemove()) { - TreeUtil.unselect(myTreeView, (DefaultMutableTreeNode)node); + TreeUtil.unselectPath(myTreeView, path); breakpoints.remove(item); } } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigator.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigator.java index a32e4591f051..ca812a3633f3 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigator.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigator.java @@ -26,7 +26,6 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.*; import com.intellij.openapi.project.DumbAwareRunnable; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.wm.ToolWindowAnchor; @@ -359,16 +358,7 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen r.run(); if (shouldCreate) { - if (myState.treeState != null) { - TreeState treeState = new TreeState(); - try { - treeState.readExternal(myState.treeState); - treeState.applyTo(myTree); - } - catch (InvalidDataException e) { - MavenLog.LOG.info(e); - } - } + TreeState.createFrom(myState.treeState).applyTo(myTree); } }); } diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/FileAssociationsConfigurable.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/FileAssociationsConfigurable.java index 4e3ab17ac1aa..11843f2bad01 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/FileAssociationsConfigurable.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/FileAssociationsConfigurable.java @@ -110,7 +110,7 @@ public class FileAssociationsConfigurable implements SearchableConfigurable, Con @Override public TreeState getState() { - return state != null ? state : new TreeState(); + return state != null ? state : TreeState.createFrom(null); } @Override