1
0
mirror of https://github.com/octoleo/plantuml.git synced 2024-06-18 08:02:21 +00:00
plantuml/src/net/sourceforge/plantuml/cucadiagram/dot/PlayField.java
2010-11-25 22:12:39 +01:00

326 lines
12 KiB
Java

/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009, Arnaud Roques
*
* Project Info: http://plantuml.sourceforge.net
*
* 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
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* 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: 4302 $
*
*/
package net.sourceforge.plantuml.cucadiagram.dot;
import java.awt.Color;
import java.awt.Font;
import java.awt.geom.Dimension2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import net.sourceforge.plantuml.ColorParam;
import net.sourceforge.plantuml.Dimension2DDouble;
import net.sourceforge.plantuml.FontParam;
import net.sourceforge.plantuml.ISkinParam;
import net.sourceforge.plantuml.OptionFlags;
import net.sourceforge.plantuml.StringUtils;
import net.sourceforge.plantuml.cucadiagram.EntityType;
import net.sourceforge.plantuml.cucadiagram.Group;
import net.sourceforge.plantuml.cucadiagram.IEntity;
import net.sourceforge.plantuml.cucadiagram.Link;
import net.sourceforge.plantuml.cucadiagram.LinkType;
import net.sourceforge.plantuml.graphic.HorizontalAlignement;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.graphic.TextBlock;
import net.sourceforge.plantuml.graphic.TextBlockUtils;
import net.sourceforge.plantuml.posimo.Block;
import net.sourceforge.plantuml.posimo.Cluster;
import net.sourceforge.plantuml.posimo.EntityImageBlock;
import net.sourceforge.plantuml.posimo.EntityImageClass2;
import net.sourceforge.plantuml.posimo.EntityImageNote2;
import net.sourceforge.plantuml.posimo.Frame;
import net.sourceforge.plantuml.posimo.GraphvizSolverB;
import net.sourceforge.plantuml.posimo.IEntityImageBlock;
import net.sourceforge.plantuml.posimo.Label;
import net.sourceforge.plantuml.posimo.LabelImage;
import net.sourceforge.plantuml.posimo.MargedBlock;
import net.sourceforge.plantuml.posimo.Path;
import net.sourceforge.plantuml.posimo.PathDrawerInterface;
import net.sourceforge.plantuml.posimo.PositionableUtils;
import net.sourceforge.plantuml.skin.rose.Rose;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.URectangle;
public final class PlayField {
private final Rose rose = new Rose();
private final ISkinParam skinParam;
private final Cluster root = new Cluster(null, 0, 0);
private final Map<Path, Link> paths = new LinkedHashMap<Path, Link>();
private final Map<IEntity, MargedBlock> blocks = new HashMap<IEntity, MargedBlock>();
private final Map<IEntity, Cluster> clusters = new HashMap<IEntity, Cluster>();
private final Map<IEntity, Frame> frames = new HashMap<IEntity, Frame>();
final private double marginLabel = 6;
final private Font fontQualif;
public PlayField(ISkinParam skinParam) {
this.skinParam = skinParam;
this.fontQualif = skinParam.getFont(FontParam.CLASS_ARROW);
}
public void initInternal(Collection<IEntity> entities, Collection<Link> links, StringBounder stringBounder) {
if (blocks.size() != 0 || paths.size() != 0 /* || images.size() != 0 */
|| clusters.size() != 0) {
throw new IllegalStateException();
}
if (entities.size() != new HashSet<IEntity>(entities).size()) {
throw new IllegalArgumentException("Duplicate entities");
}
if (links.size() != new HashSet<Link>(links).size()) {
throw new IllegalArgumentException("Duplicate entities");
}
for (IEntity ent : entities) {
if (ent.getType() == EntityType.GROUP && ent.getParent().isAutonom() == false) {
// final IEntityImageBlock title = createClusterTitle();
// final Frame frame = new Frame(StringUtils.getWithNewlines(ent.getDisplay()), Color.BLACK, skinParam
// .getFont(FontParam.CLASS), rose.getHtmlColor(skinParam, ColorParam.classBorder).getColor());
final Frame frame = new Frame(StringUtils.getWithNewlines(ent.getDisplay()), skinParam);
frames.put(ent, frame);
// final Dimension2D dimTitle =
// title.getDimension(stringBounder);
final Dimension2D dimTitle = frame.getTextDim(stringBounder);
clusters.put(ent, new Cluster(root, dimTitle.getWidth(), dimTitle.getHeight()));
}
}
for (IEntity ent : entities) {
// System.err.println("ENT=" + ent);
if (ent.getType() == EntityType.GROUP && ent.getParent().isAutonom() == false) {
assert clusters.containsKey(ent);
continue;
}
assert clusters.containsKey(ent) == false;
Cluster parentCluster = root;
if (ent.getType() != EntityType.GROUP && ent.getParent() != null) {
parentCluster = clusters.get(ent.getParent().getEntityCluster());
if (parentCluster == null) {
parentCluster = root;
}
}
final IEntityImageBlock entityImageBlock = createEntityImageBlock(links, ent);
// final Dimension2D d =
// entityImageBlock.getDimension(stringBounder);
// final Block b = new Block(uid++, d.getWidth() + 2 *
// marginDecorator, d.getHeight() + 2 * marginDecorator);
final MargedBlock b = new MargedBlock(stringBounder, entityImageBlock, getMargin(stringBounder, ent, links), parentCluster);
blocks.put(ent, b);
// images.put(ent, entityImageBlock);
parentCluster.addBloc(b.getBlock());
}
for (Cluster cl : clusters.values()) {
if (cl.getContents().size() == 0) {
throw new IllegalStateException();
}
}
for (Link link : links) {
// System.err.println("LINK=" + link);
if (entities.contains(link.getEntity1()) && entities.contains(link.getEntity2())) {
final Block b1 = getToto(link.getEntity1());
final Block b2 = getToto(link.getEntity2());
final Label label;
if (link.getLabel() == null) {
label = null;
} else {
final LabelImage labelImage = new LabelImage(link, rose, skinParam);
final Dimension2D dim = Dimension2DDouble
.delta(labelImage.getDimension(stringBounder), marginLabel);
label = new Label(dim.getWidth(), dim.getHeight());
}
final Path p = new Path(b1, b2, label, link.getLength());
paths.put(p, link);
}
}
}
private double getMargin(StringBounder stringBounder, IEntity ent, Collection<Link> links) {
double result = 0;
for (Link link : links) {
if (link.getEntity2() == ent) {
// final LinkDecor decor = link.getType().getDecor1();
result = Math.max(result, link.getMarginDecors2(stringBounder, fontQualif));
}
if (link.getEntity1() == ent) {
// final LinkDecor decor = link.getType().getDecor2();
result = Math.max(result, link.getMarginDecors1(stringBounder, fontQualif));
}
}
return result;
// return 40;
}
private Block getToto(IEntity ent) {
final MargedBlock result = blocks.get(ent);
if (result != null) {
return result.getBlock();
}
if (clusters.containsKey(ent) == false) {
throw new IllegalArgumentException();
}
return blocks.get(getOneOf(ent.getParent())).getBlock();
}
private IEntity getOneOf(Group gr) {
assert gr != null;
return gr.entities().values().iterator().next();
}
public void drawInternal(UGraphic ug) {
for (Map.Entry<IEntity, Cluster> ent : clusters.entrySet()) {
final Frame frame = frames.get(ent.getKey());
final Rectangle2D rect = PositionableUtils.convert(ent.getValue());
final double oldX = ug.getTranslateX();
final double oldY = ug.getTranslateY();
ug.translate(rect.getX(), rect.getY());
frame.drawU(ug, new Dimension2DDouble(rect.getWidth(), rect.getHeight()), null);
ug.setTranslate(oldX, oldY);
}
for (Map.Entry<Path, Link> ent : paths.entrySet()) {
final LinkType type = ent.getValue().getType();
final PathDrawerInterface pathDrawer = PathDrawerInterface.create(skinParam, type);
final Path p = ent.getKey();
ug.getParam().setColor(rose.getHtmlColor(skinParam, ColorParam.classBorder).getColor());
// pathDrawer.drawPathBefore(ug, PositionableUtils.addMargin(p
// .getStart(), -marginDecorator, -marginDecorator),
// PositionableUtils.addMargin(p.getEnd(), -marginDecorator,
// -marginDecorator), p);
if (p.getLabel() != null) {
ug.getParam().setColor(Color.BLACK);
drawLabel(ug, p);
}
}
for (Map.Entry<IEntity, MargedBlock> ent : blocks.entrySet()) {
final MargedBlock b = ent.getValue();
final Point2D pos = b.getImagePosition().getPosition();
b.getImageBlock().drawU(ug, pos.getX(), pos.getY(), 0, 0);
}
for (Map.Entry<Path, Link> ent : paths.entrySet()) {
final Link link = ent.getValue();
final LinkType type = link.getType();
final PathDrawerInterface pathDrawer = PathDrawerInterface.create(skinParam, type);
final Path p = ent.getKey();
ug.getParam().setColor(rose.getHtmlColor(skinParam, ColorParam.classBorder).getColor());
// pathDrawer.drawPathAfter(ug, PositionableUtils.addMargin(p
// .getStart(), -marginDecorator, -marginDecorator),
// PositionableUtils.addMargin(p.getEnd(), -marginDecorator,
// -marginDecorator), p);
pathDrawer.drawPathAfter(ug, getMargedBlock(p.getStart()).getImagePosition(), getMargedBlock(p.getEnd())
.getImagePosition(), p);
final String qual1 = link.getQualifier1();
if (qual1 != null) {
final TextBlock b = TextBlockUtils.create(Arrays.asList(qual1), fontQualif,
skinParam.getFontHtmlColor(FontParam.CLASS_ARROW).getColor(), HorizontalAlignement.LEFT);
final Point2D pos = p.getDotPath().getStartPoint();
b.drawU(ug, pos.getX(), pos.getY());
}
final String qual2 = link.getQualifier2();
if (qual2 != null) {
final TextBlock b = TextBlockUtils.create(Arrays.asList(qual2), fontQualif,
skinParam.getFontHtmlColor(FontParam.CLASS_ARROW).getColor(), HorizontalAlignement.LEFT);
final Point2D pos = p.getDotPath().getEndPoint();
b.drawU(ug, pos.getX(), pos.getY());
}
}
}
private MargedBlock getMargedBlock(Block b) {
for (MargedBlock margedBlock : blocks.values()) {
if (margedBlock.getBlock() == b) {
return margedBlock;
}
}
throw new IllegalArgumentException();
}
public Dimension2D solve() throws IOException, InterruptedException {
final GraphvizSolverB solver = new GraphvizSolverB();
// System.err.println("sub=" + root.getSubClusters());
final Dimension2D dim = Dimension2DDouble.delta(solver.solve(root, paths.keySet()), 20);
return dim;
}
private void drawLabel(UGraphic ug, Path p) {
final Label label = p.getLabel();
final Point2D pos = label.getPosition();
if (OptionFlags.getInstance().isDebugDot()) {
ug.getParam().setColor(Color.GREEN);
ug.getParam().setBackcolor(null);
final Dimension2D dim = label.getSize();
ug.draw(pos.getX(), pos.getY(), new URectangle(dim.getWidth(), dim.getHeight()));
final LabelImage labelImage = new LabelImage(paths.get(p), rose, skinParam);
final Dimension2D dimImage = labelImage.getDimension(ug.getStringBounder());
ug.draw(pos.getX(), pos.getY(), new URectangle(dimImage.getWidth(), dimImage.getHeight()));
}
final LabelImage labelImage = new LabelImage(paths.get(p), rose, skinParam);
labelImage.drawU(ug, pos.getX(), pos.getY());
}
private IEntityImageBlock createEntityImageBlock(Collection<Link> links, IEntity ent) {
if (ent.getType() == EntityType.CLASS || ent.getType() == EntityType.ABSTRACT_CLASS
|| ent.getType() == EntityType.INTERFACE || ent.getType() == EntityType.ENUM) {
return new EntityImageClass2(ent, skinParam, links);
}
if (ent.getType() == EntityType.NOTE) {
return new EntityImageNote2(ent, skinParam, links);
}
return new EntityImageBlock(ent, rose, skinParam, links, FontParam.PACKAGE);
}
private IEntityImageBlock createClusterTitle() {
return null;
}
}