AlignCommand.java
/*
* @(#)AlignCommand.java
*
* Project: JHotdraw - a GUI framework for technical drawings
* http://www.jhotdraw.org
* http://jhotdraw.sourceforge.net
* Copyright: © by the original author(s) and all contributors
* License: Lesser GNU Public License (LGPL)
* http://www.opensource.org/licenses/lgpl-license.html
*/
package CH.ifa.draw.standard;
import CH.ifa.draw.framework.*;
import CH.ifa.draw.util.UndoableAdapter;
import CH.ifa.draw.util.Undoable;
import java.util.*;
import java.awt.*;
/**
* Align a selection of figures relative to each other.
*
* @version <$CURRENT_VERSION$>
*/
public class AlignCommand extends AbstractCommand {
public static abstract class Alignment {
/**
* align left sides
*/
public final static Alignment LEFTS = new Alignment("Lefts") {
public void moveBy(Figure f, Rectangle anchor) {
Rectangle rr = f.displayBox();
f.moveBy(anchor.x-rr.x, 0);
}
};
/**
* align centers (horizontally)
*/
public final static Alignment CENTERS = new Alignment("Centers") {
public void moveBy(Figure f, Rectangle anchor) {
Rectangle rr = f.displayBox();
f.moveBy((anchor.x+anchor.width/2) - (rr.x+rr.width/2), 0);
}
};
/**
* align right sides
*/
public final static Alignment RIGHTS = new Alignment("Rights") {
public void moveBy(Figure f, Rectangle anchor) {
Rectangle rr = f.displayBox();
f.moveBy((anchor.x+anchor.width) - (rr.x+rr.width), 0);
}
};
/**
* align tops
*/
public final static Alignment TOPS = new Alignment("Tops") {
public void moveBy(Figure f, Rectangle anchor) {
Rectangle rr = f.displayBox();
f.moveBy(0, anchor.y-rr.y);
}
};
/**
* align middles (vertically)
*/
public final static Alignment MIDDLES = new Alignment("Middles") {
public void moveBy(Figure f, Rectangle anchor) {
Rectangle rr = f.displayBox();
f.moveBy(0, (anchor.y+anchor.height/2) - (rr.y+rr.height/2));
}
};
/**
* align bottoms
*/
public final static Alignment BOTTOMS = new Alignment("Bottoms") {
public void moveBy(Figure f, Rectangle anchor) {
Rectangle rr = f.displayBox();
f.moveBy(0, (anchor.y+anchor.height) - (rr.y+rr.height));
}
};
private String myDescription;
private Alignment(String newDescription) {
setDescription(newDescription);
}
public String toString() {
return getDescription();
}
public String getDescription() {
return myDescription;
}
private void setDescription(String newDescription) {
myDescription = newDescription;
}
public abstract void moveBy(Figure f, Rectangle anchor);
}
private Alignment myAlignment;
/**
* Constructs an alignment command.
* @param newAlignment the alignment operation (LEFTS, CENTERS, RIGHTS, etc.)
* @param newDrawingEditor the DrawingEditor which manages the views
*/
public AlignCommand(Alignment newAlignment, DrawingEditor newDrawingEditor) {
super(newAlignment.getDescription(), newDrawingEditor);
setAlignment(newAlignment);
}
protected boolean isExecutableWithView() {
return view().selectionCount() > 1;
}
public void execute() {
super.execute();
setUndoActivity(createUndoActivity());
// get selected figures in the order the figures have been selected
getUndoActivity().setAffectedFigures(new FigureEnumerator(view().selection()));
((AlignCommand.UndoActivity)getUndoActivity()).alignAffectedFigures(getAlignment());
view().checkDamage();
}
protected void setAlignment(Alignment newAlignment) {
myAlignment = newAlignment;
}
public Alignment getAlignment() {
return myAlignment;
}
/**
* Factory method for undo activity
*/
protected Undoable createUndoActivity() {
return new AlignCommand.UndoActivity(view(), getAlignment());
}
public static class UndoActivity extends UndoableAdapter {
private Hashtable myOriginalPoints;
private Alignment myAppliedAlignment;
public UndoActivity(DrawingView newView, Alignment newAlignment) {
super(newView);
myOriginalPoints = new Hashtable();
setAppliedAlignment(newAlignment);
setUndoable(true);
setRedoable(true);
}
public boolean undo() {
if (!super.undo()) {
return false;
}
FigureEnumeration k = getAffectedFigures();
while (k.hasMoreElements()) {
Figure f = k.nextFigure();
Point originalPoint = getOriginalPoint(f);
Point currentPoint = f.displayBox().getLocation();
// substract current lcoation to get to 0,0 and then move to original location
f.moveBy(-currentPoint.x + originalPoint.x,
-currentPoint.y + originalPoint.y);
}
return true;
}
public boolean redo() {
if (!isRedoable()) {
return false;
}
alignAffectedFigures(getAppliedAlignment());
return true;
}
protected void setAppliedAlignment(Alignment newAlignment) {
myAppliedAlignment = newAlignment;
}
public Alignment getAppliedAlignment() {
return myAppliedAlignment;
}
protected void addOriginalPoint(Figure f) {
myOriginalPoints.put(f, f.displayBox().getLocation());
}
public Point getOriginalPoint(Figure f) {
return (Point)myOriginalPoints.get(f);
}
public void alignAffectedFigures(Alignment applyAlignment) {
FigureEnumeration fe = getAffectedFigures();
Figure anchorFigure = fe.nextFigure();
Rectangle r = anchorFigure.displayBox();
while (fe.hasMoreElements()) {
Figure f = fe.nextFigure();
applyAlignment.moveBy(f, r);
}
}
public void setAffectedFigures(FigureEnumeration fe) {
// first make copy of FigureEnumeration in superclass
super.setAffectedFigures(fe);
// then get new FigureEnumeration of copy to save aligment
FigureEnumeration copyFe = getAffectedFigures();
while (copyFe.hasMoreElements()) {
addOriginalPoint(copyFe.nextFigure());
}
}
}
}