1
0
mirror of https://github.com/octoleo/plantuml.git synced 2024-10-31 19:22:31 +00:00
plantuml/src/net/sourceforge/plantuml/cucadiagram/Display.java

482 lines
17 KiB
Java
Raw Normal View History

2013-12-10 19:36:50 +00:00
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
2016-01-09 12:15:40 +00:00
* (C) Copyright 2009-2017, Arnaud Roques
2013-12-10 19:36:50 +00:00
*
2016-03-06 16:47:34 +00:00
* Project Info: http://plantuml.com
2013-12-10 19:36:50 +00:00
*
2017-03-15 19:13:31 +00:00
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
2013-12-10 19:36:50 +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
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.cucadiagram;
import java.util.ArrayList;
import java.util.Arrays;
2015-06-20 10:54:49 +00:00
import java.util.Collection;
2013-12-10 19:36:50 +00:00
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
2017-04-26 17:48:37 +00:00
import net.sourceforge.plantuml.BackSlash;
2015-06-20 10:54:49 +00:00
import net.sourceforge.plantuml.CharSequence2;
import net.sourceforge.plantuml.CharSequence2Impl;
2015-04-07 18:18:37 +00:00
import net.sourceforge.plantuml.EmbededDiagram;
2015-07-11 09:32:49 +00:00
import net.sourceforge.plantuml.ISkinSimple;
2017-02-26 16:26:11 +00:00
import net.sourceforge.plantuml.LineBreakStrategy;
2015-06-20 10:54:49 +00:00
import net.sourceforge.plantuml.LineLocationImpl;
2015-07-11 09:32:49 +00:00
import net.sourceforge.plantuml.SpriteContainer;
2015-05-31 18:56:03 +00:00
import net.sourceforge.plantuml.StringUtils;
2013-12-10 19:36:50 +00:00
import net.sourceforge.plantuml.UrlBuilder;
import net.sourceforge.plantuml.UrlBuilder.ModeUrl;
2016-05-31 19:41:55 +00:00
import net.sourceforge.plantuml.command.regex.Matcher2;
import net.sourceforge.plantuml.command.regex.Pattern2;
2015-07-11 09:32:49 +00:00
import net.sourceforge.plantuml.creole.CreoleMode;
import net.sourceforge.plantuml.creole.CreoleParser;
import net.sourceforge.plantuml.creole.Sheet;
import net.sourceforge.plantuml.creole.SheetBlock1;
import net.sourceforge.plantuml.creole.SheetBlock2;
import net.sourceforge.plantuml.graphic.CircledCharacter;
import net.sourceforge.plantuml.graphic.FontConfiguration;
2015-04-07 18:18:37 +00:00
import net.sourceforge.plantuml.graphic.HorizontalAlignment;
2015-07-11 09:32:49 +00:00
import net.sourceforge.plantuml.graphic.HtmlColor;
import net.sourceforge.plantuml.graphic.TextBlock;
import net.sourceforge.plantuml.graphic.TextBlockSimple;
2016-07-04 19:06:50 +00:00
import net.sourceforge.plantuml.graphic.TextBlockSprited;
2015-07-11 09:32:49 +00:00
import net.sourceforge.plantuml.graphic.TextBlockUtils;
import net.sourceforge.plantuml.graphic.VerticalAlignment;
import net.sourceforge.plantuml.sequencediagram.MessageNumber;
import net.sourceforge.plantuml.ugraphic.UFont;
import net.sourceforge.plantuml.ugraphic.UStroke;
2016-07-04 19:06:50 +00:00
import net.sourceforge.plantuml.ugraphic.sprite.Sprite;
2013-12-10 19:36:50 +00:00
public class Display implements Iterable<CharSequence> {
2015-07-11 09:32:49 +00:00
private final List<CharSequence> display;
2015-04-07 18:18:37 +00:00
private final HorizontalAlignment naturalHorizontalAlignment;
2015-07-11 09:32:49 +00:00
private final boolean isNull;
private final CreoleMode defaultCreoleMode;
public final static Display NULL = new Display(null, null, true, CreoleMode.FULL);
2015-04-07 18:18:37 +00:00
2018-03-09 21:37:34 +00:00
public Display replace(String src, String dest) {
final List<CharSequence> newDisplay = new ArrayList<CharSequence>();
for (CharSequence cs : display) {
if (cs.toString().contains(src)) {
cs = cs.toString().replace(src, dest);
}
newDisplay.add(cs);
}
return new Display(newDisplay, naturalHorizontalAlignment, isNull, defaultCreoleMode);
}
2015-04-07 18:18:37 +00:00
public boolean isWhite() {
return display.size() == 0 || (display.size() == 1 && display.get(0).toString().matches("\\s*"));
}
public static Display empty() {
2015-07-11 09:32:49 +00:00
return new Display((HorizontalAlignment) null, false, CreoleMode.FULL);
2015-04-07 18:18:37 +00:00
}
public static Display create(CharSequence... s) {
return create(Arrays.asList(s));
}
2015-06-20 10:54:49 +00:00
public static Display create(Collection<? extends CharSequence> other) {
2015-07-11 09:32:49 +00:00
return new Display(other, null, false, CreoleMode.FULL);
2015-04-07 18:18:37 +00:00
}
public static Display getWithNewlines(Code s) {
return getWithNewlines(s.getFullName());
}
public static Display getWithNewlines(String s) {
if (s == null) {
2015-07-11 09:32:49 +00:00
// Thread.dumpStack();
return NULL;
2015-04-07 18:18:37 +00:00
}
final List<String> result = new ArrayList<String>();
final StringBuilder current = new StringBuilder();
HorizontalAlignment naturalHorizontalAlignment = null;
2017-06-05 11:27:21 +00:00
boolean rawMode = false;
2015-04-07 18:18:37 +00:00
for (int i = 0; i < s.length(); i++) {
final char c = s.charAt(i);
2017-04-05 17:37:42 +00:00
final String sub = s.substring(i);
2017-06-05 11:27:21 +00:00
if (sub.startsWith("<math>") || sub.startsWith("<latex>") || sub.startsWith("[[")) {
rawMode = true;
} else if (sub.startsWith("</math>") || sub.startsWith("</latex>") || sub.startsWith("]]")) {
rawMode = false;
2017-04-05 17:37:42 +00:00
}
2017-06-05 11:27:21 +00:00
if (rawMode == false && c == '\\' && i < s.length() - 1) {
2015-04-07 18:18:37 +00:00
final char c2 = s.charAt(i + 1);
i++;
if (c2 == 'n' || c2 == 'r' || c2 == 'l') {
if (c2 == 'r') {
naturalHorizontalAlignment = HorizontalAlignment.RIGHT;
} else if (c2 == 'l') {
naturalHorizontalAlignment = HorizontalAlignment.LEFT;
}
result.add(current.toString());
current.setLength(0);
} else if (c2 == 't') {
current.append('\t');
} else if (c2 == '\\') {
current.append(c2);
} else {
current.append(c);
current.append(c2);
}
2017-04-26 17:48:37 +00:00
} else if (c == BackSlash.hiddenNewLine()) {
2015-05-31 18:56:03 +00:00
result.add(current.toString());
current.setLength(0);
2015-04-07 18:18:37 +00:00
} else {
current.append(c);
}
}
result.add(current.toString());
2015-07-11 09:32:49 +00:00
return new Display(result, naturalHorizontalAlignment, false, CreoleMode.FULL);
2015-04-07 18:18:37 +00:00
}
2013-12-10 19:36:50 +00:00
2015-07-11 09:32:49 +00:00
private Display(Display other, CreoleMode mode) {
this(other.naturalHorizontalAlignment, other.isNull, mode);
2013-12-10 19:36:50 +00:00
this.display.addAll(other.display);
}
2015-07-11 09:32:49 +00:00
private Display(HorizontalAlignment naturalHorizontalAlignment, boolean isNull, CreoleMode defaultCreoleMode) {
this.defaultCreoleMode = defaultCreoleMode;
this.isNull = isNull;
this.display = isNull ? null : new ArrayList<CharSequence>();
this.naturalHorizontalAlignment = isNull ? null : naturalHorizontalAlignment;
2015-04-07 18:18:37 +00:00
}
2015-07-11 09:32:49 +00:00
private Display(Collection<? extends CharSequence> other, HorizontalAlignment naturalHorizontalAlignment,
boolean isNull, CreoleMode defaultCreoleMode) {
this(naturalHorizontalAlignment, isNull, defaultCreoleMode);
if (isNull == false) {
this.display.addAll(manageEmbededDiagrams2(other));
}
2013-12-10 19:36:50 +00:00
}
2015-06-20 10:54:49 +00:00
private static List<CharSequence> manageEmbededDiagrams2(final Collection<? extends CharSequence> strings) {
2015-04-07 18:18:37 +00:00
final List<CharSequence> result = new ArrayList<CharSequence>();
final Iterator<? extends CharSequence> it = strings.iterator();
while (it.hasNext()) {
CharSequence s = it.next();
2015-05-31 18:56:03 +00:00
if (s != null && StringUtils.trin(s.toString()).equals("{{")) {
2015-04-07 18:18:37 +00:00
final List<CharSequence> other = new ArrayList<CharSequence>();
other.add("@startuml");
while (it.hasNext()) {
final CharSequence s2 = it.next();
2015-05-31 18:56:03 +00:00
if (s2 != null && StringUtils.trin(s2.toString()).equals("}}")) {
2015-04-07 18:18:37 +00:00
break;
}
other.add(s2);
}
other.add("@enduml");
s = new EmbededDiagram(Display.create(other));
}
result.add(s);
}
return result;
2013-12-10 19:36:50 +00:00
}
2016-11-04 21:39:29 +00:00
public Display manageGuillemet() {
final List<CharSequence> result = new ArrayList<CharSequence>();
for (CharSequence line : display) {
final String withGuillement = StringUtils.manageGuillemet(line.toString());
if (withGuillement.equals(line.toString())) {
result.add(line);
} else {
result.add(withGuillement);
}
}
return new Display(result, this.naturalHorizontalAlignment, this.isNull, this.defaultCreoleMode);
}
2017-11-20 16:10:36 +00:00
public Display withPage(int page, int lastpage) {
if (display == null) {
return this;
}
final List<CharSequence> result = new ArrayList<CharSequence>();
for (CharSequence line : display) {
line = line.toString().replace("%page%", "" + page);
line = line.toString().replace("%lastpage%", "" + lastpage);
result.add(line);
}
return new Display(result, this.naturalHorizontalAlignment, this.isNull, this.defaultCreoleMode);
}
2013-12-10 19:36:50 +00:00
public Display underlined() {
final List<CharSequence> result = new ArrayList<CharSequence>();
for (CharSequence line : display) {
result.add("<u>" + line);
}
2015-07-11 09:32:49 +00:00
return new Display(result, this.naturalHorizontalAlignment, this.isNull, this.defaultCreoleMode);
}
public Display withCreoleMode(CreoleMode mode) {
if (isNull) {
throw new IllegalArgumentException();
}
return new Display(this, mode);
2013-12-10 19:36:50 +00:00
}
2017-04-26 17:48:37 +00:00
// private String asStringWithHiddenNewLine() {
// final StringBuilder sb = new StringBuilder();
// for (int i = 0; i < display.size(); i++) {
// sb.append(display.get(i));
// if (i < display.size() - 1) {
// sb.append(BackSlash.hiddenNewLine());
// }
// }
// return sb.toString();
// }
2016-01-09 12:15:40 +00:00
2013-12-10 19:36:50 +00:00
@Override
public String toString() {
2015-07-11 09:32:49 +00:00
if (isNull) {
return "NULL";
}
2013-12-10 19:36:50 +00:00
return display.toString();
}
@Override
public int hashCode() {
return display.hashCode();
}
@Override
public boolean equals(Object other) {
return this.display.equals(((Display) other).display);
}
public Display addAll(Display other) {
2015-07-11 09:32:49 +00:00
final Display result = new Display(this, this.defaultCreoleMode);
2013-12-10 19:36:50 +00:00
result.display.addAll(other.display);
return result;
}
public Display addFirst(CharSequence s) {
2015-07-11 09:32:49 +00:00
final Display result = new Display(this, this.defaultCreoleMode);
2013-12-10 19:36:50 +00:00
result.display.add(0, s);
return result;
}
public Display add(CharSequence s) {
2015-07-11 09:32:49 +00:00
final Display result = new Display(this, this.defaultCreoleMode);
2013-12-10 19:36:50 +00:00
result.display.add(s);
return result;
}
2017-09-03 16:59:24 +00:00
public Display addGeneric(CharSequence s) {
final Display result = new Display(this, this.defaultCreoleMode);
final int size = display.size();
if (size == 0) {
result.display.add("<" + s + ">");
} else {
result.display.set(size - 1, display.get(size - 1) + "<" + s + ">");
}
return result;
}
2013-12-10 19:36:50 +00:00
public int size() {
2015-07-11 09:32:49 +00:00
if (isNull) {
return 0;
}
2013-12-10 19:36:50 +00:00
return display.size();
}
public CharSequence get(int i) {
return display.get(i);
}
public Iterator<CharSequence> iterator() {
return Collections.unmodifiableList(display).iterator();
}
public Display subList(int i, int size) {
2015-07-11 09:32:49 +00:00
return new Display(display.subList(i, size), this.naturalHorizontalAlignment, this.isNull,
this.defaultCreoleMode);
2013-12-10 19:36:50 +00:00
}
public List<? extends CharSequence> as() {
return Collections.unmodifiableList(display);
}
2015-06-20 10:54:49 +00:00
public List<CharSequence2> as2() {
final List<CharSequence2> result = new ArrayList<CharSequence2>();
LineLocationImpl location = new LineLocationImpl("inner", null);
for (CharSequence cs : display) {
location = location.oneLineRead();
result.add(new CharSequence2Impl(cs, location));
}
return Collections.unmodifiableList(result);
}
2013-12-10 19:36:50 +00:00
public boolean hasUrl() {
final UrlBuilder urlBuilder = new UrlBuilder(null, ModeUrl.ANYWHERE);
for (CharSequence s : this) {
if (urlBuilder.getUrl(s.toString()) != null) {
return true;
}
}
return false;
}
2015-04-07 18:18:37 +00:00
public HorizontalAlignment getNaturalHorizontalAlignment() {
return naturalHorizontalAlignment;
}
2016-05-31 19:41:55 +00:00
public List<Display> splitMultiline(Pattern2 separator) {
2015-05-31 18:56:03 +00:00
final List<Display> result = new ArrayList<Display>();
2015-07-11 09:32:49 +00:00
Display pending = new Display(this.naturalHorizontalAlignment, this.isNull, this.defaultCreoleMode);
2015-05-31 18:56:03 +00:00
result.add(pending);
for (CharSequence line : display) {
2016-05-31 19:41:55 +00:00
final Matcher2 m = separator.matcher(line);
2015-05-31 18:56:03 +00:00
if (m.find()) {
final CharSequence s1 = line.subSequence(0, m.start());
pending.display.add(s1);
final CharSequence s2 = line.subSequence(m.end(), line.length());
2015-07-11 09:32:49 +00:00
pending = new Display(this.naturalHorizontalAlignment, this.isNull, this.defaultCreoleMode);
2015-05-31 18:56:03 +00:00
result.add(pending);
pending.display.add(s2);
} else {
pending.display.add(line);
}
}
return Collections.unmodifiableList(result);
}
2015-07-11 09:32:49 +00:00
// ------
public static boolean isNull(Display display) {
2016-01-09 12:15:40 +00:00
// if (display == null) {
// throw new IllegalArgumentException();
// }
2015-07-11 09:32:49 +00:00
return display == null || display.isNull;
}
public TextBlock create(FontConfiguration fontConfiguration, HorizontalAlignment horizontalAlignment,
ISkinSimple spriteContainer) {
return create(fontConfiguration, horizontalAlignment, spriteContainer, CreoleMode.FULL);
}
public TextBlock createWithNiceCreoleMode(FontConfiguration fontConfiguration,
HorizontalAlignment horizontalAlignment, ISkinSimple spriteContainer) {
return create(fontConfiguration, horizontalAlignment, spriteContainer, defaultCreoleMode);
}
public TextBlock create(FontConfiguration fontConfiguration, HorizontalAlignment horizontalAlignment,
ISkinSimple spriteContainer, CreoleMode modeSimpleLine) {
2017-04-05 17:37:42 +00:00
return create(fontConfiguration, horizontalAlignment, spriteContainer, LineBreakStrategy.NONE, modeSimpleLine,
null, null);
2015-07-11 09:32:49 +00:00
}
2018-03-09 21:37:34 +00:00
public TextBlock create(FontConfiguration fontConfiguration, HorizontalAlignment horizontalAlignment,
ISkinSimple spriteContainer, CreoleMode modeSimpleLine, LineBreakStrategy maxMessageSize) {
return create(fontConfiguration, horizontalAlignment, spriteContainer, maxMessageSize, modeSimpleLine,
null, null);
}
2015-07-11 09:32:49 +00:00
public TextBlock create(FontConfiguration fontConfiguration, HorizontalAlignment horizontalAlignment,
2017-02-26 16:26:11 +00:00
ISkinSimple spriteContainer, LineBreakStrategy maxMessageSize) {
return create(fontConfiguration, horizontalAlignment, spriteContainer, maxMessageSize, defaultCreoleMode, null,
null);
}
public TextBlock create(FontConfiguration fontConfiguration, HorizontalAlignment horizontalAlignment,
ISkinSimple spriteContainer, LineBreakStrategy maxMessageSize, CreoleMode modeSimpleLine,
UFont fontForStereotype, HtmlColor htmlColorForStereotype) {
if (maxMessageSize == null) {
throw new IllegalArgumentException();
}
2015-07-11 09:32:49 +00:00
if (getNaturalHorizontalAlignment() != null) {
horizontalAlignment = getNaturalHorizontalAlignment();
}
if (size() > 0) {
if (get(0) instanceof Stereotype) {
return createStereotype(fontConfiguration, horizontalAlignment, spriteContainer, 0, fontForStereotype,
htmlColorForStereotype);
}
if (get(size() - 1) instanceof Stereotype) {
return createStereotype(fontConfiguration, horizontalAlignment, spriteContainer, size() - 1,
fontForStereotype, htmlColorForStereotype);
}
if (get(0) instanceof MessageNumber) {
return createMessageNumber(fontConfiguration, horizontalAlignment, spriteContainer, maxMessageSize);
}
}
return getCreole(fontConfiguration, horizontalAlignment, spriteContainer, maxMessageSize, modeSimpleLine);
}
private TextBlock getCreole(FontConfiguration fontConfiguration, HorizontalAlignment horizontalAlignment,
2017-02-26 16:26:11 +00:00
ISkinSimple spriteContainer, LineBreakStrategy maxMessageSize, CreoleMode modeSimpleLine) {
2015-07-11 09:32:49 +00:00
final Sheet sheet = new CreoleParser(fontConfiguration, horizontalAlignment, spriteContainer, modeSimpleLine)
.createSheet(this);
final SheetBlock1 sheetBlock1 = new SheetBlock1(sheet, maxMessageSize, spriteContainer == null ? 0
: spriteContainer.getPadding());
return new SheetBlock2(sheetBlock1, sheetBlock1, new UStroke(1.5));
}
private TextBlock createMessageNumber(FontConfiguration fontConfiguration, HorizontalAlignment horizontalAlignment,
2017-02-26 16:26:11 +00:00
ISkinSimple spriteContainer, LineBreakStrategy maxMessageSize) {
2015-07-11 09:32:49 +00:00
TextBlock tb1 = subList(0, 1).getCreole(fontConfiguration, horizontalAlignment, spriteContainer,
maxMessageSize, CreoleMode.FULL);
tb1 = TextBlockUtils.withMargin(tb1, 0, 4, 0, 0);
final TextBlock tb2 = subList(1, size()).getCreole(fontConfiguration, horizontalAlignment, spriteContainer,
maxMessageSize, CreoleMode.FULL);
return TextBlockUtils.mergeLR(tb1, tb2, VerticalAlignment.CENTER);
}
private TextBlock createStereotype(FontConfiguration fontConfiguration, HorizontalAlignment horizontalAlignment,
SpriteContainer spriteContainer, int position, UFont fontForStereotype, HtmlColor htmlColorForStereotype) {
final Stereotype stereotype = (Stereotype) get(position);
2016-07-04 19:06:50 +00:00
TextBlock circledCharacter = null;
2015-07-11 09:32:49 +00:00
if (stereotype.isSpotted()) {
2016-07-04 19:06:50 +00:00
circledCharacter = new CircledCharacter(stereotype.getCharacter(), stereotype.getRadius(),
stereotype.getCircledFont(), stereotype.getHtmlColor(), null, fontConfiguration.getColor());
} else if (stereotype.getSprite() != null) {
final Sprite tmp = spriteContainer.getSprite(stereotype.getSprite());
if (tmp != null) {
circledCharacter = tmp.asTextBlock(stereotype.getHtmlColor(), 1);
}
}
if (circledCharacter != null) {
2015-07-11 09:32:49 +00:00
if (stereotype.getLabel(false) == null) {
2016-07-04 19:06:50 +00:00
return new TextBlockSprited(circledCharacter, this.subList(1, this.size()), fontConfiguration,
2015-07-11 09:32:49 +00:00
horizontalAlignment, spriteContainer);
}
2016-07-04 19:06:50 +00:00
return new TextBlockSprited(circledCharacter, this, fontConfiguration, horizontalAlignment, spriteContainer);
2015-07-11 09:32:49 +00:00
}
return new TextBlockSimple(this, fontConfiguration, horizontalAlignment, spriteContainer, 0, fontForStereotype,
htmlColorForStereotype);
}
2013-12-10 19:36:50 +00:00
}