blob: 3c29c04965b4274a21604d354c383454a00427bf [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2006, 2008 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 API and implementation
****************************************************************************/
package org.eclipse.gmf.runtime.diagram.ui.providers.internal;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Insets;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.PointList;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.draw2d.graph.CompoundDirectedGraph;
import org.eclipse.draw2d.graph.DirectedGraph;
import org.eclipse.draw2d.graph.DirectedGraphLayout;
import org.eclipse.draw2d.graph.Edge;
import org.eclipse.draw2d.graph.Node;
import org.eclipse.draw2d.graph.NodeList;
import org.eclipse.draw2d.graph.Subgraph;
import org.eclipse.gef.ConnectionEditPart;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CompoundCommand;
import org.eclipse.gmf.runtime.diagram.ui.editparts.CompartmentEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.GroupEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IBorderItemEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeCompartmentEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeEditPart;
import org.eclipse.gmf.runtime.draw2d.ui.graph.ConstantSizeNode;
import org.eclipse.gmf.runtime.draw2d.ui.internal.graph.AdvancedSubGraph;
import org.eclipse.gmf.runtime.draw2d.ui.internal.graph.CompositeDirectedGraphLayout;
import org.eclipse.gmf.runtime.draw2d.ui.internal.graph.VirtualNode;
import org.eclipse.gmf.runtime.notation.LayoutConstraint;
import org.eclipse.gmf.runtime.notation.Size;
import org.eclipse.gmf.runtime.notation.View;
/**
* Provider that creates a command for the CompoundDirectedGraph layout in GEF.
*
* @author mmostafa
* @canBeSeenBy org.eclipse.gmf.runtime.diagram.ui.providers.*
*
*/
public abstract class CompositeLayoutProvider
extends DefaultProvider {
/* (non-Javadoc)
* @see org.eclipse.gmf.runtime.diagram.ui.providers.internal.DefaultProvider#build_nodes(java.util.List, java.util.Map, org.eclipse.draw2d.graph.Subgraph)
*/
protected NodeList build_nodes(List selectedObjects,
Map editPartToNodeDict, Subgraph rootGraph) {
ListIterator li = selectedObjects.listIterator();
NodeList nodes = new NodeList();
while (li.hasNext()) {
IGraphicalEditPart gep = (IGraphicalEditPart) li.next();
boolean hasChildren = hasChildren(gep);
if (!(gep instanceof IBorderItemEditPart)
&& (gep instanceof ShapeEditPart || gep instanceof ShapeCompartmentEditPart)) {
GraphicalEditPart ep = (GraphicalEditPart) gep;
Point position = ep.getFigure().getBounds().getLocation();
if (minX == -1) {
minX = position.x;
minY = position.y;
} else {
minX = Math.min(minX, position.x);
minY = Math.min(minY, position.y);
}
Node n = null;
if (hasChildren && !(gep instanceof GroupEditPart)) {
AdvancedSubGraph subGraph = null;
if (rootGraph != null)
subGraph = new AdvancedSubGraph(ep, rootGraph);
else
subGraph = new AdvancedSubGraph(ep);
subGraph.setAutoSize(isAutoSizeOn(subGraph,ep));
if (gep instanceof CompartmentEditPart){
subGraph.setHasBufferedZone(true);
}
subGraph.setDirection(getLayoutDirection(ep));
n = subGraph;
} else {
if (rootGraph != null)
n = new ConstantSizeNode(ep, rootGraph);
else
n = new ConstantSizeNode(ep);
}
adjustNodePadding(n, editPartToNodeDict);
Dimension size = ep.getFigure().getBounds().getSize();
setNodeMetrics(n, new Rectangle(position.x, position.y,
size.width, size.height));
editPartToNodeDict.put(ep, n);
nodes.add(n);
if (hasChildren && !(gep instanceof GroupEditPart)) {
build_nodes(gep.getChildren(), editPartToNodeDict,
(Subgraph) n);
}
if (n instanceof ConstantSizeNode) {
build_borderNodes(gep, (ConstantSizeNode)n, editPartToNodeDict);
}
}
}
return nodes;
}
/**
* Gets the layout direction for an editpart. Every editpart mapped to
* <code>AdvancedSubGraph</code> will be asked for its desired layout direction
* such that children of the subgraph are laid out accordingly to that direction.
*
* @param ep the editpart
*/
protected int getLayoutDirection(GraphicalEditPart ep) {
return PositionConstants.SOUTH;
}
private boolean isAutoSizeOn(AdvancedSubGraph subGraph, IGraphicalEditPart gEP) {
if (gEP instanceof CompartmentEditPart && subGraph.getParent() instanceof AdvancedSubGraph){
if (((AdvancedSubGraph)subGraph.getParent()).isAutoSize())
return true;
}else {
View notationView = gEP.getNotationView();
if (notationView !=null && notationView instanceof org.eclipse.gmf.runtime.notation.Node){
org.eclipse.gmf.runtime.notation.Node node = (org.eclipse.gmf.runtime.notation.Node)notationView;
LayoutConstraint contraint = node.getLayoutConstraint();
if (contraint instanceof Size){
Size size = (Size)contraint;
if (size.getHeight() != -1 || size.getWidth()!=-1){
return false;
}
return true;
}
}
}
return false;
}
/* (non-Javadoc)
* @see org.eclipse.gmf.runtime.diagram.ui.providers.internal.DefaultProvider#createGraphLayout()
*/
protected DirectedGraphLayout createGraphLayout() {
return new CompositeDirectedGraphLayout();
}
/* (non-Javadoc)
* @see org.eclipse.gmf.runtime.diagram.ui.providers.internal.DefaultProvider#createNodeChangeBoundCommands(org.eclipse.draw2d.graph.DirectedGraph, org.eclipse.draw2d.geometry.Point)
*/
protected Command createNodeChangeBoundCommands(DirectedGraph g, Point diff) {
CompoundCommand cc = new CompoundCommand(""); //$NON-NLS-1$
NodeList list = new NodeList();
NodeList subGraphs = ((CompoundDirectedGraph) g).nodes;
list.addAll(subGraphs);
for (Iterator iter = subGraphs.iterator(); iter.hasNext();) {
Node element = (Node) iter.next();
if (element instanceof Subgraph)
list.addAll(getAllMembers((Subgraph) element));
}
createSubCommands(diff, list.listIterator(), cc);
if (cc.isEmpty())
return null;
return cc;
}
private Collection getAllMembers(Subgraph element) {
NodeList list = new NodeList();
list.addAll(element.members);
for (Iterator iter = element.members.iterator(); iter.hasNext();) {
Node node = (Node) iter.next();
if (node instanceof Subgraph)
list.addAll(getAllMembers((Subgraph) node));
}
return list;
}
/* (non-Javadoc)
* @see org.eclipse.gmf.runtime.diagram.ui.providers.internal.DefaultProvider#getNodeMetrics(org.eclipse.draw2d.graph.Node)
*/
protected Rectangle getNodeMetrics(Node n) {
Rectangle rect = null;
if (n.getParent() instanceof VirtualNode) {
Node parent = n.getParent();
rect = new Rectangle(n.x + parent.x, n.y + parent.y, n.width,
n.height);
} else
rect = new Rectangle(n.x, n.y, n.width, n.height);
return translateFromGraph(rect);
}
protected void postProcessGraph(DirectedGraph g, Hashtable editPartToNodeDict) {
//default do nothing
}
/**
* @param gep
* @return
*/
protected boolean hasChildren(IGraphicalEditPart gep) {
List children = gep.getChildren();
boolean hasChildren = false;
if (!children.isEmpty()){
for (Iterator iter = children.iterator(); iter.hasNext() && !hasChildren;) {
Object element = iter.next();
if (!(element instanceof IBorderItemEditPart) &&
( element instanceof ShapeEditPart ||
element instanceof ShapeCompartmentEditPart)){
hasChildren = true;
}else
hasChildren = hasChildren((IGraphicalEditPart)element);
}
}
return hasChildren;
}
/**
* this method will adjust the passed node Padding; the default implementatio
* will use a fixed Padding then it will consider adding extra Padding if the
* node parent is not a direct parent
* clients can override this method to change the behaviour
* @param node the node to adust the padding for
*/
protected void adjustNodePadding(Node node,Map editPartToNodeDict) {
Insets padding = new Insets(getMapMode().DPtoLP(NODE_PADDING));
GraphicalEditPart ep = (GraphicalEditPart)node.data;
// check if the direct parent is added already to the graph
GraphicalEditPart parent = (GraphicalEditPart)ep.getParent();
if (parent != null &&
node.getParent() != null &&
editPartToNodeDict.get(parent)!=node.getParent()){
// now the direct parent is not added to the graph so, we had
// to adjust the padding of the node to consider the parent
IFigure thisFigure = parent.getFigure();
IFigure parentFigure = ((GraphicalEditPart)node.getParent().data).getFigure();
Point parentLocation = parentFigure.getBounds().getLocation();
Point nodeLocation = thisFigure.getBounds().getLocation();
thisFigure.translateToAbsolute(nodeLocation);
parentFigure.translateToAbsolute(parentLocation);
Dimension delta = nodeLocation.getDifference(parentLocation);
Rectangle rect = translateToGraph(new Rectangle(delta.width , delta.height , 0 , 0));
padding.top += rect.y ;
padding.left += rect.x;
}
node.setPadding(padding);
if (node instanceof ConstantSizeNode) {
ConstantSizeNode cn = (ConstantSizeNode) node;
cn.setMinIncomingPadding(getMapMode().DPtoLP(MIN_EDGE_END_POINTS_PADDING));
cn.setMinOutgoingPadding(getMapMode().DPtoLP(MIN_EDGE_END_POINTS_PADDING));
}
}
/* (non-Javadoc)
* @see org.eclipse.gmf.runtime.diagram.ui.providers.internal.DefaultProvider#createGraph()
*/
protected DirectedGraph createGraph(){
return new CompoundDirectedGraph();
}
/* (non-Javadoc)
* @see org.eclipse.gmf.runtime.diagram.ui.providers.internal.DefaultProvider#shouldHandleConnectableListItems()
*/
protected boolean shouldHandleConnectableListItems() {
return true;
}
/* (non-Javadoc)
* @see org.eclipse.gmf.runtime.diagram.ui.providers.internal.DefaultProvider#routeThrough(org.eclipse.draw2d.graph.Edge, org.eclipse.gef.ConnectionEditPart, org.eclipse.draw2d.graph.Node, org.eclipse.draw2d.graph.Node, org.eclipse.draw2d.geometry.PointList, org.eclipse.draw2d.geometry.Point)
*/
protected Command routeThrough(Edge edge, ConnectionEditPart connectEP,
Node source, Node target, PointList points, Point diff) {
Node parent = source.getParent();
if (parent == null) {
parent = target.getParent();
}
if (parent != null) {
Point parentLocation = getNodeMetrics(parent).getLocation();
points.translate(parentLocation.x, parentLocation.y);
}
return super
.routeThrough(edge, connectEP, source, target, points, diff);
}
}