1
0
mirror of https://github.com/octoleo/plantuml.git synced 2024-11-25 06:17:33 +00:00

version 1.2018.3

This commit is contained in:
Arnaud Roques 2018-04-06 22:36:30 +02:00
parent 86c9c6d603
commit e3bdf19745
84 changed files with 3641 additions and 1159 deletions

View File

@ -35,7 +35,7 @@
<groupId>net.sourceforge.plantuml</groupId>
<artifactId>plantuml</artifactId>
<version>1.2018.3-SNAPSHOT</version>
<version>1.2018.4-SNAPSHOT</version>
<packaging>jar</packaging>
<name>PlantUML</name>

View File

@ -139,6 +139,8 @@ public enum ColorParam {
nodeBorder(HtmlColorUtils.BLACK, ColorType.LINE),
rectangleBackground(HtmlColorUtils.MY_YELLOW, true, ColorType.BACK),
rectangleBorder(HtmlColorUtils.BLACK, ColorType.LINE),
cardBackground(HtmlColorUtils.MY_YELLOW, true, ColorType.BACK),
cardBorder(HtmlColorUtils.BLACK, ColorType.LINE),
agentBackground(HtmlColorUtils.MY_YELLOW, true, ColorType.BACK),
agentBorder(HtmlColorUtils.MY_RED, ColorType.LINE),
storageBackground(HtmlColorUtils.MY_YELLOW, true, ColorType.BACK),

View File

@ -35,14 +35,21 @@
*/
package net.sourceforge.plantuml;
public enum RoundParam {
public enum CornerParam {
DEFAULT, diagramBorder, titleBorder, rectangle, component;
public String getKey() {
public String getRoundKey() {
if (this == DEFAULT) {
return "roundcorner";
}
return name() + "roundcorner";
}
public String getDiagonalKey() {
if (this == DEFAULT) {
return "diagonalcorner";
}
return name() + "diagonalcorner";
}
}

View File

@ -45,6 +45,9 @@ public class Dimension2DDouble extends Dimension2D {
final private double height;
public Dimension2DDouble(double width, double height) {
if (Double.isNaN(width) || Double.isNaN(height)) {
throw new IllegalArgumentException();
}
this.width = width;
this.height = height;
}

View File

@ -76,6 +76,7 @@ public enum FontParam {
ENTITY(14, Font.PLAIN), //
AGENT(14, Font.PLAIN), //
RECTANGLE(14, Font.PLAIN), //
CARD(14, Font.PLAIN), //
NODE(14, Font.PLAIN), //
DATABASE(14, Font.PLAIN), //
QUEUE(14, Font.PLAIN), //
@ -107,6 +108,7 @@ public enum FontParam {
ENTITY_STEREOTYPE(14, Font.ITALIC), //
AGENT_STEREOTYPE(14, Font.ITALIC), //
RECTANGLE_STEREOTYPE(14, Font.ITALIC), //
CARD_STEREOTYPE(14, Font.ITALIC), //
NODE_STEREOTYPE(14, Font.ITALIC), //
FOLDER_STEREOTYPE(14, Font.ITALIC), //
FILE_STEREOTYPE(14, Font.ITALIC), //

View File

@ -101,7 +101,9 @@ public interface ISkinParam extends ISkinSimple {
public double getRanksep();
public double getRoundCorner(RoundParam param, Stereotype stereotype);
public double getRoundCorner(CornerParam param, Stereotype stereotype);
public double getDiagonalCorner(CornerParam param, Stereotype stereotype);
public LineBreakStrategy maxMessageSize();

View File

@ -49,8 +49,10 @@ import net.sourceforge.plantuml.activitydiagram3.ActivityDiagram3;
import net.sourceforge.plantuml.core.Diagram;
import net.sourceforge.plantuml.core.ImageData;
import net.sourceforge.plantuml.cucadiagram.CucaDiagram;
import net.sourceforge.plantuml.graphic.HtmlColorUtils;
import net.sourceforge.plantuml.html.CucaDiagramHtmlMaker;
import net.sourceforge.plantuml.png.PngSplitter;
import net.sourceforge.plantuml.project3.GanttDiagram;
import net.sourceforge.plantuml.sequencediagram.SequenceDiagram;
public class PSystemUtils {
@ -66,6 +68,9 @@ public class PSystemUtils {
if (system instanceof CucaDiagram) {
return exportDiagramsCuca((CucaDiagram) system, suggestedFile, fileFormatOption);
}
if (system instanceof GanttDiagram) {
return exportDiagramsGantt2((GanttDiagram) system, suggestedFile, fileFormatOption);
}
if (system instanceof ActivityDiagram3) {
return exportDiagramsActivityDiagram3((ActivityDiagram3) system, suggestedFile, fileFormatOption);
}
@ -230,6 +235,62 @@ public class PSystemUtils {
}
// static private List<FileImageData> exportDiagramsGantt1(GanttDiagram system, SuggestedFile suggestedFile,
// FileFormatOption fileFormat) throws IOException {
// if (suggestedFile.getFile(0).exists() && suggestedFile.getFile(0).isDirectory()) {
// throw new IllegalArgumentException("File is a directory " + suggestedFile);
// }
// OutputStream os = null;
// ImageData imageData = null;
// try {
// if (PSystemUtils.canFileBeWritten(suggestedFile.getFile(0)) == false) {
// return Collections.emptyList();
// }
// os = new BufferedOutputStream(new FileOutputStream(suggestedFile.getFile(0)));
// imageData = system.exportDiagram(os, 0, fileFormat);
// } finally {
// if (os != null) {
// os.close();
// }
// }
// return Arrays.asList(new FileImageData(suggestedFile.getFile(0), imageData));
// }
static private List<FileImageData> exportDiagramsGantt2(GanttDiagram system, SuggestedFile suggestedFile,
FileFormatOption fileFormat) throws IOException {
if (suggestedFile.getFile(0).exists() && suggestedFile.getFile(0).isDirectory()) {
throw new IllegalArgumentException("File is a directory " + suggestedFile);
}
ImageData cmap = null;
OutputStream os = null;
try {
if (PSystemUtils.canFileBeWritten(suggestedFile.getFile(0)) == false) {
return Collections.emptyList();
}
os = new NamedOutputStream(suggestedFile.getFile(0));
cmap = system.exportDiagram(os, 0, fileFormat);
} finally {
if (os != null) {
os.close();
}
}
List<File> result = Arrays.asList(suggestedFile.getFile(0));
if (fileFormat.getFileFormat() == FileFormat.PNG) {
final SplitParam splitParam = new SplitParam(HtmlColorUtils.BLACK, null, 5);
result = new PngSplitter(suggestedFile, system.getHorizontalPages(), system.getVerticalPages(),
system.getMetadata(), system.getDpi(fileFormat), fileFormat.isWithMetadata(), splitParam)
.getFiles();
}
final List<FileImageData> result2 = new ArrayList<FileImageData>();
for (File f : result) {
result2.add(new FileImageData(f, cmap));
}
return result2;
}
private static List<FileImageData> createFilesHtml(CucaDiagram system, SuggestedFile suggestedFile)
throws IOException {
final String name = suggestedFile.getName();

View File

@ -653,23 +653,39 @@ public class SkinParam implements ISkinParam {
return 0;
}
public double getRoundCorner(RoundParam param, Stereotype stereotype) {
Double result = getRoundCornerInternal(param, stereotype);
public double getDiagonalCorner(CornerParam param, Stereotype stereotype) {
final String key = param.getDiagonalKey();
Double result = getCornerInternal(key, param, stereotype);
if (result != null) {
return result;
}
result = getRoundCornerInternal(param, null);
result = getCornerInternal(key, param, null);
if (result != null) {
return result;
}
if (param == RoundParam.DEFAULT) {
if (param == CornerParam.DEFAULT) {
return 0;
}
return getRoundCorner(RoundParam.DEFAULT, stereotype);
return getDiagonalCorner(CornerParam.DEFAULT, stereotype);
}
private Double getRoundCornerInternal(RoundParam param, Stereotype stereotype) {
String key = param.getKey();
public double getRoundCorner(CornerParam param, Stereotype stereotype) {
final String key = param.getRoundKey();
Double result = getCornerInternal(key, param, stereotype);
if (result != null) {
return result;
}
result = getCornerInternal(key, param, null);
if (result != null) {
return result;
}
if (param == CornerParam.DEFAULT) {
return 0;
}
return getRoundCorner(CornerParam.DEFAULT, stereotype);
}
private Double getCornerInternal(String key, CornerParam param, Stereotype stereotype) {
if (stereotype != null) {
key += stereotype.getLabel(false);
}

View File

@ -147,10 +147,14 @@ public class SkinParamDelegator implements ISkinParam {
return skinParam.getRanksep();
}
public double getRoundCorner(RoundParam param, Stereotype stereotype) {
public double getRoundCorner(CornerParam param, Stereotype stereotype) {
return skinParam.getRoundCorner(param, stereotype);
}
public double getDiagonalCorner(CornerParam param, Stereotype stereotype) {
return skinParam.getDiagonalCorner(param, stereotype);
}
public UStroke getThickness(LineParam param, Stereotype stereotype) {
return skinParam.getThickness(param, stereotype);
}

View File

@ -0,0 +1,162 @@
/* ========================================================================
* 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;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import net.sourceforge.plantuml.preproc.Defines;
public class ZSourceFileReader extends ZSourceFileReaderAbstract implements ISourceFileReader {
public ZSourceFileReader(File file) throws IOException {
this(file, file.getAbsoluteFile().getParentFile());
}
public ZSourceFileReader(File file, File outputDirectory, String charset) throws IOException {
this(Defines.createWithFileName(file), file, outputDirectory, Collections.<String> emptyList(), charset,
new FileFormatOption(FileFormat.PNG));
}
public ZSourceFileReader(final File file, File outputDirectory) throws IOException {
this(Defines.createWithFileName(file), file, outputDirectory, Collections.<String> emptyList(), null,
new FileFormatOption(FileFormat.PNG));
}
public ZSourceFileReader(final File file, File outputDirectory, FileFormatOption fileFormatOption)
throws IOException {
this(Defines.createWithFileName(file), file, outputDirectory, Collections.<String> emptyList(), null,
fileFormatOption);
}
public ZSourceFileReader(Defines defines, final File file, File outputDirectory, List<String> config,
String charset, FileFormatOption fileFormatOption) throws IOException {
this.file = file;
this.fileFormatOption = fileFormatOption;
if (file.exists() == false) {
throw new IllegalArgumentException();
}
FileSystem.getInstance().setCurrentDir(file.getAbsoluteFile().getParentFile());
if (outputDirectory == null) {
outputDirectory = file.getAbsoluteFile().getParentFile();
} else if (outputDirectory.isAbsolute() == false) {
outputDirectory = FileSystem.getInstance().getFile(outputDirectory.getPath());
}
if (outputDirectory.exists() == false) {
outputDirectory.mkdirs();
}
this.outputDirectory = outputDirectory;
builder = new BlockUmlBuilder(config, charset, defines, getReader(charset), file.getAbsoluteFile()
.getParentFile(), file.getAbsolutePath());
}
private File getDirIfDirectory(String newName) {
Log.info("Checking=" + newName);
if (endsWithSlashOrAntislash(newName)) {
Log.info("It ends with / so it looks like a directory");
newName = newName.substring(0, newName.length() - 1);
File f = new File(newName);
Log.info("f=" + f);
if (f.isAbsolute() == false) {
Log.info("It's relative, so let's change it");
f = new File(outputDirectory, newName);
Log.info("f=" + f);
}
if (f.exists() == false) {
Log.info("It does not exist: let's create it");
try {
f.mkdirs();
} catch (Exception e) {
Log.info("Error " + e);
}
if (f.exists() && f.isDirectory()) {
Log.info("Creation ok");
return f;
}
Log.info("We cannot create it");
} else if (f.isDirectory() == false) {
Log.info("It exists, but is not a directory: we ignore it");
return null;
}
return f;
}
File f = new File(newName);
Log.info("f=" + f);
if (f.isAbsolute() == false) {
Log.info("Relative, so let's change it");
f = new File(outputDirectory, newName);
Log.info("f=" + f);
}
if (f.exists() && f.isDirectory()) {
Log.info("It's an existing directory");
return f;
}
Log.info("It's not a directory");
return null;
}
@Override
protected SuggestedFile getSuggestedFile(BlockUml blockUml) {
final String newName = blockUml.getFileOrDirname();
SuggestedFile suggested = null;
if (newName != null) {
Log.info("name from block=" + newName);
final File dir = getDirIfDirectory(newName);
if (dir == null) {
Log.info(newName + " is not taken as a directory");
suggested = SuggestedFile.fromOutputFile(new File(outputDirectory, newName),
fileFormatOption.getFileFormat(), 0);
} else {
Log.info("We are going to create files in directory " + dir);
suggested = SuggestedFile.fromOutputFile(new File(dir, file.getName()),
fileFormatOption.getFileFormat(), 0);
}
Log.info("We are going to put data in " + suggested);
}
if (suggested == null) {
suggested = SuggestedFile.fromOutputFile(new File(outputDirectory, file.getName()),
fileFormatOption.getFileFormat(), cpt++);
}
suggested.getParentFile().mkdirs();
return suggested;
}
}

View File

@ -0,0 +1,66 @@
/* ========================================================================
* 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;
import java.io.File;
import java.io.IOException;
import java.util.List;
import net.sourceforge.plantuml.preproc.Defines;
public class ZSourceFileReader2 extends ZSourceFileReaderAbstract implements ISourceFileReader {
public ZSourceFileReader2(Defines defines, final File file, File outputFile, List<String> config, String charset,
FileFormatOption fileFormatOption) throws IOException {
this.file = file;
this.fileFormatOption = fileFormatOption;
this.outputFile = outputFile;
if (file.exists() == false) {
throw new IllegalArgumentException();
}
FileSystem.getInstance().setCurrentDir(file.getAbsoluteFile().getParentFile());
builder = new BlockUmlBuilder(config, charset, defines, getReader(charset), file.getAbsoluteFile()
.getParentFile(), file.getAbsolutePath());
}
@Override
protected SuggestedFile getSuggestedFile(BlockUml blockUml) {
final SuggestedFile suggested = SuggestedFile.fromOutputFile(outputFile, fileFormatOption.getFileFormat());
return suggested;
}
}

View File

@ -0,0 +1,170 @@
/* ========================================================================
* 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;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import net.sourceforge.plantuml.core.Diagram;
import net.sourceforge.plantuml.preproc.FileWithSuffix;
public abstract class ZSourceFileReaderAbstract {
protected File file;
protected File outputDirectory;
protected File outputFile;
protected BlockUmlBuilder builder;
protected FileFormatOption fileFormatOption;
public boolean hasError() {
for (final BlockUml b : builder.getBlockUmls()) {
if (b.getDiagram() instanceof PSystemError) {
return true;
}
}
return false;
}
public List<BlockUml> getBlocks() {
return builder.getBlockUmls();
}
protected Reader getReader(String charset) throws FileNotFoundException, UnsupportedEncodingException {
if (charset == null) {
Log.info("Using default charset");
return new InputStreamReader(new FileInputStream(file));
}
Log.info("Using charset " + charset);
return new InputStreamReader(new FileInputStream(file), charset);
}
public final Set<FileWithSuffix> getIncludedFiles() {
return builder.getIncludedFiles();
}
public final void setFileFormatOption(FileFormatOption fileFormatOption) {
this.fileFormatOption = fileFormatOption;
}
protected boolean endsWithSlashOrAntislash(String newName) {
return newName.endsWith("/") || newName.endsWith("\\");
}
protected List<GeneratedImage> getCrashedImage(BlockUml blockUml, Throwable t, File outputFile) throws IOException {
final GeneratedImage image = new GeneratedImageImpl(outputFile, "Crash Error", blockUml);
OutputStream os = null;
try {
os = new BufferedOutputStream(new FileOutputStream(outputFile));
UmlDiagram.exportDiagramError(os, t, fileFormatOption, 42, null, blockUml.getFlashData(),
UmlDiagram.getFailureText2(t, blockUml.getFlashData()));
} finally {
if (os != null) {
os.close();
}
}
return Collections.singletonList(image);
}
protected void exportWarnOrErrIfWord(final File f, final Diagram system) throws FileNotFoundException {
if (OptionFlags.getInstance().isWord()) {
final String warnOrError = system.getWarningOrError();
if (warnOrError != null) {
final String name = f.getName().substring(0, f.getName().length() - 4) + ".err";
final File errorFile = new File(f.getParentFile(), name);
final PrintStream ps = new PrintStream(new FileOutputStream(errorFile));
ps.print(warnOrError);
ps.close();
}
}
}
protected int cpt;
final public List<GeneratedImage> getGeneratedImages() throws IOException {
Log.info("Reading file: " + file);
cpt = 0;
final List<GeneratedImage> result = new ArrayList<GeneratedImage>();
for (BlockUml blockUml : builder.getBlockUmls()) {
SuggestedFile suggested = getSuggestedFile(blockUml);
final Diagram system;
try {
system = blockUml.getDiagram();
} catch (Throwable t) {
return getCrashedImage(blockUml, t, suggested.getFile(0));
}
OptionFlags.getInstance().logData(file, system);
final List<FileImageData> exportDiagrams = PSystemUtils.exportDiagrams(system, suggested, fileFormatOption);
if (exportDiagrams.size() > 1) {
cpt += exportDiagrams.size() - 1;
}
for (FileImageData fdata : exportDiagrams) {
final String desc = "[" + file.getName() + "] " + system.getDescription();
final File f = fdata.getFile();
exportWarnOrErrIfWord(f, system);
final GeneratedImage generatedImage = new GeneratedImageImpl(f, desc, blockUml);
result.add(generatedImage);
}
}
Log.info("Number of image(s): " + result.size());
return Collections.unmodifiableList(result);
}
abstract protected SuggestedFile getSuggestedFile(BlockUml blockUml);
}

View File

@ -71,6 +71,14 @@ public class Bodier {
this.manageModifier = type == null ? false : type.manageModifier();
}
public void setLeaf(ILeaf leaf) {
if (leaf == null) {
throw new IllegalArgumentException();
}
this.leaf = leaf;
}
public void addFieldOrMethod(String s, IEntity leaf) {
if (leaf == null) {
throw new IllegalArgumentException();
@ -196,6 +204,9 @@ public class Bodier {
}
return null;
}
if (leaf == null) {
throw new IllegalStateException();
}
final MethodsOrFieldsArea fields = new MethodsOrFieldsArea(getFieldsToDisplay(), fontParam, skinParam,
stereotype, leaf);
if (type == LeafType.OBJECT) {

View File

@ -77,6 +77,7 @@ public class BodyEnhanced extends AbstractTextBlock implements TextBlock, WithPo
private final List<Url> urls = new ArrayList<Url>();
private final Stereotype stereotype;
private final ILeaf entity;
private final boolean inEllipse;
public BodyEnhanced(List<String> rawBody, FontParam fontParam, ISkinParam skinParam, boolean manageModifier,
Stereotype stereotype, ILeaf entity) {
@ -91,6 +92,7 @@ public class BodyEnhanced extends AbstractTextBlock implements TextBlock, WithPo
this.manageHorizontalLine = true;
this.manageModifier = manageModifier;
this.entity = entity;
this.inEllipse = false;
}
public BodyEnhanced(Display display, FontParam fontParam, ISkinParam skinParam, HorizontalAlignment align,
@ -98,9 +100,6 @@ public class BodyEnhanced extends AbstractTextBlock implements TextBlock, WithPo
this.entity = entity;
this.stereotype = stereotype;
this.rawBody = new ArrayList<String>();
for (CharSequence s : display) {
this.rawBody.add(s.toString());
}
this.fontParam = fontParam;
this.skinParam = skinParam;
@ -109,6 +108,14 @@ public class BodyEnhanced extends AbstractTextBlock implements TextBlock, WithPo
this.align = skinParam.getDefaultTextAlignment(align);
this.manageHorizontalLine = manageHorizontalLine;
this.manageModifier = manageModifier;
this.inEllipse = fontParam == FontParam.USECASE;
if (manageHorizontalLine && inEllipse && display.size() > 0 && isBlockSeparator(display.get(0).toString())) {
this.rawBody.add("");
}
for (CharSequence s : display) {
this.rawBody.add(s.toString());
}
}
@ -166,6 +173,9 @@ public class BodyEnhanced extends AbstractTextBlock implements TextBlock, WithPo
}
}
}
if (inEllipse && members.size() == 0) {
members.add(new MemberImpl("", false, false));
}
blocks.add(decorate(stringBounder, new MethodsOrFieldsArea(members, fontParam, skinParam, align, stereotype,
entity), separator, title));

View File

@ -289,6 +289,7 @@ public abstract class CucaDiagram extends UmlDiagram implements GroupHierarchy,
this.horizontalPages = horizontalPages;
}
final public int getVerticalPages() {
return verticalPages;
}
@ -297,6 +298,13 @@ public abstract class CucaDiagram extends UmlDiagram implements GroupHierarchy,
this.verticalPages = verticalPages;
}
@Override
public int getNbImages() {
return this.horizontalPages * this.verticalPages;
}
// final public List<File> createPng2(File pngFile) throws IOException,
// InterruptedException {
// final CucaDiagramPngMaker3 maker = new CucaDiagramPngMaker3(this);
@ -569,11 +577,6 @@ public abstract class CucaDiagram extends UmlDiagram implements GroupHierarchy,
}
}
@Override
public int getNbImages() {
return this.horizontalPages * this.verticalPages;
}
public final Set<VisibilityModifier> getHides() {
return Collections.unmodifiableSet(hides);
}

View File

@ -160,9 +160,10 @@ public class Link implements Hideable, Removeable {
// }
final Link result = new Link(cl2, cl1, getType().getInversed(), label, length, qualifier2, qualifier1,
labeldistance, labelangle, specificColor);
result.inverted = true;
result.inverted = !this.inverted;
result.port1 = this.port2;
result.port2 = this.port1;
result.url = this.url;
return result;
}

View File

@ -99,6 +99,7 @@ public class EntityFactory {
final LongCode longCode = getLongCode(code, namespaceSeparator);
final EntityImpl result = new EntityImpl(this, code, bodier, parentContainer, entityType, longCode,
namespaceSeparator, rawLayout);
bodier.setLeaf(result);
result.setDisplay(display);
return result;
}

View File

@ -40,13 +40,12 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.math.BigInteger;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageInputStream;
import net.sourceforge.plantuml.webp.VP8Decoder;
public class Dedication {
private final String name;
@ -73,13 +72,21 @@ public class Dedication {
public BufferedImage getBufferedImage(String keepLetter) {
try {
final Class<?> clVP8Decoder = Class.forName("net.sourceforge.plantuml.webp.VP8Decoder");
final Object vp8Decoder = clVP8Decoder.newInstance();
// final VP8Decoder vp8Decoder = new VP8Decoder();
final Method decodeFrame = clVP8Decoder.getMethod("decodeFrame", ImageInputStream.class);
final InputStream is = getInputStream(keepLetter);
final ImageInputStream iis = ImageIO.createImageInputStream(is);
final VP8Decoder vp8Decoder = new VP8Decoder();
vp8Decoder.decodeFrame(iis, false);
decodeFrame.invoke(vp8Decoder, iis);
// vp8Decoder.decodeFrame(iis);
iis.close();
return vp8Decoder.getFrame().getBufferedImage();
final Object frame = clVP8Decoder.getMethod("getFrame").invoke(vp8Decoder);
return (BufferedImage) frame.getClass().getMethod("getBufferedImage").invoke(frame);
// final VP8Frame frame = vp8Decoder.getFrame();
// return frame.getBufferedImage();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}

View File

@ -52,6 +52,7 @@ import net.sourceforge.plantuml.cucadiagram.IEntity;
import net.sourceforge.plantuml.cucadiagram.ILeaf;
import net.sourceforge.plantuml.cucadiagram.LeafType;
import net.sourceforge.plantuml.cucadiagram.Link;
import net.sourceforge.plantuml.cucadiagram.LinkArrow;
import net.sourceforge.plantuml.cucadiagram.LinkDecor;
import net.sourceforge.plantuml.cucadiagram.LinkType;
import net.sourceforge.plantuml.cucadiagram.Stereotype;
@ -209,6 +210,7 @@ public class CommandLinkElement extends SingleLineCommand2<DescriptionDiagram> {
private String firstLabel;
private String secondLabel;
private String labelLink;
private LinkArrow linkArrow = LinkArrow.NONE;
Labels(RegexResult arg) {
firstLabel = arg.get("LABEL1", 0);
@ -220,6 +222,27 @@ public class CommandLinkElement extends SingleLineCommand2<DescriptionDiagram> {
init();
}
labelLink = StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(labelLink);
if ("<".equals(labelLink)) {
linkArrow = LinkArrow.BACKWARD;
labelLink = null;
} else if (">".equals(labelLink)) {
linkArrow = LinkArrow.DIRECT_NORMAL;
labelLink = null;
} else if (labelLink != null && labelLink.startsWith("< ")) {
linkArrow = LinkArrow.BACKWARD;
labelLink = StringUtils.trin(labelLink.substring(2));
} else if (labelLink != null && labelLink.startsWith("> ")) {
linkArrow = LinkArrow.DIRECT_NORMAL;
labelLink = StringUtils.trin(labelLink.substring(2));
} else if (labelLink != null && labelLink.endsWith(" >")) {
linkArrow = LinkArrow.DIRECT_NORMAL;
labelLink = StringUtils.trin(labelLink.substring(0, labelLink.length() - 2));
} else if (labelLink != null && labelLink.endsWith(" <")) {
linkArrow = LinkArrow.BACKWARD;
labelLink = StringUtils.trin(labelLink.substring(0, labelLink.length() - 2));
}
}
}
@ -289,7 +312,7 @@ public class CommandLinkElement extends SingleLineCommand2<DescriptionDiagram> {
Link link = new Link(cl1, cl2, linkType, Display.getWithNewlines(labels.labelLink), queue.length(),
labels.firstLabel, labels.secondLabel, diagram.getLabeldistance(), diagram.getLabelangle());
link.setLinkArrow(labels.linkArrow);
if (dir == Direction.LEFT || dir == Direction.UP) {
link = link.getInv();
}

View File

@ -364,6 +364,10 @@ public class EpsGraphics {
appendColor(fillcolor);
epsRectangleInternal(x, y, width, height, rx, ry, true);
append("closepath eofill", true);
if (dashSpace != 0 && dashVisible != 0) {
append("[] 0 setdash", true);
}
}
if (color != null) {
@ -371,6 +375,9 @@ public class EpsGraphics {
appendColor(color);
epsRectangleInternal(x, y, width, height, rx, ry, false);
append("closepath stroke", true);
if (dashSpace != 0 && dashVisible != 0) {
append("[] 0 setdash", true);
}
}
}
@ -441,20 +448,26 @@ public class EpsGraphics {
}
private void roundRectangle(double x, double y, double width, double height, double rx, double ry) {
if (dashSpace != 0 && dashVisible != 0) {
append("[" + (int) dashSpace + " " + (int) dashVisible + "] 0 setdash", true);
}
append(format(width) + " " + format(height) + " " + format(x) + " " + format(y) + " " + format((rx + ry) / 2)
+ " roundrect", true);
roundrectUsed = true;
}
private void simpleRectangle(double x, double y, double width, double height, boolean fill) {
if (dashSpace != 0 && dashVisible != 0) {
append("[" + (int) dashSpace + " " + (int) dashVisible + "] 0 setdash", true);
}
if ((dashSpace == 0 && dashVisible == 0) || fill) {
append(format(width) + " " + format(height) + " " + format(x) + " " + format(y) + " simplerect", true);
simplerectUsed = true;
} else {
epsVLine(y, x, x + width);
epsVLine(y + height, x, x + width);
epsHLine(x, y, y + height);
epsHLine(x + width, y, y + height);
// } else {
// epsVLine(y, x, x + width);
// epsVLine(y + height, x, x + width);
// epsHLine(x, y, y + height);
// epsHLine(x + width, y, y + height);
}
}

View File

@ -177,7 +177,6 @@ public class QuoteUtils {
"Fbzrgvzrf jr pbzr ynfg ohg jr qvq bhe orfg",
"Vs lbh frr fbzrguvat, fnl fbzrguvat",
"Va gurbel gurer vf ab qvssrerapr orgjrra gurbel naq cenpgvpr. Ohg, va cenpgvpr, gurer vf.",
"Qnlyvtug, V zhfg jnvg sbe gur fhaevfr. V zhfg guvax bs n arj yvsr. Naq V zhfga'g tvir va.",
"Vs V pnaabg oevat lbh pbzsbeg gura ng yrnfg V oevat lbh ubcr",
"Jr nyy zhfg yrnea sebz fznyy zvfsbeghar, pbhag gur oyrffvatf gung ner erny",
"Cercner Guerr Frnyrq Rairybcrf...",
@ -254,7 +253,11 @@ public class QuoteUtils {
"Nyy lbhe onfr ner orybat gb hf", "Znqr ba Rnegu ol uhznaf", "Jvaaref Qba'g Hfr Qehtf",
"Lbh xabj jung fhecevfrq zr gur zbfg? Vg jnfa'g zrrgvat gurz. Vg jnf zrrgvat lbh.",
"Va jne gurer ner ab jvaaref, bayl jvqbjf",
"Vs lbh guvax guvf Havirefr vf onq, lbh fubhyq frr fbzr bs gur bguref");
"Vs lbh guvax guvf Havirefr vf onq, lbh fubhyq frr fbzr bs gur bguref", "Cnp-Zna'f n onq thl?",
"Zl ernyvgl vf whfg qvssrerag guna lbhef",
"Uvfgbel vf n avtugzner sebz juvpu V nz gelvat gb njnxr",
"L'ra n dh'bag rffnlr, vyf bag rh qrf ceboyrzrf",
"Gb ree vf uhzna, ohg gb ernyyl sbhy guvatf hc erdhverf n pbzchgre.");
private QuoteUtils() {
}

View File

@ -39,7 +39,7 @@ import net.sourceforge.plantuml.ColorParam;
import net.sourceforge.plantuml.FontParam;
import net.sourceforge.plantuml.ISkinParam;
import net.sourceforge.plantuml.LineParam;
import net.sourceforge.plantuml.RoundParam;
import net.sourceforge.plantuml.CornerParam;
import net.sourceforge.plantuml.cucadiagram.Stereotype;
import net.sourceforge.plantuml.svek.RoundedContainer;
import net.sourceforge.plantuml.ugraphic.UStroke;
@ -54,7 +54,7 @@ public class SkinParameter {
public static final SkinParameter COMPONENT1 = new SkinParameter("COMPONENT1", ColorParam.componentBackground,
ColorParam.componentBorder, FontParam.COMPONENT, FontParam.COMPONENT_STEREOTYPE, LineParam.componentBorder,
RoundParam.component);
CornerParam.component);
public static final SkinParameter NODE = new SkinParameter("NODE", ColorParam.nodeBackground,
ColorParam.nodeBorder, FontParam.NODE, FontParam.NODE_STEREOTYPE);
@ -76,7 +76,7 @@ public class SkinParameter {
public static final SkinParameter COMPONENT2 = new SkinParameter("COMPONENT2", ColorParam.componentBackground,
ColorParam.componentBorder, FontParam.COMPONENT, FontParam.COMPONENT_STEREOTYPE, LineParam.componentBorder,
RoundParam.component);
CornerParam.component);
public static final SkinParameter AGENT = new SkinParameter("AGENT", ColorParam.agentBackground,
ColorParam.agentBorder, FontParam.AGENT, FontParam.AGENT_STEREOTYPE);
@ -90,12 +90,12 @@ public class SkinParameter {
public static final SkinParameter PACKAGE = new SkinParameter("PACKAGE", ColorParam.packageBackground,
ColorParam.packageBorder, FontParam.FOLDER, FontParam.FOLDER_STEREOTYPE);
public static final SkinParameter CARD = new SkinParameter("CARD", ColorParam.rectangleBackground,
ColorParam.rectangleBorder, FontParam.RECTANGLE, FontParam.RECTANGLE_STEREOTYPE);
public static final SkinParameter CARD = new SkinParameter("CARD", ColorParam.cardBackground,
ColorParam.cardBorder, FontParam.CARD, FontParam.CARD_STEREOTYPE);
public static final SkinParameter RECTANGLE = new SkinParameter("RECTANGLE", ColorParam.rectangleBackground,
ColorParam.rectangleBorder, FontParam.RECTANGLE, FontParam.RECTANGLE_STEREOTYPE, LineParam.rectangleBorder,
RoundParam.rectangle);
CornerParam.rectangle);
public static final SkinParameter COLLECTIONS = new SkinParameter("COLLECTIONS", ColorParam.collectionsBackground,
ColorParam.collectionsBorder, FontParam.RECTANGLE, FontParam.RECTANGLE_STEREOTYPE);
@ -124,10 +124,10 @@ public class SkinParameter {
private final FontParam fontParamStereotype;
private final String name;
private final LineParam lineParam;
private final RoundParam roundParam;
private final CornerParam roundParam;
private SkinParameter(String name, ColorParam colorParamBack, ColorParam colorParamBorder, FontParam fontParam,
FontParam fontParamStereotype, LineParam lineParam, RoundParam roundParam) {
FontParam fontParamStereotype, LineParam lineParam, CornerParam roundParam) {
this.name = name;
this.colorParamBack = colorParamBack;
this.colorParamBorder = colorParamBorder;
@ -139,7 +139,7 @@ public class SkinParameter {
private SkinParameter(String name, ColorParam colorParamBack, ColorParam colorParamBorder, FontParam fontParam,
FontParam fontParamStereotype) {
this(name, colorParamBack, colorParamBorder, fontParam, fontParamStereotype, null, RoundParam.DEFAULT);
this(name, colorParamBack, colorParamBorder, fontParam, fontParamStereotype, null, CornerParam.DEFAULT);
}
public String getUpperCaseName() {
@ -169,6 +169,10 @@ public class SkinParameter {
return skinParam.getRoundCorner(roundParam, stereotype);
}
public double getDiagonalCorner(ISkinParam skinParam, Stereotype stereotype) {
return skinParam.getDiagonalCorner(roundParam, stereotype);
}
public UStroke getStroke(ISkinParam skinParam, Stereotype stereotype) {
UStroke result = null;
if (lineParam != null) {

View File

@ -48,18 +48,17 @@ public class SymbolContext {
private final boolean shadowing;
private final double deltaShadow;
private final double roundCorner;
private final double diagonalCorner;
private SymbolContext(HtmlColor backColor, HtmlColor foreColor, UStroke stroke, boolean shadowing,
double deltaShadow, double roundCorner) {
double deltaShadow, double roundCorner, double diagonalCorner) {
this.backColor = backColor;
this.foreColor = foreColor;
this.stroke = stroke;
this.shadowing = shadowing;
this.deltaShadow = deltaShadow;
this.roundCorner = roundCorner;
// if (backColor instanceof HtmlColorTransparent) {
// throw new UnsupportedOperationException();
// }
this.diagonalCorner = diagonalCorner;
}
@Override
@ -85,37 +84,37 @@ public class SymbolContext {
public SymbolContext transparentBackColorToNull() {
if (backColor instanceof HtmlColorTransparent) {
return new SymbolContext(null, foreColor, stroke, shadowing, deltaShadow, roundCorner);
return new SymbolContext(null, foreColor, stroke, shadowing, deltaShadow, roundCorner, diagonalCorner);
}
return this;
}
public SymbolContext(HtmlColor backColor, HtmlColor foreColor) {
this(backColor, foreColor, new UStroke(), false, 0, 0);
this(backColor, foreColor, new UStroke(), false, 0, 0, 0);
}
public SymbolContext withShadow(boolean newShadow) {
return new SymbolContext(backColor, foreColor, stroke, newShadow, deltaShadow, roundCorner);
return new SymbolContext(backColor, foreColor, stroke, newShadow, deltaShadow, roundCorner, diagonalCorner);
}
public SymbolContext withDeltaShadow(double deltaShadow) {
return new SymbolContext(backColor, foreColor, stroke, shadowing, deltaShadow, roundCorner);
return new SymbolContext(backColor, foreColor, stroke, shadowing, deltaShadow, roundCorner, diagonalCorner);
}
public SymbolContext withStroke(UStroke newStroke) {
return new SymbolContext(backColor, foreColor, newStroke, shadowing, deltaShadow, roundCorner);
return new SymbolContext(backColor, foreColor, newStroke, shadowing, deltaShadow, roundCorner, diagonalCorner);
}
public SymbolContext withBackColor(HtmlColor backColor) {
return new SymbolContext(backColor, foreColor, stroke, shadowing, deltaShadow, roundCorner);
return new SymbolContext(backColor, foreColor, stroke, shadowing, deltaShadow, roundCorner, diagonalCorner);
}
public SymbolContext withForeColor(HtmlColor foreColor) {
return new SymbolContext(backColor, foreColor, stroke, shadowing, deltaShadow, roundCorner);
return new SymbolContext(backColor, foreColor, stroke, shadowing, deltaShadow, roundCorner, diagonalCorner);
}
public SymbolContext withRoundCorner(double roundCorner) {
return new SymbolContext(backColor, foreColor, stroke, shadowing, deltaShadow, roundCorner);
public SymbolContext withCorner(double roundCorner, double diagonalCorner) {
return new SymbolContext(backColor, foreColor, stroke, shadowing, deltaShadow, roundCorner, diagonalCorner);
}
public HtmlColor getBackColor() {
@ -142,4 +141,8 @@ public class SymbolContext {
return roundCorner;
}
public double getDiagonalCorner() {
return diagonalCorner;
}
}

View File

@ -49,7 +49,7 @@ import net.sourceforge.plantuml.ColorParam;
import net.sourceforge.plantuml.Dimension2DDouble;
import net.sourceforge.plantuml.ISkinParam;
import net.sourceforge.plantuml.LineParam;
import net.sourceforge.plantuml.RoundParam;
import net.sourceforge.plantuml.CornerParam;
import net.sourceforge.plantuml.cucadiagram.Display;
import net.sourceforge.plantuml.posimo.Positionable;
import net.sourceforge.plantuml.posimo.PositionableImpl;
@ -82,7 +82,7 @@ public class TextBlockUtils {
if (borderColor == null) {
borderColor = HtmlColorUtils.BLACK;
}
final double corner = skinParam.getRoundCorner(RoundParam.titleBorder, null);
final double corner = skinParam.getRoundCorner(CornerParam.titleBorder, null);
return withMargin(bordered(result, stroke, borderColor, backgroundColor, corner), 2, 2);
}

View File

@ -38,8 +38,10 @@ package net.sourceforge.plantuml.graphic;
import java.awt.geom.Dimension2D;
import net.sourceforge.plantuml.Dimension2DDouble;
import net.sourceforge.plantuml.ugraphic.Shadowable;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.UGraphicStencil;
import net.sourceforge.plantuml.ugraphic.UPath;
import net.sourceforge.plantuml.ugraphic.URectangle;
import net.sourceforge.plantuml.ugraphic.UStroke;
import net.sourceforge.plantuml.ugraphic.UTranslate;
@ -64,14 +66,30 @@ class USymbolRect extends USymbol {
return skinParameter;
}
private void drawRect(UGraphic ug, double width, double height, boolean shadowing, double roundCorner) {
final URectangle shape = new URectangle(width, height, roundCorner, roundCorner);
private void drawRect(UGraphic ug, double width, double height, boolean shadowing, double roundCorner,
double diagonalCorner) {
final Shadowable shape = diagonalCorner > 0 ? getDiagonalShape(width, height, diagonalCorner) : new URectangle(
width, height, roundCorner, roundCorner);
if (shadowing) {
shape.setDeltaShadow(3.0);
}
ug.draw(shape);
}
private Shadowable getDiagonalShape(double width, double height, double diagonalCorner) {
final UPath result = new UPath();
result.moveTo(diagonalCorner, 0);
result.lineTo(width - diagonalCorner, 0);
result.lineTo(width, diagonalCorner);
result.lineTo(width, height - diagonalCorner);
result.lineTo(width - diagonalCorner, height);
result.lineTo(diagonalCorner, height);
result.lineTo(0, height - diagonalCorner);
result.lineTo(0, diagonalCorner);
result.lineTo(diagonalCorner, 0);
return result;
}
private Margin getMargin() {
return new Margin(10, 10, 10, 10);
}
@ -86,7 +104,7 @@ class USymbolRect extends USymbol {
ug = UGraphicStencil.create(ug, getRectangleStencil(dim), new UStroke());
ug = symbolContext.apply(ug);
drawRect(ug, dim.getWidth(), dim.getHeight(), symbolContext.isShadowing(),
symbolContext.getRoundCorner());
symbolContext.getRoundCorner(), symbolContext.getDiagonalCorner());
final Margin margin = getMargin();
final TextBlock tb = TextBlockUtils.mergeTB(stereotype, label, stereotypeAlignement);
tb.drawU(ug.apply(new UTranslate(margin.getX1(), margin.getY1())));
@ -108,7 +126,7 @@ class USymbolRect extends USymbol {
final Dimension2D dim = calculateDimension(ug.getStringBounder());
ug = symbolContext.apply(ug);
drawRect(ug, dim.getWidth(), dim.getHeight(), symbolContext.isShadowing(),
symbolContext.getRoundCorner());
symbolContext.getRoundCorner(), 0);
final Dimension2D dimStereo = stereotype.calculateDimension(ug.getStringBounder());
final double posStereoX;
final double posStereoY;

View File

@ -1,6 +1,5 @@
package net.sourceforge.plantuml.jasic;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
@ -12,101 +11,106 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* This defines a single class that contains an entire interpreter for a
* language very similar to the original BASIC. Everything is here (albeit in
* very simplified form): tokenizing, parsing, and interpretation. The file is
* organized in phases, with each appearing roughly in the order that they
* occur when a program is run. You should be able to read this top-down to walk
* through the entire process of loading and running a program.
/*
Jasic uses the MIT License:
Copyright (c) 2010 Robert Nystrom
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Jasic language syntax
* ---------------------
*/
/*
* This defines a single class that contains an entire interpreter for a language very similar to the original BASIC.
* Everything is here (albeit in very simplified form): tokenizing, parsing, and interpretation. The file is organized
* in phases, with each appearing roughly in the order that they occur when a program is run. You should be able to read
* this top-down to walk through the entire process of loading and running a program.
*
* Jasic language syntax ---------------------
*
* Comments start with ' and proceed to the end of the line:
*
* print "hi there" ' this is a comment
*
* Numbers and strings are supported. Strings should be in "double quotes", and
* only positive integers can be parsed (though numbers are double internally).
* Numbers and strings are supported. Strings should be in "double quotes", and only positive integers can be parsed
* (though numbers are double internally).
*
* Variables are identified by name which must start with a letter and can
* contain letters or numbers. Case is significant for names and keywords.
* Variables are identified by name which must start with a letter and can contain letters or numbers. Case is
* significant for names and keywords.
*
* Each statement is on its own line. Optionally, a line may have a label before
* the statement. A label is a name that ends with a colon:
* Each statement is on its own line. Optionally, a line may have a label before the statement. A label is a name that
* ends with a colon:
*
* foo:
*
*
* The following statements are supported:
*
* <name> = <expression>
* Evaluates the expression and assigns the result to the given named
* variable. All variables are globally scoped.
* <name> = <expression> Evaluates the expression and assigns the result to the given named variable. All variables are
* globally scoped.
*
* pi = (314159 / 10000)
*
* print <expression>
* Evaluates the expression and prints the result.
* print <expression> Evaluates the expression and prints the result.
*
* print "hello, " + "world"
*
* input <name>
* Reads in a line of input from the user and stores it in the variable with
* the given name.
* input <name> Reads in a line of input from the user and stores it in the variable with the given name.
*
* input guess
*
* goto <label>
* Jumps to the statement after the label with the given name.
* goto <label> Jumps to the statement after the label with the given name.
*
* goto loop
*
* if <expression> then <label>
* Evaluates the expression. If it evaluates to a non-zero number, then
* jumps to the statement after the given label.
* if <expression> then <label> Evaluates the expression. If it evaluates to a non-zero number, then jumps to the
* statement after the given label.
*
* if a < b then dosomething
*
*
* The following expressions are supported:
*
* <expression> = <expression>
* Evaluates to 1 if the two expressions are equal, 0 otherwise.
* <expression> = <expression> Evaluates to 1 if the two expressions are equal, 0 otherwise.
*
* <expression> + <expression>
* If the left-hand expression is a number, then adds the two expressions,
* otherwise concatenates the two strings.
* <expression> + <expression> If the left-hand expression is a number, then adds the two expressions, otherwise
* concatenates the two strings.
*
* <expression> - <expression>
* <expression> * <expression>
* <expression> / <expression>
* <expression> < <expression>
* <expression> > <expression>
* You can figure it out.
* <expression> - <expression> <expression> * <expression> <expression> / <expression> <expression> < <expression>
* <expression> > <expression> You can figure it out.
*
* <name>
* A name in an expression simply returns the value of the variable with
* that name. If the variable was never set, it defaults to 0.
* <name> A name in an expression simply returns the value of the variable with that name. If the variable was never
* set, it defaults to 0.
*
* All binary operators have the same precedence. Sorry, I had to cut corners
* somewhere.
* All binary operators have the same precedence. Sorry, I had to cut corners somewhere.
*
* To keep things simple, I've omitted some stuff or hacked things a bit. When
* possible, I'll leave a "HACK" note there explaining what and why. If you
* make your own interpreter, you'll want to address those.
* To keep things simple, I've omitted some stuff or hacked things a bit. When possible, I'll leave a "HACK" note there
* explaining what and why. If you make your own interpreter, you'll want to address those.
*
* @author Bob Nystrom
*/
public class Jasic {
/**
* Runs the interpreter as a command-line app. Takes one argument: a path
* to a script file to load and run. The script should contain one
* statement per line.
* Runs the interpreter as a command-line app. Takes one argument: a path to a script file to load and run. The
* script should contain one statement per line.
*
* @param args Command-line arguments.
* @param args
* Command-line arguments.
*/
public static void main(String[] args) {
// Just show the usage and quit if a script wasn't provided.
@ -127,9 +131,8 @@ public class Jasic {
// Tokenizing (lexing) -----------------------------------------------------
/**
* This function takes a script as a string of characters and chunks it into
* a sequence of tokens. Each token is a meaningful unit of program, like a
* variable name, a number, a string, or an operator.
* This function takes a script as a string of characters and chunks it into a sequence of tokens. Each token is a
* meaningful unit of program, like a variable name, a number, a string, or an operator.
*/
private static List<Token> tokenize(String source) {
List<Token> tokens = new ArrayList<Token>();
@ -139,11 +142,9 @@ public class Jasic {
// Many tokens are a single character, like operators and ().
String charTokens = "\n=+-*/<>()";
TokenType[] tokenTypes = { TokenType.LINE, TokenType.EQUALS,
TokenType.OPERATOR, TokenType.OPERATOR, TokenType.OPERATOR,
TokenType.OPERATOR, TokenType.OPERATOR, TokenType.OPERATOR,
TokenType.LEFT_PAREN, TokenType.RIGHT_PAREN
};
TokenType[] tokenTypes = { TokenType.LINE, TokenType.EQUALS, TokenType.OPERATOR, TokenType.OPERATOR,
TokenType.OPERATOR, TokenType.OPERATOR, TokenType.OPERATOR, TokenType.OPERATOR, TokenType.LEFT_PAREN,
TokenType.RIGHT_PAREN };
// Scan through the code one character at a time, building up the list
// of tokens.
@ -152,8 +153,7 @@ public class Jasic {
switch (state) {
case DEFAULT:
if (charTokens.indexOf(c) != -1) {
tokens.add(new Token(Character.toString(c),
tokenTypes[charTokens.indexOf(c)]));
tokens.add(new Token(Character.toString(c), tokenTypes[charTokens.indexOf(c)]));
} else if (Character.isLetter(c)) {
token += c;
state = TokenizeState.WORD;
@ -223,22 +223,18 @@ public class Jasic {
// Token data --------------------------------------------------------------
/**
* This defines the different kinds of tokens or meaningful chunks of code
* that the parser knows how to consume. These let us distinguish, for
* example, between a string "foo" and a variable named "foo".
* This defines the different kinds of tokens or meaningful chunks of code that the parser knows how to consume.
* These let us distinguish, for example, between a string "foo" and a variable named "foo".
*
* HACK: A typical tokenizer would actually have unique token types for
* each keyword (print, goto, etc.) so that the parser doesn't have to look
* at the names, but Jasic is a little more crude.
* HACK: A typical tokenizer would actually have unique token types for each keyword (print, goto, etc.) so that the
* parser doesn't have to look at the names, but Jasic is a little more crude.
*/
private enum TokenType {
WORD, NUMBER, STRING, LABEL, LINE,
EQUALS, OPERATOR, LEFT_PAREN, RIGHT_PAREN, EOF
WORD, NUMBER, STRING, LABEL, LINE, EQUALS, OPERATOR, LEFT_PAREN, RIGHT_PAREN, EOF
}
/**
* This is a single meaningful chunk of code. It is created by the tokenizer
* and consumed by the parser.
* This is a single meaningful chunk of code. It is created by the tokenizer and consumed by the parser.
*/
private static class Token {
public Token(String text, TokenType type) {
@ -251,15 +247,13 @@ public class Jasic {
}
/**
* This defines the different states the tokenizer can be in while it's
* scanning through the source code. Tokenizers are state machines, which
* means the only data they need to store is where they are in the source
* code and this one "state" or mode value.
* This defines the different states the tokenizer can be in while it's scanning through the source code. Tokenizers
* are state machines, which means the only data they need to store is where they are in the source code and this
* one "state" or mode value.
*
* One of the main differences between tokenizing and parsing is this
* regularity. Because the tokenizer stores only this one state value, it
* can't handle nesting (which would require also storing a number to
* identify how deeply nested you are). The parser is able to handle that.
* One of the main differences between tokenizing and parsing is this regularity. Because the tokenizer stores only
* this one state value, it can't handle nesting (which would require also storing a number to identify how deeply
* nested you are). The parser is able to handle that.
*/
private enum TokenizeState {
DEFAULT, WORD, NUMBER, STRING, COMMENT
@ -268,14 +262,13 @@ public class Jasic {
// Parsing -----------------------------------------------------------------
/**
* This defines the Jasic parser. The parser takes in a sequence of tokens
* and generates an abstract syntax tree. This is the nested data structure
* that represents the series of statements, and the expressions (which can
* nest arbitrarily deeply) that they evaluate. In technical terms, what we
* have is a recursive descent parser, the simplest kind to hand-write.
* This defines the Jasic parser. The parser takes in a sequence of tokens and generates an abstract syntax tree.
* This is the nested data structure that represents the series of statements, and the expressions (which can nest
* arbitrarily deeply) that they evaluate. In technical terms, what we have is a recursive descent parser, the
* simplest kind to hand-write.
*
* As a side-effect, this phase also stores off the line numbers for each
* label in the program. It's a bit gross, but it works.
* As a side-effect, this phase also stores off the line numbers for each label in the program. It's a bit gross,
* but it works.
*/
private class Parser {
public Parser(List<Token> tokens) {
@ -284,12 +277,11 @@ public class Jasic {
}
/**
* The top-level function to start parsing. This will keep consuming
* tokens and routing to the other parse functions for the different
* grammar syntax until we run out of code to parse.
* The top-level function to start parsing. This will keep consuming tokens and routing to the other parse
* functions for the different grammar syntax until we run out of code to parse.
*
* @param labels A map of label names to statement indexes. The
* parser will fill this in as it scans the code.
* @param labels
* A map of label names to statement indexes. The parser will fill this in as it scans the code.
* @return The list of parsed statements.
*/
public List<Statement> parse(Map<String, Integer> labels) {
@ -297,7 +289,8 @@ public class Jasic {
while (true) {
// Ignore empty lines.
while (match(TokenType.LINE));
while (match(TokenType.LINE))
;
if (match(TokenType.LABEL)) {
// Mark the index of the statement after the label.
@ -309,17 +302,16 @@ public class Jasic {
} else if (match("print")) {
statements.add(new PrintStatement(expression()));
} else if (match("input")) {
statements.add(new InputStatement(
consume(TokenType.WORD).text));
statements.add(new InputStatement(consume(TokenType.WORD).text));
} else if (match("goto")) {
statements.add(new GotoStatement(
consume(TokenType.WORD).text));
statements.add(new GotoStatement(consume(TokenType.WORD).text));
} else if (match("if")) {
Expression condition = expression();
consume("then");
String label = consume(TokenType.WORD).text;
statements.add(new IfThenStatement(condition, label));
} else break; // Unexpected token (likely EOF), so end.
} else
break; // Unexpected token (likely EOF), so end.
}
return statements;
@ -330,9 +322,8 @@ public class Jasic {
// noun() and verb().
/**
* Parses a single expression. Recursive descent parsers start with the
* lowest-precedent term and moves towards higher precedence. For Jasic,
* binary operators (+, -, etc.) are the lowest.
* Parses a single expression. Recursive descent parsers start with the lowest-precedent term and moves towards
* higher precedence. For Jasic, binary operators (+, -, etc.) are the lowest.
*
* @return The parsed expression.
*/
@ -341,24 +332,16 @@ public class Jasic {
}
/**
* Parses a series of binary operator expressions into a single
* expression. In Jasic, all operators have the same predecence and
* associate left-to-right. That means it will interpret:
* 1 + 2 * 3 - 4 / 5
* like:
* ((((1 + 2) * 3) - 4) / 5)
* Parses a series of binary operator expressions into a single expression. In Jasic, all operators have the
* same predecence and associate left-to-right. That means it will interpret: 1 + 2 * 3 - 4 / 5 like: ((((1 + 2)
* * 3) - 4) / 5)
*
* It works by building the expression tree one at a time. So, given
* this code: 1 + 2 * 3, this will:
* It works by building the expression tree one at a time. So, given this code: 1 + 2 * 3, this will:
*
* 1. Parse (1) as an atomic expression.
* 2. See the (+) and start a new operator expression.
* 3. Parse (2) as an atomic expression.
* 4. Build a (1 + 2) expression and replace (1) with it.
* 5. See the (*) and start a new operator expression.
* 6. Parse (3) as an atomic expression.
* 7. Build a ((1 + 2) * 3) expression and replace (1 + 2) with it.
* 8. Return the last expression built.
* 1. Parse (1) as an atomic expression. 2. See the (+) and start a new operator expression. 3. Parse (2) as an
* atomic expression. 4. Build a (1 + 2) expression and replace (1) with it. 5. See the (*) and start a new
* operator expression. 6. Parse (3) as an atomic expression. 7. Build a ((1 + 2) * 3) expression and replace (1
* + 2) with it. 8. Return the last expression built.
*
* @return The parsed expression.
*/
@ -366,8 +349,7 @@ public class Jasic {
Expression expression = atomic();
// Keep building operator expressions as long as we have operators.
while (match(TokenType.OPERATOR) ||
match(TokenType.EQUALS)) {
while (match(TokenType.OPERATOR) || match(TokenType.EQUALS)) {
char operator = last(1).text.charAt(0);
Expression right = atomic();
expression = new OperatorExpression(expression, operator, right);
@ -377,9 +359,8 @@ public class Jasic {
}
/**
* Parses an "atomic" expression. This is the highest level of
* precedence and contains single literal tokens like 123 and "foo", as
* well as parenthesized expressions.
* Parses an "atomic" expression. This is the highest level of precedence and contains single literal tokens
* like 123 and "foo", as well as parenthesized expressions.
*
* @return The parsed expression.
*/
@ -408,16 +389,19 @@ public class Jasic {
// the token stream.
/**
* Consumes the next two tokens if they are the given type (in order).
* Consumes no tokens if either check fais.
* Consumes the next two tokens if they are the given type (in order). Consumes no tokens if either check fais.
*
* @param type1 Expected type of the next token.
* @param type2 Expected type of the subsequent token.
* @param type1
* Expected type of the next token.
* @param type2
* Expected type of the subsequent token.
* @return True if tokens were consumed.
*/
private boolean match(TokenType type1, TokenType type2) {
if (get(0).type != type1) return false;
if (get(1).type != type2) return false;
if (get(0).type != type1)
return false;
if (get(1).type != type2)
return false;
position += 2;
return true;
}
@ -425,11 +409,13 @@ public class Jasic {
/**
* Consumes the next token if it's the given type.
*
* @param type Expected type of the next token.
* @param type
* Expected type of the next token.
* @return True if the token was consumed.
*/
private boolean match(TokenType type) {
if (get(0).type != type) return false;
if (get(0).type != type)
return false;
position++;
return true;
}
@ -437,47 +423,52 @@ public class Jasic {
/**
* Consumes the next token if it's a word token with the given name.
*
* @param name Expected name of the next word token.
* @param name
* Expected name of the next word token.
* @return True if the token was consumed.
*/
private boolean match(String name) {
if (get(0).type != TokenType.WORD) return false;
if (!get(0).text.equals(name)) return false;
if (get(0).type != TokenType.WORD)
return false;
if (!get(0).text.equals(name))
return false;
position++;
return true;
}
/**
* Consumes the next token if it's the given type. If not, throws an
* exception. This is for cases where the parser demands a token of a
* certain type in a certain position, for example a matching ) after
* an opening (.
* Consumes the next token if it's the given type. If not, throws an exception. This is for cases where the
* parser demands a token of a certain type in a certain position, for example a matching ) after an opening (.
*
* @param type Expected type of the next token.
* @param type
* Expected type of the next token.
* @return The consumed token.
*/
private Token consume(TokenType type) {
if (get(0).type != type) throw new Error("Expected " + type + ".");
if (get(0).type != type)
throw new Error("Expected " + type + ".");
return tokens.get(position++);
}
/**
* Consumes the next token if it's a word with the given name. If not,
* throws an exception.
* Consumes the next token if it's a word with the given name. If not, throws an exception.
*
* @param name Expected name of the next word token.
* @param name
* Expected name of the next word token.
* @return The consumed token.
*/
private Token consume(String name) {
if (!match(name)) throw new Error("Expected " + name + ".");
if (!match(name))
throw new Error("Expected " + name + ".");
return last(1);
}
/**
* Gets a previously consumed token, indexing backwards. last(1) will
* be the token just consumed, last(2) the one before that, etc.
* Gets a previously consumed token, indexing backwards. last(1) will be the token just consumed, last(2) the
* one before that, etc.
*
* @param offset How far back in the token stream to look.
* @param offset
* How far back in the token stream to look.
* @return The consumed token.
*/
private Token last(int offset) {
@ -485,10 +476,11 @@ public class Jasic {
}
/**
* Gets an unconsumed token, indexing forward. get(0) will be the next
* token to be consumed, get(1) the one after that, etc.
* Gets an unconsumed token, indexing forward. get(0) will be the next token to be consumed, get(1) the one
* after that, etc.
*
* @param offset How far forward in the token stream to look.
* @param offset
* How far forward in the token stream to look.
* @return The yet-to-be-consumed token.
*/
private Token get(int offset) {
@ -513,29 +505,25 @@ public class Jasic {
// separated out so that the AST us just a static data structure.
/**
* Base interface for a Jasic statement. The different supported statement
* types like "print" and "goto" implement this.
* Base interface for a Jasic statement. The different supported statement types like "print" and "goto" implement
* this.
*/
public interface Statement {
/**
* Statements implement this to actually perform whatever behavior the
* statement causes. "print" statements will display text here, "goto"
* statements will change the current statement, etc.
* Statements implement this to actually perform whatever behavior the statement causes. "print" statements will
* display text here, "goto" statements will change the current statement, etc.
*/
void execute();
}
/**
* Base interface for an expression. An expression is like a statement
* except that it also returns a value when executed. Expressions do not
* appear at the top level in Jasic programs, but are used in many
* statements. For example, the value printed by a "print" statement is an
* expression. Unlike statements, expressions can nest.
* Base interface for an expression. An expression is like a statement except that it also returns a value when
* executed. Expressions do not appear at the top level in Jasic programs, but are used in many statements. For
* example, the value printed by a "print" statement is an expression. Unlike statements, expressions can nest.
*/
public interface Expression {
/**
* Expression classes implement this to evaluate the expression and
* return the value.
* Expression classes implement this to evaluate the expression and return the value.
*
* @return The value of the calculated expression.
*/
@ -543,8 +531,7 @@ public class Jasic {
}
/**
* A "print" statement evaluates an expression, converts the result to a
* string, and displays it to the user.
* A "print" statement evaluates an expression, converts the result to a string, and displays it to the user.
*/
public class PrintStatement implements Statement {
public PrintStatement(Expression expression) {
@ -559,8 +546,7 @@ public class Jasic {
}
/**
* An "input" statement reads input from the user and stores it in a
* variable.
* An "input" statement reads input from the user and stores it in a variable.
*/
public class InputStatement implements Statement {
public InputStatement(String name) {
@ -587,8 +573,7 @@ public class Jasic {
}
/**
* An assignment statement evaluates an expression and stores the result in
* a variable.
* An assignment statement evaluates an expression and stores the result in a variable.
*/
public class AssignStatement implements Statement {
public AssignStatement(String name, Expression value) {
@ -622,8 +607,8 @@ public class Jasic {
}
/**
* An if then statement jumps execution to another place in the program, but
* only if an expression evaluates to something other than 0.
* An if then statement jumps execution to another place in the program, but only if an expression evaluates to
* something other than 0.
*/
public class IfThenStatement implements Statement {
public IfThenStatement(Expression condition, String label) {
@ -645,8 +630,7 @@ public class Jasic {
}
/**
* A variable expression evaluates to the current value stored in that
* variable.
* A variable expression evaluates to the current value stored in that variable.
*/
public class VariableExpression implements Expression {
public VariableExpression(String name) {
@ -664,12 +648,10 @@ public class Jasic {
}
/**
* An operator expression evaluates two expressions and then performs some
* arithmetic operation on the results.
* An operator expression evaluates two expressions and then performs some arithmetic operation on the results.
*/
public class OperatorExpression implements Expression {
public OperatorExpression(Expression left, char operator,
Expression right) {
public OperatorExpression(Expression left, char operator, Expression right) {
this.left = left;
this.operator = operator;
this.right = right;
@ -683,48 +665,37 @@ public class Jasic {
case '=':
// Coerce to the left argument's type, then compare.
if (leftVal instanceof NumberValue) {
return new NumberValue((leftVal.toNumber() ==
rightVal.toNumber()) ? 1 : 0);
return new NumberValue((leftVal.toNumber() == rightVal.toNumber()) ? 1 : 0);
} else {
return new NumberValue(leftVal.toString().equals(
rightVal.toString()) ? 1 : 0);
return new NumberValue(leftVal.toString().equals(rightVal.toString()) ? 1 : 0);
}
case '+':
// Addition if the left argument is a number, otherwise do
// string concatenation.
if (leftVal instanceof NumberValue) {
return new NumberValue(leftVal.toNumber() +
rightVal.toNumber());
return new NumberValue(leftVal.toNumber() + rightVal.toNumber());
} else {
return new StringValue(leftVal.toString() +
rightVal.toString());
return new StringValue(leftVal.toString() + rightVal.toString());
}
case '-':
return new NumberValue(leftVal.toNumber() -
rightVal.toNumber());
return new NumberValue(leftVal.toNumber() - rightVal.toNumber());
case '*':
return new NumberValue(leftVal.toNumber() *
rightVal.toNumber());
return new NumberValue(leftVal.toNumber() * rightVal.toNumber());
case '/':
return new NumberValue(leftVal.toNumber() /
rightVal.toNumber());
return new NumberValue(leftVal.toNumber() / rightVal.toNumber());
case '<':
// Coerce to the left argument's type, then compare.
if (leftVal instanceof NumberValue) {
return new NumberValue((leftVal.toNumber() <
rightVal.toNumber()) ? 1 : 0);
return new NumberValue((leftVal.toNumber() < rightVal.toNumber()) ? 1 : 0);
} else {
return new NumberValue((leftVal.toString().compareTo(
rightVal.toString()) < 0) ? 1 : 0);
return new NumberValue((leftVal.toString().compareTo(rightVal.toString()) < 0) ? 1 : 0);
}
case '>':
// Coerce to the left argument's type, then compare.
if (leftVal instanceof NumberValue) {
return new NumberValue((leftVal.toNumber() >
rightVal.toNumber()) ? 1 : 0);
return new NumberValue((leftVal.toNumber() > rightVal.toNumber()) ? 1 : 0);
} else {
return new NumberValue((leftVal.toString().compareTo(
rightVal.toString()) > 0) ? 1 : 0);
return new NumberValue((leftVal.toString().compareTo(rightVal.toString()) > 0) ? 1 : 0);
}
}
throw new Error("Unknown operator.");
@ -738,30 +709,25 @@ public class Jasic {
// Value types -------------------------------------------------------------
/**
* This is the base interface for a value. Values are the data that the
* interpreter processes. They are what gets stored in variables, printed,
* and operated on.
* This is the base interface for a value. Values are the data that the interpreter processes. They are what gets
* stored in variables, printed, and operated on.
*
* There is an implementation of this interface for each of the different
* primitive types (really just double and string) that Jasic supports.
* Wrapping them in a single Value interface lets Jasic be dynamically-typed
* and convert between different representations as needed.
* There is an implementation of this interface for each of the different primitive types (really just double and
* string) that Jasic supports. Wrapping them in a single Value interface lets Jasic be dynamically-typed and
* convert between different representations as needed.
*
* Note that Value extends Expression. This is a bit of a hack, but it lets
* us use values (which are typically only ever seen by the interpreter and
* not the parser) as both runtime values, and as object representing
* literals in code.
* Note that Value extends Expression. This is a bit of a hack, but it lets us use values (which are typically only
* ever seen by the interpreter and not the parser) as both runtime values, and as object representing literals in
* code.
*/
public interface Value extends Expression {
/**
* Value types override this to convert themselves to a string
* representation.
* Value types override this to convert themselves to a string representation.
*/
String toString();
/**
* Value types override this to convert themselves to a numeric
* representation.
* Value types override this to convert themselves to a numeric representation.
*/
double toNumber();
}
@ -774,9 +740,18 @@ public class Jasic {
this.value = value;
}
@Override public String toString() { return Double.toString(value); }
public double toNumber() { return value; }
public Value evaluate() { return this; }
@Override
public String toString() {
return Double.toString(value);
}
public double toNumber() {
return value;
}
public Value evaluate() {
return this;
}
private final double value;
}
@ -789,9 +764,18 @@ public class Jasic {
this.value = value;
}
@Override public String toString() { return value; }
public double toNumber() { return Double.parseDouble(value); }
public Value evaluate() { return this; }
@Override
public String toString() {
return value;
}
public double toNumber() {
return Double.parseDouble(value);
}
public Value evaluate() {
return this;
}
private final String value;
}
@ -799,9 +783,8 @@ public class Jasic {
// Interpreter -------------------------------------------------------------
/**
* Constructs a new Jasic instance. The instance stores the global state of
* the interpreter such as the values of all of the variables and the
* current statement.
* Constructs a new Jasic instance. The instance stores the global state of the interpreter such as the values of
* all of the variables and the current statement.
*/
public Jasic() {
variables = new HashMap<String, Value>();
@ -812,17 +795,15 @@ public class Jasic {
}
/**
* This is where the magic happens. This runs the code through the parsing
* pipeline to generate the AST. Then it executes each statement. It keeps
* track of the current line in a member variable that the statement objects
* have access to. This lets "goto" and "if then" do flow control by simply
* setting the index of the current statement.
* This is where the magic happens. This runs the code through the parsing pipeline to generate the AST. Then it
* executes each statement. It keeps track of the current line in a member variable that the statement objects have
* access to. This lets "goto" and "if then" do flow control by simply setting the index of the current statement.
*
* In an interpreter that didn't mix the interpretation logic in with the
* AST node classes, this would be doing a lot more work.
* In an interpreter that didn't mix the interpretation logic in with the AST node classes, this would be doing a
* lot more work.
*
* @param source A string containing the source code of a .jas script to
* interpret.
* @param source
* A string containing the source code of a .jas script to interpret.
*/
public void interpret(String source) {
// Tokenize.
@ -851,10 +832,10 @@ public class Jasic {
// Utility stuff -----------------------------------------------------------
/**
* Reads the file from the given path and returns its contents as a single
* string.
* Reads the file from the given path and returns its contents as a single string.
*
* @param path Path to the text file to read.
* @param path
* Path to the text file to read.
* @return The contents of the file or null if the load failed.
* @throws IOException
*/
@ -863,8 +844,7 @@ public class Jasic {
FileInputStream stream = new FileInputStream(path);
try {
InputStreamReader input = new InputStreamReader(stream,
Charset.defaultCharset());
InputStreamReader input = new InputStreamReader(stream, Charset.defaultCharset());
Reader reader = new BufferedReader(input);
StringBuilder builder = new StringBuilder();

View File

@ -0,0 +1,74 @@
/* ========================================================================
* 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 net.sourceforge.plantuml.command.CommandExecutionResult;
import net.sourceforge.plantuml.command.SingleLineCommand2;
import net.sourceforge.plantuml.command.regex.RegexConcat;
import net.sourceforge.plantuml.command.regex.RegexLeaf;
import net.sourceforge.plantuml.command.regex.RegexResult;
public class CommandGanttArrow2 extends SingleLineCommand2<GanttDiagram> {
public CommandGanttArrow2() {
super(getRegexConcat());
}
static RegexConcat getRegexConcat() {
return new RegexConcat(new RegexLeaf("^"), //
new RegexLeaf("TASK1", "\\[([^\\[\\]]+?)\\]"), //
new RegexLeaf("[%s]*"), //
new RegexLeaf("ARROW", "(-+)\\>"), //
new RegexLeaf("[%s]*"), //
new RegexLeaf("TASK2", "\\[([^\\[\\]]+?)\\]"), //
new RegexLeaf("[%s]*"), //
new RegexLeaf("$"));
}
@Override
protected CommandExecutionResult executeArg(GanttDiagram diagram, RegexResult arg) {
final String name1 = arg.get("TASK1", 0);
final String name2 = arg.get("TASK2", 0);
final Task task1 = diagram.getOrCreateTask(name1, null, false);
final Task task2 = diagram.getOrCreateTask(name2, null, false);
diagram.setTaskOrder(task1, task2);
return CommandExecutionResult.ok();
}
}

View File

@ -0,0 +1,63 @@
/* ========================================================================
* 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.List;
import net.sourceforge.plantuml.classdiagram.AbstractEntityDiagram;
import net.sourceforge.plantuml.command.CommandExecutionResult;
import net.sourceforge.plantuml.command.SingleLineCommand;
public class CommandPage extends SingleLineCommand<GanttDiagram> {
public CommandPage() {
super("(?i)^page[%s]+(\\d+)[%s]*x[%s]*(\\d+)$");
}
@Override
protected CommandExecutionResult executeArg(GanttDiagram diagram, List<String> arg) {
final int horizontal = Integer.parseInt(arg.get(0));
final int vertical = Integer.parseInt(arg.get(1));
if (horizontal <= 0 || vertical <= 0) {
return CommandExecutionResult.error("Argument must be positive");
}
diagram.setHorizontalPages(horizontal);
diagram.setVerticalPages(vertical);
return CommandExecutionResult.ok();
}
}

View File

@ -0,0 +1,65 @@
/* ========================================================================
* 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 net.sourceforge.plantuml.command.CommandExecutionResult;
import net.sourceforge.plantuml.command.SingleLineCommand2;
import net.sourceforge.plantuml.command.regex.RegexConcat;
import net.sourceforge.plantuml.command.regex.RegexLeaf;
import net.sourceforge.plantuml.command.regex.RegexResult;
public class CommandSeparator extends SingleLineCommand2<GanttDiagram> {
public CommandSeparator() {
super(getRegexConcat());
}
static RegexConcat getRegexConcat() {
return new RegexConcat(new RegexLeaf("^"), //
new RegexLeaf("--"), //
new RegexLeaf("[%s]*"), //
new RegexLeaf("COMMENT", "((.+?)[%s]*--)?"), //
new RegexLeaf("$"));
}
@Override
protected CommandExecutionResult executeArg(GanttDiagram diagram, RegexResult arg) {
final String comment = arg.get("COMMENT", 1);
diagram.addSeparator(comment);
return CommandExecutionResult.ok();
}
}

View File

@ -42,7 +42,7 @@ import net.sourceforge.plantuml.command.regex.RegexResult;
public class ComplementClose implements ComplementPattern {
public IRegex toRegex(String suffix) {
return new RegexLeaf("ADAY" + suffix, "(closed?)");
return new RegexLeaf("CLOSED" + suffix, "(closed?)");
}
public Failable<Complement> getComplement(GanttDiagram system, RegexResult arg, String suffix) {

View File

@ -0,0 +1,91 @@
/* ========================================================================
* 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 net.sourceforge.plantuml.command.regex.IRegex;
import net.sourceforge.plantuml.command.regex.RegexConcat;
import net.sourceforge.plantuml.command.regex.RegexLeaf;
import net.sourceforge.plantuml.command.regex.RegexOr;
import net.sourceforge.plantuml.command.regex.RegexResult;
public class ComplementDates implements ComplementPattern {
public IRegex toRegex(String suffix) {
return new RegexConcat( //
new RegexLeaf("YEAR1" + suffix, "([\\d]{4})"), //
new RegexLeaf("\\D"), //
new RegexLeaf("MONTH1" + suffix, "([\\d]{1,2})"), //
new RegexLeaf("\\D"), //
new RegexLeaf("DAY1" + suffix, "([\\d]{1,2})"), //
new RegexLeaf("[%s]+to[%s]+"), //
new RegexLeaf("YEAR2" + suffix, "([\\d]{4})"), //
new RegexLeaf("\\D"), //
new RegexLeaf("MONTH2" + suffix, "([\\d]{1,2})"), //
new RegexLeaf("\\D"), //
new RegexLeaf("DAY2" + suffix, "([\\d]{1,2})") //
);
}
public Subject getSubject(GanttDiagram project, RegexResult arg) {
final DayAsDate date1 = getDate(arg, "1");
final DayAsDate date2 = getDate(arg, "2");
return new DaysAsDates(date1, date2);
}
private DayAsDate getDate(RegexResult arg, String suffix) {
final int day = Integer.parseInt(arg.get("DAY" + suffix, 0));
final int month = Integer.parseInt(arg.get("MONTH" + suffix, 0));
final int year = Integer.parseInt(arg.get("YEAR" + suffix, 0));
return DayAsDate.create(year, month, day);
}
public Failable<Complement> getComplement(GanttDiagram system, RegexResult arg, String suffix) {
final int day1 = Integer.parseInt(arg.get("DAY1" + suffix, 0));
final int month1 = Integer.parseInt(arg.get("MONTH1" + suffix, 0));
final int year1 = Integer.parseInt(arg.get("YEAR1" + suffix, 0));
final DayAsDate date1 = DayAsDate.create(year1, month1, day1);
final int day2 = Integer.parseInt(arg.get("DAY2" + suffix, 0));
final int month2 = Integer.parseInt(arg.get("MONTH2" + suffix, 0));
final int year2 = Integer.parseInt(arg.get("YEAR2" + suffix, 0));
final DayAsDate date2 = DayAsDate.create(year2, month2, day2);
return Failable.<Complement> ok(new DaysAsDates(date1, date2));
}
}

View File

@ -36,17 +36,24 @@
package net.sourceforge.plantuml.project3;
import net.sourceforge.plantuml.command.regex.IRegex;
import net.sourceforge.plantuml.command.regex.RegexConcat;
import net.sourceforge.plantuml.command.regex.RegexLeaf;
import net.sourceforge.plantuml.command.regex.RegexResult;
public class ComplementSeveralDays implements ComplementPattern {
public IRegex toRegex(String suffix) {
return new RegexLeaf("COMPLEMENT" + suffix, "(\\d+)[%s]+days?");
return new RegexConcat( //
new RegexLeaf("COMPLEMENT" + suffix, "(\\d+)[%s]+days?"), //
new RegexLeaf("LOAD" + suffix, "([%s]+at[%s]+(\\d+)%)?"));
}
public Failable<Complement> getComplement(GanttDiagram system, RegexResult arg, String suffix) {
final String days = arg.get("COMPLEMENT" + suffix, 0);
return Failable.<Complement> ok(new DurationDay(Integer.parseInt(days)));
final String load = arg.get("LOAD" + suffix, 1);
if (load == null) {
return Failable.<Complement> ok(LoadInDays.inDay(Integer.parseInt(days)));
}
return Failable.<Complement> ok(LoadInDays.inDayWithLoad(Integer.parseInt(days), Integer.parseInt(load)));
}
}

View File

@ -0,0 +1,58 @@
/* ========================================================================
* 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;
public class ConstantPlan implements LoadPlanable {
private final int loadPerInstant;
private ConstantPlan(int loadPerInstant) {
this.loadPerInstant = loadPerInstant;
}
public static LoadPlanable normal() {
return new ConstantPlan(100);
}
public static LoadPlanable partial(int load) {
return new ConstantPlan(load);
}
public int getLoadAt(Instant instant) {
return loadPerInstant;
}
}

View File

@ -35,7 +35,7 @@
*/
package net.sourceforge.plantuml.project3;
public class DayAsDate implements Complement, Comparable<DayAsDate> {
public class DayAsDate implements Complement, Comparable<DayAsDate>, Subject {
private final int year;
private final int dayOfMonth;
@ -64,6 +64,17 @@ public class DayAsDate implements Complement, Comparable<DayAsDate> {
return "" + year + "/" + month + "/" + dayOfMonth;
}
@Override
public int hashCode() {
return year * 113 + dayOfMonth * 17 + month.hashCode();
}
@Override
public boolean equals(Object obj) {
final DayAsDate other = (DayAsDate) obj;
return other.internalNumber() == this.internalNumber();
}
public final int getDayOfMonth() {
return dayOfMonth;
}

View File

@ -0,0 +1,78 @@
/* ========================================================================
* 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.Iterator;
public class DaysAsDates implements Subject, Complement, Iterable<DayAsDate> {
private final DayAsDate date1;
private final DayAsDate date2;
public DaysAsDates(DayAsDate date1, DayAsDate date2) {
this.date1 = date1;
this.date2 = date2;
}
class MyIterator implements Iterator<DayAsDate> {
private DayAsDate current;
public MyIterator(DayAsDate current) {
this.current = current;
}
public boolean hasNext() {
return current.compareTo(date2) <= 0;
}
public DayAsDate next() {
final DayAsDate result = current;
current = current.next();
return result;
}
public void remove() {
throw new UnsupportedOperationException();
}
}
public Iterator<DayAsDate> iterator() {
return new MyIterator(date1);
}
}

View File

@ -37,10 +37,10 @@ package net.sourceforge.plantuml.project3;
public interface GCalendar {
// public DayAsDate next(DayAsDate day);
public DayAsDate toDayAsDate(InstantDay day);
public DayAsDate getStartingDate();
public InstantDay fromDayAsDate(DayAsDate day);
}

View File

@ -45,8 +45,22 @@ public class GCalendarSimple implements GCalendar {
public DayAsDate toDayAsDate(InstantDay day) {
DayAsDate result = start;
for (int i = 0; i < day.getNumDay(); i++) {
final int target = day.getNumDay();
int work = 0;
while (work < target) {
result = result.next();
work++;
}
return result;
}
public InstantDay fromDayAsDate(DayAsDate day) {
if (day.compareTo(start) < 0) {
throw new IllegalArgumentException();
}
InstantDay result = new InstantDay(0);
while (toDayAsDate(result).equals(day) == false) {
result = result.increment();
}
return result;
}

View File

@ -125,7 +125,7 @@ public class GanttArrow implements UDrawable {
private double getX(TaskInstant when, Direction direction) {
final double x1 = timeScale.getStartingPosition(when.getInstantTheorical());
final double x2 = timeScale.getStartingPosition(when.getInstantTheorical().increment());
final double x2 = timeScale.getEndingPosition(when.getInstantTheorical());
if (direction == Direction.LEFT) {
return x1;
}

View File

@ -38,9 +38,12 @@ package net.sourceforge.plantuml.project3;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@ -54,6 +57,7 @@ import net.sourceforge.plantuml.core.ImageData;
import net.sourceforge.plantuml.cucadiagram.Display;
import net.sourceforge.plantuml.graphic.FontConfiguration;
import net.sourceforge.plantuml.graphic.HorizontalAlignment;
import net.sourceforge.plantuml.graphic.HtmlColor;
import net.sourceforge.plantuml.graphic.HtmlColorSetSimple;
import net.sourceforge.plantuml.graphic.HtmlColorUtils;
import net.sourceforge.plantuml.graphic.IHtmlColorSet;
@ -61,10 +65,12 @@ 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.UChangeBackColor;
import net.sourceforge.plantuml.ugraphic.UChangeColor;
import net.sourceforge.plantuml.ugraphic.UFont;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.ULine;
import net.sourceforge.plantuml.ugraphic.URectangle;
import net.sourceforge.plantuml.ugraphic.UTranslate;
public class GanttDiagram extends AbstractPSystem implements Subject {
@ -73,6 +79,8 @@ public class GanttDiagram extends AbstractPSystem implements Subject {
private final Map<String, Task> byShortName = new HashMap<String, Task>();
private final List<GanttConstraint> constraints = new ArrayList<GanttConstraint>();
private final IHtmlColorSet colorSet = new HtmlColorSetSimple();
private final Collection<DayOfWeek> closedDayOfWeek = EnumSet.noneOf(DayOfWeek.class);
private final Collection<DayAsDate> closedDayAsDate = new HashSet<DayAsDate>();
private GCalendar calendar;
private final Instant min = new InstantDay(0);
@ -82,6 +90,34 @@ public class GanttDiagram extends AbstractPSystem implements Subject {
return new DiagramDescription("(Project)");
}
private int horizontalPages = 1;
private int verticalPages = 1;
final public int getHorizontalPages() {
return horizontalPages;
}
final public void setHorizontalPages(int horizontalPages) {
this.horizontalPages = horizontalPages;
}
final public int getVerticalPages() {
return verticalPages;
}
final public void setVerticalPages(int verticalPages) {
this.verticalPages = verticalPages;
}
@Override
public int getNbImages() {
return this.horizontalPages * this.verticalPages;
}
public final int getDpi(FileFormatOption fileFormatOption) {
return 96;
}
@Override
protected ImageData exportDiagramNow(OutputStream os, int index, FileFormatOption fileFormatOption, long seed)
throws IOException {
@ -129,10 +165,33 @@ public class GanttDiagram extends AbstractPSystem implements Subject {
}
private TimeScale getTimeScale() {
if (calendar == null) {
return new TimeScaleBasic();
}
return new TimeScaleBasic2(getCalendarSimple());
// return new TimeScaleWithoutWeekEnd(calendar);
}
private GCalendarSimple getCalendarSimple() {
return (GCalendarSimple) calendar;
}
public LoadPlanable getDefaultPlan() {
return new LoadPlanable() {
public int getLoadAt(Instant instant) {
if (calendar == null) {
return 100;
}
final DayAsDate day = getCalendarSimple().toDayAsDate((InstantDay) instant);
final DayOfWeek dayOfWeek = day.getDayOfWeek();
if (closedDayOfWeek.contains(dayOfWeek) || closedDayAsDate.contains(day)) {
return 0;
}
return 100;
}
};
}
private void drawConstraints(final UGraphic ug, TimeScale timeScale) {
for (GanttConstraint constraint : constraints) {
constraint.getUDrawable(timeScale).drawU(ug);
@ -142,10 +201,10 @@ public class GanttDiagram extends AbstractPSystem implements Subject {
private void drawTimeHeader(final UGraphic ug, TimeScale timeScale) {
final double yTotal = initTaskDraws(timeScale);
final double yTotal = initTaskAndResourceDraws(timeScale);
final double xmin = timeScale.getStartingPosition(min);
final double xmax = timeScale.getStartingPosition(max.increment());
final double xmax = timeScale.getEndingPosition(max);
ug.apply(new UChangeColor(HtmlColorUtils.LIGHT_GRAY)).draw(new ULine(xmax - xmin, 0));
ug.apply(new UChangeColor(HtmlColorUtils.LIGHT_GRAY)).apply(new UTranslate(0, getHeaderHeight() - 3))
.draw(new ULine(xmax - xmin, 0));
@ -157,41 +216,66 @@ public class GanttDiagram extends AbstractPSystem implements Subject {
}
private void drawCalendar(final UGraphic ug, TimeScale timeScale, final double yTotal) {
final int magic = 12;
final ULine vbar = new ULine(0, yTotal - magic);
Month lastMonth = null;
for (Instant i = min; i.compareTo(max.increment()) <= 0; i = i.increment()) {
final DayAsDate day = calendar.toDayAsDate((InstantDay) i);
final String d1 = "" + day.getDayOfMonth();
final TextBlock num = Display.getWithNewlines(d1).create(getFontConfiguration(), HorizontalAlignment.LEFT,
new SpriteContainerEmpty());
final double x1 = timeScale.getStartingPosition(i);
final double x2 = timeScale.getStartingPosition(i.increment());
if (i.compareTo(max.increment()) < 0) {
final TextBlock weekDay = Display.getWithNewlines(day.getDayOfWeek().shortName()).create(
getFontConfiguration(), HorizontalAlignment.LEFT, new SpriteContainerEmpty());
drawCenter(ug.apply(new UTranslate(0, magic * 2)), num, x1, x2);
drawCenter(ug.apply(new UTranslate(0, magic)), weekDay, x1, x2);
if (lastMonth != day.getMonth()) {
final TextBlock month = Display.getWithNewlines(day.getMonth().name()).create(
getFontConfiguration(), HorizontalAlignment.LEFT, new SpriteContainerEmpty());
month.drawU(ug.apply(new UTranslate(x1, 0)));
}
lastMonth = day.getMonth();
}
ug.apply(new UChangeColor(HtmlColorUtils.LIGHT_GRAY)).apply(new UTranslate(x1, magic)).draw(vbar);
}
}
private final HtmlColor veryLightGray = new HtmlColorSetSimple().getColorIfValid("#E0E8E8");
private double getHeaderHeight() {
if (calendar != null) {
return 40;
return Y_WEEKDAY + Y_NUMDAY;
}
return 16;
}
private static final int Y_WEEKDAY = 16;
private static final int Y_NUMDAY = 28;
private void drawCalendar(final UGraphic ug, TimeScale timeScale, final double yTotal) {
timeScale = new TimeScaleBasic();
final ULine vbar = new ULine(0, yTotal - Y_WEEKDAY);
Month lastMonth = null;
final GCalendarSimple calendarAll = getCalendarSimple();
final Instant max2 = calendarAll.fromDayAsDate(calendar.toDayAsDate((InstantDay) max));
for (Instant i = min; i.compareTo(max2.increment()) <= 0; i = i.increment()) {
final DayAsDate day = calendarAll.toDayAsDate((InstantDay) i);
final DayOfWeek dayOfWeek = day.getDayOfWeek();
final boolean isWorkingDay = getDefaultPlan().getLoadAt(i) > 0;
final String d1 = "" + day.getDayOfMonth();
final TextBlock num = getTextBlock(d1, 10);
final double x1 = timeScale.getStartingPosition(i);
final double x2 = timeScale.getEndingPosition(i);
if (i.compareTo(max2.increment()) < 0) {
final TextBlock weekDay = getTextBlock(dayOfWeek.shortName(), 10);
if (isWorkingDay) {
drawCenter(ug.apply(new UTranslate(0, Y_NUMDAY)), num, x1, x2);
drawCenter(ug.apply(new UTranslate(0, Y_WEEKDAY)), weekDay, x1, x2);
} else {
final URectangle rect = new URectangle(x2 - x1 - 1, yTotal - Y_WEEKDAY);
ug.apply(new UChangeColor(null)).apply(new UChangeBackColor(veryLightGray))
.apply(new UTranslate(x1 + 1, Y_WEEKDAY)).draw(rect);
}
if (lastMonth != day.getMonth()) {
final int delta = 5;
if (lastMonth != null) {
final TextBlock lastMonthBlock = getTextBlock(lastMonth.name(), 12);
lastMonthBlock.drawU(ug.apply(new UTranslate(x1
- lastMonthBlock.calculateDimension(ug.getStringBounder()).getWidth() - delta, 0)));
}
final TextBlock month = getTextBlock(day.getMonth().name(), 12);
month.drawU(ug.apply(new UTranslate(x1 + delta, 0)));
ug.apply(new UChangeColor(HtmlColorUtils.LIGHT_GRAY)).apply(new UTranslate(x1, 0))
.draw(new ULine(0, Y_WEEKDAY));
}
lastMonth = day.getMonth();
}
ug.apply(new UChangeColor(HtmlColorUtils.LIGHT_GRAY)).apply(new UTranslate(x1, Y_WEEKDAY)).draw(vbar);
}
}
private TextBlock getTextBlock(final String text, int size) {
return Display.getWithNewlines(text).create(getFontConfiguration(size), HorizontalAlignment.LEFT,
new SpriteContainerEmpty());
}
private void drawCenter(final UGraphic ug, final TextBlock text, final double x1, final double x2) {
final double width = text.calculateDimension(ug.getStringBounder()).getWidth();
final double delta = (x2 - x1) - width;
@ -204,10 +288,10 @@ public class GanttDiagram extends AbstractPSystem implements Subject {
private void drawSimpleDayCounter(final UGraphic ug, TimeScale timeScale, final double yTotal) {
final ULine vbar = new ULine(0, yTotal);
for (Instant i = min; i.compareTo(max.increment()) <= 0; i = i.increment()) {
final TextBlock num = Display.getWithNewlines(i.toShortString()).create(getFontConfiguration(),
final TextBlock num = Display.getWithNewlines(i.toShortString()).create(getFontConfiguration(10),
HorizontalAlignment.LEFT, new SpriteContainerEmpty());
final double x1 = timeScale.getStartingPosition(i);
final double x2 = timeScale.getStartingPosition(i.increment());
final double x2 = timeScale.getEndingPosition(i);
final double width = num.calculateDimension(ug.getStringBounder()).getWidth();
final double delta = (x2 - x1) - width;
if (i.compareTo(max.increment()) < 0) {
@ -217,12 +301,24 @@ public class GanttDiagram extends AbstractPSystem implements Subject {
}
}
private double initTaskDraws(TimeScale timeScale) {
private double initTaskAndResourceDraws(TimeScale timeScale) {
double y = getHeaderHeight();
for (Task task : tasks.values()) {
final TaskDraw draw = new TaskDraw(task, timeScale, y);
final TaskDraw draw;
if (task instanceof TaskSeparator) {
draw = new TaskDrawSeparator((TaskSeparator) task, timeScale, y, min, max);
} else {
draw = new TaskDrawRegular((TaskImpl) task, timeScale, y);
}
task.setTaskDraw(draw);
y += draw.getHeight();
}
for (Resource res : resources.values()) {
final ResourceDraw draw = new ResourceDraw(this, res, timeScale, y, min, max);
res.setTaskDraw(draw);
y += draw.getHeight();
}
return y;
}
@ -231,6 +327,9 @@ public class GanttDiagram extends AbstractPSystem implements Subject {
// min = tasks.values().iterator().next().getStart();
max = tasks.values().iterator().next().getEnd();
for (Task task : tasks.values()) {
if (task instanceof TaskSeparator) {
continue;
}
final Instant start = task.getStart();
final Instant end = task.getEnd();
// if (min.compareTo(start) > 0) {
@ -246,14 +345,20 @@ public class GanttDiagram extends AbstractPSystem implements Subject {
for (Task task : tasks.values()) {
final TaskDraw draw = task.getTaskDraw();
draw.drawU(ug.apply(new UTranslate(0, draw.getY())));
draw.getTitle().drawU(
ug.apply(new UTranslate(timeScale.getStartingPosition(task.getStart().increment()), draw.getY())));
draw.drawTitle(ug.apply(new UTranslate(0, draw.getY())));
}
for (Resource res : resources.values()) {
final ResourceDraw draw = res.getResourceDraw();
draw.drawU(ug.apply(new UTranslate(0, draw.getY())));
}
}
private FontConfiguration getFontConfiguration() {
final UFont font = UFont.serif(10);
return new FontConfiguration(font, HtmlColorUtils.LIGHT_GRAY, HtmlColorUtils.LIGHT_GRAY, false);
private FontConfiguration getFontConfiguration(int size) {
UFont font = UFont.serif(size);
if (size > 10) {
font = font.bold();
}
return new FontConfiguration(font, HtmlColorUtils.BLACK, HtmlColorUtils.BLACK, false);
}
public Task getExistingTask(String id) {
@ -268,7 +373,13 @@ public class GanttDiagram extends AbstractPSystem implements Subject {
return tasks.get(code);
}
public Task getOrCreateTask(String codeOrShortName, String shortName) {
public void setTaskOrder(final Task task1, final Task task2) {
final TaskInstant end1 = new TaskInstant(task1, TaskAttribute.END);
task2.setStart(end1.getInstantPrecise());
addContraint(new GanttConstraint(end1, new TaskInstant(task2, TaskAttribute.START)));
}
public Task getOrCreateTask(String codeOrShortName, String shortName, boolean linkedToPrevious) {
if (codeOrShortName == null) {
throw new IllegalArgumentException();
}
@ -283,15 +394,37 @@ public class GanttDiagram extends AbstractPSystem implements Subject {
final TaskCode code = new TaskCode(codeOrShortName);
result = tasks.get(code);
if (result == null) {
result = new TaskImpl(code);
Task previous = null;
if (linkedToPrevious) {
previous = getLastCreatedTask();
}
result = new TaskImpl(code, getDefaultPlan());
tasks.put(code, result);
if (byShortName != null) {
byShortName.put(shortName, result);
}
if (previous != null) {
setTaskOrder(previous, result);
}
}
return result;
}
private Task getLastCreatedTask() {
final List<Task> all = new ArrayList<Task>(tasks.values());
for (int i = all.size() - 1; i >= 0; i--) {
if (all.get(i) instanceof TaskImpl) {
return all.get(i);
}
}
return null;
}
public void addSeparator(String comment) {
TaskSeparator separator = new TaskSeparator(comment, tasks.size());
tasks.put(separator.getCode(), separator);
}
private TaskCodeSimpleOrder getCanonicalOrder(int hierarchyHeader) {
final List<TaskCode> codes = new ArrayList<TaskCode>();
for (TaskCode code : tasks.keySet()) {
@ -326,4 +459,44 @@ public class GanttDiagram extends AbstractPSystem implements Subject {
return this.calendar.getStartingDate();
}
public void closeDayOfWeek(DayOfWeek day) {
closedDayOfWeek.add(day);
}
public void closeDayAsDate(DayAsDate day) {
closedDayAsDate.add(day);
}
public Instant convert(DayAsDate day) {
return calendar.fromDayAsDate(day);
}
private final Map<String, Resource> resources = new LinkedHashMap<String, Resource>();
public void affectResource(Task result, String resourceName) {
Resource resource = getResource(resourceName);
result.addResource(resource);
}
public Resource getResource(String resourceName) {
Resource resource = resources.get(resourceName);
if (resource == null) {
resource = new Resource(resourceName, getDefaultPlan());
}
resources.put(resourceName, resource);
return resource;
}
public int getLoadForResource(Resource res, Instant i) {
int result = 0;
for (Task task : tasks.values()) {
if (task instanceof TaskSeparator) {
continue;
}
final TaskImpl task2 = (TaskImpl) task;
result += task2.loadForResource(res, i);
}
return result;
}
}

View File

@ -50,7 +50,8 @@ import net.sourceforge.plantuml.core.DiagramType;
public class GanttDiagramFactory extends UmlDiagramFactory {
private List<SubjectPattern> subjects() {
return Arrays.<SubjectPattern> asList(new SubjectTask(), new SubjectProject(), new SubjectDayOfWeek());
return Arrays.<SubjectPattern> asList(new SubjectTask(), new SubjectProject(), new SubjectDayOfWeek(),
new SubjectDayAsDate(), new SubjectDaysAsDates(), new SubjectResource());
}
public GanttDiagramFactory(DiagramType type) {
@ -68,15 +69,17 @@ public class GanttDiagramFactory extends UmlDiagramFactory {
cmds.add(cmd);
}
cmds.add(new CommandGanttArrow());
cmds.add(new CommandGanttArrow2());
cmds.add(new CommandSeparator());
cmds.add(new CommandScale());
cmds.add(new CommandPage());
// cmds.add(new CommandScaleWidthAndHeight());
// cmds.add(new CommandScaleWidthOrHeight());
// cmds.add(new CommandScaleMaxWidth());
// cmds.add(new CommandScaleMaxHeight());
// cmds.add(new CommandScaleMaxWidthAndHeight());
return cmds;
}

View File

@ -37,10 +37,6 @@ package net.sourceforge.plantuml.project3;
public interface Instant extends Value, Comparable<Instant> {
public Instant add(Duration duration);
public Instant sub(Duration duration);
public Instant increment();
public Instant decrement();

View File

@ -48,16 +48,6 @@ public class InstantDay implements Instant {
return "(day +" + numDay + ")";
}
public InstantDay add(Duration duration) {
final int nbdays = ((DurationDay) duration).getDays();
return new InstantDay(numDay + nbdays);
}
public InstantDay sub(Duration duration) {
final int nbdays = ((DurationDay) duration).getDays();
return new InstantDay(numDay - nbdays);
}
public InstantDay increment() {
return new InstantDay(numDay + 1);
}

View File

@ -35,21 +35,8 @@
*/
package net.sourceforge.plantuml.project3;
public class DurationDay implements Duration {
public interface Load extends Value, Complement, LoadPlanable {
private final int days;
public DurationDay(int days) {
this.days = days;
}
public int getDays() {
return days;
}
@Override
public String toString() {
return "{" + days + " days}";
}
int getFullLoad();
}

View File

@ -0,0 +1,65 @@
/* ========================================================================
* 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;
public class LoadInDays implements Load {
private final int days;
private final int loadPerDay;
private LoadInDays(int days, int loadPerDay) {
this.days = days;
this.loadPerDay = loadPerDay;
}
public static LoadInDays inDay(int days) {
return new LoadInDays(days, 100);
}
public static Complement inDayWithLoad(int days, int loadPerDay) {
final int tmp = (int) Math.ceil(days * 100.0 / loadPerDay);
return new LoadInDays(tmp, loadPerDay);
}
public int getFullLoad() {
return days * loadPerDay;
}
public int getLoadAt(Instant instant) {
return loadPerDay;
}
}

View File

@ -35,6 +35,7 @@
*/
package net.sourceforge.plantuml.project3;
public interface Duration extends Value, Complement {
public interface LoadPlanable {
public int getLoadAt(Instant instant);
}

View File

@ -0,0 +1,52 @@
/* ========================================================================
* 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;
public class PlanUtils {
private PlanUtils() {
}
public static LoadPlanable minOf(final LoadPlanable p1, final LoadPlanable p2) {
return new LoadPlanable() {
public int getLoadAt(Instant instant) {
return Math.min(p1.getLoadAt(instant), p2.getLoadAt(instant));
}
};
}
}

View File

@ -0,0 +1,91 @@
/* ========================================================================
* 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.Set;
import java.util.TreeSet;
public class Resource implements Subject, LoadPlanable {
private final String name;
private ResourceDraw draw;
private final LoadPlanable loadPlanable;
private Set<Instant> closed = new TreeSet<Instant>();
public Resource(String name, LoadPlanable loadPlanable) {
this.name = name;
this.loadPlanable = loadPlanable;
}
@Override
public int hashCode() {
return name.hashCode();
}
@Override
public boolean equals(Object obj) {
final Resource other = (Resource) obj;
return this.name.equals(other.name);
}
@Override
public String toString() {
return name;
}
public String getName() {
return name;
}
public ResourceDraw getResourceDraw() {
return draw;
}
public void setTaskDraw(ResourceDraw draw) {
this.draw = draw;
}
public int getLoadAt(Instant instant) {
if (this.closed.contains(instant)) {
return 0;
}
return loadPlanable.getLoadAt(instant);
}
public void addCloseDay(Instant instant) {
this.closed.add(instant);
}
}

View File

@ -0,0 +1,118 @@
/* ========================================================================
* 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 net.sourceforge.plantuml.SpriteContainerEmpty;
import net.sourceforge.plantuml.cucadiagram.Display;
import net.sourceforge.plantuml.graphic.FontConfiguration;
import net.sourceforge.plantuml.graphic.HorizontalAlignment;
import net.sourceforge.plantuml.graphic.HtmlColor;
import net.sourceforge.plantuml.graphic.HtmlColorUtils;
import net.sourceforge.plantuml.graphic.TextBlock;
import net.sourceforge.plantuml.graphic.UDrawable;
import net.sourceforge.plantuml.ugraphic.UChangeColor;
import net.sourceforge.plantuml.ugraphic.UFont;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.ULine;
import net.sourceforge.plantuml.ugraphic.UTranslate;
public class ResourceDraw implements UDrawable {
private final Resource res;
private final TimeScale timeScale;
private final double y;
private final Instant min;
private final Instant max;
private final GanttDiagram gantt;
public ResourceDraw(GanttDiagram gantt, Resource res, TimeScale timeScale, double y, Instant min, Instant max) {
this.res = res;
this.timeScale = timeScale;
this.y = y;
this.min = min;
this.max = max;
this.gantt = gantt;
}
public void drawU(UGraphic ug) {
final TextBlock title = Display.getWithNewlines(res.getName()).create(getFontConfiguration(13),
HorizontalAlignment.LEFT, new SpriteContainerEmpty());
title.drawU(ug);
final ULine line = new ULine(timeScale.getEndingPosition(max) - timeScale.getStartingPosition(min), 0);
ug.apply(new UChangeColor(HtmlColorUtils.BLACK))
.apply(new UTranslate(0, title.calculateDimension(ug.getStringBounder()).getHeight())).draw(line);
for (Instant i = min; i.compareTo(max) <= 0; i = i.increment()) {
final int load = gantt.getLoadForResource(res, i);
if (load > 0) {
final FontConfiguration fontConfiguration = getFontConfiguration(9, load > 100 ? HtmlColorUtils.RED
: HtmlColorUtils.BLACK);
final TextBlock value = Display.getWithNewlines("" + load).create(fontConfiguration,
HorizontalAlignment.LEFT, new SpriteContainerEmpty());
final double start = (timeScale.getStartingPosition(i) + timeScale.getEndingPosition(i)) / 2
- value.calculateDimension(ug.getStringBounder()).getWidth() / 2;
value.drawU(ug.apply(new UTranslate(start, 16)));
}
}
}
private FontConfiguration getFontConfiguration(int size) {
return getFontConfiguration(size, HtmlColorUtils.BLACK);
}
private FontConfiguration getFontConfiguration(int size, HtmlColor color) {
final UFont font = UFont.serif(size);
return new FontConfiguration(font, color, color, false);
}
// public void setColors(ComplementColors colors);
//
// public double getY();
//
// public double getY(Direction direction);
//
// public void drawTitle(UGraphic ug);
public double getHeight() {
return 16 * 2;
}
public double getY() {
return y;
}
}

View File

@ -0,0 +1,53 @@
/* ========================================================================
* 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.LinkedHashSet;
import java.util.Set;
public class Resources implements LoadPlanable {
private final Set<Resource> all = new LinkedHashSet<Resource>();
public int getLoadAt(Instant instant) {
int result = 0;
for (Resource res : all) {
result += res.getLoadAt(instant);
}
return result;
}
}

View File

@ -0,0 +1,56 @@
/* ========================================================================
* 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;
public class Solver2 {
public Instant solveEnd(Instant start, int fullLoad, LoadPlanable plan) {
while (fullLoad > 0) {
fullLoad -= plan.getLoadAt(start);
start = start.increment();
}
return start;
}
public Instant solveStart(Instant end, int fullLoad, LoadPlanable plan) {
while (fullLoad > 0) {
fullLoad -= plan.getLoadAt(end);
end = end.decrement();
}
return end;
}
}

View File

@ -40,10 +40,16 @@ import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
public class Solver {
public class Solver3 {
private final Map<TaskAttribute, Value> values = new LinkedHashMap<TaskAttribute, Value>();
private final LoadPlanable loadPlanable;
public Solver3(LoadPlanable loadPlanable) {
this.loadPlanable = loadPlanable;
}
public void setData(TaskAttribute attribute, Value value) {
values.remove(attribute);
values.put(attribute, value);
@ -69,23 +75,30 @@ public class Solver {
if (attribute == TaskAttribute.START) {
return computeStart();
}
throw new UnsupportedOperationException(attribute.toString());
return LoadInDays.inDay(1);
// throw new UnsupportedOperationException(attribute.toString());
}
return result;
}
private Instant computeStart() {
final Instant end = (Instant) values.get(TaskAttribute.END);
final Duration duration = (Duration) values.get(TaskAttribute.DURATION);
assert end != null && duration != null;
return end.sub(duration).increment();
}
private Instant computeEnd() {
final Instant start = (Instant) values.get(TaskAttribute.START);
final Duration duration = (Duration) values.get(TaskAttribute.DURATION);
assert start != null && duration != null;
return start.add(duration).decrement();
Instant current = (Instant) values.get(TaskAttribute.START);
int fullLoad = ((Load) values.get(TaskAttribute.LOAD)).getFullLoad();
while (fullLoad > 0) {
fullLoad -= loadPlanable.getLoadAt(current);
current = current.increment();
}
return current.decrement();
}
private Instant computeStart() {
Instant current = (Instant) values.get(TaskAttribute.END);
int fullLoad = ((Load) values.get(TaskAttribute.LOAD)).getFullLoad();
while (fullLoad > 0) {
fullLoad -= loadPlanable.getLoadAt(current);
current = current.decrement();
}
return current.increment();
}
}

View File

@ -0,0 +1,68 @@
/* ========================================================================
* 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.regex.IRegex;
import net.sourceforge.plantuml.command.regex.RegexConcat;
import net.sourceforge.plantuml.command.regex.RegexLeaf;
import net.sourceforge.plantuml.command.regex.RegexResult;
public class SubjectDayAsDate implements SubjectPattern {
public Collection<VerbPattern> getVerbs() {
return Arrays.<VerbPattern> asList(new VerbIs());
}
public IRegex toRegex() {
return new RegexConcat( //
new RegexLeaf("YEAR", "([\\d]{4})"), //
new RegexLeaf("\\D"), //
new RegexLeaf("MONTH", "([\\d]{1,2})"), //
new RegexLeaf("\\D"), //
new RegexLeaf("DAY", "([\\d]{1,2})"));
}
public Subject getSubject(GanttDiagram project, RegexResult arg) {
final int day = Integer.parseInt(arg.get("DAY", 0));
final int month = Integer.parseInt(arg.get("MONTH", 0));
final int year = Integer.parseInt(arg.get("YEAR", 0));
return DayAsDate.create(year, month, day);
}
}

View File

@ -0,0 +1,82 @@
/* ========================================================================
* 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.regex.IRegex;
import net.sourceforge.plantuml.command.regex.RegexConcat;
import net.sourceforge.plantuml.command.regex.RegexLeaf;
import net.sourceforge.plantuml.command.regex.RegexResult;
public class SubjectDaysAsDates implements SubjectPattern {
public Collection<VerbPattern> getVerbs() {
return Arrays.<VerbPattern> asList(new VerbIs());
}
public IRegex toRegex() {
return new RegexConcat( //
new RegexLeaf("YEAR1", "([\\d]{4})"), //
new RegexLeaf("\\D"), //
new RegexLeaf("MONTH1", "([\\d]{1,2})"), //
new RegexLeaf("\\D"), //
new RegexLeaf("DAY1", "([\\d]{1,2})"), //
new RegexLeaf("[%s]+to[%s]+"), //
new RegexLeaf("YEAR2", "([\\d]{4})"), //
new RegexLeaf("\\D"), //
new RegexLeaf("MONTH2", "([\\d]{1,2})"), //
new RegexLeaf("\\D"), //
new RegexLeaf("DAY2", "([\\d]{1,2})") //
);
}
public Subject getSubject(GanttDiagram project, RegexResult arg) {
final DayAsDate date1 = getDate(arg, "1");
final DayAsDate date2 = getDate(arg, "2");
return new DaysAsDates(date1, date2);
}
private DayAsDate getDate(RegexResult arg, String suffix) {
final int day = Integer.parseInt(arg.get("DAY" + suffix, 0));
final int month = Integer.parseInt(arg.get("MONTH" + suffix, 0));
final int year = Integer.parseInt(arg.get("YEAR" + suffix, 0));
return DayAsDate.create(year, month, day);
}
}

View File

@ -0,0 +1,63 @@
/* ========================================================================
* 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 java.util.StringTokenizer;
import net.sourceforge.plantuml.command.regex.IRegex;
import net.sourceforge.plantuml.command.regex.RegexConcat;
import net.sourceforge.plantuml.command.regex.RegexLeaf;
import net.sourceforge.plantuml.command.regex.RegexResult;
public class SubjectResource implements SubjectPattern {
public Collection<VerbPattern> getVerbs() {
return Arrays.<VerbPattern> asList(new VerbIsOff());
}
public IRegex toRegex() {
return new RegexConcat( //
new RegexLeaf("RESOURCE", "\\{([^{}]+)\\}") //
);
}
public Subject getSubject(GanttDiagram project, RegexResult arg) {
final String s = arg.get("RESOURCE", 0);
return project.getResource(s);
}
}

View File

@ -37,8 +37,10 @@ package net.sourceforge.plantuml.project3;
import java.util.Arrays;
import java.util.Collection;
import java.util.StringTokenizer;
import net.sourceforge.plantuml.command.regex.IRegex;
import net.sourceforge.plantuml.command.regex.RegexConcat;
import net.sourceforge.plantuml.command.regex.RegexLeaf;
import net.sourceforge.plantuml.command.regex.RegexResult;
@ -50,17 +52,31 @@ public class SubjectTask implements SubjectPattern {
}
public IRegex toRegex() {
return new RegexLeaf("SUBJECT", "\\[([^\\[\\]]+?)\\](?:[%s]+as[%s]+\\[([^\\[\\]]+?)\\])?");
return new RegexConcat( //
new RegexLeaf("THEN", "(then[%s]+)?"), //
new RegexLeaf("SUBJECT", "\\[([^\\[\\]]+?)\\](?:[%s]+as[%s]+\\[([^\\[\\]]+?)\\])?"), //
new RegexLeaf("RESOURCE", "(?:[%s]+on[%s]+((?:\\{[^{}]+\\}[%s]*)+))?") //
);
}
public Subject getSubject(GanttDiagram project, RegexResult arg) {
final String s = arg.get("SUBJECT", 0);
final String shortName = arg.get("SUBJECT", 1);
final Task result = project.getOrCreateTask(s, shortName);
final String then = arg.get("THEN", 0);
final String resource = arg.get("RESOURCE", 0);
final Task result = project.getOrCreateTask(s, shortName, then != null);
if (result == null) {
throw new IllegalStateException();
}
return result;
if (resource != null) {
for (final StringTokenizer st = new StringTokenizer(resource, "{}"); st.hasMoreTokens();) {
final String part = st.nextToken().trim();
if (part.length() > 0) {
project.affectResource(result, part);
}
}
}
return result;
}
}

View File

@ -43,18 +43,20 @@ public interface Task extends Subject {
public Instant getEnd();
public Duration getDuration();
public Load getLoad();
public void setLoad(Load load);
public void setStart(Instant start);
public void setEnd(Instant end);
public void setDuration(Duration duration);
public void setTaskDraw(TaskDraw taskDraw);
public TaskDraw getTaskDraw();
public void setColors(ComplementColors colors);
public void addResource(Resource resource);
}

View File

@ -36,7 +36,7 @@
package net.sourceforge.plantuml.project3;
public enum TaskAttribute {
START, END, DURATION;
START, END, LOAD;
public static TaskAttribute fromString(String value) {
return valueOf(value.toUpperCase());

View File

@ -81,9 +81,8 @@ public class TaskCode {
return hierarchy.toString();
}
public Display getSimpleDisplay() {
final String last = hierarchy.get(hierarchy.size() - 1);
return Display.getWithNewlines(last);
public String getSimpleDisplay() {
return hierarchy.get(hierarchy.size() - 1);
}
public int getHierarchySize() {

View File

@ -36,111 +36,19 @@
package net.sourceforge.plantuml.project3;
import net.sourceforge.plantuml.Direction;
import net.sourceforge.plantuml.SpriteContainerEmpty;
import net.sourceforge.plantuml.graphic.FontConfiguration;
import net.sourceforge.plantuml.graphic.HorizontalAlignment;
import net.sourceforge.plantuml.graphic.HtmlColorUtils;
import net.sourceforge.plantuml.graphic.TextBlock;
import net.sourceforge.plantuml.graphic.UDrawable;
import net.sourceforge.plantuml.ugraphic.UChangeBackColor;
import net.sourceforge.plantuml.ugraphic.UChangeColor;
import net.sourceforge.plantuml.ugraphic.UFont;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.UPolygon;
import net.sourceforge.plantuml.ugraphic.URectangle;
import net.sourceforge.plantuml.ugraphic.UShape;
import net.sourceforge.plantuml.ugraphic.UTranslate;
public class TaskDraw implements UDrawable {
public interface TaskDraw extends UDrawable {
private final Task task;
private final TimeScale timeScale;
private final double y;
private ComplementColors colors;
public void setColors(ComplementColors colors);
private final double margin = 2;
public double getY();
public TaskDraw(Task task, TimeScale timeScale, double y) {
this.y = y;
this.task = task;
this.timeScale = timeScale;
}
public double getY(Direction direction);
public TextBlock getTitle() {
return task.getCode().getSimpleDisplay()
.create(getFontConfiguration(), HorizontalAlignment.LEFT, new SpriteContainerEmpty());
}
public void drawTitle(UGraphic ug);
private FontConfiguration getFontConfiguration() {
final UFont font = UFont.serif(11);
return new FontConfiguration(font, HtmlColorUtils.BLACK, HtmlColorUtils.BLACK, false);
}
public double getHeight();
public void drawU(UGraphic ug) {
final double start = timeScale.getStartingPosition(task.getStart());
final UShape rect = getShape();
ug = applyColors(ug);
ug.apply(new UTranslate(start + margin, margin)).draw(rect);
}
private UGraphic applyColors(UGraphic ug) {
if (colors != null && colors.isOk()) {
return colors.apply(ug);
}
if (isDiamond()) {
return ug.apply(new UChangeColor(HtmlColorUtils.BLACK)).apply(new UChangeBackColor(HtmlColorUtils.BLACK));
}
return ug.apply(new UChangeColor(HtmlColorUtils.BLUE)).apply(new UChangeBackColor(HtmlColorUtils.COL_84BE84));
}
private UShape getShape() {
if (isDiamond()) {
return getDiamond();
}
final Instant instantStart = task.getStart();
final Instant instantEnd = task.getEnd();
final double start = timeScale.getStartingPosition(instantStart);
final double end = timeScale.getStartingPosition(instantEnd.increment());
return new URectangle(end - start - 2 * margin, getHeight() - 2 * margin, 8, 8);
}
private boolean isDiamond() {
final Instant instantStart = task.getStart();
final Instant instantEnd = task.getEnd();
return instantStart.compareTo(instantEnd) == 0;
}
private UShape getDiamond() {
final double h = getHeight() - 2 * margin;
final UPolygon result = new UPolygon();
result.addPoint(h / 2, 0);
result.addPoint(h, h / 2);
result.addPoint(h / 2, h);
result.addPoint(0, h / 2);
return result;
// return result.translate(2, 2);
}
public double getHeight() {
return 16;
}
public double getY() {
return y;
}
public double getY(Direction direction) {
if (direction == Direction.UP) {
return y;
}
if (direction == Direction.DOWN) {
return y + getHeight();
}
return y + getHeight() / 2;
}
public void setColors(ComplementColors colors) {
this.colors = colors;
}
}

View File

@ -0,0 +1,174 @@
/* ========================================================================
* 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 net.sourceforge.plantuml.Direction;
import net.sourceforge.plantuml.SpriteContainerEmpty;
import net.sourceforge.plantuml.cucadiagram.Display;
import net.sourceforge.plantuml.graphic.FontConfiguration;
import net.sourceforge.plantuml.graphic.HorizontalAlignment;
import net.sourceforge.plantuml.graphic.HtmlColorUtils;
import net.sourceforge.plantuml.graphic.TextBlock;
import net.sourceforge.plantuml.ugraphic.UChangeBackColor;
import net.sourceforge.plantuml.ugraphic.UChangeColor;
import net.sourceforge.plantuml.ugraphic.UFont;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.UPolygon;
import net.sourceforge.plantuml.ugraphic.URectangle;
import net.sourceforge.plantuml.ugraphic.UShape;
import net.sourceforge.plantuml.ugraphic.UTranslate;
public class TaskDrawRegular implements TaskDraw {
private final TaskImpl task;
private final TimeScale timeScale;
private final double y;
private ComplementColors colors;
private final double margin = 2;
public TaskDrawRegular(TaskImpl task, TimeScale timeScale, double y) {
this.y = y;
this.task = task;
this.timeScale = timeScale;
}
public void drawTitle(UGraphic ug) {
final TextBlock title = Display.getWithNewlines(task.getPrettyDisplay()).create(getFontConfiguration(),
HorizontalAlignment.LEFT, new SpriteContainerEmpty());
title.drawU(ug.apply(new UTranslate(timeScale.getEndingPosition(task.getStart()), 0)));
}
private FontConfiguration getFontConfiguration() {
final UFont font = UFont.serif(11);
return new FontConfiguration(font, HtmlColorUtils.BLACK, HtmlColorUtils.BLACK, false);
}
public void drawU(UGraphic ug1) {
final double start = timeScale.getStartingPosition(task.getStart());
ug1 = applyColors(ug1);
UGraphic ug2 = ug1.apply(new UTranslate(start + margin, margin));
// final int load = 42; // task.getLoad();
final UShape shapeFull = getShape(100);
if (shapeFull instanceof UPolygon) {
ug2.draw(shapeFull);
} else {
final double fullHeight = ((URectangle) shapeFull).getHeight();
ug2.apply(new UChangeBackColor(HtmlColorUtils.WHITE)).apply(new UChangeColor(HtmlColorUtils.WHITE))
.draw(shapeFull);
drawInside(ug1, fullHeight);
ug2.apply(new UChangeBackColor(null)).draw(shapeFull);
}
}
private void drawInside(UGraphic ug, double fullHeight) {
for (Instant i = task.getStart(); i.compareTo(task.getEnd()) <= 0; i = i.increment()) {
final int load = task.getLoadAt(i);
final URectangle shapeLoad = getShapeInside(load, i);
final double diffHeight = fullHeight - shapeLoad.getHeight();
final double start = timeScale.getStartingPosition(i);
ug.apply(new UChangeColor(null)).apply(new UTranslate(start, diffHeight + margin)).draw(shapeLoad);
}
}
private UGraphic applyColors(UGraphic ug) {
if (colors != null && colors.isOk()) {
return colors.apply(ug);
}
if (isDiamond()) {
return ug.apply(new UChangeColor(HtmlColorUtils.BLACK)).apply(new UChangeBackColor(HtmlColorUtils.BLACK));
}
return ug.apply(new UChangeColor(HtmlColorUtils.BLUE)).apply(new UChangeBackColor(HtmlColorUtils.COL_84BE84));
}
private URectangle getShapeInside(int load, Instant instant) {
final double start = timeScale.getStartingPosition(instant);
final double end = timeScale.getEndingPosition(instant);
final double height = (getHeight() - 2 * margin) * load / 100.0;
return new URectangle(end - start, height);
}
private UShape getShape(int load) {
if (isDiamond()) {
return getDiamond();
}
final Instant instantStart = task.getStart();
final Instant instantEnd = task.getEnd();
final double start = timeScale.getStartingPosition(instantStart);
final double end = timeScale.getEndingPosition(instantEnd);
final double height = (getHeight() - 2 * margin) * load / 100.0;
return new URectangle(end - start - 2 * margin, height, 8, 8);
}
private boolean isDiamond() {
final Instant instantStart = task.getStart();
final Instant instantEnd = task.getEnd();
return instantStart.compareTo(instantEnd) == 0;
}
private UShape getDiamond() {
final double h = getHeight() - 2 * margin;
final UPolygon result = new UPolygon();
result.addPoint(h / 2, 0);
result.addPoint(h, h / 2);
result.addPoint(h / 2, h);
result.addPoint(0, h / 2);
return result;
// return result.translate(2, 2);
}
public double getHeight() {
return 16;
}
public double getY() {
return y;
}
public double getY(Direction direction) {
if (direction == Direction.UP) {
return y;
}
if (direction == Direction.DOWN) {
return y + getHeight();
}
return y + getHeight() / 2;
}
public void setColors(ComplementColors colors) {
this.colors = colors;
}
}

View File

@ -0,0 +1,128 @@
/* ========================================================================
* 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 net.sourceforge.plantuml.Direction;
import net.sourceforge.plantuml.SpriteContainerEmpty;
import net.sourceforge.plantuml.cucadiagram.Display;
import net.sourceforge.plantuml.graphic.FontConfiguration;
import net.sourceforge.plantuml.graphic.HorizontalAlignment;
import net.sourceforge.plantuml.graphic.HtmlColorUtils;
import net.sourceforge.plantuml.graphic.TextBlock;
import net.sourceforge.plantuml.graphic.TextBlockUtils;
import net.sourceforge.plantuml.ugraphic.UChangeColor;
import net.sourceforge.plantuml.ugraphic.UFont;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.ULine;
import net.sourceforge.plantuml.ugraphic.UTranslate;
public class TaskDrawSeparator implements TaskDraw {
private final TimeScale timeScale;
private final double y;
private final Instant min;
private final Instant max;
private final String name;
public TaskDrawSeparator(TaskSeparator task, TimeScale timeScale, double y, Instant min, Instant max) {
this.name = task.getName();
this.y = y;
this.timeScale = timeScale;
this.min = min;
this.max = max;
}
public void drawTitle(UGraphic ug) {
getTitle().drawU(ug.apply(new UTranslate(MARGIN1, 0)));
}
private TextBlock getTitle() {
if (name == null) {
return TextBlockUtils.empty(0, 0);
}
return Display.getWithNewlines(this.name).create(getFontConfiguration(), HorizontalAlignment.LEFT,
new SpriteContainerEmpty());
}
private FontConfiguration getFontConfiguration() {
final UFont font = UFont.serif(11);
return new FontConfiguration(font, HtmlColorUtils.BLACK, HtmlColorUtils.BLACK, false);
}
private final static double MARGIN1 = 10;
private final static double MARGIN2 = 2;
public void drawU(UGraphic ug) {
final double widthTitle = getTitle().calculateDimension(ug.getStringBounder()).getWidth();
final double start = timeScale.getStartingPosition(min) + widthTitle;
final double end = timeScale.getEndingPosition(max);
ug = ug.apply(new UChangeColor(HtmlColorUtils.BLACK));
ug = ug.apply(new UTranslate(0, getHeight() / 2));
if (widthTitle == 0) {
final ULine line = new ULine(end - start, 0);
ug.draw(line);
} else {
final ULine line1 = new ULine(MARGIN1 - MARGIN2, 0);
final ULine line2 = new ULine(end - start - MARGIN1 - MARGIN2, 0);
ug.draw(line1);
ug.apply(new UTranslate(widthTitle + MARGIN1 + MARGIN2, 0)).draw(line2);
}
}
public double getHeight() {
return 16;
}
public double getY() {
return y;
}
public double getY(Direction direction) {
if (direction == Direction.UP) {
return y;
}
if (direction == Direction.DOWN) {
return y + getHeight();
}
return y + getHeight() / 2;
}
public void setColors(ComplementColors colors) {
}
}

View File

@ -35,15 +35,80 @@
*/
package net.sourceforge.plantuml.project3;
public class TaskImpl implements Task {
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
public class TaskImpl implements Task, LoadPlanable {
private final TaskCode code;
private final Solver solver = new Solver();
private final Solver3 solver;
private final Set<Resource> resources = new LinkedHashSet<Resource>();
private final LoadPlanable defaultPlan;
public TaskImpl(TaskCode code) {
public TaskImpl(TaskCode code, LoadPlanable defaultPlan) {
this.code = code;
this.defaultPlan = defaultPlan;
this.solver = new Solver3(this);
setStart(new InstantDay(0));
setDuration(new DurationDay(1));
setLoad(LoadInDays.inDay(1));
}
public int getLoadAt(Instant instant) {
LoadPlanable plan1 = defaultPlan;
if (resources.size() > 0) {
plan1 = PlanUtils.minOf(plan1, getRessourcePlan());
}
return PlanUtils.minOf(getLoad(), plan1).getLoadAt(instant);
}
public int loadForResource(Resource res, Instant i) {
if (resources.contains(res) && i.compareTo(getStart()) >= 0 && i.compareTo(getEnd()) <= 0) {
if (res.getLoadAt(i) == 0) {
return 0;
}
int size = 0;
for (Resource r : resources) {
if (r.getLoadAt(i) > 0) {
size++;
}
}
return getLoadAt(i) / size;
}
return 0;
}
private LoadPlanable getRessourcePlan() {
if (resources.size() == 0) {
throw new IllegalStateException();
}
return new LoadPlanable() {
public int getLoadAt(Instant instant) {
int result = 0;
for (Resource res : resources) {
result += res.getLoadAt(instant);
}
return result;
}
};
}
public String getPrettyDisplay() {
if (resources.size() > 0) {
final StringBuilder result = new StringBuilder(code.getSimpleDisplay());
result.append(" ");
for (Iterator<Resource> it = resources.iterator(); it.hasNext();) {
result.append("{");
result.append(it.next().getName());
result.append("}");
if (it.hasNext()) {
result.append(" ");
}
}
return result.toString();
}
return code.getSimpleDisplay();
}
@Override
@ -52,7 +117,7 @@ public class TaskImpl implements Task {
}
public String debug() {
return "" + getStart() + " ---> " + getEnd() + " [" + getDuration() + "]";
return "" + getStart() + " ---> " + getEnd() + " [" + getLoad() + "]";
}
public TaskCode getCode() {
@ -60,15 +125,23 @@ public class TaskImpl implements Task {
}
public Instant getStart() {
return (Instant) solver.getData(TaskAttribute.START);
Instant result = (Instant) solver.getData(TaskAttribute.START);
while (getLoadAt(result) == 0) {
result = result.increment();
}
return result;
}
public Instant getEnd() {
return (Instant) solver.getData(TaskAttribute.END);
}
public Duration getDuration() {
return (Duration) solver.getData(TaskAttribute.DURATION);
public Load getLoad() {
return (Load) solver.getData(TaskAttribute.LOAD);
}
public void setLoad(Load load) {
solver.setData(TaskAttribute.LOAD, load);
}
public void setStart(Instant start) {
@ -79,10 +152,6 @@ public class TaskImpl implements Task {
solver.setData(TaskAttribute.END, end);
}
public void setDuration(Duration duration) {
solver.setData(TaskAttribute.DURATION, duration);
}
private TaskDraw taskDraw;
private ComplementColors colors;
@ -99,4 +168,8 @@ public class TaskImpl implements Task {
this.colors = colors;
}
public void addResource(Resource resource) {
this.resources.add(resource);
}
}

View File

@ -0,0 +1,99 @@
/* ========================================================================
* 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;
public class TaskSeparator implements Task {
// public static final double SPACE = 15;
private final TaskCode code;
private final String comment;
private TaskDraw taskDraw;
public TaskSeparator(String comment, int id) {
this.code = new TaskCode("##" + id);
this.comment = comment;
}
public TaskCode getCode() {
return code;
}
public Instant getStart() {
throw new UnsupportedOperationException();
}
public Instant getEnd() {
throw new UnsupportedOperationException();
}
public void setStart(Instant start) {
throw new UnsupportedOperationException();
}
public void setEnd(Instant end) {
throw new UnsupportedOperationException();
}
public void setTaskDraw(TaskDraw taskDraw) {
this.taskDraw = taskDraw;
}
public TaskDraw getTaskDraw() {
return taskDraw;
}
public void setColors(ComplementColors colors) {
throw new UnsupportedOperationException();
}
public String getName() {
return comment;
}
public void addResource(Resource resource) {
throw new UnsupportedOperationException();
}
public Load getLoad() {
throw new UnsupportedOperationException();
}
public void setLoad(Load load) {
throw new UnsupportedOperationException();
}
}

View File

@ -39,6 +39,8 @@ public interface TimeScale {
public double getStartingPosition(Instant instant);
public double getEndingPosition(Instant instant);
public double getWidth(Instant instant);
}

View File

@ -44,6 +44,10 @@ public class TimeScaleBasic implements TimeScale {
return day * scale;
}
public double getEndingPosition(Instant instant) {
return getStartingPosition(instant) + getWidth(instant);
}
public double getWidth(Instant instant) {
return scale;
}

View File

@ -0,0 +1,79 @@
/* ========================================================================
* 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.Map;
import java.util.TreeMap;
public class TimeScaleBasic2 implements TimeScale {
private final GCalendar calendar;
private final GCalendar calendarAllOpen;
private final TimeScaleBasic basic = new TimeScaleBasic();
private final Map<Instant, Instant> cache = new TreeMap<Instant, Instant>();
public TimeScaleBasic2(GCalendarSimple calendar) {
this.calendar = calendar;
this.calendarAllOpen = calendar;
}
private Instant changeInstantSlow(Instant instant) {
final DayAsDate day = calendar.toDayAsDate((InstantDay) instant);
return calendarAllOpen.fromDayAsDate(day);
}
private Instant changeInstant(Instant instant) {
Instant result = cache.get(instant);
if (result == null) {
result = changeInstantSlow(instant);
cache.put(instant, result);
}
return result;
}
public double getStartingPosition(Instant instant) {
return basic.getStartingPosition(changeInstant(instant));
}
public double getEndingPosition(Instant instant) {
return basic.getEndingPosition(changeInstant(instant));
}
public double getWidth(Instant instant) {
return basic.getWidth(changeInstant(instant));
}
}

View File

@ -66,4 +66,8 @@ public class TimeScaleWithoutWeekEnd implements TimeScale {
return scale;
}
public double getEndingPosition(Instant instant) {
throw new UnsupportedOperationException();
}
}

View File

@ -57,9 +57,9 @@ public class VerbAre implements VerbPattern {
return new Verb() {
public CommandExecutionResult execute(Subject subject, Complement complement) {
final DayOfWeek day = (DayOfWeek) subject;
project.closeDayOfWeek(day);
return CommandExecutionResult.ok();
}
};
}
}

View File

@ -58,7 +58,7 @@ public class VerbHappens implements VerbPattern {
public CommandExecutionResult execute(Subject subject, Complement complement) {
final Task task = (Task) subject;
final TaskInstant when = (TaskInstant) complement;
task.setDuration(new DurationDay(1));
task.setLoad(LoadInDays.inDay(1));
task.setStart(when.getInstantTheorical());
return CommandExecutionResult.ok();
}

View File

@ -0,0 +1,73 @@
/* ========================================================================
* 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 VerbIs implements VerbPattern {
public Collection<ComplementPattern> getComplements() {
return Arrays.<ComplementPattern> asList(new ComplementClose());
}
public IRegex toRegex() {
return new RegexLeaf("is");
}
public Verb getVerb(final GanttDiagram project, RegexResult arg) {
return new Verb() {
public CommandExecutionResult execute(Subject subject, Complement complement) {
if (subject instanceof DayAsDate) {
final DayAsDate day = (DayAsDate) subject;
project.closeDayAsDate(day);
}
if (subject instanceof DaysAsDates) {
final DaysAsDates days = (DaysAsDates) subject;
for (DayAsDate d : days) {
project.closeDayAsDate(d);
}
}
return CommandExecutionResult.ok();
}
};
}
}

View File

@ -0,0 +1,74 @@
/* ========================================================================
* 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 VerbIsOff implements VerbPattern {
public Collection<ComplementPattern> getComplements() {
return Arrays.<ComplementPattern> asList(new ComplementDate(), new ComplementDates());
}
public IRegex toRegex() {
return new RegexLeaf("is off on");
}
public Verb getVerb(final GanttDiagram project, RegexResult arg) {
return new Verb() {
public CommandExecutionResult execute(Subject subject, Complement complement) {
final Resource resource = (Resource) subject;
if (complement instanceof DaysAsDates) {
for (DayAsDate when : (DaysAsDates) complement) {
resource.addCloseDay(project.convert(when));
}
} else {
final DayAsDate when = (DayAsDate) complement;
resource.addCloseDay(project.convert(when));
}
return CommandExecutionResult.ok();
}
};
}
}

View File

@ -57,8 +57,8 @@ public class VerbLasts implements VerbPattern {
return new Verb() {
public CommandExecutionResult execute(Subject subject, Complement complement) {
final Task task = (Task) subject;
final Duration duration = (Duration) complement;
task.setDuration(duration);
final Load duration = (Load) complement;
task.setLoad(duration);
return CommandExecutionResult.ok();
}

View File

@ -41,7 +41,7 @@ import net.sourceforge.plantuml.FontParam;
import net.sourceforge.plantuml.ISkinParam;
import net.sourceforge.plantuml.LineParam;
import net.sourceforge.plantuml.PaddingParam;
import net.sourceforge.plantuml.RoundParam;
import net.sourceforge.plantuml.CornerParam;
import net.sourceforge.plantuml.SkinParamUtils;
import net.sourceforge.plantuml.cucadiagram.Display;
import net.sourceforge.plantuml.cucadiagram.Stereotype;
@ -108,7 +108,7 @@ public class Rose implements Skin {
param.strictUmlStyle() == false, param.responseMessageBelowArrow());
}
final double padding = param.getPadding(PaddingParam.PARTICIPANT);
final double roundCorner = param.getRoundCorner(RoundParam.DEFAULT, null);
final double roundCorner = param.getRoundCorner(CornerParam.DEFAULT, null);
if (type == ComponentType.PARTICIPANT_HEAD) {
return new ComponentRoseParticipant(getSymbolContext(param, ColorParam.participantBorder), getUFont2(param,
FontParam.PARTICIPANT), stringsToDisplay, param, roundCorner, newFontForStereotype, getFontColor(

View File

@ -93,7 +93,7 @@ public class ClusterDecoration {
throw new UnsupportedOperationException();
}
final SymbolContext symbolContext = biColor.withShadow(shadowing).withStroke(defaultStroke)
.withRoundCorner(roundCorner);
.withCorner(roundCorner, 0);
symbol.asBig(title, titleAlignment, stereo, maxX - minX, maxY - minY, symbolContext).drawU(
ug.apply(new UTranslate(minX, minY)));
// return;

View File

@ -44,7 +44,7 @@ import net.sourceforge.plantuml.FontParam;
import net.sourceforge.plantuml.ISkinParam;
import net.sourceforge.plantuml.LineConfigurable;
import net.sourceforge.plantuml.LineParam;
import net.sourceforge.plantuml.RoundParam;
import net.sourceforge.plantuml.CornerParam;
import net.sourceforge.plantuml.SkinParamUtils;
import net.sourceforge.plantuml.Url;
import net.sourceforge.plantuml.creole.Stencil;
@ -85,7 +85,7 @@ public class EntityImageClass extends AbstractEntityImage implements Stencil, Wi
public EntityImageClass(GraphvizVersion version, ILeaf entity, ISkinParam skinParam, PortionShower portionShower) {
super(entity, entity.getColors(skinParam).mute(skinParam));
this.lineConfig = entity;
this.roundCorner = getSkinParam().getRoundCorner(RoundParam.DEFAULT, null);
this.roundCorner = getSkinParam().getRoundCorner(CornerParam.DEFAULT, null);
this.shield = version != null && version.useShield() && entity.hasNearDecoration() ? Margins.uniform(16)
: Margins.NONE;
final boolean showMethods = portionShower.showPortion(EntityPortion.METHOD, entity);

View File

@ -87,7 +87,6 @@ public class EntityImageDescription extends AbstractEntityImage {
private final Collection<Link> links;
private final boolean useRankSame;
public EntityImageDescription(ILeaf entity, ISkinParam skinParam, PortionShower portionShower,
Collection<Link> links) {
super(entity, entity.getColors(skinParam).mute(skinParam));
@ -116,10 +115,12 @@ public class EntityImageDescription extends AbstractEntityImage {
assert getStereo() == stereotype;
final HtmlColor forecolor = SkinParamUtils.getColor(getSkinParam(), symbol.getColorParamBorder(), stereotype);
final double roundCorner = symbol.getSkinParameter().getRoundCorner(getSkinParam(), stereotype);
final double diagonalCorner = symbol.getSkinParameter().getDiagonalCorner(getSkinParam(), stereotype);
final UStroke stroke = colors.muteStroke(symbol.getSkinParameter().getStroke(getSkinParam(), stereotype));
final SymbolContext ctx = new SymbolContext(backcolor, forecolor).withStroke(stroke)
.withShadow(getSkinParam().shadowing2(symbol.getSkinParameter())).withRoundCorner(roundCorner);
.withShadow(getSkinParam().shadowing2(symbol.getSkinParameter()))
.withCorner(roundCorner, diagonalCorner);
stereo = TextBlockUtils.empty(0, 0);

View File

@ -45,7 +45,7 @@ import net.sourceforge.plantuml.Direction;
import net.sourceforge.plantuml.FontParam;
import net.sourceforge.plantuml.ISkinParam;
import net.sourceforge.plantuml.LineParam;
import net.sourceforge.plantuml.RoundParam;
import net.sourceforge.plantuml.CornerParam;
import net.sourceforge.plantuml.SkinParamBackcolored;
import net.sourceforge.plantuml.SkinParamUtils;
import net.sourceforge.plantuml.Url;
@ -221,7 +221,7 @@ public class EntityImageNote extends AbstractEntityImage implements Stencil {
}
private double getRoundCorner() {
return skinParam.getRoundCorner(RoundParam.DEFAULT, null);
return skinParam.getRoundCorner(CornerParam.DEFAULT, null);
}
private static Point2D move(Point2D pt, double dx, double dy) {

View File

@ -43,7 +43,7 @@ import net.sourceforge.plantuml.FontParam;
import net.sourceforge.plantuml.ISkinParam;
import net.sourceforge.plantuml.LineConfigurable;
import net.sourceforge.plantuml.LineParam;
import net.sourceforge.plantuml.RoundParam;
import net.sourceforge.plantuml.CornerParam;
import net.sourceforge.plantuml.SkinParamUtils;
import net.sourceforge.plantuml.Url;
import net.sourceforge.plantuml.creole.Stencil;
@ -88,7 +88,7 @@ public class EntityImageObject extends AbstractEntityImage implements Stencil {
super(entity, skinParam);
this.lineConfig = entity;
final Stereotype stereotype = entity.getStereotype();
this.roundCorner = skinParam.getRoundCorner(RoundParam.DEFAULT, null);
this.roundCorner = skinParam.getRoundCorner(CornerParam.DEFAULT, null);
this.name = TextBlockUtils.withMargin(
entity.getDisplay().create(new FontConfiguration(getSkinParam(), FontParam.OBJECT, stereotype),
HorizontalAlignment.CENTER, skinParam), 2, 2);

View File

@ -110,6 +110,7 @@ public class Footprint {
drawText(x, y, (UText) shape);
} else if (shape instanceof UHorizontalLine) {
// Definitively a Horizontal line
// line.drawTitleInternalForFootprint(this, x, y);
} else if (shape instanceof ULine) {
// Probably a Horizontal line
} else if (shape instanceof UImage) {

View File

@ -104,7 +104,8 @@ public class Histogram implements TimeDrawing {
return Collections.emptyList();
}
for (int i = 0; i < changes.size(); i++) {
if (changes.get(i).getWhen().compareTo(tick) == 0) {
final int tickWithCurrentChangeTimeComparisonResult = changes.get(i).getWhen().compareTo(tick);
if (tickWithCurrentChangeTimeComparisonResult == 0) {
if (i == 0 && initialState == null) {
return Arrays.asList(changes.get(i).getState());
}
@ -113,8 +114,16 @@ public class Histogram implements TimeDrawing {
}
return Arrays.asList(changes.get(i - 1).getState(), changes.get(i).getState());
}
if (changes.get(i).getWhen().compareTo(tick) > 0) {
return Collections.singletonList(changes.get(i - 1).getState());
if (tickWithCurrentChangeTimeComparisonResult > 0) {
final int changeIndex;
if (i == 0) {
// if this time tick was not yet defined in any place, and is less then the first one,
// assume it's the leftmost
changeIndex = 0;
} else {
changeIndex = i - 1;
}
return Collections.singletonList(changes.get(changeIndex).getState());
}
}
return Collections.singletonList(changes.get(changes.size() - 1).getState());

View File

@ -63,7 +63,7 @@ import net.sourceforge.plantuml.FileUtils;
import net.sourceforge.plantuml.ISkinParam;
import net.sourceforge.plantuml.LineParam;
import net.sourceforge.plantuml.OptionFlags;
import net.sourceforge.plantuml.RoundParam;
import net.sourceforge.plantuml.CornerParam;
import net.sourceforge.plantuml.StringUtils;
import net.sourceforge.plantuml.Url;
import net.sourceforge.plantuml.anim.AffineTransformation;
@ -143,7 +143,7 @@ public class ImageBuilder {
final Rose rose = new Rose();
this.borderColor = rose.getHtmlColor(skinParam, ColorParam.diagramBorder);
this.borderStroke = skinParam.getThickness(LineParam.diagramBorder, null);
this.borderCorner = skinParam.getRoundCorner(RoundParam.diagramBorder, null);
this.borderCorner = skinParam.getRoundCorner(CornerParam.diagramBorder, null);
if (borderStroke == null && borderColor != null) {
this.borderStroke = new UStroke();
}

View File

@ -144,6 +144,15 @@ public class UHorizontalLine implements UShape {
ug.apply(new UTranslate(startingX, y)).draw(new ULine(endingX - startingX, 0));
}
// public void drawTitleInternalForFootprint(UGraphic ug, double x, double y) {
// if (title == null || blankTitle) {
// return;
// }
// final Dimension2D dimTitle = title.calculateDimension(ug.getStringBounder());
// final double y1 = y - dimTitle.getHeight() / 2 - 0.5;
// title.drawU(ug.apply(new UTranslate(skipAtStart, y1)));
// }
public void drawTitleInternal(UGraphic ug, double startingX, double endingX, double y, boolean clearArea) {
if (title == null || blankTitle) {
return;

View File

@ -43,7 +43,7 @@ public class Version {
private static final int MAJOR_SEPARATOR = 1000000;
public static int version() {
return 1201802;
return 1201803;
}
public static int versionPatched() {
@ -88,7 +88,7 @@ public class Version {
}
public static long compileTime() {
return 1520616044801L;
return 1522947555139L;
}
public static String compileTimeString() {

View File

@ -30,8 +30,9 @@ public class VP8Decoder {
coefProbs = Globals.getDefaultCoefProbs();
}
public void decodeFrame(ImageInputStream stream, boolean debug)
public void decodeFrame(ImageInputStream stream)
throws IOException {
final boolean debug = false;
coefProbs = Globals.getDefaultCoefProbs();
f = new VP8Frame(stream, coefProbs);
if (f.decodeFrame(debug)) {
@ -52,27 +53,9 @@ public class VP8Decoder {
return f.getWidth();
}
@SuppressWarnings("unused")
private void writeFile(int[][] data) {
FileOutputStream out;
try {
out = new FileOutputStream("outagain.raw");
for (int y = 0; y < data[0].length; y++)
for (int x = 0; x < data.length; x++) {
out.write(data[x][y]);
out.write(data[x][y]);
out.write(data[x][y]);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void writePGMFile(String fileName, VP8Frame frame) {
FileOutputStream out;
try {
int[][] yData = frame.getYBuffer();