blob: 00bf70951ea52747984c0099092a3e058ee07bd8 [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.diagram.core.actions;
import java.util.Iterator;
import java.util.List;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.emf.transaction.impl.InternalTransactionalEditingDomain;
import org.eclipse.epf.diagram.core.DiagramCoreResources;
import org.eclipse.epf.diagram.core.commands.ChangeBoundsCommand;
import org.eclipse.epf.diagram.core.commands.ReconnectLinkCommand;
import org.eclipse.epf.diagram.core.util.DiagramCoreUtil;
import org.eclipse.gef.DefaultEditDomain;
import org.eclipse.gef.EditPart;
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.gef.ui.actions.GEFActionConstants;
import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil;
import org.eclipse.gmf.runtime.diagram.ui.actions.ActionIds;
import org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionNodeEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeNodeEditPart;
import org.eclipse.gmf.runtime.notation.Edge;
import org.eclipse.gmf.runtime.notation.Node;
import org.eclipse.gmf.runtime.notation.NotationPackage;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
/**
* Service class to allow create and register common actions to the action
* register. Code is migrate from old method of diagramming.
*
* @author Shashidhar Kannoori
* @since 1.2
*/
public class DiagramActionsService {
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;
private InternalTransactionalEditingDomain transactionDomain;
/**
* Constructor
* @param graphicalViewer {@link GraphicalViewer}
* @param editDomain {@link DefaultEditDomain}
* @param actionRegistry {@link ActionRegistry}
*/
public DiagramActionsService(InternalTransactionalEditingDomain transactionDomain, GraphicalViewer graphicalViewer,
DefaultEditDomain editDomain, ActionRegistry actionRegistry) {
this.transactionDomain = transactionDomain;
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(
DiagramCoreResources.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(
DiagramCoreResources.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(
DiagramCoreResources.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(
DiagramCoreResources.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 ShapeNodeEditPart) {
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(transactionDomain,
(Node) ep.getModel(), new Point(bounds.x, firstPart
.getFigure().getBounds().y
- offset), bounds.width, -1);
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 ShapeNodeEditPart) {
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 ShapeNodeEditPart) {
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(transactionDomain,
(Node) ep.getModel(),
new Point(bounds.x, yave - offset), bounds.width, -1);
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 ShapeNodeEditPart) {
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 ShapeNodeEditPart) {
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(transactionDomain,
(Node) ep.getModel(),
new Point(xave - offset, bounds.y), bounds.width, -1);
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 ShapeNodeEditPart) {
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 ShapeNodeEditPart) {
AbstractGraphicalEditPart ep = (AbstractGraphicalEditPart) editParts
.get(a);
// we can skip the first one since this is an align-to
if (ep != alignToPart
&& !(DiagramCoreUtil.isSyncBar(alignToPart))) {
// calculate the offset for centerline alignment
if (!(DiagramCoreUtil.isSyncBar(ep))) {
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(transactionDomain,
(Node) ep.getModel(), new Point(alignToPart
.getFigure().getBounds().x
- offset, bounds.y), bounds.width, -1);
getCommandStack().execute(c);
ep.getFigure().setLocation(
new Point(alignToPart.getFigure().getBounds().x
- offset, bounds.y));
} else {
Point tp = ep.getFigure().getBounds().getCenter();
boolean connected = false;
boolean source = false;
Point endPoint = null;
ConnectionNodeEditPart lp = null;
// check target connections
List list = ((ShapeNodeEditPart) ep).getTargetConnections();
for (Iterator itor = list.iterator(); itor.hasNext();) {
lp = (ConnectionNodeEditPart) itor.next();
if (lp.getSource().equals(alignToPart)) {
connected = true;
break;
}
}
// check source connections if not found in target connections
if (!connected) {
list = ((ShapeNodeEditPart) ep).getSourceConnections();
for (Iterator itor = list.iterator(); itor
.hasNext();) {
lp = (ConnectionNodeEditPart) itor.next();
if (lp.getTarget().equals(alignToPart)) {
connected = true;
source = true;
break;
}
}
}
if (connected && (alignToPart instanceof ShapeNodeEditPart)) {
Point centerPoint = alignToPart.getFigure()
.getBounds().getCenter();
int delta = centerPoint.x - tp.x;
endPoint.x += delta;
ReconnectLinkCommand c = new ReconnectLinkCommand(transactionDomain,
(Edge) 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
&& !(DiagramCoreUtil.isSyncBar(alignToPart))) {
Point sp = alignToPart.getFigure().getBounds()
.getCenter();
boolean connected = false;
// check if the part is connected via source connections
List list = ((ShapeNodeEditPart) alignToPart)
.getSourceConnections();
for (Iterator itor = list.iterator(); itor.hasNext();) {
ConnectionNodeEditPart lp = (ConnectionNodeEditPart) itor.next();
if (lp.getTarget().equals(ep)) {
connected = true;
break;
}
}
// if not found above, check if it is connected via target connections
if (!connected) {
list = ((ShapeNodeEditPart) alignToPart)
.getTargetConnections();
for (Iterator itor = list.iterator(); itor.hasNext();) {
ConnectionNodeEditPart lp = (ConnectionNodeEditPart) itor.next();
if (lp.getSource().equals(ep)) {
connected = true;
break;
}
}
}
if (DiagramCoreUtil.isSyncBar(ep)) {
Point p = new Point();
p.x = ((Integer) ViewUtil.getStructuralFeatureValue((View)ep.getModel(),
NotationPackage.eINSTANCE.getLocation_X())).intValue();
p.y = ((Integer) ViewUtil.getStructuralFeatureValue((View)ep.getModel(),
NotationPackage.eINSTANCE.getLocation_Y())).intValue();
Point tp = p.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(transactionDomain,
(Node) ep.getModel(), tp, ep.getFigure()
.getBounds().width, -1);
getCommandStack().execute(c);
ep.getFigure().setLocation(new Point(tp.x, tp.y));
} else if (ep instanceof ShapeNodeEditPart) {
Point p = new Point();
p.x = ((Integer) ViewUtil.getStructuralFeatureValue((View)ep.getModel(),
NotationPackage.eINSTANCE.getLocation_X())).intValue();
p.y = ((Integer) ViewUtil.getStructuralFeatureValue((View)ep.getModel(),
NotationPackage.eINSTANCE.getLocation_Y())).intValue();
Point tp = p.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(transactionDomain,
(Node) ep.getModel(), tp, ep.getFigure()
.getBounds().width, -1);
getCommandStack().execute(c);
ep.getFigure().setLocation(new Point(tp.x, tp.y));
}
}
}
}
}
public void createAlignMenu(IMenuManager menu, boolean canModify) {
// create a new menu manager for the cascading menu
IContributionItem formatMenu = menu.find(ActionIds.MENU_FORMAT);
MenuManager alignMenuManager = null;
if (alignMenuManager == null) {
alignMenuManager = new MenuManager(
DiagramCoreResources.AbstractDiagramEditor_alignMenu_text) { //$NON-NLS-1$
public boolean isEnabled() {
int total = 0;
// enable the menu only if 2 or more nodes or node
// containers
// are selected
List editParts = graphicalViewer.getSelectedEditParts();
// need at least two things selected to align
if (editParts.size() > 1) {
for (int a = 0; a < editParts.size(); a++) {
EditPart editPart = (EditPart) editParts.get(a);
// we can align nodes and containers
if (editPart instanceof ShapeNodeEditPart) {
// add up the elements we need, there may be
// more
// elements selected (links, etc.)
total++;
if (total > 1) {
// we only need to know there is more than
// 1, so
// we can stop here
break;
}
}
}
}
return total > 1;
}
};
}
if (formatMenu != null && formatMenu instanceof IMenuManager
&& alignMenuManager.isEnabled() && canModify) {
IContributionItem item = ((IMenuManager)formatMenu).find(ActionIds.MENU_ALIGN);
if(item != null && item instanceof IMenuManager){
IMenuManager alignMenu = (IMenuManager)item;
alignMenu.add(getActionRegistry().getAction(
DiagramActionsService.ALIGN_HORZ_AVERAGE));
alignMenu.add(getActionRegistry().getAction(
DiagramActionsService.ALIGN_HORZ_FIRST_SELECTED));
alignMenu.add(getActionRegistry().getAction(
DiagramActionsService.ALIGN_VERT_AVERAGE));
alignMenu.add(getActionRegistry().getAction(
DiagramActionsService.ALIGN_VERT_FIRST_SELECTED));
}
}else{
alignMenuManager.add(getActionRegistry().getAction(
DiagramActionsService.ALIGN_HORZ_AVERAGE));
alignMenuManager.add(getActionRegistry().getAction(
DiagramActionsService.ALIGN_HORZ_FIRST_SELECTED));
alignMenuManager.add(getActionRegistry().getAction(
DiagramActionsService.ALIGN_VERT_AVERAGE));
alignMenuManager.add(getActionRegistry().getAction(
DiagramActionsService.ALIGN_VERT_FIRST_SELECTED));
if (alignMenuManager.isEnabled() && canModify) {
menu.appendToGroup(GEFActionConstants.MB_ADDITIONS,
new Separator());
menu.appendToGroup(GEFActionConstants.MB_ADDITIONS, alignMenuManager);
menu.appendToGroup(GEFActionConstants.MB_ADDITIONS,
new Separator());
}
}
}
}