blob: 9078a46ce559041f2e480869a6ef8dae25d34db4 [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.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.draw2d.ToolbarLayout;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.epf.authoring.gef.commands.ChangeBoundsCommand;
import org.eclipse.epf.diagram.model.Node;
import org.eclipse.gef.DefaultEditDomain;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CommandStack;
import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
import org.eclipse.gef.ui.actions.ActionRegistry;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.StructuredSelection;
/**
* Service class to allow updating diagram to a default layout. Most of the code
* are moved from the Editor class.
*
* @author Jinhua Xi
* @since 1.0
*/
public class DiagramUpdateService {
private DefaultEditDomain editDomain;
private GraphicalViewer graphicalViewer;
private ActionRegistry actionRegistry;
public DiagramUpdateService(
GraphicalViewer graphicalViewer, DefaultEditDomain editDomain,
ActionRegistry actionRegistry) {
this.graphicalViewer = graphicalViewer;
this.editDomain = editDomain;
this.actionRegistry = actionRegistry;
}
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;
}
/**
* Lazily creates and returns the action registry.
*
* @return the action registry
*/
protected ActionRegistry getActionRegistry() {
return actionRegistry;
}
/**
* Method used only in ActivityDetailDiagram or any diagram need auto-layout.
* Method will verify recently added editparts in the Activitydetaildiagram editpart
* indirectly from WorkBreakdownStructure (means any descriptors created in wbs, corresponding
* EditPart will get created in ActivityDetailDiagram Viewer) and does auto-layout
* all the new added editparts and existing ones.
*
*/
public void cleanUpDiagram() {
if (getGraphicalViewer().getContents() instanceof ActivityDetailDiagramEditPart) {
ActivityDetailDiagramEditPart dep = (ActivityDetailDiagramEditPart) getGraphicalViewer()
.getContents();
List children = dep.getRecentlyAddedParts();
if (!children.isEmpty()) {
Comparator comparator = new Comparator() {
public int compare(Object arg0, Object arg1) {
int rc = 0;
if (arg0 instanceof RoleTaskCompositeEditPart) {
if (!(arg1 instanceof RoleTaskCompositeEditPart))
rc = -1;
} else if (arg1 instanceof RoleTaskCompositeEditPart)
rc = 1;
return rc;
}
};
Object[] array = children.toArray();
Arrays.sort(array, comparator);
for (int a = 0; a < array.length; a++) {
AbstractGraphicalEditPart ep = (AbstractGraphicalEditPart) array[a];
adjustSize(ep);
}
for (int b = 0; b < array.length; b++) {
AbstractGraphicalEditPart ep = (AbstractGraphicalEditPart) array[b];
cleanUp(ep);
}
for (int c = 0; c < array.length; c++) {
AbstractGraphicalEditPart ep = (AbstractGraphicalEditPart) array[c];
reduceLinkLength(ep);
}
// for (int c = 0; c < array.length; c++) {
// AbstractGraphicalEditPart ep = (AbstractGraphicalEditPart) array[c];
// if(ep instanceof RoleTaskCompositeEditPart){
// resetSizes(ep, ep);
// }
// }
packDiagram();
dep.clearRecentlyAddedParts();
getGraphicalViewer().setSelection(new StructuredSelection());
}
}
}
/*
private void resetSizes(AbstractGraphicalEditPart ep, AbstractGraphicalEditPart parent) {
if (!(ep instanceof WorkProductCompositeEditPart)) {
List sourceLinks = ep.getSourceConnections();
if (sourceLinks.size() > 0) {
for (int b = 0; b < sourceLinks.size(); b++) {
LinkEditPart link = (LinkEditPart) sourceLinks.get(b);
AbstractGraphicalEditPart target = (AbstractGraphicalEditPart) link
.getTarget();
int w = target.getFigure().getBounds().width;
int ew = ep.getFigure().getPreferredSize().width;
if (w > ew) {
Point location = ep.getFigure().getBounds()
.getLocation();
location.x+=(w-ew)/2;
Command c = new ChangeBoundsCommand(((Node) ep
.getModel()), ep.getFigure().getBounds()
.getLocation(), w);
getCommandStack().execute(c);
int h = ep.getFigure().getPreferredSize().height;
ep.getFigure()
.setPreferredSize(new Dimension(w, h));
ep.getFigure().setSize(new Dimension(w, h));
}
getGraphicalViewer()
.setSelection(
new StructuredSelection(new Object[] { ep,
target }));
IAction valign = getActionRegistry().getAction(
DiagramActionService.ALIGN_VERT_FIRST_SELECTED);
valign.run();
}
}
List targetLinks = ep.getTargetConnections();
if (targetLinks.size() > 0) {
for (int b = 0; b < targetLinks.size(); b++) {
LinkEditPart link = (LinkEditPart) targetLinks.get(b);
AbstractGraphicalEditPart source = (AbstractGraphicalEditPart) link
.getSource();
int w = source.getFigure().getBounds().width;
int ew = ep.getFigure().getPreferredSize().width;
if (w > ew) {
Command c = new ChangeBoundsCommand(((Node) ep
.getModel()), ep.getFigure().getBounds()
.getLocation(), w);
getCommandStack().execute(c);
int h = ep.getFigure().getPreferredSize().height;
ep.getFigure()
.setPreferredSize(new Dimension(w, h));
ep.getFigure().setSize(new Dimension(w, h));
}
getGraphicalViewer()
.setSelection(
new StructuredSelection(new Object[] { ep,
source }));
IAction valign = getActionRegistry().getAction(
DiagramActionService.ALIGN_VERT_FIRST_SELECTED);
valign.run();
}
}
parent.getFigure().getLayoutManager().layout(parent.getFigure());
if (ep instanceof NodeContainerEditPart) {
List children = ep.getChildren();
for (int d = 0; d < children.size(); d++) {
AbstractGraphicalEditPart p = (AbstractGraphicalEditPart) children
.get(d);
resetSizes(p, ep);
}
}
}
}
*/
/**
* This method does a vertical alignment of all nodes with links
*/
private void cleanUp(AbstractGraphicalEditPart ep) {
if (!(ep instanceof WorkProductCompositeEditPart)) {
List sourceLinks = ep.getSourceConnections();
if (sourceLinks.size() > 0) {
for (int b = 0; b < sourceLinks.size(); b++) {
LinkEditPart link = (LinkEditPart) sourceLinks.get(b);
AbstractGraphicalEditPart target = (AbstractGraphicalEditPart) link
.getTarget();
int w = target.getFigure().getBounds().width;
int ew = ep.getFigure().getPreferredSize().width;
if (w < ew) {
Command c = new ChangeBoundsCommand(((Node) ep
.getModel()), target.getFigure().getBounds()
.getLocation(), w);
getCommandStack().execute(c);
int h = target.getFigure().getPreferredSize().height;
target.getFigure()
.setPreferredSize(new Dimension(w, h));
target.getFigure().setSize(new Dimension(w, h));
}
getGraphicalViewer()
.setSelection(
new StructuredSelection(new Object[] { ep,
target }));
IAction valign = getActionRegistry().getAction(
DiagramActionService.ALIGN_VERT_FIRST_SELECTED);
valign.run();
}
}
List targetLinks = ep.getTargetConnections();
if (targetLinks.size() > 0) {
for (int b = 0; b < targetLinks.size(); b++) {
LinkEditPart link = (LinkEditPart) targetLinks.get(b);
AbstractGraphicalEditPart source = (AbstractGraphicalEditPart) link
.getSource();
int w = source.getFigure().getBounds().width;
int ew = ep.getFigure().getPreferredSize().width;
if (w < ew) {
Command c = new ChangeBoundsCommand(((Node) ep
.getModel()), source.getFigure().getBounds()
.getLocation(), w);
getCommandStack().execute(c);
int h = source.getFigure().getPreferredSize().height;
source.getFigure()
.setPreferredSize(new Dimension(w, h));
source.getFigure().setSize(new Dimension(w, h));
}
getGraphicalViewer()
.setSelection(
new StructuredSelection(new Object[] { ep,
source }));
IAction valign = getActionRegistry().getAction(
DiagramActionService.ALIGN_VERT_FIRST_SELECTED);
valign.run();
}
}
if (ep instanceof NodeContainerEditPart) {
List children = ep.getChildren();
for (int d = 0; d < children.size(); d++) {
AbstractGraphicalEditPart p = (AbstractGraphicalEditPart) children
.get(d);
cleanUp(p);
}
}
}
}
/**
* For auto-layout, need to adjust connection(or link) length, based on
* connecting editparts(figures).
*
*/
private boolean reduceLinkLength(AbstractGraphicalEditPart part) {
boolean moved = false;
// only move new WorkProductComposite elements
if (part instanceof WorkProductCompositeEditPart) {
AbstractGraphicalEditPart linkedPart = null;
int position = PositionConstants.CENTER;
// is this element linked to another item?
if (part.getTargetConnections().size() > 0) {
linkedPart = (AbstractGraphicalEditPart) ((LinkEditPart) part
.getTargetConnections().get(0)).getSource();
position = PositionConstants.NORTH;
} else if (part.getSourceConnections().size() > 0) {
linkedPart = (AbstractGraphicalEditPart) ((LinkEditPart) part
.getSourceConnections().get(0)).getTarget();
position = PositionConstants.SOUTH;
}
if (linkedPart != null) {
if (!(linkedPart.getParent() instanceof DiagramEditPart)) {
linkedPart = (AbstractGraphicalEditPart) linkedPart
.getParent();
}
// get the part's position
Rectangle partBounds = part.getFigure().getBounds();
// get the linked part's position
Rectangle linkedPartBounds = linkedPart.getFigure().getBounds();
// determine in which direction is the linked part
// int position = partBounds.getPosition(linkedPartBounds
// .getLocation());
// assume it is below us, so this part moves up
int direction = -1;
if ((position & PositionConstants.NORTH) == PositionConstants.NORTH
|| (position & PositionConstants.CENTER) == PositionConstants.CENTER) {
// above us, move down
direction = 1;
}
// set new bounds for the part so that it sites just outside of
// the linked part
Rectangle testBounds = partBounds.getCopy();
if (direction == 1) {
testBounds.y = linkedPartBounds.y + linkedPartBounds.height
+ VERT_PIX_PADDING;
} else {
testBounds.y = linkedPartBounds.y - VERT_PIX_PADDING
- partBounds.height;
}
// set the new location for the part in the model
Point np = new Point(testBounds.x, testBounds.y);
part.getFigure().setLocation(np);
Command c = new ChangeBoundsCommand((Node) part.getModel(), np,
partBounds.width);
getCommandStack().execute(c);
}
}
return moved;
}
/**
* Method to adjust the size of editpart.
*
*/
private void adjustSize(AbstractGraphicalEditPart ep) {
if (ep instanceof WorkProductCompositeEditPart) {
adjustSize((NodeContainerEditPart) ep, 1);
}
// Below Code generic NodeContainerEditPart modification.
else if (ep instanceof NodeContainerEditPart) {
// This is to allow user customizable
// String count = AuthoringUIPlugin.getDefault().getPreferenceStore()
// .getString(TemplateConstants.ADD_ROLE_TASKS_COUNT);
// if(count != null || count != ""){
// int i = Integer.parseInt(count);
// if(i > 0){
// adjustSize((NodeContainerEditPart) ep, i);
// }
// }else{
// adjustSize((NodeContainerEditPart) ep, 50);
// }
adjustSize((NodeContainerEditPart) ep, 50);
}
}
protected final static int HORIZ_PIX_PADDING = 30;
protected final static int VERT_PIX_PADDING = 20;
/**
* Adjusts the size of ContainerEditPart to accomodate number of editparts in a row,
* push the remaining the editparts in two second row.
* This is useful for {@link ToolbarLayout}
*
*/
private void adjustSize(NodeContainerEditPart ep, int horizCount) {
int requiredWidth = 0;
int rowMaxHeight = 0;
int rows = 0;
int widthSum = 0;
int heightSum = 0;
int column = 0;
//int originalWidth = ep.getFigure().getSize().width;
List children = ep.getChildren();
for (int p = 0; p < children.size();) {
if (column == 0) {
rows++;
}
if (column < horizCount) {
AbstractGraphicalEditPart child = (AbstractGraphicalEditPart) children
.get(p);
Dimension d = child.getFigure().getPreferredSize();
widthSum += d.width;
if (d.height > rowMaxHeight) {
rowMaxHeight = d.height;
}
p++;
column++;
} else {
if (widthSum > requiredWidth) {
requiredWidth = widthSum;
}
heightSum += rowMaxHeight;
rowMaxHeight = 0;
widthSum = 0;
column = 0;
}
}
if (widthSum > requiredWidth) {
requiredWidth = widthSum;
}
heightSum += rowMaxHeight;
requiredWidth += HORIZ_PIX_PADDING
* Math.min(horizCount, children.size());
int requiredHeight = heightSum + (VERT_PIX_PADDING * rows);
Command cmd = new ChangeBoundsCommand(((Node) ep.getModel()), ep
.getFigure().getBounds().getLocation(), requiredWidth);
getCommandStack().execute(cmd);
ep.getFigure().setPreferredSize(
new Dimension(requiredWidth, requiredHeight));
((Node) ep.getModel()).setHeight(requiredHeight);
ep.getFigure().setSize(new Dimension(requiredWidth, requiredHeight));
ep.getFigure().getLayoutManager().layout(ep.getFigure());
// after layout, check the bottom-most child figure against the bottom
// of the container, adjust the bottom of the container is necessary
if (ep instanceof WorkProductCompositeEditPart && children.size() > 0) {
GraphicalEditPart last = (GraphicalEditPart) children.get(children
.size() - 1);
Point childBottom = last.getFigure().getBounds().getBottom();
Point parentBottom = ep.getFigure().getBounds().getBottom();
int delta = parentBottom.y - childBottom.y - (VERT_PIX_PADDING / 2);
ep.getFigure().setPreferredSize(
new Dimension(requiredWidth, requiredHeight - delta));
((Node) ep.getModel()).setHeight(requiredHeight - delta);
ep.getFigure().setSize(
new Dimension(requiredWidth, requiredHeight - delta));
}
}
protected void enumerateConnectedParts(AbstractGraphicalEditPart part,
List connected) {
// only add parts directly on the diagram surface
if (!connected.contains(part)) {
if (!(part.getParent() instanceof DiagramEditPart)) {
if (!connected.contains(part.getParent())) {
connected.add(part.getParent());
}
} else {
connected.add(part);
}
AbstractGraphicalEditPart linkedPart = null;
List children = part.getChildren();
for (int x = 0; x < children.size(); x++) {
AbstractGraphicalEditPart p = (AbstractGraphicalEditPart) children
.get(x);
enumerateConnectedParts(p, connected);
}
// is this element linked to another item?
for (int x = 0; x < part.getTargetConnections().size(); x++) {
linkedPart = (AbstractGraphicalEditPart) ((LinkEditPart) part
.getTargetConnections().get(x)).getSource();
enumerateConnectedParts(linkedPart, connected);
}
for (int x = 0; x < part.getSourceConnections().size(); x++) {
linkedPart = (AbstractGraphicalEditPart) ((LinkEditPart) part
.getSourceConnections().get(x)).getTarget();
enumerateConnectedParts(linkedPart, connected);
}
}
}
/**
* This method finds single elements and groups of elements, and positions
* them starting from the top of the diagram and continuously down the page.
*/
private void packDiagram() {
ActivityDetailDiagramEditPart diagram = (ActivityDetailDiagramEditPart) getGraphicalViewer()
.getContents();
// start at the top of the diagram
// Dimension diagramSize = diagram.getFigure().getSize();
// no new shapes can be moved above this y-axis value
int reserved = 0;
// these are elements without connections
List stragglers = new ArrayList();
// these are groups of elements connected with links
List groups = new ArrayList();
// these are top level parts on the diagram that have been added
List diagramParts = diagram.getRecentlyAddedParts();
for (int x = 0; x < diagramParts.size(); x++) {
AbstractGraphicalEditPart p = (AbstractGraphicalEditPart) diagramParts
.get(x);
boolean found = false;
for (int g = 0; g < groups.size() && found == false; g++) {
List group = (List) groups.get(g);
if (group.contains(p)) {
found = true;
break;
}
}
if (!found) {
List connected = new ArrayList();
enumerateConnectedParts(p, connected);
if (connected.size() == 1) {
stragglers.add(p);
} else {
groups.add(connected);
}
}
}
// process each group closest to the top (min y value)
while (groups.size() > 0) {
List top = (List) groups.get(0);
int topY = getVerticalMinPart(top).getFigure().getBounds().y;
for (int x = 0; x < groups.size(); x++) {
List g = (List) groups.get(x);
int y = getVerticalMinPart(g).getFigure().getBounds().y;
if (y < topY) {
top = g;
topY = y;
}
}
int limit = reserved + 1;
int verticalDelta = limit - topY;
int leftX = getHorizontalMinPart(top).getFigure().getBounds().x;
int horizontalDelta = HORIZ_PIX_PADDING - leftX;
for (int x = 0; x < top.size(); x++) {
AbstractGraphicalEditPart p = (AbstractGraphicalEditPart) top
.get(x);
Rectangle bounds = p.getFigure().getBounds();
ChangeBoundsCommand cbc = new ChangeBoundsCommand((Node) p
.getModel(), new Point(bounds.x + horizontalDelta,
bounds.y + verticalDelta), bounds.width);
getCommandStack().execute(cbc);
p.getFigure().setLocation(
new Point(bounds.x + horizontalDelta, bounds.y
+ verticalDelta));
}
int bottomY = getVerticalMaxPart(top).getFigure().getBounds()
.bottom();
reserved = bottomY + (VERT_PIX_PADDING * 2);
groups.remove(top);
}
int next = HORIZ_PIX_PADDING;
for (int x = 0; x < stragglers.size(); x++) {
int limit = reserved + 1;
AbstractGraphicalEditPart p = (AbstractGraphicalEditPart) stragglers
.get(x);
Rectangle bounds = p.getFigure().getBounds();
ChangeBoundsCommand cbc = new ChangeBoundsCommand((Node) p
.getModel(), new Point(next, limit), bounds.width);
getCommandStack().execute(cbc);
p.getFigure().setLocation(new Point(next, limit));
next += bounds.width + HORIZ_PIX_PADDING;
}
}
private AbstractGraphicalEditPart getVerticalMinPart(List parts) {
AbstractGraphicalEditPart rc = parts.size() > 0 ? (AbstractGraphicalEditPart) parts
.get(0)
: null;
for (int x = 0; x < parts.size(); x++) {
AbstractGraphicalEditPart p = (AbstractGraphicalEditPart) parts
.get(x);
if (p.getFigure().getBounds().y < rc.getFigure().getBounds().y) {
rc = p;
}
}
return rc;
}
private AbstractGraphicalEditPart getHorizontalMinPart(List parts) {
AbstractGraphicalEditPart rc = parts.size() > 0 ? (AbstractGraphicalEditPart) parts
.get(0)
: null;
for (int x = 0; x < parts.size(); x++) {
AbstractGraphicalEditPart p = (AbstractGraphicalEditPart) parts
.get(x);
if (p.getFigure().getBounds().x < rc.getFigure().getBounds().x) {
rc = p;
}
}
return rc;
}
private AbstractGraphicalEditPart getVerticalMaxPart(List parts) {
AbstractGraphicalEditPart rc = parts.size() > 0 ? (AbstractGraphicalEditPart) parts
.get(0)
: null;
for (int x = 0; x < parts.size(); x++) {
AbstractGraphicalEditPart p = (AbstractGraphicalEditPart) parts
.get(x);
if (p.getFigure().getBounds().bottom() > rc.getFigure().getBounds()
.bottom()) {
rc = p;
}
}
return rc;
}
}