1
0
mirror of https://github.com/octoleo/plantuml.git synced 2024-06-03 09:00:48 +00:00
plantuml/src/net/sourceforge/plantuml/svek/Cluster.java

877 lines
26 KiB
Java
Raw Normal View History

2011-08-08 17:48:29 +00:00
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
2016-01-09 12:15:40 +00:00
* (C) Copyright 2009-2017, Arnaud Roques
2011-08-08 17:48:29 +00:00
*
2016-03-06 16:47:34 +00:00
* Project Info: http://plantuml.com
2011-08-08 17:48:29 +00:00
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
2013-12-10 19:36:50 +00:00
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
2011-08-08 17:48:29 +00:00
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* Original Author: Arnaud Roques
*
* Revision $Revision: 4236 $
*
*/
package net.sourceforge.plantuml.svek;
import java.awt.geom.Dimension2D;
2013-12-10 19:36:50 +00:00
import java.awt.geom.Point2D;
2011-08-08 17:48:29 +00:00
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
2016-04-04 19:05:10 +00:00
import java.util.EnumSet;
2011-08-08 17:48:29 +00:00
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.sourceforge.plantuml.ColorParam;
import net.sourceforge.plantuml.Dimension2DDouble;
2013-12-10 19:36:50 +00:00
import net.sourceforge.plantuml.FontParam;
import net.sourceforge.plantuml.ISkinParam;
2015-04-07 18:18:37 +00:00
import net.sourceforge.plantuml.LineParam;
2015-09-28 20:42:17 +00:00
import net.sourceforge.plantuml.SkinParamUtils;
2016-03-06 16:47:34 +00:00
import net.sourceforge.plantuml.StringUtils;
2011-08-08 17:48:29 +00:00
import net.sourceforge.plantuml.UmlDiagramType;
2013-12-10 19:36:50 +00:00
import net.sourceforge.plantuml.Url;
import net.sourceforge.plantuml.cucadiagram.EntityPosition;
import net.sourceforge.plantuml.cucadiagram.EntityUtils;
2011-09-08 10:42:27 +00:00
import net.sourceforge.plantuml.cucadiagram.IEntity;
2013-12-10 19:36:50 +00:00
import net.sourceforge.plantuml.cucadiagram.IGroup;
import net.sourceforge.plantuml.cucadiagram.Member;
import net.sourceforge.plantuml.cucadiagram.MethodsOrFieldsArea;
import net.sourceforge.plantuml.cucadiagram.Stereotype;
2015-04-07 18:18:37 +00:00
import net.sourceforge.plantuml.cucadiagram.dot.GraphvizVersion;
2011-08-08 17:48:29 +00:00
import net.sourceforge.plantuml.graphic.HtmlColor;
2013-12-10 19:36:50 +00:00
import net.sourceforge.plantuml.graphic.HtmlColorTransparent;
2011-09-08 10:42:27 +00:00
import net.sourceforge.plantuml.graphic.StringBounder;
2011-08-08 17:48:29 +00:00
import net.sourceforge.plantuml.graphic.TextBlock;
2013-12-10 19:36:50 +00:00
import net.sourceforge.plantuml.graphic.TextBlockEmpty;
import net.sourceforge.plantuml.graphic.TextBlockWidth;
2015-04-07 18:18:37 +00:00
import net.sourceforge.plantuml.graphic.USymbol;
2015-09-28 20:42:17 +00:00
import net.sourceforge.plantuml.graphic.color.ColorType;
2011-09-08 10:42:27 +00:00
import net.sourceforge.plantuml.posimo.Moveable;
2011-08-08 17:48:29 +00:00
import net.sourceforge.plantuml.skin.rose.Rose;
2013-12-10 19:36:50 +00:00
import net.sourceforge.plantuml.svek.image.EntityImageState;
import net.sourceforge.plantuml.ugraphic.UChangeBackColor;
import net.sourceforge.plantuml.ugraphic.UChangeColor;
2011-08-08 17:48:29 +00:00
import net.sourceforge.plantuml.ugraphic.UGraphic;
2011-09-08 10:42:27 +00:00
import net.sourceforge.plantuml.ugraphic.ULine;
2011-08-08 17:48:29 +00:00
import net.sourceforge.plantuml.ugraphic.URectangle;
import net.sourceforge.plantuml.ugraphic.UStroke;
2013-12-10 19:36:50 +00:00
import net.sourceforge.plantuml.ugraphic.UTranslate;
2015-04-07 18:18:37 +00:00
import net.sourceforge.plantuml.utils.UniqueSequence;
2011-08-08 17:48:29 +00:00
2011-09-08 10:42:27 +00:00
public class Cluster implements Moveable {
2011-08-08 17:48:29 +00:00
private final Cluster parent;
2013-12-10 19:36:50 +00:00
private final IGroup group;
2011-08-08 17:48:29 +00:00
private final List<Shape> shapes = new ArrayList<Shape>();
private final List<Cluster> children = new ArrayList<Cluster>();
private final int color;
private final int colorTitle;
2013-12-10 19:36:50 +00:00
private final ISkinParam skinParam;
2011-08-08 17:48:29 +00:00
2013-12-10 19:36:50 +00:00
private int titleAndAttributeWidth;
private int titleAndAttributeHeight;
private TextBlock ztitle;
private TextBlock zstereo;
2011-09-08 10:42:27 +00:00
private double xTitle;
private double yTitle;
private double minX;
private double minY;
private double maxX;
private double maxY;
public void moveSvek(double deltaX, double deltaY) {
this.xTitle += deltaX;
this.minX += deltaX;
this.maxX += deltaX;
this.yTitle += deltaY;
this.minY += deltaY;
this.maxY += deltaY;
}
2013-12-10 19:36:50 +00:00
private boolean hasEntryOrExitPoint() {
for (Shape sh : shapes) {
if (sh.getEntityPosition() != EntityPosition.NORMAL) {
return true;
}
}
return false;
2011-08-08 17:48:29 +00:00
}
2013-12-10 19:36:50 +00:00
public Cluster(ColorSequence colorSequence, ISkinParam skinParam, IGroup root) {
this(null, root, colorSequence, skinParam);
2011-08-08 17:48:29 +00:00
}
2015-04-07 18:18:37 +00:00
private ColorParam border;
2013-12-10 19:36:50 +00:00
private Cluster(Cluster parent, IGroup group, ColorSequence colorSequence, ISkinParam skinParam) {
if (group == null) {
throw new IllegalStateException();
}
2011-08-08 17:48:29 +00:00
this.parent = parent;
this.group = group;
2015-04-07 18:18:37 +00:00
if (group.getUSymbol() != null) {
border = group.getUSymbol().getColorParamBorder();
}
2011-08-08 17:48:29 +00:00
this.color = colorSequence.getValue();
this.colorTitle = colorSequence.getValue();
2015-09-28 20:42:17 +00:00
this.skinParam = group.getColors(skinParam).mute(skinParam);
2011-08-08 17:48:29 +00:00
}
@Override
public String toString() {
return super.toString() + " " + group;
}
public final Cluster getParent() {
return parent;
}
public void addShape(Shape sh) {
2013-12-10 19:36:50 +00:00
if (sh == null) {
throw new IllegalArgumentException();
}
2011-08-08 17:48:29 +00:00
this.shapes.add(sh);
sh.setCluster(this);
}
public final List<Shape> getShapes() {
return Collections.unmodifiableList(shapes);
}
2013-12-10 19:36:50 +00:00
private List<Shape> getShapesOrderedTop(Collection<Line> lines) {
2011-08-08 17:48:29 +00:00
final List<Shape> firsts = new ArrayList<Shape>();
final Set<String> tops = new HashSet<String>();
final Map<String, Shape> shs = new HashMap<String, Shape>();
2013-12-10 19:36:50 +00:00
for (final Iterator<Shape> it = shapes.iterator(); it.hasNext();) {
final Shape sh = it.next();
shs.put(sh.getUid(), sh);
if (sh.isTop() && sh.getEntityPosition() == EntityPosition.NORMAL) {
firsts.add(sh);
tops.add(sh.getUid());
}
}
for (Line l : lines) {
if (tops.contains(l.getStartUid())) {
final Shape sh = shs.get(l.getEndUid());
if (sh != null && sh.getEntityPosition() == EntityPosition.NORMAL) {
firsts.add(0, sh);
}
}
if (l.isInverted()) {
final Shape sh = shs.get(l.getStartUid());
if (sh != null && sh.getEntityPosition() == EntityPosition.NORMAL) {
firsts.add(0, sh);
}
}
}
return firsts;
}
2016-04-04 19:05:10 +00:00
private List<Shape> getShapesEntryExit(EnumSet<EntityPosition> positions) {
2013-12-10 19:36:50 +00:00
final List<Shape> result = new ArrayList<Shape>();
for (final Iterator<Shape> it = shapes.iterator(); it.hasNext();) {
final Shape sh = it.next();
2016-04-04 19:05:10 +00:00
if (positions.contains(sh.getEntityPosition())) {
2013-12-10 19:36:50 +00:00
result.add(sh);
}
}
return result;
}
private List<Shape> getShapesOrderedWithoutTop(Collection<Line> lines) {
final List<Shape> all = new ArrayList<Shape>(shapes);
final Set<String> tops = new HashSet<String>();
final Map<String, Shape> shs = new HashMap<String, Shape>();
2011-08-08 17:48:29 +00:00
for (final Iterator<Shape> it = all.iterator(); it.hasNext();) {
final Shape sh = it.next();
2013-12-10 19:36:50 +00:00
if (sh.getEntityPosition() != EntityPosition.NORMAL) {
it.remove();
continue;
}
2011-08-08 17:48:29 +00:00
shs.put(sh.getUid(), sh);
if (sh.isTop()) {
tops.add(sh.getUid());
it.remove();
}
}
for (Line l : lines) {
if (tops.contains(l.getStartUid())) {
final Shape sh = shs.get(l.getEndUid());
2013-12-10 19:36:50 +00:00
if (sh != null) {
all.remove(sh);
}
2011-08-08 17:48:29 +00:00
}
2013-12-10 19:36:50 +00:00
2011-08-08 17:48:29 +00:00
if (l.isInverted()) {
final Shape sh = shs.get(l.getStartUid());
2013-12-10 19:36:50 +00:00
if (sh != null) {
all.remove(sh);
}
2011-08-08 17:48:29 +00:00
}
}
return all;
}
public final List<Cluster> getChildren() {
return Collections.unmodifiableList(children);
}
2013-12-10 19:36:50 +00:00
public Cluster createChild(IGroup g, int titleAndAttributeWidth, int titleAndAttributeHeight, TextBlock title,
TextBlock stereo, ColorSequence colorSequence, ISkinParam skinParam) {
final Cluster child = new Cluster(this, g, colorSequence, skinParam);
child.titleAndAttributeWidth = titleAndAttributeWidth;
child.titleAndAttributeHeight = titleAndAttributeHeight;
child.ztitle = title;
child.zstereo = stereo;
2011-08-08 17:48:29 +00:00
this.children.add(child);
return child;
}
2013-12-10 19:36:50 +00:00
public final IGroup getGroup() {
2011-08-08 17:48:29 +00:00
return group;
}
2013-12-10 19:36:50 +00:00
public final int getTitleAndAttributeWidth() {
return titleAndAttributeWidth;
}
public final int getTitleAndAttributeHeight() {
return titleAndAttributeHeight;
}
public double getWidth() {
return maxX - minX;
}
public double getMinX() {
return minX;
2011-08-08 17:48:29 +00:00
}
2013-12-10 19:36:50 +00:00
public ClusterPosition getClusterPosition() {
return new ClusterPosition(minX, minY, maxX, maxY);
2011-08-08 17:48:29 +00:00
}
public void setTitlePosition(double x, double y) {
this.xTitle = x;
this.yTitle = y;
}
2015-08-05 20:17:01 +00:00
private static HtmlColor getColor(ColorParam colorParam, ISkinParam skinParam, Stereotype stereotype) {
2015-09-28 20:42:17 +00:00
return SkinParamUtils.getColor(skinParam, colorParam, stereotype);
2015-04-07 18:18:37 +00:00
}
2016-03-06 16:47:34 +00:00
public void drawU(UGraphic ug, UStroke stroke, final UmlDiagramType umlDiagramType, final ISkinParam skinParam2) {
2015-08-05 20:17:01 +00:00
final Stereotype stereotype = group.getStereotype();
2015-04-07 18:18:37 +00:00
HtmlColor borderColor;
2016-03-06 16:47:34 +00:00
if (umlDiagramType == UmlDiagramType.STATE) {
2015-09-28 20:42:17 +00:00
borderColor = getColor(ColorParam.stateBorder, skinParam, stereotype);
2015-04-07 18:18:37 +00:00
} else {
2015-09-28 20:42:17 +00:00
borderColor = getColor(ColorParam.packageBorder, skinParam, stereotype);
2015-04-07 18:18:37 +00:00
}
2013-12-10 19:36:50 +00:00
final Url url = group.getUrl99();
if (url != null) {
ug.startUrl(url);
2011-08-08 17:48:29 +00:00
}
2013-12-10 19:36:50 +00:00
try {
if (hasEntryOrExitPoint()) {
2016-03-06 16:47:34 +00:00
manageEntryExitPoint(ug.getStringBounder());
2013-12-10 19:36:50 +00:00
}
2016-03-06 16:47:34 +00:00
if (skinParam.useSwimlanes(umlDiagramType)) {
drawSwinLinesState(ug, borderColor);
2013-12-10 19:36:50 +00:00
return;
}
2016-03-06 16:47:34 +00:00
final boolean isState = umlDiagramType == UmlDiagramType.STATE;
2013-12-10 19:36:50 +00:00
if (isState) {
2015-09-28 20:42:17 +00:00
if (group.getColors(skinParam).getSpecificLineStroke() != null) {
stroke = group.getColors(skinParam).getSpecificLineStroke();
2015-04-07 18:18:37 +00:00
}
2015-09-28 20:42:17 +00:00
if (group.getColors(skinParam).getColor(ColorType.LINE) != null) {
borderColor = group.getColors(skinParam).getColor(ColorType.LINE);
2015-04-07 18:18:37 +00:00
}
2016-03-06 16:47:34 +00:00
drawUState(ug, borderColor, skinParam2, stroke);
2013-12-10 19:36:50 +00:00
return;
}
PackageStyle style = group.getPackageStyle();
if (style == null) {
2016-03-06 16:47:34 +00:00
style = skinParam2.getPackageStyle();
2013-12-10 19:36:50 +00:00
}
2015-04-07 18:18:37 +00:00
if (border != null) {
2016-03-06 16:47:34 +00:00
final HtmlColor tmp = skinParam2.getHtmlColor(border, group.getStereotype(), false);
2015-04-07 18:18:37 +00:00
if (tmp != null) {
borderColor = tmp;
}
}
2013-12-10 19:36:50 +00:00
if (ztitle != null || zstereo != null) {
2016-03-06 16:47:34 +00:00
final HtmlColor back = getBackColor(getBackColor(), skinParam2, group.getStereotype());
2013-12-10 19:36:50 +00:00
final ClusterDecoration decoration = new ClusterDecoration(style, group.getUSymbol(), ztitle, zstereo,
2016-03-06 16:47:34 +00:00
minX, minY, maxX, maxY, getStroke(skinParam2, group.getStereotype()));
decoration.drawU(ug, back, borderColor, skinParam2.shadowing());
2013-12-10 19:36:50 +00:00
return;
}
final URectangle rect = new URectangle(maxX - minX, maxY - minY);
2016-03-06 16:47:34 +00:00
if (skinParam2.shadowing()) {
2013-12-10 19:36:50 +00:00
rect.setDeltaShadow(3.0);
}
2016-03-06 16:47:34 +00:00
final HtmlColor backColor = getBackColor(getBackColor(), skinParam2, group.getStereotype());
2015-09-06 17:28:59 +00:00
ug = ug.apply(new UChangeBackColor(backColor)).apply(new UChangeColor(borderColor));
2013-12-10 19:36:50 +00:00
ug.apply(new UStroke(2)).apply(new UTranslate(minX, minY)).draw(rect);
} finally {
if (url != null) {
ug.closeAction();
}
2011-08-08 17:48:29 +00:00
}
2011-09-08 10:42:27 +00:00
2013-12-10 19:36:50 +00:00
}
2011-09-08 10:42:27 +00:00
2015-04-07 18:18:37 +00:00
private UStroke getStroke(ISkinParam skinParam, Stereotype stereo) {
UStroke stroke = skinParam.getThickness(LineParam.packageBorder, stereo);
if (stroke == null) {
stroke = new UStroke(2.0);
}
return stroke;
}
2016-03-06 16:47:34 +00:00
public void manageEntryExitPoint(StringBounder stringBounder) {
2013-12-10 19:36:50 +00:00
final Collection<ClusterPosition> insides = new ArrayList<ClusterPosition>();
final List<Point2D> points = new ArrayList<Point2D>();
for (Shape sh : shapes) {
if (sh.getEntityPosition() == EntityPosition.NORMAL) {
insides.add(sh.getClusterPosition());
} else {
points.add(sh.getClusterPosition().getPointCenter());
}
2011-08-08 17:48:29 +00:00
}
2013-12-10 19:36:50 +00:00
for (Cluster in : children) {
insides.add(in.getClusterPosition());
2011-09-08 10:42:27 +00:00
}
2013-12-10 19:36:50 +00:00
final FrontierCalculator frontierCalculator = new FrontierCalculator(getClusterPosition(), insides, points);
if (titleAndAttributeHeight > 0 && titleAndAttributeWidth > 0) {
frontierCalculator.ensureMinWidth(titleAndAttributeWidth + 10);
2011-09-08 10:42:27 +00:00
}
2013-12-10 19:36:50 +00:00
final ClusterPosition forced = frontierCalculator.getSuggestedPosition();
xTitle += ((forced.getMinX() - minX) + (forced.getMaxX() - maxX)) / 2;
minX = forced.getMinX();
minY = forced.getMinY();
maxX = forced.getMaxX();
maxY = forced.getMaxY();
yTitle = minY + IEntityImage.MARGIN;
final double widthTitle = ztitle.calculateDimension(stringBounder).getWidth();
xTitle = minX + ((maxX - minX - widthTitle) / 2);
}
2016-03-06 16:47:34 +00:00
private void drawSwinLinesState(UGraphic ug, HtmlColor borderColor) {
2013-12-10 19:36:50 +00:00
if (ztitle != null) {
ztitle.drawU(ug.apply(new UTranslate(xTitle, 0)));
2011-09-08 10:42:27 +00:00
}
2013-12-10 19:36:50 +00:00
final ULine line = new ULine(0, maxY - minY);
ug = ug.apply(new UChangeColor(borderColor));
ug.apply(new UTranslate(minX, 0)).draw(line);
ug.apply(new UTranslate(maxX, 0)).draw(line);
2011-08-08 17:48:29 +00:00
}
2016-03-06 16:47:34 +00:00
private HtmlColor getColor(ISkinParam skinParam, ColorParam colorParam, Stereotype stereo) {
return new Rose().getHtmlColor(skinParam, colorParam, stereo);
2011-08-08 17:48:29 +00:00
}
2016-03-06 16:47:34 +00:00
private void drawUState(UGraphic ug, HtmlColor borderColor, ISkinParam skinParam2, UStroke stroke) {
2011-08-08 17:48:29 +00:00
final Dimension2D total = new Dimension2DDouble(maxX - minX, maxY - minY);
2013-12-10 19:36:50 +00:00
final double suppY;
if (ztitle == null) {
suppY = 0;
} else {
suppY = ztitle.calculateDimension(ug.getStringBounder()).getHeight() + IEntityImage.MARGIN
+ IEntityImage.MARGIN_LINE;
}
2011-08-08 17:48:29 +00:00
HtmlColor stateBack = getBackColor();
if (stateBack == null) {
2016-03-06 16:47:34 +00:00
stateBack = getColor(skinParam2, ColorParam.stateBackground, group.getStereotype());
2011-08-08 17:48:29 +00:00
}
2016-03-06 16:47:34 +00:00
final HtmlColor background = getColor(skinParam2, ColorParam.background, null);
final TextBlockWidth attribute = getTextBlockAttribute(skinParam2);
2013-12-10 19:36:50 +00:00
final double attributeHeight = attribute.calculateDimension(ug.getStringBounder()).getHeight();
final RoundedContainer r = new RoundedContainer(total, suppY, attributeHeight
2015-04-07 18:18:37 +00:00
+ (attributeHeight > 0 ? IEntityImage.MARGIN : 0), borderColor, stateBack, background, stroke);
2016-03-06 16:47:34 +00:00
r.drawU(ug.apply(new UTranslate(minX, minY)), skinParam2.shadowing());
2011-08-08 17:48:29 +00:00
2013-12-10 19:36:50 +00:00
if (ztitle != null) {
ztitle.drawU(ug.apply(new UTranslate(xTitle, yTitle)));
}
2011-08-08 17:48:29 +00:00
2013-12-10 19:36:50 +00:00
if (attributeHeight > 0) {
attribute.asTextBlock(total.getWidth()).drawU(
ug.apply(new UTranslate(minX + IEntityImage.MARGIN, minY + suppY + IEntityImage.MARGIN / 2.0)));
}
final Stereotype stereotype = group.getStereotype();
final boolean withSymbol = stereotype != null && stereotype.isWithOOSymbol();
if (withSymbol) {
EntityImageState.drawSymbol(ug.apply(new UChangeColor(borderColor)), maxX, maxY);
}
}
2016-03-06 16:47:34 +00:00
private TextBlockWidth getTextBlockAttribute(ISkinParam skinParam) {
2013-12-10 19:36:50 +00:00
final TextBlockWidth attribute;
2015-06-07 10:23:10 +00:00
final List<Member> members = group.getBodier().getFieldsToDisplay();
2013-12-10 19:36:50 +00:00
if (members.size() == 0) {
attribute = new TextBlockEmpty();
} else {
2016-03-06 16:47:34 +00:00
attribute = new MethodsOrFieldsArea(members, FontParam.STATE_ATTRIBUTE, skinParam, group.getStereotype());
2013-12-10 19:36:50 +00:00
}
return attribute;
2011-08-08 17:48:29 +00:00
}
public void setPosition(double minX, double minY, double maxX, double maxY) {
this.minX = minX;
this.maxX = maxX;
this.minY = minY;
this.maxY = maxY;
}
2013-12-10 19:36:50 +00:00
private boolean isThereALinkFromOrToGroup(Collection<Line> lines) {
for (Line line : lines) {
2015-04-07 18:18:37 +00:00
if (line.isLinkFromOrTo(group)) {
2013-12-10 19:36:50 +00:00
return true;
}
}
return false;
2011-08-08 17:48:29 +00:00
}
2013-12-10 19:36:50 +00:00
public void printCluster1(StringBuilder sb, Collection<Line> lines) {
for (Shape sh : getShapesOrderedTop(lines)) {
sh.appendShape(sb);
}
}
2011-08-08 17:48:29 +00:00
2013-12-10 19:36:50 +00:00
private List<IShapePseudo> addProtection(List<Shape> entries, double width) {
final List<IShapePseudo> result = new ArrayList<IShapePseudo>();
result.add(entries.get(0));
for (int i = 1; i < entries.size(); i++) {
result.add(new ShapePseudoImpl("psd" + UniqueSequence.getValue(), width, 5));
result.add(entries.get(i));
}
return result;
}
private double getMaxWidthFromLabelForEntryExit(List<Shape> entries, StringBounder stringBounder) {
double result = -Double.MAX_VALUE;
for (Shape shape : entries) {
final double w = getMaxWidthFromLabelForEntryExit(shape, stringBounder);
if (w > result) {
result = w;
}
}
return result;
}
private double getMaxWidthFromLabelForEntryExit(Shape shape, StringBounder stringBounder) {
return shape.getMaxWidthFromLabelForEntryExit(stringBounder);
}
public void printClusterEntryExit(StringBuilder sb, StringBounder stringBounder) {
2016-04-04 19:05:10 +00:00
final List<Shape> shapesEntryExitList = getShapesEntryExit(EntityPosition.getInputs());
2013-12-10 19:36:50 +00:00
final double maxWith = getMaxWidthFromLabelForEntryExit(shapesEntryExitList, stringBounder);
final double naturalSpace = 70;
final List<? extends IShapePseudo> entries;
if (maxWith > naturalSpace) {
entries = addProtection(shapesEntryExitList, maxWith - naturalSpace);
} else {
entries = shapesEntryExitList;
}
if (entries.size() > 0) {
sb.append("{rank=source;");
for (IShapePseudo sh : entries) {
sb.append(sh.getUid() + ";");
}
sb.append("}");
for (IShapePseudo sh : entries) {
sh.appendShape(sb);
2011-08-08 17:48:29 +00:00
}
}
2016-04-04 19:05:10 +00:00
final List<Shape> exits = getShapesEntryExit(EntityPosition.getOutputs());
2013-12-10 19:36:50 +00:00
if (exits.size() > 0) {
sb.append("{rank=sink;");
for (Shape sh : exits) {
sb.append(sh.getUid() + ";");
}
sb.append("}");
for (Shape sh : exits) {
sh.appendShape(sb);
}
}
}
2011-08-08 17:48:29 +00:00
2015-04-07 18:18:37 +00:00
public boolean printCluster2(StringBuilder sb, Collection<Line> lines, StringBounder stringBounder,
DotMode dotMode, GraphvizVersion graphvizVersion, UmlDiagramType type) {
2013-12-10 19:36:50 +00:00
// Log.println("Cluster::printCluster " + this);
boolean added = false;
for (Shape sh : getShapesOrderedWithoutTop(lines)) {
2011-08-08 17:48:29 +00:00
sh.appendShape(sb);
2013-12-10 19:36:50 +00:00
added = true;
}
if (dotMode != DotMode.NO_LEFT_RIGHT) {
appendRankSame(sb, lines);
}
for (Cluster child : getChildren()) {
2015-04-07 18:18:37 +00:00
child.printInternal(sb, lines, stringBounder, dotMode, graphvizVersion, type);
2011-08-08 17:48:29 +00:00
}
2013-12-10 19:36:50 +00:00
return added;
}
private void appendRankSame(StringBuilder sb, Collection<Line> lines) {
for (String same : getRankSame(lines)) {
2011-08-08 17:48:29 +00:00
sb.append(same);
SvekUtils.println(sb);
}
2013-12-10 19:36:50 +00:00
}
2011-08-08 17:48:29 +00:00
2013-12-10 19:36:50 +00:00
private Set<String> getRankSame(Collection<Line> lines) {
final Set<String> rankSame = new HashSet<String>();
for (Line l : lines) {
if (l.hasEntryPoint()) {
continue;
}
final String startUid = l.getStartUid();
final String endUid = l.getEndUid();
if (isInCluster(startUid) && isInCluster(endUid)) {
final String same = l.rankSame();
if (same != null) {
rankSame.add(same);
}
}
2011-08-08 17:48:29 +00:00
}
2013-12-10 19:36:50 +00:00
return rankSame;
2011-08-08 17:48:29 +00:00
}
public void fillRankMin(Set<String> rankMin) {
for (Shape sh : getShapes()) {
if (sh.isTop()) {
rankMin.add(sh.getUid());
}
}
for (Cluster child : getChildren()) {
child.fillRankMin(rankMin);
}
}
private boolean isInCluster(String uid) {
for (Shape sh : shapes) {
if (sh.getUid().equals(uid)) {
return true;
}
}
return false;
}
public String getClusterId() {
return "cluster" + color;
}
2013-12-10 19:36:50 +00:00
public static String getSpecialPointId(IEntity group) {
return CENTER_ID + group.getUid();
2011-08-08 17:48:29 +00:00
}
2013-12-10 19:36:50 +00:00
public final static String CENTER_ID = "za";
2011-09-08 10:42:27 +00:00
2015-04-07 18:18:37 +00:00
private boolean protection0(UmlDiagramType type) {
if (skinParam.useSwimlanes(type)) {
2013-12-10 19:36:50 +00:00
return false;
}
return true;
}
2011-09-08 10:42:27 +00:00
2015-04-07 18:18:37 +00:00
private boolean protection1(UmlDiagramType type) {
if (group.getUSymbol() == USymbol.NODE) {
return true;
}
if (skinParam.useSwimlanes(type)) {
2013-12-10 19:36:50 +00:00
return false;
}
return true;
}
2015-04-07 18:18:37 +00:00
public String getMinPoint(UmlDiagramType type) {
if (skinParam.useSwimlanes(type)) {
2013-12-10 19:36:50 +00:00
return "minPoint" + color;
}
return null;
}
2015-04-07 18:18:37 +00:00
public String getMaxPoint(UmlDiagramType type) {
if (skinParam.useSwimlanes(type)) {
2013-12-10 19:36:50 +00:00
return "maxPoint" + color;
}
return null;
}
2015-04-07 18:18:37 +00:00
private String getSourceInPoint(UmlDiagramType type) {
if (skinParam.useSwimlanes(type)) {
2013-12-10 19:36:50 +00:00
return "sourceIn" + color;
}
return null;
}
2015-04-07 18:18:37 +00:00
private String getSinkInPoint(UmlDiagramType type) {
if (skinParam.useSwimlanes(type)) {
2013-12-10 19:36:50 +00:00
return "sinkIn" + color;
}
return null;
}
2015-04-07 18:18:37 +00:00
private void printInternal(StringBuilder sb, Collection<Line> lines, StringBounder stringBounder, DotMode dotMode,
GraphvizVersion graphvizVersion, UmlDiagramType type) {
final boolean thereALinkFromOrToGroup2 = isThereALinkFromOrToGroup(lines);
boolean thereALinkFromOrToGroup1 = thereALinkFromOrToGroup2;
final boolean useProtectionWhenThereALinkFromOrToGroup = graphvizVersion
.useProtectionWhenThereALinkFromOrToGroup();
if (useProtectionWhenThereALinkFromOrToGroup == false) {
thereALinkFromOrToGroup1 = false;
}
// final boolean thereALinkFromOrToGroup1 = false;
if (thereALinkFromOrToGroup1) {
2011-08-08 17:48:29 +00:00
subgraphCluster(sb, "a");
}
2013-12-10 19:36:50 +00:00
final boolean hasEntryOrExitPoint = hasEntryOrExitPoint();
if (hasEntryOrExitPoint) {
for (Line line : lines) {
2015-04-07 18:18:37 +00:00
if (line.isLinkFromOrTo(group)) {
2013-12-10 19:36:50 +00:00
line.setProjectionCluster(this);
}
}
}
2015-04-07 18:18:37 +00:00
boolean protection0 = protection0(type);
boolean protection1 = protection1(type);
if (hasEntryOrExitPoint || useProtectionWhenThereALinkFromOrToGroup == false) {
2013-12-10 19:36:50 +00:00
protection0 = false;
protection1 = false;
}
2016-06-19 14:16:41 +00:00
// if (graphvizVersion.modeSafe()) {
// protection0 = false;
// protection1 = false;
// }
2011-09-08 10:42:27 +00:00
if (protection0) {
subgraphCluster(sb, "p0");
}
2011-08-08 17:48:29 +00:00
sb.append("subgraph " + getClusterId() + " {");
sb.append("style=solid;");
sb.append("color=\"" + StringUtils.getAsHtml(color) + "\";");
2013-12-10 19:36:50 +00:00
final String label;
2016-04-04 19:05:10 +00:00
if (isLabel()) {
2013-12-10 19:36:50 +00:00
final StringBuilder sblabel = new StringBuilder("<");
Line.appendTable(sblabel, getTitleAndAttributeWidth(), getTitleAndAttributeHeight() - 5, colorTitle);
sblabel.append(">");
label = sblabel.toString();
} else {
label = "\"\"";
}
if (hasEntryOrExitPoint) {
printClusterEntryExit(sb, stringBounder);
subgraphCluster(sb, "ee", label);
} else {
sb.append("label=" + label + ";");
SvekUtils.println(sb);
2011-08-08 17:48:29 +00:00
}
2013-12-10 19:36:50 +00:00
// if (hasEntryOrExitPoint) {
// printClusterEntryExit(sb);
// subgraphCluster(sb, "ee");
// }
2015-04-07 18:18:37 +00:00
if (thereALinkFromOrToGroup2) {
2013-12-10 19:36:50 +00:00
sb.append(getSpecialPointId(group) + " [shape=point,width=.01,label=\"\"];");
2015-04-07 18:18:37 +00:00
}
if (thereALinkFromOrToGroup1) {
2011-08-08 17:48:29 +00:00
subgraphCluster(sb, "i");
}
2011-09-08 10:42:27 +00:00
if (protection1) {
subgraphCluster(sb, "p1");
}
2015-04-07 18:18:37 +00:00
if (skinParam.useSwimlanes(type)) {
2013-12-10 19:36:50 +00:00
sb.append("{rank = source; ");
2015-04-07 18:18:37 +00:00
sb.append(getSourceInPoint(type));
2013-12-10 19:36:50 +00:00
sb.append(" [shape=point,width=.01,label=\"\"];");
2015-04-07 18:18:37 +00:00
sb.append(getMinPoint(type) + "->" + getSourceInPoint(type) + " [weight=999];");
2013-12-10 19:36:50 +00:00
sb.append("}");
SvekUtils.println(sb);
sb.append("{rank = sink; ");
2015-04-07 18:18:37 +00:00
sb.append(getSinkInPoint(type));
2013-12-10 19:36:50 +00:00
sb.append(" [shape=point,width=.01,label=\"\"];");
sb.append("}");
2015-04-07 18:18:37 +00:00
sb.append(getSinkInPoint(type) + "->" + getMaxPoint(type) + " [weight=999];");
2013-12-10 19:36:50 +00:00
SvekUtils.println(sb);
}
SvekUtils.println(sb);
printCluster1(sb, lines);
2015-04-07 18:18:37 +00:00
final boolean added = printCluster2(sb, lines, stringBounder, dotMode, graphvizVersion, type);
2013-12-10 19:36:50 +00:00
if (hasEntryOrExitPoint && added == false) {
final String empty = "empty" + color;
sb.append(empty + " [shape=point,width=.01,label=\"\"];");
}
sb.append("}");
2011-09-08 10:42:27 +00:00
if (protection1) {
sb.append("}");
}
2015-04-07 18:18:37 +00:00
if (thereALinkFromOrToGroup1) {
2013-12-10 19:36:50 +00:00
sb.append("}");
2011-08-08 17:48:29 +00:00
sb.append("}");
}
2013-12-10 19:36:50 +00:00
if (hasEntryOrExitPoint) {
2011-09-08 10:42:27 +00:00
sb.append("}");
}
2013-12-10 19:36:50 +00:00
if (protection0) {
2011-08-08 17:48:29 +00:00
sb.append("}");
}
SvekUtils.println(sb);
}
2016-04-04 19:05:10 +00:00
public boolean isLabel() {
return getTitleAndAttributeHeight() > 0 && getTitleAndAttributeWidth() > 0;
}
2011-08-08 17:48:29 +00:00
private void subgraphCluster(StringBuilder sb, String id) {
2013-12-10 19:36:50 +00:00
subgraphCluster(sb, id, "\"\"");
}
private void subgraphCluster(StringBuilder sb, String id, String label) {
2011-08-08 17:48:29 +00:00
final String uid = getClusterId() + id;
sb.append("subgraph " + uid + " {");
2013-12-10 19:36:50 +00:00
sb.append("label=" + label + ";");
2011-08-08 17:48:29 +00:00
}
public int getColor() {
return color;
}
public int getTitleColor() {
return colorTitle;
}
private final HtmlColor getBackColor() {
2013-12-10 19:36:50 +00:00
if (EntityUtils.groupRoot(group)) {
2011-09-08 10:42:27 +00:00
return null;
}
2015-09-28 20:42:17 +00:00
final HtmlColor result = group.getColors(skinParam).getColor(ColorType.BACK);
2011-09-08 10:42:27 +00:00
if (result != null) {
return result;
}
2015-04-07 18:18:37 +00:00
final Stereotype stereo = group.getStereotype();
final USymbol sym = group.getUSymbol() == null ? USymbol.PACKAGE : group.getUSymbol();
final ColorParam backparam = sym.getColorParamBack();
final HtmlColor c1 = skinParam.getHtmlColor(backparam, stereo, false);
if (c1 != null) {
return c1;
}
2011-09-08 10:42:27 +00:00
if (parent == null) {
return null;
}
return parent.getBackColor();
}
public boolean isClusterOf(IEntity ent) {
2013-12-10 19:36:50 +00:00
if (ent.isGroup() == false) {
2011-09-08 10:42:27 +00:00
return false;
}
2013-12-10 19:36:50 +00:00
return group == ent;
2011-08-08 17:48:29 +00:00
}
2015-08-05 20:17:01 +00:00
public static HtmlColor getBackColor(HtmlColor backColor, ISkinParam skinParam, Stereotype stereotype) {
if (backColor == null) {
backColor = skinParam.getHtmlColor(ColorParam.packageBackground, stereotype, false);
2013-12-10 19:36:50 +00:00
}
2015-08-05 20:17:01 +00:00
if (backColor == null) {
backColor = skinParam.getHtmlColor(ColorParam.background, stereotype, false);
2013-12-10 19:36:50 +00:00
}
2015-08-05 20:17:01 +00:00
if (backColor == null /* || stateBack instanceof HtmlColorTransparent */) {
backColor = new HtmlColorTransparent();
2013-12-10 19:36:50 +00:00
}
2015-08-05 20:17:01 +00:00
return backColor;
2013-12-10 19:36:50 +00:00
}
2015-04-07 18:18:37 +00:00
public double checkFolderPosition(Point2D pt, StringBounder stringBounder) {
if (getClusterPosition().isPointJustUpper(pt)) {
if (ztitle == null) {
return 0;
}
final Dimension2D dimTitle = ztitle.calculateDimension(stringBounder);
if (pt.getX() < getClusterPosition().getMinX() + dimTitle.getWidth()) {
return 0;
}
return getClusterPosition().getMinY() - pt.getY() + dimTitle.getHeight();
}
return 0;
}
2013-12-10 19:36:50 +00:00
// public Point2D projection(double x, double y) {
// final double v1 = Math.abs(minX - x);
// final double v2 = Math.abs(maxX - x);
// final double v3 = Math.abs(minY - y);
// final double v4 = Math.abs(maxY - y);
// if (v1 <= v2 && v1 <= v3 && v1 <= v4) {
// return new Point2D.Double(minX, y);
// }
// if (v2 <= v1 && v2 <= v3 && v2 <= v4) {
// return new Point2D.Double(maxX, y);
// }
// if (v3 <= v1 && v3 <= v2 && v3 <= v4) {
// return new Point2D.Double(x, minY);
// }
// if (v4 <= v1 && v4 <= v1 && v4 <= v3) {
// return new Point2D.Double(x, maxY);
// }
// throw new IllegalStateException();
// }
2011-08-08 17:48:29 +00:00
}