| //------------------------------------------------------------------------------ |
| // 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; |
| } |
| |
| } |