mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
TreeState: cleanup & treePath instead of DMT nodes
This commit is contained in:
+1
-9
@@ -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) {
|
||||
|
||||
+1
-11
@@ -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 <T extends ExternalSystemNode> List<T> getSelectedNodes(Class<T> aClass) {
|
||||
|
||||
+10
-5
@@ -439,9 +439,10 @@ public abstract class AbstractProjectViewPane implements DataProvider, Disposabl
|
||||
List<Element> 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() {
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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<WeakReference<ActionCallback>> 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<PathElement>> list, String name) throws InvalidDataException {
|
||||
private static void readExternal(Element root, List<List<PathElement>> 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<PathElement> readPath(final Element xmlPathElement) throws InvalidDataException {
|
||||
final ArrayList<PathElement> 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<PathElement>> list, String name) throws WriteExternalException {
|
||||
Element root = new Element(name);
|
||||
for (List<PathElement> 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<PathElement> path) throws WriteExternalException {
|
||||
for (final PathElement aPath : path) {
|
||||
final Element pathXmlElementElement = new Element(PATH_ELEMENT);
|
||||
aPath.writeExternal(pathXmlElementElement);
|
||||
pathXmlElement.addContent(pathXmlElementElement);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<List<PathElement>> createPaths(final JTree tree) {
|
||||
final List<TreePath> expandedPaths = TreeUtil.collectExpandedPaths(tree);
|
||||
return createPaths(tree, expandedPaths);
|
||||
}
|
||||
|
||||
private static List<List<PathElement>> createExpandedPaths(JTree tree, final DefaultMutableTreeNode treeNode) {
|
||||
final List<TreePath> expandedPaths = TreeUtil.collectExpandedPaths(tree, new TreePath(treeNode.getPath()));
|
||||
return createPaths(tree, expandedPaths);
|
||||
}
|
||||
|
||||
private static List<List<PathElement>> createSelectedPaths(JTree tree, final DefaultMutableTreeNode treeNode) {
|
||||
final List<TreePath> selectedPaths
|
||||
= TreeUtil.collectSelectedPaths(tree, new TreePath(treeNode.getPath()));
|
||||
return createPaths(tree, selectedPaths);
|
||||
element.addContent(root);
|
||||
}
|
||||
|
||||
private static List<List<PathElement>> createPaths(JTree tree, List<TreePath> paths) {
|
||||
ArrayList<List<PathElement>> result = new ArrayList<>();
|
||||
for (TreePath path : paths) {
|
||||
if (tree.isRootVisible() || path.getPathCount() > 1) {
|
||||
List<PathElement> list = createPath(path);
|
||||
if (list != null) result.add(list);
|
||||
ContainerUtil.addIfNotNull(result, createPath(tree.getModel(), path));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<PathElement> createPath(final TreePath treePath) {
|
||||
final ArrayList<PathElement> result = new ArrayList<>();
|
||||
@NotNull
|
||||
private static List<PathElement> createPath(@NotNull TreeModel model, @NotNull TreePath treePath) {
|
||||
ArrayList<PathElement> 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<PathElement> 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<TreePath> selectionPaths = new ArrayList<>();
|
||||
for (List<PathElement> 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<PathElement> 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<TreePath> selection = new ArrayList<>();
|
||||
for (List<PathElement> 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<PathElement> 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<PathElement> 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<PathElement> path,
|
||||
Object root,
|
||||
JTree tree,
|
||||
final List<TreePath> 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<ActionCallback> ref = (WeakReference<ActionCallback>)myTree.getClientProperty(CALLBACK);
|
||||
final ActionCallback callback = SoftReference.dereference(ref);
|
||||
WeakReference<ActionCallback> 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
+2
-3
@@ -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<BreakpointItem> 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);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-11
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user