diff --git a/openapi/src/com/intellij/ide/util/treeView/TreeState.java b/openapi/src/com/intellij/ide/util/treeView/TreeState.java new file mode 100644 index 000000000000..5eacef0f6a2c --- /dev/null +++ b/openapi/src/com/intellij/ide/util/treeView/TreeState.java @@ -0,0 +1,178 @@ +package com.intellij.ide.util.treeView; + +import com.intellij.openapi.util.*; +import com.intellij.util.ui.tree.TreeUtil; +import org.jdom.Element; + +import javax.swing.*; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class TreeState implements JDOMExternalizable{ +private static final String PATH = "PATH"; +private static final String PATH_ELEMENT = "PATH_ELEMENT"; + +static class PathElement implements JDOMExternalizable{ + public String myItemId; + public String myItemType; + + public PathElement(final String itemId, final String itemType) { + myItemId = itemId; + myItemType = itemType; + } + + public PathElement() { + } + + public boolean matchedWith(NodeDescriptor nodeDescriptor) { + return Comparing.equal(myItemId, nodeDescriptor.toString()) && + Comparing.equal(myItemType, nodeDescriptor.getClass().getName()); + } + + public void readExternal(Element element) throws InvalidDataException { + DefaultJDOMExternalizer.readExternal(this, element); + } + + public void writeExternal(Element element) throws WriteExternalException { + DefaultJDOMExternalizer.writeExternal(this, element); + } +} + +private final List> myPaths; + +private TreeState(List> paths) { + myPaths = paths; +} + +public TreeState() { + myPaths = new ArrayList>(); +} + +public void readExternal(Element element) throws InvalidDataException { + myPaths.clear(); + final List paths = element.getChildren(PATH); + for (Iterator iterator = paths.iterator(); iterator.hasNext();) { + Element xmlPathElement = (Element)iterator.next(); + myPaths.add(readPath(xmlPathElement)); + } +} + +private List readPath(final Element xmlPathElement) throws InvalidDataException { + final ArrayList result = new ArrayList(); + final List elements = xmlPathElement.getChildren(PATH_ELEMENT); + for (Iterator iterator = elements.iterator(); iterator.hasNext();) { + Element xmlPathElementElement = (Element)iterator.next(); + final PathElement pathElement = new PathElement(); + pathElement.readExternal(xmlPathElementElement); + result.add(pathElement); + } + return result; +} + +public void writeExternal(Element element) throws WriteExternalException { + for (Iterator> iterator = myPaths.iterator(); iterator.hasNext();) { + List path = iterator.next(); + final Element pathElement = new Element(PATH); + writeExternal(pathElement, path); + element.addContent(pathElement); + } +} + +private void writeExternal(final Element pathXmlElement, final List path) throws WriteExternalException { + for (Iterator iterator = path.iterator(); iterator.hasNext();) { + final Element pathXmlElementElement = new Element(PATH_ELEMENT); + PathElement pathElement = iterator.next(); + pathElement.writeExternal(pathXmlElementElement); + pathXmlElement.addContent(pathXmlElementElement); + } +} + +public static TreeState createOn(JTree tree) { + return new TreeState(createPaths(tree)); +} + +private static List> createPaths(final JTree tree) { + final ArrayList> result = new ArrayList>(); + final ArrayList expandedPaths = TreeUtil.collectExpandedPaths(tree); + for (Iterator iterator = expandedPaths.iterator(); iterator.hasNext();) { + final List path = createPath(iterator.next()); + if (path != null) { + result.add(path); + } + } + return result; +} + +private static List createPath(final TreePath treePath) { + final ArrayList result = new ArrayList(); + for (int i = 0; i < treePath.getPathCount(); i++) { + final Object pathComponent = treePath.getPathComponent(i); + if (pathComponent instanceof DefaultMutableTreeNode) { + final Object userObject = ((DefaultMutableTreeNode)pathComponent).getUserObject(); + if (userObject instanceof NodeDescriptor) { + final NodeDescriptor nodeDescriptor = ((NodeDescriptor)userObject); + nodeDescriptor.update(); + final String key = nodeDescriptor.toString(); + final String type = nodeDescriptor.getClass().getName(); + result.add(new PathElement(key, type)); + } else { + return null; + } + } else { + return null; + } + } + return result; +} + +public void applyTo(JTree tree) { + for (Iterator> iterator = myPaths.iterator(); iterator.hasNext();) { + applyTo(iterator.next(), tree); + } +} + +private void applyTo(final List path, final JTree tree) { + applyTo(0, path, tree.getModel().getRoot(), tree); +} + +private boolean applyTo(final int positionInPath, final List path, final Object root, JTree tree) { + if (!(root instanceof DefaultMutableTreeNode)) return false; + + final DefaultMutableTreeNode treeNode = ((DefaultMutableTreeNode)root); + + final Object userObject = treeNode.getUserObject(); + + if (!(userObject instanceof NodeDescriptor)) return false; + + final NodeDescriptor nodeDescriptor = ((NodeDescriptor)userObject); + + final PathElement pathElement = path.get(positionInPath); + + if (!pathElement.matchedWith(nodeDescriptor)) return false; + + final TreePath currentPath = new TreePath(treeNode.getPath()); + + if (!tree.isExpanded(currentPath)) { + tree.expandPath(currentPath); + } + + if (positionInPath == path.size() - 1) { + return true; + } + + for (int j = 0; j < treeNode.getChildCount(); j++) { + final TreeNode child = treeNode.getChildAt(j); + final boolean resultFromChild = applyTo(positionInPath + 1, path, child, tree); + if (resultFromChild) { + break; + } + } + + return true; +} +} + diff --git a/source/com/intellij/ide/projectView/impl/AbstractProjectViewPSIPane.java b/source/com/intellij/ide/projectView/impl/AbstractProjectViewPSIPane.java index cbefa984e095..ad4c93008620 100644 --- a/source/com/intellij/ide/projectView/impl/AbstractProjectViewPSIPane.java +++ b/source/com/intellij/ide/projectView/impl/AbstractProjectViewPSIPane.java @@ -19,7 +19,6 @@ import com.intellij.openapi.ide.CopyPasteManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.startup.StartupManager; -import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.Navigatable; import com.intellij.ui.AutoScrollToSourceHandler; @@ -29,7 +28,6 @@ import com.intellij.ui.TreeToolTipHandler; import com.intellij.util.EditSourceOnDoubleClickHandler; import com.intellij.util.ui.Tree; import com.intellij.util.ui.tree.TreeUtil; -import org.jdom.Element; import javax.swing.*; import javax.swing.event.TreeModelEvent; @@ -50,9 +48,6 @@ public abstract class AbstractProjectViewPSIPane extends AbstractProjectViewPane protected AbstractProjectViewPSIPane(Project project) { super(project); - myExpandedElements.registerExpandedElementProvider(new ClassUrl(null, null)); - myExpandedElements.registerExpandedElementProvider(new ModuleUrl(null, null)); - myExpandedElements.registerExpandedElementProvider(new DirectoryUrl(null, null)); } protected final void initPSITree() { @@ -123,8 +118,6 @@ public abstract class AbstractProjectViewPSIPane extends AbstractProjectViewPane } } }); - - myExpandedElements.restoreExpandedElements(this, myProject); } public final void expand(Object[] path) { @@ -195,6 +188,7 @@ public abstract class AbstractProjectViewPSIPane extends AbstractProjectViewPane selectInManager.addTarget(createSelectInTarget()); initPSITree(); + restoreState(); } protected abstract ProjectViewSelectInTarget createSelectInTarget(); @@ -273,14 +267,4 @@ public abstract class AbstractProjectViewPSIPane extends AbstractProjectViewPane public JComponent getComponent() { return myComponent; } - - public void readExternal(Element viewElement) throws InvalidDataException { - myExpandedElements.readExternal(viewElement); - } - - public void writeExternal(Element viewElement) { - new ExpandedElements(getExpandedUrls()).writeExternal(viewElement); - } - - } \ No newline at end of file diff --git a/source/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java b/source/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java index 1eeddf540346..fa9e1c5046b0 100644 --- a/source/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java +++ b/source/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java @@ -8,11 +8,14 @@ import com.intellij.ide.projectView.impl.nodes.PackageElement; import com.intellij.ide.util.treeView.AbstractTreeNode; import com.intellij.ide.util.treeView.AbstractTreeStructure; import com.intellij.ide.util.treeView.NodeDescriptor; +import com.intellij.ide.util.treeView.TreeState; import com.intellij.openapi.actionSystem.DataConstants; import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.JDOMExternalizable; +import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiPackage; @@ -24,7 +27,8 @@ import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreePath; import java.util.ArrayList; import java.util.List; -import java.util.Enumeration; + +import org.jdom.Element; public abstract class AbstractProjectViewPane implements JDOMExternalizable, DataProvider { @@ -33,7 +37,7 @@ public abstract class AbstractProjectViewPane implements JDOMExternalizable, Dat protected ProjectViewTree myTree; protected AbstractTreeStructure myTreeStructure; protected BaseProjectTreeBuilder myTreeBuilder; - protected final ExpandedElements myExpandedElements = new ExpandedElements(); + private final TreeState myReadTreeState = new TreeState(); protected final void fireTreeChangeListener() { if (myTreeChangeListener != null) myTreeChangeListener.run(); @@ -70,48 +74,9 @@ public abstract class AbstractProjectViewPane implements JDOMExternalizable, Dat autoScrollFromSourceHandler.install(); } - protected final List getExpandedUrls(){ - if (myTree == null) { - // this is the case when invoked on partially initialized/disposed ProjectView - return new ArrayList(); - } - List urls = new ArrayList(); - DefaultMutableTreeNode rootNode = (DefaultMutableTreeNode)myTree.getModel().getRoot(); - Enumeration descendants = myTree.getExpandedDescendants(new TreePath(rootNode.getPath())); - if (descendants != null) { - NextDescendant: - while (descendants.hasMoreElements()) { - TreePath treePath = (TreePath)descendants.nextElement(); - // build up path from tree node elements - Object[] path = treePath.getPath(); - List elementsPath = new ArrayList(path.length); - for (int i = 0; i < path.length; i++) { - Object node = path[i]; - if (node instanceof DefaultMutableTreeNode) { - DefaultMutableTreeNode mutableNode = (DefaultMutableTreeNode)node; - if (mutableNode.getUserObject() instanceof AbstractTreeNode) { - AbstractTreeNode descriptor = (AbstractTreeNode)mutableNode.getUserObject(); - Object element = descriptor.getValue(); - if (element != null) { - elementsPath.add(element); - } else { - continue NextDescendant; - } - } - } - } - AbstractUrl url = myExpandedElements.createUrlByPath(elementsPath); - if (url != null) { - urls.add(url); - } - } - } - return urls; - } - - public void addToolbarActions(DefaultActionGroup actionGroup) { } + public Object getData(String dataId) { if (DataConstants.NAVIGATABLE.equals(dataId)){ TreePath[] paths = getSelectionPaths(); @@ -211,4 +176,16 @@ public abstract class AbstractProjectViewPane implements JDOMExternalizable, Dat public BaseProjectTreeBuilder getTreeBuilder() { return myTreeBuilder; } + + public void readExternal(Element element) throws InvalidDataException { + myReadTreeState.readExternal(element); + } + + public void writeExternal(Element element) throws WriteExternalException { + TreeState.createOn(myTree).writeExternal(element); + } + + public final void restoreState(){ + myReadTreeState.applyTo(myTree); + } } diff --git a/source/com/intellij/ide/projectView/impl/PackageViewPane.java b/source/com/intellij/ide/projectView/impl/PackageViewPane.java index 7d19b7dac686..ebaaa42b46fb 100644 --- a/source/com/intellij/ide/projectView/impl/PackageViewPane.java +++ b/source/com/intellij/ide/projectView/impl/PackageViewPane.java @@ -38,7 +38,6 @@ public final class PackageViewPane extends AbstractProjectViewPSIPane implements public PackageViewPane(Project project) { super(project); - myExpandedElements.registerExpandedElementProvider(new PackageUrl(null,null)); } public String getTitle() {