From f1679987b8cd29b92e37434b10ef5b05da26a488 Mon Sep 17 00:00:00 2001 From: "Denis.Zhdanov" Date: Mon, 20 Aug 2012 22:25:47 +0400 Subject: [PATCH] IDEA-19061 Integrate the Rearranger-plugin into core-IDE Performing tree modification via the tree model (the goal is to propagate the modification events to the tree ui) --- .../ArrangementConfigUtilTest.groovy | 21 ++++++--- .../arrangement/ArrangementConfigUtil.java | 45 ++++++++++--------- .../ArrangementRuleEditingModelBuilder.java | 14 +++++- .../ArrangementRuleEditingModelImpl.java | 15 ++++--- .../arrangement/ArrangementRuleTree.java | 9 +++- 5 files changed, 68 insertions(+), 36 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/application/options/codeStyle/arrangement/ArrangementConfigUtilTest.groovy b/java/java-tests/testSrc/com/intellij/application/options/codeStyle/arrangement/ArrangementConfigUtilTest.groovy index 8e0cc861c7bd..d0d36a708207 100644 --- a/java/java-tests/testSrc/com/intellij/application/options/codeStyle/arrangement/ArrangementConfigUtilTest.groovy +++ b/java/java-tests/testSrc/com/intellij/application/options/codeStyle/arrangement/ArrangementConfigUtilTest.groovy @@ -20,6 +20,7 @@ import org.jetbrains.annotations.Nullable import org.junit.Test import javax.swing.tree.DefaultMutableTreeNode +import javax.swing.tree.DefaultTreeModel import static org.junit.Assert.assertEquals /** @@ -50,7 +51,7 @@ four = '4'() '1' { '4'() } - def rowMappings = ArrangementConfigUtil.replace(one, four, replacement) + def rowMappings = doReplace(initial, one, four, replacement) // Check def expected = new TreeNodeBuilder(). @@ -108,8 +109,8 @@ four = '4'() } '5'() } - - ArrangementConfigUtil.insert(initial, 0, toAdd) + + doInsert(initial, 0, toAdd) assertNodesEqual(expected, initial) } @@ -145,7 +146,7 @@ four = '4'() '5'() } - ArrangementConfigUtil.insert(initial, 1, toAdd) + doInsert(initial, 1, toAdd) assertNodesEqual(expected, initial) } @@ -181,7 +182,7 @@ four = '4'() '5'() } - ArrangementConfigUtil.insert(initial, 2, toAdd) + doInsert(initial, 2, toAdd) assertNodesEqual(expected, initial) } @@ -221,10 +222,18 @@ four = '4'() } } - ArrangementConfigUtil.insert(initial, 3, toAdd) + doInsert(initial, 3, toAdd) assertNodesEqual(expected, initial) } + private static def doReplace(initial, from, to, replacement) { + ArrangementConfigUtil.replace(from, to, replacement, new DefaultTreeModel(initial)) + } + + private static def doInsert(parent, i, child) { + ArrangementConfigUtil.insert(parent, i, child, new DefaultTreeModel(ArrangementConfigUtil.getRoot(parent))) + } + private static void assertNodesEqual(@NotNull DefaultMutableTreeNode expected, @NotNull DefaultMutableTreeNode actual) { assertEquals(expected.userObject, actual.userObject) assertEquals(expected.childCount, actual.childCount) diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementConfigUtil.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementConfigUtil.java index 8348fdc28b52..7f12f8865bcf 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementConfigUtil.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementConfigUtil.java @@ -30,6 +30,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import java.awt.*; @@ -215,20 +216,22 @@ public class ArrangementConfigUtil { * @param from indicates start of the node sub-hierarchy to be replaced (inclusive) * @param to indicates end of the node sub-hierarchy to be replaced (inclusive) * @param replacement root of the node sub-hierarchy which should replace the one identified by the given 'start' and 'end' nodes + * @param treeModel model which should hold ui nodes * @return collection of row changes at the form {@code 'old row -> new row'} */ @SuppressWarnings("AssignmentToForLoopParameter") @NotNull public static TIntIntHashMap replace(@NotNull DefaultMutableTreeNode from, @NotNull DefaultMutableTreeNode to, - @NotNull DefaultMutableTreeNode replacement) + @NotNull DefaultMutableTreeNode replacement, + @NotNull DefaultTreeModel treeModel) { markRows(from); if (from == to) { DefaultMutableTreeNode parent = (DefaultMutableTreeNode)from.getParent(); int index = parent.getIndex(from); - parent.remove(index); - parent.insert(replacement, index); + treeModel.removeNodeFromParent(from); + treeModel.insertNodeInto(replacement, parent, index); return collectRowChangesAndUnmark(parent); } @@ -306,7 +309,7 @@ public class ArrangementConfigUtil { } for (int j = i + 1; j < childCount; j++) { DefaultMutableTreeNode child = (DefaultMutableTreeNode)parent.getChildAt(j); - parent.remove(j); + treeModel.removeNodeFromParent(child); // Unwrap node's data. child.setUserObject(child.getChildCount() > 0 ? extractUserObject(child.getUserObject()) : child.getUserObject()); parentCopy.add(child); @@ -320,7 +323,7 @@ public class ArrangementConfigUtil { //region Remove target sub-hierarchy for (DefaultMutableTreeNode current = to; current != root;) { DefaultMutableTreeNode parent = (DefaultMutableTreeNode)current.getParent(); - parent.remove(current); + treeModel.removeNodeFromParent(current); current = parent; if (current != to) { current.setUserObject(extractUserObject(current.getUserObject())); @@ -332,9 +335,9 @@ public class ArrangementConfigUtil { //endregion //region Insert nodes. - boolean merged = insert(root, insertionIndex, replacement); + boolean merged = insert(root, insertionIndex, replacement, treeModel); if (cutHierarchy != null) { - insert(root, insertionIndex + (merged ? 0 : 1), cutHierarchy); + insert(root, insertionIndex + (merged ? 0 : 1), cutHierarchy, treeModel); } //endregion @@ -469,20 +472,25 @@ public class ArrangementConfigUtil { * *

* - * @param parent parent node to insert into - * @param index insertion index to use for the given parent node - * @param child node to insert to the given parent node at the given insertion index - * @return true if given child node has been merged to the existing node; false otherwise + * @param parent parent node to insert into + * @param index insertion index to use for the given parent node + * @param child node to insert to the given parent node at the given insertion index + * @param treeModel model which should hold UI nodes + * @return true if given child node has been merged to the existing node; false otherwise */ - public static boolean insert(@NotNull final DefaultMutableTreeNode parent, final int index, @NotNull final DefaultMutableTreeNode child) { + public static boolean insert(@NotNull final DefaultMutableTreeNode parent, + final int index, + @NotNull final DefaultMutableTreeNode child, + @NotNull DefaultTreeModel treeModel) + { if (parent.getChildCount() < index) { - parent.add(child); + treeModel.insertNodeInto(child, parent, parent.getChildCount()); return false; } if (child.getChildCount() <= 0) { // Don't merge the last child. - parent.insert(child, index); + treeModel.insertNodeInto(child, parent, index); } boolean anchorAbove = false; @@ -503,17 +511,12 @@ public class ArrangementConfigUtil { } if (mergeCandidate == null) { - if (index < parent.getChildCount()) { - parent.insert(child, index); - } - else { - parent.add(child); - } + treeModel.insertNodeInto(child, parent, index); return false; } for (int i = 0, limit = child.getChildCount(); i < limit; i++) { - insert(mergeCandidate, anchorAbove ? 0 : mergeCandidate.getChildCount(), (DefaultMutableTreeNode)child.getChildAt(0)); + insert(mergeCandidate, anchorAbove ? 0 : mergeCandidate.getChildCount(), (DefaultMutableTreeNode)child.getChildAt(0), treeModel); } return true; } diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModelBuilder.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModelBuilder.java index c6dd34513203..04cc4d3bbf5b 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModelBuilder.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModelBuilder.java @@ -26,6 +26,7 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeNode; /** @@ -92,11 +93,20 @@ public class ArrangementRuleEditingModelBuilder { } HierarchicalArrangementSettingsNode grouped = grouper.group(setting); + DefaultTreeModel treeModel = (DefaultTreeModel)tree.getModel(); Pair pair = ArrangementConfigUtil.map(root, grouped); DefaultMutableTreeNode topMostNode = (DefaultMutableTreeNode)ArrangementConfigUtil.getLastBefore(pair.first, root); int row = initialInsertRow + pair.second - 1; - ArrangementRuleEditingModelImpl model - = new ArrangementRuleEditingModelImpl(setting, topMostNode, pair.first, grouper, rowMappings, row, tree.isRootVisible() ? 0 : -1); + ArrangementRuleEditingModelImpl model = new ArrangementRuleEditingModelImpl( + treeModel, + setting, + topMostNode, + pair.first, + grouper, + rowMappings, + row, + tree.isRootVisible() ? 0 : -1 + ); rowMappings.put(row, model); } diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModelImpl.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModelImpl.java index 1d16632e7847..852bfe8aa6ff 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModelImpl.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModelImpl.java @@ -26,6 +26,7 @@ import gnu.trove.TIntObjectProcedure; import org.jetbrains.annotations.NotNull; import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; import java.util.Set; /** @@ -41,6 +42,7 @@ public class ArrangementRuleEditingModelImpl implements ArrangementRuleEditingMo @NotNull private final Set myListeners = new HashSet(); @NotNull private final Set myConditions = new HashSet(); + @NotNull private final DefaultTreeModel myTreeModel; @NotNull private final TIntObjectHashMap myRowMappings; @NotNull private final ArrangementSettingsGrouper myGrouper; private final int myRowShift; @@ -53,18 +55,20 @@ public class ArrangementRuleEditingModelImpl implements ArrangementRuleEditingMo /** * Creates new ArrangementRuleEditingModelImpl object. * + * @param model tree model which holds target ui nodes. Basically, we need to perform ui nodes modification via it in order + * to generate corresponding events automatically * @param node backing settings node * @param topMost there is a possible case that a single settings node is shown in more than one visual line - * ({@link HierarchicalArrangementSettingsNode}). This argument is the top-most UI node used for the - * settings node representation + * ({@link HierarchicalArrangementSettingsNode}). This argument is the top-most UI node used for the + * settings node representation * @param bottomMost bottom-most UI node used for the given settings node representation * @param grouper strategy that encapsulates information on how settings node should be displayed * @param mappings {@code 'row -> model'} mappings * @param row row number for which current model is registered at the given model mappings * @param shift specifies a shift to be applied to the node rows on model modification. Primary intention is to handle - * a situation when tree root is not shown (a shift is '-1' then) */ - public ArrangementRuleEditingModelImpl(@NotNull ArrangementSettingsNode node, + public ArrangementRuleEditingModelImpl(@NotNull DefaultTreeModel model, + @NotNull ArrangementSettingsNode node, @NotNull DefaultMutableTreeNode topMost, @NotNull DefaultMutableTreeNode bottomMost, @NotNull ArrangementSettingsGrouper grouper, @@ -72,6 +76,7 @@ public class ArrangementRuleEditingModelImpl implements ArrangementRuleEditingMo int row, int shift) { + myTreeModel = model; mySettingsNode = node; myTopMost = topMost; myBottomMost = bottomMost; @@ -180,7 +185,7 @@ public class ArrangementRuleEditingModelImpl implements ArrangementRuleEditingMo Pair replacement = ArrangementConfigUtil.map(null, grouped); DefaultMutableTreeNode newBottom = replacement.first; DefaultMutableTreeNode newTop = ArrangementConfigUtil.getRoot(newBottom); - final TIntIntHashMap rowChanges = ArrangementConfigUtil.replace(myTopMost, myBottomMost, newTop); + final TIntIntHashMap rowChanges = ArrangementConfigUtil.replace(myTopMost, myBottomMost, newTop, myTreeModel); myTopMost = newTop; myBottomMost = newBottom; diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleTree.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleTree.java index bf1fd834d1ac..a7484a0b5b18 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleTree.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleTree.java @@ -300,7 +300,6 @@ public class ArrangementRuleTree { TreePath path = new TreePath(node.getPath()); int row = myTree.getRowForPath(path); myRenderers.remove(row); - myTreeModel.nodeChanged(node); mySelectionModel.addSelectionPath(path); getNodeComponentAt(row, (ArrangementSettingsNode)node.getUserObject()).setSelected(true); if (node == topMost) { @@ -310,6 +309,8 @@ public class ArrangementRuleTree { } finally { mySkipSelectionChange = false; + // TODO den check + //expandAll(myTree, new TreePath(myTreeModel.getRoot())); } } @@ -321,11 +322,15 @@ public class ArrangementRuleTree { boolean expanded, boolean leaf, int row, - boolean hasFocus) { + boolean hasFocus) + { if (row < 0) { return EMPTY_RENDERER; } ArrangementSettingsNode node = (ArrangementSettingsNode)((DefaultMutableTreeNode)value).getUserObject(); + if (node == null) { + return EMPTY_RENDERER; + } return getNodeComponentAt(row, node).getUiComponent(); } }