All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sourceforge.plantuml.sdot.CucaDiagramFileMakerSmetana Maven / Gradle / Ivy

// THIS FILE HAS BEEN GENERATED BY A PREPROCESSOR.
/* +=======================================================================
 * |
 * |      PlantUML : a free UML diagram generator
 * |
 * +=======================================================================
 *
 * (C) Copyright 2009-2024, Arnaud Roques
 *
 * Project Info:  https://plantuml.com
 *
 * If you like this project or if you find it useful, you can support us at:
 *
 * https://plantuml.com/patreon (only 1$ per month!)
 * https://plantuml.com/liberapay (only 1€ per month!)
 * https://plantuml.com/paypal
 *
 *
 * PlantUML is free software; you can redistribute it and/or modify it
 * under the terms of the Revised BSD License.
 *
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * * Neither the name of the University of California, Berkeley nor the
 *   names of its contributors may be used to endorse or promote products
 *   derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * PlantUML can occasionally display sponsored or advertising messages. Those
 * messages are usually generated on welcome or error images and never on
 * functional diagrams.
 * See https://plantuml.com/professional if you want to remove them
 *
 * Images (whatever their format : PNG, SVG, EPS...) generated by running PlantUML
 * are owned by the author of their corresponding sources code (that is, their
 * textual description in PlantUML language). Those images are not covered by
 * this BSD license.
 *
 * The generated images can then be used without any reference to the BSD license.
 * It is not even necessary to stipulate that they have been generated with PlantUML,
 * although this will be appreciated by the PlantUML team.
 *
 * There is an exception : if the textual description in PlantUML language is also covered
 * by any license, then the generated images are logically covered
 * by the very same license.
 *
 * This is the IGY distribution (Install GraphViz by Yourself).
 * You have to install GraphViz and to setup the GRAPHVIZ_DOT environment variable
 * (see https://plantuml.com/graphviz-dot )
 *
 * Icons provided by OpenIconic :  https://useiconic.com/open
 * Archimate sprites provided by Archi :  http://www.archimatetool.com
 * Stdlib AWS provided by https://github.com/milo-minderbinder/AWS-PlantUML
 * Stdlib Icons provided https://github.com/tupadr3/plantuml-icon-font-sprites
 * ASCIIMathML (c) Peter Jipsen http://www.chapman.edu/~jipsen
 * ASCIIMathML (c) David Lippman http://www.pierce.ctc.edu/dlippman
 * CafeUndZopfli ported by Eugene Klyuchnikov https://github.com/eustas/CafeUndZopfli
 * Brotli (c) by the Brotli Authors https://github.com/google/brotli
 * Themes (c) by Brett Schwarz https://github.com/bschwarz/puml-themes
 * Twemoji (c) by Twitter at https://twemoji.twitter.com/
 *
 */
package net.sourceforge.plantuml.sdot;

import static gen.lib.cgraph.attr__c.agsafeset;
import static gen.lib.cgraph.edge__c.agedge;
import static gen.lib.cgraph.graph__c.agopen;
import static gen.lib.cgraph.node__c.agnode;
import static gen.lib.cgraph.subg__c.agsubg;
import static gen.lib.gvc.gvc__c.gvContext;
import static gen.lib.gvc.gvlayout__c.gvLayoutJobs;

import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import h.ST_Agedge_s;
import h.ST_Agnode_s;
import h.ST_Agraph_s;
import h.ST_Agraphinfo_t;
import h.ST_Agrec_s;
import h.ST_GVC_s;
import net.sourceforge.plantuml.FileFormatOption;
import net.sourceforge.plantuml.StringUtils;
import net.sourceforge.plantuml.UmlDiagram;
import net.sourceforge.plantuml.abel.CucaNote;
import net.sourceforge.plantuml.abel.Entity;
import net.sourceforge.plantuml.abel.GroupType;
import net.sourceforge.plantuml.abel.LeafType;
import net.sourceforge.plantuml.abel.Link;
import net.sourceforge.plantuml.abel.LinkArrow;
import net.sourceforge.plantuml.annotation.DuplicateCode;
import net.sourceforge.plantuml.api.ImageDataSimple;
import net.sourceforge.plantuml.core.ImageData;
import net.sourceforge.plantuml.cucadiagram.ICucaDiagram;
import net.sourceforge.plantuml.eggs.QuoteUtils;
import net.sourceforge.plantuml.klimt.UTranslate;
import net.sourceforge.plantuml.klimt.color.HColor;
import net.sourceforge.plantuml.klimt.creole.CreoleMode;
import net.sourceforge.plantuml.klimt.creole.Display;
import net.sourceforge.plantuml.klimt.drawing.UGraphic;
import net.sourceforge.plantuml.klimt.font.FontConfiguration;
import net.sourceforge.plantuml.klimt.font.StringBounder;
import net.sourceforge.plantuml.klimt.geom.HorizontalAlignment;
import net.sourceforge.plantuml.klimt.geom.MinMaxMutable;
import net.sourceforge.plantuml.klimt.geom.Rankdir;
import net.sourceforge.plantuml.klimt.geom.VerticalAlignment;
import net.sourceforge.plantuml.klimt.geom.XDimension2D;
import net.sourceforge.plantuml.klimt.geom.XPoint2D;
import net.sourceforge.plantuml.klimt.shape.AbstractTextBlock;
import net.sourceforge.plantuml.klimt.shape.TextBlock;
import net.sourceforge.plantuml.klimt.shape.TextBlockUtils;
import net.sourceforge.plantuml.log.Logme;
import net.sourceforge.plantuml.skin.AlignmentParam;
import net.sourceforge.plantuml.skin.UmlDiagramType;
import net.sourceforge.plantuml.skin.VisibilityModifier;
import net.sourceforge.plantuml.skin.rose.Rose;
import net.sourceforge.plantuml.stereo.Stereotype;
import net.sourceforge.plantuml.style.ISkinParam;
import net.sourceforge.plantuml.style.SName;
import net.sourceforge.plantuml.style.Style;
import net.sourceforge.plantuml.style.StyleSignature;
import net.sourceforge.plantuml.style.StyleSignatureBasic;
import net.sourceforge.plantuml.svek.Bibliotekon;
import net.sourceforge.plantuml.svek.Cluster;
import net.sourceforge.plantuml.svek.ClusterHeader;
import net.sourceforge.plantuml.svek.CucaDiagramFileMaker;
import net.sourceforge.plantuml.svek.DotStringFactory;
import net.sourceforge.plantuml.svek.GeneralImageBuilder;
import net.sourceforge.plantuml.svek.GraphvizCrash;
import net.sourceforge.plantuml.svek.IEntityImage;
import net.sourceforge.plantuml.svek.SvekNode;
import net.sourceforge.plantuml.svek.image.EntityImageNote;
import net.sourceforge.plantuml.svek.image.EntityImageNoteLink;
import net.sourceforge.plantuml.utils.Position;
import smetana.core.CString;
import smetana.core.Globals;
import smetana.core.JUtils;
import smetana.core.Macro;
import smetana.core.debug.SmetanaDebug;

@DuplicateCode(reference = "SvekEdge, CucaDiagramFileMakerElk, CucaDiagramFileMakerSmetana")
public class CucaDiagramFileMakerSmetana implements CucaDiagramFileMaker {
	// ::remove folder when __HAXE__

	private final ICucaDiagram diagram;

	private final StringBounder stringBounder;
	private final Map nodes = new LinkedHashMap();
	private final Map coreNodes = new LinkedHashMap();
	private final Map edges = new LinkedHashMap();
	private final Map smetanaPathes = new LinkedHashMap();
	private final Map clusters = new LinkedHashMap();

	private final DotStringFactory dotStringFactory;
	private final Rankdir rankdir;

	private MinMaxMutable getSmetanaMinMax() {
		final MinMaxMutable result = MinMaxMutable.getEmpty(false);
		for (ST_Agnode_s n : nodes.values()) {
			final BoxInfo data = BoxInfo.fromNode(n);
			result.addPoint(data.getUpperRight());
			result.addPoint(data.getLowerLeft());
		}
		for (ST_Agraph_s gr : clusters.values()) {
			final ST_Agrec_s tmp1 = gr.data;
			if (tmp1 instanceof ST_Agraphinfo_t == false) {
				System.err.println("ERROR IN CucaDiagramFileMakerSmetana");
				continue;
			}
			final ST_Agraphinfo_t info = (ST_Agraphinfo_t) tmp1;
			final BoxInfo data = BoxInfo.fromGraphInfo(info);
			result.addPoint(data.getUpperRight());
			result.addPoint(data.getLowerLeft());

		}
		return result;
	}

	class Drawing extends AbstractTextBlock {

		private final YMirror ymirror;
		private final MinMaxMutable minMax;

		public Drawing() {
			this.minMax = getSmetanaMinMax();
			this.ymirror = new YMirror(minMax.getMaxY() + 6);
		}

		public void drawU(UGraphic ug) {

			smetanaPathes.clear();

			ug = ug.apply(new UTranslate(6, 6 - minMax.getMinY()));

			for (Map.Entry ent : edges.entrySet()) {
				final Link link = ent.getKey();
				if (link.isInvis())
					continue;

				final ST_Agedge_s edge = ent.getValue();
				final SmetanaEdge smetanaPath = new SmetanaEdge(link, edge, ymirror, getLabel(link),
						getQuantifier(link, 1), getQuantifier(link, 2), dotStringFactory.getBibliotekon(), diagram.getSkinParam());
				smetanaPathes.put(link, smetanaPath);
			}

			for (Map.Entry ent : clusters.entrySet())
				drawGroup(ug, ymirror, ent.getKey(), ent.getValue());

			for (Map.Entry ent : nodes.entrySet()) {
				final Entity leaf = ent.getKey();
				final ST_Agnode_s agnode = ent.getValue();
				final XPoint2D corner = getCorner(agnode);

				final SvekNode node = dotStringFactory.getBibliotekon().getNode(leaf);
				node.resetMove();
				node.moveDelta(corner.getX(), corner.getY());
				final IEntityImage image = node.getImage();
				image.drawU(ug.apply(UTranslate.point(corner)));
			}

			for (Entry ent : smetanaPathes.entrySet())
				if (ent.getKey().isOpale() == false)
					ent.getValue().drawU(ug);

		}

		public XDimension2D calculateDimension(StringBounder stringBounder) {
			return minMax.getDimension().delta(6);
		}

		private XPoint2D getCorner(ST_Agnode_s n) {
			final BoxInfo data = BoxInfo.fromNode(n);
			return ymirror.getMirrored(data.getLowerLeft());
		}

		public HColor getBackcolor() {
			return null;
		}

	}

	public CucaDiagramFileMakerSmetana(ICucaDiagram diagram, StringBounder stringBounder) {
		this.diagram = diagram;
		this.stringBounder = stringBounder;
		this.dotStringFactory = new DotStringFactory(stringBounder, diagram);
		this.rankdir = diagram.getSkinParam().getRankdir();

		printAllSubgroups(diagram.getRootGroup());
		printEntities(getUnpackagedEntities());

		for (Link link : diagram.getLinks()) {
			if (link.isRemoved())
				continue;

			if (isOpalisable(link.getEntity1())) {
				final SvekNode node = dotStringFactory.getBibliotekon().getNode(link.getEntity1());
				final SvekNode other = dotStringFactory.getBibliotekon().getNode(link.getEntity2());
				if (other != null) {
					((EntityImageNote) node.getImage()).setOpaleLink(link, node, other, smetanaPathes);
					link.setOpale(true);
				}
			} else if (isOpalisable(link.getEntity2())) {
				final SvekNode node = dotStringFactory.getBibliotekon().getNode(link.getEntity2());
				final SvekNode other = dotStringFactory.getBibliotekon().getNode(link.getEntity1());
				if (other != null) {
					((EntityImageNote) node.getImage()).setOpaleLink(link, node, other, smetanaPathes);
					link.setOpale(true);
				}
			}

		}

	}

	// Duplicate GeneralImageBuilder
	private boolean isOpalisable(Entity entity) {
		if (entity.isGroup())
			return false;

		if (entity.getLeafType() != LeafType.NOTE)
			return false;

		final Link single = onlyOneLink(entity);
		if (single == null)
			return false;

		return single.getOther(entity).getLeafType() != LeafType.NOTE;
	}

	// Duplicate GeneralImageBuilder
	private Link onlyOneLink(Entity ent) {
		Link single = null;
		for (Link link : diagram.getLinks()) {
			if (link.isInvis())
				continue;
			if (link.contains(ent) == false)
				continue;

			if (single != null)
				return null;
			single = link;
		}
		return single;
	}

	private void drawGroup(UGraphic ug, YMirror ymirror, Entity group, ST_Agraph_s gr) {
		JUtils.LOG2("drawGroup");
		try {
			final ST_Agrec_s tmp1 = gr.data;
			final ST_Agraphinfo_t data = (ST_Agraphinfo_t) tmp1;
			final BoxInfo boxInfo = BoxInfo.fromGraphInfo(data);
			final XPoint2D upperRight = ymirror.getMirrored(boxInfo.getUpperRight());
			final XPoint2D lowerLeft = ymirror.getMirrored(boxInfo.getLowerLeft());

			final Cluster cluster = dotStringFactory.getBibliotekon().getCluster(group);
			cluster.setPosition(upperRight, lowerLeft);

			final XDimension2D dimTitle = cluster.getTitleDimension(ug.getStringBounder());
			if (dimTitle != null) {
				final double x = (upperRight.getX() + lowerLeft.getX()) / 2 - dimTitle.getWidth() / 2;
				cluster.setTitlePosition(new XPoint2D(x, Math.min(upperRight.getY(), lowerLeft.getY())));
			}
			JUtils.LOG2("cluster=" + cluster);
			cluster.drawU(ug, diagram.getUmlDiagramType());
			// ug.apply(new UTranslate(llx, lly)).apply(HColors.BLUE).draw(new
			// URectangle(urx - llx, ury - lly));
		} catch (Exception e) {
			System.err.println("CANNOT DRAW GROUP");
		}
	}

	private void printAllSubgroups(Entity parent) {
		for (Entity g : diagram.getChildrenGroups(parent)) {
			if (g.isRemoved())
				continue;

			if (diagram.isEmpty(g) && g.getGroupType() == GroupType.PACKAGE) {
				g.muteToType(LeafType.EMPTY_PACKAGE);
				printEntity(g);
			} else {
				printSingleGroup(g);
			}
		}
	}

	private void printSingleGroup(Entity g) {
		if (g.getGroupType() == GroupType.CONCURRENT_STATE)
			return;

		if (g.isPacked() == false) {
			final ClusterHeader clusterHeader = new ClusterHeader(g, diagram.getSkinParam(), diagram, stringBounder);
			dotStringFactory.openCluster(g, clusterHeader);
		}

		this.printEntities(g.leafs());

		printAllSubgroups(g);

		if (g.isPacked() == false) {
			dotStringFactory.closeCluster();
		}
	}

	private void printEntities(Collection entities) {
		for (Entity ent : entities) {
			if (ent.isRemoved())
				continue;

			printEntity(ent);
		}
	}

	private void exportEntities(Globals zz, ST_Agraph_s cluster, Collection entities) {
		for (Entity ent : entities) {
			if (ent.isRemoved())
				continue;
			exportEntity(zz, cluster, ent);
		}
	}

	private XDimension2D getDim(SvekNode node) {
		final double width = node.getWidth() / 72;
		final double height = node.getHeight() / 72;
		return new XDimension2D(width, height);
	}

	private ST_Agnode_s getCoreFromGroup(Globals zz, Entity group) {
		ST_Agnode_s result = coreNodes.get(group);
		if (result != null)
			return result;

		final ST_Agraph_s cluster = clusters.get(group);
		if (cluster == null)
			throw new IllegalStateException();

		result = agnode(zz, cluster, new CString("z" + group.getUid()), true);
		agsafeset(zz, result, new CString("shape"), new CString("box"), new CString(""));
		agsafeset(zz, result, new CString("width"), new CString("0.1"), new CString(""));
		agsafeset(zz, result, new CString("height"), new CString("0.1"), new CString(""));
		coreNodes.put(group, result);
		return result;
	}

	private void exportEntity(Globals zz, ST_Agraph_s cluster, Entity leaf) {
		final SvekNode node = dotStringFactory.getBibliotekon().getNode(leaf);
		if (node == null) {
			System.err.println("CANNOT FIND NODE");
			return;
		}
		final ST_Agnode_s agnode = agnode(zz, cluster, new CString(node.getUid()), true);
		agsafeset(zz, agnode, new CString("shape"), new CString("box"), new CString(""));
		final XDimension2D dim = getDim(node);
		final String width = "" + dim.getWidth();
		final String height = "" + dim.getHeight();
		agsafeset(zz, agnode, new CString("width"), new CString(width), new CString(""));
		agsafeset(zz, agnode, new CString("height"), new CString(height), new CString(""));
		nodes.put(leaf, agnode);
	}

	private void printEntity(Entity ent) {
		if (ent.isRemoved())
			throw new IllegalStateException();

		final IEntityImage image = printEntityInternal(ent);
		final SvekNode node = getBibliotekon().createNode(ent, image, dotStringFactory.getColorSequence(),
				stringBounder);
		dotStringFactory.addNode(node);
	}

	private Collection getUnpackagedEntities() {
		final List result = new ArrayList<>();
		for (Entity ent : diagram.getEntityFactory().leafs())
			if (diagram.getEntityFactory().getRootGroup() == ent.getParentContainer())
				result.add(ent);

		return result;
	}

	private static final Lock lock = new ReentrantLock();

	public ImageData createFile(OutputStream os, List dotStrings, FileFormatOption fileFormatOption)
			throws IOException {
		lock.lock();
		try {
			return createFileLocked(os, dotStrings, fileFormatOption);
		} finally {
			lock.unlock();
		}
	}

	@Override
	public void createOneGraphic(UGraphic ug) {
		final Globals zz = Globals.open();
		try {
			final TextBlock textBlock = getTextBlock(zz);
			textBlock.drawU(ug);
		} catch (Throwable e) {
			SmetanaDebug.printMe();
		} finally {
			Globals.close();
		}
	}

	private ImageData createFileLocked(OutputStream os, List dotStrings, FileFormatOption fileFormatOption)
			throws IOException {

		final Globals zz = Globals.open();
		try {
			final TextBlock drawable = getTextBlock(zz);
			return diagram.createImageBuilder(fileFormatOption).drawable(drawable).write(os);
		} catch (Throwable e) {
			SmetanaDebug.printMe();
			UmlDiagram.exportDiagramError(os, e, fileFormatOption, diagram.seed(), diagram.getMetadata(),
					diagram.getFlashData(), getFailureText3(e));
			return ImageDataSimple.error();
		} finally {
			Globals.close();
		}
	}

	private TextBlock getTextBlock(Globals zz) {
		final ST_Agraph_s g = agopen(zz, new CString("g"), zz.Agdirected, null);

		exportEntities(zz, g, getUnpackagedEntities());
		exportGroups(zz, g, diagram.getEntityFactory().getRootGroup());

		for (Link link : diagram.getLinks()) {
			final ST_Agedge_s e = createEdge(zz, g, link);
			if (e != null)
				edges.put(link, e);

		}

		final ST_GVC_s gvc = gvContext(zz);
		SmetanaDebug.reset();
		if (rankdir == Rankdir.LEFT_TO_RIGHT)
			agsafeset(zz, g, new CString("rankdir"), new CString("LR"), new CString("LR"));
		gvLayoutJobs(zz, gvc, g);
		SmetanaDebug.printMe();

		final TextBlock drawable = new Drawing();
		return drawable;
	}

	private void exportGroups(Globals zz, ST_Agraph_s graph, Entity parent) {
		for (Entity g : diagram.getChildrenGroups(parent)) {
			if (g.isRemoved())
				continue;

			if (diagram.isEmpty(g) && g.getGroupType() == GroupType.PACKAGE)
				exportEntity(zz, graph, g);
			else
				exportGroup(zz, graph, g);

		}

	}

	private void exportGroup(Globals zz, ST_Agraph_s graph, Entity group) {
		if (group.isPacked()) {
			this.exportEntities(zz, graph, group.leafs());
			this.exportGroups(zz, graph, group);
			return;
		}
		final Cluster cluster = getBibliotekon().getCluster(group);
		if (cluster == null) {
			System.err.println("CucaDiagramFileMakerSmetana::exportGroup issue");
			return;
		}
		JUtils.LOG2("cluster = " + cluster.getClusterId());
		final ST_Agraph_s cluster1 = agsubg(zz, graph, new CString(cluster.getClusterId()), true);
		if (cluster.isLabel()) {
			final double width = cluster.getTitleAndAttributeWidth();
			final double height = cluster.getTitleAndAttributeHeight() - 5;
			agsafeset(zz, cluster1, new CString("label"), createLabelDim(width, height), new CString(""));
		}
		this.exportEntities(zz, cluster1, group.leafs());
		this.clusters.put(group, cluster1);
		this.exportGroups(zz, cluster1, group);
	}

	private CString createLabelDim(final double width, final double height) {
		return Macro.createHackInitDimensionFromLabel((int) width, (int) height);
	}

	private Style getStyle() {
		return StyleSignatureBasic
				.of(SName.root, SName.element, diagram.getUmlDiagramType().getStyleName(), SName.arrow)
				.getMergedStyle(diagram.getSkinParam().getCurrentStyleBuilder());
	}

	// Duplication from SvekEdge
	final public StyleSignature getDefaultStyleDefinitionArrow(Stereotype stereotype, SName styleName) {
		StyleSignature result = StyleSignatureBasic.of(SName.root, SName.element, styleName, SName.arrow);
		if (stereotype != null)
			result = result.withTOBECHANGED(stereotype);

		return result;
	}

	private FontConfiguration getFontForLink(Link link, final ISkinParam skinParam) {
		final SName styleName = skinParam.getUmlDiagramType().getStyleName();
		
		final Style style = getDefaultStyleDefinitionArrow(link.getStereotype(), styleName).getMergedStyle(link.getStyleBuilder());
		return style.getFontConfiguration(skinParam.getIHtmlColorSet());
	}

	private HorizontalAlignment getMessageTextAlignment(UmlDiagramType umlDiagramType, ISkinParam skinParam) {
		if (umlDiagramType == UmlDiagramType.STATE)
			return skinParam.getHorizontalAlignment(AlignmentParam.stateMessageAlignment, null, false, null);

		return skinParam.getDefaultTextAlignment(HorizontalAlignment.CENTER);
	}

	private TextBlock addVisibilityModifier(TextBlock block, Link link, ISkinParam skinParam) {
		final VisibilityModifier visibilityModifier = link.getVisibilityModifier();
		if (visibilityModifier != null) {
			final Rose rose = new Rose();
			final HColor fore = rose.getHtmlColor(skinParam, visibilityModifier.getForeground());
			TextBlock visibility = visibilityModifier.getUBlock(skinParam.classAttributeIconSize(), fore, null, false);
			visibility = TextBlockUtils.withMargin(visibility, 0, 1, 2, 0);
			block = TextBlockUtils.mergeLR(visibility, block, VerticalAlignment.CENTER);
		}
		final double marginLabel = 1; // startUid.equalsId(endUid) ? 6 : 1;
		return TextBlockUtils.withMargin(block, marginLabel, marginLabel);
	}

	private LinkArrow getLinkArrow(Link link) {
		return link.getLinkArrow();
	}

	private TextBlock getLabel(Link link) {
		ISkinParam skinParam = diagram.getSkinParam();
		final double marginLabel = 1; // startUid.equals(endUid) ? 6 : 1;

		// final FontConfiguration labelFont =
		// style.getFontConfiguration(skinParam.getIHtmlColorSet());
//		TextBlock labelOnly = link.getLabel().create(labelFont,
//				skinParam.getDefaultTextAlignment(HorizontalAlignment.CENTER), skinParam);

		final UmlDiagramType type = skinParam.getUmlDiagramType();
		final FontConfiguration font = getFontForLink(link, skinParam);

		TextBlock labelOnly;
		// toto2
		if (Display.isNull(link.getLabel())) {
			labelOnly = TextBlockUtils.EMPTY_TEXT_BLOCK;
			if (getLinkArrow(link) != LinkArrow.NONE_OR_SEVERAL) {
				// labelOnly = StringWithArrow.addMagicArrow(labelOnly, this, font);
			}

		} else {
			final HorizontalAlignment alignment = getMessageTextAlignment(type, skinParam);
			final boolean hasSeveralGuideLines = link.getLabel().hasSeveralGuideLines();
			final TextBlock block;
			// if (hasSeveralGuideLines)
				// block = StringWithArrow.addSeveralMagicArrows(link.getLabel(), this, font, alignment, skinParam);
			// else
				block = link.getLabel().create0(font, alignment, skinParam, skinParam.maxMessageSize(),
						CreoleMode.SIMPLE_LINE, null, null);

			labelOnly = addVisibilityModifier(block, link, skinParam);
			if (getLinkArrow(link) != LinkArrow.NONE_OR_SEVERAL && hasSeveralGuideLines == false) {
				// labelOnly = StringWithArrow.addMagicArrow(labelOnly, this, font);
			}

		}

		final CucaNote note = link.getNote();
		if (note == null) {
			if (TextBlockUtils.isEmpty(labelOnly, stringBounder) == false)
				labelOnly = TextBlockUtils.withMargin(labelOnly, marginLabel, marginLabel);
			return labelOnly;
		}
		final TextBlock noteOnly = new EntityImageNoteLink(note.getDisplay(), note.getColors(), skinParam,
				link.getStyleBuilder());

		if (note.getPosition() == Position.LEFT)
			return TextBlockUtils.mergeLR(noteOnly, labelOnly, VerticalAlignment.CENTER);
		else if (note.getPosition() == Position.RIGHT)
			return TextBlockUtils.mergeLR(labelOnly, noteOnly, VerticalAlignment.CENTER);
		else if (note.getPosition() == Position.TOP)
			return TextBlockUtils.mergeTB(noteOnly, labelOnly, HorizontalAlignment.CENTER);
		else
			return TextBlockUtils.mergeTB(labelOnly, noteOnly, HorizontalAlignment.CENTER);

	}

	private TextBlock getQuantifier(Link link, int n) {
		final String tmp = n == 1 ? link.getQuantifier1() : link.getQuantifier2();
		if (tmp == null)
			return null;

		final double marginLabel = 1; // startUid.equals(endUid) ? 6 : 1;
		ISkinParam skinParam = diagram.getSkinParam();
		final Style style = getStyle();
		final FontConfiguration labelFont = style.getFontConfiguration(skinParam.getIHtmlColorSet());
		final TextBlock label = Display.getWithNewlines(tmp).create(labelFont,
				skinParam.getDefaultTextAlignment(HorizontalAlignment.CENTER), skinParam);
		if (TextBlockUtils.isEmpty(label, stringBounder))
			return label;

		return TextBlockUtils.withMargin(label, marginLabel, marginLabel);
	}

	private ST_Agnode_s getAgnodeFromLeaf(Entity entity) {
		final ST_Agnode_s n = nodes.get(entity);
		if (n != null)
			return n;

		try {
			final String id = getBibliotekon().getNodeUid((Entity) entity);
			for (Map.Entry ent : nodes.entrySet())
				if (id.equals(getBibliotekon().getNodeUid(ent.getKey())))
					return ent.getValue();

		} catch (IllegalStateException e) {
			System.err.println("UNKNOWN ENTITY");
		}
		return null;

	}

	private ST_Agedge_s createEdge(Globals zz, final ST_Agraph_s g, Link link) {

		final ST_Agnode_s node1;
		final ST_Agnode_s node2;

		if (link.getEntity1().isGroup())
			node1 = getCoreFromGroup(zz, link.getEntity1());
		else
			node1 = getAgnodeFromLeaf(link.getEntity1());

		if (link.getEntity2().isGroup())
			node2 = getCoreFromGroup(zz, link.getEntity2());
		else
			node2 = getAgnodeFromLeaf(link.getEntity2());

		if (node1 == null || node2 == null)
			return null;
		// throw new IllegalStateException();

		final ST_Agedge_s e = agedge(zz, g, node1, node2, null, true);
		agsafeset(zz, e, new CString("arrowtail"), new CString("none"), new CString(""));
		agsafeset(zz, e, new CString("arrowhead"), new CString("none"), new CString(""));

		int length = link.getLength();
		agsafeset(zz, e, new CString("minlen"), new CString("" + (length - 1)), new CString(""));

		final TextBlock label = getLabel(link);
		if (TextBlockUtils.isEmpty(label, stringBounder) == false) {
			final XDimension2D dimLabel = label.calculateDimension(stringBounder);
			final CString hackDim = createLabelDim(dimLabel.getWidth(), dimLabel.getHeight());
			agsafeset(zz, e, new CString("label"), hackDim, new CString(""));
		}
		final TextBlock q1 = getQuantifier(link, 1);
		if (q1 != null) {
			final XDimension2D dimLabel = q1.calculateDimension(stringBounder);
			final CString hackDim = createLabelDim(dimLabel.getWidth(), dimLabel.getHeight());
			agsafeset(zz, e, new CString("taillabel"), hackDim, new CString(""));
		}
		final TextBlock q2 = getQuantifier(link, 2);
		if (q2 != null) {
			final XDimension2D dimLabel = q2.calculateDimension(stringBounder);
			final CString hackDim = createLabelDim(dimLabel.getWidth(), dimLabel.getHeight());
			agsafeset(zz, e, new CString("headlabel"), hackDim, new CString(""));
		}
		return e;
	}

	static private List getFailureText3(Throwable exception) {
		Logme.error(exception);
		final List strings = new ArrayList<>();
		strings.add("An error has occured : " + exception);
		final String quote = StringUtils.rot(QuoteUtils.getSomeQuote());
		strings.add("" + quote);
		strings.add(" ");
		GraphvizCrash.addProperties(strings);
		strings.add(" ");
		strings.add("Sorry, the subproject Smetana is not finished yet...");
		strings.add(" ");
		strings.add("You should send this diagram and this image to [email protected] or");
		strings.add("post to https://plantuml.com/qa to solve this issue.");
		strings.add(" ");
		return strings;
	}

	private Bibliotekon getBibliotekon() {
		return dotStringFactory.getBibliotekon();
	}

	private IEntityImage printEntityInternal(Entity ent) {
		if (ent.isRemoved())
			throw new IllegalStateException();

		if (ent.getSvekImage() == null) {
			ISkinParam skinParam = diagram.getSkinParam();
			if (skinParam.sameClassWidth()) {
				System.err.println("NOT YET IMPLEMENED");
//				throw new UnsupportedOperationException();
				// final double width = getMaxWidth();
				// skinParam = new SkinParamSameClassWidth(dotData.getSkinParam(), width);
			}

			final IEntityImage result = GeneralImageBuilder.createEntityImageBlock(ent, skinParam,
					diagram.isHideEmptyDescriptionForState(), diagram, getBibliotekon(), null,
					diagram.getUmlDiagramType(), diagram.getLinks());
			ent.setSvekImage(result);
			return result;
		}
		return ent.getSvekImage();
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy