mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
tree tests moved to community
This commit is contained in:
@@ -155,78 +155,6 @@ public class IdeaTestUtil extends PlatformTestUtil {
|
||||
assertDirectoriesEqual(dirAfter, dirBefore, CVS_FILE_FILTER);
|
||||
}
|
||||
|
||||
public static StringBuffer print(AbstractTreeStructure structure,
|
||||
Object node,
|
||||
int currentLevel,
|
||||
Comparator comparator,
|
||||
int maxRowCount,
|
||||
char paddingChar) {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
doPrint(buffer, currentLevel, node, structure, comparator, maxRowCount, 0, paddingChar);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private static int doPrint(StringBuffer buffer,
|
||||
int currentLevel,
|
||||
Object node,
|
||||
AbstractTreeStructure structure,
|
||||
Comparator comparator,
|
||||
int maxRowCount,
|
||||
int currentLine,
|
||||
char paddingChar) {
|
||||
if (currentLine >= maxRowCount && maxRowCount != -1) return currentLine;
|
||||
|
||||
StringUtil.repeatSymbol(buffer, paddingChar, currentLevel);
|
||||
buffer.append(toString(node)).append("\n");
|
||||
currentLine++;
|
||||
Object[] children = structure.getChildElements(node);
|
||||
|
||||
if (comparator != null) {
|
||||
ArrayList<?> list = new ArrayList<Object>(Arrays.asList(children));
|
||||
Collections.sort(list, comparator);
|
||||
children = list.toArray(new Object[list.size()]);
|
||||
}
|
||||
for (Object child : children) {
|
||||
currentLine = doPrint(buffer, currentLevel + 1, child, structure, comparator, maxRowCount, currentLine, paddingChar);
|
||||
}
|
||||
|
||||
return currentLine;
|
||||
}
|
||||
|
||||
public static String print(Object[] objects) {
|
||||
return print(Arrays.asList(objects));
|
||||
}
|
||||
|
||||
public static String print(Collection c) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (Iterator iterator = c.iterator(); iterator.hasNext();) {
|
||||
Object each = iterator.next();
|
||||
result.append(toString(each));
|
||||
if (iterator.hasNext()) {
|
||||
result.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public static String print(ListModel model) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (int i = 0; i < model.getSize(); i++) {
|
||||
result.append(toString(model.getElementAt(i)));
|
||||
result.append("\n");
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public static String print(JTree tree) {
|
||||
return print(tree, false);
|
||||
}
|
||||
|
||||
public static void assertTreeStructureEquals(final AbstractTreeStructure treeStructure, final String expected) {
|
||||
Assert.assertEquals(expected, print(treeStructure, treeStructure.getRootElement(), 0, null, -1, ' ').toString());
|
||||
}
|
||||
|
||||
public static void assertTiming(String message, long expected, long actual) {
|
||||
if (COVERAGE_ENABLED_BUILD) return;
|
||||
long expectedOnMyMachine = expected * Timings.MACHINE_TIMING / ETALON_TIMING;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
<orderEntry type="module" module-name="lvcs-api" exported="" />
|
||||
<orderEntry type="library" scope="TEST" name="JUnit4" level="project" />
|
||||
<orderEntry type="library" name="JavaHelp" level="project" />
|
||||
<orderEntry type="module" module-name="testFramework" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
|
||||
+277
@@ -0,0 +1,277 @@
|
||||
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() {
|
||||
public void run() {
|
||||
getBuilder().addSubtreeToUpdateByElement(myRoot.getChild("folder1"));
|
||||
getBuilder().addSubtreeToUpdateByElement(myRoot.getChild("folder2"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void testElementMovedButNodeIsStillInStructure2() throws Exception {
|
||||
assertNodeMove(new Runnable() {
|
||||
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() {
|
||||
public Object getRootElement() {
|
||||
return root;
|
||||
}
|
||||
|
||||
public Object[] doGetChildElements(final Object element) {
|
||||
return ((Node)element).getChildren();
|
||||
}
|
||||
|
||||
public Object getParentElement(final Object element) {
|
||||
return ((Node)element).getParent();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public NodeDescriptor doCreateDescriptor(final Object element, final NodeDescriptor parentDescriptor) {
|
||||
return (NodeDescriptor)element;
|
||||
}
|
||||
|
||||
public void commit() {
|
||||
}
|
||||
|
||||
public boolean hasSomethingToCommit() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
});
|
||||
|
||||
getBuilder().getUi().setCheckStructure(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];
|
||||
}
|
||||
|
||||
public boolean update() {
|
||||
return false;
|
||||
}
|
||||
|
||||
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 static class NoYieldNoBackground extends AbstractTreeBuilderCrashTest {
|
||||
public NoYieldNoBackground() {
|
||||
super(false, false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+611
@@ -0,0 +1,611 @@
|
||||
package com.intellij.ide.util.treeView;
|
||||
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.testFramework.PlatformTestUtil;
|
||||
import com.intellij.ui.treeStructure.Tree;
|
||||
import com.intellij.util.Time;
|
||||
import com.intellij.util.WaitFor;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import junit.framework.Assert;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import javax.swing.tree.TreeNode;
|
||||
import javax.swing.tree.TreePath;
|
||||
import java.util.*;
|
||||
|
||||
abstract class AbstractTreeBuilderTest extends BaseTreeTestCase<BaseTreeTestCase.NodeElement> {
|
||||
protected MyStructure myStructure;
|
||||
|
||||
Node myRoot;
|
||||
DefaultTreeModel myTreeModel;
|
||||
Node myCom;
|
||||
Node myOpenApi;
|
||||
Node myIde;
|
||||
Node myRunner;
|
||||
Node myRcp;
|
||||
|
||||
|
||||
boolean myEnsureSelection = false;
|
||||
|
||||
AbstractTreeBuilderTest.Node myFabrique;
|
||||
|
||||
|
||||
Map<NodeElement, ElementEntry> myElementUpdate = new TreeMap<NodeElement, ElementEntry>();
|
||||
ElementUpdateHook myElementUpdateHook;
|
||||
|
||||
Map<String, Integer> mySortedParent = new TreeMap<String, Integer>();
|
||||
|
||||
NodeDescriptor.NodeComparator.Delegate<NodeDescriptor> myComparator;
|
||||
Node myIntellij;
|
||||
|
||||
protected AbstractTreeBuilderTest(boolean passthrougth) {
|
||||
super(passthrougth);
|
||||
}
|
||||
|
||||
protected AbstractTreeBuilderTest(boolean yieldingUiBuild, boolean bgStructureBuilding) {
|
||||
super(yieldingUiBuild, bgStructureBuilding);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
myComparator = new NodeDescriptor.NodeComparator.Delegate<NodeDescriptor>(new NodeDescriptor.NodeComparator<NodeDescriptor>() {
|
||||
public int compare(NodeDescriptor o1, NodeDescriptor o2) {
|
||||
return AlphaComparator.INSTANCE.compare(o1, o2);
|
||||
}
|
||||
});
|
||||
|
||||
mySortedParent.clear();
|
||||
|
||||
myTreeModel = new DefaultTreeModel(new DefaultMutableTreeNode(null));
|
||||
myTreeModel.addTreeModelListener(new TreeModelListener() {
|
||||
public void treeNodesChanged(TreeModelEvent e) {
|
||||
assertEdt();
|
||||
}
|
||||
|
||||
public void treeNodesInserted(TreeModelEvent e) {
|
||||
assertEdt();
|
||||
}
|
||||
|
||||
public void treeNodesRemoved(TreeModelEvent e) {
|
||||
assertEdt();
|
||||
}
|
||||
|
||||
public void treeStructureChanged(TreeModelEvent e) {
|
||||
assertEdt();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
myTree = new Tree(myTreeModel);
|
||||
myStructure = new MyStructure();
|
||||
myRoot = new Node(null, "/");
|
||||
|
||||
initBuilder(new MyBuilder());
|
||||
|
||||
myTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
|
||||
public void valueChanged(TreeSelectionEvent e) {
|
||||
assertEdt();
|
||||
}
|
||||
});
|
||||
|
||||
myTree.addTreeExpansionListener(new TreeExpansionListener() {
|
||||
public void treeExpanded(TreeExpansionEvent event) {
|
||||
assertEdt();
|
||||
}
|
||||
|
||||
public void treeCollapsed(TreeExpansionEvent event) {
|
||||
assertEdt();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
myElementUpdate.clear();
|
||||
myElementUpdateHook = null;
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
|
||||
Node removeFromParentButKeepRef(NodeElement child) {
|
||||
NodeElement parent = (NodeElement)myStructure.getParentElement(child);
|
||||
AbstractTreeBuilderTest.Node node = myStructure.getNodeFor(parent).remove(child, false);
|
||||
Assert.assertEquals(parent, myStructure.getParentElement(child));
|
||||
Assert.assertFalse(Arrays.asList(myStructure._getChildElements(parent, false)).contains(child));
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void assertSorted(String expected) {
|
||||
Iterator<String> keys = mySortedParent.keySet().iterator();
|
||||
StringBuffer result = new StringBuffer();
|
||||
while (keys.hasNext()) {
|
||||
String each = keys.next();
|
||||
result.append(each);
|
||||
int count = mySortedParent.get(each);
|
||||
if (count > 1) {
|
||||
result.append(" (" + count + ")");
|
||||
}
|
||||
|
||||
if (keys.hasNext()) {
|
||||
result.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
Assert.assertEquals(expected + "\n", result + "\n");
|
||||
mySortedParent.clear();
|
||||
}
|
||||
|
||||
private void addEntry(String value) {
|
||||
if (mySortedParent.containsKey(value)) {
|
||||
mySortedParent.put(value, mySortedParent.get(value) + 1);
|
||||
} else {
|
||||
mySortedParent.put(value, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void assertUpdates(String expected) {
|
||||
List<Object> entries = Arrays.asList(myElementUpdate.values().toArray());
|
||||
Assert.assertEquals(expected + "\n", PlatformTestUtil.print(entries) + "\n");
|
||||
myElementUpdate.clear();
|
||||
}
|
||||
|
||||
public void _testNoUpdateIfHidden() throws Exception {
|
||||
final ArrayList processedNodes = new ArrayList();
|
||||
final boolean[] toHide = new boolean[] {false};
|
||||
|
||||
myElementUpdateHook = new ElementUpdateHook() {
|
||||
public void onElementAction(String action, Object element) {
|
||||
if (toHide[0]) {
|
||||
if ("jetbrains".equals(element.toString())) {
|
||||
getBuilder().getUi().deactivate();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
buildStructure(myRoot);
|
||||
|
||||
waitBuilderToCome();
|
||||
processedNodes.clear();
|
||||
|
||||
|
||||
buildNode("/", false);
|
||||
assertTree(
|
||||
"-/\n" +
|
||||
" +com\n" +
|
||||
" +jetbrains\n" +
|
||||
" +org\n" +
|
||||
" +xunit\n");
|
||||
Assert.assertEquals("/\n" +
|
||||
"com\n" +
|
||||
"jetbrains\n" +
|
||||
"xunit\n" +
|
||||
"org\n" +
|
||||
"intellij\n" +
|
||||
"fabrique\n" +
|
||||
"runner\n" +
|
||||
"eclipse", PlatformTestUtil.print(processedNodes));
|
||||
|
||||
|
||||
processedNodes.clear();
|
||||
toHide[0] = true;
|
||||
updateFromRoot();
|
||||
|
||||
Assert.assertEquals("/\n" +
|
||||
"com\n" +
|
||||
"intellij\n" +
|
||||
"jetbrains", PlatformTestUtil.print(processedNodes));
|
||||
|
||||
processedNodes.clear();
|
||||
toHide[0] = false;
|
||||
|
||||
|
||||
showTree();
|
||||
|
||||
assertTree(
|
||||
"-/\n" +
|
||||
" +com\n" +
|
||||
" +jetbrains\n" +
|
||||
" +org\n" +
|
||||
" +xunit\n");
|
||||
Assert.assertEquals("/\n" +
|
||||
"com\n" +
|
||||
"intellij\n" +
|
||||
"jetbrains\n" +
|
||||
"fabrique\n" +
|
||||
"org\n" +
|
||||
"eclipse\n" +
|
||||
"xunit\n" +
|
||||
"runner", PlatformTestUtil.print(processedNodes));
|
||||
|
||||
}
|
||||
|
||||
|
||||
void buildStructure(final Node root) throws Exception {
|
||||
doAndWaitForBuilder(new Runnable() {
|
||||
public void run() {
|
||||
myCom = root.addChild("com");
|
||||
myIntellij = myCom.addChild("intellij");
|
||||
myOpenApi = myIntellij.addChild("openapi");
|
||||
myFabrique = root.addChild("jetbrains").addChild("fabrique");
|
||||
myIde = myFabrique.addChild("ide");
|
||||
myRunner = root.addChild("xunit").addChild("runner");
|
||||
myRcp = root.addChild("org").addChild("eclipse").addChild("rcp");
|
||||
|
||||
getBuilder().getUi().activate(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void activate() throws Exception {
|
||||
doAndWaitForBuilder(new Runnable() {
|
||||
public void run() {
|
||||
getBuilder().getUi().activate(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void hideTree() throws Exception {
|
||||
Assert.assertFalse(getMyBuilder().myWasCleanedUp);
|
||||
|
||||
invokeLaterIfNeeded(new Runnable() {
|
||||
public void run() {
|
||||
getBuilder().getUi().deactivate();
|
||||
}
|
||||
});
|
||||
|
||||
final WaitFor waitFor = new WaitFor() {
|
||||
protected boolean condition() {
|
||||
return getMyBuilder().myWasCleanedUp || myCancelRequest != null;
|
||||
}
|
||||
};
|
||||
|
||||
if (myCancelRequest != null) {
|
||||
throw new Exception(myCancelRequest);
|
||||
}
|
||||
|
||||
waitFor.assertCompleted("Tree cleanup was not performed");
|
||||
|
||||
Assert.assertTrue(getMyBuilder().myWasCleanedUp);
|
||||
}
|
||||
|
||||
void buildNode(String elementText, boolean select) throws Exception {
|
||||
buildNode(new NodeElement(elementText), select);
|
||||
}
|
||||
|
||||
void buildNode(Node node, boolean select) throws Exception {
|
||||
buildNode(node.myElement, select);
|
||||
}
|
||||
|
||||
void buildNode(final NodeElement element, final boolean select) throws Exception {
|
||||
buildNode(element, select, true);
|
||||
}
|
||||
|
||||
|
||||
void buildNode(final NodeElement element, final boolean select, final boolean addToSelection) throws Exception {
|
||||
final boolean[] done = new boolean[] {false};
|
||||
|
||||
doAndWaitForBuilder(new Runnable() {
|
||||
public void run() {
|
||||
if (select) {
|
||||
getBuilder().select(element, new Runnable() {
|
||||
public void run() {
|
||||
done[0] = true;
|
||||
}
|
||||
}, addToSelection);
|
||||
} else {
|
||||
getBuilder().expand(element, new Runnable() {
|
||||
public void run() {
|
||||
done[0] = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}, new Condition() {
|
||||
public boolean value(Object o) {
|
||||
return done[0];
|
||||
}
|
||||
});
|
||||
|
||||
Assert.assertNotNull(findNode(element, select));
|
||||
}
|
||||
|
||||
|
||||
DefaultMutableTreeNode findNode(String elementText, boolean shouldBeSelected) {
|
||||
return findNode(new NodeElement(elementText), shouldBeSelected);
|
||||
}
|
||||
|
||||
DefaultMutableTreeNode findNode(NodeElement element, boolean shouldBeSelected) {
|
||||
return findNode((DefaultMutableTreeNode)myTree.getModel().getRoot(), element, shouldBeSelected);
|
||||
}
|
||||
|
||||
private DefaultMutableTreeNode findNode(DefaultMutableTreeNode treeNode, NodeElement toFind, boolean shouldBeSelected) {
|
||||
final Object object = treeNode.getUserObject();
|
||||
Assert.assertNotNull(object);
|
||||
if (!(object instanceof NodeDescriptor)) return null;
|
||||
final NodeElement element = (NodeElement)((NodeDescriptor)object).getElement();
|
||||
if (toFind.equals(element)) return treeNode;
|
||||
|
||||
for (int i = 0; i < treeNode.getChildCount(); i++) {
|
||||
final DefaultMutableTreeNode result = findNode((DefaultMutableTreeNode)treeNode.getChildAt(i), toFind, shouldBeSelected);
|
||||
if (result != null) {
|
||||
if (shouldBeSelected) {
|
||||
final TreePath path = new TreePath(result.getPath());
|
||||
Assert.assertTrue("Path should be selected: " + path, myTree.isPathSelected(path));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
class Node {
|
||||
|
||||
final NodeElement myElement;
|
||||
final ArrayList<Node> myChildElements = new ArrayList<Node>();
|
||||
|
||||
Node(Node parent, String textName) {
|
||||
this(parent, new NodeElement(textName));
|
||||
}
|
||||
|
||||
Node(Node parent, NodeElement name) {
|
||||
myElement = name;
|
||||
setParent(parent);
|
||||
}
|
||||
|
||||
private void setParent(Node parent) {
|
||||
myStructure.register(parent != null ? parent.myElement : null, this);
|
||||
}
|
||||
|
||||
public NodeElement getElement() {
|
||||
return myElement;
|
||||
}
|
||||
|
||||
public Node addChild(Node node) {
|
||||
myChildElements.add(node);
|
||||
node.setParent(this);
|
||||
return node;
|
||||
}
|
||||
|
||||
public Node addChild(String name) {
|
||||
final Node node = new Node(this, name);
|
||||
myChildElements.add(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return myElement.toString();
|
||||
}
|
||||
|
||||
public void removeAll() {
|
||||
myChildElements.clear();
|
||||
}
|
||||
|
||||
public Node getChildNode(String name) {
|
||||
for (Node each : myChildElements) {
|
||||
if (name.equals(each.myElement.myName)) return each;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object[] getChildElements() {
|
||||
Object[] elements = new Object[myChildElements.size()];
|
||||
for (int i = 0; i < myChildElements.size(); i++) {
|
||||
elements[i] = myChildElements.get(i).myElement;
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
final NodeElement parent = (NodeElement)myStructure.getParentElement(myElement);
|
||||
Assert.assertNotNull(myElement.toString(), parent);
|
||||
|
||||
myStructure.getNodeFor(parent).remove(myElement, true);
|
||||
}
|
||||
|
||||
private Node remove(final NodeElement name, boolean removeRefToParent) {
|
||||
final Iterator<Node> kids = myChildElements.iterator();
|
||||
Node removed = null;
|
||||
while (kids.hasNext()) {
|
||||
Node each = kids.next();
|
||||
if (name.equals(each.myElement)) {
|
||||
kids.remove();
|
||||
removed = each;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (removeRefToParent) {
|
||||
myStructure.myChild2Parent.remove(name);
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
}
|
||||
|
||||
class MyStructure extends BaseStructure {
|
||||
|
||||
private final Map<NodeElement, NodeElement> myChild2Parent = new HashMap<NodeElement, NodeElement>();
|
||||
private final Map<NodeElement, Node> myElement2Node = new HashMap<NodeElement, Node>();
|
||||
private Set<NodeElement> myLeaves = new HashSet<NodeElement>();
|
||||
|
||||
public Object getRootElement() {
|
||||
return myRoot.myElement;
|
||||
}
|
||||
|
||||
public void reinitRoot(Node root) {
|
||||
myRoot = root;
|
||||
myElement2Node.clear();
|
||||
myLeaves.clear();
|
||||
myElement2Node.put(root.myElement, root);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] doGetChildElements(Object element) {
|
||||
|
||||
onElementAction("getChildren", (NodeElement)element);
|
||||
|
||||
final AbstractTreeBuilderTest.Node node = myElement2Node.get((NodeElement)element);
|
||||
return node.getChildElements();
|
||||
}
|
||||
|
||||
private Node getNodeFor(Object element) {
|
||||
return myElement2Node.get(element);
|
||||
}
|
||||
|
||||
public Object getParentElement(final Object element) {
|
||||
return myChild2Parent.get((NodeElement)element);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isAlwaysLeaf(Object element) {
|
||||
return myLeaves.contains(element);
|
||||
}
|
||||
|
||||
public void addLeaf(NodeElement element) {
|
||||
myLeaves.add(element);
|
||||
}
|
||||
|
||||
public void removeLeaf(NodeElement element) {
|
||||
myLeaves.remove(element);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public NodeDescriptor doCreateDescriptor(final Object element, final NodeDescriptor parentDescriptor) {
|
||||
return new NodeDescriptor(null, parentDescriptor) {
|
||||
public boolean update() {
|
||||
onElementAction("update", (NodeElement)element);
|
||||
return true;
|
||||
}
|
||||
|
||||
public Object getElement() {
|
||||
return element;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getElement().toString();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void register(final NodeElement parent, final Node child) {
|
||||
myChild2Parent.put(child.myElement, parent);
|
||||
myElement2Node.put(child.myElement, child);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
myChild2Parent.clear();
|
||||
myElement2Node.clear();
|
||||
myElement2Node.put(myRoot.myElement, myRoot);
|
||||
}
|
||||
|
||||
public Node getNodeFor(NodeElement element) {
|
||||
return myElement2Node.get(element);
|
||||
}
|
||||
}
|
||||
|
||||
class MyBuilder extends BaseTreeBuilder {
|
||||
|
||||
public MyBuilder() {
|
||||
super(AbstractTreeBuilderTest.this.myTree, AbstractTreeBuilderTest.this.myTreeModel, AbstractTreeBuilderTest.this.myStructure, myComparator,
|
||||
false);
|
||||
|
||||
initRootNode();
|
||||
|
||||
getUi().setJantorPollPeriod(Time.SECOND * 2);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void sortChildren(Comparator<TreeNode> nodeComparator, DefaultMutableTreeNode node, ArrayList<TreeNode> children) {
|
||||
super.sortChildren(nodeComparator, node, children);
|
||||
addEntry(node.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isToEnsureSelectionOnFocusGained() {
|
||||
return myEnsureSelection;
|
||||
}
|
||||
}
|
||||
|
||||
private void onElementAction(String action, NodeElement element) {
|
||||
ElementEntry entry = myElementUpdate.get(element);
|
||||
if (entry == null) {
|
||||
entry = new ElementEntry(element);
|
||||
myElementUpdate.put(element, entry);
|
||||
}
|
||||
entry.onElementAction(action);
|
||||
|
||||
if (myElementUpdateHook != null) {
|
||||
myElementUpdateHook.onElementAction(action, element);
|
||||
}
|
||||
}
|
||||
|
||||
static interface ElementUpdateHook {
|
||||
void onElementAction(String action, Object element);
|
||||
}
|
||||
|
||||
private class ElementEntry {
|
||||
|
||||
NodeElement myElement;
|
||||
|
||||
int myUpdateCount;
|
||||
int myGetChildrenCount;
|
||||
|
||||
private ElementEntry(NodeElement element) {
|
||||
myElement = element;
|
||||
}
|
||||
|
||||
void onElementAction(String action) {
|
||||
try {
|
||||
if ("update".equals(action)) {
|
||||
myUpdateCount++;
|
||||
} else if ("getChildren".equals(action)) {
|
||||
Assert.assertTrue("getChildren() is called before update(), node=" + myElement, myUpdateCount > 0);
|
||||
myGetChildrenCount++;
|
||||
}
|
||||
}
|
||||
catch (Throwable e) {
|
||||
myCancelRequest = e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return (myElement + ": " + asString(myUpdateCount, "update") + " " + asString(myGetChildrenCount, "getChildren")).trim();
|
||||
}
|
||||
|
||||
private String asString(int count, String text) {
|
||||
if (count == 0) return "";
|
||||
return count > 1 ? text + " (" + count + ")" : text;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
MyBuilder getMyBuilder() {
|
||||
return (MyBuilder)getBuilder();
|
||||
}
|
||||
|
||||
interface TreeAction {
|
||||
void run(Runnable onDone);
|
||||
}
|
||||
|
||||
TreePath getPath(String s) {
|
||||
return new TreePath(findNode(s, false).getPath());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,465 @@
|
||||
package com.intellij.ide.util.treeView;
|
||||
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.SimpleTimer;
|
||||
import com.intellij.testFramework.FlyIdeaTestCase;
|
||||
import com.intellij.testFramework.PlatformTestUtil;
|
||||
import com.intellij.ui.treeStructure.Tree;
|
||||
import com.intellij.util.WaitFor;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.util.ui.update.ComparableObject;
|
||||
import com.intellij.util.ui.update.MergingUpdateQueue;
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.AssertionFailedError;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import javax.swing.tree.TreePath;
|
||||
import java.awt.*;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
abstract class BaseTreeTestCase<StructureElement> extends FlyIdeaTestCase {
|
||||
|
||||
private BaseTreeBuilder myBuilder;
|
||||
Tree myTree;
|
||||
|
||||
Throwable myCancelRequest;
|
||||
boolean myReadyRequest;
|
||||
|
||||
private boolean myYieldingUiBuild;
|
||||
private boolean myBgStructureBuilding;
|
||||
private boolean myPassthroughMode;
|
||||
|
||||
final Set<StructureElement> myAutoExpand = new HashSet<StructureElement>();
|
||||
final Set<StructureElement> myAlwaysShowPlus = new HashSet<StructureElement>();
|
||||
boolean mySmartExpand;
|
||||
private Thread myTestThread;
|
||||
|
||||
protected BaseTreeTestCase(boolean passthrougth) {
|
||||
this(false, false);
|
||||
myPassthroughMode = passthrougth;
|
||||
}
|
||||
|
||||
protected BaseTreeTestCase(boolean yieldingUiBuild, boolean bgStructureBuilding) {
|
||||
myYieldingUiBuild = yieldingUiBuild;
|
||||
myBgStructureBuilding = bgStructureBuilding;
|
||||
}
|
||||
|
||||
void doAndWaitForBuilder(final Runnable runnable, final Condition condition) throws Exception {
|
||||
final Ref<Boolean> started = new Ref<Boolean>();
|
||||
invokeLaterIfNeeded(new Runnable() {
|
||||
public void run() {
|
||||
started.set(true);
|
||||
runnable.run();
|
||||
}
|
||||
});
|
||||
|
||||
waitBuilderToCome(new Condition() {
|
||||
public boolean value(Object o) {
|
||||
return started.get() && condition.value(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void waitBuilderToCome() {
|
||||
try {
|
||||
waitBuilderToCome(Condition.TRUE);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
void waitBuilderToCome(final Condition<Object> condition) throws Exception {
|
||||
boolean success = new WaitFor(600000) {
|
||||
protected boolean condition() {
|
||||
final boolean[] ready = new boolean[]{false};
|
||||
invokeAndWaitIfNeeded(new Runnable() {
|
||||
public void run() {
|
||||
AbstractTreeUi ui = getBuilder().getUi();
|
||||
if (ui == null) {
|
||||
ready[0] = true;
|
||||
return;
|
||||
}
|
||||
|
||||
ready[0] = (myCancelRequest != null || myReadyRequest) || (condition.value(null) && (ui.isReady()));
|
||||
}
|
||||
});
|
||||
|
||||
return ready[0];
|
||||
}
|
||||
}.isConditionRealized();
|
||||
|
||||
if (myCancelRequest != null) {
|
||||
Thread.dumpStack();
|
||||
throw new Exception(myCancelRequest);
|
||||
}
|
||||
|
||||
Assert.assertTrue(getBuilder().getUi().getNodeActions().isEmpty());
|
||||
|
||||
Assert.assertTrue(success);
|
||||
}
|
||||
|
||||
void expand(final TreePath p) throws Exception {
|
||||
invokeAndWaitIfNeeded(new Runnable() {
|
||||
public void run() {
|
||||
myTree.expandPath(p);
|
||||
}
|
||||
});
|
||||
waitBuilderToCome();
|
||||
}
|
||||
|
||||
void collapsePath(final TreePath p) throws Exception {
|
||||
invokeAndWaitIfNeeded(new Runnable() {
|
||||
public void run() {
|
||||
myTree.collapsePath(p);
|
||||
}
|
||||
});
|
||||
waitBuilderToCome();
|
||||
}
|
||||
|
||||
AbstractTreeBuilder getBuilder() {
|
||||
return myBuilder;
|
||||
}
|
||||
|
||||
protected void initBuilder(BaseTreeBuilder builder) {
|
||||
myBuilder = builder;
|
||||
myBuilder.setCanYieldUpdate(myYieldingUiBuild);
|
||||
myBuilder.setPassthroughMode(myPassthroughMode);
|
||||
}
|
||||
|
||||
|
||||
class BaseTreeBuilder extends AbstractTreeBuilder {
|
||||
volatile boolean myWasCleanedUp;
|
||||
|
||||
public BaseTreeBuilder(JTree tree,
|
||||
DefaultTreeModel treeModel,
|
||||
AbstractTreeStructure treeStructure,
|
||||
@Nullable Comparator<NodeDescriptor> comparator) {
|
||||
super(tree, treeModel, treeStructure, comparator);
|
||||
}
|
||||
|
||||
public BaseTreeBuilder(JTree tree,
|
||||
DefaultTreeModel treeModel,
|
||||
AbstractTreeStructure treeStructure,
|
||||
@Nullable Comparator<NodeDescriptor> comparator,
|
||||
boolean updateIfInactive) {
|
||||
super(tree, treeModel, treeStructure, comparator, updateIfInactive);
|
||||
}
|
||||
|
||||
public BaseTreeBuilder() {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected final boolean updateNodeDescriptor(NodeDescriptor descriptor) {
|
||||
checkThread();
|
||||
|
||||
int delay = getNodeDescriptorUpdateDelay();
|
||||
if (delay > 0) {
|
||||
try {
|
||||
Thread.currentThread().sleep(delay);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return super.updateNodeDescriptor(descriptor);
|
||||
}
|
||||
|
||||
protected boolean isAutoExpandNode(final NodeDescriptor nodeDescriptor) {
|
||||
return myAutoExpand.contains(nodeDescriptor.getElement());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isSmartExpand() {
|
||||
return mySmartExpand;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean isAlwaysShowPlus(NodeDescriptor descriptor) {
|
||||
return myAlwaysShowPlus.contains(descriptor.getElement());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractTreeUpdater createUpdater() {
|
||||
return _createUpdater(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateAfterLoadedInBackground(Runnable runnable) {
|
||||
_updateAfterLoadedInBackground(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runBackgroundLoading(Runnable runnable) {
|
||||
_runBackgroundLoading(runnable);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void cleanUp() {
|
||||
super.cleanUp();
|
||||
myWasCleanedUp = true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected AbstractTreeUi createUi() {
|
||||
return _createUi();
|
||||
}
|
||||
}
|
||||
|
||||
void _updateAfterLoadedInBackground(Runnable runnable) {
|
||||
SwingUtilities.invokeLater(runnable);
|
||||
}
|
||||
|
||||
void _runBackgroundLoading(Runnable runnable) {
|
||||
SimpleTimer.getInstance().setUp(runnable, getChildrenLoadingDelay());
|
||||
}
|
||||
|
||||
|
||||
AbstractTreeUi _createUi() {
|
||||
return new AbstractTreeUi() {
|
||||
@Override
|
||||
protected void yield(Runnable runnable) {
|
||||
SimpleTimer.getInstance().setUp(runnable, 100);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canYield() {
|
||||
return myYieldingUiBuild;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runOnYieldingDone(Runnable onDone) {
|
||||
SwingUtilities.invokeLater(onDone);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
AbstractTreeUpdater _createUpdater(AbstractTreeBuilder builder) {
|
||||
final AbstractTreeUpdater updater = new AbstractTreeUpdater(builder) {
|
||||
@Override
|
||||
protected void invokeLater(Runnable runnable) {
|
||||
runnable.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEdt() {
|
||||
return SwingUtilities.isEventDispatchThread();
|
||||
}
|
||||
};
|
||||
updater.setModalityStateComponent(MergingUpdateQueue.ANY_COMPONENT);
|
||||
return updater;
|
||||
}
|
||||
|
||||
abstract class BaseStructure extends AbstractTreeStructure {
|
||||
|
||||
@Override
|
||||
public boolean isToBuildChildrenInBackground(Object element) {
|
||||
return myBgStructureBuilding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commit() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSomethingToCommit() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public final NodeDescriptor createDescriptor(Object element, NodeDescriptor parentDescriptor) {
|
||||
checkThread();
|
||||
return doCreateDescriptor(element, parentDescriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public abstract NodeDescriptor doCreateDescriptor(Object element, NodeDescriptor parentDescriptor);
|
||||
|
||||
@Override
|
||||
public final Object[] getChildElements(Object element) {
|
||||
return _getChildElements(element, true);
|
||||
}
|
||||
|
||||
public final Object[] _getChildElements(Object element, boolean checkThread) {
|
||||
if (checkThread) {
|
||||
checkThread();
|
||||
}
|
||||
|
||||
return doGetChildElements(element);
|
||||
}
|
||||
|
||||
public abstract Object[] doGetChildElements(Object element);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
myCancelRequest = null;
|
||||
myReadyRequest = false;
|
||||
mySmartExpand = false;
|
||||
myAutoExpand.clear();
|
||||
myAlwaysShowPlus.clear();
|
||||
myTestThread = Thread.currentThread();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
invokeLaterIfNeeded(new Runnable() {
|
||||
public void run() {
|
||||
if (getBuilder() != null) {
|
||||
Disposer.dispose(getBuilder());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
void assertTree(final String expected) throws Exception {
|
||||
waitBuilderToCome();
|
||||
Assert.assertEquals(expected, PlatformTestUtil.print(myTree, true));
|
||||
}
|
||||
|
||||
void doAndWaitForBuilder(final Runnable runnable) throws Exception {
|
||||
doAndWaitForBuilder(runnable, Condition.TRUE);
|
||||
}
|
||||
|
||||
|
||||
void updateFromRoot() throws Exception {
|
||||
doAndWaitForBuilder(new Runnable() {
|
||||
public void run() {
|
||||
getBuilder().updateFromRoot();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void updateFrom(final NodeElement element) throws Exception {
|
||||
updateFrom(element, false);
|
||||
}
|
||||
|
||||
void updateFrom(final NodeElement element, final boolean forceResort) throws Exception {
|
||||
doAndWaitForBuilder(new Runnable() {
|
||||
public void run() {
|
||||
getBuilder().queueUpdateFrom(element, forceResort);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void showTree() throws Exception {
|
||||
doAndWaitForBuilder(new Runnable() {
|
||||
public void run() {
|
||||
getBuilder().getUi().activate(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void select(final Object element, final boolean addToSelection) throws Exception {
|
||||
select(new Object[] {element}, addToSelection);
|
||||
}
|
||||
|
||||
void select(final Object[] elements, final boolean addToSelection) throws Exception {
|
||||
final Ref<Boolean> done = new Ref<Boolean>(false);
|
||||
doAndWaitForBuilder(new Runnable() {
|
||||
public void run() {
|
||||
getBuilder().select(elements, new Runnable() {
|
||||
public void run() {
|
||||
done.set(true);
|
||||
}
|
||||
}, addToSelection);
|
||||
}
|
||||
}, new Condition() {
|
||||
public boolean value(Object o) {
|
||||
return done.get();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected final boolean isYieldingUiBuild() {
|
||||
return myYieldingUiBuild;
|
||||
}
|
||||
|
||||
protected final boolean isBgStructureBuilding() {
|
||||
return myBgStructureBuilding;
|
||||
}
|
||||
|
||||
protected int getChildrenLoadingDelay() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected int getNodeDescriptorUpdateDelay() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void checkThread() {
|
||||
String message = "Wrong thread used for query structure, thread=" + Thread.currentThread();
|
||||
|
||||
if (myPassthroughMode) {
|
||||
Assert.assertSame(message, myTestThread, Thread.currentThread());
|
||||
} else {
|
||||
if (isBgStructureBuilding()) {
|
||||
Assert.assertFalse(message, EventQueue.isDispatchThread());
|
||||
} else {
|
||||
Assert.assertTrue(message, EventQueue.isDispatchThread());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected final void invokeLaterIfNeeded(Runnable runnable) {
|
||||
if (myPassthroughMode) {
|
||||
runnable.run();
|
||||
} else {
|
||||
UIUtil.invokeLaterIfNeeded(runnable);
|
||||
}
|
||||
}
|
||||
|
||||
protected final void invokeAndWaitIfNeeded(Runnable runnable) {
|
||||
if (myPassthroughMode) {
|
||||
runnable.run();
|
||||
} else {
|
||||
UIUtil.invokeAndWaitIfNeeded(runnable);
|
||||
}
|
||||
}
|
||||
|
||||
protected final void assertEdt() {
|
||||
if (myPassthroughMode) {
|
||||
checkThread();
|
||||
} else if (!EventQueue.isDispatchThread()) {
|
||||
myCancelRequest = new AssertionFailedError("Must be event dispatch thread");
|
||||
throw new RuntimeException(myCancelRequest);
|
||||
}
|
||||
}
|
||||
|
||||
public static class NodeElement extends ComparableObject.Impl implements Comparable<NodeElement>{
|
||||
|
||||
final String myName;
|
||||
|
||||
public NodeElement(String name) {
|
||||
super(name);
|
||||
myName = name;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
public int compareTo(NodeElement o) {
|
||||
return myName.compareTo(o.myName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+252
@@ -0,0 +1,252 @@
|
||||
package com.intellij.ide.util.treeView;
|
||||
|
||||
import com.intellij.openapi.util.ActionCallback;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.ui.TreeUIHelper;
|
||||
import com.intellij.ui.speedSearch.ElementFilter;
|
||||
import com.intellij.ui.treeStructure.*;
|
||||
import com.intellij.ui.treeStructure.filtered.FilteringTreeBuilder;
|
||||
import com.intellij.ui.treeStructure.filtered.FilteringTreeStructure;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
public class FilteringTreeBuilderTest extends BaseTreeTestCase {
|
||||
private FilteringTreeBuilder myBuilder;
|
||||
private MyFilter myFilter;
|
||||
private Node myRoot;
|
||||
private SimpleTreeStructure myStructure;
|
||||
|
||||
public FilteringTreeBuilderTest() {
|
||||
super(false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
myTree = new SimpleTree() {
|
||||
@Override
|
||||
protected void configureUiHelper(final TreeUIHelper helper) {
|
||||
}
|
||||
};
|
||||
|
||||
myFilter = new MyFilter();
|
||||
myRoot = new Node(null, "/");
|
||||
myStructure = new SimpleTreeStructure.Impl(myRoot);
|
||||
}
|
||||
|
||||
private void initBuilder() throws Exception {
|
||||
myBuilder = new FilteringTreeBuilder(null, myTree, myFilter, myStructure, AlphaComparator.INSTANCE) {
|
||||
@Override
|
||||
protected AbstractTreeUpdater createUpdater() {
|
||||
return _createUpdater(this);
|
||||
}
|
||||
};
|
||||
|
||||
showTree();
|
||||
|
||||
Disposer.register(getRootDisposable(), myBuilder);
|
||||
}
|
||||
|
||||
public void testFilter() throws Exception {
|
||||
myTree.setRootVisible(false);
|
||||
|
||||
final Node f1 = myRoot.addChild("folder1");
|
||||
f1.addChild("file11");
|
||||
f1.addChild("file12");
|
||||
Node f11 = f1.addChild("folder11");
|
||||
f11.addChild("element111");
|
||||
myRoot.addChild("folder2").addChild("file21");
|
||||
|
||||
initBuilder();
|
||||
|
||||
assertTree("-/\n"
|
||||
+ " -folder1\n"
|
||||
+ " file11\n"
|
||||
+ " file12\n"
|
||||
+ " -folder11\n"
|
||||
+ " element111\n"
|
||||
+ " -folder2\n"
|
||||
+ " file21\n");
|
||||
|
||||
update("", findNode("file11"));
|
||||
assertTree("-/\n"
|
||||
+ " -folder1\n"
|
||||
+ " [file11]\n"
|
||||
+ " file12\n"
|
||||
+ " -folder11\n"
|
||||
+ " element111\n"
|
||||
+ " -folder2\n"
|
||||
+ " file21\n");
|
||||
|
||||
update("f", null);
|
||||
assertTree("-/\n"
|
||||
+ " -folder1\n"
|
||||
+ " [file11]\n"
|
||||
+ " file12\n"
|
||||
+ " folder11\n"
|
||||
+ " -folder2\n"
|
||||
+ " file21\n");
|
||||
|
||||
update("fo", null);
|
||||
assertTree("-/\n"
|
||||
+ " -folder1\n"
|
||||
+ " [folder11]\n"
|
||||
+ " folder2\n");
|
||||
|
||||
update("fo_", null);
|
||||
assertTree("+/\n");
|
||||
|
||||
update("", null);
|
||||
assertTree("-/\n"
|
||||
+ " -[folder1]\n"
|
||||
+ " file11\n"
|
||||
+ " file12\n"
|
||||
+ " -folder11\n"
|
||||
+ " element111\n"
|
||||
+ " -folder2\n"
|
||||
+ " file21\n");
|
||||
|
||||
|
||||
select("element111");
|
||||
assertTree("-/\n"
|
||||
+ " -folder1\n"
|
||||
+ " file11\n"
|
||||
+ " file12\n"
|
||||
+ " -folder11\n"
|
||||
+ " [element111]\n"
|
||||
+ " -folder2\n"
|
||||
+ " file21\n");
|
||||
|
||||
update("folder2", null);
|
||||
assertTree("-/\n"
|
||||
+ " [folder2]\n");
|
||||
|
||||
update("", null);
|
||||
assertTree("-/\n"
|
||||
+ " -folder1\n"
|
||||
+ " file11\n"
|
||||
+ " file12\n"
|
||||
+ " -folder11\n"
|
||||
+ " element111\n"
|
||||
+ " -[folder2]\n"
|
||||
+ " file21\n");
|
||||
|
||||
update("file1", null);
|
||||
assertTree("-/\n"
|
||||
+ " -[folder1]\n"
|
||||
+ " file11\n"
|
||||
+ " file12\n");
|
||||
|
||||
select("file12");
|
||||
assertTree("-/\n"
|
||||
+ " -folder1\n"
|
||||
+ " file11\n"
|
||||
+ " [file12]\n");
|
||||
|
||||
update("", null);
|
||||
assertTree("-/\n"
|
||||
+ " -folder1\n"
|
||||
+ " file11\n"
|
||||
+ " [file12]\n"
|
||||
+ " -folder11\n"
|
||||
+ " element111\n"
|
||||
+ " -folder2\n"
|
||||
+ " file21\n");
|
||||
|
||||
}
|
||||
|
||||
private void select(String element) throws Exception {
|
||||
FilteringTreeStructure.Node node = myBuilder.getVisibleNodeFor(findNode(element));
|
||||
select(new Object[] {node}, false);
|
||||
}
|
||||
|
||||
private void update(final String text, final Object selection) throws Exception {
|
||||
final ActionCallback result = new ActionCallback();
|
||||
doAndWaitForBuilder(new Runnable() {
|
||||
public void run() {
|
||||
myFilter.update(text, selection).notify(result);
|
||||
}
|
||||
}, new Condition<Object>() {
|
||||
public boolean value(Object o) {
|
||||
return result.isProcessed();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private class Node extends CachingSimpleNode {
|
||||
|
||||
private final LinkedHashMap<String, Node> myKids = new LinkedHashMap<String, Node>();
|
||||
|
||||
private Node(final SimpleNode aParent, String name) {
|
||||
super(aParent);
|
||||
myName = name;
|
||||
}
|
||||
|
||||
public Node addChild(String name) {
|
||||
if (!myKids.containsKey(name)) {
|
||||
myKids.put(name, new Node(this, name));
|
||||
}
|
||||
|
||||
return myKids.get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doUpdate() {
|
||||
setPlainText(myName);
|
||||
}
|
||||
|
||||
protected SimpleNode[] buildChildren() {
|
||||
return myKids.values().toArray(new Node[myKids.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateFileStatus() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private Object findNode(final String name) {
|
||||
final Ref<Object> node = new Ref<Object>();
|
||||
((SimpleTree)myTree).accept(myBuilder, new SimpleNodeVisitor() {
|
||||
public boolean accept(final SimpleNode simpleNode) {
|
||||
if (name.equals(simpleNode.toString())) {
|
||||
node.set(myBuilder.getOriginalNode(simpleNode));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return node.get();
|
||||
}
|
||||
|
||||
|
||||
private class MyFilter extends ElementFilter.Active.Impl {
|
||||
|
||||
String myPattern = "";
|
||||
|
||||
public boolean shouldBeShowing(final Object value) {
|
||||
return value.toString().startsWith(myPattern);
|
||||
}
|
||||
|
||||
public ActionCallback update(final String pattern, Object selection) {
|
||||
myPattern = pattern;
|
||||
return fireUpdate(selection, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
AbstractTreeBuilder getBuilder() {
|
||||
return myBuilder;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,44 @@
|
||||
package com.intellij.testFramework;
|
||||
|
||||
import com.intellij.mock.MockApplication;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ex.ApplicationManagerEx;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public abstract class FlyIdeaTestCase extends TestCase {
|
||||
|
||||
private Disposable myRootDisposable;
|
||||
private File myTempDir;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
MockApplication app = new MockApplication();
|
||||
myRootDisposable = Disposer.newDisposable();
|
||||
ApplicationManagerEx.setApplication(app, myRootDisposable);
|
||||
|
||||
}
|
||||
|
||||
public File getTempDir() throws IOException {
|
||||
if (myTempDir == null) {
|
||||
myTempDir = FileUtil.createTempDirectory(getName(), getClass().getName());
|
||||
}
|
||||
|
||||
return myTempDir;
|
||||
}
|
||||
|
||||
public Disposable getRootDisposable() {
|
||||
return myRootDisposable;
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
if (myTempDir != null) {
|
||||
FileUtil.asyncDelete(myTempDir);
|
||||
}
|
||||
Disposer.dispose(myRootDisposable);
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.intellij.testFramework;
|
||||
|
||||
import com.intellij.ide.util.treeView.AbstractTreeNode;
|
||||
import com.intellij.ide.util.treeView.AbstractTreeStructure;
|
||||
import com.intellij.idea.Bombed;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
@@ -37,8 +38,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.TreePath;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
@@ -200,4 +200,76 @@ public class PlatformTestUtil {
|
||||
private static boolean isItMe(final String who) {
|
||||
return Comparing.equal(who, SystemProperties.getUserName(), false);
|
||||
}
|
||||
|
||||
public static StringBuffer print(AbstractTreeStructure structure,
|
||||
Object node,
|
||||
int currentLevel,
|
||||
Comparator comparator,
|
||||
int maxRowCount,
|
||||
char paddingChar) {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
doPrint(buffer, currentLevel, node, structure, comparator, maxRowCount, 0, paddingChar);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private static int doPrint(StringBuffer buffer,
|
||||
int currentLevel,
|
||||
Object node,
|
||||
AbstractTreeStructure structure,
|
||||
Comparator comparator,
|
||||
int maxRowCount,
|
||||
int currentLine,
|
||||
char paddingChar) {
|
||||
if (currentLine >= maxRowCount && maxRowCount != -1) return currentLine;
|
||||
|
||||
StringUtil.repeatSymbol(buffer, paddingChar, currentLevel);
|
||||
buffer.append(toString(node)).append("\n");
|
||||
currentLine++;
|
||||
Object[] children = structure.getChildElements(node);
|
||||
|
||||
if (comparator != null) {
|
||||
ArrayList<?> list = new ArrayList<Object>(Arrays.asList(children));
|
||||
Collections.sort(list, comparator);
|
||||
children = list.toArray(new Object[list.size()]);
|
||||
}
|
||||
for (Object child : children) {
|
||||
currentLine = doPrint(buffer, currentLevel + 1, child, structure, comparator, maxRowCount, currentLine, paddingChar);
|
||||
}
|
||||
|
||||
return currentLine;
|
||||
}
|
||||
|
||||
public static String print(Object[] objects) {
|
||||
return print(Arrays.asList(objects));
|
||||
}
|
||||
|
||||
public static String print(Collection c) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (Iterator iterator = c.iterator(); iterator.hasNext();) {
|
||||
Object each = iterator.next();
|
||||
result.append(toString(each));
|
||||
if (iterator.hasNext()) {
|
||||
result.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public static String print(ListModel model) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (int i = 0; i < model.getSize(); i++) {
|
||||
result.append(toString(model.getElementAt(i)));
|
||||
result.append("\n");
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public static String print(JTree tree) {
|
||||
return print(tree, false);
|
||||
}
|
||||
|
||||
public static void assertTreeStructureEquals(final AbstractTreeStructure treeStructure, final String expected) {
|
||||
Assert.assertEquals(expected, print(treeStructure, treeStructure.getRootElement(), 0, null, -1, ' ').toString());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user