/*FreeMind - A Program for creating and viewing Mindmaps
*Copyright (C) 2000-2004 Joerg Mueller, Daniel Polansky, Christian Foltin and others.
*
*See COPYING for Details
*
*This program is free software; you can redistribute it and/or
*modify it under the terms of the GNU General Public License
*as published by the Free Software Foundation; either version 2
*of the License, or (at your option) any later version.
*
*This program is distributed in the hope that it will be useful,
*but WITHOUT ANY WARRANTY; without even the implied warranty of
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*GNU General Public License for more details.
*
*You should have received a copy of the GNU General Public License
*along with this program; if not, write to the Free Software
*Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Created on 21.08.2004
*/
package freemind.modes.mindmapmode.actions;
import java.awt.event.ActionEvent;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;
import java.util.Vector;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import freemind.controller.actions.generated.instance.MoveNodesAction;
import freemind.controller.actions.generated.instance.NodeListMember;
import freemind.controller.actions.generated.instance.XmlAction;
import freemind.modes.MapAdapter;
import freemind.modes.MindMapNode;
import freemind.modes.mindmapmode.MindMapController;
import freemind.modes.mindmapmode.actions.xml.ActionPair;
import freemind.modes.mindmapmode.actions.xml.ActorXml;
public class NodeUpAction extends AbstractAction implements ActorXml {
private final MindMapController modeController;
private static Logger logger;
public NodeUpAction(MindMapController modeController) {
super(modeController.getText("node_up"));
this.modeController = modeController;
modeController.getActionFactory().registerActor(this,
getDoActionClass());
if (logger == null) {
logger = modeController.getFrame().getLogger(
this.getClass().getName());
}
}
public void actionPerformed(ActionEvent e) {
MindMapNode selected = modeController.getSelected();
List selecteds = modeController.getSelecteds();
moveNodes(selected, selecteds, -1);
modeController.select(selected, selecteds);
}
/**
*/
public void moveNodes(MindMapNode selected, List selecteds, int direction) {
MoveNodesAction doAction = createMoveNodesAction(selected, selecteds,
direction);
MoveNodesAction undoAction = createMoveNodesAction(selected, selecteds,
-direction);
modeController.doTransaction((String) getValue(NAME), new ActionPair(
doAction, undoAction));
}
public void _moveNodes(MindMapNode selected, List selecteds, int direction) {
Comparator comparator = (direction == -1) ? null : new Comparator() {
public int compare(Object o1, Object o2) {
int i1 = ((Integer) o1).intValue();
int i2 = ((Integer) o2).intValue();
return i2 - i1;
}
};
if (!selected.isRoot()) {
MindMapNode parent = selected.getParentNode();
// multiple move:
Vector sortedChildren = getSortedSiblings(parent);
TreeSet range = new TreeSet(comparator);
for (Iterator i = selecteds.iterator(); i.hasNext();) {
MindMapNode node = (MindMapNode) i.next();
if (node.getParent() != parent) {
logger.warning("Not all selected nodes (here: "
+ node.getText() + ") have the same parent "
+ parent.getText() + ".");
return;
}
range.add(new Integer(sortedChildren.indexOf(node)));
}
// test range for adjacent nodes:
Integer last = (Integer) range.iterator().next();
for (Iterator i = range.iterator(); i.hasNext();) {
Integer newInt = (Integer) i.next();
if (Math.abs(newInt.intValue() - last.intValue()) > 1) {
logger.warning("Not adjacent nodes. Skipped. ");
return;
}
last = newInt;
}
for (Iterator i = range.iterator(); i.hasNext();) {
Integer position = (Integer) i.next();
// from above:
MindMapNode node = (MindMapNode) sortedChildren.get(position
.intValue());
moveNodeTo(node, parent, direction);
}
}
}
/**
* The direction is used if side left and right are present. then the next
* suitable place on the same side# is searched. if there is no such place,
* then the side is changed.
*
* @return returns the new index.
*/
public int moveNodeTo(MindMapNode newChild, MindMapNode parent,
int direction) {
MapAdapter model = modeController.getModel();
int index = model.getIndexOfChild(parent, newChild);
int newIndex = index;
int maxIndex = parent.getChildCount();
Vector sortedNodesIndices = getSortedSiblings(parent);
int newPositionInVector = sortedNodesIndices.indexOf(newChild)
+ direction;
if (newPositionInVector < 0) {
newPositionInVector = maxIndex - 1;
}
if (newPositionInVector >= maxIndex) {
newPositionInVector = 0;
}
MindMapNode destinationNode = (MindMapNode) sortedNodesIndices
.get(newPositionInVector);
newIndex = model.getIndexOfChild(parent, destinationNode);
modeController.removeNodeFromParent(newChild);
modeController.insertNodeInto(newChild, parent, newIndex);
modeController.nodeChanged(newChild);
return newIndex;
}
/**
* Sorts nodes by their left/right status. The left are first.
*/
private Vector getSortedSiblings(MindMapNode node) {
Vector nodes = new Vector();
for (Iterator i = node.childrenUnfolded(); i.hasNext();) {
nodes.add(i.next());
}
Collections.sort(nodes, new Comparator() {
public int compare(Object o1, Object o2) {
if (o1 instanceof MindMapNode) {
MindMapNode n1 = (MindMapNode) o1;
if (o2 instanceof MindMapNode) {
MindMapNode n2 = (MindMapNode) o2;
// left is less than right
int b1 = n1.isLeft() ? 0 : 1;
int b2 = n2.isLeft() ? 0 : 1;
return b1 - b2;
}
}
throw new IllegalArgumentException(
"Elements in LeftRightComparator are not comparable.");
}
});
// logger.finest("Sorted nodes "+ nodes);
return nodes;
}
public void act(XmlAction action) {
if (action instanceof MoveNodesAction) {
MoveNodesAction moveAction = (MoveNodesAction) action;
MindMapNode selected = modeController.getNodeFromID(moveAction
.getNode());
Vector selecteds = new Vector();
for (Iterator i = moveAction.getListNodeListMemberList().iterator(); i
.hasNext();) {
NodeListMember node = (NodeListMember) i.next();
selecteds.add(modeController.getNodeFromID(node.getNode()));
}
_moveNodes(selected, selecteds, moveAction.getDirection());
}
}
public Class getDoActionClass() {
return MoveNodesAction.class;
}
private MoveNodesAction createMoveNodesAction(MindMapNode selected,
List selecteds, int direction) {
MoveNodesAction moveAction = new MoveNodesAction();
moveAction.setDirection(direction);
moveAction.setNode(selected.getObjectId(modeController));
// selectedNodes list
for (Iterator i = selecteds.iterator(); i.hasNext();) {
MindMapNode node = (MindMapNode) i.next();
NodeListMember nodeListMember = new NodeListMember();
nodeListMember.setNode(node.getObjectId(modeController));
moveAction.addNodeListMember(nodeListMember);
}
return moveAction;
}
}