From 8b5a1521e713c1637385251849dda47cd9dea2b0 Mon Sep 17 00:00:00 2001 From: Arnaud Roques Date: Thu, 23 Nov 2023 17:50:00 +0100 Subject: [PATCH] fix: several Gantt improvement https://forum.plantuml.net/18397/gantt-how-handle-resource-starts-terminates-specific-date https://forum.plantuml.net/17571/is-it-possible-to-set-gantt-tasks-to-be-incomplete-by-default?show=17571#q17571 https://forum.plantuml.net/18128/gantt-diagram-vertical-separator-styling?show=18128#q18128 --- gradle.properties | 2 +- skin/plantuml.skin | 5 + src/net/sourceforge/plantuml/OptionPrint.java | 130 ++++++++--------- .../plantuml/project/ConstantPlan.java | 6 + .../plantuml/project/GanttDiagram.java | 48 +++++- .../plantuml/project/GanttDiagramFactory.java | 2 + .../plantuml/project/LoadPlanable.java | 2 + .../plantuml/project/OpenClose.java | 25 ++++ .../plantuml/project/PlanUtils.java | 18 +++ .../project/TimeHeaderParameters.java | 13 +- .../project/command/CommandPrintBetween.java | 2 +- .../command/CommandTaskCompleteDefault.java | 84 +++++++++++ .../plantuml/project/core/Resource.java | 13 ++ .../plantuml/project/core/Task.java | 2 + .../plantuml/project/core/TaskGroup.java | 20 +++ .../plantuml/project/core/TaskImpl.java | 45 +++++- .../plantuml/project/core/TaskSeparator.java | 19 +++ .../plantuml/project/draw/ResourceDraw.java | 91 +----------- .../project/draw/ResourceDrawBasicImpl.java | 132 +++++++++++++++++ .../project/draw/ResourceDrawVersion2.java | 138 ++++++++++++++++++ .../project/draw/TaskDrawRegular.java | 6 +- .../plantuml/project/draw/TimeHeader.java | 66 ++++----- .../project/draw/TimeHeaderCalendar.java | 14 +- .../project/draw/TimeHeaderDaily.java | 30 ++-- .../project/draw/TimeHeaderMonthly.java | 41 +++--- .../project/draw/TimeHeaderQuarterly.java | 41 +++--- .../project/draw/TimeHeaderSimple.java | 55 +++---- .../project/draw/TimeHeaderWeekly.java | 36 ++--- .../project/draw/TimeHeaderYearly.java | 25 ++-- .../plantuml/project/lang/ComplementDate.java | 48 ++++-- .../project/lang/SentenceHappensDate.java | 2 +- .../project/lang/SentencePausesDate.java | 2 +- .../lang/SentenceTaskEndsAbsolute.java | 2 +- .../lang/SentenceTaskStartsAbsolute.java | 4 +- .../lang/SentenceTaskStartsOnlyRelative.java | 58 ++++++++ .../plantuml/project/lang/SubjectProject.java | 2 +- .../project/lang/SubjectResource.java | 39 ++++- .../project/lang/SubjectSeparator.java | 4 +- .../plantuml/project/lang/SubjectTask.java | 10 +- .../plantuml/project/lang/SubjectToday.java | 2 +- .../plantuml/project/lang/Verbs.java | 16 ++ .../solver/ImpossibleSolvingException.java | 44 ++++++ .../plantuml/project/solver/SolverImpl.java | 11 +- src/net/sourceforge/plantuml/style/SName.java | 3 +- .../sourceforge/plantuml/version/Version.java | 2 +- 45 files changed, 984 insertions(+), 376 deletions(-) create mode 100644 src/net/sourceforge/plantuml/project/command/CommandTaskCompleteDefault.java create mode 100644 src/net/sourceforge/plantuml/project/draw/ResourceDrawBasicImpl.java create mode 100644 src/net/sourceforge/plantuml/project/draw/ResourceDrawVersion2.java create mode 100644 src/net/sourceforge/plantuml/project/lang/SentenceTaskStartsOnlyRelative.java create mode 100644 src/net/sourceforge/plantuml/project/solver/ImpossibleSolvingException.java diff --git a/gradle.properties b/gradle.properties index b1f62183a..2318ed74a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ # Warning, "version" should be the same in gradle.properties and Version.java # Any idea anyone how to magically synchronize those :-) ? -version = 1.2023.13beta2 +version = 1.2023.13beta3 org.gradle.workers.max = 3 \ No newline at end of file diff --git a/skin/plantuml.skin b/skin/plantuml.skin index 9f7920474..ecba3aa67 100644 --- a/skin/plantuml.skin +++ b/skin/plantuml.skin @@ -367,6 +367,11 @@ ganttDiagram { Margin 5 Padding 5 } + verticalSeparator { + LineThickness 2 + LineStyle 2-2 + LineColor black + } timeline { BackgroundColor transparent LineColor #C0C0C0 diff --git a/src/net/sourceforge/plantuml/OptionPrint.java b/src/net/sourceforge/plantuml/OptionPrint.java index df6938de7..984b8db51 100644 --- a/src/net/sourceforge/plantuml/OptionPrint.java +++ b/src/net/sourceforge/plantuml/OptionPrint.java @@ -85,83 +85,77 @@ public class OptionPrint { System.out.println("\t?\tone and only one character but '" + SFile.separator + "'"); System.out.println("\t**\tmeans any characters (used to recurse through directories)"); System.out.println(); - System.out.println("where options include:"); - System.out.println(" -darkmode\t\tTo use dark mode for diagrams"); - System.out.println(" -gui\t\tTo run the graphical user interface"); - System.out.println(" -tpng\t\tTo generate images using PNG format (default)"); - System.out.println(" -tsvg\t\tTo generate images using SVG format"); - System.out.println(" -teps\t\tTo generate images using EPS format"); - System.out.println(" -tpdf\t\tTo generate images using PDF format"); - System.out.println(" -tvdx\t\tTo generate images using VDX format"); - System.out.println(" -txmi\t\tTo generate XMI file for class diagram"); - System.out.println(" -tscxml\t\tTo generate SCXML file for state diagram"); - System.out.println(" -thtml\t\tTo generate HTML file for class diagram"); - System.out.println(" -ttxt\t\tTo generate images with ASCII art"); - System.out.println(" -tutxt\t\tTo generate images with ASCII art using Unicode characters"); - System.out.println(" -tlatex\t\tTo generate images using LaTeX/Tikz format"); - System.out.println(" -tlatex:nopreamble\tTo generate images using LaTeX/Tikz format without preamble"); - System.out.println(" -o[utput] \"dir\"\tTo generate images in the specified directory"); - System.out.println(" -DVAR1=value\tTo set a preprocessing variable as if '!define VAR1 value' were used"); - System.out.println(" -Sparam1=value\tTo set a skin parameter as if 'skinparam param1 value' were used"); - System.out.println(" -Ppragma1=value\tTo set pragma as if '!pragma pragma1 value' were used"); - // System.out.println(" -config \"file\"\tTo read the provided config file - // before each diagram"); final char separator = SFile.separatorChar; - System.out.println(" -I" + separator + "path" + separator + "to" + separator - + "file\tTo include file as if '!include file' were used"); - System.out.println( - " -I" + separator + "path" + separator + "to" + separator + "*.puml\tTo include files with pattern"); - System.out.println(" -theme xxx\t\tTo use a specific theme"); - System.out.println(" -charset xxx\tTo use a specific charset (default is " + charset + ")"); - System.out.println(" -e[x]clude pattern\tTo exclude files that match the provided pattern"); - System.out.println(" -metadata\t\tTo retrieve PlantUML sources from PNG images"); - System.out.println(" -nometadata\t\tTo NOT export metadata in PNG/SVG generated files"); + System.out.println("where options include:"); + System.out.println(" -author[s]\t\tTo print information about PlantUML authors"); System.out.println(" -checkmetadata\t\tSkip PNG files that don't need to be regenerated"); - System.out.println(" -version\t\tTo display information about PlantUML and Java versions"); - System.out.println(" -v[erbose]\t\tTo have log information"); - System.out.println(" -quiet\t\tTo NOT print error message into the console"); - System.out.println(" -debugsvek\t\tTo generate intermediate svek files"); - System.out.println(" -h[elp]\t\tTo display this help message"); - System.out.println(" -testdot\t\tTo test the installation of graphviz"); - System.out.println(" -graphvizdot \"exe\"\tTo specify dot executable"); - System.out.println(" -p[ipe]\t\tTo use stdin for PlantUML source and stdout for PNG/SVG/EPS generation"); - System.out.println( - " -encodesprite 4|8|16[z] \"file\"\tTo encode a sprite at gray level (z for compression) from an image"); - System.out.println(" -computeurl|-encodeurl\tTo compute the encoded URL of a PlantUML source file"); - System.out.println(" -decodeurl\t\tTo retrieve the PlantUML source from an encoded URL"); - System.out.println(" -syntax\t\tTo report any syntax error from standard input without generating images"); - System.out.println(" -language\t\tTo print the list of PlantUML keywords"); - // System.out.println(" -nosuggestengine\tTo disable the suggest engine when - // errors in diagrams"); System.out.println(" -checkonly\t\tTo check the syntax of files without generating images"); + System.out.println(" -charset xxx\tTo use a specific charset (default is " + charset + ")"); + System.out.println(" -computeurl|-encodeurl\tTo compute the encoded URL of a PlantUML source file"); + // System.out.println(" -config \"file\"\tTo read the provided config file + System.out.println(" -cypher\t\tTo cypher texts of diagrams so that you can share them"); + System.out.println(" -DVAR1=value\tTo set a preprocessing variable as if '!define VAR1 value' were used"); + System.out.println(" -darkmode\t\tTo use dark mode for diagrams"); + System.out.println(" -debugsvek\t\tTo generate intermediate svek files"); + System.out.println(" -decodeurl\t\tTo retrieve the PlantUML source from an encoded URL"); + System.out.println(" -disablestats\tTo disable statistics computation (default)"); + System.out.println(" -duration\t\tTo print the duration of complete diagrams processing"); + System.out.println(" -e[x]clude pattern\tTo exclude files that match the provided pattern"); + System.out.println(" -enablestats\tTo enable statistics computation"); + System.out.println(" -encodesprite 4|8|16[z] \"file\"\tTo encode a sprite at gray level (z for compression) from an image"); + System.out.println(" -extractstdlib\tTo extract PlantUML Standard Library into stdlib folder"); System.out.println(" -failfast\t\tTo stop processing as soon as a syntax error in diagram occurs"); System.out.println(" -failfast2\t\tTo do a first syntax check before processing files, to fail even faster"); - System.out.println(" -noerror\t\tTo skip images when error in diagrams"); - System.out.println(" -duration\t\tTo print the duration of complete diagrams processing"); + System.out.println(" -filedir xxx\tTo behave as if the PlantUML source is in this dir (only affects '-pipe' and PicoWeb 'POST /render')"); + System.out.println(" -filename \"example.puml\"\tTo override %filename% variable"); + System.out.println(" -graphvizdot \"exe\"\tTo specify dot executable"); + System.out.println(" -gui\t\tTo run the graphical user interface"); + System.out.println(" -h[elp]\t\tTo display this help message"); + System.out.println(" -htmlstats\t\tTo output general statistics in file plantuml-stats.html"); + System.out.println(" -I" + separator + "path" + separator + "to" + separator + "file\tTo include file as if '!include file' were used"); + System.out.println(" -I" + separator + "path" + separator + "to" + separator + "*.puml\tTo include files with pattern"); + System.out.println(" -language\t\tTo print the list of PlantUML keywords"); + System.out.println(" -loopstats\t\tTo continuously print statistics about usage"); + System.out.println(" -metadata\t\tTo retrieve PlantUML sources from PNG images"); System.out.println(" -nbthread N\t\tTo use (N) threads for processing"); System.out.println(" -nbthread auto\tTo use " + Option.defaultNbThreads() + " threads for processing"); - System.out - .println(" -timeout N\t\tProcessing timeout in (N) seconds. Defaults to 15 minutes (900 seconds)."); - System.out.println(" -author[s]\t\tTo print information about PlantUML authors"); + System.out.println(" -noerror\t\tTo skip images when error in diagrams"); + System.out.println(" -nometadata\t\tTo NOT export metadata in PNG/SVG generated files"); + System.out.println(" -o[utput] \"dir\"\tTo generate images in the specified directory"); System.out.println(" -overwrite\t\tTo allow to overwrite read only files"); - System.out.println(" -printfonts\t\tTo print fonts available on your system"); - System.out.println(" -enablestats\tTo enable statistics computation"); - System.out.println(" -disablestats\tTo disable statistics computation (default)"); - System.out.println(" -htmlstats\t\tTo output general statistics in file plantuml-stats.html"); - System.out.println(" -xmlstats\t\tTo output general statistics in file plantuml-stats.xml"); - System.out.println(" -realtimestats\tTo generate statistics on the fly rather than at the end"); - System.out.println(" -loopstats\t\tTo continuously print statistics about usage"); - System.out.println(" -splash\t\tTo display a splash screen with some progress bar"); - System.out.println(" -progress\t\tTo display a textual progress bar in console"); - System.out.println(" -pipeimageindex N\tTo generate the Nth image with pipe option"); - System.out.println(" -stdlib\t\tTo print standard library info"); - System.out.println(" -extractstdlib\tTo extract PlantUML Standard Library into stdlib folder"); - System.out.println( - " -filedir xxx\tTo behave as if the PlantUML source is in this dir (only affects '-pipe' and PicoWeb 'POST /render')"); - System.out.println(" -filename \"example.puml\"\tTo override %filename% variable"); - System.out.println(" -preproc\t\tTo output preprocessor text of diagrams"); - System.out.println(" -cypher\t\tTo cypher texts of diagrams so that you can share them"); + System.out.println(" -Ppragma1=value\tTo set pragma as if '!pragma pragma1 value' were used"); + System.out.println(" -p[ipe]\t\tTo use stdin for PlantUML source and stdout for PNG/SVG/EPS generation"); System.out.println(" -picoweb\t\tTo start internal HTTP Server. See https://plantuml.com/picoweb"); + System.out.println(" -pipeimageindex N\tTo generate the Nth image with pipe option"); + System.out.println(" -preproc\t\tTo output preprocessor text of diagrams"); + System.out.println(" -printfonts\t\tTo print fonts available on your system"); + System.out.println(" -progress\t\tTo display a textual progress bar in console"); + System.out.println(" -quiet\t\tTo NOT print error message into the console"); + System.out.println(" -realtimestats\tTo generate statistics on the fly rather than at the end"); + System.out.println(" -Sparam1=value\tTo set a skin parameter as if 'skinparam param1 value' were used"); + System.out.println(" -splash\t\tTo display a splash screen with some progress bar"); + System.out.println(" -stdlib\t\tTo print standard library info"); + System.out.println(" -syntax\t\tTo report any syntax error from standard input without generating images"); + System.out.println(" -testdot\t\tTo test the installation of graphviz"); + System.out.println(" -theme xxx\t\tTo use a specific theme"); + System.out.println(" -timeout N\t\tProcessing timeout in (N) seconds. Defaults to 15 minutes (900 seconds)."); + System.out.println(" -teps\t\tTo generate images using EPS format"); + System.out.println(" -testdot\t\tTo test the installation of graphviz"); + System.out.println(" -theme xxx\t\tTo use a specific theme"); + System.out.println(" -thtml\t\tTo generate HTML file for class diagram"); + System.out.println(" -tlatex:nopreamble\tTo generate images using LaTeX/Tikz format without preamble"); + System.out.println(" -tlatex\t\tTo generate images using LaTeX/Tikz format"); + System.out.println(" -tpdf\t\tTo generate images using PDF format"); + System.out.println(" -tpng\t\tTo generate images using PNG format (default)"); + System.out.println(" -tscxml\t\tTo generate SCXML file for state diagram"); + System.out.println(" -tsvg\t\tTo generate images using SVG format"); + System.out.println(" -ttxt\t\tTo generate images with ASCII art"); + System.out.println(" -tutxt\t\tTo generate images with ASCII art using Unicode characters"); + System.out.println(" -tvdx\t\tTo generate images using VDX format"); + System.out.println(" -txmi\t\tTo generate XMI file for class diagram"); + System.out.println(" -v[erbose]\t\tTo have log information"); + System.out.println(" -version\t\tTo display information about PlantUML and Java versions"); + System.out.println(" -xmlstats\t\tTo output general statistics in file plantuml-stats.xml"); System.out.println(); System.out.println("If needed, you can setup the environment variable GRAPHVIZ_DOT."); exit(0); diff --git a/src/net/sourceforge/plantuml/project/ConstantPlan.java b/src/net/sourceforge/plantuml/project/ConstantPlan.java index 67ebf79eb..0d0b74b3c 100644 --- a/src/net/sourceforge/plantuml/project/ConstantPlan.java +++ b/src/net/sourceforge/plantuml/project/ConstantPlan.java @@ -53,8 +53,14 @@ public class ConstantPlan implements LoadPlanable { return new ConstantPlan(load); } + @Override public int getLoadAt(Day instant) { return loadPerInstant; } + + @Override + public Day getLastDayIfAny() { + return null; + } } diff --git a/src/net/sourceforge/plantuml/project/GanttDiagram.java b/src/net/sourceforge/plantuml/project/GanttDiagram.java index fdc8a18c0..b3207c3df 100644 --- a/src/net/sourceforge/plantuml/project/GanttDiagram.java +++ b/src/net/sourceforge/plantuml/project/GanttDiagram.java @@ -86,6 +86,7 @@ import net.sourceforge.plantuml.project.core.TaskInstant; import net.sourceforge.plantuml.project.core.TaskSeparator; import net.sourceforge.plantuml.project.draw.FingerPrint; import net.sourceforge.plantuml.project.draw.ResourceDraw; +import net.sourceforge.plantuml.project.draw.ResourceDrawVersion2; import net.sourceforge.plantuml.project.draw.TaskDraw; import net.sourceforge.plantuml.project.draw.TaskDrawDiamond; import net.sourceforge.plantuml.project.draw.TaskDrawGroup; @@ -99,6 +100,7 @@ import net.sourceforge.plantuml.project.draw.TimeHeaderSimple; import net.sourceforge.plantuml.project.draw.TimeHeaderWeekly; import net.sourceforge.plantuml.project.draw.TimeHeaderYearly; import net.sourceforge.plantuml.project.lang.CenterBorderColor; +import net.sourceforge.plantuml.project.solver.ImpossibleSolvingException; import net.sourceforge.plantuml.project.time.Day; import net.sourceforge.plantuml.project.time.DayOfWeek; import net.sourceforge.plantuml.project.time.WeekNumberStrategy; @@ -149,6 +151,8 @@ public class GanttDiagram extends TitledDiagram implements ToTaskDraw, WithSprit private final RealOrigin origin = RealUtils.createOrigin(); + private int defaultCompletion = 100; + public CommandExecutionResult changeLanguage(String lang) { this.locale = new Locale(lang); return CommandExecutionResult.ok(); @@ -202,6 +206,16 @@ public class GanttDiagram extends TitledDiagram implements ToTaskDraw, WithSprit return false; } + @Override + public String checkFinalError() { + try { + initMinMax(); + } catch (ImpossibleSolvingException ex) { + return ex.getMessage(); + } + return null; + } + @Override protected TextBlock getTextBlock() { final FileFormatOption fileFormatOption = new FileFormatOption(FileFormat.PNG); @@ -312,7 +326,8 @@ public class GanttDiagram extends TitledDiagram implements ToTaskDraw, WithSprit private TimeHeaderParameters thParam() { return new TimeHeaderParameters(colorDays(), getFactorScale(), min, max, getIHtmlColorSet(), getTimelineStyle(), - getClosedStyle(), locale, openClose, colorDaysOfWeek, verticalSeparatorBefore); + getClosedStyle(), locale, openClose, colorDaysOfWeek, verticalSeparatorBefore, + getVerticalSeparatorStyle()); } private Map colorDays() { @@ -330,6 +345,11 @@ public class GanttDiagram extends TitledDiagram implements ToTaskDraw, WithSprit .getMergedStyle(getCurrentStyleBuilder()); } + private Style getVerticalSeparatorStyle() { + return StyleSignatureBasic.of(SName.root, SName.element, SName.ganttDiagram, SName.verticalSeparator) + .getMergedStyle(getCurrentStyleBuilder()); + } + private double getTotalHeight(TimeHeader timeHeader) { if (showFootbox) return totalHeightWithoutFooter + timeHeader.getTimeFooterHeight(); @@ -457,14 +477,19 @@ public class GanttDiagram extends TitledDiagram implements ToTaskDraw, WithSprit yy = headerHeight; } else if (this.hideResourceFoobox == false) for (Resource res : resources.values()) { - final ResourceDraw draw = new ResourceDraw(this, res, timeScale, yy, min, max); + final ResourceDraw draw = buildResourceDraw(this, res, timeScale, yy, min, max); res.setTaskDraw(draw); - yy += draw.getHeight(); + yy += draw.getHeight(stringBounder); } this.totalHeightWithoutFooter = yy; } + private ResourceDraw buildResourceDraw(GanttDiagram gantt, Resource res, TimeScale timeScale, double y, Day min, + Day max) { + return new ResourceDrawVersion2(gantt, res, timeScale, y, min, max); + } + private Collection getConstraints(Task task) { final List result = new ArrayList<>(); for (GanttConstraint constraint : constraints) { @@ -603,7 +628,7 @@ public class GanttDiagram extends TitledDiagram implements ToTaskDraw, WithSprit final OpenClose except = this.openCloseForTask.get(codeOrShortName); result = new TaskImpl(getSkinParam().getCurrentStyleBuilder(), code, openClose.mutateMe(except), - openClose.getStartingDay()); + openClose.getStartingDay(), defaultCompletion); if (currentGroup != null) currentGroup.addTask(result); @@ -866,4 +891,19 @@ public class GanttDiagram extends TitledDiagram implements ToTaskDraw, WithSprit verticalSeparatorBefore.add(day); } + public void setTaskDefaultCompletion(int defaultCompletion) { + this.defaultCompletion = defaultCompletion; + } + + public List getAllTasksForResource(Resource res) { + final List result = new ArrayList(); + for (Task task : tasks.values()) + if (task.isAssignedTo(res)) { + final TaskDrawRegular draw = (TaskDrawRegular) draws.get(task); + result.add(draw); + } + + return Collections.unmodifiableList(result); + } + } diff --git a/src/net/sourceforge/plantuml/project/GanttDiagramFactory.java b/src/net/sourceforge/plantuml/project/GanttDiagramFactory.java index 392990439..eb7d662d3 100644 --- a/src/net/sourceforge/plantuml/project/GanttDiagramFactory.java +++ b/src/net/sourceforge/plantuml/project/GanttDiagramFactory.java @@ -59,6 +59,7 @@ import net.sourceforge.plantuml.project.command.CommandNoteBottom; import net.sourceforge.plantuml.project.command.CommandPrintBetween; import net.sourceforge.plantuml.project.command.CommandPrintScale; import net.sourceforge.plantuml.project.command.CommandSeparator; +import net.sourceforge.plantuml.project.command.CommandTaskCompleteDefault; import net.sourceforge.plantuml.project.command.CommandWeekNumberStrategy; import net.sourceforge.plantuml.project.command.NaturalCommand; import net.sourceforge.plantuml.project.lang.SentenceAnd; @@ -115,6 +116,7 @@ public class GanttDiagramFactory extends PSystemCommandFactory { cmds.add(new CommandLabelOnColumn()); cmds.add(new CommandHideResourceName()); cmds.add(new CommandHideResourceFootbox()); + cmds.add(new CommandTaskCompleteDefault()); } private void addLanguageCommands(List cmd) { diff --git a/src/net/sourceforge/plantuml/project/LoadPlanable.java b/src/net/sourceforge/plantuml/project/LoadPlanable.java index d8e71f71d..76ad4c539 100644 --- a/src/net/sourceforge/plantuml/project/LoadPlanable.java +++ b/src/net/sourceforge/plantuml/project/LoadPlanable.java @@ -40,4 +40,6 @@ import net.sourceforge.plantuml.project.time.Day; public interface LoadPlanable { public int getLoadAt(Day instant); + + public Day getLastDayIfAny(); } diff --git a/src/net/sourceforge/plantuml/project/OpenClose.java b/src/net/sourceforge/plantuml/project/OpenClose.java index 1e8afbf65..7d0256c6d 100644 --- a/src/net/sourceforge/plantuml/project/OpenClose.java +++ b/src/net/sourceforge/plantuml/project/OpenClose.java @@ -49,6 +49,8 @@ public class OpenClose implements Histogram, LoadPlanable { private final Map weekdayStatus = new EnumMap<>(DayOfWeek.class); private final Map dayStatus = new HashMap<>(); private Day startingDay; + private Day offBefore; + private Day offAfter; public int daysInWeek() { int result = 7; @@ -89,6 +91,11 @@ public class OpenClose implements Histogram, LoadPlanable { } private DayStatus getLocalStatus(Day day) { + if (offBefore != null && day.compareTo(offBefore) < 0) + return DayStatus.CLOSE; + if (offAfter != null && day.compareTo(offAfter) > 0) + return DayStatus.CLOSE; + final DayStatus status1 = dayStatus.get(day); if (status1 != null) return status1; @@ -174,6 +181,14 @@ public class OpenClose implements Histogram, LoadPlanable { return getLoatAtInternal(day); } + public void setOffBeforeDate(Day day) { + this.offBefore = day; + } + + public void setOffAfterDate(Day day) { + this.offAfter = day; + } + private int getLoatAtInternal(Day day) { if (isClosed(day)) return 0; @@ -193,8 +208,18 @@ public class OpenClose implements Histogram, LoadPlanable { return 100; return OpenClose.this.getLoadAt(instant); } + + @Override + public Day getLastDayIfAny() { + return offAfter; + } }; return this; } + @Override + public Day getLastDayIfAny() { + return offAfter; + } + } diff --git a/src/net/sourceforge/plantuml/project/PlanUtils.java b/src/net/sourceforge/plantuml/project/PlanUtils.java index b80f591b8..d75adfd5e 100644 --- a/src/net/sourceforge/plantuml/project/PlanUtils.java +++ b/src/net/sourceforge/plantuml/project/PlanUtils.java @@ -48,6 +48,10 @@ public class PlanUtils { public int getLoadAt(Day instant) { return Math.min(p1.getLoadAt(instant), p2.getLoadAt(instant)); } + + public Day getLastDayIfAny() { + return lastOf(p1.getLastDayIfAny(), p2.getLastDayIfAny()); + } }; } @@ -56,7 +60,21 @@ public class PlanUtils { public int getLoadAt(Day instant) { return p1.getLoadAt(instant) * p2.getLoadAt(instant) / 100; } + + public Day getLastDayIfAny() { + return lastOf(p1.getLastDayIfAny(), p2.getLastDayIfAny()); + } }; } + private static Day lastOf(Day day1, Day day2) { + if (day1 == null) + return day2; + if (day2 == null) + return day1; + if (day1.compareTo(day2) > 0) + return day1; + return day2; + } + } diff --git a/src/net/sourceforge/plantuml/project/TimeHeaderParameters.java b/src/net/sourceforge/plantuml/project/TimeHeaderParameters.java index 95bcdd4f4..d19da40ce 100644 --- a/src/net/sourceforge/plantuml/project/TimeHeaderParameters.java +++ b/src/net/sourceforge/plantuml/project/TimeHeaderParameters.java @@ -39,10 +39,13 @@ import java.util.Locale; import java.util.Map; import java.util.Set; +import net.sourceforge.plantuml.klimt.UStroke; import net.sourceforge.plantuml.klimt.color.HColor; import net.sourceforge.plantuml.klimt.color.HColorSet; +import net.sourceforge.plantuml.klimt.drawing.UGraphic; import net.sourceforge.plantuml.project.time.Day; import net.sourceforge.plantuml.project.time.DayOfWeek; +import net.sourceforge.plantuml.style.PName; import net.sourceforge.plantuml.style.Style; public class TimeHeaderParameters { @@ -54,6 +57,7 @@ public class TimeHeaderParameters { private final HColorSet colorSet; private final Style timelineStyle; private final Style closedStyle; + private final Style verticalSeparatorStyle; private final Locale locale; private final OpenClose openClose; private final Map colorDaysOfWeek; @@ -61,7 +65,7 @@ public class TimeHeaderParameters { public TimeHeaderParameters(Map colorDays, double scale, Day min, Day max, HColorSet colorSet, Style timelineStyle, Style closedStyle, Locale locale, OpenClose openClose, - Map colorDaysOfWeek, Set verticalSeparatorBefore) { + Map colorDaysOfWeek, Set verticalSeparatorBefore, Style verticalSeparatorStyle) { this.colorDays = colorDays; this.scale = scale; this.min = min; @@ -73,6 +77,7 @@ public class TimeHeaderParameters { this.openClose = openClose; this.colorDaysOfWeek = colorDaysOfWeek; this.verticalSeparatorBefore = verticalSeparatorBefore; + this.verticalSeparatorStyle = verticalSeparatorStyle; } public HColor getColor(Day wink) { @@ -123,4 +128,10 @@ public class TimeHeaderParameters { return verticalSeparatorBefore; } + public final UGraphic forVerticalSeparator(UGraphic ug) { + final HColor color = verticalSeparatorStyle.value(PName.LineColor).asColor(getColorSet()); + final UStroke stroke = verticalSeparatorStyle.getStroke(); + return ug.apply(color).apply(stroke); + } + } diff --git a/src/net/sourceforge/plantuml/project/command/CommandPrintBetween.java b/src/net/sourceforge/plantuml/project/command/CommandPrintBetween.java index cc0412fb2..f13460e09 100644 --- a/src/net/sourceforge/plantuml/project/command/CommandPrintBetween.java +++ b/src/net/sourceforge/plantuml/project/command/CommandPrintBetween.java @@ -48,7 +48,7 @@ import net.sourceforge.plantuml.utils.LineLocation; public class CommandPrintBetween extends SingleLineCommand2 { - private static final ComplementDate pattern = new ComplementDate(); + private static final ComplementDate pattern = ComplementDate.any(); public CommandPrintBetween() { super(getRegexConcat()); diff --git a/src/net/sourceforge/plantuml/project/command/CommandTaskCompleteDefault.java b/src/net/sourceforge/plantuml/project/command/CommandTaskCompleteDefault.java new file mode 100644 index 000000000..aeec499cd --- /dev/null +++ b/src/net/sourceforge/plantuml/project/command/CommandTaskCompleteDefault.java @@ -0,0 +1,84 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2024, Arnaud Roques + * + * Project Info: https://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * https://plantuml.com/patreon (only 1$ per month!) + * https://plantuml.com/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.project.command; + +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.command.SingleLineCommand2; +import net.sourceforge.plantuml.klimt.color.NoSuchColorException; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.regex.IRegex; +import net.sourceforge.plantuml.regex.RegexConcat; +import net.sourceforge.plantuml.regex.RegexLeaf; +import net.sourceforge.plantuml.regex.RegexOr; +import net.sourceforge.plantuml.regex.RegexResult; +import net.sourceforge.plantuml.utils.LineLocation; + +public class CommandTaskCompleteDefault extends SingleLineCommand2 { + + public CommandTaskCompleteDefault() { + super(getRegexConcat()); + } + + static IRegex getRegexConcat() { + return RegexConcat.build(CommandTaskCompleteDefault.class.getName(), RegexLeaf.start(), // + new RegexLeaf("task"), // + RegexLeaf.spaceOneOrMore(), // + new RegexOr(// + new RegexLeaf("default[%s]+completion"), // + new RegexLeaf("completion[%s]+default")), // + RegexLeaf.spaceOneOrMore(), // + new RegexLeaf("to"), // + RegexLeaf.spaceOneOrMore(), // + new RegexLeaf("VALUE", "(\\d+)"), // + new RegexLeaf(".*"), // + RegexLeaf.spaceZeroOrMore(), // + RegexLeaf.end()); + } + + @Override + protected CommandExecutionResult executeArg(GanttDiagram diagram, LineLocation location, RegexResult arg) + throws NoSuchColorException { + + final int value = Integer.parseInt(arg.get("VALUE", 0)); + if (value > 100) + return CommandExecutionResult.error("Completetion must between 0 and 100"); + + diagram.setTaskDefaultCompletion(value); + + return CommandExecutionResult.ok(); + } + +} diff --git a/src/net/sourceforge/plantuml/project/core/Resource.java b/src/net/sourceforge/plantuml/project/core/Resource.java index 687b479a2..594209158 100644 --- a/src/net/sourceforge/plantuml/project/core/Resource.java +++ b/src/net/sourceforge/plantuml/project/core/Resource.java @@ -94,4 +94,17 @@ public class Resource { public void addCloseDay(DayOfWeek day) { openClose.close(day); } + + public void setOffBeforeDate(Day day) { + openClose.setOffBeforeDate(day); + } + + public void setOffAfterDate(Day day) { + openClose.setOffAfterDate(day); + } + + public Day getLastDayIfAny() { + return openClose.getLastDayIfAny(); + } + } diff --git a/src/net/sourceforge/plantuml/project/core/Task.java b/src/net/sourceforge/plantuml/project/core/Task.java index 653cff0d2..178b6283e 100644 --- a/src/net/sourceforge/plantuml/project/core/Task.java +++ b/src/net/sourceforge/plantuml/project/core/Task.java @@ -79,4 +79,6 @@ public interface Task extends Moment { public StyleBuilder getStyleBuilder(); + public boolean isAssignedTo(Resource res); + } diff --git a/src/net/sourceforge/plantuml/project/core/TaskGroup.java b/src/net/sourceforge/plantuml/project/core/TaskGroup.java index 804e08bf1..b8d1e8c49 100644 --- a/src/net/sourceforge/plantuml/project/core/TaskGroup.java +++ b/src/net/sourceforge/plantuml/project/core/TaskGroup.java @@ -56,6 +56,7 @@ public class TaskGroup extends AbstractTask implements Task { this.parent = parent; } + @Override public Day getStart() { Day min = null; for (Task child : children) @@ -68,6 +69,7 @@ public class TaskGroup extends AbstractTask implements Task { throw new UnsupportedOperationException(); } + @Override public Day getEnd() { Day max = null; for (Task child : children) @@ -80,54 +82,67 @@ public class TaskGroup extends AbstractTask implements Task { throw new UnsupportedOperationException(); } + @Override public void setStart(Day start) { throw new UnsupportedOperationException(); } + @Override public void setEnd(Day end) { throw new UnsupportedOperationException(); } + @Override public void setColors(CenterBorderColor... colors) { throw new UnsupportedOperationException(); } + @Override public void addResource(Resource resource, int percentage) { throw new UnsupportedOperationException(); } + @Override public Load getLoad() { throw new UnsupportedOperationException(); } + @Override public void setLoad(Load load) { throw new UnsupportedOperationException(); } + @Override public void setDiamond(boolean diamond) { throw new UnsupportedOperationException(); } + @Override public boolean isDiamond() { throw new UnsupportedOperationException(); } + @Override public void setCompletion(int completion) { throw new UnsupportedOperationException(); } + @Override public void setUrl(Url url) { throw new UnsupportedOperationException(); } + @Override public void addPause(Day pause) { throw new UnsupportedOperationException(); } + @Override public void addPause(DayOfWeek pause) { throw new UnsupportedOperationException(); } + @Override public void setNote(Display note) { } @@ -139,4 +154,9 @@ public class TaskGroup extends AbstractTask implements Task { return parent; } + @Override + public boolean isAssignedTo(Resource res) { + return false; + } + } diff --git a/src/net/sourceforge/plantuml/project/core/TaskImpl.java b/src/net/sourceforge/plantuml/project/core/TaskImpl.java index 491a3dbc1..a3db7f866 100644 --- a/src/net/sourceforge/plantuml/project/core/TaskImpl.java +++ b/src/net/sourceforge/plantuml/project/core/TaskImpl.java @@ -66,7 +66,7 @@ public class TaskImpl extends AbstractTask implements Task, LoadPlanable { private final LoadPlanable defaultPlan; private boolean diamond; - private int completion = 100; + private int completion; private Display note; private Url url; @@ -76,8 +76,9 @@ public class TaskImpl extends AbstractTask implements Task, LoadPlanable { this.url = url; } - public TaskImpl(StyleBuilder styleBuilder, TaskCode code, LoadPlanable plan, Day startingDay) { + public TaskImpl(StyleBuilder styleBuilder, TaskCode code, LoadPlanable plan, Day startingDay, int completion) { super(styleBuilder, code); + this.completion = completion; this.defaultPlan = plan; this.solver = new SolverImpl(this); if (startingDay == null) @@ -88,6 +89,7 @@ public class TaskImpl extends AbstractTask implements Task, LoadPlanable { setLoad(Load.inWinks(1)); } + @Override public int getLoadAt(Day instant) { if (isPaused(instant)) return 0; @@ -131,10 +133,12 @@ public class TaskImpl extends AbstractTask implements Task, LoadPlanable { return 0; } + @Override public void addPause(Day pause) { this.pausedDay.add(pause); } + @Override public void addPause(DayOfWeek pause) { this.pausedDayOfWeek.add(pause); } @@ -156,9 +160,29 @@ public class TaskImpl extends AbstractTask implements Task, LoadPlanable { } return result; } + + @Override + public Day getLastDayIfAny() { + return TaskImpl.this.getLastDayIfAny(); + } }; } + @Override + public Day getLastDayIfAny() { + Day result = null; + + for (Resource res : resources.keySet()) { + if (res.getLastDayIfAny() == null) + return null; + + if (result == null || result.compareTo(res.getLastDayIfAny()) < 0) + result = res.getLastDayIfAny(); + } + + return result; + } + public String getPrettyDisplay() { if (resources.size() > 0) { final StringBuilder result = new StringBuilder(getCode().getSimpleDisplay()); @@ -190,6 +214,7 @@ public class TaskImpl extends AbstractTask implements Task, LoadPlanable { return "" + getStart() + " ---> " + getEnd() + " [" + getLoad() + "]"; } + @Override public Day getStart() { Day result = (Day) solver.getData(TaskAttribute.START); if (diamond == false) @@ -199,42 +224,52 @@ public class TaskImpl extends AbstractTask implements Task, LoadPlanable { return result; } + @Override public Day getEnd() { return (Day) solver.getData(TaskAttribute.END); } + @Override public Load getLoad() { return (Load) solver.getData(TaskAttribute.LOAD); } + @Override public void setLoad(Load load) { solver.setData(TaskAttribute.LOAD, load); } + @Override public void setStart(Day start) { solver.setData(TaskAttribute.START, start); } + @Override public void setEnd(Day end) { solver.setData(TaskAttribute.END, end); } + @Override public void setColors(CenterBorderColor... colors) { this.colors = colors; } + @Override public void addResource(Resource resource, int percentage) { this.resources.put(resource, percentage); } + @Override public void setDiamond(boolean diamond) { this.diamond = diamond; } + @Override public boolean isDiamond() { return this.diamond; } + @Override public void setCompletion(int completion) { this.completion = completion; } @@ -274,6 +309,7 @@ public class TaskImpl extends AbstractTask implements Task, LoadPlanable { } + @Override public void setNote(Display note) { this.note = note; } @@ -286,4 +322,9 @@ public class TaskImpl extends AbstractTask implements Task, LoadPlanable { return defaultPlan; } + @Override + public boolean isAssignedTo(Resource res) { + return resources.containsKey(res); + } + } diff --git a/src/net/sourceforge/plantuml/project/core/TaskSeparator.java b/src/net/sourceforge/plantuml/project/core/TaskSeparator.java index fcf21d64a..68b30a326 100644 --- a/src/net/sourceforge/plantuml/project/core/TaskSeparator.java +++ b/src/net/sourceforge/plantuml/project/core/TaskSeparator.java @@ -52,22 +52,27 @@ public class TaskSeparator extends AbstractTask implements Task { this.comment = comment; } + @Override public Day getStart() { throw new UnsupportedOperationException(); } + @Override public Day getEnd() { throw new UnsupportedOperationException(); } + @Override public void setStart(Day start) { throw new UnsupportedOperationException(); } + @Override public void setEnd(Day end) { throw new UnsupportedOperationException(); } + @Override public void setColors(CenterBorderColor... colors) { throw new UnsupportedOperationException(); } @@ -76,10 +81,12 @@ public class TaskSeparator extends AbstractTask implements Task { return comment; } + @Override public void addResource(Resource resource, int percentage) { throw new UnsupportedOperationException(); } + @Override public Load getLoad() { throw new UnsupportedOperationException(); } @@ -88,31 +95,43 @@ public class TaskSeparator extends AbstractTask implements Task { throw new UnsupportedOperationException(); } + @Override public void setDiamond(boolean diamond) { throw new UnsupportedOperationException(); } + @Override public boolean isDiamond() { throw new UnsupportedOperationException(); } + @Override public void setCompletion(int completion) { throw new UnsupportedOperationException(); } + @Override public void setUrl(Url url) { throw new UnsupportedOperationException(); } + @Override public void addPause(Day pause) { throw new UnsupportedOperationException(); } + @Override public void addPause(DayOfWeek pause) { throw new UnsupportedOperationException(); } + @Override public void setNote(Display note) { } + @Override + public boolean isAssignedTo(Resource res) { + return false; + } + } diff --git a/src/net/sourceforge/plantuml/project/draw/ResourceDraw.java b/src/net/sourceforge/plantuml/project/draw/ResourceDraw.java index fb4f72f99..0215bceae 100644 --- a/src/net/sourceforge/plantuml/project/draw/ResourceDraw.java +++ b/src/net/sourceforge/plantuml/project/draw/ResourceDraw.java @@ -35,96 +35,13 @@ */ package net.sourceforge.plantuml.project.draw; -import net.sourceforge.plantuml.klimt.UTranslate; -import net.sourceforge.plantuml.klimt.color.HColor; -import net.sourceforge.plantuml.klimt.color.HColors; -import net.sourceforge.plantuml.klimt.creole.Display; -import net.sourceforge.plantuml.klimt.drawing.UGraphic; -import net.sourceforge.plantuml.klimt.font.FontConfiguration; -import net.sourceforge.plantuml.klimt.font.UFont; -import net.sourceforge.plantuml.klimt.geom.HorizontalAlignment; -import net.sourceforge.plantuml.klimt.shape.TextBlock; +import net.sourceforge.plantuml.klimt.font.StringBounder; import net.sourceforge.plantuml.klimt.shape.UDrawable; -import net.sourceforge.plantuml.klimt.shape.ULine; -import net.sourceforge.plantuml.klimt.sprite.SpriteContainerEmpty; -import net.sourceforge.plantuml.project.GanttDiagram; -import net.sourceforge.plantuml.project.core.Resource; -import net.sourceforge.plantuml.project.time.Day; -import net.sourceforge.plantuml.project.timescale.TimeScale; -public class ResourceDraw implements UDrawable { +public interface ResourceDraw extends UDrawable { - private final Resource res; - private final TimeScale timeScale; - private final double y; - private final Day min; - private final Day max; - private final GanttDiagram gantt; + public double getHeight(StringBounder stringBounder); - public ResourceDraw(GanttDiagram gantt, Resource res, TimeScale timeScale, double y, Day min, Day 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 = ULine.hline(timeScale.getEndingPosition(max) - timeScale.getStartingPosition(min)); - ug.apply(HColors.BLACK).apply(UTranslate.dy(title.calculateDimension(ug.getStringBounder()).getHeight())) - .draw(line); - - double startingPosition = -1; - int totalLoad = 0; - int totalLimit = 0; - for (Day i = min; i.compareTo(max) <= 0; i = i.increment()) { - final boolean isBreaking = timeScale.isBreaking(i); - totalLoad += gantt.getLoadForResource(res, i); - totalLimit += 100; - if (isBreaking) { - if (totalLoad > 0) { - final boolean over = totalLoad > totalLimit; - final FontConfiguration fontConfiguration = getFontConfiguration(9, - over ? HColors.RED : HColors.BLACK); - final TextBlock value = Display.getWithNewlines("" + totalLoad).create(fontConfiguration, - HorizontalAlignment.LEFT, new SpriteContainerEmpty()); - if (startingPosition == -1) - startingPosition = timeScale.getStartingPosition(i); - final double endingPosition = timeScale.getEndingPosition(i); - final double start = (startingPosition + endingPosition) / 2 - - value.calculateDimension(ug.getStringBounder()).getWidth() / 2; - value.drawU(ug.apply(new UTranslate(start, 16))); - } - startingPosition = -1; - totalLoad = 0; - totalLimit = 0; - } else { - if (startingPosition == -1) - startingPosition = timeScale.getStartingPosition(i); - } - } - - } - - private FontConfiguration getFontConfiguration(int size) { - return getFontConfiguration(size, HColors.BLACK); - } - - private FontConfiguration getFontConfiguration(int size, HColor color) { - final UFont font = UFont.serif(size); - return FontConfiguration.create(font, color, color, null); - } - - public double getHeight() { - return 16 * 2; - } - - public final double getY() { - return y; - } + public double getY(); } diff --git a/src/net/sourceforge/plantuml/project/draw/ResourceDrawBasicImpl.java b/src/net/sourceforge/plantuml/project/draw/ResourceDrawBasicImpl.java new file mode 100644 index 000000000..7be2906d0 --- /dev/null +++ b/src/net/sourceforge/plantuml/project/draw/ResourceDrawBasicImpl.java @@ -0,0 +1,132 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2024, Arnaud Roques + * + * Project Info: https://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * https://plantuml.com/patreon (only 1$ per month!) + * https://plantuml.com/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.project.draw; + +import net.sourceforge.plantuml.klimt.UTranslate; +import net.sourceforge.plantuml.klimt.color.HColor; +import net.sourceforge.plantuml.klimt.color.HColors; +import net.sourceforge.plantuml.klimt.creole.Display; +import net.sourceforge.plantuml.klimt.drawing.UGraphic; +import net.sourceforge.plantuml.klimt.font.FontConfiguration; +import net.sourceforge.plantuml.klimt.font.StringBounder; +import net.sourceforge.plantuml.klimt.font.UFont; +import net.sourceforge.plantuml.klimt.geom.HorizontalAlignment; +import net.sourceforge.plantuml.klimt.shape.TextBlock; +import net.sourceforge.plantuml.klimt.shape.ULine; +import net.sourceforge.plantuml.klimt.sprite.SpriteContainerEmpty; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.core.Resource; +import net.sourceforge.plantuml.project.time.Day; +import net.sourceforge.plantuml.project.timescale.TimeScale; + +public class ResourceDrawBasicImpl implements ResourceDraw { + + private final Resource res; + private final TimeScale timeScale; + private final double y; + private final Day min; + private final Day max; + private final GanttDiagram gantt; + + public ResourceDrawBasicImpl(GanttDiagram gantt, Resource res, TimeScale timeScale, double y, Day min, Day 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 = ULine.hline(timeScale.getEndingPosition(max) - timeScale.getStartingPosition(min)); + ug.apply(HColors.BLACK).apply(UTranslate.dy(title.calculateDimension(ug.getStringBounder()).getHeight())) + .draw(line); + + double startingPosition = -1; + int totalLoad = 0; + int totalLimit = 0; + for (Day i = min; i.compareTo(max) <= 0; i = i.increment()) { + final boolean isBreaking = timeScale.isBreaking(i); + totalLoad += gantt.getLoadForResource(res, i); + totalLimit += 100; + if (isBreaking) { + if (totalLoad > 0) { + final boolean over = totalLoad > totalLimit; + final FontConfiguration fontConfiguration = getFontConfiguration(9, + over ? HColors.RED : HColors.BLACK); + final TextBlock value = Display.getWithNewlines("" + totalLoad).create(fontConfiguration, + HorizontalAlignment.LEFT, new SpriteContainerEmpty()); + if (startingPosition == -1) + startingPosition = timeScale.getStartingPosition(i); + final double endingPosition = timeScale.getEndingPosition(i); + final double start = (startingPosition + endingPosition) / 2 + - value.calculateDimension(ug.getStringBounder()).getWidth() / 2; + value.drawU(ug.apply(new UTranslate(start, 16))); + } + startingPosition = -1; + totalLoad = 0; + totalLimit = 0; + } else { + if (startingPosition == -1) + startingPosition = timeScale.getStartingPosition(i); + } + } + + } + + private FontConfiguration getFontConfiguration(int size) { + return getFontConfiguration(size, HColors.BLACK); + } + + private FontConfiguration getFontConfiguration(int size, HColor color) { + final UFont font = UFont.serif(size); + return FontConfiguration.create(font, color, color, null); + } + + @Override + public double getHeight(StringBounder stringBounder) { + return 16 * 2; + } + + @Override + public final double getY() { + return y; + } + +} diff --git a/src/net/sourceforge/plantuml/project/draw/ResourceDrawVersion2.java b/src/net/sourceforge/plantuml/project/draw/ResourceDrawVersion2.java new file mode 100644 index 000000000..522fe9e91 --- /dev/null +++ b/src/net/sourceforge/plantuml/project/draw/ResourceDrawVersion2.java @@ -0,0 +1,138 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2024, Arnaud Roques + * + * Project Info: https://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * https://plantuml.com/patreon (only 1$ per month!) + * https://plantuml.com/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.project.draw; + +import net.sourceforge.plantuml.klimt.UShape; +import net.sourceforge.plantuml.klimt.UTranslate; +import net.sourceforge.plantuml.klimt.color.HColor; +import net.sourceforge.plantuml.klimt.color.HColors; +import net.sourceforge.plantuml.klimt.creole.Display; +import net.sourceforge.plantuml.klimt.drawing.UGraphic; +import net.sourceforge.plantuml.klimt.font.FontConfiguration; +import net.sourceforge.plantuml.klimt.font.StringBounder; +import net.sourceforge.plantuml.klimt.font.UFont; +import net.sourceforge.plantuml.klimt.geom.HorizontalAlignment; +import net.sourceforge.plantuml.klimt.shape.TextBlock; +import net.sourceforge.plantuml.klimt.shape.ULine; +import net.sourceforge.plantuml.klimt.shape.URectangle; +import net.sourceforge.plantuml.klimt.sprite.SpriteContainerEmpty; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.LabelPosition; +import net.sourceforge.plantuml.project.LabelStrategy; +import net.sourceforge.plantuml.project.core.Resource; +import net.sourceforge.plantuml.project.time.Day; +import net.sourceforge.plantuml.project.timescale.TimeScale; + +public class ResourceDrawVersion2 implements ResourceDraw { + + private final Resource res; + private final TimeScale timeScale; + private final double y; + private final Day min; + private final Day max; + private final GanttDiagram gantt; + + public ResourceDrawVersion2(GanttDiagram gantt, Resource res, TimeScale timeScale, double y, Day min, Day 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 StringBounder stringBounder = ug.getStringBounder(); + + double ypos = 16; + final double tmpHeight = getHeight(stringBounder) - ypos; + for (Day wink = gantt.getStartingDate(); wink.compareTo(gantt.getEndingDate()) <= 0; wink = wink.increment()) { + final double start = timeScale.getStartingPosition(wink); + final double end = timeScale.getEndingPosition(wink); + final UShape rect = URectangle.build(end - start, tmpHeight); + if (res.isClosedAt(wink)) + ug.apply(HColors.LIGHT_GRAY.bg()).apply(new UTranslate(start, ypos)).draw(rect); + + } + + final TextBlock title = Display.getWithNewlines(res.getName()).create(getFontConfiguration(13), + HorizontalAlignment.LEFT, new SpriteContainerEmpty()); + title.drawU(ug); + final ULine line = ULine.hline(timeScale.getEndingPosition(max) - timeScale.getStartingPosition(min)); + ug.apply(HColors.BLACK).apply(UTranslate.dy(title.calculateDimension(ug.getStringBounder()).getHeight())) + .draw(line); + + final LabelStrategy labelStrategy = new LabelStrategy(LabelPosition.LEGACY, HorizontalAlignment.LEFT); + + for (TaskDrawRegular draw : gantt.getAllTasksForResource(res)) { + draw.drawShape(ug.apply(UTranslate.dy(ypos + getTopMarginBetweenTask()))); + draw.drawTitle(ug.apply(UTranslate.dy(ypos + getTopMarginBetweenTask())), labelStrategy, 10, 100); + ypos += draw.getShapeHeight(stringBounder) + getMarginBetweenTask(); + } + } + + @Override + public double getHeight(StringBounder stringBounder) { + double ypos = 16; + for (TaskDrawRegular draw : gantt.getAllTasksForResource(res)) + ypos += draw.getShapeHeight(stringBounder) + getMarginBetweenTask(); + + return ypos + 8; + } + + private double getTopMarginBetweenTask() { + return 2; + } + + private double getMarginBetweenTask() { + return 4; + } + + private FontConfiguration getFontConfiguration(int size) { + return getFontConfiguration(size, HColors.BLACK); + } + + private FontConfiguration getFontConfiguration(int size, HColor color) { + final UFont font = UFont.serif(size); + return FontConfiguration.create(font, color, color, null); + } + + @Override + public final double getY() { + return y; + } + +} diff --git a/src/net/sourceforge/plantuml/project/draw/TaskDrawRegular.java b/src/net/sourceforge/plantuml/project/draw/TaskDrawRegular.java index ebe606c9a..cf3cb4cab 100644 --- a/src/net/sourceforge/plantuml/project/draw/TaskDrawRegular.java +++ b/src/net/sourceforge/plantuml/project/draw/TaskDrawRegular.java @@ -101,7 +101,7 @@ public class TaskDrawRegular extends AbstractTaskDraw { } @Override - protected double getShapeHeight(StringBounder stringBounder) { + public double getShapeHeight(StringBounder stringBounder) { final Style style = getStyle(); final ClockwiseTopRightBottomLeft padding = style.getPadding(); return padding.getTop() + getTitle().calculateDimension(stringBounder).getHeight() + padding.getBottom(); @@ -170,7 +170,6 @@ public class TaskDrawRegular extends AbstractTaskDraw { final double startPos = timeScale.getStartingPosition(start); drawNote(ug.apply((new UTranslate(startPos, getYNotePosition(ug.getStringBounder()))))); - ug = applyColors(ug); drawShape(ug); } @@ -256,7 +255,8 @@ public class TaskDrawRegular extends AbstractTaskDraw { return endPos; } - private void drawShape(UGraphic ug) { + public void drawShape(UGraphic ug) { + ug = applyColors(ug); final Style style = getStyleSignature().getMergedStyle(getStyleBuilder()); final ClockwiseTopRightBottomLeft margin = style.getMargin(); diff --git a/src/net/sourceforge/plantuml/project/draw/TimeHeader.java b/src/net/sourceforge/plantuml/project/draw/TimeHeader.java index ab995c7e4..b50138d03 100644 --- a/src/net/sourceforge/plantuml/project/draw/TimeHeader.java +++ b/src/net/sourceforge/plantuml/project/draw/TimeHeader.java @@ -35,12 +35,8 @@ */ package net.sourceforge.plantuml.project.draw; -import java.util.Objects; - -import net.sourceforge.plantuml.klimt.UStroke; import net.sourceforge.plantuml.klimt.UTranslate; import net.sourceforge.plantuml.klimt.color.HColor; -import net.sourceforge.plantuml.klimt.color.HColorSet; import net.sourceforge.plantuml.klimt.color.HColors; import net.sourceforge.plantuml.klimt.creole.Display; import net.sourceforge.plantuml.klimt.drawing.UGraphic; @@ -51,13 +47,13 @@ import net.sourceforge.plantuml.klimt.shape.TextBlock; import net.sourceforge.plantuml.klimt.shape.ULine; import net.sourceforge.plantuml.klimt.shape.URectangle; import net.sourceforge.plantuml.klimt.sprite.SpriteContainerEmpty; +import net.sourceforge.plantuml.project.TimeHeaderParameters; import net.sourceforge.plantuml.project.time.Day; import net.sourceforge.plantuml.project.timescale.TimeScale; import net.sourceforge.plantuml.style.PName; -import net.sourceforge.plantuml.style.Style; public abstract class TimeHeader { - // ::remove folder when __HAXE__ + // ::remove folder when __HAXE__ protected final double Y_POS_ROW16() { return 16; @@ -68,38 +64,40 @@ public abstract class TimeHeader { } private final TimeScale timeScale; - private final Style closedStyle; - private final Style timelineStyle; - private final HColorSet colorSet; + protected final TimeHeaderParameters thParam; - protected final Day min; - protected final Day max; - - public TimeHeader(Style timelineStyle, Style closedStyle, Day min, Day max, TimeScale timeScale, - HColorSet colorSet) { + public TimeHeader(TimeHeaderParameters thParam, TimeScale timeScale) { + this.thParam = thParam; this.timeScale = timeScale; - this.min = min; - this.max = max; - this.closedStyle = Objects.requireNonNull(closedStyle); - this.timelineStyle = Objects.requireNonNull(timelineStyle); - this.colorSet = colorSet; + } + + protected final boolean isBold2(Day wink) { + return thParam.getVerticalSeparatorBefore().contains(wink); + } + + protected final Day getMin() { + return thParam.getMin(); + } + + protected final Day getMax() { + return thParam.getMax(); } protected final HColor closedBackgroundColor() { - return closedStyle.value(PName.BackGroundColor).asColor(colorSet); + return thParam.getClosedStyle().value(PName.BackGroundColor).asColor(thParam.getColorSet()); } protected final HColor closedFontColor() { - return closedStyle.value(PName.FontColor).asColor(colorSet); + return thParam.getClosedStyle().value(PName.FontColor).asColor(thParam.getColorSet()); } protected final HColor openFontColor() { - return timelineStyle.value(PName.FontColor).asColor(colorSet); + return thParam.getTimelineStyle().value(PName.FontColor).asColor(thParam.getColorSet()); } - protected final HColor getBarColor() { - return timelineStyle.value(PName.LineColor).asColor(colorSet); + protected final HColor getLineColor() { + return thParam.getTimelineStyle().value(PName.LineColor).asColor(thParam.getColorSet()); } public abstract double getTimeHeaderHeight(); @@ -113,18 +111,14 @@ public abstract class TimeHeader { public abstract double getFullHeaderHeight(); protected final void drawHline(UGraphic ug, double y) { - final double xmin = getTimeScale().getStartingPosition(min); - final double xmax = getTimeScale().getEndingPosition(max); + final double xmin = getTimeScale().getStartingPosition(thParam.getMin()); + final double xmax = getTimeScale().getEndingPosition(thParam.getMax()); final ULine hline = ULine.hline(xmax - xmin); - ug.apply(getBarColor()).apply(UTranslate.dy(y)).draw(hline); + ug.apply(getLineColor()).apply(UTranslate.dy(y)).draw(hline); } - protected final void drawVbar(UGraphic ug, double x, double y1, double y2, boolean bold) { + protected final void drawVline(UGraphic ug, double x, double y1, double y2) { final ULine vbar = ULine.vline(y2 - y1); - if (bold) - ug = goBold(ug); - else - ug = ug.apply(getBarColor()); ug.apply(new UTranslate(x, y1)).draw(vbar); } @@ -175,8 +169,12 @@ public abstract class TimeHeader { ug.draw(URectangle.build(x2 - x1, height)); } - protected final UGraphic goBold(UGraphic ug) { - return ug.apply(HColors.BLACK).apply(UStroke.withThickness(2)); + protected void printVerticalSeparators(UGraphic ug, double totalHeightWithoutFooter) { + ug = thParam.forVerticalSeparator(ug); + for (Day wink = getMin(); wink.compareTo(getMax()) <= 0; wink = wink.increment()) + if (isBold2(wink)) + drawVline(ug, getTimeScale().getStartingPosition(wink), getFullHeaderHeight(), + totalHeightWithoutFooter); } } diff --git a/src/net/sourceforge/plantuml/project/draw/TimeHeaderCalendar.java b/src/net/sourceforge/plantuml/project/draw/TimeHeaderCalendar.java index 3d8274958..ff606e347 100644 --- a/src/net/sourceforge/plantuml/project/draw/TimeHeaderCalendar.java +++ b/src/net/sourceforge/plantuml/project/draw/TimeHeaderCalendar.java @@ -45,16 +45,8 @@ import net.sourceforge.plantuml.project.timescale.TimeScale; public abstract class TimeHeaderCalendar extends TimeHeader { - private final TimeHeaderParameters thParam; - public TimeHeaderCalendar(TimeHeaderParameters thParam, TimeScale timeScale) { - super(thParam.getTimelineStyle(), thParam.getClosedStyle(), thParam.getMin(), thParam.getMax(), timeScale, - thParam.getColorSet()); - this.thParam = thParam; - } - - protected final boolean isBold(Day wink) { - return thParam.getVerticalSeparatorBefore().contains(wink); + super(thParam, timeScale); } protected final Locale locale() { @@ -64,7 +56,7 @@ public abstract class TimeHeaderCalendar extends TimeHeader { protected final int getLoadAt(Day instant) { return thParam.getLoadPlanable().getLoadAt(instant); } - + // Duplicate in TimeHeaderSimple class Pending { final double x1; @@ -87,7 +79,7 @@ public abstract class TimeHeaderCalendar extends TimeHeader { final double height = totalHeightWithoutFooter - getFullHeaderHeight(); Pending pending = null; - for (Day wink = min; wink.compareTo(max) <= 0; wink = wink.increment()) { + for (Day wink = getMin(); wink.compareTo(getMax()) <= 0; wink = wink.increment()) { final double x1 = getTimeScale().getStartingPosition(wink); final double x2 = getTimeScale().getEndingPosition(wink); HColor back = thParam.getColor(wink); diff --git a/src/net/sourceforge/plantuml/project/draw/TimeHeaderDaily.java b/src/net/sourceforge/plantuml/project/draw/TimeHeaderDaily.java index 8fd5bf794..55f04437c 100644 --- a/src/net/sourceforge/plantuml/project/draw/TimeHeaderDaily.java +++ b/src/net/sourceforge/plantuml/project/draw/TimeHeaderDaily.java @@ -70,7 +70,7 @@ public class TimeHeaderDaily extends TimeHeaderCalendar { drawTextsDayOfWeek(ug.apply(UTranslate.dy(Y_POS_ROW16()))); drawTextDayOfMonth(ug.apply(UTranslate.dy(Y_POS_ROW28()))); drawMonths(ug); - printSmallVbars(ug, totalHeightWithoutFooter); + printVerticalSeparators(ug, totalHeightWithoutFooter); printNamedDays(ug); @@ -78,12 +78,20 @@ public class TimeHeaderDaily extends TimeHeaderCalendar { drawHline(ug, totalHeightWithoutFooter); } - private void printSmallVbars(final UGraphic ug, double totalHeightWithoutFooter) { - for (Day wink = min; wink.compareTo(max) <= 0; wink = wink.increment()) - drawVbar(ug, getTimeScale().getStartingPosition(wink), getFullHeaderHeight(), totalHeightWithoutFooter, - isBold(wink)); + @Override + protected void printVerticalSeparators(final UGraphic ug, double totalHeightWithoutFooter) { + final UGraphic ugVerticalSeparator = thParam.forVerticalSeparator(ug); + final UGraphic ugLineColor = ug.apply(getLineColor()); + for (Day wink = getMin(); wink.compareTo(getMax()) <= 0; wink = wink.increment()) + if (isBold2(wink)) + drawVline(ugVerticalSeparator, getTimeScale().getStartingPosition(wink), getFullHeaderHeight(), + totalHeightWithoutFooter); + else + drawVline(ugLineColor, getTimeScale().getStartingPosition(wink), getFullHeaderHeight(), + totalHeightWithoutFooter); - drawVbar(ug, getTimeScale().getEndingPosition(max), getFullHeaderHeight(), totalHeightWithoutFooter, false); + drawVline(ugLineColor, getTimeScale().getEndingPosition(getMax()), getFullHeaderHeight(), + totalHeightWithoutFooter); } @Override @@ -94,7 +102,7 @@ public class TimeHeaderDaily extends TimeHeaderCalendar { } private void drawTextsDayOfWeek(UGraphic ug) { - for (Day wink = min; wink.compareTo(max) <= 0; wink = wink.increment()) { + for (Day wink = getMin(); wink.compareTo(getMax()) <= 0; wink = wink.increment()) { final double x1 = getTimeScale().getStartingPosition(wink); final double x2 = getTimeScale().getEndingPosition(wink); final HColor textColor = getTextBackColor(wink); @@ -103,7 +111,7 @@ public class TimeHeaderDaily extends TimeHeaderCalendar { } private void drawTextDayOfMonth(UGraphic ug) { - for (Day wink = min; wink.compareTo(max) <= 0; wink = wink.increment()) { + for (Day wink = getMin(); wink.compareTo(getMax()) <= 0; wink = wink.increment()) { final double x1 = getTimeScale().getStartingPosition(wink); final double x2 = getTimeScale().getEndingPosition(wink); final HColor textColor = getTextBackColor(wink); @@ -121,7 +129,7 @@ public class TimeHeaderDaily extends TimeHeaderCalendar { private void drawMonths(final UGraphic ug) { MonthYear last = null; double lastChangeMonth = -1; - for (Day wink = min; wink.compareTo(max) <= 0; wink = wink.increment()) { + for (Day wink = getMin(); wink.compareTo(getMax()) <= 0; wink = wink.increment()) { final double x1 = getTimeScale().getStartingPosition(wink); if (wink.monthYear().equals(last) == false) { if (last != null) @@ -131,7 +139,7 @@ public class TimeHeaderDaily extends TimeHeaderCalendar { last = wink.monthYear(); } } - final double x1 = getTimeScale().getStartingPosition(max.increment()); + final double x1 = getTimeScale().getStartingPosition(getMax().increment()); if (x1 > lastChangeMonth) printMonth(ug, last, lastChangeMonth, x1); @@ -147,7 +155,7 @@ public class TimeHeaderDaily extends TimeHeaderCalendar { private void printNamedDays(final UGraphic ug) { if (nameDays.size() > 0) { String last = null; - for (Day wink = min; wink.compareTo(max.increment()) <= 0; wink = wink.increment()) { + for (Day wink = getMin(); wink.compareTo(getMax().increment()) <= 0; wink = wink.increment()) { final String name = nameDays.get(wink); if (name != null && name.equals(last) == false) { final double x1 = getTimeScale().getStartingPosition(wink); diff --git a/src/net/sourceforge/plantuml/project/draw/TimeHeaderMonthly.java b/src/net/sourceforge/plantuml/project/draw/TimeHeaderMonthly.java index d8d6e2d67..fc6c99771 100644 --- a/src/net/sourceforge/plantuml/project/draw/TimeHeaderMonthly.java +++ b/src/net/sourceforge/plantuml/project/draw/TimeHeaderMonthly.java @@ -62,19 +62,12 @@ public class TimeHeaderMonthly extends TimeHeaderCalendar { drawTextsBackground(ug, totalHeightWithoutFooter); drawYears(ug); drawMonths(ug.apply(UTranslate.dy(16))); - printSmallVbars(ug, totalHeightWithoutFooter); + printVerticalSeparators(ug, totalHeightWithoutFooter); drawHline(ug, 0); drawHline(ug, 16); drawHline(ug, getFullHeaderHeight()); } - private void printSmallVbars(final UGraphic ug, double totalHeightWithoutFooter) { - for (Day wink = min; wink.compareTo(max) <= 0; wink = wink.increment()) - if (isBold(wink)) - drawVbar(ug, getTimeScale().getStartingPosition(wink), getFullHeaderHeight(), totalHeightWithoutFooter, - isBold(wink)); - } - @Override public void drawTimeFooter(UGraphic ug) { ug = ug.apply(UTranslate.dy(3)); @@ -88,43 +81,43 @@ public class TimeHeaderMonthly extends TimeHeaderCalendar { private void drawYears(final UGraphic ug) { MonthYear last = null; double lastChange = -1; - for (Day wink = min; wink.compareTo(max) < 0; wink = wink.increment()) { + for (Day wink = getMin(); wink.compareTo(getMax()) < 0; wink = wink.increment()) { final double x1 = getTimeScale().getStartingPosition(wink); if (last == null || wink.monthYear().year() != last.year()) { - drawVbar(ug, x1, 0, 15, false); - if (last != null) { + drawVline(ug.apply(getLineColor()), x1, 0, 15); + if (last != null) printYear(ug, last, lastChange, x1); - } + lastChange = x1; last = wink.monthYear(); } } - final double x1 = getTimeScale().getStartingPosition(max.increment()); - if (x1 > lastChange) { + final double x1 = getTimeScale().getStartingPosition(getMax().increment()); + if (x1 > lastChange) printYear(ug, last, lastChange, x1); - } - drawVbar(ug, getTimeScale().getEndingPosition(max), 0, 15, false); + + drawVline(ug.apply(getLineColor()), getTimeScale().getEndingPosition(getMax()), (double) 0, (double) 15); } private void drawMonths(UGraphic ug) { MonthYear last = null; double lastChange = -1; - for (Day wink = min; wink.compareTo(max) < 0; wink = wink.increment()) { + for (Day wink = getMin(); wink.compareTo(getMax()) < 0; wink = wink.increment()) { final double x1 = getTimeScale().getStartingPosition(wink); if (wink.monthYear().equals(last) == false) { - drawVbar(ug, x1, 0, 12, false); - if (last != null) { + drawVline(ug.apply(getLineColor()), x1, (double) 0, (double) 12); + if (last != null) printMonth(ug, last, lastChange, x1); - } + lastChange = x1; last = wink.monthYear(); } } - final double x1 = getTimeScale().getStartingPosition(max.increment()); - if (x1 > lastChange) { + final double x1 = getTimeScale().getStartingPosition(getMax().increment()); + if (x1 > lastChange) printMonth(ug, last, lastChange, x1); - } - drawVbar(ug, getTimeScale().getEndingPosition(max), 0, 12, false); + + drawVline(ug.apply(getLineColor()), getTimeScale().getEndingPosition(getMax()), (double) 0, (double) 12); } private void printYear(UGraphic ug, MonthYear monthYear, double start, double end) { diff --git a/src/net/sourceforge/plantuml/project/draw/TimeHeaderQuarterly.java b/src/net/sourceforge/plantuml/project/draw/TimeHeaderQuarterly.java index dcf03c017..b19cdad98 100644 --- a/src/net/sourceforge/plantuml/project/draw/TimeHeaderQuarterly.java +++ b/src/net/sourceforge/plantuml/project/draw/TimeHeaderQuarterly.java @@ -62,19 +62,12 @@ public class TimeHeaderQuarterly extends TimeHeaderCalendar { drawTextsBackground(ug, totalHeightWithoutFooter); drawYears(ug); drawQuarters(ug.apply(UTranslate.dy(16))); - printSmallVbars(ug, totalHeightWithoutFooter); + printVerticalSeparators(ug, totalHeightWithoutFooter); drawHline(ug, 0); drawHline(ug, 16); drawHline(ug, getFullHeaderHeight()); } - private void printSmallVbars(final UGraphic ug, double totalHeightWithoutFooter) { - for (Day wink = min; wink.compareTo(max) <= 0; wink = wink.increment()) - if (isBold(wink)) - drawVbar(ug, getTimeScale().getStartingPosition(wink), getFullHeaderHeight(), totalHeightWithoutFooter, - isBold(wink)); - } - @Override public void drawTimeFooter(UGraphic ug) { ug = ug.apply(UTranslate.dy(3)); @@ -88,43 +81,43 @@ public class TimeHeaderQuarterly extends TimeHeaderCalendar { private void drawYears(final UGraphic ug) { MonthYear last = null; double lastChange = -1; - for (Day wink = min; wink.compareTo(max) < 0; wink = wink.increment()) { + for (Day wink = getMin(); wink.compareTo(getMax()) < 0; wink = wink.increment()) { final double x1 = getTimeScale().getStartingPosition(wink); if (last == null || wink.monthYear().year() != last.year()) { - drawVbar(ug, x1, 0, 15, false); - if (last != null) { + drawVline(ug.apply(getLineColor()), x1, (double) 0, (double) 15); + if (last != null) printYear(ug, last, lastChange, x1); - } + lastChange = x1; last = wink.monthYear(); } } - final double x1 = getTimeScale().getStartingPosition(max.increment()); - if (x1 > lastChange) { + final double x1 = getTimeScale().getStartingPosition(getMax().increment()); + if (x1 > lastChange) printYear(ug, last, lastChange, x1); - } - drawVbar(ug, getTimeScale().getEndingPosition(max), 0, 15, false); + + drawVline(ug.apply(getLineColor()), getTimeScale().getEndingPosition(getMax()), (double) 0, (double) 15); } private void drawQuarters(UGraphic ug) { String last = null; double lastChange = -1; - for (Day wink = min; wink.compareTo(max) < 0; wink = wink.increment()) { + for (Day wink = getMin(); wink.compareTo(getMax()) < 0; wink = wink.increment()) { final double x1 = getTimeScale().getStartingPosition(wink); if (quarter(wink).equals(last) == false) { - drawVbar(ug, x1, 0, 12, false); - if (last != null) { + drawVline(ug.apply(getLineColor()), x1, (double) 0, (double) 12); + if (last != null) printQuarter(ug, last, lastChange, x1); - } + lastChange = x1; last = quarter(wink); } } - final double x1 = getTimeScale().getStartingPosition(max.increment()); - if (x1 > lastChange) { + final double x1 = getTimeScale().getStartingPosition(getMax().increment()); + if (x1 > lastChange) printQuarter(ug, last, lastChange, x1); - } - drawVbar(ug, getTimeScale().getEndingPosition(max), 0, 12, false); + + drawVline(ug.apply(getLineColor()), getTimeScale().getEndingPosition(getMax()), (double) 0, (double) 12); } private String quarter(Day day) { diff --git a/src/net/sourceforge/plantuml/project/draw/TimeHeaderSimple.java b/src/net/sourceforge/plantuml/project/draw/TimeHeaderSimple.java index a4a68f26f..7d23798ea 100644 --- a/src/net/sourceforge/plantuml/project/draw/TimeHeaderSimple.java +++ b/src/net/sourceforge/plantuml/project/draw/TimeHeaderSimple.java @@ -35,8 +35,6 @@ */ package net.sourceforge.plantuml.project.draw; -import java.util.Set; - import net.sourceforge.plantuml.klimt.UTranslate; import net.sourceforge.plantuml.klimt.color.HColor; import net.sourceforge.plantuml.klimt.creole.Display; @@ -53,9 +51,7 @@ import net.sourceforge.plantuml.project.timescale.TimeScaleWink; public class TimeHeaderSimple extends TimeHeader { - private final TimeHeaderParameters colorDays; private final PrintScale printScale; - private final Set verticalSeparators; @Override public double getFullHeaderHeight() { @@ -75,37 +71,21 @@ public class TimeHeaderSimple extends TimeHeader { } public TimeHeaderSimple(TimeHeaderParameters thParam, PrintScale printScale) { - super(thParam.getTimelineStyle(), thParam.getClosedStyle(), thParam.getMin(), thParam.getMax(), - new TimeScaleWink(thParam.getScale(), printScale), thParam.getColorSet()); - this.colorDays = thParam; + super(thParam, new TimeScaleWink(thParam.getScale(), printScale)); this.printScale = printScale; - this.verticalSeparators = thParam.getVerticalSeparatorBefore(); - } - - private boolean isBold(Day wink) { - return verticalSeparators.contains(wink); - } - - private void drawSeparatorsDay(UGraphic ug, TimeScale timeScale, double totalHeightWithoutFooter) { - final ULine vbar = ULine.vline(totalHeightWithoutFooter - getFullHeaderHeight() + 2); - ug = goBold(ug).apply(UTranslate.dy(getFullHeaderHeight() - 1)); - for (Day i = min; i.compareTo(max.increment()) <= 0; i = i.increment(printScale)) - if (isBold(i)) { - final double x1 = timeScale.getStartingPosition(i); - ug.apply(UTranslate.dx(x1)).draw(vbar); - } } private void drawSmallVlinesDay(UGraphic ug, TimeScale timeScale, double totalHeightWithoutFooter) { + ug = ug.apply(getLineColor()); final ULine vbar = ULine.vline(totalHeightWithoutFooter); - for (Day i = min; i.compareTo(max.increment()) <= 0; i = i.increment(printScale)) { + for (Day i = getMin(); i.compareTo(getMax().increment()) <= 0; i = i.increment(printScale)) { final double x1 = timeScale.getStartingPosition(i); - ug.apply(getBarColor()).apply(UTranslate.dx(x1)).draw(vbar); + ug.apply(UTranslate.dx(x1)).draw(vbar); } } private void drawSimpleDayCounter(UGraphic ug, TimeScale timeScale) { - for (Day i = min; i.compareTo(max.increment()) <= 0; i = i.increment(printScale)) { + for (Day i = getMin(); i.compareTo(getMax().increment()) <= 0; i = i.increment(printScale)) { final int value; if (printScale == PrintScale.WEEKLY) value = i.getAbsoluteDayNum() / 7 + 1; @@ -122,33 +102,34 @@ public class TimeHeaderSimple extends TimeHeader { x2 = timeScale.getEndingPosition(i); final double width = num.calculateDimension(ug.getStringBounder()).getWidth(); final double delta = (x2 - x1) - width; - if (i.compareTo(max.increment()) < 0) + if (i.compareTo(getMax().increment()) < 0) num.drawU(ug.apply(UTranslate.dx(x1 + delta / 2))); } } @Override - public void drawTimeHeader(final UGraphic ug, double totalHeightWithoutFooter) { + public void drawTimeHeader(UGraphic ug, double totalHeightWithoutFooter) { drawTextsBackground(ug.apply(UTranslate.dy(-3)), totalHeightWithoutFooter + 6); - final double xmin = getTimeScale().getStartingPosition(min); - final double xmax = getTimeScale().getEndingPosition(max); + final double xmin = getTimeScale().getStartingPosition(getMin()); + final double xmax = getTimeScale().getEndingPosition(getMax()); drawSmallVlinesDay(ug, getTimeScale(), totalHeightWithoutFooter + 2); - drawSeparatorsDay(ug, getTimeScale(), totalHeightWithoutFooter); + printVerticalSeparators(ug, totalHeightWithoutFooter); drawSimpleDayCounter(ug, getTimeScale()); - ug.apply(getBarColor()).draw(ULine.hline(xmax - xmin)); - ug.apply(getBarColor()).apply(UTranslate.dy(getFullHeaderHeight() - 3)).draw(ULine.hline(xmax - xmin)); + ug = ug.apply(getLineColor()); + ug.draw(ULine.hline(xmax - xmin)); + ug.apply(UTranslate.dy(getFullHeaderHeight() - 3)).draw(ULine.hline(xmax - xmin)); } @Override public void drawTimeFooter(UGraphic ug) { - final double xmin = getTimeScale().getStartingPosition(min); - final double xmax = getTimeScale().getEndingPosition(max); + final double xmin = getTimeScale().getStartingPosition(getMin()); + final double xmax = getTimeScale().getEndingPosition(getMax()); ug = ug.apply(UTranslate.dy(3)); drawSmallVlinesDay(ug, getTimeScale(), getTimeFooterHeight() - 3); drawSimpleDayCounter(ug, getTimeScale()); - ug.apply(getBarColor()).draw(ULine.hline(xmax - xmin)); + ug.apply(getLineColor()).draw(ULine.hline(xmax - xmin)); } // Duplicate in TimeHeaderDaily @@ -173,10 +154,10 @@ public class TimeHeaderSimple extends TimeHeader { final double height = totalHeightWithoutFooter - getFullHeaderHeight(); Pending pending = null; - for (Day wink = min; wink.compareTo(max) <= 0; wink = wink.increment()) { + for (Day wink = getMin(); wink.compareTo(getMax()) <= 0; wink = wink.increment()) { final double x1 = getTimeScale().getStartingPosition(wink); final double x2 = getTimeScale().getEndingPosition(wink); - HColor back = colorDays.getColor(wink); + HColor back = thParam.getColor(wink); // // Day of week should be stronger than period of time (back color). // final HColor backDoW = colorDaysOfWeek.get(wink.getDayOfWeek()); // if (backDoW != null) { diff --git a/src/net/sourceforge/plantuml/project/draw/TimeHeaderWeekly.java b/src/net/sourceforge/plantuml/project/draw/TimeHeaderWeekly.java index aa8374632..53688b08c 100644 --- a/src/net/sourceforge/plantuml/project/draw/TimeHeaderWeekly.java +++ b/src/net/sourceforge/plantuml/project/draw/TimeHeaderWeekly.java @@ -82,47 +82,43 @@ public class TimeHeaderWeekly extends TimeHeaderCalendar { private void drawCalendar(final UGraphic ug, double totalHeightWithoutFooter) { printDaysOfMonth(ug); - printSmallVbars(ug, totalHeightWithoutFooter); + printVerticalSeparators(ug, totalHeightWithoutFooter); printMonths(ug); } private void printMonths(final UGraphic ug) { MonthYear last = null; double lastChangeMonth = -1; - for (Day wink = min; wink.compareTo(max) < 0; wink = wink.increment()) { + for (Day wink = getMin(); wink.compareTo(getMax()) < 0; wink = wink.increment()) { final double x1 = getTimeScale().getStartingPosition(wink); if (wink.monthYear().equals(last) == false) { - drawVbar(ug, x1, 0, Y_POS_ROW16(), false); - if (last != null) { + drawVline(ug.apply(getLineColor()), x1, (double) 0, Y_POS_ROW16()); + if (last != null) printMonth(ug, last, lastChangeMonth, x1); - } + lastChangeMonth = x1; last = wink.monthYear(); } } - drawVbar(ug, getTimeScale().getEndingPosition(max), 0, Y_POS_ROW16(), false); - final double x1 = getTimeScale().getStartingPosition(max.increment()); - if (x1 > lastChangeMonth) { + drawVline(ug.apply(getLineColor()), getTimeScale().getEndingPosition(getMax()), (double) 0, Y_POS_ROW16()); + final double x1 = getTimeScale().getStartingPosition(getMax().increment()); + if (x1 > lastChangeMonth) printMonth(ug, last, lastChangeMonth, x1); - } + } - private void printSmallVbars(final UGraphic ug, double totalHeightWithoutFooter) { - for (Day wink = min; wink.compareTo(max) <= 0; wink = wink.increment()) + @Override + protected void printVerticalSeparators(final UGraphic ug, double totalHeightWithoutFooter) { + for (Day wink = getMin(); wink.compareTo(getMax()) <= 0; wink = wink.increment()) if (wink.getDayOfWeek() == weekNumberStrategy.getFirstDayOfWeek()) - drawVbar(ug, getTimeScale().getStartingPosition(wink), Y_POS_ROW16(), totalHeightWithoutFooter, false); - - drawVbar(ug, getTimeScale().getEndingPosition(max), Y_POS_ROW16(), totalHeightWithoutFooter, false); - - for (Day wink = min; wink.compareTo(max) <= 0; wink = wink.increment()) - if (isBold(wink)) - drawVbar(ug, getTimeScale().getStartingPosition(wink), getFullHeaderHeight(), totalHeightWithoutFooter, - isBold(wink)); + drawVline(ug.apply(getLineColor()), getTimeScale().getStartingPosition(wink), Y_POS_ROW16(), totalHeightWithoutFooter); + drawVline(ug.apply(getLineColor()), getTimeScale().getEndingPosition(getMax()), Y_POS_ROW16(), totalHeightWithoutFooter); + super.printVerticalSeparators(ug, totalHeightWithoutFooter); } private void printDaysOfMonth(final UGraphic ug) { - for (Day wink = min; wink.compareTo(max) < 0; wink = wink.increment()) { + for (Day wink = getMin(); wink.compareTo(getMax()) < 0; wink = wink.increment()) { if (wink.getDayOfWeek() == weekNumberStrategy.getFirstDayOfWeek()) { final String num; if (withCalendarDate) diff --git a/src/net/sourceforge/plantuml/project/draw/TimeHeaderYearly.java b/src/net/sourceforge/plantuml/project/draw/TimeHeaderYearly.java index 9d537fd41..04b25e86c 100644 --- a/src/net/sourceforge/plantuml/project/draw/TimeHeaderYearly.java +++ b/src/net/sourceforge/plantuml/project/draw/TimeHeaderYearly.java @@ -61,18 +61,11 @@ public class TimeHeaderYearly extends TimeHeaderCalendar { public void drawTimeHeader(final UGraphic ug, double totalHeightWithoutFooter) { drawTextsBackground(ug, totalHeightWithoutFooter); drawYears(ug); - printSmallVbars(ug, totalHeightWithoutFooter); + printVerticalSeparators(ug, totalHeightWithoutFooter); drawHline(ug, 0); drawHline(ug, getFullHeaderHeight()); } - private void printSmallVbars(final UGraphic ug, double totalHeightWithoutFooter) { - for (Day wink = min; wink.compareTo(max) <= 0; wink = wink.increment()) - if (isBold(wink)) - drawVbar(ug, getTimeScale().getStartingPosition(wink), getFullHeaderHeight(), totalHeightWithoutFooter, - isBold(wink)); - } - @Override public void drawTimeFooter(UGraphic ug) { ug = ug.apply(UTranslate.dy(3)); @@ -84,22 +77,22 @@ public class TimeHeaderYearly extends TimeHeaderCalendar { private void drawYears(final UGraphic ug) { MonthYear last = null; double lastChange = -1; - for (Day wink = min; wink.compareTo(max) < 0; wink = wink.increment()) { + for (Day wink = getMin(); wink.compareTo(getMax()) < 0; wink = wink.increment()) { final double x1 = getTimeScale().getStartingPosition(wink); if (last == null || wink.monthYear().year() != last.year()) { - drawVbar(ug, x1, 0, 19, false); - if (last != null) { + drawVline(ug.apply(getLineColor()), x1, (double) 0, (double) 19); + if (last != null) printYear(ug, last, lastChange, x1); - } + lastChange = x1; last = wink.monthYear(); } } - final double x1 = getTimeScale().getStartingPosition(max.increment()); - if (x1 > lastChange) { + final double x1 = getTimeScale().getStartingPosition(getMax().increment()); + if (x1 > lastChange) printYear(ug, last, lastChange, x1); - } - drawVbar(ug, getTimeScale().getEndingPosition(max), 0, 19, false); + + drawVline(ug.apply(getLineColor()), getTimeScale().getEndingPosition(getMax()), (double) 0, (double) 19); } private void printYear(UGraphic ug, MonthYear monthYear, double start, double end) { diff --git a/src/net/sourceforge/plantuml/project/lang/ComplementDate.java b/src/net/sourceforge/plantuml/project/lang/ComplementDate.java index ae52dfdb0..701f15dfc 100644 --- a/src/net/sourceforge/plantuml/project/lang/ComplementDate.java +++ b/src/net/sourceforge/plantuml/project/lang/ComplementDate.java @@ -47,7 +47,35 @@ import net.sourceforge.plantuml.regex.RegexResult; public class ComplementDate implements Something { + private final Type type; + + static enum Type { + ANY, ONLY_RELATIVE, ONLY_ABSOLUTE; + } + + private ComplementDate(Type type) { + this.type = type; + } + + public static ComplementDate any() { + return new ComplementDate(Type.ANY); + } + + public static ComplementDate onlyRelative() { + return new ComplementDate(Type.ONLY_RELATIVE); + } + + public static ComplementDate onlyAbsolute() { + return new ComplementDate(Type.ONLY_ABSOLUTE); + } + public IRegex toRegex(String suffix) { + switch (type) { + case ONLY_ABSOLUTE: + return new RegexOr(toRegexA(suffix), toRegexB(suffix), toRegexC(suffix)); + case ONLY_RELATIVE: + return new RegexOr(toRegexD(suffix), toRegexE(suffix)); + } return new RegexOr(toRegexA(suffix), toRegexB(suffix), toRegexC(suffix), toRegexD(suffix), toRegexE(suffix)); } @@ -98,21 +126,21 @@ public class ComplementDate implements Something { } public Failable getMe(GanttDiagram system, RegexResult arg, String suffix) { - if (arg.get("ADAY" + suffix, 0) != null) { + if (arg.get("ADAY" + suffix, 0) != null) return Failable.ok(resultA(arg, suffix)); - } - if (arg.get("BDAY" + suffix, 0) != null) { + + if (arg.get("BDAY" + suffix, 0) != null) return Failable.ok(resultB(arg, suffix)); - } - if (arg.get("CDAY" + suffix, 0) != null) { + + if (arg.get("CDAY" + suffix, 0) != null) return Failable.ok(resultC(arg, suffix)); - } - if (arg.get("DCOUNT" + suffix, 0) != null) { + + if (arg.get("DCOUNT" + suffix, 0) != null) return Failable.ok(resultD(system, arg, suffix)); - } - if (arg.get("ECOUNT" + suffix, 0) != null) { + + if (arg.get("ECOUNT" + suffix, 0) != null) return Failable.ok(resultE(system, arg, suffix)); - } + throw new IllegalStateException(); } diff --git a/src/net/sourceforge/plantuml/project/lang/SentenceHappensDate.java b/src/net/sourceforge/plantuml/project/lang/SentenceHappensDate.java index 2d1b81ead..456935ae1 100644 --- a/src/net/sourceforge/plantuml/project/lang/SentenceHappensDate.java +++ b/src/net/sourceforge/plantuml/project/lang/SentenceHappensDate.java @@ -44,7 +44,7 @@ import net.sourceforge.plantuml.project.time.Day; public class SentenceHappensDate extends SentenceSimple { public SentenceHappensDate() { - super(SubjectTask.ME, Verbs.happens, new ComplementDate()); + super(SubjectTask.ME, Verbs.happens, ComplementDate.any()); } @Override diff --git a/src/net/sourceforge/plantuml/project/lang/SentencePausesDate.java b/src/net/sourceforge/plantuml/project/lang/SentencePausesDate.java index bc311db46..97ceea3a1 100644 --- a/src/net/sourceforge/plantuml/project/lang/SentencePausesDate.java +++ b/src/net/sourceforge/plantuml/project/lang/SentencePausesDate.java @@ -43,7 +43,7 @@ import net.sourceforge.plantuml.project.time.Day; public class SentencePausesDate extends SentenceSimple { public SentencePausesDate() { - super(SubjectTask.ME, Verbs.pauses, new ComplementDate()); + super(SubjectTask.ME, Verbs.pauses, ComplementDate.any()); } @Override diff --git a/src/net/sourceforge/plantuml/project/lang/SentenceTaskEndsAbsolute.java b/src/net/sourceforge/plantuml/project/lang/SentenceTaskEndsAbsolute.java index 484f7a41b..a01539449 100644 --- a/src/net/sourceforge/plantuml/project/lang/SentenceTaskEndsAbsolute.java +++ b/src/net/sourceforge/plantuml/project/lang/SentenceTaskEndsAbsolute.java @@ -43,7 +43,7 @@ import net.sourceforge.plantuml.project.time.Day; public class SentenceTaskEndsAbsolute extends SentenceSimple { public SentenceTaskEndsAbsolute() { - super(SubjectTask.ME, Verbs.ends2, new ComplementDate()); + super(SubjectTask.ME, Verbs.ends2, ComplementDate.any()); } @Override diff --git a/src/net/sourceforge/plantuml/project/lang/SentenceTaskStartsAbsolute.java b/src/net/sourceforge/plantuml/project/lang/SentenceTaskStartsAbsolute.java index e535412e0..492259ec7 100644 --- a/src/net/sourceforge/plantuml/project/lang/SentenceTaskStartsAbsolute.java +++ b/src/net/sourceforge/plantuml/project/lang/SentenceTaskStartsAbsolute.java @@ -43,7 +43,7 @@ import net.sourceforge.plantuml.project.time.Day; public class SentenceTaskStartsAbsolute extends SentenceSimple { public SentenceTaskStartsAbsolute() { - super(SubjectTask.ME, Verbs.starts3, new ComplementDate()); + super(SubjectTask.ME, Verbs.starts3, ComplementDate.any()); } @Override @@ -52,7 +52,7 @@ public class SentenceTaskStartsAbsolute extends SentenceSimple { final Day start = (Day) complement; final Day startingDate = project.getStartingDate(); if (startingDate.getAbsoluteDayNum() == 0) - project.setProjectStartingDate(start); + return CommandExecutionResult.error("No starting date for the project"); task.setStart(start); return CommandExecutionResult.ok(); diff --git a/src/net/sourceforge/plantuml/project/lang/SentenceTaskStartsOnlyRelative.java b/src/net/sourceforge/plantuml/project/lang/SentenceTaskStartsOnlyRelative.java new file mode 100644 index 000000000..bf9d07fae --- /dev/null +++ b/src/net/sourceforge/plantuml/project/lang/SentenceTaskStartsOnlyRelative.java @@ -0,0 +1,58 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2024, Arnaud Roques + * + * Project Info: https://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * https://plantuml.com/patreon (only 1$ per month!) + * https://plantuml.com/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.project.lang; + +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.core.Task; +import net.sourceforge.plantuml.project.time.Day; + +public class SentenceTaskStartsOnlyRelative extends SentenceSimple { + + public SentenceTaskStartsOnlyRelative() { + super(SubjectTask.ME, Verbs.starts3, ComplementDate.onlyRelative()); + } + + @Override + public CommandExecutionResult execute(GanttDiagram project, Object subject, Object complement) { + final Task task = (Task) subject; + final Day start = (Day) complement; + + task.setStart(start); + return CommandExecutionResult.ok(); + } + +} diff --git a/src/net/sourceforge/plantuml/project/lang/SubjectProject.java b/src/net/sourceforge/plantuml/project/lang/SubjectProject.java index 7b7a29c4d..50a42619f 100644 --- a/src/net/sourceforge/plantuml/project/lang/SubjectProject.java +++ b/src/net/sourceforge/plantuml/project/lang/SubjectProject.java @@ -68,7 +68,7 @@ public class SubjectProject implements Subject { class Starts extends SentenceSimple { public Starts() { - super(SubjectProject.this, Verbs.starts, new ComplementDate()); + super(SubjectProject.this, Verbs.starts, ComplementDate.onlyAbsolute()); } @Override diff --git a/src/net/sourceforge/plantuml/project/lang/SubjectResource.java b/src/net/sourceforge/plantuml/project/lang/SubjectResource.java index 95b813ce9..89e14f57b 100644 --- a/src/net/sourceforge/plantuml/project/lang/SubjectResource.java +++ b/src/net/sourceforge/plantuml/project/lang/SubjectResource.java @@ -63,7 +63,8 @@ public class SubjectResource implements Subject { } public Collection getSentences() { - return Arrays.asList(new IsOffDate(), new IsOffDates(), new IsOffDayOfWeek(), new IsOnDate(), new IsOnDates()); + return Arrays.asList(new IsOffDate(), new IsOffDates(), new IsOffDayOfWeek(), new IsOnDate(), new IsOnDates(), + new IsOffBeforeDate(), new IsOffAfterDate()); } public IRegex toRegex() { @@ -72,10 +73,42 @@ public class SubjectResource implements Subject { ); } + public class IsOffBeforeDate extends SentenceSimple { + + public IsOffBeforeDate() { + super(SubjectResource.this, Verbs.isOffBefore, ComplementDate.any()); + } + + @Override + public CommandExecutionResult execute(GanttDiagram project, Object subject, Object complement) { + final Resource resource = (Resource) subject; + final Day when = (Day) complement; + resource.setOffBeforeDate(when); + return CommandExecutionResult.ok(); + } + + } + + public class IsOffAfterDate extends SentenceSimple { + + public IsOffAfterDate() { + super(SubjectResource.this, Verbs.isOffAfter, ComplementDate.any()); + } + + @Override + public CommandExecutionResult execute(GanttDiagram project, Object subject, Object complement) { + final Resource resource = (Resource) subject; + final Day when = (Day) complement; + resource.setOffAfterDate(when); + return CommandExecutionResult.ok(); + } + + } + public class IsOffDate extends SentenceSimple { public IsOffDate() { - super(SubjectResource.this, Verbs.isOff, new ComplementDate()); + super(SubjectResource.this, Verbs.isOff, ComplementDate.any()); } @Override @@ -123,7 +156,7 @@ public class SubjectResource implements Subject { public class IsOnDate extends SentenceSimple { public IsOnDate() { - super(SubjectResource.this, Verbs.isOn, new ComplementDate()); + super(SubjectResource.this, Verbs.isOn, ComplementDate.any()); } @Override diff --git a/src/net/sourceforge/plantuml/project/lang/SubjectSeparator.java b/src/net/sourceforge/plantuml/project/lang/SubjectSeparator.java index 85344a55f..261e640d4 100644 --- a/src/net/sourceforge/plantuml/project/lang/SubjectSeparator.java +++ b/src/net/sourceforge/plantuml/project/lang/SubjectSeparator.java @@ -69,7 +69,7 @@ public class SubjectSeparator implements Subject { class JustBefore extends SentenceSimple { public JustBefore() { - super(SubjectSeparator.this, Verbs.justBefore, new ComplementDate()); + super(SubjectSeparator.this, Verbs.justBefore, ComplementDate.any()); } @Override @@ -85,7 +85,7 @@ public class SubjectSeparator implements Subject { class JustAfter extends SentenceSimple { public JustAfter() { - super(SubjectSeparator.this, Verbs.justAfter, new ComplementDate()); + super(SubjectSeparator.this, Verbs.justAfter, ComplementDate.any()); } @Override diff --git a/src/net/sourceforge/plantuml/project/lang/SubjectTask.java b/src/net/sourceforge/plantuml/project/lang/SubjectTask.java index b9386bb85..50cc79164 100644 --- a/src/net/sourceforge/plantuml/project/lang/SubjectTask.java +++ b/src/net/sourceforge/plantuml/project/lang/SubjectTask.java @@ -81,11 +81,11 @@ public class SubjectTask implements Subject { public Collection getSentences() { return Arrays.asList(new SentenceLasts(), new SentenceTaskStarts(), new SentenceTaskStartsWithColor(), - new SentenceTaskStartsAbsolute(), new SentenceHappens(), new SentenceHappensDate(), new SentenceEnds(), - new SentenceTaskEndsAbsolute(), new SentenceIsColored(), new SentenceIsColoredForCompletion(), - new SentenceIsDeleted(), new SentenceIsForTask(), new SentenceLinksTo(), new SentenceOccurs(), - new SentenceDisplayOnSameRowAs(), new SentencePausesDate(), new SentencePausesDates(), - new SentencePausesDayOfWeek()); + new SentenceTaskStartsOnlyRelative(), new SentenceTaskStartsAbsolute(), new SentenceHappens(), + new SentenceHappensDate(), new SentenceEnds(), new SentenceTaskEndsAbsolute(), new SentenceIsColored(), + new SentenceIsColoredForCompletion(), new SentenceIsDeleted(), new SentenceIsForTask(), + new SentenceLinksTo(), new SentenceOccurs(), new SentenceDisplayOnSameRowAs(), new SentencePausesDate(), + new SentencePausesDates(), new SentencePausesDayOfWeek()); } public IRegex toRegex() { diff --git a/src/net/sourceforge/plantuml/project/lang/SubjectToday.java b/src/net/sourceforge/plantuml/project/lang/SubjectToday.java index 05c58e6eb..3ee19a018 100644 --- a/src/net/sourceforge/plantuml/project/lang/SubjectToday.java +++ b/src/net/sourceforge/plantuml/project/lang/SubjectToday.java @@ -90,7 +90,7 @@ public class SubjectToday implements Subject { class IsDate extends SentenceSimple { public IsDate() { - super(SubjectToday.this, Verbs.is, new ComplementDate()); + super(SubjectToday.this, Verbs.is, ComplementDate.any()); } @Override diff --git a/src/net/sourceforge/plantuml/project/lang/Verbs.java b/src/net/sourceforge/plantuml/project/lang/Verbs.java index f80c3a88e..58f92eafb 100644 --- a/src/net/sourceforge/plantuml/project/lang/Verbs.java +++ b/src/net/sourceforge/plantuml/project/lang/Verbs.java @@ -70,17 +70,33 @@ public class Verbs { new RegexLeaf("off"), // RegexLeaf.spaceOneOrMore(), // new RegexOr(// + new RegexLeaf("from"), // new RegexLeaf("on"), // new RegexLeaf("for"), // new RegexLeaf("the"), // new RegexLeaf("at") // )); + public static IRegex isOffBefore = new RegexConcat(new RegexLeaf("is"), // + RegexLeaf.spaceOneOrMore(), // + new RegexLeaf("off"), // + RegexLeaf.spaceOneOrMore(), // + new RegexLeaf("before") // + ); + + public static IRegex isOffAfter = new RegexConcat(new RegexLeaf("is"), // + RegexLeaf.spaceOneOrMore(), // + new RegexLeaf("off"), // + RegexLeaf.spaceOneOrMore(), // + new RegexLeaf("after") // + ); + public static IRegex isOn = new RegexConcat(new RegexLeaf("is"), // RegexLeaf.spaceOneOrMore(), // new RegexLeaf("on"), // RegexLeaf.spaceOneOrMore(), // new RegexOr(// + new RegexLeaf("from"), // new RegexLeaf("on"), // new RegexLeaf("for"), // new RegexLeaf("the"), // diff --git a/src/net/sourceforge/plantuml/project/solver/ImpossibleSolvingException.java b/src/net/sourceforge/plantuml/project/solver/ImpossibleSolvingException.java new file mode 100644 index 000000000..c13085fde --- /dev/null +++ b/src/net/sourceforge/plantuml/project/solver/ImpossibleSolvingException.java @@ -0,0 +1,44 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2024, Arnaud Roques + * + * Project Info: https://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * https://plantuml.com/patreon (only 1$ per month!) + * https://plantuml.com/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.project.solver; + +public class ImpossibleSolvingException extends RuntimeException { + + public ImpossibleSolvingException(String message) { + super(message); + } + +} diff --git a/src/net/sourceforge/plantuml/project/solver/SolverImpl.java b/src/net/sourceforge/plantuml/project/solver/SolverImpl.java index b7898c72b..d20d0d851 100644 --- a/src/net/sourceforge/plantuml/project/solver/SolverImpl.java +++ b/src/net/sourceforge/plantuml/project/solver/SolverImpl.java @@ -41,7 +41,7 @@ import net.sourceforge.plantuml.project.core.TaskAttribute; import net.sourceforge.plantuml.project.time.Day; public class SolverImpl extends AbstractSolver implements Solver { - // ::remove folder when __HAXE__ + // ::remove folder when __HAXE__ private final LoadPlanable loadPlanable; @@ -54,12 +54,17 @@ public class SolverImpl extends AbstractSolver implements Solver { Day current = (Day) values.get(TaskAttribute.START); int fullLoad = ((Load) values.get(TaskAttribute.LOAD)).getFullLoad(); int cpt = 0; + final Day lastDayIfAny = loadPlanable.getLastDayIfAny(); while (fullLoad > 0) { fullLoad -= loadPlanable.getLoadAt(current); current = current.increment(); + if (lastDayIfAny != null && current.compareTo(lastDayIfAny) > 0) + throw new ImpossibleSolvingException( + "Because all resources will be off at some point, we cannot compute any end date for " + + loadPlanable); cpt++; if (cpt > 100000) - throw new IllegalStateException(); + throw new ImpossibleSolvingException("There is an issue in planning your tasks!"); } return current.decrement(); @@ -78,7 +83,7 @@ public class SolverImpl extends AbstractSolver implements Solver { cpt++; if (cpt > 100000) - throw new IllegalStateException(); + throw new ImpossibleSolvingException("There is an issue in planning your tasks!"); } return current.increment(); diff --git a/src/net/sourceforge/plantuml/style/SName.java b/src/net/sourceforge/plantuml/style/SName.java index aa74331bb..96644bffe 100644 --- a/src/net/sourceforge/plantuml/style/SName.java +++ b/src/net/sourceforge/plantuml/style/SName.java @@ -138,7 +138,8 @@ public enum SName { undone, // unstarted, // usecase, // - + verticalSeparator, // + visibilityIcon, // private_, // protected_, // diff --git a/src/net/sourceforge/plantuml/version/Version.java b/src/net/sourceforge/plantuml/version/Version.java index a8d2af927..942297437 100644 --- a/src/net/sourceforge/plantuml/version/Version.java +++ b/src/net/sourceforge/plantuml/version/Version.java @@ -46,7 +46,7 @@ public class Version { // Warning, "version" should be the same in gradle.properties and Version.java // Any idea anyone how to magically synchronize those :-) ? - private static final String version = "1.2023.13beta2"; + private static final String version = "1.2023.13beta3"; public static String versionString() { return version;