diff --git a/pom.xml b/pom.xml index a61a91ad2..642323dd0 100644 --- a/pom.xml +++ b/pom.xml @@ -35,7 +35,7 @@ net.sourceforge.plantuml plantuml - 1.2018.9-SNAPSHOT + 1.2018.10-SNAPSHOT jar PlantUML diff --git a/src/net/sourceforge/plantuml/AlignParam.java b/src/net/sourceforge/plantuml/AlignmentParam.java similarity index 79% rename from src/net/sourceforge/plantuml/AlignParam.java rename to src/net/sourceforge/plantuml/AlignmentParam.java index 9a4fbaa55..e6293b238 100644 --- a/src/net/sourceforge/plantuml/AlignParam.java +++ b/src/net/sourceforge/plantuml/AlignmentParam.java @@ -38,17 +38,18 @@ package net.sourceforge.plantuml; import net.sourceforge.plantuml.graphic.HorizontalAlignment; -public enum AlignParam { +public enum AlignmentParam { - ARROW_MESSAGE_ALIGN(HorizontalAlignment.LEFT), - SEQUENCE_MESSAGE_ALIGN(HorizontalAlignment.LEFT), - SEQUENCE_MESSAGETEXT_ALIGN(HorizontalAlignment.LEFT), - SEQUENCE_REFERENCE_ALIGN(HorizontalAlignment.CENTER), - PACKAGE_TITLE_ALIGNMENT(HorizontalAlignment.CENTER); + arrowMessageAlignment(HorizontalAlignment.LEFT), + sequenceMessageAlignment(HorizontalAlignment.LEFT), + sequenceMessageTextAlignment(HorizontalAlignment.LEFT), + sequenceReferenceAlignment(HorizontalAlignment.CENTER), + packageTitleAlignment(HorizontalAlignment.CENTER), + noteTextAlignment(HorizontalAlignment.LEFT); private final HorizontalAlignment defaultValue; - private AlignParam(HorizontalAlignment defaultValue) { + private AlignmentParam(HorizontalAlignment defaultValue) { this.defaultValue = defaultValue; } diff --git a/src/net/sourceforge/plantuml/BlockUml.java b/src/net/sourceforge/plantuml/BlockUml.java index 33a6d7b17..70dfbf8d0 100644 --- a/src/net/sourceforge/plantuml/BlockUml.java +++ b/src/net/sourceforge/plantuml/BlockUml.java @@ -173,9 +173,9 @@ public class BlockUml { return data.get(0).toString().equalsIgnoreCase(signature); } - public List getDefinition() { - if (data.get(0).toString().startsWith("@startdef") == false) { - throw new IllegalStateException(); + public List getDefinition(boolean withHeader) { + if (withHeader) { + return Collections.unmodifiableList(data); } return Collections.unmodifiableList(data.subList(1, data.size() - 1)); } diff --git a/src/net/sourceforge/plantuml/BlockUmlBuilder.java b/src/net/sourceforge/plantuml/BlockUmlBuilder.java index 33690243e..ef1587a86 100644 --- a/src/net/sourceforge/plantuml/BlockUmlBuilder.java +++ b/src/net/sourceforge/plantuml/BlockUmlBuilder.java @@ -141,7 +141,7 @@ public final class BlockUmlBuilder implements DefinitionsContainer { for (BlockUml block : blocks) { if (block.isStartDef(name)) { this.defines.importFrom(block.getLocalDefines()); - return block.getDefinition(); + return block.getDefinition(false); } } return Collections.emptyList(); diff --git a/src/net/sourceforge/plantuml/EmptyImageBuilder.java b/src/net/sourceforge/plantuml/EmptyImageBuilder.java index a5ae18d74..16824732e 100644 --- a/src/net/sourceforge/plantuml/EmptyImageBuilder.java +++ b/src/net/sourceforge/plantuml/EmptyImageBuilder.java @@ -49,18 +49,18 @@ public class EmptyImageBuilder { private final BufferedImage im; private final Graphics2D g2d; - + public EmptyImageBuilder(double width, double height, Color background) { this((int) width, (int) height, background); } public EmptyImageBuilder(int width, int height, Color background) { if (width > GraphvizUtils.getenvImageLimit()) { - Log.info("Width too large " + width); + Log.info("Width too large " + width + ". You should set PLANTUML_LIMIT_SIZE"); width = GraphvizUtils.getenvImageLimit(); } if (height > GraphvizUtils.getenvImageLimit()) { - Log.info("Height too large " + height); + Log.info("Height too large " + height + ". You should set PLANTUML_LIMIT_SIZE"); height = GraphvizUtils.getenvImageLimit(); } Log.info("Creating image " + width + "x" + height); diff --git a/src/net/sourceforge/plantuml/FileFormat.java b/src/net/sourceforge/plantuml/FileFormat.java index 5a7786050..ba691c926 100644 --- a/src/net/sourceforge/plantuml/FileFormat.java +++ b/src/net/sourceforge/plantuml/FileFormat.java @@ -55,7 +55,7 @@ import net.sourceforge.plantuml.ugraphic.UFont; * */ public enum FileFormat { - PNG, SVG, EPS, EPS_TEXT, ATXT, UTXT, XMI_STANDARD, XMI_STAR, XMI_ARGO, SCXML, PDF, MJPEG, ANIMATED_GIF, HTML, HTML5, VDX, LATEX, LATEX_NO_PREAMBLE, BASE64, BRAILLE_PNG; + PNG, SVG, EPS, EPS_TEXT, ATXT, UTXT, XMI_STANDARD, XMI_STAR, XMI_ARGO, SCXML, PDF, MJPEG, ANIMATED_GIF, HTML, HTML5, VDX, LATEX, LATEX_NO_PREAMBLE, BASE64, BRAILLE_PNG, PREPROC; /** * Returns the file format to be used for that format. diff --git a/src/net/sourceforge/plantuml/ISkinParam.java b/src/net/sourceforge/plantuml/ISkinParam.java index 8314e44be..22aed027a 100644 --- a/src/net/sourceforge/plantuml/ISkinParam.java +++ b/src/net/sourceforge/plantuml/ISkinParam.java @@ -51,6 +51,8 @@ import net.sourceforge.plantuml.ugraphic.UStroke; public interface ISkinParam extends ISkinSimple { + public static final int SWIMLANE_WIDTH_SAME = -1; + public HtmlColor getHyperlinkColor(); public boolean useUnderlineForHyperlink(); @@ -67,7 +69,7 @@ public interface ISkinParam extends ISkinSimple { public UFont getFont(Stereotype stereotype, boolean inPackageTitle, FontParam... fontParam); - public HorizontalAlignment getHorizontalAlignment(AlignParam param, ArrowDirection arrowDirection); + public HorizontalAlignment getHorizontalAlignment(AlignmentParam param, ArrowDirection arrowDirection); public HorizontalAlignment getDefaultTextAlignment(HorizontalAlignment defaultValue); @@ -109,6 +111,8 @@ public interface ISkinParam extends ISkinSimple { public LineBreakStrategy wrapWidth(); + public LineBreakStrategy swimlaneWrapTitleWidth(); + public boolean strictUmlStyle(); public boolean forceSequenceParticipantUnderlined(); diff --git a/src/net/sourceforge/plantuml/LineBreakStrategy.java b/src/net/sourceforge/plantuml/LineBreakStrategy.java index 347d8fe04..5934eb7e7 100644 --- a/src/net/sourceforge/plantuml/LineBreakStrategy.java +++ b/src/net/sourceforge/plantuml/LineBreakStrategy.java @@ -45,7 +45,11 @@ public class LineBreakStrategy { this.value = value; } - public double getMathWidth() { + public boolean isAuto() { + return "auto".equalsIgnoreCase(value); + } + + public double getMaxWidth() { if (value != null && value.matches("-?\\d+")) { return Double.parseDouble(value); } diff --git a/src/net/sourceforge/plantuml/Option.java b/src/net/sourceforge/plantuml/Option.java index fb2095488..0968f8fad 100644 --- a/src/net/sourceforge/plantuml/Option.java +++ b/src/net/sourceforge/plantuml/Option.java @@ -68,6 +68,7 @@ public class Option { private boolean pipeNoStdErr = false; private boolean syntax = false; private boolean checkOnly = false; + private OptionPreprocOutputMode preprocessorOutput = null; private boolean failfast = false; private boolean failfast2 = false; private boolean pattern = false; @@ -332,6 +333,10 @@ public class Option { textProgressBar = true; } else if (s.equalsIgnoreCase("-nometadata")) { hideMetadata = true; + } else if (s.equalsIgnoreCase("-preproc")) { + preprocessorOutput = OptionPreprocOutputMode.NORMAL; + } else if (s.equalsIgnoreCase("-cypher")) { + preprocessorOutput = OptionPreprocOutputMode.CYPHER; } else if (s.equalsIgnoreCase("-checkmetadata")) { checkMetadata = true; } else if (s.equalsIgnoreCase("-pipeimageindex")) { @@ -588,4 +593,12 @@ public class Option { return checkMetadata; } + public final OptionPreprocOutputMode getPreprocessorOutputMode() { + return preprocessorOutput; + } + + // public final void setPreprocessorOutput(boolean preprocessorOutput) { + // this.preprocessorOutput = preprocessorOutput; + // } + } diff --git a/src/net/sourceforge/plantuml/OptionPreprocOutputMode.java b/src/net/sourceforge/plantuml/OptionPreprocOutputMode.java new file mode 100644 index 000000000..4fc91798a --- /dev/null +++ b/src/net/sourceforge/plantuml/OptionPreprocOutputMode.java @@ -0,0 +1,41 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2017, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * 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 + * + * 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; + +public enum OptionPreprocOutputMode { + NORMAL, CYPHER + +} diff --git a/src/net/sourceforge/plantuml/OptionPrint.java b/src/net/sourceforge/plantuml/OptionPrint.java index f368ce1c5..bd3e6e2bb 100644 --- a/src/net/sourceforge/plantuml/OptionPrint.java +++ b/src/net/sourceforge/plantuml/OptionPrint.java @@ -142,9 +142,10 @@ public class OptionPrint { System.out.println(" -splash\t\tTo display a splash screen with some progress bar"); System.out.println(" -progress\t\tTo display a textual progress bar in console"); System.out.println(" -pipeimageindex N\tTo generate the Nth image with pipe option"); - System.out.println(" -stdlib\tTo print standart library info"); + System.out.println(" -stdlib\t\tTo print standart library info"); System.out.println(" -extractstdlib\tTo extract PlantUML Standard Library into stdlib folder"); System.out.println(" -filename \"example.puml\"\tTo override %filename% variable"); + System.out.println(" -preproc\t\tTo output preprocessor text of diagrams"); System.out.println(); System.out.println("If needed, you can setup the environment variable GRAPHVIZ_DOT."); exit(); diff --git a/src/net/sourceforge/plantuml/PSystemError.java b/src/net/sourceforge/plantuml/PSystemError.java index 64b19c028..407affa46 100644 --- a/src/net/sourceforge/plantuml/PSystemError.java +++ b/src/net/sourceforge/plantuml/PSystemError.java @@ -71,6 +71,7 @@ import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.UImage; import net.sourceforge.plantuml.ugraphic.UTranslate; import net.sourceforge.plantuml.ugraphic.txt.UGraphicTxt; +import net.sourceforge.plantuml.version.LicenseInfo; import net.sourceforge.plantuml.version.PSystemVersion; public class PSystemError extends AbstractPSystem { @@ -144,9 +145,11 @@ public class PSystemError extends AbstractPSystem { } else { udrawable = result; } - final int min = (int) (System.currentTimeMillis() / 60000L) % 60; - if (min == 0) { - udrawable = addMessage(udrawable); + if (LicenseInfo.retrieveQuick().isValid() == false) { + final int min = (int) (System.currentTimeMillis() / 60000L) % 60; + if (min == 0) { + udrawable = addMessage(udrawable); + } } imageBuilder.setUDrawable(udrawable); final ImageData imageData = imageBuilder.writeImageTOBEMOVED(fileFormat, seed(), os); diff --git a/src/net/sourceforge/plantuml/Run.java b/src/net/sourceforge/plantuml/Run.java index 1d5ea969a..7182af853 100644 --- a/src/net/sourceforge/plantuml/Run.java +++ b/src/net/sourceforge/plantuml/Run.java @@ -43,6 +43,9 @@ import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; @@ -67,12 +70,16 @@ import net.sourceforge.plantuml.sequencediagram.SequenceDiagramFactory; import net.sourceforge.plantuml.statediagram.StateDiagramFactory; import net.sourceforge.plantuml.stats.StatsUtils; import net.sourceforge.plantuml.swing.MainWindow2; +import net.sourceforge.plantuml.syntax.LanguageDescriptor; import net.sourceforge.plantuml.ugraphic.sprite.SpriteGrayLevel; import net.sourceforge.plantuml.ugraphic.sprite.SpriteUtils; +import net.sourceforge.plantuml.utils.Cypher; import net.sourceforge.plantuml.version.Version; public class Run { + private static Cypher cypher; + public static void main(String[] argsArray) throws IOException, InterruptedException { System.setProperty("log4j.debug", "false"); final long start = System.currentTimeMillis(); @@ -135,6 +142,9 @@ public class Run { } forceOpenJdkResourceLoad(); + if (option.getPreprocessorOutputMode() == OptionPreprocOutputMode.CYPHER) { + cypher = new LanguageDescriptor().getCypher(); + } boolean error = false; boolean forceQuit = false; if (option.isPattern()) { @@ -231,10 +241,13 @@ public class Run { return false; } + static private final String httpProtocol = "http://"; + static private final String httpsProtocol = "https://"; + private static void encodeSprite(List result) throws IOException { SpriteGrayLevel level = SpriteGrayLevel.GRAY_16; boolean compressed = false; - final File f; + final String path; if (result.size() > 1 && result.get(0).matches("(4|8|16)z?")) { if (result.get(0).startsWith("8")) { level = SpriteGrayLevel.GRAY_8; @@ -243,28 +256,52 @@ public class Run { level = SpriteGrayLevel.GRAY_4; } compressed = StringUtils.goLowerCase(result.get(0)).endsWith("z"); - f = new File(result.get(1)); + path = result.get(1); } else { - f = new File(result.get(0)); + path = result.get(0); } - final BufferedImage im = ImageIO.read(f); - final String name = getSpriteName(f); + + final String fileName; + final URL source; + final String lowerPath = StringUtils.goLowerCase(path); + if (lowerPath.startsWith(httpProtocol) || lowerPath.startsWith(httpsProtocol)) { + source = new URL(path); + final String p = source.getPath(); + fileName = p.substring(p.lastIndexOf('/') + 1, p.length()); + } else { + final File f = new File(path); + source = f.toURI().toURL(); + fileName = f.getName(); + } + + InputStream stream = null; + final BufferedImage im; + try { + stream = source.openStream(); + im = ImageIO.read(stream); + } finally { + if (stream != null) { + stream.close(); + } + } + + final String name = getSpriteName(fileName); final String s = compressed ? SpriteUtils.encodeCompressed(im, name, level) : SpriteUtils.encode(im, name, level); System.out.println(s); } - private static String getSpriteName(File f) { - final String s = getSpriteNameInternal(f); + private static String getSpriteName(String fileName) { + final String s = getSpriteNameInternal(fileName); if (s.length() == 0) { return "test"; } return s; } - private static String getSpriteNameInternal(File f) { + private static String getSpriteNameInternal(String fileName) { final StringBuilder sb = new StringBuilder(); - for (char c : f.getName().toCharArray()) { + for (char c : fileName.toCharArray()) { if (("" + c).matches("[\\p{L}0-9_]")) { sb.append(c); } else { @@ -291,7 +328,6 @@ public class Run { for (String n : name) { System.out.println("n=" + n); } - } private static void managePattern() { @@ -356,6 +392,7 @@ public class Run { files.addAll(group.getFiles()); } } + Log.info("Found " + files.size() + " files"); for (File f : files) { try { final boolean error = manageFileInternal(f, option); @@ -417,6 +454,7 @@ public class Run { } private static boolean manageFileInternal(File f, Option option) throws IOException, InterruptedException { + Log.info("Working on " + f.getAbsolutePath()); if (OptionFlags.getInstance().isExtractFromMetadata()) { System.out.println("------------------------"); System.out.println(f); @@ -435,6 +473,7 @@ public class Run { option.getConfig(), option.getCharset(), option.getFileFormatOption()); } sourceFileReader.setCheckMetadata(option.isCheckMetadata()); + if (option.isComputeurl()) { for (BlockUml s : sourceFileReader.getBlocks()) { System.out.println(s.getEncodedUrl()); @@ -447,10 +486,33 @@ public class Run { hasErrors(f, result); return hasError; } + if (option.getPreprocessorOutputMode() != null) { + extractPreproc(option, sourceFileReader); + return false; + } final List result = sourceFileReader.getGeneratedImages(); + return hasErrors(f, result); } + private static void extractPreproc(Option option, final ISourceFileReader sourceFileReader) throws IOException { + final String charset = option.getCharset(); + for (BlockUml blockUml : sourceFileReader.getBlocks()) { + final SuggestedFile suggested = ((SourceFileReaderAbstract) sourceFileReader).getSuggestedFile(blockUml) + .withPreprocFormat(); + final File file = suggested.getFile(0); + Log.info("Export preprocessing source to " + file.getAbsolutePath()); + final PrintWriter pw = charset == null ? new PrintWriter(file) : new PrintWriter(file, charset); + for (CharSequence s : blockUml.getDefinition(true)) { + if (cypher != null) { + s = cypher.cypher(s.toString()); + } + pw.println(s); + } + pw.close(); + } + } + private static boolean hasErrors(File f, final List list) throws IOException { boolean result = false; for (GeneratedImage i : list) { diff --git a/src/net/sourceforge/plantuml/SignatureUtils.java b/src/net/sourceforge/plantuml/SignatureUtils.java index 1d5b88a1c..ea0cf2d94 100644 --- a/src/net/sourceforge/plantuml/SignatureUtils.java +++ b/src/net/sourceforge/plantuml/SignatureUtils.java @@ -42,18 +42,30 @@ import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; import net.sourceforge.plantuml.code.AsciiEncoder; public class SignatureUtils { + public static byte[] salting(String pass, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException, + UnsupportedEncodingException { + final int iterations = 10000; + final int keyLength = 512; + final SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); + final PBEKeySpec spec = new PBEKeySpec(pass.toCharArray(), salt, iterations, keyLength); + final SecretKey key = skf.generateSecret(spec); + return SignatureUtils.getSHA512raw(key.getEncoded()); + } + public static String getSignature(String s) { try { - final AsciiEncoder coder = new AsciiEncoder(); - final MessageDigest msgDigest = MessageDigest.getInstance("MD5"); - msgDigest.update(s.getBytes("UTF-8")); - final byte[] digest = msgDigest.digest(); - return coder.encode(digest); + final byte[] digest = getMD5raw(s); + return toString(digest); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); throw new UnsupportedOperationException(e); @@ -63,21 +75,24 @@ public class SignatureUtils { } } - public static String getMD5(String s) { + public static String toString(byte data[]) { + final AsciiEncoder coder = new AsciiEncoder(); + return coder.encode(data); + } + + public static String toHexString(byte data[]) { + final StringBuilder sb = new StringBuilder(data.length * 2); + for (byte b : data) { + sb.append(String.format("%02x", b)); + } + return sb.toString(); + } + + public static String getMD5Hex(String s) { try { - final MessageDigest msgDigest = MessageDigest.getInstance("MD5"); - msgDigest.update(s.getBytes("UTF-8")); - final byte[] digest = msgDigest.digest(); - final StringBuilder result = new StringBuilder(32); - for (byte b : digest) { - final String tmp = Integer.toHexString(b & 0xFF); - if (tmp.length() == 1) { - result.append("0"); - } - result.append(tmp); - } - assert result.length() == 32; - return result.toString(); + final byte[] digest = getMD5raw(s); + assert digest.length == 16; + return toHexString(digest); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); throw new UnsupportedOperationException(e); @@ -87,6 +102,36 @@ public class SignatureUtils { } } + public static String getSHA512Hex(String s) { + try { + final byte[] digest = getSHA512raw(s); + assert digest.length == 64; + return toHexString(digest); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + throw new UnsupportedOperationException(e); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + throw new UnsupportedOperationException(e); + } + } + + public static byte[] getMD5raw(String s) throws NoSuchAlgorithmException, UnsupportedEncodingException { + final MessageDigest msgDigest = MessageDigest.getInstance("MD5"); + msgDigest.update(s.getBytes("UTF-8")); + return msgDigest.digest(); + } + + public static byte[] getSHA512raw(String s) throws NoSuchAlgorithmException, UnsupportedEncodingException { + return getSHA512raw(s.getBytes("UTF-8")); + } + + public static byte[] getSHA512raw(byte data[]) throws NoSuchAlgorithmException, UnsupportedEncodingException { + final MessageDigest msgDigest = MessageDigest.getInstance("SHA-512"); + msgDigest.update(data); + return msgDigest.digest(); + } + public static String getSignatureSha512(File f) throws IOException { final InputStream is = new FileInputStream(f); try { @@ -98,14 +143,13 @@ public class SignatureUtils { public static String getSignatureSha512(InputStream is) throws IOException { try { - final AsciiEncoder coder = new AsciiEncoder(); final MessageDigest msgDigest = MessageDigest.getInstance("SHA-512"); int read = 0; while ((read = is.read()) != -1) { msgDigest.update((byte) read); } final byte[] digest = msgDigest.digest(); - return coder.encode(digest); + return toString(digest); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); throw new UnsupportedOperationException(e); @@ -130,7 +174,6 @@ public class SignatureUtils { public static String getSignature(File f) throws IOException { try { - final AsciiEncoder coder = new AsciiEncoder(); final MessageDigest msgDigest = MessageDigest.getInstance("MD5"); final FileInputStream is = new FileInputStream(f); int read = -1; @@ -139,7 +182,7 @@ public class SignatureUtils { } is.close(); final byte[] digest = msgDigest.digest(); - return coder.encode(digest); + return toString(digest); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); throw new UnsupportedOperationException(e); diff --git a/src/net/sourceforge/plantuml/SkinParam.java b/src/net/sourceforge/plantuml/SkinParam.java index b24ca1344..2216ab0fa 100644 --- a/src/net/sourceforge/plantuml/SkinParam.java +++ b/src/net/sourceforge/plantuml/SkinParam.java @@ -137,6 +137,7 @@ public class SkinParam implements ISkinParam { key = key.replaceAll("statearrow", "arrow"); key = key.replaceAll("usecasearrow", "arrow"); key = key.replaceAll("sequencearrow", "arrow"); + key = key.replaceAll("align$", "alignment"); final Matcher2 mm = stereoPattern.matcher(key); final List result = new ArrayList(); while (mm.find()) { @@ -427,8 +428,10 @@ public class SkinParam implements ISkinParam { result.add("PageBorderColor"); result.add("PageExternalColor"); result.add("PageMargin"); + result.add("WrapWidth"); + result.add("SwimlaneWidth"); + result.add("SwimlaneWrapTitleWidth"); - for (FontParam p : EnumSet.allOf(FontParam.class)) { final String h = humanName(p.name()); result.add(h + "FontStyle"); @@ -444,6 +447,10 @@ public class SkinParam implements ISkinParam { final String h = capitalize(p.name()); result.add(h + "Thickness"); } + for (AlignmentParam p : EnumSet.allOf(AlignmentParam.class)) { + final String h = capitalize(p.name()); + result.add(h); + } return Collections.unmodifiableSet(result); } @@ -470,14 +477,14 @@ public class SkinParam implements ISkinParam { return DotSplines.SPLINES; } - public HorizontalAlignment getHorizontalAlignment(AlignParam param, ArrowDirection arrowDirection) { + public HorizontalAlignment getHorizontalAlignment(AlignmentParam param, ArrowDirection arrowDirection) { final String value; switch (param) { - case SEQUENCE_MESSAGE_ALIGN: - value = getArg(getValue(AlignParam.SEQUENCE_MESSAGE_ALIGN.name()), 0); + case sequenceMessageAlignment: + value = getArg(getValue(AlignmentParam.sequenceMessageAlignment.name()), 0); break; - case SEQUENCE_MESSAGETEXT_ALIGN: - value = getArg(getValue(AlignParam.SEQUENCE_MESSAGE_ALIGN.name()), 1); + case sequenceMessageTextAlignment: + value = getArg(getValue(AlignmentParam.sequenceMessageAlignment.name()), 1); break; default: value = getValue(param.name()); @@ -489,6 +496,9 @@ public class SkinParam implements ISkinParam { if (arrowDirection == ArrowDirection.RIGHT_TO_LEFT_REVERSE) { return HorizontalAlignment.RIGHT; } + if (arrowDirection == ArrowDirection.BOTH_DIRECTION) { + return HorizontalAlignment.CENTER; + } } if ("reversedirection".equalsIgnoreCase(value)) { if (arrowDirection == ArrowDirection.LEFT_TO_RIGHT_NORMAL) { @@ -497,9 +507,14 @@ public class SkinParam implements ISkinParam { if (arrowDirection == ArrowDirection.RIGHT_TO_LEFT_REVERSE) { return HorizontalAlignment.LEFT; } + if (arrowDirection == ArrowDirection.BOTH_DIRECTION) { + return HorizontalAlignment.CENTER; + } } final HorizontalAlignment result = HorizontalAlignment.fromString(value); - if (result == null) { + if (result == null && param == AlignmentParam.noteTextAlignment) { + return getDefaultTextAlignment(HorizontalAlignment.LEFT); + } else if (result == null) { return param.getDefaultValue(); } return result; @@ -755,6 +770,11 @@ public class SkinParam implements ISkinParam { return new LineBreakStrategy(value); } + public LineBreakStrategy swimlaneWrapTitleWidth() { + final String value = getValue("swimlanewraptitlewidth"); + return new LineBreakStrategy(value); + } + public boolean strictUmlStyle() { final String value = getValue("style"); if ("strictuml".equalsIgnoreCase(value)) { @@ -917,7 +937,7 @@ public class SkinParam implements ISkinParam { public int swimlaneWidth() { final String value = getValue("swimlanewidth"); if ("same".equalsIgnoreCase(value)) { - return -1; + return SWIMLANE_WIDTH_SAME; } if (value != null && value.matches("\\d+")) { return Integer.parseInt(value); diff --git a/src/net/sourceforge/plantuml/SkinParamDelegator.java b/src/net/sourceforge/plantuml/SkinParamDelegator.java index 362f2b6f3..854b1500b 100644 --- a/src/net/sourceforge/plantuml/SkinParamDelegator.java +++ b/src/net/sourceforge/plantuml/SkinParamDelegator.java @@ -103,7 +103,7 @@ public class SkinParamDelegator implements ISkinParam { return skinParam.getDotExecutable(); } - public HorizontalAlignment getHorizontalAlignment(AlignParam param, ArrowDirection arrowDirection) { + public HorizontalAlignment getHorizontalAlignment(AlignmentParam param, ArrowDirection arrowDirection) { return skinParam.getHorizontalAlignment(param, arrowDirection); } @@ -295,4 +295,8 @@ public class SkinParamDelegator implements ISkinParam { return skinParam.getCircledCharacter(stereotype); } + public LineBreakStrategy swimlaneWrapTitleWidth() { + return skinParam.swimlaneWrapTitleWidth(); + } + } diff --git a/src/net/sourceforge/plantuml/SourceFileReaderAbstract.java b/src/net/sourceforge/plantuml/SourceFileReaderAbstract.java index 93bbb0574..7b4bd1229 100644 --- a/src/net/sourceforge/plantuml/SourceFileReaderAbstract.java +++ b/src/net/sourceforge/plantuml/SourceFileReaderAbstract.java @@ -140,7 +140,7 @@ public abstract class SourceFileReaderAbstract { final List result = new ArrayList(); for (BlockUml blockUml : builder.getBlockUmls()) { - SuggestedFile suggested = getSuggestedFile(blockUml); + final SuggestedFile suggested = getSuggestedFile(blockUml); final Diagram system; try { diff --git a/src/net/sourceforge/plantuml/SuggestedFile.java b/src/net/sourceforge/plantuml/SuggestedFile.java index 5db9a0c12..834fe5ade 100644 --- a/src/net/sourceforge/plantuml/SuggestedFile.java +++ b/src/net/sourceforge/plantuml/SuggestedFile.java @@ -52,6 +52,10 @@ public class SuggestedFile { this.initialCpt = initialCpt; } + public SuggestedFile withPreprocFormat() { + return new SuggestedFile(outputFile, FileFormat.PREPROC, initialCpt); + } + @Override public String toString() { return outputFile.getAbsolutePath() + "[" + initialCpt + "]"; diff --git a/src/net/sourceforge/plantuml/SvgString.java b/src/net/sourceforge/plantuml/SvgString.java index f580d4e88..7d589bfd8 100644 --- a/src/net/sourceforge/plantuml/SvgString.java +++ b/src/net/sourceforge/plantuml/SvgString.java @@ -48,8 +48,11 @@ public class SvgString { this.scale = scale; } - public String getSvg() { + public String getSvg(boolean raw) { String result = svg; + if (raw) { + return result; + } if (result.startsWith(" swimlanes = new ArrayList(); + private Swimlane currentSwimlane = null; + + private final Instruction root = new InstructionList(); + private Instruction currentInstruction = root; + + private LinkRendering nextLinkRenderer = LinkRendering.none(); + + public SwimlanesA(ISkinParam skinParam, Pragma pragma) { + this.skinParam = skinParam; + this.pragma = pragma; + } + + private FtileFactory getFtileFactory(StringBounder stringBounder) { + FtileFactory factory = new VCompactFactory(skinParam, stringBounder); + factory = new FtileFactoryDelegatorAddUrl(factory); + factory = new FtileFactoryDelegatorAssembly(factory); + factory = new FtileFactoryDelegatorIf(factory, pragma); + factory = new FtileFactoryDelegatorWhile(factory); + factory = new FtileFactoryDelegatorRepeat(factory); + factory = new FtileFactoryDelegatorCreateParallel(factory); + // factory = new FtileFactoryDelegatorCreateParallelAddingMargin(new + // FtileFactoryDelegatorCreateParallel1(factory)); + factory = new FtileFactoryDelegatorAddNote(factory); + factory = new FtileFactoryDelegatorCreateGroup(factory); + return factory; + } + + public void swimlane(String name, HtmlColor color, Display label) { + currentSwimlane = getOrCreate(name); + if (color != null) { + currentSwimlane.setSpecificColorTOBEREMOVED(ColorType.BACK, color); + } + if (Display.isNull(label) == false) { + currentSwimlane.setDisplay(label); + } + } + + private Swimlane getOrCreate(String name) { + for (Swimlane s : swimlanes) { + if (s.getName().equals(name)) { + return s; + } + } + final Swimlane result = new Swimlane(name); + swimlanes.add(result); + return result; + } + + class Cross extends UGraphicDelegator { + + private Cross(UGraphic ug) { + super(ug); + } + + @Override + public void draw(UShape shape) { + if (shape instanceof Ftile) { + final Ftile tile = (Ftile) shape; + tile.drawU(this); + } else if (shape instanceof Connection) { + final Connection connection = (Connection) shape; + final Ftile tile1 = connection.getFtile1(); + final Ftile tile2 = connection.getFtile2(); + + if (tile1 == null || tile2 == null) { + return; + } + if (tile1.getSwimlaneOut() != tile2.getSwimlaneIn()) { + final ConnectionCross connectionCross = new ConnectionCross(connection); + connectionCross.drawU(getUg()); + } + } + } + + public UGraphic apply(UChange change) { + return new Cross(getUg().apply(change)); + } + + } + + static protected final double separationMargin = 10; + + private TextBlock full; + + public void drawU(UGraphic ug) { + if (full == null) { + final FtileFactory factory = getFtileFactory(ug.getStringBounder()); + full = root.createFtile(factory); + if (swimlanes.size() <= 1) { + // BUG42 + full = new TextBlockInterceptorUDrawable(full); + } + } + + ug = new UGraphicForSnake(ug); + if (swimlanes.size() <= 1) { + full.drawU(ug); + ug.flushUg(); + return; + } + + drawWhenSwimlanes(ug, full); + } + + static private void printDebug(UGraphic ug, SlotSet slot, HtmlColor col, TextBlock full) { + slot.drawDebugX(ug.apply(new UChangeColor(col)).apply(new UChangeBackColor(col)), + full.calculateDimension(ug.getStringBounder()).getHeight()); + + } + + protected void drawWhenSwimlanes(final UGraphic ug, TextBlock full) { + final StringBounder stringBounder = ug.getStringBounder(); + final Dimension2D dimensionFull = full.calculateDimension(stringBounder); + + computeSize(ug, full); + final UTranslate titleHeightTranslate = getTitleHeightTranslate(stringBounder); + + double x2 = 0; + for (Swimlane swimlane : swimlanes) { + final HtmlColor back = swimlane.getColors(skinParam).getColor(ColorType.BACK); + if (back != null) { + final UGraphic background = ug.apply(new UChangeBackColor(back)).apply(new UChangeColor(back)) + .apply(new UTranslate(x2, 0)); + background.draw(new URectangle(swimlane.getActualWidth(), dimensionFull.getHeight() + + titleHeightTranslate.getDy())); + } + + full.drawU(new UGraphicInterceptorOneSwimlane(ug, swimlane).apply(swimlane.getTranslate()).apply( + titleHeightTranslate)); + x2 += swimlane.getActualWidth(); + + } + final Cross cross = new Cross(ug.apply(titleHeightTranslate)); + full.drawU(cross); + cross.flushUg(); + } + + protected UTranslate getTitleHeightTranslate(final StringBounder stringBounder) { + return new UTranslate(); + } + + private void computeDrawingWidths(UGraphic ug, TextBlock full) { + final StringBounder stringBounder = ug.getStringBounder(); + for (Swimlane swimlane : swimlanes) { + final LimitFinder limitFinder = new LimitFinder(stringBounder, false); + final UGraphicInterceptorOneSwimlane interceptor = new UGraphicInterceptorOneSwimlane(new UGraphicForSnake( + limitFinder), swimlane); + full.drawU(interceptor); + interceptor.flushUg(); + final MinMax minMax = limitFinder.getMinMax(); + swimlane.setMinMax(minMax); + } + } + + private void computeSize(UGraphic ug, TextBlock full) { + computeDrawingWidths(ug, full); + double x1 = 0; + + double swimlaneWidth = skinParam.swimlaneWidth(); + + if (swimlaneWidth == ISkinParam.SWIMLANE_WIDTH_SAME) { + for (Swimlane swimlane : swimlanes) { + swimlaneWidth = Math.max(swimlaneWidth, rawDrawingWidth(swimlane)); + } + + } + for (Swimlane swimlane : swimlanes) { + final double swimlaneActualWidth = swimlaneActualWidth(ug.getStringBounder(), swimlaneWidth, swimlane); + + final UTranslate translate = new UTranslate(x1 - swimlane.getMinMax().getMinX() + separationMargin + + (swimlaneActualWidth - rawDrawingWidth(swimlane)) / 2.0, 0); + swimlane.setTranslateAndWidth(translate, swimlaneActualWidth); + + x1 += swimlaneActualWidth; + } + } + + protected double swimlaneActualWidth(StringBounder stringBounder, double swimlaneWidth, Swimlane swimlane) { + return MathUtils.max(swimlaneWidth, rawDrawingWidth(swimlane)); + } + + private double rawDrawingWidth(Swimlane swimlane) { + return swimlane.getMinMax().getWidth() + 2 * separationMargin; + } + + public Dimension2D calculateDimension(StringBounder stringBounder) { + return getMinMax(stringBounder).getDimension(); + } + + public Instruction getCurrent() { + return currentInstruction; + } + + public void setCurrent(Instruction current) { + this.currentInstruction = current; + } + + public LinkRendering nextLinkRenderer() { + return nextLinkRenderer; + } + + public void setNextLinkRenderer(LinkRendering link) { + if (link == null) { + throw new IllegalArgumentException(); + } + this.nextLinkRenderer = link; + } + + public Swimlane getCurrentSwimlane() { + return currentSwimlane; + } + + private MinMax cachedMinMax; + + @Override + public MinMax getMinMax(StringBounder stringBounder) { + if (cachedMinMax == null) { + cachedMinMax = TextBlockUtils.getMinMax(this, stringBounder); + } + return cachedMinMax; + } + +} diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ftile/SwimlanesB.java b/src/net/sourceforge/plantuml/activitydiagram3/ftile/SwimlanesB.java new file mode 100644 index 000000000..9250a3274 --- /dev/null +++ b/src/net/sourceforge/plantuml/activitydiagram3/ftile/SwimlanesB.java @@ -0,0 +1,112 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2017, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * 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 + * + * 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.activitydiagram3.ftile; + +import net.sourceforge.plantuml.FontParam; +import net.sourceforge.plantuml.ISkinParam; +import net.sourceforge.plantuml.LineBreakStrategy; +import net.sourceforge.plantuml.Pragma; +import net.sourceforge.plantuml.graphic.FontConfiguration; +import net.sourceforge.plantuml.graphic.HorizontalAlignment; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.graphic.TextBlock; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.UTranslate; +import net.sourceforge.plantuml.utils.MathUtils; + +public class SwimlanesB extends SwimlanesA { + + public SwimlanesB(ISkinParam skinParam, Pragma pragma) { + super(skinParam, pragma); + } + + @Override + protected void drawWhenSwimlanes(UGraphic ug, TextBlock full) { + super.drawWhenSwimlanes(ug, full); + double x2 = 0; + + final StringBounder stringBounder = ug.getStringBounder(); + for (Swimlane swimlane : swimlanes) { + final TextBlock swTitle = getTitle(swimlane); + final double titleWidth = swTitle.calculateDimension(stringBounder).getWidth(); + final double posTitle = x2 + (swimlane.getActualWidth() - titleWidth) / 2; + swTitle.drawU(ug.apply(new UTranslate(posTitle, 0))); + x2 += swimlane.getActualWidth(); + } + } + + private TextBlock getTitle(Swimlane swimlane) { + final FontConfiguration fontConfiguration = new FontConfiguration(skinParam, FontParam.SWIMLANE_TITLE, null); + + LineBreakStrategy wrap = getWrap(); + if (wrap.isAuto()) { + wrap = new LineBreakStrategy("" + ((int) swimlane.getActualWidth())); + } + + return swimlane.getDisplay().create(fontConfiguration, HorizontalAlignment.LEFT, skinParam, wrap); + } + + private LineBreakStrategy getWrap() { + LineBreakStrategy wrap = skinParam.swimlaneWrapTitleWidth(); + if (wrap == LineBreakStrategy.NONE) { + wrap = skinParam.wrapWidth(); + } + return wrap; + } + + @Override + protected double swimlaneActualWidth(StringBounder stringBounder, double swimlaneWidth, Swimlane swimlane) { + final double m1 = super.swimlaneActualWidth(stringBounder, swimlaneWidth, swimlane); + if (getWrap().isAuto()) { + return m1; + } + + final double titleWidth = getTitle(swimlane).calculateDimension(stringBounder).getWidth(); + return MathUtils.max(m1, titleWidth + 2 * separationMargin); + + } + + @Override + protected UTranslate getTitleHeightTranslate(final StringBounder stringBounder) { + double titlesHeight = 0; + for (Swimlane swimlane : swimlanes) { + final TextBlock swTitle = getTitle(swimlane); + titlesHeight = Math.max(titlesHeight, swTitle.calculateDimension(stringBounder).getHeight()); + } + return new UTranslate(0, titlesHeight); + } + +} diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ftile/SwimlanesC.java b/src/net/sourceforge/plantuml/activitydiagram3/ftile/SwimlanesC.java new file mode 100644 index 000000000..1184b410d --- /dev/null +++ b/src/net/sourceforge/plantuml/activitydiagram3/ftile/SwimlanesC.java @@ -0,0 +1,89 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2017, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * 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 + * + * 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.activitydiagram3.ftile; + +import java.awt.geom.Dimension2D; + +import net.sourceforge.plantuml.ColorParam; +import net.sourceforge.plantuml.ISkinParam; +import net.sourceforge.plantuml.LineParam; +import net.sourceforge.plantuml.Pragma; +import net.sourceforge.plantuml.graphic.HtmlColor; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.graphic.TextBlock; +import net.sourceforge.plantuml.skin.rose.Rose; +import net.sourceforge.plantuml.ugraphic.UChangeColor; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.ULine; +import net.sourceforge.plantuml.ugraphic.UStroke; +import net.sourceforge.plantuml.ugraphic.UTranslate; + +public class SwimlanesC extends SwimlanesB { + + public SwimlanesC(ISkinParam skinParam, Pragma pragma) { + super(skinParam, pragma); + } + + @Override + protected void drawWhenSwimlanes(UGraphic ug, TextBlock full) { + super.drawWhenSwimlanes(ug, full); + double x2 = 0; + + final StringBounder stringBounder = ug.getStringBounder(); + final Dimension2D dimensionFull = full.calculateDimension(stringBounder); + + final UTranslate titleHeightTranslate = getTitleHeightTranslate(stringBounder); + + for (Swimlane swimlane : swimlanes) { + drawSeparation(ug.apply(new UTranslate(x2, 0)), dimensionFull.getHeight() + titleHeightTranslate.getDy()); + + x2 += swimlane.getActualWidth(); + + } + drawSeparation(ug.apply(new UTranslate(x2, 0)), dimensionFull.getHeight() + titleHeightTranslate.getDy()); + + } + + private void drawSeparation(UGraphic ug, double height) { + HtmlColor color = skinParam.getHtmlColor(ColorParam.swimlaneBorder, null, false); + if (color == null) { + color = ColorParam.swimlaneBorder.getDefaultValue(); + } + final UStroke thickness = Rose.getStroke(skinParam, LineParam.swimlaneBorder, 2); + ug.apply(thickness).apply(new UChangeColor(color)).draw(new ULine(0, height)); + } + +} diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileGroup.java b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileGroup.java index d249d56f8..c566a342e 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileGroup.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileGroup.java @@ -38,7 +38,7 @@ package net.sourceforge.plantuml.activitydiagram3.ftile.vcompact; import java.awt.geom.Dimension2D; import java.util.Set; -import net.sourceforge.plantuml.AlignParam; +import net.sourceforge.plantuml.AlignmentParam; import net.sourceforge.plantuml.FontParam; import net.sourceforge.plantuml.ISkinParam; import net.sourceforge.plantuml.LineParam; @@ -196,7 +196,7 @@ public class FtileGroup extends AbstractFtile { final SymbolContext symbolContext = new SymbolContext(backColor, borderColor).withShadow( skinParam().shadowing()).withStroke(stroke); - USymbol.FRAME.asBig(name, inner.skinParam().getHorizontalAlignment(AlignParam.PACKAGE_TITLE_ALIGNMENT, null), + USymbol.FRAME.asBig(name, inner.skinParam().getHorizontalAlignment(AlignmentParam.packageTitleAlignment, null), TextBlockUtils.empty(0, 0), dimTotal.getWidth(), dimTotal.getHeight(), symbolContext).drawU(ug); final Dimension2D dimHeaderNote = headerNote.calculateDimension(stringBounder); diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileWhile.java b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileWhile.java index 93f59ec48..85c17364e 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileWhile.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileWhile.java @@ -250,7 +250,6 @@ class FtileWhile extends AbstractFtile { final double x1 = p1.getX(); final double y1 = p1.getY(); final double x2 = p2.getX() + dimDiamond1.getWidth(); - // final double y2 = p2.getY() + dimDiamond1.getOutY() / 2; final double half = (dimDiamond1.getOutY() - dimDiamond1.getInY()) / 2; final double y2 = p2.getY() + dimDiamond1.getInY() + half; @@ -268,8 +267,6 @@ class FtileWhile extends AbstractFtile { ug.apply(new UTranslate(x1, y1bis)).draw(new UEmpty(5, Diamond.diamondHalfSize)); - // ug = ug.apply(new UChangeColor(endInlinkColor)).apply(new UChangeBackColor(endInlinkColor)); - // ug.apply(new UTranslate(xx, (y1 + y2) / 2)).draw(Arrows.asToUp()); } public void drawTranslate(UGraphic ug, UTranslate translate1, UTranslate translate2) { @@ -281,12 +278,13 @@ class FtileWhile extends AbstractFtile { final Point2D p1 = translate1.getTranslated(ap1); final Point2D p2 = translate2.getTranslated(ap2); - final Dimension2D dimDiamond1 = diamond1.calculateDimension(stringBounder); + final FtileGeometry dimDiamond1 = diamond1.calculateDimension(stringBounder); final double x1 = p1.getX(); final double y1 = p1.getY(); final double x2 = p2.getX() + dimDiamond1.getWidth(); - final double y2 = p2.getY() + dimDiamond1.getHeight() / 2; + final double half = (dimDiamond1.getOutY() - dimDiamond1.getInY()) / 2; + final double y2 = p2.getY() + dimDiamond1.getInY() + half; snake.addPoint(x1, y1); snake.addPoint(x1, y1 + Diamond.diamondHalfSize); @@ -402,8 +400,6 @@ class FtileWhile extends AbstractFtile { snake.goUnmergeable(MergeStrategy.LIMITED); ug.draw(snake); - // ug = ug.apply(new UChangeColor(afterEndwhileColor)).apply(new UChangeBackColor(afterEndwhileColor)); - // ug.apply(new UTranslate(Diamond.diamondHalfSize, (y1 + y2) / 2)).draw(Arrows.asToDown()); final Snake snake2 = new Snake(arrowHorizontalAlignment(), afterEndwhileColor); snake2.addPoint(Diamond.diamondHalfSize, y2); diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vertical/FtileBox.java b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vertical/FtileBox.java index ff6970448..d7868eb86 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vertical/FtileBox.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vertical/FtileBox.java @@ -125,7 +125,7 @@ public class FtileBox extends AbstractFtile { final FontConfiguration fc = new FontConfiguration(skinParam, FontParam.ACTIVITY, null); final Sheet sheet = new CreoleParser(fc, skinParam.getDefaultTextAlignment(HorizontalAlignment.LEFT), skinParam, CreoleMode.FULL).createSheet(label); - this.tb = new SheetBlock2(new SheetBlock1(sheet, LineBreakStrategy.NONE, skinParam.getPadding()), new MyStencil(), new UStroke(1)); + this.tb = new SheetBlock2(new SheetBlock1(sheet, skinParam.wrapWidth(), skinParam.getPadding()), new MyStencil(), new UStroke(1)); this.print = label.toString(); } diff --git a/src/net/sourceforge/plantuml/graphic/TextBlockCompressed2.java b/src/net/sourceforge/plantuml/code/ArobaseStringCompressor2.java similarity index 55% rename from src/net/sourceforge/plantuml/graphic/TextBlockCompressed2.java rename to src/net/sourceforge/plantuml/code/ArobaseStringCompressor2.java index 2a8e7a4d6..3433de76d 100644 --- a/src/net/sourceforge/plantuml/graphic/TextBlockCompressed2.java +++ b/src/net/sourceforge/plantuml/code/ArobaseStringCompressor2.java @@ -30,34 +30,33 @@ * * * Original Author: Arnaud Roques - * + * * */ -package net.sourceforge.plantuml.graphic; +package net.sourceforge.plantuml.code; -import java.awt.geom.Dimension2D; +import java.io.IOException; -import net.sourceforge.plantuml.Dimension2DDouble; -import net.sourceforge.plantuml.ugraphic.CompressionTransform; -import net.sourceforge.plantuml.ugraphic.UGraphic; -import net.sourceforge.plantuml.ugraphic.UGraphicCompress2; +import net.sourceforge.plantuml.StringUtils; -public class TextBlockCompressed2 extends AbstractTextBlock implements TextBlock { +public class ArobaseStringCompressor2 implements StringCompressor { - private final TextBlock textBlock; - private final CompressionTransform compressionTransform; - - public TextBlockCompressed2(TextBlock textBlock, CompressionTransform compressionTransform) { - this.textBlock = textBlock; - this.compressionTransform = compressionTransform; + public String compress(String data) throws IOException { + return clean2(data); } - public void drawU(final UGraphic ug) { - textBlock.drawU(new UGraphicCompress2(ug, compressionTransform)); + public String decompress(String s) throws IOException { + return clean2(s); } - public Dimension2D calculateDimension(StringBounder stringBounder) { - final Dimension2D dim = textBlock.calculateDimension(stringBounder); - return new Dimension2DDouble(compressionTransform.transform(dim.getWidth()), dim.getHeight()); + private String clean2(String s) { + s = s.replace("\0", ""); + s = StringUtils.trin(s); + s = s.replace("\r", "").replaceAll("\n+$", ""); + if (s.startsWith("@start")) { + return s; + } + return "@startuml\n" + s + "\n@enduml"; } + } \ No newline at end of file diff --git a/src/net/sourceforge/plantuml/code/TranscoderSmart2.java b/src/net/sourceforge/plantuml/code/TranscoderSmart2.java new file mode 100644 index 000000000..cbdec7e2a --- /dev/null +++ b/src/net/sourceforge/plantuml/code/TranscoderSmart2.java @@ -0,0 +1,109 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2017, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * 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 + * + * 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.code; + +import java.io.IOException; + +public class TranscoderSmart2 implements Transcoder { + + // Legacy encoder + private final Transcoder oldOne = new TranscoderImpl(new AsciiEncoder(), new ArobaseStringCompressor2(), + new CompressionHuffman()); + private final Transcoder zlib = new TranscoderImpl(new AsciiEncoder(), new ArobaseStringCompressor2(), + new CompressionZlib()); + private final Transcoder brotli = new TranscoderImpl(new AsciiEncoder(), new ArobaseStringCompressor2(), + new CompressionBrotli()); + + + private final Transcoder zlibBase64 = new TranscoderImpl(new AsciiEncoderBase64(), new ArobaseStringCompressor2(), + new CompressionZlib()); + private final Transcoder brotliBase64 = new TranscoderImpl(new AsciiEncoderBase64(), new ArobaseStringCompressor2(), + new CompressionBrotli()); + private final Transcoder base64only = new TranscoderImpl(new AsciiEncoderBase64(), new ArobaseStringCompressor2(), + new CompressionNone()); + private final Transcoder hexOnly = new TranscoderImpl(new AsciiEncoderHex(), new ArobaseStringCompressor2(), + new CompressionNone()); + + public String decode(String code) throws IOException { + // Work in progress + // See https://github.com/plantuml/plantuml/issues/117 + + // Two char headers + if (code.startsWith("0A")) { + return zlibBase64.decode(code.substring(2)); + } + if (code.startsWith("0B")) { + return brotliBase64.decode(code.substring(2)); + } + if (code.startsWith("0C")) { + return base64only.decode(code.substring(2)); + } + if (code.startsWith("0D")) { + return hexOnly.decode(code.substring(2)); + } + // Text prefix + // Just a wild try: use them only for testing + if (code.startsWith("-deflate-")) { + return zlibBase64.decode(code.substring("-deflate-".length())); + } + if (code.startsWith("-brotli-")) { + return brotliBase64.decode(code.substring("-brotli-".length())); + } + if (code.startsWith("-base64-")) { + return base64only.decode(code.substring("-base64-".length())); + } + if (code.startsWith("-hex-")) { + return hexOnly.decode(code.substring("-hex-".length())); + } + + // Legacy decoding : you should not use it any more. + if (code.startsWith("0")) { + return brotli.decode(code.substring(1)); + } + try { + return zlib.decode(code); + } catch (Exception ex) { + return oldOne.decode(code); + } + // return zlib.decode(code); + } + + public String encode(String text) throws IOException { + // Right now, we still use the legacy encoding. + // This will be changed in the incoming months + return zlib.encode(text); + } +} diff --git a/src/net/sourceforge/plantuml/code/TranscoderUtil.java b/src/net/sourceforge/plantuml/code/TranscoderUtil.java index 21734bf99..0c0402215 100644 --- a/src/net/sourceforge/plantuml/code/TranscoderUtil.java +++ b/src/net/sourceforge/plantuml/code/TranscoderUtil.java @@ -41,4 +41,8 @@ public class TranscoderUtil { return new TranscoderSmart(); } + public static Transcoder getDefaultTranscoder2() { + return new TranscoderSmart2(); + } + } diff --git a/src/net/sourceforge/plantuml/command/regex/Matcher2.java b/src/net/sourceforge/plantuml/command/regex/Matcher2.java index 736802097..742e2b64b 100644 --- a/src/net/sourceforge/plantuml/command/regex/Matcher2.java +++ b/src/net/sourceforge/plantuml/command/regex/Matcher2.java @@ -40,6 +40,8 @@ import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; +import net.sourceforge.plantuml.Log; + public class Matcher2 { private final static boolean INSTRUMENT = false; @@ -80,6 +82,7 @@ public class Matcher2 { } private static final Map durations = new HashMap(); + private static long printed; private static synchronized void addTime(String id, long duration) { Long total = durations.get(id); @@ -88,12 +91,29 @@ public class Matcher2 { } total += duration; durations.put(id, total); - if (total > 200) { - System.err.println("foo " + total + " " + id); + final String longest = getLongest(); + if (longest == null) { + return; + } + if (durations.get(longest) > printed) { + Log.info("---------- Regex " + longest + " " + durations.get(longest) + "ms (" + durations.size() + ")"); + printed = durations.get(longest); } } + private static String getLongest() { + long max = 0; + String result = null; + for (Map.Entry ent : durations.entrySet()) { + if (ent.getValue() > max) { + max = ent.getValue(); + result = ent.getKey(); + } + } + return result; + } + public String group(int n) { final long now = System.currentTimeMillis(); try { diff --git a/src/net/sourceforge/plantuml/creole/AtomText.java b/src/net/sourceforge/plantuml/creole/AtomText.java index 32a7e7c20..47d51ec92 100644 --- a/src/net/sourceforge/plantuml/creole/AtomText.java +++ b/src/net/sourceforge/plantuml/creole/AtomText.java @@ -291,7 +291,7 @@ public class AtomText implements Atom { } public List getSplitted(StringBounder stringBounder, LineBreakStrategy maxWidthAsString) { - final double maxWidth = maxWidthAsString.getMathWidth(); + final double maxWidth = maxWidthAsString.getMaxWidth(); final List result = new ArrayList(); final StringTokenizer st = new StringTokenizer(text, " ", true); final StringBuilder currentLine = new StringBuilder(); diff --git a/src/net/sourceforge/plantuml/creole/Fission.java b/src/net/sourceforge/plantuml/creole/Fission.java index 0cdf3d41e..bfb84a055 100644 --- a/src/net/sourceforge/plantuml/creole/Fission.java +++ b/src/net/sourceforge/plantuml/creole/Fission.java @@ -58,7 +58,7 @@ public class Fission { } public List getSplitted(StringBounder stringBounder) { - final double valueMaxWidth = maxWidth.getMathWidth(); + final double valueMaxWidth = maxWidth.getMaxWidth(); if (valueMaxWidth == 0) { return Arrays.asList(stripe); } diff --git a/src/net/sourceforge/plantuml/cucadiagram/BodyEnhanced.java b/src/net/sourceforge/plantuml/cucadiagram/BodyEnhanced.java index 8258c70ce..8fb8b2bab 100644 --- a/src/net/sourceforge/plantuml/cucadiagram/BodyEnhanced.java +++ b/src/net/sourceforge/plantuml/cucadiagram/BodyEnhanced.java @@ -146,7 +146,7 @@ public class BodyEnhanced extends AbstractTextBlock implements TextBlock, WithPo char separator = lineFirst ? '_' : 0; TextBlock title = null; List members = new ArrayList(); - final LineBreakStrategy lineBreakStrategy = skinParam.wrapWidth(); + // final LineBreakStrategy lineBreakStrategy = skinParam.wrapWidth(); for (ListIterator it = rawBody.listIterator(); it.hasNext();) { final String s = it.next(); if (manageHorizontalLine && isBlockSeparator(s)) { diff --git a/src/net/sourceforge/plantuml/cucadiagram/Display.java b/src/net/sourceforge/plantuml/cucadiagram/Display.java index 018a5fc51..4e6e16965 100644 --- a/src/net/sourceforge/plantuml/cucadiagram/Display.java +++ b/src/net/sourceforge/plantuml/cucadiagram/Display.java @@ -95,7 +95,8 @@ public class Display implements Iterable { } public boolean isWhite() { - return display.size() == 0 || (display.size() == 1 && display.get(0).toString().matches("\\s*")); + return display == null || display.size() == 0 + || (display.size() == 1 && display.get(0).toString().matches("\\s*")); } public static Display empty() { @@ -398,8 +399,8 @@ public class Display implements Iterable { public TextBlock create(FontConfiguration fontConfiguration, HorizontalAlignment horizontalAlignment, ISkinSimple spriteContainer, CreoleMode modeSimpleLine, LineBreakStrategy maxMessageSize) { - return create(fontConfiguration, horizontalAlignment, spriteContainer, maxMessageSize, modeSimpleLine, - null, null); + return create(fontConfiguration, horizontalAlignment, spriteContainer, maxMessageSize, modeSimpleLine, null, + null); } public TextBlock create(FontConfiguration fontConfiguration, HorizontalAlignment horizontalAlignment, diff --git a/src/net/sourceforge/plantuml/dedication/QBlock.java b/src/net/sourceforge/plantuml/dedication/QBlock.java index 3fed0bcde..98f0c78aa 100644 --- a/src/net/sourceforge/plantuml/dedication/QBlock.java +++ b/src/net/sourceforge/plantuml/dedication/QBlock.java @@ -40,6 +40,8 @@ import java.io.InputStream; import java.io.OutputStream; import java.math.BigInteger; +import net.sourceforge.plantuml.version.Magic; + public class QBlock { private final BigInteger big; @@ -59,6 +61,20 @@ public class QBlock { return new QBlock(new BigInteger(block)); } + public static QBlock fromMagic(Magic magic) { + final byte[] buffer = magic.getBuffer(); + final byte[] block = new byte[buffer.length + 1]; + System.arraycopy(buffer, 0, block, 1, buffer.length); + final BigInteger big = new BigInteger(block); + return new QBlock(big); + } + + public Magic toMagic() { + final Magic magic = new Magic(); + magic.set(0, getData512()); + return magic; + } + public QBlock(BigInteger number) { this.big = number; } @@ -68,13 +84,27 @@ public class QBlock { return new QBlock(changed); } - public byte[] getData() { + private byte[] getData512() { + final byte[] nb = big.toByteArray(); + if (nb.length == 512) { + return nb; + } + final byte[] result = new byte[512]; + if (nb.length < 512) { + System.arraycopy(nb, 0, result, 512 - nb.length, nb.length); + } else { + System.arraycopy(nb, nb.length - 512, result, 0, 512); + } + return result; + } + + public byte[] getDataRaw() { return big.toByteArray(); } @Override public String toString() { - return big.toByteArray().length + " " + big.toString(); + return big.toByteArray().length + " " + big.toString(36); } public void write(OutputStream os, int size) throws IOException { diff --git a/src/net/sourceforge/plantuml/dedication/QBlocks.java b/src/net/sourceforge/plantuml/dedication/QBlocks.java index 6f052dc44..586c4e478 100644 --- a/src/net/sourceforge/plantuml/dedication/QBlocks.java +++ b/src/net/sourceforge/plantuml/dedication/QBlocks.java @@ -77,24 +77,24 @@ public class QBlocks { } } - public String encodeAscii() { - final StringBuilder sb = new StringBuilder(); - final AsciiEncoder encoder = new AsciiEncoder(); - for (QBlock rsa : all) { - sb.append(encoder.encode(rsa.getData())); - sb.append("!"); - } - return sb.toString(); - } +// public String encodeAscii() { +// final StringBuilder sb = new StringBuilder(); +// final AsciiEncoder encoder = new AsciiEncoder(); +// for (QBlock rsa : all) { +// sb.append(encoder.encode(rsa.getDataRaw())); +// sb.append("!"); +// } +// return sb.toString(); +// } - public static QBlocks descodeAscii(String s) { - final QBlocks result = new QBlocks(); - final AsciiEncoder encoder = new AsciiEncoder(); - for (String bl : s.split("!")) { - final BigInteger bigInteger = new BigInteger(encoder.decode(bl)); - result.all.add(new QBlock(bigInteger)); - - } - return result; - } +// public static QBlocks descodeAscii(String s) { +// final QBlocks result = new QBlocks(); +// final AsciiEncoder encoder = new AsciiEncoder(); +// for (String bl : s.split("!")) { +// final BigInteger bigInteger = new BigInteger(encoder.decode(bl)); +// result.all.add(new QBlock(bigInteger)); +// +// } +// return result; +// } } diff --git a/src/net/sourceforge/plantuml/dedication/TurningBytes.java b/src/net/sourceforge/plantuml/dedication/TurningBytes.java index 9627c93e7..fa79642c1 100644 --- a/src/net/sourceforge/plantuml/dedication/TurningBytes.java +++ b/src/net/sourceforge/plantuml/dedication/TurningBytes.java @@ -35,7 +35,7 @@ */ package net.sourceforge.plantuml.dedication; -class TurningBytes { +public class TurningBytes { private final byte key[]; private int idx; diff --git a/src/net/sourceforge/plantuml/descdiagram/command/CommandCreateElementMultilines.java b/src/net/sourceforge/plantuml/descdiagram/command/CommandCreateElementMultilines.java index 268cb9bfc..27213b830 100644 --- a/src/net/sourceforge/plantuml/descdiagram/command/CommandCreateElementMultilines.java +++ b/src/net/sourceforge/plantuml/descdiagram/command/CommandCreateElementMultilines.java @@ -39,6 +39,9 @@ import java.util.List; import net.sourceforge.plantuml.FontParam; import net.sourceforge.plantuml.StringUtils; +import net.sourceforge.plantuml.Url; +import net.sourceforge.plantuml.UrlBuilder; +import net.sourceforge.plantuml.UrlBuilder.ModeUrl; import net.sourceforge.plantuml.classdiagram.AbstractEntityDiagram; import net.sourceforge.plantuml.command.BlocLines; import net.sourceforge.plantuml.command.CommandExecutionResult; @@ -89,6 +92,8 @@ public class CommandCreateElementMultilines extends CommandMultilines2\\>)?"), // new RegexLeaf("[%s]*"), // + new RegexLeaf("URL", "(" + UrlBuilder.getRegexp() + ")?"), // + new RegexLeaf("[%s]*"), // ColorParser.exp1(), // new RegexLeaf("[%s]*"), // new RegexLeaf("DESC", "as[%s]*[%g]([^%g]*)$")); @@ -100,6 +105,8 @@ public class CommandCreateElementMultilines extends CommandMultilines2\\>)?"), // new RegexLeaf("[%s]*"), // + new RegexLeaf("URL", "(" + UrlBuilder.getRegexp() + ")?"), // + new RegexLeaf("[%s]*"), // ColorParser.exp1(), // new RegexLeaf("[%s]*"), // new RegexLeaf("DESC", "\\[(.*)$")); @@ -154,6 +161,14 @@ public class CommandCreateElementMultilines extends CommandMultilines2 lines, boolean emptyParentheses) { - this.signature = new DefineSignature(key); this.emptyParentheses = emptyParentheses; if (lines == null) { this.definition = null; @@ -65,6 +64,7 @@ public class Define { this.definition = sb.toString(); this.definitionQuoted = Matcher.quoteReplacement(definition); } + this.signature = new DefineSignature(key, this.definitionQuoted); } @Override @@ -78,7 +78,7 @@ public class Define { } if (signature.isMethod()) { for (Variables vars : signature.getVariationVariables()) { - line = vars.applyOn(line, signature.getFonctionName(), definitionQuoted); + line = vars.applyOn(line); } } else { final String regex = "\\b" + signature.getKey() + "\\b" + (emptyParentheses ? "(\\(\\))?" : ""); diff --git a/src/net/sourceforge/plantuml/preproc/DefineSignature.java b/src/net/sourceforge/plantuml/preproc/DefineSignature.java index 46235d1b1..6952810a7 100644 --- a/src/net/sourceforge/plantuml/preproc/DefineSignature.java +++ b/src/net/sourceforge/plantuml/preproc/DefineSignature.java @@ -43,24 +43,30 @@ import java.util.StringTokenizer; public class DefineSignature { private final String key; - private final String fctName; - private final Variables vars = new Variables(); + private final String fonctionName; + private final List variables = new ArrayList(); - public DefineSignature(String key) { + public DefineSignature(String key, String definitionQuoted) { this.key = key; final StringTokenizer st = new StringTokenizer(key, "(),"); - this.fctName = st.nextToken().trim(); + this.fonctionName = st.nextToken().trim(); + final Variables master = new Variables(fonctionName, definitionQuoted); while (st.hasMoreTokens()) { final String var1 = st.nextToken().trim(); - this.vars.add(new DefineVariable(var1)); + master.add(new DefineVariable(var1)); + } + + final int count = master.countDefaultValue(); + for (int i = 0; i <= count; i++) { + variables.add(master.removeSomeDefaultValues(i)); } } @Override public String toString() { - return key + "/" + fctName + "/" + vars; + return key + "/" + fonctionName; } public boolean isMethod() { @@ -72,16 +78,7 @@ public class DefineSignature { } public List getVariationVariables() { - final List result = new ArrayList(); - final int count = vars.countDefaultValue(); - for (int i = 0; i <= count; i++) { - result.add(vars.removeSomeDefaultValues(i)); - } - return Collections.unmodifiableList(result); - } - - public String getFonctionName() { - return fctName; + return Collections.unmodifiableList(variables); } } diff --git a/src/net/sourceforge/plantuml/preproc/IfManager.java b/src/net/sourceforge/plantuml/preproc/IfManager.java index 85f9b1f58..dd38d199e 100644 --- a/src/net/sourceforge/plantuml/preproc/IfManager.java +++ b/src/net/sourceforge/plantuml/preproc/IfManager.java @@ -43,7 +43,7 @@ import net.sourceforge.plantuml.command.regex.MyPattern; import net.sourceforge.plantuml.command.regex.Pattern2; import net.sourceforge.plantuml.version.Version; -class IfManager implements ReadLine { +class IfManager extends ReadLineInstrumented implements ReadLine { protected static final Pattern2 ifdefPattern = MyPattern.cmpile("^[%s]*!if(n)?def[%s]+(.+)$"); protected static final Pattern2 ifcomparePattern = MyPattern @@ -61,7 +61,8 @@ class IfManager implements ReadLine { this.source = source; } - final public CharSequence2 readLine() throws IOException { + @Override + final CharSequence2 readLineInst() throws IOException { if (child != null) { final CharSequence2 s = child.readLine(); if (s != null) { @@ -117,7 +118,8 @@ class IfManager implements ReadLine { return 0; } - public void close() throws IOException { + @Override + void closeInst() throws IOException { source.close(); } diff --git a/src/net/sourceforge/plantuml/preproc/Preprocessor.java b/src/net/sourceforge/plantuml/preproc/Preprocessor.java index fde02325f..1a2e242d2 100644 --- a/src/net/sourceforge/plantuml/preproc/Preprocessor.java +++ b/src/net/sourceforge/plantuml/preproc/Preprocessor.java @@ -37,192 +37,62 @@ package net.sourceforge.plantuml.preproc; import java.io.File; import java.io.IOException; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; import net.sourceforge.plantuml.CharSequence2; -import net.sourceforge.plantuml.CharSequence2Impl; import net.sourceforge.plantuml.DefinitionsContainer; -import net.sourceforge.plantuml.StringUtils; -import net.sourceforge.plantuml.command.regex.Matcher2; -import net.sourceforge.plantuml.command.regex.MyPattern; -import net.sourceforge.plantuml.command.regex.Pattern2; -import net.sourceforge.plantuml.utils.StartUtils; +import net.sourceforge.plantuml.Log; -public class Preprocessor implements ReadLine { +public class Preprocessor extends ReadLineInstrumented implements ReadLine { - private static final String END_DEFINE_LONG = "!enddefinelong"; - private static final String ID = "[A-Za-z_][A-Za-z_0-9]*"; - private static final String ID_ARG = "\\s*[A-Za-z_][A-Za-z_0-9]*\\s*(?:=\\s*(?:\"[^\"]*\"|'[^']*')\\s*)?"; - private static final String ARG = "(?:\\(" + ID_ARG + "(?:," + ID_ARG + ")*?\\))?"; - private static final Pattern2 definePattern = MyPattern.cmpile("^[%s]*!define[%s]+(" + ID + ARG + ")" - + "(?:[%s]+(.*))?$"); - private static final Pattern2 filenamePattern = MyPattern.cmpile("^[%s]*!filename[%s]+(.+)$"); - private static final Pattern2 undefPattern = MyPattern.cmpile("^[%s]*!undef[%s]+(" + ID + ")$"); - private static final Pattern2 definelongPattern = MyPattern.cmpile("^[%s]*!definelong[%s]+(" + ID + ARG + ")"); - private static final Pattern2 enddefinelongPattern = MyPattern.cmpile("^[%s]*" + END_DEFINE_LONG + "[%s]*$"); - - private final Defines defines; - private final PreprocessorInclude rawSource; - private final ReadLineInsertable source; + private final PreprocessorInclude include; private final SubPreprocessor subPreprocessor; + private final String description; public Sub getSub(String blocname) { return subPreprocessor.getSub(blocname); } + // public Preprocessor(List config, ReadLine reader, String charset, Defines defines, File newCurrentDir, + // DefinitionsContainer definitionsContainer) { + // + // final ReadLine source2 = new IfManager(reader, defines); + // final ReadLineInsertable source3 = new ReadLineInsertable(source2); + // final ReadLine source4 = new PreprocessorDefine(defines, source3); + // this.include = new PreprocessorInclude(config, source4, defines, charset, newCurrentDir, definitionsContainer); + // this.subPreprocessor = new SubPreprocessor(config, charset, defines, definitionsContainer, include); + // } + public Preprocessor(List config, ReadLine reader, String charset, Defines defines, File newCurrentDir, DefinitionsContainer definitionsContainer) { - this.defines = defines; - this.defines.saveState(); - this.rawSource = new PreprocessorInclude(config, reader, defines, charset, newCurrentDir, definitionsContainer); - this.source = new ReadLineInsertable(new IfManager(rawSource, defines)); - this.subPreprocessor = new SubPreprocessor(config, charset, defines, definitionsContainer, new ReadLine() { - - public void close() throws IOException { - Preprocessor.this.close(); - } - - public CharSequence2 readLine() throws IOException { - return readLineInternal(); - } - }); + this.description = reader.toString(); + this.include = new PreprocessorInclude(config, reader, defines, charset, newCurrentDir, definitionsContainer); + final ReadLine source2 = new IfManager(include, defines); + final ReadLineInsertable source3 = new ReadLineInsertable(source2); + final ReadLine source4 = new PreprocessorDefine(defines, source3); + this.subPreprocessor = new SubPreprocessor(config, charset, defines, definitionsContainer, source4); } - public CharSequence2 readLine() throws IOException { + @Override + CharSequence2 readLineInst() throws IOException { return subPreprocessor.readLine(); } - private CharSequence2 readLineInternal() throws IOException { - final CharSequence2 s = source.readLine(); - if (s == null) { - return null; - } - if (StartUtils.isArobaseStartDiagram(s)) { - this.defines.restoreState(); - } - - Matcher2 m = filenamePattern.matcher(s); - if (m.find()) { - return manageFilename(m); - } - m = definePattern.matcher(s); - if (m.find()) { - return manageDefine(m, s.toString().trim().endsWith("()")); - } - - m = definelongPattern.matcher(s); - if (m.find()) { - return manageDefineLong(m, s.toString().trim().endsWith("()")); - } - - m = undefPattern.matcher(s); - if (m.find()) { - return manageUndef(m); - } - - if (ignoreDefineDuringSeveralLines > 0) { - ignoreDefineDuringSeveralLines--; - return s; - } - - List result = defines.applyDefines(s.toString2()); - if (result.size() > 1) { - result = cleanEndDefineLong(result); - final List inserted = cleanEndDefineLong(result.subList(1, result.size())); - ignoreDefineDuringSeveralLines = inserted.size(); - source.insert(inserted, s.getLocation()); - } - return new CharSequence2Impl(result.get(0), s.getLocation(), s.getPreprocessorError()); - } - - private List cleanEndDefineLong(List data) { - final List result = new ArrayList(); - for (String s : data) { - final String clean = cleanEndDefineLong(s); - if (clean != null) { - result.add(clean); - } - } - return result; - - } - - private String cleanEndDefineLong(String s) { - if (s.trim().startsWith(END_DEFINE_LONG)) { - s = s.trim().substring(END_DEFINE_LONG.length()); - if (s.length() == 0) { - return null; - } - } - return s; - } - - private int ignoreDefineDuringSeveralLines = 0; - - private CharSequence2 manageUndef(Matcher2 m) throws IOException { - defines.undefine(m.group(1)); - return this.readLine(); - } - - private CharSequence2 manageDefineLong(Matcher2 m, boolean emptyParentheses) throws IOException { - final String group1 = m.group(1); - final List def = new ArrayList(); - while (true) { - final CharSequence2 read = this.readLine(); - if (read == null) { - return null; - } - if (enddefinelongPattern.matcher(read).find()) { - defines.define(group1, def, emptyParentheses); - return this.readLine(); - } - def.add(read.toString2()); - } - } - - private CharSequence2 manageFilename(Matcher2 m) throws IOException { - final String group1 = m.group(1); - this.defines.overrideFilename(group1); - return this.readLine(); - } - - private CharSequence2 manageDefine(Matcher2 m, boolean emptyParentheses) throws IOException { - final String group1 = m.group(1); - final String group2 = m.group(2); - if (group2 == null) { - defines.define(group1, null, emptyParentheses); - } else { - final List strings = defines.applyDefines(group2); - if (strings.size() > 1) { - defines.define(group1, strings, emptyParentheses); - } else { - final StringBuilder value = new StringBuilder(strings.get(0)); - while (StringUtils.endsWithBackslash(value.toString())) { - value.setLength(value.length() - 1); - final CharSequence2 read = this.readLine(); - value.append(read.toString2()); - } - final List li = new ArrayList(); - li.add(value.toString()); - defines.define(group1, li, emptyParentheses); - } - } - return this.readLine(); - } - public int getLineNumber() { - return rawSource.getLineNumber(); + return include.getLineNumber(); } - public void close() throws IOException { - rawSource.close(); + @Override + void closeInst() throws IOException { + // Log.info("Closing preprocessor of " + description); + include.close(); + subPreprocessor.close(); } public Set getFilesUsed() { - return Collections.unmodifiableSet(rawSource.getFilesUsedGlobal()); + return Collections.unmodifiableSet(include.getFilesUsedGlobal()); } } \ No newline at end of file diff --git a/src/net/sourceforge/plantuml/preproc/PreprocessorDefine.java b/src/net/sourceforge/plantuml/preproc/PreprocessorDefine.java new file mode 100644 index 000000000..13de98495 --- /dev/null +++ b/src/net/sourceforge/plantuml/preproc/PreprocessorDefine.java @@ -0,0 +1,201 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2017, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * 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 + * + * 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.preproc; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import net.sourceforge.plantuml.CharSequence2; +import net.sourceforge.plantuml.CharSequence2Impl; +import net.sourceforge.plantuml.StringUtils; +import net.sourceforge.plantuml.command.regex.Matcher2; +import net.sourceforge.plantuml.command.regex.MyPattern; +import net.sourceforge.plantuml.command.regex.Pattern2; +import net.sourceforge.plantuml.utils.StartUtils; + +public class PreprocessorDefine extends ReadLineInstrumented implements ReadLine { + + private static final String END_DEFINE_LONG = "!enddefinelong"; + private static final String ID = "[A-Za-z_][A-Za-z_0-9]*"; + private static final String ID_ARG = "\\s*[A-Za-z_][A-Za-z_0-9]*\\s*(?:=\\s*(?:\"[^\"]*\"|'[^']*')\\s*)?"; + private static final String ARG = "(?:\\(" + ID_ARG + "(?:," + ID_ARG + ")*?\\))?"; + private static final Pattern2 definePattern = MyPattern.cmpile("^[%s]*!define[%s]+(" + ID + ARG + ")" + + "(?:[%s]+(.*))?$"); + private static final Pattern2 filenamePattern = MyPattern.cmpile("^[%s]*!filename[%s]+(.+)$"); + private static final Pattern2 undefPattern = MyPattern.cmpile("^[%s]*!undef[%s]+(" + ID + ")$"); + private static final Pattern2 definelongPattern = MyPattern.cmpile("^[%s]*!definelong[%s]+(" + ID + ARG + ")"); + private static final Pattern2 enddefinelongPattern = MyPattern.cmpile("^[%s]*" + END_DEFINE_LONG + "[%s]*$"); + + private final Defines defines; + + private final ReadLineInsertable source; + + public PreprocessorDefine(Defines defines, ReadLineInsertable source) { + this.defines = defines; + this.defines.saveState(); + this.source = source; + } + + @Override + CharSequence2 readLineInst() throws IOException { + final CharSequence2 s = source.readLine(); + if (s == null) { + return null; + } + if (StartUtils.isArobaseStartDiagram(s)) { + this.defines.restoreState(); + } + + Matcher2 m = filenamePattern.matcher(s); + if (m.find()) { + return manageFilename(m); + } + m = definePattern.matcher(s); + if (m.find()) { + return manageDefine(m, s.toString().trim().endsWith("()")); + } + + m = definelongPattern.matcher(s); + if (m.find()) { + return manageDefineLong(m, s.toString().trim().endsWith("()")); + } + + m = undefPattern.matcher(s); + if (m.find()) { + return manageUndef(m); + } + + if (ignoreDefineDuringSeveralLines > 0) { + ignoreDefineDuringSeveralLines--; + return s; + } + + List result = defines.applyDefines(s.toString2()); + if (result.size() > 1) { + result = cleanEndDefineLong(result); + final List inserted = cleanEndDefineLong(result.subList(1, result.size())); + ignoreDefineDuringSeveralLines = inserted.size(); + source.insert(inserted, s.getLocation()); + } + return new CharSequence2Impl(result.get(0), s.getLocation(), s.getPreprocessorError()); + } + + private List cleanEndDefineLong(List data) { + final List result = new ArrayList(); + for (String s : data) { + final String clean = cleanEndDefineLong(s); + if (clean != null) { + result.add(clean); + } + } + return result; + + } + + private String cleanEndDefineLong(String s) { + if (s.trim().startsWith(END_DEFINE_LONG)) { + s = s.trim().substring(END_DEFINE_LONG.length()); + if (s.length() == 0) { + return null; + } + } + return s; + } + + private int ignoreDefineDuringSeveralLines = 0; + + private CharSequence2 manageUndef(Matcher2 m) throws IOException { + defines.undefine(m.group(1)); + return this.readLine(); + } + + private CharSequence2 manageDefineLong(Matcher2 m, boolean emptyParentheses) throws IOException { + final String group1 = m.group(1); + final List def = new ArrayList(); + while (true) { + final CharSequence2 read = this.readLine(); + if (read == null) { + return null; + } + if (enddefinelongPattern.matcher(read).find()) { + defines.define(group1, def, emptyParentheses); + return this.readLine(); + } + def.add(read.toString2()); + } + } + + private CharSequence2 manageFilename(Matcher2 m) throws IOException { + final String group1 = m.group(1); + this.defines.overrideFilename(group1); + return this.readLine(); + } + + private CharSequence2 manageDefine(Matcher2 m, boolean emptyParentheses) throws IOException { + final String group1 = m.group(1); + final String group2 = m.group(2); + if (group2 == null) { + defines.define(group1, null, emptyParentheses); + } else { + final List strings = defines.applyDefines(group2); + if (strings.size() > 1) { + defines.define(group1, strings, emptyParentheses); + } else { + final StringBuilder value = new StringBuilder(strings.get(0)); + while (StringUtils.endsWithBackslash(value.toString())) { + value.setLength(value.length() - 1); + final CharSequence2 read = this.readLine(); + value.append(read.toString2()); + } + final List li = new ArrayList(); + li.add(value.toString()); + defines.define(group1, li, emptyParentheses); + } + } + return this.readLine(); + } + +// public int getLineNumber() { +// return source.getLineNumber(); +// } + + @Override + void closeInst() throws IOException { + source.close(); + } + +} \ No newline at end of file diff --git a/src/net/sourceforge/plantuml/preproc/PreprocessorInclude.java b/src/net/sourceforge/plantuml/preproc/PreprocessorInclude.java index 7db9fa46f..bf542c716 100644 --- a/src/net/sourceforge/plantuml/preproc/PreprocessorInclude.java +++ b/src/net/sourceforge/plantuml/preproc/PreprocessorInclude.java @@ -63,7 +63,7 @@ import net.sourceforge.plantuml.command.regex.MyPattern; import net.sourceforge.plantuml.command.regex.Pattern2; import net.sourceforge.plantuml.utils.StartUtils; -public class PreprocessorInclude implements ReadLine { +public class PreprocessorInclude extends ReadLineInstrumented implements ReadLine { private static final Pattern2 includeDefPattern = MyPattern.cmpile("^[%s]*!includedef[%s]+[%g]?([^%g]+)[%g]?$"); private static final Pattern2 includePattern = MyPattern.cmpile("^[%s]*!include[%s]+[%g]?([^%g]+)[%g]?$"); @@ -119,7 +119,8 @@ public class PreprocessorInclude implements ReadLine { } } - public CharSequence2 readLine() throws IOException { + @Override + CharSequence2 readLineInst() throws IOException { final CharSequence2 result = readLineInternal(); if (result != null && StartUtils.isArobaseStartDiagram(result) && config.size() > 0) { final List empty = new ArrayList(); @@ -266,21 +267,13 @@ public class PreprocessorInclude implements ReadLine { } private InputStream getStdlibInputStream(String filename) { - return Stdlib.getResourceAsStream(filename); - } - - private InputStream getStdlibInputStreamOld(String filename) { - if (filename.endsWith(".puml") == false) { - filename = filename + ".puml"; - } - InputStream is = PreprocessorInclude.class.getResourceAsStream("/stdlib/" + filename); - if (is == null) { - is = PreprocessorInclude.class.getResourceAsStream("/stdlib/" + filename.toLowerCase()); - } - return is; + final InputStream result = Stdlib.getResourceAsStream(filename); + // Log.info("Loading sdlib " + filename + " ok"); + return result; } private ReadLine getReaderStdlibInclude(CharSequence2 s, String filename) { + Log.info("Loading sdlib " + filename); InputStream is = getStdlibInputStream(filename); if (is == null) { return null; @@ -295,23 +288,12 @@ public class PreprocessorInclude implements ReadLine { if (is == null) { return null; } - return ReadLineReader.create(new InputStreamReader(is), filename); + return ReadLineReader.create(new InputStreamReader(is), description); } catch (IOException e) { return new ReadLineSimple(s, e.toString()); } } - // private ReadLine getReaderStdlibInclude2(CharSequence2 s, String filename) { - // InputStream is = DummyEmptyStdlibFile.class.getResourceAsStream(filename); - // if (is == null) { - // is = DummyEmptyStdlibFile.class.getResourceAsStream(filename.toLowerCase()); - // } - // if (is == null) { - // return null; - // } - // return new ReadLineReader(new InputStreamReader(is), filename); - // } - private ReadLine getReaderInclude(CharSequence2 s, final File f, String suf) { try { if (StartDiagramExtractReader.containsStartDiagram(s, f, charset)) { @@ -352,7 +334,8 @@ public class PreprocessorInclude implements ReadLine { return numLine; } - public void close() throws IOException { + @Override + void closeInst() throws IOException { restoreCurrentDir(); reader2.close(); } diff --git a/src/net/sourceforge/plantuml/preproc/ReadLineInstrumented.java b/src/net/sourceforge/plantuml/preproc/ReadLineInstrumented.java new file mode 100644 index 000000000..b3c8d472b --- /dev/null +++ b/src/net/sourceforge/plantuml/preproc/ReadLineInstrumented.java @@ -0,0 +1,98 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2017, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * 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 + * + * 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.preproc; + +import java.io.IOException; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicLong; + +import net.sourceforge.plantuml.CharSequence2; +import net.sourceforge.plantuml.Log; + +public abstract class ReadLineInstrumented implements ReadLine { + + private static final boolean TRACE = false; + + private static ConcurrentMap durations = new ConcurrentHashMap(); + private static ConcurrentMap maxes = new ConcurrentHashMap(); + + private long current = 0; + + private AtomicLong get(ConcurrentMap source) { + AtomicLong result = source.get(getClass()); + if (result == null) { + result = new AtomicLong(); + source.put(getClass(), result); + } + return result; + } + + public final CharSequence2 readLine() throws IOException { + if (TRACE == false) { + return readLineInst(); + } + final long now = System.currentTimeMillis(); + try { + return readLineInst(); + } finally { + final long time = System.currentTimeMillis() - now; + current += time; + get(durations).addAndGet(time); + } + } + + @Override + public String toString() { + return super.toString() + " current=" + current; + } + + abstract CharSequence2 readLineInst() throws IOException; + + public final void close() throws IOException { + if (TRACE) { + if (current > get(maxes).get()) { + get(maxes).set(current); + } + Log.info("DURATION::" + getClass() + " duration= " + get(durations).get() + " current=" + current + " max=" + + get(maxes).get()); + } + closeInst(); + } + + abstract void closeInst() throws IOException; + +} \ No newline at end of file diff --git a/src/net/sourceforge/plantuml/preproc/ReadLineQuoteComment.java b/src/net/sourceforge/plantuml/preproc/ReadLineQuoteComment.java index 8fff8b065..60e2979f1 100644 --- a/src/net/sourceforge/plantuml/preproc/ReadLineQuoteComment.java +++ b/src/net/sourceforge/plantuml/preproc/ReadLineQuoteComment.java @@ -40,7 +40,7 @@ import java.io.IOException; import net.sourceforge.plantuml.CharSequence2; import net.sourceforge.plantuml.CharSequence2Impl; -public class ReadLineQuoteComment implements ReadLine { +public class ReadLineQuoteComment extends ReadLineInstrumented implements ReadLine { private final ReadLine raw; private boolean longComment = false; @@ -49,11 +49,13 @@ public class ReadLineQuoteComment implements ReadLine { this.raw = source; } - public void close() throws IOException { + @Override + void closeInst() throws IOException { raw.close(); } - public CharSequence2 readLine() throws IOException { + @Override + CharSequence2 readLineInst() throws IOException { while (true) { final CharSequence2 result = raw.readLine(); if (result == null) { diff --git a/src/net/sourceforge/plantuml/preproc/ReadLineReader.java b/src/net/sourceforge/plantuml/preproc/ReadLineReader.java index 1df3ea5fd..bb73124d0 100644 --- a/src/net/sourceforge/plantuml/preproc/ReadLineReader.java +++ b/src/net/sourceforge/plantuml/preproc/ReadLineReader.java @@ -43,19 +43,28 @@ import net.sourceforge.plantuml.CharSequence2; import net.sourceforge.plantuml.CharSequence2Impl; import net.sourceforge.plantuml.LineLocation; import net.sourceforge.plantuml.LineLocationImpl; +import net.sourceforge.plantuml.Log; -public class ReadLineReader implements ReadLine { +public class ReadLineReader extends ReadLineInstrumented implements ReadLine { // private static final int LIMIT = 850; private final BufferedReader br; private LineLocationImpl location; + private final String description; private ReadLineReader(Reader reader, String description, LineLocation parent) { if (description == null) { description = "?"; } - br = new BufferedReader(reader); - location = new LineLocationImpl(description, parent); + this.br = new BufferedReader(reader); + this.location = new LineLocationImpl(description, parent); + this.description = description; + Log.info("Reading from " + description); + } + + @Override + public String toString() { + return super.toString() + " " + description; } private ReadLineReader(Reader reader, String desc) { @@ -70,7 +79,8 @@ public class ReadLineReader implements ReadLine { return new ReadLineReader(reader, description, parent); } - public CharSequence2 readLine() throws IOException { + @Override + CharSequence2 readLineInst() throws IOException { String s = br.readLine(); location = location.oneLineRead(); if (s == null) { @@ -99,7 +109,8 @@ public class ReadLineReader implements ReadLine { return new CharSequence2Impl(s, location); } - public void close() throws IOException { + @Override + void closeInst() throws IOException { br.close(); } diff --git a/src/net/sourceforge/plantuml/preproc/Stdlib.java b/src/net/sourceforge/plantuml/preproc/Stdlib.java index 99264779d..b29047a22 100644 --- a/src/net/sourceforge/plantuml/preproc/Stdlib.java +++ b/src/net/sourceforge/plantuml/preproc/Stdlib.java @@ -76,9 +76,11 @@ public class Stdlib { if (cached != null) { final String cachedResult = cached.get(); if (cachedResult != null) { + // Log.info("Using cache for " + file); return cachedResult; } } + Log.info("No cache for " + file); final DataInputStream dataStream = getDataStream(); if (dataStream == null) { return null; @@ -94,6 +96,7 @@ public class Stdlib { while (true) { final String filename = dataStream.readUTF(); if (filename.equals(SEPARATOR)) { + Log.info("Not found " + filename); return null; } if (filename.equalsIgnoreCase(file)) { @@ -121,8 +124,10 @@ public class Stdlib { } final int width = Integer.parseInt(m.group(1)); final int height = Integer.parseInt(m.group(2)); - final String sprite = readSprite(width, height, spriteStream); - if (found != null) { + if (found == null) { + skipSprite(width, height, spriteStream); + } else { + final String sprite = readSprite(width, height, spriteStream); found.append(sprite); found.append("}\n"); } @@ -141,9 +146,14 @@ public class Stdlib { fillMap(info); } - private String readSprite(int width, int height, InputStream inputStream) throws IOException { - final StringBuilder result = new StringBuilder(); + private void skipSprite(int width, int height, InputStream inputStream) throws IOException { final int nbLines = (height + 1) / 2; + inputStream.skip(nbLines * width); + } + + private String readSprite(int width, int height, InputStream inputStream) throws IOException { + final int nbLines = (height + 1) / 2; + final StringBuilder result = new StringBuilder(); int line = 0; for (int j = 0; j < nbLines; j++) { final StringBuilder sb1 = new StringBuilder(); diff --git a/src/net/sourceforge/plantuml/preproc/SubPreprocessor.java b/src/net/sourceforge/plantuml/preproc/SubPreprocessor.java index df9209e45..f9030f34f 100644 --- a/src/net/sourceforge/plantuml/preproc/SubPreprocessor.java +++ b/src/net/sourceforge/plantuml/preproc/SubPreprocessor.java @@ -52,7 +52,7 @@ import net.sourceforge.plantuml.command.regex.Matcher2; import net.sourceforge.plantuml.command.regex.MyPattern; import net.sourceforge.plantuml.command.regex.Pattern2; -public class SubPreprocessor implements ReadLine { +public class SubPreprocessor extends ReadLineInstrumented implements ReadLine { private static final String ID = "[A-Za-z_][A-Za-z_0-9]*"; @@ -79,7 +79,8 @@ public class SubPreprocessor implements ReadLine { this.definitionsContainer = definitionsContainer; } - public CharSequence2 readLine() throws IOException { + @Override + CharSequence2 readLineInst() throws IOException { if (includedSub != null) { final CharSequence2 s = includedSub.readLine(); if (s != null) { @@ -176,7 +177,8 @@ public class SubPreprocessor implements ReadLine { return result; } - public void close() throws IOException { + @Override + void closeInst() throws IOException { source.close(); } diff --git a/src/net/sourceforge/plantuml/preproc/UncommentReadLine.java b/src/net/sourceforge/plantuml/preproc/UncommentReadLine.java index 1b03651e1..a8f1b73b5 100644 --- a/src/net/sourceforge/plantuml/preproc/UncommentReadLine.java +++ b/src/net/sourceforge/plantuml/preproc/UncommentReadLine.java @@ -44,21 +44,27 @@ import net.sourceforge.plantuml.command.regex.MyPattern; import net.sourceforge.plantuml.command.regex.Pattern2; import net.sourceforge.plantuml.utils.StartUtils; -public class UncommentReadLine implements ReadLine { +public class UncommentReadLine extends ReadLineInstrumented implements ReadLine { + + private static final Pattern2 unpause = MyPattern.cmpile(StartUtils.PAUSE_PATTERN); private final ReadLine raw; - private final Pattern2 start; - private final Pattern2 unpause; + // private final Pattern2 start; private String headerToRemove; private boolean paused; public UncommentReadLine(ReadLine source) { this.raw = source; - this.start = MyPattern.cmpile(StartUtils.START_PATTERN); - this.unpause = MyPattern.cmpile(StartUtils.PAUSE_PATTERN); + // this.start = MyPattern.cmpile(StartUtils.START_PATTERN); } - public CharSequence2 readLine() throws IOException { + @Override + public String toString() { + return "UncommentReadLine of " + raw; + } + + @Override + CharSequence2 readLineInst() throws IOException { final CharSequence2 result = raw.readLine(); if (result == null) { @@ -88,7 +94,8 @@ public class UncommentReadLine implements ReadLine { return result; } - public void close() throws IOException { + @Override + void closeInst() throws IOException { this.raw.close(); } diff --git a/src/net/sourceforge/plantuml/preproc/Variables.java b/src/net/sourceforge/plantuml/preproc/Variables.java index d916c57cc..19442ac05 100644 --- a/src/net/sourceforge/plantuml/preproc/Variables.java +++ b/src/net/sourceforge/plantuml/preproc/Variables.java @@ -38,10 +38,18 @@ package net.sourceforge.plantuml.preproc; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; +import java.util.regex.Pattern; public class Variables { private final List all = new ArrayList(); + private final String fonctionName; + private final String definitionQuoted; + + public Variables(String fonctionName, String definitionQuoted) { + this.fonctionName = fonctionName; + this.definitionQuoted = definitionQuoted; + } public void add(DefineVariable var) { this.all.add(var); @@ -61,7 +69,7 @@ public class Variables { if (nb == 0) { return this; } - final Variables result = new Variables(); + final Variables result = new Variables(fonctionName, definitionQuoted); for (DefineVariable v : all) { if (v.getDefaultValue() != null && nb > 0) { result.add(v.removeDefault()); @@ -76,36 +84,39 @@ public class Variables { return result; } - public String applyOn(String line, String fonctionName, String newValue) { - // System.err.println("KEY="+key); - // final StringTokenizer st = new StringTokenizer(key, "(),"); - // final String fctName = st.nextToken(); - final StringBuilder regex = new StringBuilder("\\b" + fonctionName + "\\("); + private String newValue; + private Pattern regex2; - final List variables = all; - boolean appended = false; - for (int j = 0; j < variables.size(); j++) { - final DefineVariable variable = variables.get(j); - final String varName = variable.getName(); - final String var2 = "(##" + varName + "\\b)|(\\b" + varName + "##)|(\\b" + varName + "\\b)"; - if (variable.getDefaultValue() == null) { - regex.append("(?:(?:\\s*\"([^\"]*)\"\\s*)|(?:\\s*'([^']*)'\\s*)|\\s*" + "((?:\\([^()]*\\)|[^,'\"])*?)" - + ")"); - final int i = 1 + 3 * j; - newValue = newValue.replaceAll(var2, "\\$" + i + "\\$" + (i + 1) + "\\$" + (i + 2)); - regex.append(","); - appended = true; - } else { - newValue = newValue.replaceAll(var2, Matcher.quoteReplacement(variable.getDefaultValue())); + public String applyOn(String line) { + if (newValue == null) { + newValue = definitionQuoted; + final StringBuilder regex = new StringBuilder("\\b" + fonctionName + "\\("); + + final List variables = all; + boolean appended = false; + for (int j = 0; j < variables.size(); j++) { + final DefineVariable variable = variables.get(j); + final String varName = variable.getName(); + final String var2 = "(##" + varName + "\\b)|(\\b" + varName + "##)|(\\b" + varName + "\\b)"; + if (variable.getDefaultValue() == null) { + regex.append("(?:(?:\\s*\"([^\"]*)\"\\s*)|(?:\\s*'([^']*)'\\s*)|\\s*" + + "((?:\\([^()]*\\)|[^,'\"])*?)" + ")"); + final int i = 1 + 3 * j; + newValue = newValue.replaceAll(var2, "\\$" + i + "\\$" + (i + 1) + "\\$" + (i + 2)); + regex.append(","); + appended = true; + } else { + newValue = newValue.replaceAll(var2, Matcher.quoteReplacement(variable.getDefaultValue())); + } } + if (appended == true) { + regex.setLength(regex.length() - 1); + } + regex.append("\\)"); + regex2 = Pattern.compile(regex.toString()); } - if (appended == true) { - regex.setLength(regex.length() - 1); - } - regex.append("\\)"); - // System.err.println("regex=" + regex); - // System.err.println("newValue=" + newValue); - line = line.replaceAll(regex.toString(), newValue); + // line = line.replaceAll(regex.toString(), newValue); + line = regex2.matcher(line).replaceAll(newValue); return line; } diff --git a/src/net/sourceforge/plantuml/project3/SubjectTask.java b/src/net/sourceforge/plantuml/project3/SubjectTask.java index 84b565f3f..21632dfd1 100644 --- a/src/net/sourceforge/plantuml/project3/SubjectTask.java +++ b/src/net/sourceforge/plantuml/project3/SubjectTask.java @@ -48,7 +48,7 @@ public class SubjectTask implements SubjectPattern { public Collection getVerbs() { return Arrays. asList(new VerbLasts(), new VerbTaskStarts(), new VerbTaskStartsAbsolute(), - new VerbHappens(), new VerbEnds(), new VerbIsColored()); + new VerbHappens(), new VerbEnds(), new VerbTaskEndsAbsolute(), new VerbIsColored()); } public IRegex toRegex() { diff --git a/src/net/sourceforge/plantuml/project3/VerbTaskEndsAbsolute.java b/src/net/sourceforge/plantuml/project3/VerbTaskEndsAbsolute.java new file mode 100644 index 000000000..b0f7cf466 --- /dev/null +++ b/src/net/sourceforge/plantuml/project3/VerbTaskEndsAbsolute.java @@ -0,0 +1,71 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2017, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * 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 + * + * 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.project3; + +import java.util.Arrays; +import java.util.Collection; + +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.command.regex.IRegex; +import net.sourceforge.plantuml.command.regex.RegexLeaf; +import net.sourceforge.plantuml.command.regex.RegexResult; + +public class VerbTaskEndsAbsolute implements VerbPattern { + + public Collection getComplements() { + return Arrays. asList(new ComplementDate()); + } + + public IRegex toRegex() { + return new RegexLeaf("ends[%s]*(the[%s]*|on[%s]*|at[%s]*)*"); + } + + public Verb getVerb(final GanttDiagram project, RegexResult arg) { + return new Verb() { + public CommandExecutionResult execute(Subject subject, Complement complement) { + final Task task = (Task) subject; + final DayAsDate end = (DayAsDate) complement; + final DayAsDate startingDate = project.getStartingDate(); + if (startingDate == null) { + return CommandExecutionResult.error("No starting date for the project"); + } + task.setEnd(end.asInstantDay(startingDate)); + return CommandExecutionResult.ok(); + } + + }; + } +} diff --git a/src/net/sourceforge/plantuml/salt/PSystemSalt.java b/src/net/sourceforge/plantuml/salt/PSystemSalt.java index fb8e697ad..f0ef2a5ea 100644 --- a/src/net/sourceforge/plantuml/salt/PSystemSalt.java +++ b/src/net/sourceforge/plantuml/salt/PSystemSalt.java @@ -47,6 +47,7 @@ import net.sourceforge.plantuml.AbstractPSystem; import net.sourceforge.plantuml.Dimension2DDouble; import net.sourceforge.plantuml.FileFormatOption; import net.sourceforge.plantuml.Log; +import net.sourceforge.plantuml.ScaleSimple; import net.sourceforge.plantuml.UmlDiagram; import net.sourceforge.plantuml.WithSprite; import net.sourceforge.plantuml.api.ImageDataSimple; @@ -108,7 +109,12 @@ public class PSystemSalt extends AbstractPSystem implements WithSprite { final Element salt = createElement(manageSprite()); final Dimension2D size = salt.getPreferredDimension(fileFormat.getDefaultStringBounder(), 0, 0); - final ImageBuilder builder = new ImageBuilder(new ColorMapperIdentity(), 1.0, HtmlColorUtils.WHITE, null, + + double scale = 1; + if (getScale() != null) { + scale = getScale().getScale(size.getWidth(), size.getHeight()); + } + final ImageBuilder builder = new ImageBuilder(new ColorMapperIdentity(), scale, HtmlColorUtils.WHITE, null, null, 5, 5, null, false); builder.setUDrawable(new UDrawable() { @@ -146,6 +152,10 @@ public class PSystemSalt extends AbstractPSystem implements WithSprite { // System.err.println("skipping " + s); } else if (s.startsWith("skinparam ")) { // System.err.println("skipping " + s); + } else if (s.startsWith("scale ")) { + final Double scale = Double.parseDouble(s.substring("scale ".length())); + this.setScale(new ScaleSimple(scale)); + // System.err.println("skipping " + s); } else if (s.startsWith("sprite $")) { BlocLines bloc = BlocLines.single(s); do { diff --git a/src/net/sourceforge/plantuml/sequencediagram/SequenceDiagram.java b/src/net/sourceforge/plantuml/sequencediagram/SequenceDiagram.java index b11a1ffac..94d847a61 100644 --- a/src/net/sourceforge/plantuml/sequencediagram/SequenceDiagram.java +++ b/src/net/sourceforge/plantuml/sequencediagram/SequenceDiagram.java @@ -280,7 +280,10 @@ public class SequenceDiagram extends UmlDiagram { p.incInitialLife(new SymbolContext(backcolor, linecolor)); return null; } - return "Only activate command can occur before message are send"; + if (p.getInitialLife() == 0) { + return "You cannot deactivate here"; + } + return null; } if (lifeEventType == LifeEventType.ACTIVATE && lastEventWithDeactivate instanceof Message) { activationState.push((Message) lastEventWithDeactivate); diff --git a/src/net/sourceforge/plantuml/sequencediagram/graphic/SequenceDiagramTxtMaker.java b/src/net/sourceforge/plantuml/sequencediagram/graphic/SequenceDiagramTxtMaker.java index f7ac12c9b..cc9b55c89 100644 --- a/src/net/sourceforge/plantuml/sequencediagram/graphic/SequenceDiagramTxtMaker.java +++ b/src/net/sourceforge/plantuml/sequencediagram/graphic/SequenceDiagramTxtMaker.java @@ -41,15 +41,19 @@ import java.io.OutputStream; import java.io.PrintStream; import net.sourceforge.plantuml.FileFormat; +import net.sourceforge.plantuml.StringUtils; import net.sourceforge.plantuml.api.ImageDataSimple; import net.sourceforge.plantuml.asciiart.TextSkin; import net.sourceforge.plantuml.asciiart.TextStringBounder; +import net.sourceforge.plantuml.asciiart.UmlCharArea; import net.sourceforge.plantuml.core.ImageData; +import net.sourceforge.plantuml.cucadiagram.Display; import net.sourceforge.plantuml.graphic.StringBounder; import net.sourceforge.plantuml.sequencediagram.Event; import net.sourceforge.plantuml.sequencediagram.Participant; import net.sourceforge.plantuml.sequencediagram.SequenceDiagram; import net.sourceforge.plantuml.skin.Skin; +import net.sourceforge.plantuml.ugraphic.UTranslate; import net.sourceforge.plantuml.ugraphic.txt.UGraphicTxt; public class SequenceDiagramTxtMaker implements FileMaker { @@ -75,18 +79,18 @@ public class SequenceDiagramTxtMaker implements FileMaker { } for (Event ev : sequenceDiagram.events()) { initializer.addEvent(ev); -// if (ev instanceof Message) { -// // TODO mieux faire -// final Message m = (Message) ev; -// for (LifeEvent lifeEvent : m.getLiveEvents()) { -// if (lifeEvent.getType() == LifeEventType.DESTROY -// /* -// * || lifeEvent.getType() == LifeEventType.CREATE -// */) { -// initializer.addEvent(lifeEvent); -// } -// } -// } + // if (ev instanceof Message) { + // // TODO mieux faire + // final Message m = (Message) ev; + // for (LifeEvent lifeEvent : m.getLiveEvents()) { + // if (lifeEvent.getType() == LifeEventType.DESTROY + // /* + // * || lifeEvent.getType() == LifeEventType.CREATE + // */) { + // initializer.addEvent(lifeEvent); + // } + // } + // } } drawableSet = initializer.createDrawableSet(dummyStringBounder); // final List newpages = new ArrayList(); @@ -100,10 +104,24 @@ public class SequenceDiagramTxtMaker implements FileMaker { final double tailHeight = drawableSet.getTailHeight(dummyStringBounder, diagram.isShowFootbox()); final double newpage2 = fullDimension.getHeight() - (diagram.isShowFootbox() ? tailHeight : 0) - headerHeight; final Page page = new Page(headerHeight, 0, newpage2, tailHeight, 0, null); - //drawableSet.drawU_REMOVEDME_4243(ug, 0, fullDimension.getWidth(), page, diagram.isShowFootbox()); - drawableSet.drawU22(ug, 0, fullDimension.getWidth(), page, diagram.isShowFootbox()); - } + // drawableSet.drawU_REMOVEDME_4243(ug, 0, fullDimension.getWidth(), page, diagram.isShowFootbox()); + final Display title = diagram.getTitle().getDisplay(); + + final UGraphicTxt ug2; + if (title.isWhite()) { + ug2 = ug; + } else { + ug2 = (UGraphicTxt) ug.apply(new UTranslate(0, title.as().size() + 1)); + } + drawableSet.drawU22(ug2, 0, fullDimension.getWidth(), page, diagram.isShowFootbox()); + if (title.isWhite() == false) { + final int widthTitle = StringUtils.getWcWidth(title); + final UmlCharArea charArea = ug.getCharArea(); + charArea.drawStringsLR(title.as(), (int) ((fullDimension.getWidth() - widthTitle) / 2), 0); + } + + } public ImageData createOne(OutputStream os, int index, boolean isWithMetadata) throws IOException { if (fileFormat == FileFormat.UTXT) { diff --git a/src/net/sourceforge/plantuml/sequencediagram/teoz/LifeEventTile.java b/src/net/sourceforge/plantuml/sequencediagram/teoz/LifeEventTile.java index 68f18dcb2..a7428a5fb 100644 --- a/src/net/sourceforge/plantuml/sequencediagram/teoz/LifeEventTile.java +++ b/src/net/sourceforge/plantuml/sequencediagram/teoz/LifeEventTile.java @@ -60,7 +60,7 @@ public class LifeEventTile implements TileWithUpdateStairs { private final ISkinParam skinParam; public void updateStairs(StringBounder stringBounder, double y) { - System.err.println("LifeEventTile::updateStairs " + lifeEvent + " " + livingSpace.getParticipant() + " y=" + y); + // System.err.println("LifeEventTile::updateStairs " + lifeEvent + " " + livingSpace.getParticipant() + " y=" + y); livingSpace.addStepForLivebox(getEvent(), y); } diff --git a/src/net/sourceforge/plantuml/sequencediagram/teoz/SequenceDiagramFileMakerTeoz.java b/src/net/sourceforge/plantuml/sequencediagram/teoz/SequenceDiagramFileMakerTeoz.java index 67e5115ab..b3edc6766 100644 --- a/src/net/sourceforge/plantuml/sequencediagram/teoz/SequenceDiagramFileMakerTeoz.java +++ b/src/net/sourceforge/plantuml/sequencediagram/teoz/SequenceDiagramFileMakerTeoz.java @@ -148,8 +148,9 @@ public class SequenceDiagramFileMakerTeoz implements FileMaker { public void drawU(UGraphic ug) { ug = ug.apply(min1translate); - englobers.drawEnglobers(goDownForEnglobers(ug), main.calculateDimension(stringBounder).getHeight() - + heightEnglober1 + heightEnglober2 / 2, new SimpleContext2D(true)); + + englobers.drawEnglobers(goDownAndCenterForEnglobers(ug), main.calculateDimension(stringBounder) + .getHeight() + heightEnglober1 + heightEnglober2 / 2, new SimpleContext2D(true)); printAligned(ug, diagram.getFooterOrHeaderTeoz(FontParam.HEADER).getHorizontalAlignment(), header); ug = goDown(ug, header); @@ -182,13 +183,14 @@ public class SequenceDiagramFileMakerTeoz implements FileMaker { } - private UGraphic goDownForEnglobers(UGraphic ug) { + private UGraphic goDownAndCenterForEnglobers(UGraphic ug) { ug = goDown(ug, title); ug = goDown(ug, header); if (diagram.getLegend().getVerticalAlignment() == VerticalAlignment.TOP) { ug = goDown(ug, legend); } - return ug; + final double dx = (dimTotal.getWidth() - main.calculateDimension(stringBounder).getWidth()) / 2; + return ug.apply(new UTranslate(dx, 0)); } private UGraphic goDown(UGraphic ug, TextBlock size) { diff --git a/src/net/sourceforge/plantuml/skin/AbstractTextualComponent.java b/src/net/sourceforge/plantuml/skin/AbstractTextualComponent.java index 741142705..bf7c6f5ff 100644 --- a/src/net/sourceforge/plantuml/skin/AbstractTextualComponent.java +++ b/src/net/sourceforge/plantuml/skin/AbstractTextualComponent.java @@ -84,7 +84,7 @@ public abstract class AbstractTextualComponent extends AbstractComponent { if (strings.size() == 1 && strings.get(0).length() == 0) { textBlock = new TextBlockEmpty(); } else if (enhanced) { - textBlock = new BodyEnhanced2(strings, FontParam.NOTE, spriteContainer, HorizontalAlignment.LEFT, font, + textBlock = new BodyEnhanced2(strings, FontParam.NOTE, spriteContainer, horizontalAlignment, font, maxMessageSize); } else { textBlock = strings.create(font, horizontalAlignment, spriteContainer, maxMessageSize, CreoleMode.FULL, diff --git a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseNote.java b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseNote.java index c1aa2d71d..f9bf9f47d 100644 --- a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseNote.java +++ b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseNote.java @@ -60,9 +60,9 @@ final public class ComponentRoseNote extends AbstractTextualComponent implements private final double roundCorner; public ComponentRoseNote(SymbolContext symbolContext, FontConfiguration font, Display strings, double paddingX, - double paddingY, ISkinSimple spriteContainer, double roundCorner) { - super(LineBreakStrategy.NONE, strings, font, HorizontalAlignment.LEFT, 6, 15, 5, spriteContainer, true, null, - null); + double paddingY, ISkinSimple spriteContainer, double roundCorner, HorizontalAlignment horizontalAlignment) { + super(LineBreakStrategy.NONE, strings, font, horizontalAlignment, + horizontalAlignment == HorizontalAlignment.CENTER ? 15 : 6, 15, 5, spriteContainer, true, null, null); this.roundCorner = roundCorner; this.paddingX = paddingX; this.paddingY = paddingY; diff --git a/src/net/sourceforge/plantuml/skin/rose/Rose.java b/src/net/sourceforge/plantuml/skin/rose/Rose.java index dcdcc680a..784aa1873 100644 --- a/src/net/sourceforge/plantuml/skin/rose/Rose.java +++ b/src/net/sourceforge/plantuml/skin/rose/Rose.java @@ -35,7 +35,7 @@ */ package net.sourceforge.plantuml.skin.rose; -import net.sourceforge.plantuml.AlignParam; +import net.sourceforge.plantuml.AlignmentParam; import net.sourceforge.plantuml.ColorParam; import net.sourceforge.plantuml.FontParam; import net.sourceforge.plantuml.ISkinParam; @@ -100,9 +100,9 @@ public class Rose implements Skin { config, param, param.maxMessageSize(), param.strictUmlStyle() == false); } final HorizontalAlignment messageHorizontalAlignment = param.getHorizontalAlignment( - AlignParam.SEQUENCE_MESSAGE_ALIGN, config.getArrowDirection()); + AlignmentParam.sequenceMessageAlignment, config.getArrowDirection()); final HorizontalAlignment textHorizontalAlignment = param.getHorizontalAlignment( - AlignParam.SEQUENCE_MESSAGETEXT_ALIGN, config.getArrowDirection()); + AlignmentParam.sequenceMessageTextAlignment, config.getArrowDirection()); return new ComponentRoseArrow(sequenceArrow, getUFont2(param, FontParam.ARROW), stringsToDisplay, config, messageHorizontalAlignment, param, textHorizontalAlignment, param.maxMessageSize(), param.strictUmlStyle() == false, param.responseMessageBelowArrow()); @@ -198,8 +198,9 @@ public class Rose implements Skin { FontParam.DATABASE_STEREOTYPE)); } if (type == ComponentType.NOTE) { + final HorizontalAlignment alignment = param.getHorizontalAlignment(AlignmentParam.noteTextAlignment, null); return new ComponentRoseNote(getSymbolContext(param, ColorParam.noteBorder), getUFont2(param, - FontParam.NOTE), stringsToDisplay, paddingX, paddingY, param, roundCorner); + FontParam.NOTE), stringsToDisplay, paddingX, paddingY, param, roundCorner, alignment); } if (type == ComponentType.NOTE_HEXAGONAL) { return new ComponentRoseNoteHexagonal(getSymbolContext(param, ColorParam.noteBorder), getUFont2(param, @@ -258,7 +259,7 @@ public class Rose implements Skin { if (type == ComponentType.REFERENCE) { return new ComponentRoseReference(getUFont2(param, FontParam.SEQUENCE_REFERENCE), getSymbolContext(param, ColorParam.sequenceReferenceBorder), bigFont, stringsToDisplay, param.getHorizontalAlignment( - AlignParam.SEQUENCE_REFERENCE_ALIGN, null), param, getHtmlColor(param, + AlignmentParam.sequenceReferenceAlignment, null), param, getHtmlColor(param, ColorParam.sequenceReferenceBackground)); } // if (type == ComponentType.TITLE) { diff --git a/src/net/sourceforge/plantuml/svek/Cluster.java b/src/net/sourceforge/plantuml/svek/Cluster.java index 00d9cfa8d..f1c2d99de 100644 --- a/src/net/sourceforge/plantuml/svek/Cluster.java +++ b/src/net/sourceforge/plantuml/svek/Cluster.java @@ -48,7 +48,7 @@ import java.util.List; import java.util.Map; import java.util.Set; -import net.sourceforge.plantuml.AlignParam; +import net.sourceforge.plantuml.AlignmentParam; import net.sourceforge.plantuml.ColorParam; import net.sourceforge.plantuml.Dimension2DDouble; import net.sourceforge.plantuml.FontParam; @@ -365,7 +365,7 @@ public class Cluster implements Moveable { final ClusterDecoration decoration = new ClusterDecoration(style, group.getUSymbol(), ztitle, zstereo, minX, minY, maxX, maxY, stroke2); decoration.drawU(ug, back, borderColor, shadowing, roundCorner, - skinParam2.getHorizontalAlignment(AlignParam.PACKAGE_TITLE_ALIGNMENT, null)); + skinParam2.getHorizontalAlignment(AlignmentParam.packageTitleAlignment, null)); return; } final URectangle rect = new URectangle(maxX - minX, maxY - minY); @@ -742,7 +742,7 @@ public class Cluster implements Moveable { sblabel.append(">"); label = sblabel.toString(); final HorizontalAlignment align = skinParam - .getHorizontalAlignment(AlignParam.PACKAGE_TITLE_ALIGNMENT, null); + .getHorizontalAlignment(AlignmentParam.packageTitleAlignment, null); sb.append("labeljust=\"" + align.getGraphVizValue() + "\";"); } else { label = "\"\""; diff --git a/src/net/sourceforge/plantuml/svek/GraphvizCrash.java b/src/net/sourceforge/plantuml/svek/GraphvizCrash.java index 7a82d6555..f7ea9c96e 100644 --- a/src/net/sourceforge/plantuml/svek/GraphvizCrash.java +++ b/src/net/sourceforge/plantuml/svek/GraphvizCrash.java @@ -184,7 +184,7 @@ public class GraphvizCrash extends AbstractTextBlock implements IEntityImage { if (flashCode != null) { final double h = graphicStrings.calculateDimension(ug.getStringBounder()).getHeight(); ug = ug.apply(new UTranslate(0, h)); - ug.draw(new UImage(flashCode)); + ug.draw(new UImage(flashCode).scaleNearestNeighbor(3)); } } diff --git a/src/net/sourceforge/plantuml/svek/UGraphicForSnake.java b/src/net/sourceforge/plantuml/svek/UGraphicForSnake.java index bfd74f055..fe4382279 100644 --- a/src/net/sourceforge/plantuml/svek/UGraphicForSnake.java +++ b/src/net/sourceforge/plantuml/svek/UGraphicForSnake.java @@ -51,6 +51,11 @@ public class UGraphicForSnake extends UGraphicDelegator { private final double dy; private final List snakes; + @Override + public String toString() { + return super.toString() + " " + getUg(); + } + public UTranslate getTranslation() { return new UTranslate(dx, dy); } diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageEmptyPackage.java b/src/net/sourceforge/plantuml/svek/image/EntityImageEmptyPackage.java index d12cbe85f..3d86ef8ea 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageEmptyPackage.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageEmptyPackage.java @@ -37,7 +37,7 @@ package net.sourceforge.plantuml.svek.image; import java.awt.geom.Dimension2D; -import net.sourceforge.plantuml.AlignParam; +import net.sourceforge.plantuml.AlignmentParam; import net.sourceforge.plantuml.ColorParam; import net.sourceforge.plantuml.Dimension2DDouble; import net.sourceforge.plantuml.FontParam; @@ -130,7 +130,7 @@ public class EntityImageEmptyPackage extends AbstractEntityImage { decoration.drawU(ug, back, SkinParamUtils.getColor(getSkinParam(), ColorParam.packageBorder, getStereo()), getSkinParam().shadowing(), roundCorner, - getSkinParam().getHorizontalAlignment(AlignParam.PACKAGE_TITLE_ALIGNMENT, null)); + getSkinParam().getHorizontalAlignment(AlignmentParam.packageTitleAlignment, null)); if (url != null) { ug.closeAction(); diff --git a/src/net/sourceforge/plantuml/svg/SvgGraphics.java b/src/net/sourceforge/plantuml/svg/SvgGraphics.java index d3bfcc464..6005be725 100644 --- a/src/net/sourceforge/plantuml/svg/SvgGraphics.java +++ b/src/net/sourceforge/plantuml/svg/SvgGraphics.java @@ -743,11 +743,11 @@ public class SvgGraphics { private String manageScale(SvgString svg) { final double svgScale = svg.getScale(); if (svgScale * scale == 1) { - return svg.getSvg(); + return svg.getSvg(false); } final String s1 = "\\ preproc = new TreeSet(); public LanguageDescriptor() { - + type.add("actor"); type.add("participant"); type.add("usecase"); @@ -165,6 +166,26 @@ public class LanguageDescriptor { preproc.add("!enddefinelong"); } + public Cypher getCypher() { + final Cypher cypher = new Cypher(); + for (String s : type) { + cypher.addException(s); + } + for (String s : keyword) { + cypher.addException(s.replace("@", "")); + } + for (String s : preproc) { + cypher.addException(s.substring(1)); + } + for (String s : SkinParam.getPossibleValues()) { + cypher.addException(s); + } + for (String s : new HtmlColorSetSimple().names()) { + cypher.addException(s); + } + return cypher; + } + public void print(PrintStream ps) { print(ps, "type", type); print(ps, "keyword", keyword); @@ -175,7 +196,7 @@ public class LanguageDescriptor { } private static void print(PrintStream ps, String name, Collection data) { - ps.println(";"+name); + ps.println(";" + name); ps.println(";" + data.size()); for (String k : data) { ps.println(k); diff --git a/src/net/sourceforge/plantuml/ugraphic/FontChecker.java b/src/net/sourceforge/plantuml/ugraphic/FontChecker.java index 4e0ee26d1..68a6d7d1b 100644 --- a/src/net/sourceforge/plantuml/ugraphic/FontChecker.java +++ b/src/net/sourceforge/plantuml/ugraphic/FontChecker.java @@ -48,7 +48,6 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.Arrays; import java.util.HashSet; -import java.util.Random; import java.util.Set; import javax.imageio.ImageIO; diff --git a/src/net/sourceforge/plantuml/ugraphic/ImageBuilder.java b/src/net/sourceforge/plantuml/ugraphic/ImageBuilder.java index 5b2ceebfd..e0ee57a9c 100644 --- a/src/net/sourceforge/plantuml/ugraphic/ImageBuilder.java +++ b/src/net/sourceforge/plantuml/ugraphic/ImageBuilder.java @@ -55,6 +55,7 @@ import javax.swing.ImageIcon; import net.sourceforge.plantuml.AnimatedGifEncoder; import net.sourceforge.plantuml.CMapData; import net.sourceforge.plantuml.ColorParam; +import net.sourceforge.plantuml.CornerParam; import net.sourceforge.plantuml.Dimension2DDouble; import net.sourceforge.plantuml.EmptyImageBuilder; import net.sourceforge.plantuml.FileFormat; @@ -63,7 +64,6 @@ import net.sourceforge.plantuml.FileUtils; import net.sourceforge.plantuml.ISkinParam; import net.sourceforge.plantuml.LineParam; import net.sourceforge.plantuml.OptionFlags; -import net.sourceforge.plantuml.CornerParam; import net.sourceforge.plantuml.StringUtils; import net.sourceforge.plantuml.Url; import net.sourceforge.plantuml.anim.AffineTransformation; diff --git a/src/net/sourceforge/plantuml/ugraphic/SlotFinderX.java b/src/net/sourceforge/plantuml/ugraphic/SlotFinderX.java deleted file mode 100644 index 0c3aabfba..000000000 --- a/src/net/sourceforge/plantuml/ugraphic/SlotFinderX.java +++ /dev/null @@ -1,156 +0,0 @@ -/* ======================================================================== - * PlantUML : a free UML diagram generator - * ======================================================================== - * - * (C) Copyright 2009-2017, Arnaud Roques - * - * Project Info: http://plantuml.com - * - * 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 - * - * 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.ugraphic; - -import net.sourceforge.plantuml.Url; -import net.sourceforge.plantuml.graphic.StringBounder; - -public class SlotFinderX implements UGraphic { - - public boolean matchesProperty(String propertyName) { - return false; - } - - public double dpiFactor() { - return 1; - } - - public UGraphic apply(UChange change) { - if (change instanceof UTranslate) { - return new SlotFinderX(stringBounder, xslot, yslot, translate.compose((UTranslate) change)); - } else if (change instanceof UStroke) { - return new SlotFinderX(this); - } else if (change instanceof UChangeBackColor) { - return new SlotFinderX(this); - } else if (change instanceof UChangeColor) { - return new SlotFinderX(this); - } - throw new UnsupportedOperationException(); - } - - private final SlotSet xslot; - private final SlotSet yslot; - private final StringBounder stringBounder; - private final UTranslate translate; - - public SlotFinderX(StringBounder stringBounder) { - this(stringBounder, new SlotSet(), new SlotSet(), new UTranslate()); - } - - private SlotFinderX(StringBounder stringBounder, SlotSet xslot, SlotSet yslot, UTranslate translate) { - this.stringBounder = stringBounder; - this.xslot = xslot; - this.yslot = yslot; - this.translate = translate; - } - - private SlotFinderX(SlotFinderX other) { - this(other.stringBounder, other.xslot, other.yslot, other.translate); - } - - public StringBounder getStringBounder() { - return stringBounder; - } - - public UParam getParam() { - return new UParamNull(); - } - - public void draw(UShape shape) { - final double x = translate.getDx(); - final double y = translate.getDy(); - if (shape instanceof URectangle) { - drawRectangle(x, y, (URectangle) shape); - } else if (shape instanceof UPolygon) { - drawPolygon(x, y, (UPolygon) shape); - } else if (shape instanceof UEllipse) { - drawEllipse(x, y, (UEllipse) shape); - } else if (shape instanceof UText) { - drawText(x, y, (UText) shape); - } else if (shape instanceof UEmpty) { - drawEmpty(x, y, (UEmpty) shape); - } - } - - private void drawEmpty(double x, double y, UEmpty shape) { - xslot.addSlot(x, x + shape.getWidth()); - yslot.addSlot(y, y + shape.getHeight()); - } - - private void drawText(double x, double y, UText shape) { - final TextLimitFinder finder = new TextLimitFinder(stringBounder, false); - finder.apply(new UTranslate(x, y)).draw(shape); - xslot.addSlot(finder.getMinX(), finder.getMaxX()); - yslot.addSlot(finder.getMinY(), finder.getMaxY()); - } - - private void drawEllipse(double x, double y, UEllipse shape) { - xslot.addSlot(x, x + shape.getWidth()); - yslot.addSlot(y, y + shape.getHeight()); - } - - private void drawPolygon(double x, double y, UPolygon shape) { - xslot.addSlot(x + shape.getMinX(), x + shape.getMaxX()); - yslot.addSlot(y + shape.getMinY(), y + shape.getMaxY()); - } - - private void drawRectangle(double x, double y, URectangle shape) { - xslot.addSlot(x, x + shape.getWidth()); - yslot.addSlot(y, y + shape.getHeight()); - } - - public ColorMapper getColorMapper() { - return new ColorMapperIdentity(); - } - - public void startUrl(Url url) { - } - - public void closeAction() { - } - - public SlotSet getXSlotSet() { - return xslot; - } - - public SlotSet getYSlotSet() { - return yslot; - } - - public void flushUg() { - } - -} diff --git a/src/net/sourceforge/plantuml/ugraphic/UGraphicCompress2.java b/src/net/sourceforge/plantuml/ugraphic/UGraphicCompress2.java deleted file mode 100644 index e670639c1..000000000 --- a/src/net/sourceforge/plantuml/ugraphic/UGraphicCompress2.java +++ /dev/null @@ -1,98 +0,0 @@ -/* ======================================================================== - * PlantUML : a free UML diagram generator - * ======================================================================== - * - * (C) Copyright 2009-2017, Arnaud Roques - * - * Project Info: http://plantuml.com - * - * 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 - * - * 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.ugraphic; - -import net.sourceforge.plantuml.activitydiagram3.ftile.Snake; -import net.sourceforge.plantuml.graphic.UGraphicDelegator; - -public class UGraphicCompress2 extends UGraphicDelegator { - - public UGraphic apply(UChange change) { - if (change instanceof UTranslate) { - return new UGraphicCompress2(getUg(), compressionTransform, translate.compose((UTranslate) change)); - } else if (change instanceof UStroke || change instanceof UChangeBackColor || change instanceof UChangeColor) { - return new UGraphicCompress2(getUg().apply(change), compressionTransform, translate); - } - throw new UnsupportedOperationException(); - } - - private final CompressionTransform compressionTransform; - private final UTranslate translate; - - public UGraphicCompress2(UGraphic ug, CompressionTransform compressionTransform) { - this(ug, compressionTransform, new UTranslate()); - } - - private UGraphicCompress2(UGraphic ug, CompressionTransform compressionTransform, UTranslate translate) { - super(ug); - this.compressionTransform = compressionTransform; - this.translate = translate; - } - - public void draw(UShape shape) { - final double x = translate.getDx(); - final double y = translate.getDy(); - if (shape instanceof ULine) { - drawLine(x, y, (ULine) shape); - } else if (shape instanceof Snake) { - drawSnake(x, y, (Snake) shape); - } else { - getUg().apply(new UTranslate(ct(x), y)).draw(shape); - } - } - - private void drawSnake(double x, double y, Snake shape) { - final Snake transformed = shape.translate(new UTranslate(x, y)).transformX(compressionTransform); - getUg().draw(transformed); - } - - private void drawLine(double x, double y, ULine shape) { - drawLine(ct(x), y, ct(x + shape.getDX()), y + shape.getDY()); - } - - private double ct(double v) { - return compressionTransform.transform(v); - } - - private void drawLine(double x1, double y1, double x2, double y2) { - final double xmin = Math.min(x1, x2); - final double xmax = Math.max(x1, x2); - final double ymin = Math.min(y1, y2); - final double ymax = Math.max(y1, y2); - getUg().apply(new UTranslate(xmin, ymin)).draw(new ULine(xmax - xmin, ymax - ymin)); - } - -} diff --git a/src/net/sourceforge/plantuml/ugraphic/UImage.java b/src/net/sourceforge/plantuml/ugraphic/UImage.java index 4936fd09d..41d356427 100644 --- a/src/net/sourceforge/plantuml/ugraphic/UImage.java +++ b/src/net/sourceforge/plantuml/ugraphic/UImage.java @@ -43,32 +43,19 @@ public class UImage implements UShape { private final BufferedImage image; - // public final double getScale() { - // return scale; - // } - public UImage(BufferedImage image) { this.image = image; } - // public UImage(BufferedImage before, double scale) { - // this.image = before; - // this.scale = scale; - // // if (scale == 1) { - // // this.image = before; - // // return; - // // } - // - // // final int w = (int) Math.round(before.getWidth() * scale); - // // final int h = (int) Math.round(before.getHeight() * scale); - // // final BufferedImage after = new BufferedImage(w, h, before.getType()); - // // final AffineTransform at = new AffineTransform(); - // // at.scale(scale, scale); - // // final AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR); - // // this.image = scaleOp.filter(before, after); - // } - public UImage scale(double scale) { + return scale(scale, AffineTransformOp.TYPE_BILINEAR); + } + + public UImage scaleNearestNeighbor(double scale) { + return scale(scale, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); + } + + private UImage scale(double scale, final int type) { if (scale == 1) { return this; } @@ -77,7 +64,7 @@ public class UImage implements UShape { final BufferedImage after = new BufferedImage(w, h, image.getType()); final AffineTransform at = new AffineTransform(); at.scale(scale, scale); - final AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR); + final AffineTransformOp scaleOp = new AffineTransformOp(at, type); return new UImage(scaleOp.filter(image, after)); } @@ -93,8 +80,4 @@ public class UImage implements UShape { return image.getHeight() - 1; } - // public UShape getScaled(double scale) { - // return scale(scale); - // } - } diff --git a/src/net/sourceforge/plantuml/ugraphic/URectangle.java b/src/net/sourceforge/plantuml/ugraphic/URectangle.java index eb110b320..0230333e7 100644 --- a/src/net/sourceforge/plantuml/ugraphic/URectangle.java +++ b/src/net/sourceforge/plantuml/ugraphic/URectangle.java @@ -44,13 +44,20 @@ public class URectangle extends AbstractShadowable implements Scalable, UShapeSi private final double ry; private final String comment; - public URectangle withWidth(double newHeight) { + public URectangle withHeight(double newHeight) { final URectangle result = new URectangle(width, newHeight, rx, ry, comment); result.ignoreForCompression = this.ignoreForCompression; result.setDeltaShadow(this.getDeltaShadow()); return result; } + public URectangle withWidth(double newWidth) { + final URectangle result = new URectangle(newWidth, height, rx, ry, comment); + result.ignoreForCompression = this.ignoreForCompression; + result.setDeltaShadow(this.getDeltaShadow()); + return result; + } + public UShape getScaled(double scale) { if (scale == 1) { return this; diff --git a/src/net/sourceforge/plantuml/ugraphic/comp/CompressionMode.java b/src/net/sourceforge/plantuml/ugraphic/comp/CompressionMode.java new file mode 100644 index 000000000..d14d55329 --- /dev/null +++ b/src/net/sourceforge/plantuml/ugraphic/comp/CompressionMode.java @@ -0,0 +1,41 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2017, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * 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 + * + * 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.ugraphic.comp; + +public enum CompressionMode { + ON_X, ON_Y + +} diff --git a/src/net/sourceforge/plantuml/ugraphic/CompressionTransform.java b/src/net/sourceforge/plantuml/ugraphic/comp/CompressionTransform.java similarity index 97% rename from src/net/sourceforge/plantuml/ugraphic/CompressionTransform.java rename to src/net/sourceforge/plantuml/ugraphic/comp/CompressionTransform.java index c229442d7..9cc7bd37b 100644 --- a/src/net/sourceforge/plantuml/ugraphic/CompressionTransform.java +++ b/src/net/sourceforge/plantuml/ugraphic/comp/CompressionTransform.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.ugraphic; +package net.sourceforge.plantuml.ugraphic.comp; import java.util.List; diff --git a/src/net/sourceforge/plantuml/ugraphic/Slot.java b/src/net/sourceforge/plantuml/ugraphic/comp/Slot.java similarity index 98% rename from src/net/sourceforge/plantuml/ugraphic/Slot.java rename to src/net/sourceforge/plantuml/ugraphic/comp/Slot.java index 671d6a282..8c0bd5ab9 100644 --- a/src/net/sourceforge/plantuml/ugraphic/Slot.java +++ b/src/net/sourceforge/plantuml/ugraphic/comp/Slot.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.ugraphic; +package net.sourceforge.plantuml.ugraphic.comp; public class Slot implements Comparable { diff --git a/src/net/sourceforge/plantuml/ugraphic/SlotFinder.java b/src/net/sourceforge/plantuml/ugraphic/comp/SlotFinder.java similarity index 54% rename from src/net/sourceforge/plantuml/ugraphic/SlotFinder.java rename to src/net/sourceforge/plantuml/ugraphic/comp/SlotFinder.java index b4992065f..bf26fb9de 100644 --- a/src/net/sourceforge/plantuml/ugraphic/SlotFinder.java +++ b/src/net/sourceforge/plantuml/ugraphic/comp/SlotFinder.java @@ -33,10 +33,28 @@ * * */ -package net.sourceforge.plantuml.ugraphic; +package net.sourceforge.plantuml.ugraphic.comp; import net.sourceforge.plantuml.Url; import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.ugraphic.ColorMapper; +import net.sourceforge.plantuml.ugraphic.ColorMapperIdentity; +import net.sourceforge.plantuml.ugraphic.TextLimitFinder; +import net.sourceforge.plantuml.ugraphic.UChange; +import net.sourceforge.plantuml.ugraphic.UChangeBackColor; +import net.sourceforge.plantuml.ugraphic.UChangeColor; +import net.sourceforge.plantuml.ugraphic.UEllipse; +import net.sourceforge.plantuml.ugraphic.UEmpty; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.UParam; +import net.sourceforge.plantuml.ugraphic.UParamNull; +import net.sourceforge.plantuml.ugraphic.UPath; +import net.sourceforge.plantuml.ugraphic.UPolygon; +import net.sourceforge.plantuml.ugraphic.URectangle; +import net.sourceforge.plantuml.ugraphic.UShape; +import net.sourceforge.plantuml.ugraphic.UStroke; +import net.sourceforge.plantuml.ugraphic.UText; +import net.sourceforge.plantuml.ugraphic.UTranslate; public class SlotFinder implements UGraphic { @@ -50,7 +68,7 @@ public class SlotFinder implements UGraphic { public UGraphic apply(UChange change) { if (change instanceof UTranslate) { - return new SlotFinder(stringBounder, yslot, translate.compose((UTranslate) change)); + return new SlotFinder(mode, stringBounder, slot, translate.compose((UTranslate) change)); } else if (change instanceof UStroke) { return new SlotFinder(this); } else if (change instanceof UChangeBackColor) { @@ -61,22 +79,25 @@ public class SlotFinder implements UGraphic { throw new UnsupportedOperationException(); } - private final SlotSet yslot; + private final SlotSet slot; + private final StringBounder stringBounder; private final UTranslate translate; + private final CompressionMode mode; - public SlotFinder(StringBounder stringBounder) { - this(stringBounder, new SlotSet(), new UTranslate()); + public SlotFinder(CompressionMode mode, StringBounder stringBounder) { + this(mode, stringBounder, new SlotSet(), new UTranslate()); } - private SlotFinder(StringBounder stringBounder, SlotSet yslot, UTranslate translate) { + private SlotFinder(CompressionMode mode, StringBounder stringBounder, SlotSet slot, UTranslate translate) { this.stringBounder = stringBounder; - this.yslot = yslot; + this.slot = slot; this.translate = translate; + this.mode = mode; } private SlotFinder(SlotFinder other) { - this(other.stringBounder, other.yslot, other.translate); + this(other.mode, other.stringBounder, other.slot, other.translate); } public StringBounder getStringBounder() { @@ -92,12 +113,19 @@ public class SlotFinder implements UGraphic { final double y = translate.getDy(); if (shape instanceof URectangle) { final URectangle rect = (URectangle) shape; - if (rect.isIgnoreForCompression()) { + if (mode == CompressionMode.ON_X && rect.isIgnoreForCompression()) { + drawRectangle(x, y, new URectangle(2, rect.getHeight())); + drawRectangle(x + rect.getWidth() - 2, y, new URectangle(2, rect.getHeight())); + return; + } + if (mode == CompressionMode.ON_Y && rect.isIgnoreForCompression()) { drawRectangle(x, y, new URectangle(rect.getWidth(), 2)); drawRectangle(x, y + rect.getHeight() - 2, new URectangle(rect.getWidth(), 2)); return; } - drawRectangle(x, y, rect); + drawRectangle(x, y, (URectangle) shape); + } else if (shape instanceof UPath) { + drawPath(x, y, (UPath) shape); } else if (shape instanceof UPolygon) { drawPolygon(x, y, (UPolygon) shape); } else if (shape instanceof UEllipse) { @@ -109,26 +137,55 @@ public class SlotFinder implements UGraphic { } } + private void drawPath(double x, double y, UPath shape) { + if (mode == CompressionMode.ON_X) { + slot.addSlot(x + shape.getMinX(), x + shape.getMaxX()); + } else { + slot.addSlot(y + shape.getMinY(), y + shape.getMaxY()); + } + + } + private void drawEmpty(double x, double y, UEmpty shape) { - yslot.addSlot(y, y + shape.getHeight()); + if (mode == CompressionMode.ON_X) { + slot.addSlot(x, x + shape.getWidth()); + } else { + slot.addSlot(y, y + shape.getHeight()); + } } private void drawText(double x, double y, UText shape) { final TextLimitFinder finder = new TextLimitFinder(stringBounder, false); finder.apply(new UTranslate(x, y)).draw(shape); - yslot.addSlot(finder.getMinY(), finder.getMaxY()); + if (mode == CompressionMode.ON_X) { + slot.addSlot(finder.getMinX(), finder.getMaxX()); + } else { + slot.addSlot(finder.getMinY(), finder.getMaxY()); + } } private void drawEllipse(double x, double y, UEllipse shape) { - yslot.addSlot(y, y + shape.getHeight()); + if (mode == CompressionMode.ON_X) { + slot.addSlot(x, x + shape.getWidth()); + } else { + slot.addSlot(y, y + shape.getHeight()); + } } private void drawPolygon(double x, double y, UPolygon shape) { - yslot.addSlot(y + shape.getMinY(), y + shape.getMaxY()); + if (mode == CompressionMode.ON_X) { + slot.addSlot(x + shape.getMinX(), x + shape.getMaxX()); + } else { + slot.addSlot(y + shape.getMinY(), y + shape.getMaxY()); + } } private void drawRectangle(double x, double y, URectangle shape) { - yslot.addSlot(y, y + shape.getHeight()); + if (mode == CompressionMode.ON_X) { + slot.addSlot(x, x + shape.getWidth()); + } else { + slot.addSlot(y, y + shape.getHeight()); + } } public ColorMapper getColorMapper() { @@ -141,8 +198,8 @@ public class SlotFinder implements UGraphic { public void closeAction() { } - public SlotSet getYSlotSet() { - return yslot; + public SlotSet getSlotSet() { + return slot; } public void flushUg() { diff --git a/src/net/sourceforge/plantuml/ugraphic/SlotSet.java b/src/net/sourceforge/plantuml/ugraphic/comp/SlotSet.java similarity index 93% rename from src/net/sourceforge/plantuml/ugraphic/SlotSet.java rename to src/net/sourceforge/plantuml/ugraphic/comp/SlotSet.java index 1ad5fc800..0be097d4d 100644 --- a/src/net/sourceforge/plantuml/ugraphic/SlotSet.java +++ b/src/net/sourceforge/plantuml/ugraphic/comp/SlotSet.java @@ -33,13 +33,17 @@ * * */ -package net.sourceforge.plantuml.ugraphic; +package net.sourceforge.plantuml.ugraphic.comp; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.URectangle; +import net.sourceforge.plantuml.ugraphic.UTranslate; + public class SlotSet implements Iterable { private final List all = new ArrayList(); diff --git a/src/net/sourceforge/plantuml/graphic/TextBlockCompressed.java b/src/net/sourceforge/plantuml/ugraphic/comp/TextBlockCompressedOnXorY.java similarity index 73% rename from src/net/sourceforge/plantuml/graphic/TextBlockCompressed.java rename to src/net/sourceforge/plantuml/ugraphic/comp/TextBlockCompressedOnXorY.java index 21a88ebbb..a5c03206e 100644 --- a/src/net/sourceforge/plantuml/graphic/TextBlockCompressed.java +++ b/src/net/sourceforge/plantuml/ugraphic/comp/TextBlockCompressedOnXorY.java @@ -33,30 +33,32 @@ * * */ -package net.sourceforge.plantuml.graphic; +package net.sourceforge.plantuml.ugraphic.comp; import java.awt.geom.Dimension2D; import net.sourceforge.plantuml.Dimension2DDouble; -import net.sourceforge.plantuml.ugraphic.CompressionTransform; +import net.sourceforge.plantuml.graphic.AbstractTextBlock; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.graphic.TextBlock; +import net.sourceforge.plantuml.graphic.TextBlockUtils; import net.sourceforge.plantuml.ugraphic.MinMax; -import net.sourceforge.plantuml.ugraphic.SlotFinder; -import net.sourceforge.plantuml.ugraphic.SlotSet; import net.sourceforge.plantuml.ugraphic.UGraphic; -import net.sourceforge.plantuml.ugraphic.UGraphicCompress; -public class TextBlockCompressed extends AbstractTextBlock implements TextBlock { +public class TextBlockCompressedOnXorY extends AbstractTextBlock implements TextBlock { private final TextBlock textBlock; + private final CompressionMode mode; - public TextBlockCompressed(TextBlock textBlock) { + public TextBlockCompressedOnXorY(CompressionMode mode, TextBlock textBlock) { this.textBlock = textBlock; + this.mode = mode; } public void drawU(final UGraphic ug) { final StringBounder stringBounder = ug.getStringBounder(); final CompressionTransform compressionTransform = getCompressionTransform(stringBounder); - textBlock.drawU(new UGraphicCompress(ug, compressionTransform)); + textBlock.drawU(new UGraphicCompressOnXorY(mode, ug, compressionTransform)); } private MinMax cachedMinMax; @@ -79,9 +81,9 @@ public class TextBlockCompressed extends AbstractTextBlock implements TextBlock } private CompressionTransform getCompressionTransformSlow(final StringBounder stringBounder) { - final SlotFinder slotFinder = new SlotFinder(stringBounder); + final SlotFinder slotFinder = new SlotFinder(mode, stringBounder); textBlock.drawU(slotFinder); - final SlotSet ysSlotSet = slotFinder.getYSlotSet().reverse().smaller(5.0); + final SlotSet ysSlotSet = slotFinder.getSlotSet().reverse().smaller(5.0); final CompressionTransform compressionTransform = new CompressionTransform(ysSlotSet); return compressionTransform; } @@ -89,6 +91,10 @@ public class TextBlockCompressed extends AbstractTextBlock implements TextBlock public Dimension2D calculateDimension(StringBounder stringBounder) { final CompressionTransform compressionTransform = getCompressionTransform(stringBounder); final Dimension2D dim = textBlock.calculateDimension(stringBounder); - return new Dimension2DDouble(dim.getWidth(), compressionTransform.transform(dim.getHeight())); + if (mode == CompressionMode.ON_X) { + return new Dimension2DDouble(compressionTransform.transform(dim.getWidth()), dim.getHeight()); + } else { + return new Dimension2DDouble(dim.getWidth(), compressionTransform.transform(dim.getHeight())); + } } } \ No newline at end of file diff --git a/src/net/sourceforge/plantuml/ugraphic/UGraphicCompress.java b/src/net/sourceforge/plantuml/ugraphic/comp/UGraphicCompressOnXorY.java similarity index 56% rename from src/net/sourceforge/plantuml/ugraphic/UGraphicCompress.java rename to src/net/sourceforge/plantuml/ugraphic/comp/UGraphicCompressOnXorY.java index 64dacfcc1..3986b217e 100644 --- a/src/net/sourceforge/plantuml/ugraphic/UGraphicCompress.java +++ b/src/net/sourceforge/plantuml/ugraphic/comp/UGraphicCompressOnXorY.java @@ -33,30 +33,42 @@ * * */ -package net.sourceforge.plantuml.ugraphic; +package net.sourceforge.plantuml.ugraphic.comp; import net.sourceforge.plantuml.graphic.UGraphicDelegator; +import net.sourceforge.plantuml.ugraphic.UChange; +import net.sourceforge.plantuml.ugraphic.UChangeBackColor; +import net.sourceforge.plantuml.ugraphic.UChangeColor; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.ULine; +import net.sourceforge.plantuml.ugraphic.URectangle; +import net.sourceforge.plantuml.ugraphic.UShape; +import net.sourceforge.plantuml.ugraphic.UStroke; +import net.sourceforge.plantuml.ugraphic.UTranslate; -public class UGraphicCompress extends UGraphicDelegator { +public class UGraphicCompressOnXorY extends UGraphicDelegator { public UGraphic apply(UChange change) { if (change instanceof UTranslate) { - return new UGraphicCompress(getUg(), compressionTransform, translate.compose((UTranslate) change)); + return new UGraphicCompressOnXorY(mode, getUg(), compressionTransform, translate.compose((UTranslate) change)); } else if (change instanceof UStroke || change instanceof UChangeBackColor || change instanceof UChangeColor) { - return new UGraphicCompress(getUg().apply(change), compressionTransform, translate); + return new UGraphicCompressOnXorY(mode, getUg().apply(change), compressionTransform, translate); } throw new UnsupportedOperationException(); } + private final CompressionMode mode; private final CompressionTransform compressionTransform; private final UTranslate translate; - public UGraphicCompress(UGraphic ug, CompressionTransform compressionTransform) { - this(ug, compressionTransform, new UTranslate()); + public UGraphicCompressOnXorY(CompressionMode mode, UGraphic ug, CompressionTransform compressionTransform) { + this(mode, ug, compressionTransform, new UTranslate()); } - private UGraphicCompress(UGraphic ug, CompressionTransform compressionTransform, UTranslate translate) { + private UGraphicCompressOnXorY(CompressionMode mode, UGraphic ug, CompressionTransform compressionTransform, + UTranslate translate) { super(ug); + this.mode = mode; this.compressionTransform = compressionTransform; this.translate = translate; } @@ -67,19 +79,32 @@ public class UGraphicCompress extends UGraphicDelegator { if (shape instanceof URectangle) { final URectangle rect = (URectangle) shape; if (rect.isIgnoreForCompression()) { - final double y2 = ct(y + rect.getHeight()); - shape = rect.withWidth(y2 - ct(y)); + if (mode == CompressionMode.ON_X) { + final double x2 = ct(x + rect.getWidth()); + shape = rect.withWidth(x2 - ct(x)); + } else { + final double y2 = ct(y + rect.getHeight()); + shape = rect.withHeight(y2 - ct(y)); + } } } if (shape instanceof ULine) { drawLine(x, y, (ULine) shape); } else { - getUg().apply(new UTranslate(x, ct(y))).draw(shape); + if (mode == CompressionMode.ON_X) { + getUg().apply(new UTranslate(ct(x), y)).draw(shape); + } else { + getUg().apply(new UTranslate(x, ct(y))).draw(shape); + } } } private void drawLine(double x, double y, ULine shape) { - drawLine(x, ct(y), x + shape.getDX(), ct(y + shape.getDY())); + if (mode == CompressionMode.ON_X) { + drawLine(ct(x), y, ct(x + shape.getDX()), y + shape.getDY()); + } else { + drawLine(x, ct(y), x + shape.getDX(), ct(y + shape.getDY())); + } } private double ct(double v) { @@ -92,15 +117,7 @@ public class UGraphicCompress extends UGraphicDelegator { return; } assert y1 <= y2; - final double xmin = Math.min(x1, x2); - final double xmax = Math.max(x1, x2); - final double ymin = Math.min(y1, y2); - final double ymax = Math.max(y1, y2); - if (x2 >= x1) { - getUg().apply(new UTranslate(xmin, ymin)).draw(new ULine(xmax - xmin, ymax - ymin)); - } else { - getUg().apply(new UTranslate(xmax, ymin)).draw(new ULine(-(xmax - xmin), ymax - ymin)); - } + getUg().apply(new UTranslate(x1, y1)).draw(new ULine(x2 - x1, y2 - y1)); } } diff --git a/src/net/sourceforge/plantuml/ugraphic/txt/UGraphicTxt.java b/src/net/sourceforge/plantuml/ugraphic/txt/UGraphicTxt.java index 90c8785ee..56ea48a40 100644 --- a/src/net/sourceforge/plantuml/ugraphic/txt/UGraphicTxt.java +++ b/src/net/sourceforge/plantuml/ugraphic/txt/UGraphicTxt.java @@ -84,7 +84,6 @@ public class UGraphicTxt extends AbstractCommonUGraphic implements ClipContainer if (shape instanceof UText) { final UText txt = (UText) shape; final int y = ((int) (getTranslateY() + txt.getDescent())) / 10; - System.err.println("x=" + getDx()); if (txt.getFontConfiguration().containsStyle(FontStyle.WAVE)) { charArea.drawHLine('^', y, getDx(), txt.getText().length()); charArea.drawStringLR(txt.getText(), getDx(), y + 1); diff --git a/src/net/sourceforge/plantuml/utils/Cypher.java b/src/net/sourceforge/plantuml/utils/Cypher.java new file mode 100644 index 000000000..6588a2ae3 --- /dev/null +++ b/src/net/sourceforge/plantuml/utils/Cypher.java @@ -0,0 +1,98 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2017, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * 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 + * + * 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.utils; + +import java.security.SecureRandom; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Cypher { + + final private static Pattern p = Pattern.compile("[\\p{L}\\p{N}]+"); + + private final SecureRandom rnd = new SecureRandom(); + private final Map convert = new HashMap(); + private final Set except = new HashSet(); + + public synchronized String cypher(String s) { + + final Matcher m = p.matcher(s); + final StringBuffer sb = new StringBuffer(); + while (m.find()) { + final String word = m.group(0); + m.appendReplacement(sb, changeWord(word)); + } + m.appendTail(sb); + + return sb.toString(); + } + + private String changeWord(final String word) { + final String lower = word.toLowerCase(); + if (except.contains(lower) || lower.matches("^[a-f0-9]{6}$")) { + return word; + } + String res = convert.get(word); + if (res != null) { + return res; + } + int len = word.length(); + if (len < 4) { + len = 4; + } + while (true) { + final StringBuilder sb = new StringBuilder(); + for (int i = 0; i < len; i++) { + final char letter = (char) ('a' + rnd.nextInt(26)); + sb.append(letter); + } + res = sb.toString(); + if (convert.containsValue(res) == false) { + convert.put(word, res); + return res; + } + } + } + + public void addException(String word) { + except.add(word.toLowerCase()); + } + +} diff --git a/src/net/sourceforge/plantuml/version/License.java b/src/net/sourceforge/plantuml/version/License.java index 8ebb8b8c0..6d7a0e39b 100644 --- a/src/net/sourceforge/plantuml/version/License.java +++ b/src/net/sourceforge/plantuml/version/License.java @@ -34,6 +34,7 @@ */ package net.sourceforge.plantuml.version; +import java.text.DateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -48,81 +49,81 @@ public enum License { return GPL; } - private void addMit(final List text) { + private void addMit(final LicenseInfo licenseInfo, final List text) { text.add("PlantUML is free software; you can redistribute it and/or modify it"); text.add("under the terms of the MIT License."); - text.add(""); + text.add(" "); text.add("See http://opensource.org/licenses/MIT"); - text.add(""); + text.add(" "); text.add("Permission is hereby granted, free of charge, to any person obtaining"); text.add("a copy of this software and associated documentation files (the \"Software\"),"); text.add("to deal in the Software without restriction, including without limitation"); text.add("the rights to use, copy, modify, merge, publish, distribute, sublicense,"); text.add("and/or sell copies of the Software, and to permit persons to whom the"); text.add("Software is furnished to do so, subject to the following conditions:"); - text.add(""); + text.add(" "); text.add("The above copyright notice and this permission notice shall be included"); text.add("in all copies or substantial portions of the Software."); - text.add(""); + text.add(" "); text.add("THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS"); text.add("OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,"); text.add("FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE"); text.add("AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,"); text.add("WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR"); text.add("IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."); - text.add(""); - addSupplementary(text); + text.add(" "); + addSupplementary(licenseInfo, text); text.add("the MIT License."); - text.add(""); + text.add(" "); text.add("The generated images can then be used without any reference to the MIT License."); text.add("It is not even necessary to stipulate that they have been generated with PlantUML,"); text.add("also this will be appreciate by PlantUML team."); - text.add(""); + text.add(" "); text.add("There is an exception : if the textual description in PlantUML language is also covered"); text.add("by a license (like the MIT), then the generated images are logically covered"); text.add("by the very same license."); } - private void addEpl(final List text) { + private void addEpl(final LicenseInfo licenseInfo, final List text) { text.add("PlantUML is free software; you can redistribute it and/or modify it"); text.add("under the terms of the Eclipse Public License."); - text.add(""); + text.add(" "); text.add("THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC"); text.add("LICENSE (\"AGREEMENT\"). [Eclipse Public License - v 1.0]"); - text.add(""); + text.add(" "); text.add("ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES"); text.add("RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT."); - text.add(""); + text.add(" "); text.add("You may obtain a copy of the License at"); - text.add(""); + text.add(" "); text.add("http://www.eclipse.org/legal/epl-v10.html"); - text.add(""); + text.add(" "); text.add("Unless required by applicable law or agreed to in writing, software"); text.add("distributed under the License is distributed on an \"AS IS\" BASIS,"); text.add("WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied."); text.add("See the License for the specific language governing permissions and"); text.add("limitations under the License."); - text.add(""); - addSupplementary(text); + text.add(" "); + addSupplementary(licenseInfo, text); text.add("the Eclipse Public License."); - text.add(""); + text.add(" "); text.add("The generated images can then be used without any reference to the Eclipse Public License."); text.add("It is not even necessary to stipulate that they have been generated with PlantUML,"); text.add("also this will be appreciate by PlantUML team."); - text.add(""); + text.add(" "); text.add("There is an exception : if the textual description in PlantUML language is also covered"); text.add("by a license (like the EPL), then the generated images are logically covered"); text.add("by the very same license."); } - private void addBsd(final List text) { + private void addBsd(final LicenseInfo licenseInfo, final List text) { text.add("PlantUML is free software; you can redistribute it and/or modify it"); text.add("under the terms of the Revised BSD License."); - text.add(""); + text.add(" "); text.add("All rights reserved."); text.add("Redistribution and use in source and binary forms, with or without"); text.add("modification, are permitted provided that the following conditions are met:"); - text.add(""); + text.add(" "); text.add("* Redistributions of source code must retain the above copyright"); text.add(" notice, this list of conditions and the following disclaimer."); text.add("* Redistributions in binary form must reproduce the above copyright"); @@ -131,7 +132,7 @@ public enum License { text.add("* Neither the name of the University of California, Berkeley nor the"); text.add(" names of its contributors may be used to endorse or promote products"); text.add(" derived from this software without specific prior written permission."); - text.add(""); + text.add(" "); text.add("THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY"); text.add("EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED"); text.add("WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE"); @@ -142,159 +143,180 @@ public enum License { text.add("ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT"); text.add("(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS"); text.add("SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."); - text.add(""); - addSupplementary(text); + text.add(" "); + addSupplementary(licenseInfo, text); text.add("the Eclipse Public License."); - text.add(""); + text.add(" "); text.add("The generated images can then be used without any reference to the Eclipse Public License."); text.add("It is not even necessary to stipulate that they have been generated with PlantUML,"); text.add("also this will be appreciate by PlantUML team."); - text.add(""); + text.add(" "); text.add("There is an exception : if the textual description in PlantUML language is also covered"); text.add("by a license (like the BSD), then the generated images are logically covered"); text.add("by the very same license."); } - private void addApache(final List text) { + private void addApache(final LicenseInfo licenseInfo, final List text) { text.add("PlantUML is free software; you can redistribute it and/or modify it"); text.add("under the terms of the Apache Software License."); - text.add(""); + text.add(" "); text.add("Licensed under the Apache License, Version 2.0 (the \"License\");"); text.add("you may not use this file except in compliance with the License."); text.add("You may obtain a copy of the License at"); - text.add(""); + text.add(" "); text.add("http://www.apache.org/licenses/LICENSE-2.0"); - text.add(""); + text.add(" "); text.add("Unless required by applicable law or agreed to in writing, software"); text.add("distributed under the License is distributed on an \"AS IS\" BASIS,"); text.add("WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied."); text.add("See the License for the specific language governing permissions and"); text.add("limitations under the License."); - text.add(""); - addSupplementary(text); + text.add(" "); + addSupplementary(licenseInfo, text); text.add("the Apache license."); - text.add(""); + text.add(" "); text.add("The generated images can then be used without any reference to the Apache license."); text.add("It is not even necessary to stipulate that they have been generated with PlantUML,"); text.add("also this will be appreciate by PlantUML team."); - text.add(""); + text.add(" "); text.add("There is an exception : if the textual description in PlantUML language is also covered"); text.add("by a license (like the Apache), then the generated images are logically covered"); text.add("by the very same license."); } - private void addGpl(final List text) { + private void addGpl(final LicenseInfo licenseInfo, final List text) { text.add("PlantUML is free software; you can redistribute it and/or modify it"); text.add("under the terms of the GNU General Public License as published by"); text.add("the Free Software Foundation, either version 3 of the License, or"); text.add("(at your option) any later version."); - text.add(""); + text.add(" "); text.add("PlantUML distributed in the hope that it will be useful, but"); text.add("WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY"); text.add("or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public"); text.add("License for more details."); - text.add(""); + text.add(" "); text.add("You should have received a copy of the GNU General Public"); text.add("License along with this library; if not, write to the Free Software"); text.add("Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,"); text.add("USA."); - text.add(""); - addSupplementary(text); + text.add(" "); + addSupplementary(licenseInfo, text); text.add("the GPL license."); - text.add(""); + text.add(" "); text.add("The generated images can then be used without any reference to the GPL license."); text.add("It is not even necessary to stipulate that they have been generated with PlantUML,"); text.add("also this will be appreciate by PlantUML team."); - text.add(""); + text.add(" "); text.add("There is an exception : if the textual description in PlantUML language is also covered"); text.add("by a license (like the GPL), then the generated images are logically covered"); text.add("by the very same license."); } - private void addGplV2(final List text) { + private void addGplV2(final LicenseInfo licenseInfo, final List text) { text.add("PlantUML is free software; you can redistribute it and/or modify it"); text.add("under the terms of the GNU General Public License as published by"); text.add("the Free Software Foundation, either version 2 of the License, or"); text.add("(at your option) any later version."); - text.add(""); + text.add(" "); text.add("PlantUML distributed in the hope that it will be useful, but"); text.add("WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY"); text.add("or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public"); text.add("License for more details."); - text.add(""); + text.add(" "); text.add("You should have received a copy of the GNU General Public"); text.add("License along with this library; if not, write to the Free Software"); text.add("Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,"); text.add("USA."); - text.add(""); - addSupplementary(text); + text.add(" "); + addSupplementary(licenseInfo, text); text.add("the GPL license."); - text.add(""); + text.add(" "); text.add("The generated images can then be used without any reference to the GPL license."); text.add("It is not even necessary to stipulate that they have been generated with PlantUML,"); text.add("also this will be appreciate by PlantUML team."); - text.add(""); + text.add(" "); text.add("There is an exception : if the textual description in PlantUML language is also covered"); text.add("by a license (like the GPL), then the generated images are logically covered"); text.add("by the very same license."); } - private void addLgpl(final List text) { + private void addLgpl(final LicenseInfo licenseInfo, final List text) { text.add("PlantUML is free software; you can redistribute it and/or modify it"); text.add("under the terms of the GNU Lesser General Public License as published by"); text.add("the Free Software Foundation, either version 3 of the License, or"); text.add("(at your option) any later version."); - text.add(""); + text.add(" "); text.add("PlantUML distributed in the hope that it will be useful, but"); text.add("WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY"); text.add("or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public"); text.add("License for more details."); - text.add(""); + text.add(" "); text.add("You should have received a copy of the GNU Lesser General Public"); text.add("License along with this library; if not, write to the Free Software"); text.add("Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,"); text.add("USA."); - text.add(""); - addSupplementary(text); + text.add(" "); + addSupplementary(licenseInfo, text); text.add("the LGPL license."); - text.add(""); + text.add(" "); text.add("The generated images can then be used without any reference to the LGPL license."); text.add("It is not even necessary to stipulate that they have been generated with PlantUML,"); text.add("although this will be appreciate by PlantUML team."); - text.add(""); + text.add(" "); text.add("There is an exception : if the textual description in PlantUML language is also covered"); text.add("by a license (like the LGPL), then the generated images are logically covered"); text.add("by the very same license."); } - private void addSupplementary(final List text) { - text.add("PlantUML can occasionally display sponsored or advertising messages. Those"); - text.add("messages are usually generated on welcome or error images and never on"); - text.add("functional diagrams."); - text.add(" "); + private void addSupplementary(final LicenseInfo licenseInfo, final List text) { + if (licenseInfo.isValid() == false) { + text.add("PlantUML can occasionally display sponsored or advertising messages. Those"); + text.add("messages are usually generated on welcome or error images and never on"); + text.add("functional diagrams."); + text.add(" "); + } text.add("Images (whatever their format : PNG, SVG, EPS...) generated by running PlantUML"); text.add("are owned by the author of their corresponding sources code (that is, their"); text.add("textual description in PlantUML language). Those images are not covered by"); } - private List getHeaderStart() { + private List getHeaderStart(LicenseInfo licenseInfo) { final List text = new ArrayList(); - text.add("========================================================================"); - text.add("PlantUML : a free UML diagram generator"); - text.add("========================================================================"); - text.add(""); + if (licenseInfo.isNone()) { + text.add("========================================================================"); + text.add("PlantUML : a free UML diagram generator"); + text.add("========================================================================"); + text.add(" "); + } else { + text.add("========================================================================"); + text.add("This is PlantUML Professional Edition"); + text.add("========================================================================"); + addLicenseInfo(text, licenseInfo); + text.add("========================================================================"); + text.add(" "); + } text.add("(C) Copyright 2009-2017, Arnaud Roques"); - text.add(""); + text.add(" "); text.add("Project Info: http://plantuml.com"); - text.add(""); - text.add("If you like this project or if you find it useful, you can support us at:"); - text.add(""); - text.add("http://plantuml.com/patreon (only 1$ per month!)"); - text.add("http://plantuml.com/paypal"); - text.add(""); + text.add(" "); + if (licenseInfo.isValid() == false) { + text.add("If you like this project or if you find it useful, you can support us at:"); + text.add(" "); + text.add("http://plantuml.com/patreon (only 1$ per month!)"); + text.add("http://plantuml.com/paypal"); + text.add(" "); + } return text; } + public static void addLicenseInfo(final List text, LicenseInfo licenseInfo) { + text.add("LICENSED TO : " + licenseInfo.getOwner()); + text.add("EXPIRATION DATE : " + DateFormat.getDateInstance().format(licenseInfo.getExpirationDate())); + if (licenseInfo.hasExpired()) { + text.add("Warning: Your license has expired."); + } + } + public List getJavaHeader() { final List h = new ArrayList(); h.add("/* ========================================================================"); @@ -430,30 +452,31 @@ public enum License { } public List getText() { - final List text = getHeaderStart(); + final LicenseInfo licenseInfo = LicenseInfo.retrieveSlow(); + final List text = getHeaderStart(licenseInfo); if (this == License.GPL) { - addGpl(text); + addGpl(licenseInfo, text); } else if (this == License.GPLV2) { - addGplV2(text); + addGplV2(licenseInfo, text); } else if (this == License.MIT) { - addMit(text); + addMit(licenseInfo, text); } else if (this == License.EPL) { - addEpl(text); + addEpl(licenseInfo, text); } else if (this == License.BSD) { - addBsd(text); + addBsd(licenseInfo, text); } else if (this == License.APACHE) { - addApache(text); + addApache(licenseInfo, text); } else if (this == License.LGPL) { - addLgpl(text); + addLgpl(licenseInfo, text); } else { throw new IllegalStateException(); } if (OptionFlags.getInstance().isEnableStats()) { - text.add(""); + text.add(" "); text.add("This version of PlantUML records general local statistics about usage."); text.add("(more info on http://plantuml.com/statistics-report)"); } - text.add(""); + text.add(" "); text.add("Icons provided by OpenIconic : https://useiconic.com/open"); text.add("Archimate sprites provided by Archi : http://www.archimatetool.com"); text.add("Stdlib AWS provided by https://github.com/milo-minderbinder/AWS-PlantUML"); @@ -462,8 +485,7 @@ public enum License { text.add("ASCIIMathML (c) David Lippman http://www.pierce.ctc.edu/dlippman"); text.add("CafeUndZopfli ported by Eugene Klyuchnikov https://github.com/eustas/CafeUndZopfli"); text.add("Brotli (c) by the Brotli Authors https://github.com/google/brotli"); - text.add(""); + text.add(" "); return text; } - } diff --git a/src/net/sourceforge/plantuml/version/LicenseInfo.java b/src/net/sourceforge/plantuml/version/LicenseInfo.java new file mode 100644 index 000000000..1f842c496 --- /dev/null +++ b/src/net/sourceforge/plantuml/version/LicenseInfo.java @@ -0,0 +1,221 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2017, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * 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 + * + * 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.version; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.math.BigInteger; +import java.security.NoSuchAlgorithmException; +import java.util.Collection; +import java.util.Date; +import java.util.Set; +import java.util.TreeSet; +import java.util.prefs.BackingStoreException; +import java.util.prefs.Preferences; + +import net.sourceforge.plantuml.Log; +import net.sourceforge.plantuml.SignatureUtils; +import net.sourceforge.plantuml.dedication.Dedication; +import net.sourceforge.plantuml.dedication.QBlock; + +public class LicenseInfo { + + private final static Preferences prefs = Preferences.userNodeForPackage(LicenseInfo.class); + private final static LicenseInfo NONE = new LicenseInfo(); + + public static final int POS_TYPE = 2; + public static final int POS_SIGNATURE = 10; + public static final int POS_GENERATION = 100; + public static final int POS_EXPIRATION = 108; + public static final int POS_OWNER = 128; + + private final long generationDate; + private final long expirationDate; + private final String owner; + + private LicenseInfo() { + this.expirationDate = 0; + this.generationDate = 0; + this.owner = null; + } + + private LicenseInfo(Magic magic) throws NoSuchAlgorithmException, IOException { + final String signature = SignatureUtils.toHexString(magic.get(LicenseInfo.POS_SIGNATURE, 64)); + final String local = SignatureUtils.toHexString(Magic.signature()); + if (local.equals(signature) == false) { + throw new IOException(); + } + final int type = magic.getByte(Magic.signature(), LicenseInfo.POS_TYPE); + this.generationDate = bytesToLong(magic.get(LicenseInfo.POS_GENERATION, 8)); + this.expirationDate = bytesToLong(magic.get(LicenseInfo.POS_EXPIRATION, 8)); + this.owner = magic.getString(LicenseInfo.POS_OWNER); + } + + public static long bytesToLong(byte[] b) { + long result = 0; + for (int i = 0; i < 8; i++) { + result <<= 8; + result |= (b[i] & 0xFF); + } + return result; + } + + public static void persistMe(String key) throws BackingStoreException { + prefs.sync(); + prefs.put("license", key); + } + + private static LicenseInfo cache; + + public static synchronized LicenseInfo retrieveQuick() { + if (cache == null) { + return retrieveSlow(); + } + return cache; + } + + public static synchronized LicenseInfo retrieveSlow() { + cache = LicenseInfo.NONE; + final String key = prefs.get("license", ""); + if (key.length() > 0) { + cache = setIfValid(retrieve(key), cache); + if (cache.isValid()) { + return cache; + } + } + for (File f : fileCandidates()) { + try { + if (f.exists() && f.canRead()) { + final LicenseInfo result = retrieve(f); + cache = setIfValid(result, cache); + if (cache.isValid()) { + return cache; + } + } + } catch (IOException e) { + Log.info("Error " + e); + // e.printStackTrace(); + } + } + return cache; + } + + private static LicenseInfo setIfValid(LicenseInfo value, LicenseInfo def) { + if (value.isValid() || def.isNone()) { + return value; + } + return def; + } + + private static LicenseInfo retrieve(File f) throws IOException { + final BufferedReader br = new BufferedReader(new FileReader(f)); + final String s = br.readLine(); + br.close(); + final LicenseInfo result = retrieve(s); + if (result != null) { + Log.info("Reading license from " + f.getAbsolutePath()); + } + return result; + } + + public static LicenseInfo retrieve(final String key) { + if (key.matches("^[0-9a-z]+$")) { + try { + final BigInteger lu = new BigInteger(key, 36); + final QBlock qb2 = new QBlock(lu); + final QBlock qb3 = qb2.change(Dedication.E, Dedication.N); + final Magic magic = qb3.toMagic(); + + final String sig = SignatureUtils.toHexString(Magic.signature()); + magic.xor(SignatureUtils.getSHA512raw(SignatureUtils.salting(sig, Magic.getSalt(sig)))); + return new LicenseInfo(magic); + } catch (Exception e) { + // e.printStackTrace(); + Log.info("Error " + e); + } + } + return LicenseInfo.NONE; + } + + public static Collection fileCandidates() { + final Set result = new TreeSet(); + final String classpath = System.getProperty("java.class.path"); + String[] classpathEntries = classpath.split(File.pathSeparator); + for (String s : classpathEntries) { + File dir = new File(s); + if (dir.isFile()) { + dir = dir.getParentFile(); + } + if (dir.isDirectory()) { + result.add(new File(dir, "license.txt")); + } + } + return result; + } + + public static void main(String[] args) { + LicenseInfo info = retrieveSlow(); + System.err.println("valid=" + info.isValid()); + System.err.println("info=" + info.owner); + + } + + public final Date getGenerationDate() { + return new Date(generationDate); + } + + public final Date getExpirationDate() { + return new Date(expirationDate); + } + + public final String getOwner() { + return owner; + } + + public boolean isNone() { + return owner == null; + } + + public boolean isValid() { + return owner != null && System.currentTimeMillis() <= this.expirationDate; + } + + public boolean hasExpired() { + return owner != null && System.currentTimeMillis() > this.expirationDate; + } + +} diff --git a/src/net/sourceforge/plantuml/version/Magic.java b/src/net/sourceforge/plantuml/version/Magic.java new file mode 100644 index 000000000..a5e7d2c8e --- /dev/null +++ b/src/net/sourceforge/plantuml/version/Magic.java @@ -0,0 +1,192 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2017, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * 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 + * + * 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.version; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.NetworkInterface; +import java.security.NoSuchAlgorithmException; +import java.util.Enumeration; +import java.util.Random; + +import net.sourceforge.plantuml.OptionPrint; +import net.sourceforge.plantuml.SignatureUtils; +import net.sourceforge.plantuml.dedication.TurningBytes; + +public class Magic { + + private final byte buffer[] = new byte[512]; + + @Override + public String toString() { + return SignatureUtils.toString(buffer); + } + + public String toHexString() { + return SignatureUtils.toHexString(buffer); + } + + private void xor(TurningBytes turningBytes) { + for (int i = 0; i < buffer.length; i++) { + buffer[i] ^= turningBytes.nextByte(); + } + } + + public void xor(byte[] key) { + xor(new TurningBytes(key)); + } + + public static Magic fromHexString(String s) { + if (s.length() != 1024) { + throw new IllegalArgumentException(); + } + final Magic result = new Magic(); + for (int i = 0; i < 512; i++) { + result.buffer[i] = (byte) (Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16) & 0xFF); + } + return result; + } + + public final byte[] getBuffer() { + return buffer; + } + + public void setByte(byte[] shrink, int pos, int data) { + buffer[pos] = (byte) (0xFF & (data ^ shrink(shrink))); + } + + public int getByte(byte[] shrink, int pos) { + return buffer[pos] ^ shrink(shrink); + } + + public void set(int pos, byte[] data) { + for (int i = 0; i < data.length; i++) { + buffer[pos + i] = data[i]; + } + } + + public void setString(int pos, String s) throws UnsupportedEncodingException, NoSuchAlgorithmException { + final byte[] tmp = s.getBytes("UTF-8"); + buffer[pos] = (byte) tmp.length; + set(pos + 1, tmp); + // set(pos + 1 + tmp.length, SignatureUtils.getSHA512raw(s)); + } + + public String getString(int pos) throws UnsupportedEncodingException, NoSuchAlgorithmException { + final int len = buffer[pos]; + if (len < 0 || len > 127) { + throw new IllegalArgumentException(); + } + final String result = new String(get(pos + 1, len), "UTF-8"); + // if (isEquals(SignatureUtils.getSHA512raw(result), get(pos + 1 + len, 64)) == false) { + // throw new UnsupportedEncodingException(); + // } + return result; + } + + public byte[] get(int pos, int len) { + final byte result[] = new byte[len]; + System.arraycopy(buffer, pos, result, 0, len); + return result; + } + + private boolean isEquals(byte data1[], byte[] data2) { + if (data1.length != data2.length) { + return false; + } + for (int i = 0; i < data1.length; i++) { + if (data1[i] != data2[i]) { + return false; + } + } + return true; + } + + public static byte[] signature() throws IOException { + final String signature = OptionPrint.getHostName() + getMacAddress(); + try { + return SignatureUtils.getSHA512raw(SignatureUtils.salting(signature, getSalt(signature))); + } catch (Exception e) { + e.printStackTrace(); + throw new IOException(); + } + } + + public static byte shrink(byte data[]) { + byte result = 42; + for (byte b : data) { + result ^= b; + } + return result; + } + + public static byte[] getSalt(final String signature) throws UnsupportedEncodingException { + final Random rnd = new Random(getSeed(signature.getBytes("UTF-8"))); + final byte salt[] = new byte[512]; + rnd.nextBytes(salt); + return salt; + } + + private static long getSeed(byte[] bytes) { + long result = 19; + for (byte b : bytes) { + result = result * 41 + b; + } + return result; + } + + private static String getMacAddress() throws IOException { + + final Enumeration net = NetworkInterface.getNetworkInterfaces(); + final StringBuilder result = new StringBuilder(); + while (net.hasMoreElements()) { + final NetworkInterface element = net.nextElement(); + byte[] mac = element.getHardwareAddress(); + if (mac != null) { + for (byte b : mac) { + result.append(String.format("%02x", b)); + } + } + } + return result.toString(); + } + + public static void main(String[] args) throws IOException { + System.err.println(SignatureUtils.toHexString(signature())); + System.out.println("Mac: " + getMacAddress()); + + } + +} diff --git a/src/net/sourceforge/plantuml/version/PSystemKeygen.java b/src/net/sourceforge/plantuml/version/PSystemKeygen.java new file mode 100644 index 000000000..2693ac8d5 --- /dev/null +++ b/src/net/sourceforge/plantuml/version/PSystemKeygen.java @@ -0,0 +1,169 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2017, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * 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 + * + * 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.version; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.prefs.BackingStoreException; + +import net.sourceforge.plantuml.AbstractPSystem; +import net.sourceforge.plantuml.FileFormatOption; +import net.sourceforge.plantuml.SignatureUtils; +import net.sourceforge.plantuml.core.DiagramDescription; +import net.sourceforge.plantuml.core.ImageData; +import net.sourceforge.plantuml.flashcode.FlashCodeFactory; +import net.sourceforge.plantuml.flashcode.FlashCodeUtils; +import net.sourceforge.plantuml.graphic.GraphicStrings; +import net.sourceforge.plantuml.graphic.HtmlColorUtils; +import net.sourceforge.plantuml.graphic.TextBlock; +import net.sourceforge.plantuml.graphic.UDrawable; +import net.sourceforge.plantuml.ugraphic.ColorMapperIdentity; +import net.sourceforge.plantuml.ugraphic.ImageBuilder; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.UImage; +import net.sourceforge.plantuml.ugraphic.UTranslate; + +public class PSystemKeygen extends AbstractPSystem { + + final private String key; + + public PSystemKeygen(String key) { + this.key = key; + } + + @Override + final protected ImageData exportDiagramNow(OutputStream os, int num, FileFormatOption fileFormat, long seed) + throws IOException { + final ImageBuilder imageBuilder = new ImageBuilder(new ColorMapperIdentity(), 1.0, HtmlColorUtils.WHITE, + getMetadata(), null, 0, 0, null, false); + + imageBuilder.setUDrawable(new UDrawable() { + public void drawU(UGraphic ug) { + try { + drawInternal(ug); + } catch (IOException e) { + e.printStackTrace(); + } + } + }); + return imageBuilder.writeImageTOBEMOVED(fileFormat, seed, os); + } + + public DiagramDescription getDescription() { + return new DiagramDescription("(Genkey)"); + } + + private void drawInternal(UGraphic ug) throws IOException { + if (key.length() == 0) { + drawFlash(ug); + return; + } + final LicenseInfo info = LicenseInfo.retrieve(key); + if (info.isNone()) { + drawFlash(ug); + return; + } + final List strings = header(); + strings.add("Provided license information:"); + License.addLicenseInfo(strings, info); + strings.add(" "); + strings.add("========================================================================"); + try { + LicenseInfo.persistMe(key); + } catch (BackingStoreException e) { + strings.add("Error: Cannot store license key."); + } + + final LicenseInfo installed = LicenseInfo.retrieveSlow(); + if (installed.isNone()) { + strings.add("No license currently installed."); + strings.add(" "); + strings.add("Please copy license.txt to one of those files:"); + for (File f : LicenseInfo.fileCandidates()) { + strings.add(f.getAbsolutePath()); + } + strings.add(" "); + } else { + strings.add("Installed license:"); + License.addLicenseInfo(strings, installed); + strings.add(" "); + } + + final TextBlock disp = GraphicStrings.createBlackOnWhite(strings); + disp.drawU(ug); + } + + private ArrayList header() { + final ArrayList strings = new ArrayList(); + strings.add("PlantUML version " + Version.versionString() + " (" + Version.compileTimeString() + ")"); + strings.add("(" + License.getCurrent() + " source distribution)"); + strings.add("Loaded from " + Version.getJarPath()); + strings.add(" "); + return strings; + } + + public void drawFlash(UGraphic ug) throws IOException { + final List strings = header(); + strings.add("To get your Professional Edition License,"); + strings.add("please send this flashcode to plantuml@gmail.com :"); + + TextBlock disp = GraphicStrings.createBlackOnWhite(strings); + disp.drawU(ug); + + ug = ug.apply(new UTranslate(0, disp.calculateDimension(ug.getStringBounder()).getHeight())); + final FlashCodeUtils utils = FlashCodeFactory.getFlashCodeUtils(); + final BufferedImage im = utils.exportFlashcode(Version.versionString() + "\n" + + SignatureUtils.toHexString(Magic.signature())); + final UImage flash = new UImage(im).scaleNearestNeighbor(4); + ug.draw(flash); + + ug = ug.apply(new UTranslate(0, flash.getHeight())); + + final LicenseInfo info = LicenseInfo.retrieveSlow(); + if (info.isNone() == false) { + strings.clear(); + strings.add("Installed license:"); + License.addLicenseInfo(strings, info); + strings.add(" "); + disp = GraphicStrings.createBlackOnWhite(strings); + disp.drawU(ug); + } + + } +} diff --git a/src/net/sourceforge/plantuml/version/PSystemVersionFactory.java b/src/net/sourceforge/plantuml/version/PSystemVersionFactory.java index 0f6a0ba70..a492e4ff7 100644 --- a/src/net/sourceforge/plantuml/version/PSystemVersionFactory.java +++ b/src/net/sourceforge/plantuml/version/PSystemVersionFactory.java @@ -62,6 +62,11 @@ public class PSystemVersionFactory extends PSystemSingleLineFactory { if (line.matches("(?i)^checkversion\\s*$")) { return PSystemVersion.createCheckVersions(null, null); } + if (line.matches("(?i)^keygen(\\s+[0-9a-z]+)?\\s*$")) { + line = line.trim(); + final String key = line.substring("keygen".length()).trim(); + return new PSystemKeygen(key); + } final Pattern p1 = Pattern.compile("(?i)^checkversion\\(proxy=([\\w.]+),port=(\\d+)\\)$"); final Matcher m1 = p1.matcher(line); if (m1.matches()) { diff --git a/src/net/sourceforge/plantuml/version/Professionnal.java b/src/net/sourceforge/plantuml/version/Professionnal.java deleted file mode 100644 index edd9827f3..000000000 --- a/src/net/sourceforge/plantuml/version/Professionnal.java +++ /dev/null @@ -1,119 +0,0 @@ -/* ======================================================================== - * PlantUML : a free UML diagram generator - * ======================================================================== - * - * (C) Copyright 2009-2017, Arnaud Roques - * - * Project Info: http://plantuml.com - * - * 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 - * - * 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.version; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Date; -import java.util.prefs.Preferences; - -import net.sourceforge.plantuml.OptionPrint; -import net.sourceforge.plantuml.dedication.DecoderInputStream; -import net.sourceforge.plantuml.dedication.Dedication; -import net.sourceforge.plantuml.dedication.QBlocks; - -public class Professionnal { - - final private static Preferences prefs = Preferences.userNodeForPackage(Professionnal.class); - - private final String hostname; - private final String organization; - private final String mail; - private final Date date1; - private final Date date2; - - private Professionnal(String hostname, String organization, String mail, int date1, int date2) { - this.hostname = hostname; - this.organization = organization; - this.mail = mail; - this.date1 = new Date(date1 * 1000L); - this.date2 = new Date(date2 * 1000L); - } - - public static Professionnal decodeNow(final String license) throws IOException { - final QBlocks data = QBlocks.descodeAscii(license); - final QBlocks decrypted = data.change(Dedication.E, Dedication.N); - - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - decrypted.writeTo(baos, Dedication.SIZE); - baos.close(); - - final String hostname = OptionPrint.getHostName(); - InputStream source1 = null; - try { - source1 = new DecoderInputStream(new ByteArrayInputStream(baos.toByteArray()), hostname); - final DataInputStream src = new DataInputStream(source1); - final int version = src.readByte(); - if (version != 42) { - throw new IOException(); - } - final String host1 = src.readUTF(); - final String organization = src.readUTF(); - final String mail = src.readUTF(); - final int date1 = src.readInt(); - final int date2 = src.readInt(); - - return new Professionnal(host1, organization, mail, date1, date2); - } finally { - if (source1 != null) { - source1.close(); - } - } - } - - public String getHostname() { - return hostname; - } - - public String getMail() { - return mail; - } - - public String getOrganization() { - return organization; - } - - public Date getDate1() { - return date1; - } - - public Date getDate2() { - return date2; - } - -} diff --git a/src/net/sourceforge/plantuml/version/Version.java b/src/net/sourceforge/plantuml/version/Version.java index 29050566d..8bc63d19c 100644 --- a/src/net/sourceforge/plantuml/version/Version.java +++ b/src/net/sourceforge/plantuml/version/Version.java @@ -43,7 +43,7 @@ public class Version { private static final int MAJOR_SEPARATOR = 1000000; public static int version() { - return 1201808; + return 1201809; } public static int versionPatched() { @@ -88,7 +88,7 @@ public class Version { } public static long compileTime() { - return 1529843460982L; + return 1532710698423L; } public static String compileTimeString() { diff --git a/stdlib/cloudogu-abx.repx b/stdlib/cloudogu-abx.repx new file mode 100644 index 000000000..7bf0221c1 Binary files /dev/null and b/stdlib/cloudogu-abx.repx differ diff --git a/stdlib/cloudogu-dex.repx b/stdlib/cloudogu-dex.repx new file mode 100644 index 000000000..fd6dbd42e Binary files /dev/null and b/stdlib/cloudogu-dex.repx differ diff --git a/stdlib/home.repx b/stdlib/home.repx index 582fbbff8..81206b6be 100644 --- a/stdlib/home.repx +++ b/stdlib/home.repx @@ -1,5 +1,6 @@ aws cloudinsight +cloudogu devicons font-awesome material