mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
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:
+15
-6
@@ -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)
|
||||
|
||||
+24
-21
@@ -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;
|
||||
}
|
||||
|
||||
+12
-2
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+10
-5
@@ -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;
|
||||
|
||||
|
||||
+7
-2
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user