summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Wouters2014-01-06 08:22:43 (EST)
committerLaurent Wouters2014-01-08 04:09:22 (EST)
commit160761f7891826fc78df7637738827f70d5c69f0 (patch)
treefea8ee91b17816204e5ed643fe6ad4d331661a97
parentd8a2f2ae3c6fbb335153c6de0c6dae7c2f3fb6f2 (diff)
downloadorg.eclipse.papyrus-160761f7891826fc78df7637738827f70d5c69f0.zip
org.eclipse.papyrus-160761f7891826fc78df7637738827f70d5c69f0.tar.gz
org.eclipse.papyrus-160761f7891826fc78df7637738827f70d5c69f0.tar.bz2
Support the layout of an element's label within its associated SVG shape
Change-Id: I031bfaf0d0b9289cdd76cb80ca58d61e964d20c3 Signed-off-by: Laurent Wouters <laurent.wouters@cea.fr>
-rw-r--r--plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/figure/node/SVGNodePlateFigure.java414
-rw-r--r--plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.common/src/org/eclipse/papyrus/uml/diagram/common/figure/node/AutomaticCompartmentLayoutManager.java471
-rw-r--r--plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.statemachine/custom-src/org/eclipse/papyrus/uml/diagram/statemachine/custom/figures/NoExtraHeightLayoutManager.java24
3 files changed, 568 insertions, 341 deletions
diff --git a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/figure/node/SVGNodePlateFigure.java b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/figure/node/SVGNodePlateFigure.java
index 8f5725d..5a0fcf9 100644
--- a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/figure/node/SVGNodePlateFigure.java
+++ b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/figure/node/SVGNodePlateFigure.java
@@ -9,15 +9,20 @@
*
* Contributors:
* Patrick Tessier (CEA LIST) Patrick.tessier@cea.fr - Initial API and implementation
+ * Laurent Wouters (CEA LIST) laurent.wouters@cea.fr - Refactoring, cleanup, added support for PapyrusLabel element
*****************************************************************************/
package org.eclipse.papyrus.infra.gmfdiag.common.figure.node;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
import org.apache.batik.dom.svg.AbstractSVGPathSegList.SVGPathSegMovetoLinetoItem;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.PointList;
+import org.eclipse.draw2d.geometry.PrecisionDimension;
import org.eclipse.draw2d.geometry.PrecisionPoint;
+import org.eclipse.draw2d.geometry.PrecisionRectangle;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gmf.runtime.gef.ui.figures.DefaultSizeNodeFigure;
import org.w3c.dom.Element;
@@ -27,211 +32,320 @@ import org.w3c.dom.svg.SVGLength;
import org.w3c.dom.svg.SVGPathElement;
import org.w3c.dom.svg.SVGPathSeg;
import org.w3c.dom.svg.SVGPathSegList;
+import org.w3c.dom.svg.SVGRectElement;
import org.w3c.dom.svg.SVGSVGElement;
/**
- * this figure is used to make links following SVG shape
- *
- *
+ * This figure is used to make links following SVG shape
*/
public class SVGNodePlateFigure extends DefaultSizeNodeFigure {
- protected SVGPathSegList pathSegList = null;
+ /**
+ * Represents a transformation from SVG to Draw2D coordinates.
+ * This class replaces the Draw2D Transform class which can only operate over Draw2D points.
+ * This class always defines a transformation that is composed of a scaling operation followed by a translation operation.
+ *
+ * @author Laurent Wouters
+ */
+ private static class SvgToDraw2DTransform {
+ private double scaleX;
+ private double scaleY;
+ private double translationX;
+ private double translationY;
+
+ /**
+ * Initializes this transformation
+ *
+ * @param scaleX
+ * Scale on the X axis
+ * @param scaleY
+ * Scale on the Y axis
+ * @param translationX
+ * Translation on the X axis
+ * @param translationY
+ * Translation on the Y axis
+ */
+ public SvgToDraw2DTransform(double scaleX, double scaleY, double translationX, double translationY) {
+ this.scaleX = scaleX;
+ this.scaleY = scaleY;
+ this.translationX = translationX;
+ this.translationY = translationY;
+ }
+
+ /**
+ * Transforms the given points in the target frame of reference
+ *
+ * @param point
+ * The point to transform
+ * @return The transformed point in the target frame of reference
+ */
+ public PrecisionPoint transform(PrecisionPoint point) {
+ return new PrecisionPoint(point.preciseX() * scaleX + translationX, point.preciseY() * scaleY + translationY);
+ }
+
+ /**
+ * Transforms the given rectangle in the target frame of reference
+ *
+ * @param rectangle
+ * The rectangle to transform
+ * @return The transformed rectangle in the target frame of reference
+ */
+ public PrecisionRectangle transform(PrecisionRectangle rectangle) {
+ return new PrecisionRectangle(rectangle.preciseX() * scaleX + translationX, rectangle.preciseY() * scaleY + translationY, rectangle.preciseWidth() * scaleX, rectangle.preciseHeight() * scaleY);
+ }
+ }
+
+
+ private PrecisionDimension svgDimension = null;
+
+ private List<PrecisionPoint> outlinePoints = null;
+
+ private PrecisionDimension outlineDimension = null;
- protected SVGDocument svgDocument = null;
+ private PrecisionRectangle labelBounds = null;
protected DefaultSizeNodeFigure defaultNodePlate;
/**
- * associate the SVG document that represent the SVG
+ * Initializes the figure.
+ *
+ * @param width
+ * The figure's original width
+ * @param height
+ * The figure's original height
+ */
+ public SVGNodePlateFigure(int width, int height) {
+ super(width, height);
+ }
+
+
+ /**
+ * Associates the given SVG document to this figure
*
* @param svgDocument
- * the SVG document
+ * the SVG document
*/
public void setSVGDocument(SVGDocument svgDocument) {
- if(svgDocument == null) {
- this.svgDocument = null;
- this.pathSegList = null;
- } else {
- this.svgDocument = svgDocument;
- Element path = svgDocument.getElementById("PapyrusPath");
- if(path != null) {
- SVGPathElement svgPath = (SVGPathElement)path;
- SVGPathSegList segmentList = svgPath.getPathSegList();
- this.setSegemntList(segmentList);
+ if (svgDocument != null) {
+ this.svgDimension = getSvgDimension(svgDocument);
+ Element element = svgDocument.getElementById("PapyrusPath");
+ if (element != null) {
+ outlinePoints = toDraw2DPoints(((SVGPathElement) element).getPathSegList());
+ outlineDimension = getDimensionOf(outlinePoints);
}
+ element = svgDocument.getElementById("PapyrusLabel");
+ if (element != null)
+ labelBounds = toDraw2DRectangle((SVGRectElement) element);
}
}
/**
- * set the node plate that is wrapped by it.
+ * Transforms the given SVG animated length to a base value, assuming the units in the SVG are pixels
*
- * @param defaultNodePlate
+ * @param length
+ * The SVG length
+ * @return The base value as a double
*/
- public void setDefaultNodePlate(IFigure defaultNodePlate) {
- if(defaultNodePlate instanceof DefaultSizeNodeFigure) {
- this.defaultNodePlate = (DefaultSizeNodeFigure)defaultNodePlate;
- this.setDefaultSize(((DefaultSizeNodeFigure)defaultNodePlate).getDefaultSize());
- }
- if(defaultNodePlate instanceof ICustomNodePlate) {
- ((ICustomNodePlate)this.defaultNodePlate).setSVGNodePlateContainer(this);
- }
+ private double getValueOf(SVGAnimatedLength length) {
+ if (length == null)
+ return 0;
+ SVGLength base = length.getBaseVal();
+ if (base == null)
+ return 0;
+ return base.getValue();
}
/**
+ * Gets the dimension of the SVG document, assuming the units in the SVG are pixels
*
- * Constructor.
- *
- * @param width
- * @param height
+ * @param svgDocument
+ * The SVG document
+ * @return The equivalent Draw2D dimension
*/
- public SVGNodePlateFigure(int width, int height) {
- super(width, height);
+ private PrecisionDimension getSvgDimension(SVGDocument svgDocument) {
+ double svgWidth = 0;
+ double svgHeight = 0;
+ SVGSVGElement svgElement = svgDocument.getRootElement();
+ if (svgElement != null) {
+ svgWidth = getValueOf(svgElement.getWidth());
+ svgHeight = getValueOf(svgElement.getHeight());
+ }
+ return new PrecisionDimension(svgWidth, svgHeight);
}
/**
- * set the papyrus path to follow the shape
+ * Transforms the given SVG path to a list of Draw2D precision points, assuming the units in the SVG are pixels
*
- * @param pathSegList
+ * @param segments
+ * The SVG path as a list of segments
+ * @return The list of the corresponding Draw2D points
*/
+ private List<PrecisionPoint> toDraw2DPoints(SVGPathSegList segments) {
+ ArrayList<PrecisionPoint> pointList = new ArrayList<PrecisionPoint>();
- public void setSegemntList(SVGPathSegList pathSegList) {
- this.pathSegList = pathSegList;
- }
-
- public boolean containShapeCompatment() {
- if(this.getChildren().size() > 0 && this.getChildren().get(0) instanceof IFigure) {
- IFigure primaryShape = (IFigure)this.getChildren().get(0);
- for(Object subFigure : primaryShape.getChildren()) {
- if(subFigure instanceof ScalableCompartmentFigure) {
- return true;
+ // current coordinates
+ double currentX = 0;
+ double currentY = 0;
+ for (int i = 0; i < segments.getNumberOfItems(); i++) {
+ SVGPathSeg seg = segments.getItem(i);
+ if (seg instanceof SVGPathSegMovetoLinetoItem) {
+ SVGPathSegMovetoLinetoItem linetoItem = (SVGPathSegMovetoLinetoItem) seg;
+ String letter = linetoItem.getPathSegTypeAsLetter();
+ double x = linetoItem.getX();
+ double y = linetoItem.getY();
+ if (letter.equals("M")) {
+ currentX = x;
+ currentY = y;
+ pointList.add(new PrecisionPoint(currentX, currentY));
+ } else if (letter.equals("m")) {
+ currentX = currentX + x;
+ currentY = currentY + y;
+ pointList.add(new PrecisionPoint(currentX, currentY));
+ } else if (letter.equals("L")) {
+ currentX = x;
+ currentY = y;
+ pointList.add(new PrecisionPoint(currentX, currentY));
+ } else if (letter.equals("l")) {
+ currentX = currentX + x;
+ currentY = currentY + y;
+ pointList.add(new PrecisionPoint(currentX, currentY));
}
+ } else {
+ System.err.println("Unsupported SVG segment in PapyrusPath at index " + i + " in SVG document");
}
}
- return false;
+
+ return pointList;
}
- public IFigure getShapeCompatment() {
- if(this.getChildren().size() > 0 && this.getChildren().get(0) instanceof IFigure) {
- IFigure primaryShape = (IFigure)this.getChildren().get(0);
- for(Object subFigure : primaryShape.getChildren()) {
- if(subFigure instanceof ScalableCompartmentFigure) {
- return (IFigure)subFigure;
- }
- }
+ /**
+ * Gets the dimension of the given collection of points
+ *
+ * @param points
+ * A list of points
+ * @return The dimension of the points
+ */
+ private PrecisionDimension getDimensionOf(Collection<PrecisionPoint> points) {
+ double maxWidth = 0;
+ double maxHeight = 0;
+ for (PrecisionPoint point : points) {
+ maxWidth = Math.max(maxWidth, point.preciseX());
+ maxHeight = Math.max(maxHeight, point.preciseY());
}
- return null;
+ return new PrecisionDimension(maxWidth, maxHeight);
}
+ /**
+ * Transforms the given SVG rectangle to a Draw2D rectangle, assuming the units in the SVG are pixels
+ *
+ * @param element
+ * The SVG rectangle
+ * @return The equivalent Draw2D rectangle
+ */
+ private PrecisionRectangle toDraw2DRectangle(SVGRectElement element) {
+ return new PrecisionRectangle(
+ getValueOf(element.getX()),
+ getValueOf(element.getY()),
+ getValueOf(element.getWidth()),
+ getValueOf(element.getHeight()));
+ }
- // This returns as the anchoring area only the central line
- @Override
- public PointList getPolygonPoints() {
- if(this.pathSegList == null) {
- if(defaultNodePlate != null) {
- defaultNodePlate.setBounds(this.getBounds());
- return defaultNodePlate.getPolygonPoints();
- }
- return super.getPolygonPoints();
+
+
+ /**
+ * Sets the node plate that is wrapped by it.
+ *
+ * @param defaultNodePlate
+ */
+ public void setDefaultNodePlate(IFigure defaultNodePlate) {
+ if (defaultNodePlate instanceof DefaultSizeNodeFigure) {
+ this.defaultNodePlate = (DefaultSizeNodeFigure) defaultNodePlate;
+ this.setDefaultSize(((DefaultSizeNodeFigure) defaultNodePlate).getDefaultSize());
}
- double svgWidth = 0;
- double svgHeight = 0;
- SVGSVGElement svgElement = svgDocument.getRootElement();
- if(svgElement != null) {
- SVGAnimatedLength widthALength = svgElement.getWidth();
- SVGAnimatedLength heightALength = svgElement.getHeight();
- if(widthALength != null && heightALength != null) {
- SVGLength svgWidthLength = widthALength.getBaseVal();
- SVGLength svgHeightLength = heightALength.getBaseVal();
- if(svgWidthLength != null && svgHeightLength != null) {
- // if( width.getUnitType()==width.SVG_LENGTHTYPE_PX){
- svgWidth = svgWidthLength.getValueInSpecifiedUnits();
- svgHeight = svgHeightLength.getValueInSpecifiedUnits();
- // }
- }
- }
+ if (defaultNodePlate instanceof ICustomNodePlate) {
+ ((ICustomNodePlate) this.defaultNodePlate).setSVGNodePlateContainer(this);
}
+ }
- //transform coordinate to absolute in the context of the SVG
- //getBounds
- ArrayList<PrecisionPoint> pointList = new ArrayList<PrecisionPoint>();
+ /**
+ * Gets the transformation from SVG to Draw2D positions
+ *
+ * @param innerWidth
+ * Maximum width of the elements to transform
+ * @param innerHeight
+ * Maximum height of the elements to transform
+ * @param anchor
+ * The Draw2D rectangle anchoring the SVG figure
+ * @return The transformation
+ */
+ private SvgToDraw2DTransform getTransform(double innerWidth, double innerHeight, Rectangle anchor) {
+ PrecisionDimension maxDim = new PrecisionDimension(Math.max(svgDimension.preciseWidth(), innerWidth), Math.max(svgDimension.preciseHeight(), innerHeight));
+ return new SvgToDraw2DTransform(
+ anchor.width / maxDim.preciseWidth(),
+ anchor.height / maxDim.preciseHeight(),
+ anchor.x,
+ anchor.y);
+ }
- //current absolute coordinates
- float currentAbsoluteSVGPositionX = 0;
- float currentAbsoluteSVGPositionY = 0;
- for(int i = 0; i < pathSegList.getNumberOfItems(); i++) {
- SVGPathSeg seg = pathSegList.getItem(i);
- if(seg instanceof SVGPathSegMovetoLinetoItem) {
- SVGPathSegMovetoLinetoItem linetoItem = (SVGPathSegMovetoLinetoItem)seg;
- //short value =linetoItem.getPathSegType();
- String letter = linetoItem.getPathSegTypeAsLetter();
- float x = linetoItem.getX();
- float y = linetoItem.getY();
- // System.out.println("value="+value +" letter="+letter+ " x="+ x+ " y="+y);
- if(letter.equals("M")) {
- currentAbsoluteSVGPositionX = x;
- currentAbsoluteSVGPositionY = y;
- pointList.add(new PrecisionPoint(currentAbsoluteSVGPositionX, currentAbsoluteSVGPositionY));
- } else if(letter.equals("m")) {
- currentAbsoluteSVGPositionX = currentAbsoluteSVGPositionX + x;
- currentAbsoluteSVGPositionY = currentAbsoluteSVGPositionY + y;
- pointList.add(new PrecisionPoint(currentAbsoluteSVGPositionX, currentAbsoluteSVGPositionY));
- } else if(letter.equals("L")) {
- currentAbsoluteSVGPositionX = x;
- currentAbsoluteSVGPositionY = y;
- pointList.add(new PrecisionPoint(currentAbsoluteSVGPositionX, currentAbsoluteSVGPositionY));
- } else if(letter.equals("l")) {
- currentAbsoluteSVGPositionX = currentAbsoluteSVGPositionX + x;
- currentAbsoluteSVGPositionY = currentAbsoluteSVGPositionY + y;
- pointList.add(new PrecisionPoint(currentAbsoluteSVGPositionX, currentAbsoluteSVGPositionY));
+ /**
+ * Gets the current Draw2D anchor for the SVG figure
+ *
+ * @return The Draw2D anchor as a Rectangle
+ */
+ private Rectangle getDraw2DAnchor() {
+ if (this.getChildren().size() > 0 && this.getChildren().get(0) instanceof IFigure) {
+ IFigure primaryShape = (IFigure) this.getChildren().get(0);
+ for (Object subFigure : primaryShape.getChildren()) {
+ if (subFigure instanceof ScalableCompartmentFigure) {
+ return ((IFigure) subFigure).getBounds();
}
- } else {
- System.err.println("this is not i linear segment " + i);
}
}
+ return getHandleBounds();
+ }
-
- //get the original size of SVG
- double maxWitdh = 0;
- double maxHeight = 0;
- if(svgWidth != 0 && svgHeight != 0) {
- maxWitdh = svgWidth;
- maxHeight = svgHeight;
- } else {
- for(int i = 0; i < pointList.size(); i++) {
- PrecisionPoint point = pointList.get(i);
- if(point.preciseX() > maxWitdh) {
- maxWitdh = point.preciseX();
- }
- if(point.preciseY() > maxHeight) {
- maxHeight = point.preciseY();
- }
+ /**
+ * @see org.eclipse.gmf.runtime.gef.ui.figures.NodeFigure#getPolygonPoints()
+ */
+ @Override
+ public PointList getPolygonPoints() {
+ if (this.outlinePoints == null) {
+ if (defaultNodePlate != null) {
+ defaultNodePlate.setBounds(this.getBounds());
+ return defaultNodePlate.getPolygonPoints();
}
- }
- //System.out.println("Size of the SVG figure is= "+maxHeight +" "+maxHeight);
- PointList points = new PointList(5);
- Rectangle anchorableRectangle = null;
- if(containShapeCompatment()) {
- anchorableRectangle = getShapeCompatment().getBounds();
+ return super.getPolygonPoints();
}
- else {
- anchorableRectangle = getHandleBounds();
- }
- double ratioX = anchorableRectangle.width / maxWitdh;
- double ratioY = anchorableRectangle.height / maxHeight;
- //PackageFigure packageFigure = getPackageFigure();
- //System.out.println("Begin-------------" );
-
- for(int i = 0; i < pointList.size(); i++) {
- PrecisionPoint point = pointList.get(i);
- double x = point.preciseX() * ratioX;
- double y = point.preciseY() * ratioY;
- points.addPoint(anchorableRectangle.x + (int)x, anchorableRectangle.y + (int)y);
- //System.out.println("add point x="+x +" y=" +y +" ratioX= "+ratioX+" ratioY="+ratioY );
+ SvgToDraw2DTransform transform = getTransform(outlineDimension.preciseWidth(), outlineDimension.preciseHeight(), getDraw2DAnchor());
+ PointList points = new PointList(5);
+ for (PrecisionPoint point : outlinePoints) {
+ points.addPoint(transform.transform(point));
}
- //System.out.println("End-------------" );
return points;
}
+
+ /**
+ * Determines whether this figure defines the bounds of a possible label
+ *
+ * @return <code>true</code> if this figures defines the bounds of the label
+ */
+ public boolean hasLabelBounds() {
+ return (labelBounds != null);
+ }
+
+ /**
+ * Gets the bounds of the label, if they are defined
+ *
+ * @param anchor
+ * The Draw2D rectangle anchoring the SVG figure
+ * @return The label's bounds, or <code>null</code> if they are not defined
+ */
+ public Rectangle getLabelBounds(Rectangle anchor) {
+ if (labelBounds == null)
+ return null;
+ SvgToDraw2DTransform transform = getTransform(labelBounds.preciseRight(), labelBounds.preciseBottom(), anchor);
+ return transform.transform(labelBounds);
+ }
}
diff --git a/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.common/src/org/eclipse/papyrus/uml/diagram/common/figure/node/AutomaticCompartmentLayoutManager.java b/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.common/src/org/eclipse/papyrus/uml/diagram/common/figure/node/AutomaticCompartmentLayoutManager.java
index ed6ff56..b19be98 100644
--- a/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.common/src/org/eclipse/papyrus/uml/diagram/common/figure/node/AutomaticCompartmentLayoutManager.java
+++ b/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.common/src/org/eclipse/papyrus/uml/diagram/common/figure/node/AutomaticCompartmentLayoutManager.java
@@ -8,7 +8,8 @@
*
* Contributors:
* Patrick Tessier (CEA LIST), Thibault Landre (Atos Origin) - Initial API and implementation
- * Vincent Lorenzo (CEA LIST), change layout(IFigure container)
+ * Vincent Lorenzo (CEA LIST), change layout(IFigure container)
+ * Laurent Wouters (CEA LIST), refactoring, cleanup, added layout of labels on top of shapes
*****************************************************************************/
package org.eclipse.papyrus.uml.diagram.common.figure.node;
@@ -22,33 +23,47 @@ import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gmf.runtime.diagram.ui.figures.ResizableCompartmentFigure;
import org.eclipse.gmf.runtime.draw2d.ui.figures.WrappingLabel;
+import org.eclipse.papyrus.infra.gmfdiag.common.figure.node.SVGNodePlateFigure;
import org.eclipse.papyrus.infra.gmfdiag.common.figure.node.ScalableCompartmentFigure;
/**
- * this is the layout manager in charge to place element in compartment element.
+ * This is the layout manager in charge to place element in compartment element.
* A modification of the code has been done in order to manage none visible
* compartment. if a compartment becomes invisible, its size and its height are
* equal to 1.
*
*/
-
public class AutomaticCompartmentLayoutManager extends AbstractLayout {
protected static final int MINIMUM_COMPARTMENT_HEIGHT = 15;
- // list of compartments
- protected ArrayList<IFigure> compartmentList = new ArrayList<IFigure>();
+ /**
+ * list of visible compartment children
+ */
+ protected ArrayList<IFigure> visibleCompartments = new ArrayList<IFigure>();
- // list of none compartments ex wrapping label etc...
- protected ArrayList<IFigure> notCompartmentList = new ArrayList<IFigure>();
+ /**
+ * list of visible non-compartment children (e.g. labels)
+ */
+ protected ArrayList<IFigure> visibleOthers = new ArrayList<IFigure>();
- // background figure
- //protected IFigure backgroundFigure;
+ /**
+ * list of the invisible children
+ */
+ protected ArrayList<IFigure> invisibles = new ArrayList<IFigure>();
+ /**
+ * true if the bounds of the labels are forced by an inner figure
+ */
+ protected boolean forcedLabelBounds = false;
+
+ /**
+ * true if extra distance between compartment should be added
+ */
protected boolean addExtraHeight = true;
/**
- * set the distance between compartments
+ * Sets whether extra distance between compartment should be added
*
* @param addExtraHeight
*/
@@ -57,257 +72,355 @@ public class AutomaticCompartmentLayoutManager extends AbstractLayout {
}
/**
- *
* {@inheritDoc}
*/
@Override
protected Dimension calculatePreferredSize(IFigure container, int hint, int hint2) {
- collectInformationOnChildren(container);
+ collectInformation(container);
int minimumWith = 0;
int minimumHeight = 0;
- if(container instanceof CompartmentFigure) {
+ if (container instanceof CompartmentFigure) {
+ CompartmentFigure cf = (CompartmentFigure) container;
+ WrappingLabel wl = cf.getNameLabel();
// display name
- if(((CompartmentFigure)container).getNameLabel() != null&& container.getChildren().contains(((CompartmentFigure)container).getNameLabel())) {
- if(((CompartmentFigure)container).getNameLabel().getPreferredSize().width > minimumWith) {
- minimumWith = ((CompartmentFigure)container).getNameLabel().getPreferredSize().width;
+ if (wl != null && container.getChildren().contains(wl)) {
+ if (wl.getPreferredSize().width > minimumWith) {
+ minimumWith = wl.getPreferredSize().width;
}
-
}
}
- if(compartmentList.size() != 0) {
- for(int i = 0; i < container.getChildren().size(); i++) {
- IFigure child = (IFigure)container.getChildren().get(i);
+ if (!visibleCompartments.isEmpty()) {
+ for (Object o : container.getChildren()) {
+ IFigure child = (IFigure) o;
minimumHeight += child.getPreferredSize().height;
minimumWith = Math.max(minimumWith, child.getPreferredSize().width);
}
} else {
- for(int i = 0; i < notCompartmentList.size(); i++) {
- minimumHeight += notCompartmentList.get(i).getPreferredSize().height;
+ for (IFigure child : visibleOthers) {
+ minimumHeight += child.getPreferredSize().height;
}
}
- if(addExtraHeight)
+ if (addExtraHeight)
minimumHeight += 7;
return new Dimension(minimumWith, minimumHeight);
}
+ /**
+ * {@inheritDoc}
+ */
@Override
public Dimension getMinimumSize(IFigure container, int wHint, int hHint) {
return new Dimension(20, 20);
}
/**
- * layout by putting label in the center of figure
+ * {@inheritDoc}
+ */
+ public void layout(IFigure container) {
+ collectInformation(container);
+ // gets the bounds of this container
+ Rectangle bounds = container.getBounds();
+ // do the layout based on the policies
+ if (!visibleCompartments.isEmpty()) {
+ if (forcedLabelBounds) {
+ layoutForcedLabel(container);
+ } else {
+ layoutDefault(container);
+ }
+ } else {
+ // only non-compartment elements are visible
+ // center them within this container
+ layoutOthers(bounds);
+ }
+ // layout the invisible elements
+ layoutInvisibles(bounds.x + 3, bounds.getBottomLeft().y + 1);
+ }
+
+ /**
+ * Layouts the invisible elements at the given location
*
- * @param container
+ * @param x
+ * location's x coordinate
+ * @param y
+ * location's y coordinate
*/
- protected void layoutCenterForLabel(IFigure container) {
- int labelheight = 0;
- for(int i = 0; i < notCompartmentList.size(); i++) {
- labelheight += notCompartmentList.get(i).getPreferredSize().height;
+ protected void layoutInvisibles(int x, int y) {
+ for (IFigure child : invisibles) {
+ Rectangle bound = new Rectangle(child.getBounds());
+ bound.x = x;
+ bound.y = y;
+ child.setBounds(bound);
}
+ }
- for(int i = 0; i < container.getChildren().size(); i++) {
- if(notCompartmentList.contains((container.getChildren().get(i)))) {
- Rectangle bound = new Rectangle(((IFigure)container.getChildren().get(i)).getBounds());
- bound.setSize(getPreferedSize(((IFigure)container.getChildren().get(i))));
- if(i > 0) {
- bound.y = ((IFigure)container.getChildren().get(i - 1)).getBounds().getBottomLeft().y + 1;
- bound.x = container.getBounds().x + 3;
- bound.width = container.getBounds().width;
- } else {
- bound.x = container.getBounds().x + 3;
- bound.y = container.getBounds().y + ((container.getBounds().height - labelheight) / 2);
- bound.width = container.getBounds().width;
+ /**
+ * Layout the other elements within the given container bounds
+ *
+ * @param container
+ * The container's bound
+ */
+ protected void layoutOthers(Rectangle container) {
+ int totalHeight = 0;
+ for (IFigure child : visibleOthers) {
+ totalHeight += child.getPreferredSize().height;
+ }
- }
- ((IFigure)container.getChildren().get(i)).setBounds(bound);
+ IFigure previous = null;
+ for (IFigure child : visibleOthers) {
+ Rectangle bound = new Rectangle();
+ bound.setSize(getPreferedSize(child));
+ if (previous != null) {
+ bound.y = previous.getBounds().getBottomLeft().y + 1;
+ bound.x = container.x + 3;
+ bound.width = container.width;
} else {
- Rectangle bound = new Rectangle(((IFigure)container.getChildren().get(i)).getBounds());
- bound.y = container.getBounds().getBottomLeft().y + 1;
- bound.x = container.getBounds().x + 3;
- ((IFigure)container.getChildren().get(i)).setBounds(bound);
+ bound.x = container.x + 3;
+ bound.y = container.y + ((container.height - totalHeight) / 2);
+ bound.width = container.width;
}
+ child.setBounds(bound);
+ previous = child;
}
-
}
/**
+ * Gets the preferred size of the given figure
*
- * {@inheritDoc}
+ * @param figure
+ * A figure that contains a GMF compartment
+ * @return The figure's preferred size
*/
- public void layout(IFigure container) {
- collectInformationOnChildren(container);
-
- // container.remove(backgroundFigure);
- // container.add(backgroundFigure, 0);
+ private Dimension getPreferedSize(IFigure figure) {
+ Dimension dim = figure.getPreferredSize();
+ if (!figure.getChildren().isEmpty()) {
+ Object compartment = figure.getChildren().get(0);
+ if (compartment instanceof ResizableCompartmentFigure) {
+ dim.height = ((ResizableCompartmentFigure) compartment).getPreferredSize().height + 10;
+ if (dim.height < MINIMUM_COMPARTMENT_HEIGHT) {
+ dim.height = MINIMUM_COMPARTMENT_HEIGHT;
+ }
+ }
+ }
+ return dim;
+ }
+ /**
+ * Default layout behavior with compartments
+ *
+ * @param container
+ * The container to layout
+ */
+ protected void layoutDefault(IFigure container) {
// this list contains the visible compartments (that is to say :
// notCompartmentList + compartmentsList
- List<IFigure> visibleCompartments = new ArrayList<IFigure>();
-
- visibleCompartments.addAll(notCompartmentList);
- visibleCompartments.addAll(compartmentList);
-
- // choose the good layout by taking in account if it exist GMF
- // compartment
- if(compartmentList.size() != 0) {
- // visit all compartment
- for(int i = 0; i < container.getChildren().size(); i++) {
- IFigure currentCompartment = (IFigure)container.getChildren().get(i);
- // this is a visible compartment
- if(visibleCompartments.contains(currentCompartment)) {
-
- Rectangle bound = new Rectangle(currentCompartment.getBounds());
- currentCompartment.invalidate();
- Dimension pref = currentCompartment.getPreferredSize();
- currentCompartment.invalidate();
- Dimension prefConstraint = currentCompartment.getPreferredSize(container.getBounds().width - 40, -1);
- if(pref.width < prefConstraint.width) {
- bound.setSize(pref);
- } else {
- bound.setSize(prefConstraint);
- }
- //bound.setSize(getPreferedSize(currentCompartment));
- if(visibleCompartments.indexOf(currentCompartment) > 0) {
- bound.y = (visibleCompartments.get(visibleCompartments.indexOf(currentCompartment) - 1)).getBounds().getBottomLeft().y + 1;
- bound.x = container.getBounds().x + 3;
- bound.width = container.getBounds().width;
- } else {
- bound.x = container.getBounds().x + 3;
- bound.y = container.getBounds().y + 3;
- bound.width = container.getBounds().width;
- }
- currentCompartment.setBounds(bound);
- } else {
- // this is a none visible compartment
- Rectangle bound = new Rectangle(currentCompartment.getBounds());
- bound.setSize(1, 1);
- currentCompartment.setBounds(bound);
- }
+ List<IFigure> visibles = new ArrayList<IFigure>();
+ visibles.addAll(visibleOthers);
+ visibles.addAll(visibleCompartments);
+
+ List<Rectangle> bounds = buildInitialsBounds(container, visibles);
+ double notCompartmentsHeight = getTotalHeight(bounds, 0, visibleOthers.size());
+ double compartmentsHeight = getTotalHeight(bounds, visibleOthers.size(), visibleCompartments.size());
+ double remainingspace = container.getBounds().height - notCompartmentsHeight;
+ // because of the place of the label we have to remove 3
+ remainingspace -= 3;
+ // because we move compartment of 1 pixel the space is decrease of 1 per compartment
+ remainingspace -= visibleCompartments.size();
+ // adjustment ratio for the height of the compartments
+ double ratio = compartmentsHeight / remainingspace;
+
+ for (int i = 0; i != bounds.size(); i++) {
+ Rectangle bound = bounds.get(i);
+ if (i < visibleOthers.size()) {
+ fillBoundsForOther(container, bound, (i == 0) ? null : bounds.get(i - 1));
+ } else {
+ fillBoundsForCompartment(container, bound, (i == 0) ? null : bounds.get(i - 1), ratio);
}
- optimizeCompartmentSize(container);
- } else {
- layoutCenterForLabel(container);
+ visibles.get(i).setBounds(bound);
}
-
- // if(backgroundFigure!=null) {
- // Rectangle bound = new Rectangle(((IFigure)container).getBounds());
- // bound.y = container.getBounds().y + 1;
- // bound.x = container.getBounds().x + 3;
- // backgroundFigure.setBounds(bound);
- // }
- //
}
/**
- * Optimize the size of each compartment depending on the size of the
- * compartments container, and the size of each compartment. If a
- * compartment is empty, or not expanded, then a default size is applied to
- * this compartment
+ * Fills the given bound data as a compartment child
*
- * @param compartmentsDimension
- * an hashmap containing each compartment dimension.
+ * @param container
+ * The container to layout
+ * @param bound
+ * The bound to fill
+ * @param previous
+ * The previously filled bound
+ * @param ratio
+ * The ratio to be applied on the height of the compartment
*/
- protected void optimizeCompartmentSize(IFigure container) {
- int compartmentsHeight = 0;
- int notCompartmentsHeight = 0;
- for(int i = 0; i < notCompartmentList.size(); i++) {
- notCompartmentsHeight += notCompartmentList.get(i).getBounds().height;
+ private void fillBoundsForCompartment(IFigure container, Rectangle bound, Rectangle previous, double ratio) {
+ fillBoundsForOther(container, bound, previous);
+ bound.height = (int) ((double) bound.height / ratio);
+ if (previous == null) {
+ bound.y = container.getBounds().y;
}
+ }
- for(int i = 0; i < compartmentList.size(); i++) {
- compartmentsHeight += compartmentList.get(i).getBounds().height;
-
- }
- int remainingspace = container.getBounds().height - notCompartmentsHeight;
- //because of the place of the label we have to remove 3
- remainingspace=remainingspace-3;
- //because we move compartment of 1 pixel the space is decrease of 1
- for(int i = 0; i < compartmentList.size(); i++) {
- remainingspace=remainingspace-1;
+ /**
+ * Fills the given bound data as a non-compartment child
+ *
+ * @param container
+ * The container to layout
+ * @param bound
+ * The bound to fill
+ * @param previous
+ * The previously filled bound
+ */
+ private void fillBoundsForOther(IFigure container, Rectangle bound, Rectangle previous) {
+ bound.x = container.getBounds().x + 1;
+ bound.width = container.getBounds().width;
+ if (previous == null) {
+ bound.y = container.getBounds().y + 3;
+ } else {
+ bound.y = previous.getBottomLeft().y + 1;
}
-
-
- // ratio between the height of all compartments and the size of the
- // compartments container.
- double ratio = new Integer(compartmentsHeight).doubleValue() / new Integer(remainingspace).doubleValue();
-
- for(int i = 0; i < compartmentList.size(); i++) {
- Rectangle bound = new Rectangle((compartmentList.get(i)).getBounds());
- int value = (int)((double)bound.height / ratio);
- bound.height = value;
- bound.x = container.getBounds().x;
- if(i > 0) {
- bound.y = (compartmentList.get(i - 1)).getBounds().getBottomLeft().y + 1;
-
- }
- (compartmentList.get(i)).setBounds(bound);
+ }
+ /**
+ * Computes the total height of the given list of bounds
+ *
+ * @param bounds
+ * A list of bounds
+ * @param startIndex
+ * The starting index of the bounds to take into account
+ * @param count
+ * The number of bounds to take into account
+ * @return The total height of the slice of bounds data
+ */
+ private double getTotalHeight(List<Rectangle> bounds, int startIndex, int count) {
+ double result = 0.0;
+ for (int i = startIndex; i != startIndex + count; i++) {
+ result += bounds.get(i).preciseHeight();
}
+ return result;
+ }
+ /**
+ * Builds the initial bounds data for all the given children
+ *
+ * @param container
+ * The container to layout
+ * @param visibles
+ * The list of the visible children
+ * @return A list of the bounds of the given children in the same order
+ */
+ private List<Rectangle> buildInitialsBounds(IFigure container, List<IFigure> visibles) {
+ List<Rectangle> result = new ArrayList<Rectangle>(visibles.size());
+ for (IFigure child : visibles) {
+ result.add(buildInitialsBounds(container, child));
+ }
+ return result;
}
/**
- * use to know what kind of element we have in order to apply the good
- * policy for the disposition
+ * Builds the initial bounds data for the given container and child
*
* @param container
+ * The container to layout
+ * @param child
+ * The child for which bounds shall be built
+ * @return The initial child's bounds
*/
- public void collectInformationOnChildren(IFigure container) {
- compartmentList = new ArrayList<IFigure>();
- notCompartmentList = new ArrayList<IFigure>();
- for(int i = 0; i < container.getChildren().size(); i++) {
- if(isAGMFContainer(((IFigure)container.getChildren().get(i)))) {
- compartmentList.add(((IFigure)container.getChildren().get(i)));
- } else if((container.getChildren().get(i)) instanceof Label || (container.getChildren().get(i)) instanceof WrappingLabel || ((container.getChildren().get(i)) instanceof StereotypePropertiesCompartment)) {
- notCompartmentList.add(((IFigure)container.getChildren().get(i)));
- } else {
- if((container.getChildren().get(i)) instanceof ScalableCompartmentFigure) {
- compartmentList.add((IFigure)container.getChildren().get(i));
- }
+ private Rectangle buildInitialsBounds(IFigure container, IFigure child) {
+ Rectangle bounds = new Rectangle(child.getBounds());
+ child.invalidate();
+ Dimension pref = child.getPreferredSize();
+ child.invalidate();
+ Dimension prefConstraint = child.getPreferredSize(container.getBounds().width - 40, -1);
+ if (pref.width < prefConstraint.width) {
+ bounds.setSize(pref);
+ } else {
+ bounds.setSize(prefConstraint);
+ }
+ return bounds;
+ }
+ /**
+ * Layout all the compartment by their default and the label at the forced position
+ *
+ * @param container
+ * The container to layout
+ */
+ protected void layoutForcedLabel(IFigure container) {
+ // first, fixes the order of the children
+ // remove the labels
+ container.getChildren().removeAll(visibleOthers);
+ // add them at the end
+ container.getChildren().addAll(visibleOthers);
+
+ List<Rectangle> bounds = buildInitialsBounds(container, visibleCompartments);
+ double compartmentsHeight = getTotalHeight(bounds, 0, visibleCompartments.size());
+ double remainingspace = container.getBounds().height;
+ // because we move compartment of 1 pixel the space is decrease of 1 per compartment
+ remainingspace -= visibleCompartments.size();
+ // adjustment ratio for the height of the compartments
+ double ratio = compartmentsHeight / remainingspace;
+
+ IFigure shapeCompartment = null;
+ for (int i = 0; i != visibleCompartments.size(); i++) {
+ Rectangle bound = bounds.get(i);
+ fillBoundsForCompartment(container, bound, (i == 0) ? null : bounds.get(i - 1), ratio);
+ IFigure compartment = visibleCompartments.get(i);
+ compartment.setBounds(bound);
+ if (compartment instanceof ScalableCompartmentFigure) {
+ shapeCompartment = (ScalableCompartmentFigure) compartment;
}
}
+
+ Rectangle otherBounds = container.getBounds();
+ if (shapeCompartment != null) {
+ otherBounds = ((SVGNodePlateFigure) container.getParent()).getLabelBounds(shapeCompartment.getBounds());
+ }
+ layoutOthers(otherBounds);
}
/**
- * obtain a prefered size
+ * Collects information on the container to layout
*
- * @param figure
- * that can contain a GMF compartment figure
- * @return a the size
+ * @param container
+ * The container to layout
*/
- public Dimension getPreferedSize(IFigure figure) {
- Dimension dim = figure.getPreferredSize();
- if(figure.getChildren().size() > 0) {
- Object compartment = figure.getChildren().get(0);
- if(compartment instanceof ResizableCompartmentFigure) {
- dim.height = ((ResizableCompartmentFigure)compartment).getPreferredSize().height + 10;
- if(dim.height == 0) {
- dim.height = MINIMUM_COMPARTMENT_HEIGHT;
- }
-
+ protected void collectInformation(IFigure container) {
+ forcedLabelBounds = false;
+ if (container.getParent() instanceof SVGNodePlateFigure) {
+ forcedLabelBounds = ((SVGNodePlateFigure) container.getParent()).hasLabelBounds();
+ }
+ visibleCompartments.clear();
+ visibleOthers.clear();
+ invisibles.clear();
+ for (Object o : container.getChildren()) {
+ IFigure child = (IFigure) o;
+ if (isGMFContainer(child)) {
+ visibleCompartments.add(child);
+ } else if (child instanceof Label || child instanceof WrappingLabel || child instanceof StereotypePropertiesCompartment) {
+ visibleOthers.add(child);
+ } else if (child instanceof ScalableCompartmentFigure) {
+ visibleCompartments.add(child);
+ } else {
+ invisibles.add(child);
}
}
- return dim;
}
/**
- * tests is the figure contains a GMF compartment
+ * Tests whether the figure contains a GMF compartment
*
* @param figure
- * @return true if this is the case
+ * The figure to test
+ * @return <code>true</code> if the figure contains a GMF compartment
*/
- public boolean isAGMFContainer(IFigure figure) {
- if(figure instanceof StereotypePropertiesCompartment) {
+ private boolean isGMFContainer(IFigure figure) {
+ if (figure instanceof StereotypePropertiesCompartment) {
return false;
}
- if(figure.getChildren().size() > 0) {
- if(figure.getChildren().get(0) instanceof ResizableCompartmentFigure) {
+ if (figure.getChildren().size() > 0) {
+ if (figure.getChildren().get(0) instanceof ResizableCompartmentFigure) {
return true;
}
}
return false;
}
-
}
diff --git a/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.statemachine/custom-src/org/eclipse/papyrus/uml/diagram/statemachine/custom/figures/NoExtraHeightLayoutManager.java b/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.statemachine/custom-src/org/eclipse/papyrus/uml/diagram/statemachine/custom/figures/NoExtraHeightLayoutManager.java
index 919b89b..46e3a6d 100644
--- a/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.statemachine/custom-src/org/eclipse/papyrus/uml/diagram/statemachine/custom/figures/NoExtraHeightLayoutManager.java
+++ b/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.statemachine/custom-src/org/eclipse/papyrus/uml/diagram/statemachine/custom/figures/NoExtraHeightLayoutManager.java
@@ -45,12 +45,12 @@ public class NoExtraHeightLayoutManager extends AutomaticCompartmentLayoutManage
protected void optimizeCompartmentSize(IFigure container, int vOffset) {
int compartmentsHeight = 0;
int notCompartmentsHeight = vOffset;
- for(int i = 0; i < notCompartmentList.size(); i++) {
- notCompartmentsHeight += notCompartmentList.get(i).getBounds().height;
+ for(int i = 0; i < visibleOthers.size(); i++) {
+ notCompartmentsHeight += visibleOthers.get(i).getBounds().height;
}
- for(int i = 0; i < compartmentList.size(); i++) {
- compartmentsHeight += compartmentList.get(i).getBounds().height;
+ for(int i = 0; i < visibleCompartments.size(); i++) {
+ compartmentsHeight += visibleCompartments.get(i).getBounds().height;
}
int remainingspace = container.getBounds().height - notCompartmentsHeight;
@@ -58,23 +58,23 @@ public class NoExtraHeightLayoutManager extends AutomaticCompartmentLayoutManage
// compartments container.
double ratio = new Integer(compartmentsHeight).doubleValue() / new Integer(remainingspace).doubleValue();
- for(int i = 0; i < compartmentList.size(); i++) {
- Rectangle bound = new Rectangle((compartmentList.get(i)).getBounds());
+ for(int i = 0; i < visibleCompartments.size(); i++) {
+ Rectangle bound = new Rectangle((visibleCompartments.get(i)).getBounds());
int value = (int)(bound.height / ratio);
bound.height = value;
bound.x = container.getBounds().x;
if(i > 0) {
- bound.y = (compartmentList.get(i - 1)).getBounds().getBottomLeft().y;
+ bound.y = (visibleCompartments.get(i - 1)).getBounds().getBottomLeft().y;
}
- (compartmentList.get(i)).setBounds(bound);
+ (visibleCompartments.get(i)).setBounds(bound);
}
}
@Override
public void layout(IFigure container) {
- collectInformationOnChildren(container);
- if(compartmentList.size() != 0) {
+ collectInformation(container);
+ if(visibleCompartments.size() != 0) {
// visit all compartments
IFigure previousCompartment = null;
int vOffset = 0;
@@ -104,7 +104,7 @@ public class NoExtraHeightLayoutManager extends AutomaticCompartmentLayoutManage
bounds.y = container.getBounds().y;
// difference to superclass: first visible compartment does not start with a vertical offset of 3 pixels, unless
// a "not"-compartment, i.e. a label
- if(notCompartmentList.contains(currentCompartment)) {
+ if(visibleOthers.contains(currentCompartment)) {
vOffset = 3; // is taken into account by optimizeCompartmentSize;
bounds.y += vOffset;
}
@@ -121,7 +121,7 @@ public class NoExtraHeightLayoutManager extends AutomaticCompartmentLayoutManage
}
optimizeCompartmentSize(container, vOffset);
} else {
- layoutCenterForLabel(container);
+ layoutOthers(container.getBounds());
}
}
}