blob: c9a2ffdb0ae02c466482f360a0aad03d04feaf68 [file] [log] [blame]
package com.intellij.ide.util.treeView;
import com.intellij.openapi.util.Disposer;
import com.intellij.ui.treeStructure.Tree;
import org.jetbrains.annotations.NotNull;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import java.util.ArrayList;
public abstract class AbstractTreeBuilderCrashTest extends BaseTreeTestCase {
private AbstractTreeStructure myStructure;
private DefaultTreeModel myTreeModel;
private CachedNode myRoot;
protected AbstractTreeBuilderCrashTest(boolean yeild, boolean bg) {
super(yeild, bg);
}
public void testElementMovedButNodeIsStillInStructure() throws Exception {
assertNodeMove(new Runnable() {
@Override
public void run() {
getBuilder().addSubtreeToUpdateByElement(myRoot.getChild("folder1"));
getBuilder().addSubtreeToUpdateByElement(myRoot.getChild("folder2"));
}
});
}
public void testElementMovedButNodeIsStillInStructure2() throws Exception {
assertNodeMove(new Runnable() {
@Override
public void run() {
getBuilder().addSubtreeToUpdateByElement(myRoot.getChild("folder2"));
getBuilder().addSubtreeToUpdateByElement(myRoot.getChild("folder1"));
}
});
}
private void assertNodeMove(final Runnable update) throws Exception {
myRoot = new CachedNode("root");
final CachedNode folder1 = myRoot.addChild("folder1");
final CachedNode file = folder1.addChild("file");
final CachedNode folder2 = myRoot.addChild("folder2");
initTree(myRoot);
getBuilder().updateFromRoot();
getBuilder().select(file, null);
assertTree(
"-root\n" +
" -folder1\n" +
" [file]\n" +
" folder2\n");
folder1.myChildren.remove(file);
folder2.addChild("file");
update.run();
assertTree(
"-root\n" +
" folder1\n" +
" -folder2\n" +
" [file]\n");
}
public void testNewUniqueChilden() throws Exception {
final boolean[] changes = new boolean[1];
final Node root = new Node("root", null) {
@Override
Node[] getChildren() {
if (changes[0]) {
return new Node[] {new Node("node1", this, "node1id", "changedNode1") {
@Override
Node[] getChildren() {
return new Node[] {new Node("newNode11", this, "node11id"), new Node("node13", this, "node13id")};
}
}, new Node("node2", this, "node2id")};
} else {
return new Node[] {new Node("node1", this, "node1id") {
@Override
Node[] getChildren() {
return new Node[] {new Node("node11", this, "node11id"), new Node("node12", this, "node12id")};
}
}, new Node("node2", this, "node2id")};
}
}
};
initTree(root);
updateFromRoot();
assertTree("-root\n" +
" -node1\n" +
" node11\n" +
" node12\n" +
" node2\n");
collapsePath(new TreePath(myTreeModel.getRoot()));
getBuilder().expand(root, null);
assertTree("-root\n" +
" -node1\n" +
" node11\n" +
" node12\n" +
" node2\n");
updateFromRoot();
assertTree("-root\n" +
" -node1\n" +
" node11\n" +
" node12\n" +
" node2\n");
changes[0] = true;
updateFromRoot();
assertTree("-root\n" +
" -node1\n" +
" newNode11\n" +
" node13\n" +
" node2\n");
}
private void initTree(final Node root) throws Exception {
myStructure = new BaseStructure() {
@Override
public Object getRootElement() {
return root;
}
@Override
public Object[] doGetChildElements(final Object element) {
return ((Node)element).getChildren();
}
@Override
public Object getParentElement(final Object element) {
return ((Node)element).getParent();
}
@Override
@NotNull
public NodeDescriptor doCreateDescriptor(final Object element, final NodeDescriptor parentDescriptor) {
return (NodeDescriptor)element;
}
};
myTreeModel = new DefaultTreeModel(new DefaultMutableTreeNode());
myTree = new Tree(myTreeModel);
myTree.setRootVisible(false);
initBuilder(new BaseTreeBuilder(myTree, myTreeModel, myStructure, AlphaComparator.INSTANCE) {
@Override
protected boolean isAutoExpandNode(final NodeDescriptor nodeDescriptor) {
return true;
}
@Override
protected boolean isDisposeOnCollapsing(final NodeDescriptor nodeDescriptor) {
return false;
}
});
Disposer.register(getRootDisposable(), getBuilder());
showTree();
}
class Node extends NodeDescriptor {
Node myParent;
String myId;
String myEqualityString;
String myComment;
Node(String id, final Node parent) {
this(id, parent, id, null);
}
Node(String id, final Node parent, String equalityString) {
this(id, parent, equalityString, null);
}
Node(String id, final Node parent, String equalityString, String comment) {
super(null, parent);
myParent = parent;
myId = id;
myEqualityString = equalityString;
myComment = comment;
}
Node getParent() {
return myParent;
}
Node[] getChildren() {
return new Node[0];
}
@Override
public boolean update() {
return false;
}
@Override
public Object getElement() {
return this;
}
@Override
public String toString() {
return myId;
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (!(o instanceof Node)) return false;
final Node node = (Node)o;
if (!myEqualityString.equals(node.myEqualityString)) return false;
return true;
}
@Override
public int hashCode() {
return myId.hashCode();
}
}
class CachedNode extends Node {
private final ArrayList<CachedNode> myChildren = new ArrayList<CachedNode>();
CachedNode(final String id) {
super(id, null);
}
CachedNode addChild(String id) {
final CachedNode node = new CachedNode(id);
myChildren.add(node);
node.myParent = this;
return node;
}
CachedNode getChild(String id) {
for (CachedNode each : myChildren) {
if (id.equals(each.myId)) return each;
}
return null;
}
@Override
final Node[] getChildren() {
return myChildren.toArray(new Node[myChildren.size()]);
}
}
public abstract static class NoYieldNoBackground extends AbstractTreeBuilderCrashTest {
public NoYieldNoBackground() {
super(false, false);
}
}
}