blob: 17c29c4625ae3bf27a48a799e339aef2ebf8d2b4 [file] [log] [blame]
//------------------------------------------------------------------------------
// Copyright (c) 2005, 2006 IBM Corporation and others.
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// which accompanies this distribution, and is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// Contributors:
// IBM Corporation - initial implementation
//------------------------------------------------------------------------------
package org.eclipse.epf.authoring.gef.edit;
import java.util.Iterator;
import java.util.List;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.epf.authoring.gef.commands.ChangeBoundsCommand;
import org.eclipse.epf.authoring.gef.commands.ReconnectLinkCommand;
import org.eclipse.epf.authoring.gef.util.DiagramUIResources;
import org.eclipse.epf.diagram.model.Link;
import org.eclipse.epf.diagram.model.Node;
import org.eclipse.gef.DefaultEditDomain;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.commands.CommandStack;
import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
import org.eclipse.gef.ui.actions.ActionRegistry;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
/**
* Service class to allow create and register common action to the action
* register. Most of the code are moved from the Editor class.
*
* @author Jinhua Xi
* @since 1.0
*/
public class DiagramActionService {
public static final String ALIGN_HORZ_AVERAGE = "align_horizontal_to_average"; //$NON-NLS-1$
public static final String ALIGN_HORZ_FIRST_SELECTED = "align_horizontal_to_first_selection"; //$NON-NLS-1$
public static final String ALIGN_VERT_AVERAGE = "align_vertical_to_average"; //$NON-NLS-1$
public static final String ALIGN_VERT_FIRST_SELECTED = "align_vertical_to_first_selection"; //$NON-NLS-1$
private DefaultEditDomain editDomain;
private GraphicalViewer graphicalViewer;
private ActionRegistry actionRegistry;
/**
* Constructor
* @param graphicalViewer {@link GraphicalViewer}
* @param editDomain {@link DefaultEditDomain}
* @param actionRegistry {@link ActionRegistry}
*/
public DiagramActionService(GraphicalViewer graphicalViewer,
DefaultEditDomain editDomain, ActionRegistry actionRegistry) {
this.graphicalViewer = graphicalViewer;
this.editDomain = editDomain;
this.actionRegistry = actionRegistry;
}
/**
* Sets the GraphicalViewer.
*/
public void setGraphicalViewer(GraphicalViewer graphicalViewer) {
this.graphicalViewer = graphicalViewer;
}
/**
* returns GraphicalViewer
*/
private GraphicalViewer getGraphicalViewer() {
return graphicalViewer;
}
/**
* Returns the command stack.
*
* @return the command stack
*/
protected CommandStack getCommandStack() {
return getEditDomain().getCommandStack();
}
/**
* Returns the edit domain.
*
* @return the edit domain
*/
protected DefaultEditDomain getEditDomain() {
return editDomain;
}
protected ActionRegistry getActionRegistry() {
return actionRegistry;
}
/**
* Register HorizontalAlignAverageAction action.
* HorizontalAignAverage Action aligns selected editparts to horizontal average.
*/
public IAction registerHorizontalAlignAverageAction() {
// align horizontally to average y-value of all nodes
IAction hAlignAverageAction = new Action(
DiagramUIResources.AbstractDiagramEditor_hAlignAverageAction_text) { //$NON-NLS-1$
public void run() {
horizAlignToAverageSelected();
}
public String getId() {
return ALIGN_HORZ_AVERAGE;
}
};
getActionRegistry().registerAction(hAlignAverageAction);
return hAlignAverageAction;
}
/**
* Register HorizontalAlignFirstSelectedAction action.
* HorizontalAlignFirstSelectedAction aligns selected editparts with
* respect to first selected editpart.
*/
public IAction registerHorizontalAlignFirstSelectedAction() {
// align horizontally to y-value of first selected node
IAction hAlignFirstSelectedAction = new Action(
DiagramUIResources.AbstractDiagramEditor_hAlignFirstSelectedAction_text) { //$NON-NLS-1$
public void run() {
horzAlignToFirstSelected();
}
public String getId() {
return ALIGN_HORZ_FIRST_SELECTED;
}
};
getActionRegistry().registerAction(hAlignFirstSelectedAction);
return hAlignFirstSelectedAction;
}
/**
* Register vertialAlignAverageAction action.
* vertialAlignAverageAction aligns selected editparts vertically w.r.t average.
*
*/
public IAction registerVerticalAlignAverageAction() {
// align vertically to average x-value of all selected nodes
IAction vAlignAverageAction = new Action(
DiagramUIResources.AbstractDiagramEditor_vAlignAverageAction_text) { //$NON-NLS-1$
public void run() {
verticalAlignToAverageSelected();
}
public String getId() {
return ALIGN_VERT_AVERAGE;
}
};
getActionRegistry().registerAction(vAlignAverageAction);
return vAlignAverageAction;
}
/**
* Register vertialAlignFirstSelectedAction action.
* vertialAlignFirstSelectedAction aligns selected editparts vertically w.r.t first selected.
*
*/
public IAction registerVerticalAlignFirstSelectedAction() {
// align vertically to x-value of first selected node
IAction vAlignFirstSelectedAction = new Action(
DiagramUIResources.AbstractDiagramEditor_vAlignFirstSelectedAction_text) { //$NON-NLS-1$
public void run() {
verticalAlignToFirstSelected();
}
public String getId() {
return ALIGN_VERT_FIRST_SELECTED;
}
};
getActionRegistry().registerAction(vAlignFirstSelectedAction);
return vAlignFirstSelectedAction;
}
// /////////////////////////////////////////////////////////////////////////////////////////////////
// action methods
// /////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Action implementation method for horizontalAlignFirsteSElectedAction.
*
*/
public void horzAlignToFirstSelected() {
List editParts = getGraphicalViewer().getSelectedEditParts();
AbstractGraphicalEditPart firstPart = null;
// loop through all selected items, remember the y-value of the
// first node,
// set the following nodes to the same y-value
for (int a = 0; a < editParts.size(); a++) {
if (editParts.get(a) instanceof NodeEditPart
|| editParts.get(a) instanceof NodeContainerEditPart) {
AbstractGraphicalEditPart ep = (AbstractGraphicalEditPart) editParts
.get(a);
// remember the first part we move
if (firstPart == null) {
firstPart = ep;
} else {
// calculate the offset for centerline alignment
Rectangle bounds = ep.getFigure().getBounds();
int offset = (int) ((double) (bounds.height - firstPart
.getFigure().getBounds().height) / 2.0);
// is this node in a container?
if (!(ep.getParent() instanceof DiagramEditPart)) {
// need to move the container, adjust the offset
ep = (AbstractGraphicalEditPart) ep.getParent();
Rectangle parentBounds = ep.getFigure().getBounds();
offset += bounds.y - parentBounds.y;
bounds = parentBounds;
}
// send the command to move the node
org.eclipse.gef.commands.Command c = new ChangeBoundsCommand(
(Node) ep.getModel(), new Point(bounds.x, firstPart
.getFigure().getBounds().y
- offset), bounds.width);
getCommandStack().execute(c);
}
}
}
}
/**
* Action implementation method for horizontalAlignAverageAction.
*
*/
public void horizAlignToAverageSelected() {
List editParts = getGraphicalViewer().getSelectedEditParts();
AbstractGraphicalEditPart firstPart = null;
int total = 0;
int ysum = 0;
for (int a = 0; a < editParts.size(); a++) {
if (editParts.get(a) instanceof NodeEditPart
|| editParts.get(a) instanceof NodeContainerEditPart) {
AbstractGraphicalEditPart ep = (AbstractGraphicalEditPart) editParts
.get(a);
// remember the first part we move
if (firstPart == null) {
firstPart = ep;
}
ysum += ep.getFigure().getBounds().y;
total++;
}
}
// calculate the average y-value for all nodes
int yave = (int) ((double) ysum / (double) total);
// loop through all the nodes again and set them
for (int a = 0; a < editParts.size(); a++) {
if (editParts.get(a) instanceof NodeEditPart
|| editParts.get(a) instanceof NodeContainerEditPart) {
AbstractGraphicalEditPart ep = (AbstractGraphicalEditPart) editParts
.get(a);
// calculate the height difference, so that elements are aligned
// through the centerline
Rectangle bounds = ep.getFigure().getBounds();
int offset = (int) ((double) (bounds.height - firstPart
.getFigure().getBounds().height) / 2.0);
// is this node inside a container?
if (!(ep.getParent() instanceof DiagramEditPart)) {
// we need to move the container, adjust the offset
ep = (AbstractGraphicalEditPart) ep.getParent();
Rectangle parentBounds = ep.getFigure().getBounds();
offset += bounds.y - parentBounds.y;
bounds = parentBounds;
}
// send the command to move the node
org.eclipse.gef.commands.Command c = new ChangeBoundsCommand(
(Node) ep.getModel(),
new Point(bounds.x, yave - offset), bounds.width);
getCommandStack().execute(c);
}
}
}
/**
* Action implementation method for verticalAlignToAverageAction.
*
*/
public void verticalAlignToAverageSelected() {
List editParts = getGraphicalViewer().getSelectedEditParts();
AbstractGraphicalEditPart firstPart = null;
int total = 0;
int xsum = 0;
// loop through the selected parts
for (int a = 0; a < editParts.size(); a++) {
// we are only interested in nodes and containers
if (editParts.get(a) instanceof NodeEditPart
|| editParts.get(a) instanceof NodeContainerEditPart) {
AbstractGraphicalEditPart ep = (AbstractGraphicalEditPart) editParts
.get(a);
if (firstPart == null) {
firstPart = ep;
}
// sum the x coordinates of each element
xsum += ep.getFigure().getBounds().x;
// remember how many selected elements applied to this operation
total++;
}
}
// calculate the average x-value for all nodes
int xave = (int) ((double) xsum / (double) total);
// loop through all the nodes again and set them
for (int a = 0; a < editParts.size(); a++) {
if (editParts.get(a) instanceof NodeEditPart
|| editParts.get(a) instanceof NodeContainerEditPart) {
AbstractGraphicalEditPart ep = (AbstractGraphicalEditPart) editParts
.get(a);
// calculate the offset for centerline alignment
Rectangle bounds = ep.getFigure().getBounds();
int offset = (int) ((double) (bounds.width - firstPart
.getFigure().getBounds().width) / 2.0);
// are we inside a container?
if (!(ep.getParent() instanceof DiagramEditPart)) {
// adjust the offset since we have to move the container
ep = (AbstractGraphicalEditPart) ep.getParent();
Rectangle parentBounds = ep.getFigure().getBounds();
offset += bounds.x - parentBounds.x;
bounds = parentBounds;
}
// send the command to move the element
org.eclipse.gef.commands.Command c = new ChangeBoundsCommand(
(Node) ep.getModel(),
new Point(xave - offset, bounds.y), bounds.width);
getCommandStack().execute(c);
}
}
}
/**
* Action implementation method for verticalAlignToFirstSelectedAction.
*
*/
public void verticalAlignToFirstSelected() {
// get the selected items
List editParts = getGraphicalViewer().getSelectedEditParts();
AbstractGraphicalEditPart alignToPart = null;
// find the first diagram part we can align to
for (int a = 0; a < editParts.size(); a++) {
if (editParts.get(a) instanceof NodeEditPart
|| editParts.get(a) instanceof NodeContainerEditPart) {
AbstractGraphicalEditPart ep = (AbstractGraphicalEditPart) editParts
.get(a);
if (alignToPart == null) {
// remember it and stop
alignToPart = ep;
break;
}
}
}
// loop through the elements and set their new position
for (int a = 0; a < editParts.size(); a++) {
if (editParts.get(a) instanceof NodeEditPart
|| editParts.get(a) instanceof NodeContainerEditPart) {
AbstractGraphicalEditPart ep = (AbstractGraphicalEditPart) editParts
.get(a);
// we can skip the first one since this is an align-to
if (ep != alignToPart
&& !(alignToPart instanceof SynchBarNodeEditPart)) {
// calculate the offset for centerline alignment
if (!(ep instanceof SynchBarNodeEditPart)) {
Rectangle bounds = ep.getFigure().getBounds();
int offset = (int) ((double) (bounds.width - alignToPart
.getFigure().getBounds().width) / 2.0);
// is this inside a container?
if (!(ep.getParent() instanceof DiagramEditPart)) {
// adjust the offset since we are moving the
// container
ep = (AbstractGraphicalEditPart) ep.getParent();
Rectangle parentBounds = ep.getFigure().getBounds();
offset += bounds.x - parentBounds.x;
bounds = parentBounds;
}
// send the command to move the element
org.eclipse.gef.commands.Command c = new ChangeBoundsCommand(
(Node) ep.getModel(), new Point(alignToPart
.getFigure().getBounds().x
- offset, bounds.y), bounds.width);
getCommandStack().execute(c);
ep.getFigure().setLocation(
new Point(alignToPart.getFigure().getBounds().x
- offset, bounds.y));
} else {
Point tp = ep.getFigure().getBounds().getLocation();
boolean connected = false;
boolean source = false;
Point endPoint = null;
LinkEditPart lp = null;
// check target connections
List list = ((NodeEditPart) ep).getTargetConnections();
for (Iterator itor = list.iterator(); itor.hasNext();) {
lp = (LinkEditPart) itor.next();
if (lp.getSource().equals(alignToPart)) {
endPoint = ((Link) lp.getModel())
.getTargetEndPoint();
tp = tp.getTranslated(endPoint);
connected = true;
break;
}
}
// check source connections if not found in target connections
if (!connected) {
list = ((NodeEditPart) ep).getSourceConnections();
for (Iterator itor = list.iterator(); itor
.hasNext();) {
lp = (LinkEditPart) itor.next();
if (lp.getTarget().equals(alignToPart)) {
endPoint = ((Link) lp.getModel())
.getSourceEndPoint();
tp = tp.getTranslated(endPoint);
connected = true;
source = true;
break;
}
}
}
if (connected && (alignToPart instanceof NodeEditPart)) {
Point centerPoint = alignToPart.getFigure()
.getBounds().getCenter();
int delta = centerPoint.x - tp.x;
endPoint.x += delta;
ReconnectLinkCommand c = new ReconnectLinkCommand(
(Link) lp.getModel(), (Node) ep.getModel(),
source);
c.setEndPoint(endPoint);
getCommandStack().execute(c);
}
}
}
// If first selected edit part is syncbarnodeeditpart, need to
// handle differently
if (ep != alignToPart
&& (alignToPart instanceof SynchBarNodeEditPart)) {
Point sp = alignToPart.getFigure().getBounds()
.getLocation();
boolean connected = false;
// check if the part is connected via source connections
List list = ((NodeEditPart) alignToPart)
.getSourceConnections();
for (Iterator itor = list.iterator(); itor.hasNext();) {
LinkEditPart lp = (LinkEditPart) itor.next();
if (lp.getTarget().equals(ep)) {
Point sourceEndPoint = ((Link) lp.getModel())
.getSourceEndPoint();
sp = sp.getTranslated(sourceEndPoint);
connected = true;
break;
}
}
// if not found above, check if it is connected via target connections
if (!connected) {
list = ((NodeEditPart) alignToPart)
.getTargetConnections();
for (Iterator itor = list.iterator(); itor.hasNext();) {
LinkEditPart lp = (LinkEditPart) itor.next();
if (lp.getSource().equals(ep)) {
Point targetEndPoint = ((Link) lp.getModel())
.getTargetEndPoint();
sp = sp.getTranslated(targetEndPoint);
connected = true;
break;
}
}
}
if (ep instanceof SynchBarNodeEditPart) {
Point tp = ((Node) ep.getModel()).getLocation()
.getCopy();
Point alignToCenter = alignToPart.getFigure().getBounds().getCenter();
Point centerPoint = ep.getFigure().getBounds().getCenter();
int delta = alignToCenter.x - centerPoint.x;
tp.x = tp.x + delta;
org.eclipse.gef.commands.Command c = new ChangeBoundsCommand(
(Node) ep.getModel(), tp, ep.getFigure()
.getBounds().width);
getCommandStack().execute(c);
ep.getFigure().setLocation(new Point(tp.x, tp.y));
} else if (ep instanceof NodeEditPart) {
Point tp = ((Node) ep.getModel()).getLocation()
.getCopy();
Point centerPoint = ep.getFigure().getBounds()
.getCenter();
int delta = sp.x - centerPoint.x;
tp.x = tp.x + delta;
org.eclipse.gef.commands.Command c = new ChangeBoundsCommand(
(Node) ep.getModel(), tp, ep.getFigure()
.getBounds().width);
getCommandStack().execute(c);
ep.getFigure().setLocation(new Point(tp.x, tp.y));
}
}
}
}
}
}