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)
This commit is contained in:
Denis.Zhdanov
2012-08-20 22:26:09 +04:00
parent 9899440429
commit f1679987b8
5 changed files with 68 additions and 36 deletions
@@ -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)
@@ -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 {
* </pre>
* <p/>
*
* @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 <code>true</code> if given child node has been merged to the existing node; <code>false</code> 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 <code>true</code> if given child node has been merged to the existing node; <code>false</code> 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;
}
@@ -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<DefaultMutableTreeNode, Integer> 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);
}
@@ -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<Listener> myListeners = new HashSet<Listener>();
@NotNull private final Set<Object> myConditions = new HashSet<Object>();
@NotNull private final DefaultTreeModel myTreeModel;
@NotNull private final TIntObjectHashMap<ArrangementRuleEditingModelImpl> myRowMappings;
@NotNull private final ArrangementSettingsGrouper myGrouper;
private final int myRowShift;
@@ -53,18 +55,20 @@ public class ArrangementRuleEditingModelImpl implements ArrangementRuleEditingMo
/**
* Creates new <code>ArrangementRuleEditingModelImpl</code> 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<DefaultMutableTreeNode, Integer> 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;
@@ -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();
}
}