From 4cad5546ac72871deca19e0fb4a43953ce6a473e Mon Sep 17 00:00:00 2001 From: Arnaud Roques Date: Tue, 18 Feb 2020 22:24:31 +0100 Subject: [PATCH] version 1.2020.1 --- pom.xml | 2 +- src/net/sourceforge/plantuml/FontParam.java | 2 +- .../sourceforge/plantuml/PSystemBuilder.java | 6 +- .../sourceforge/plantuml/PSystemUtils.java | 2 +- src/net/sourceforge/plantuml/Pipe.java | 10 + src/net/sourceforge/plantuml/Pragma.java | 8 + .../sourceforge/plantuml/UmlDiagramType.java | 2 +- .../ActivityDiagramFactory.java | 8 +- .../activitydiagram3/ActivityDiagram3.java | 4 +- .../ActivityDiagramFactory3.java | 2 +- .../activitydiagram3/InstructionRepeat.java | 19 +- .../command/CommandRepeat3.java | 28 +- .../activitydiagram3/ftile/FtileFactory.java | 6 +- .../ftile/FtileFactoryDelegator.java | 14 +- .../vcompact/FtileFactoryDelegatorRepeat.java | 51 +- .../ftile/vcompact/FtileRepeat.java | 16 +- .../ftile/vcompact/VCompactFactory.java | 15 +- .../plantuml/classdiagram/ClassDiagram.java | 2 + .../classdiagram/ClassDiagramFactory.java | 20 +- .../command/CommandCreateClassMultilines.java | 1 + .../command/CommandLinkClass.java | 30 +- .../plantuml/command/BlocLines.java | 8 + ...Command.java => CommandFactorySprite.java} | 10 +- .../plantuml/command/UmlDiagramFactory.java | 2 +- .../note/CommandConstraintOnLinks.java | 101 ++++ ...teCommand.java => CommandFactoryNote.java} | 6 +- ...d.java => CommandFactoryNoteActivity.java} | 6 +- ...d.java => CommandFactoryNoteOnEntity.java} | 10 +- ...and.java => CommandFactoryNoteOnLink.java} | 6 +- ...nd.java => CommandFactoryTipOnEntity.java} | 8 +- .../plantuml/core/DiagramType.java | 5 +- .../sourceforge/plantuml/creole/AtomImg.java | 16 +- .../sourceforge/plantuml/creole/AtomMath.java | 2 +- .../sourceforge/plantuml/creole/AtomText.java | 77 +-- .../plantuml/cucadiagram/Bodier.java | 8 +- .../plantuml/cucadiagram/BodyEnhanced.java | 4 +- .../plantuml/cucadiagram/CucaDiagram.java | 73 ++- .../plantuml/cucadiagram/GroupHierarchy.java | 9 +- .../plantuml/cucadiagram/Ident.java | 8 + .../plantuml/cucadiagram/Link.java | 25 +- .../plantuml/cucadiagram/LinkConstraint.java | 106 ++++ .../plantuml/cucadiagram/Member.java | 165 +++++- .../plantuml/cucadiagram/MemberImpl.java | 205 -------- .../SuperGroup.java} | 17 +- .../plantuml/cucadiagram/dot/DotData.java | 4 + .../cucadiagram/entity/EntityFactory.java | 108 +++- .../cucadiagram/entity/EntityImpl.java | 59 ++- .../DescriptionDiagramFactory.java | 12 +- .../CommandCreateElementParenthesis.java | 242 +++++++++ .../plantuml/donors/PSystemDonors.java | 43 +- .../plantuml/graphic/QuoteUtils.java | 495 +++++++----------- .../plantuml/graphic/TextBlockUtils.java | 10 +- .../jdot/CucaDiagramFileMakerJDot.java | 106 ++-- .../objectdiagram/ObjectDiagramFactory.java | 12 +- .../sourceforge/plantuml/posimo/DotPath.java | 49 +- .../sourceforge/plantuml/preproc/Stdlib.java | 46 +- .../{project3 => project}/Arrows.java | 2 +- .../Completion.java} | 23 +- .../{project3 => project}/ConstantPlan.java | 6 +- .../{project3 => project}/DayAsDate.java | 47 +- .../{project3 => project}/DayOfWeek.java | 4 +- .../{project3 => project}/DaysAsDates.java | 5 +- .../{project3 => project}/Failable.java | 2 +- .../GCalendar.java} | 16 +- .../{project3 => project}/GanttArrow.java | 11 +- .../GanttConstraint.java | 5 +- .../{project3 => project}/GanttDiagram.java | 321 ++++-------- .../GanttDiagramFactory.java | 28 +- .../plantuml/{project3 => project}/Load.java | 20 +- .../{project3 => project}/LoadPlanable.java | 6 +- .../{project3 => project}/PlanUtils.java | 8 +- .../{project3 => project}/Solver3.java | 22 +- .../plantuml/{project3 => project}/Today.java | 4 +- .../plantuml/{project3 => project}/Value.java | 2 +- .../command}/CommandGanttArrow.java | 7 +- .../command}/CommandGanttArrow2.java | 4 +- .../command}/CommandPage.java | 3 +- .../project/command/CommandPrintBetween.java | 84 +++ .../project/command/CommandPrintScale.java | 73 +++ .../command}/CommandSeparator.java | 3 +- .../command}/NaturalCommand.java | 11 +- .../command}/NaturalCommandAnd.java | 10 +- .../command}/NaturalCommandAndAnd.java | 9 +- .../{project3 => project/core}/Moment.java | 6 +- .../core}/MomentImpl.java | 12 +- .../{project3 => project/core}/Month.java | 11 +- .../core/PrintScale.java} | 17 +- .../{project3 => project/core}/Resource.java | 21 +- .../{project3 => project/core}/Task.java | 17 +- .../core}/TaskAttribute.java | 2 +- .../{project3 => project/core}/TaskCode.java | 2 +- .../{project3 => project/core}/TaskImpl.java | 39 +- .../core}/TaskInstant.java | 10 +- .../core}/TaskSeparator.java | 18 +- .../core/Wink.java} | 32 +- .../draw}/ResourceDraw.java | 14 +- .../{project3 => project/draw}/TaskDraw.java | 5 +- .../draw}/TaskDrawRegular.java | 68 ++- .../draw}/TaskDrawSeparator.java | 14 +- .../plantuml/project/draw/TimeHeader.java | 113 ++++ .../project/draw/TimeHeaderDaily.java | 188 +++++++ .../project/draw/TimeHeaderSimple.java | 97 ++++ .../project/draw/TimeHeaderWeekly.java | 188 +++++++ .../lang}/Complement.java | 2 +- ...lementBeforeOrAfterOrAtTaskStartOrEnd.java | 7 +- .../lang}/ComplementClose.java | 4 +- .../lang}/ComplementColors.java | 2 +- .../project/lang/ComplementCompleted.java | 55 ++ .../lang}/ComplementDate.java | 6 +- .../lang}/ComplementDates.java | 6 +- .../lang}/ComplementDayOfWeek.java | 5 +- .../lang}/ComplementEmpty.java | 4 +- .../lang}/ComplementInColors.java | 4 +- .../lang}/ComplementInColors2.java | 4 +- .../lang}/ComplementName.java | 2 +- .../lang}/ComplementNamed.java | 4 +- .../lang}/ComplementOpen.java | 4 +- .../lang}/ComplementPattern.java | 4 +- .../lang}/ComplementSeveralDays.java | 7 +- .../{project3 => project/lang}/Subject.java | 2 +- .../lang}/SubjectDayAsDate.java | 4 +- .../lang}/SubjectDayOfWeek.java | 4 +- .../lang}/SubjectDaysAsDates.java | 5 +- .../lang}/SubjectPattern.java | 3 +- .../lang}/SubjectProject.java | 3 +- .../lang}/SubjectResource.java | 3 +- .../lang}/SubjectTask.java | 6 +- .../lang}/SubjectToday.java | 4 +- .../{project3 => project/lang}/Verb.java | 2 +- .../{project3 => project/lang}/VerbAre.java | 4 +- .../{project3 => project/lang}/VerbEnds.java | 7 +- .../lang}/VerbHappens.java | 9 +- .../lang}/VerbIsColored.java | 4 +- .../lang}/VerbIsColoredForToday.java | 4 +- .../lang}/VerbIsDeleted.java | 4 +- .../plantuml/project/lang/VerbIsForTask.java | 70 +++ .../lang}/VerbIsForToday.java | 6 +- .../{project3 => project/lang}/VerbIsOff.java | 7 +- .../{project3 => project/lang}/VerbIsOn.java | 6 +- .../lang}/VerbIsOrAre.java | 5 +- .../lang}/VerbIsOrAreNamed.java | 5 +- .../{project3 => project/lang}/VerbLasts.java | 5 +- .../lang}/VerbPattern.java | 3 +- .../lang}/VerbProjectStarts.java | 4 +- .../lang}/VerbTaskEndsAbsolute.java | 5 +- .../lang}/VerbTaskStarts.java | 7 +- .../lang}/VerbTaskStartsAbsolute.java | 5 +- .../timescale}/TimeScale.java | 10 +- .../project/timescale/TimeScaleDaily.java | 69 +++ .../timescale/TimeScaleWeekly.java} | 28 +- .../timescale/TimeScaleWink.java} | 16 +- .../UnusedTimeScaleWithoutWeekEnd.java} | 23 +- .../plantuml/project3/TimeScaleBasic2.java | 79 --- .../plantuml/salt/PSystemSalt.java | 5 +- .../SequenceDiagramFileMakerPuma2.java | 2 +- .../teoz/SequenceDiagramFileMakerTeoz.java | 2 +- .../plantuml/sprite/CommandStdlib.java | 67 +++ .../plantuml/sprite/StdlibDiagram.java | 164 ++++++ .../plantuml/sprite/StdlibDiagramFactory.java | 66 +++ .../statediagram/StateDiagramFactory.java | 12 +- .../plantuml/svek/Bibliotekon.java | 41 +- .../sourceforge/plantuml/svek/Cluster.java | 145 ++--- .../svek/CucaDiagramFileMakerSvek.java | 10 +- .../plantuml/svek/DotStringFactory.java | 62 ++- .../plantuml/svek/GeneralImageBuilder.java | 72 ++- .../plantuml/svek/GroupPngMakerActivity.java | 26 +- .../plantuml/svek/GroupPngMakerState.java | 34 +- src/net/sourceforge/plantuml/svek/Line.java | 113 ++-- .../plantuml/svek/{Shape.java => Node.java} | 32 +- .../sourceforge/plantuml/svek/SvekResult.java | 10 +- .../svek/image/EntityImageActivity.java | 6 +- .../EntityImageLollipopInterfaceEye1.java | 2 +- .../plantuml/svek/image/EntityImageNote.java | 18 +- .../svek/image/EntityImageStateBorder.java | 6 +- .../plantuml/svek/image/EntityImageTips.java | 14 +- .../sourceforge/plantuml/svg/SvgGraphics.java | 12 +- .../plantuml/tikz/TikzGraphics.java | 16 +- .../sourceforge/plantuml/ugraphic/UImage.java | 31 +- .../ugraphic/tikz/DriverImageTikz.java | 11 +- .../sourceforge/plantuml/version/Version.java | 7 +- src/net/sourceforge/plantuml/wire/Block.java | 208 ++++++++ .../plantuml/wire/CommandComponent.java | 82 +++ .../plantuml/wire/CommandContainer.java | 70 +++ .../plantuml/wire/CommandContainerEnd.java | 65 +++ .../plantuml/wire/CommandNewColumn.java | 65 +++ .../sourceforge/plantuml/wire/CommandPin.java | 79 +++ .../plantuml/wire/CommandPinSpace.java | 72 +++ .../plantuml/wire/CommandVspace.java | 68 +++ .../plantuml/wire/WireDiagram.java | 163 ++++++ .../plantuml/wire/WireDiagramFactory.java | 72 +++ stdlib/cloudinsight-abx.repx | Bin 802 -> 803 bytes stdlib/home.repx | 1 + stdlib/logos-abx.repx | Bin 0 -> 11300 bytes stdlib/logos-dex.repx | Bin 0 -> 273114 bytes 194 files changed, 4759 insertions(+), 1634 deletions(-) rename src/net/sourceforge/plantuml/command/{FactorySpriteCommand.java => CommandFactorySprite.java} (94%) create mode 100644 src/net/sourceforge/plantuml/command/note/CommandConstraintOnLinks.java rename src/net/sourceforge/plantuml/command/note/{FactoryNoteCommand.java => CommandFactoryNote.java} (96%) rename src/net/sourceforge/plantuml/command/note/{FactoryNoteActivityCommand.java => CommandFactoryNoteActivity.java} (97%) rename src/net/sourceforge/plantuml/command/note/{FactoryNoteOnEntityCommand.java => CommandFactoryNoteOnEntity.java} (96%) rename src/net/sourceforge/plantuml/command/note/{FactoryNoteOnLinkCommand.java => CommandFactoryNoteOnLink.java} (96%) rename src/net/sourceforge/plantuml/command/note/{FactoryTipOnEntityCommand.java => CommandFactoryTipOnEntity.java} (96%) create mode 100644 src/net/sourceforge/plantuml/cucadiagram/LinkConstraint.java delete mode 100644 src/net/sourceforge/plantuml/cucadiagram/MemberImpl.java rename src/net/sourceforge/plantuml/{project3/Instant.java => cucadiagram/SuperGroup.java} (80%) create mode 100644 src/net/sourceforge/plantuml/descdiagram/command/CommandCreateElementParenthesis.java rename src/net/sourceforge/plantuml/{project3 => project}/Arrows.java (98%) rename src/net/sourceforge/plantuml/{project3/Resources.java => project/Completion.java} (76%) rename src/net/sourceforge/plantuml/{project3 => project}/ConstantPlan.java (92%) rename src/net/sourceforge/plantuml/{project3 => project}/DayAsDate.java (74%) rename src/net/sourceforge/plantuml/{project3 => project}/DayOfWeek.java (93%) rename src/net/sourceforge/plantuml/{project3 => project}/DaysAsDates.java (93%) rename src/net/sourceforge/plantuml/{project3 => project}/Failable.java (97%) rename src/net/sourceforge/plantuml/{project3/GCalendarSimple.java => project/GCalendar.java} (84%) rename src/net/sourceforge/plantuml/{project3 => project}/GanttArrow.java (92%) rename src/net/sourceforge/plantuml/{project3 => project}/GanttConstraint.java (88%) rename src/net/sourceforge/plantuml/{project3 => project}/GanttDiagram.java (63%) rename src/net/sourceforge/plantuml/{project3 => project}/GanttDiagramFactory.java (74%) rename src/net/sourceforge/plantuml/{project3 => project}/Load.java (78%) rename src/net/sourceforge/plantuml/{project3 => project}/LoadPlanable.java (90%) rename src/net/sourceforge/plantuml/{project3 => project}/PlanUtils.java (90%) rename src/net/sourceforge/plantuml/{project3 => project}/Solver3.java (84%) rename src/net/sourceforge/plantuml/{project3 => project}/Today.java (93%) rename src/net/sourceforge/plantuml/{project3 => project}/Value.java (96%) rename src/net/sourceforge/plantuml/{project3 => project/command}/CommandGanttArrow.java (89%) rename src/net/sourceforge/plantuml/{project3 => project/command}/CommandGanttArrow2.java (94%) rename src/net/sourceforge/plantuml/{project3 => project/command}/CommandPage.java (96%) create mode 100644 src/net/sourceforge/plantuml/project/command/CommandPrintBetween.java create mode 100644 src/net/sourceforge/plantuml/project/command/CommandPrintScale.java rename src/net/sourceforge/plantuml/{project3 => project/command}/CommandSeparator.java (95%) rename src/net/sourceforge/plantuml/{project3 => project/command}/NaturalCommand.java (86%) rename src/net/sourceforge/plantuml/{project3 => project/command}/NaturalCommandAnd.java (89%) rename src/net/sourceforge/plantuml/{project3 => project/command}/NaturalCommandAndAnd.java (91%) rename src/net/sourceforge/plantuml/{project3 => project/core}/Moment.java (92%) rename src/net/sourceforge/plantuml/{project3 => project/core}/MomentImpl.java (87%) rename src/net/sourceforge/plantuml/{project3 => project/core}/Month.java (92%) rename src/net/sourceforge/plantuml/{project3/GCalendar.java => project/core/PrintScale.java} (85%) rename src/net/sourceforge/plantuml/{project3 => project/core}/Resource.java (79%) rename src/net/sourceforge/plantuml/{project3 => project/core}/Task.java (79%) rename src/net/sourceforge/plantuml/{project3 => project/core}/TaskAttribute.java (96%) rename src/net/sourceforge/plantuml/{project3 => project/core}/TaskCode.java (97%) rename src/net/sourceforge/plantuml/{project3 => project/core}/TaskImpl.java (82%) rename src/net/sourceforge/plantuml/{project3 => project/core}/TaskInstant.java (92%) rename src/net/sourceforge/plantuml/{project3 => project/core}/TaskSeparator.java (85%) rename src/net/sourceforge/plantuml/{project3/InstantDay.java => project/core/Wink.java} (72%) rename src/net/sourceforge/plantuml/{project3 => project/draw}/ResourceDraw.java (90%) rename src/net/sourceforge/plantuml/{project3 => project/draw}/TaskDraw.java (89%) rename src/net/sourceforge/plantuml/{project3 => project/draw}/TaskDrawRegular.java (70%) rename src/net/sourceforge/plantuml/{project3 => project/draw}/TaskDrawSeparator.java (89%) create mode 100644 src/net/sourceforge/plantuml/project/draw/TimeHeader.java create mode 100644 src/net/sourceforge/plantuml/project/draw/TimeHeaderDaily.java create mode 100644 src/net/sourceforge/plantuml/project/draw/TimeHeaderSimple.java create mode 100644 src/net/sourceforge/plantuml/project/draw/TimeHeaderWeekly.java rename src/net/sourceforge/plantuml/{project3 => project/lang}/Complement.java (96%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/ComplementBeforeOrAfterOrAtTaskStartOrEnd.java (88%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/ComplementClose.java (92%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/ComplementColors.java (97%) create mode 100644 src/net/sourceforge/plantuml/project/lang/ComplementCompleted.java rename src/net/sourceforge/plantuml/{project3 => project/lang}/ComplementDate.java (94%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/ComplementDates.java (93%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/ComplementDayOfWeek.java (90%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/ComplementEmpty.java (91%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/ComplementInColors.java (93%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/ComplementInColors2.java (93%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/ComplementName.java (96%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/ComplementNamed.java (92%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/ComplementOpen.java (92%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/ComplementPattern.java (91%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/ComplementSeveralDays.java (89%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/Subject.java (96%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/SubjectDayAsDate.java (93%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/SubjectDayOfWeek.java (92%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/SubjectDaysAsDates.java (95%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/SubjectPattern.java (93%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/SubjectProject.java (94%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/SubjectResource.java (95%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/SubjectTask.java (93%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/SubjectToday.java (92%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/Verb.java (96%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/VerbAre.java (93%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/VerbEnds.java (87%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/VerbHappens.java (88%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/VerbIsColored.java (93%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/VerbIsColoredForToday.java (93%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/VerbIsDeleted.java (93%) create mode 100644 src/net/sourceforge/plantuml/project/lang/VerbIsForTask.java rename src/net/sourceforge/plantuml/{project3 => project/lang}/VerbIsForToday.java (91%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/VerbIsOff.java (90%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/VerbIsOn.java (91%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/VerbIsOrAre.java (94%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/VerbIsOrAreNamed.java (91%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/VerbLasts.java (91%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/VerbPattern.java (93%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/VerbProjectStarts.java (94%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/VerbTaskEndsAbsolute.java (92%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/VerbTaskStarts.java (87%) rename src/net/sourceforge/plantuml/{project3 => project/lang}/VerbTaskStartsAbsolute.java (92%) rename src/net/sourceforge/plantuml/{project3 => project/timescale}/TimeScale.java (84%) create mode 100644 src/net/sourceforge/plantuml/project/timescale/TimeScaleDaily.java rename src/net/sourceforge/plantuml/{project3/LoadInDays.java => project/timescale/TimeScaleWeekly.java} (65%) rename src/net/sourceforge/plantuml/{project3/TimeScaleBasic.java => project/timescale/TimeScaleWink.java} (79%) rename src/net/sourceforge/plantuml/{project3/TimeScaleWithoutWeekEnd.java => project/timescale/UnusedTimeScaleWithoutWeekEnd.java} (72%) delete mode 100644 src/net/sourceforge/plantuml/project3/TimeScaleBasic2.java create mode 100644 src/net/sourceforge/plantuml/sprite/CommandStdlib.java create mode 100644 src/net/sourceforge/plantuml/sprite/StdlibDiagram.java create mode 100644 src/net/sourceforge/plantuml/sprite/StdlibDiagramFactory.java rename src/net/sourceforge/plantuml/svek/{Shape.java => Node.java} (91%) create mode 100644 src/net/sourceforge/plantuml/wire/Block.java create mode 100644 src/net/sourceforge/plantuml/wire/CommandComponent.java create mode 100644 src/net/sourceforge/plantuml/wire/CommandContainer.java create mode 100644 src/net/sourceforge/plantuml/wire/CommandContainerEnd.java create mode 100644 src/net/sourceforge/plantuml/wire/CommandNewColumn.java create mode 100644 src/net/sourceforge/plantuml/wire/CommandPin.java create mode 100644 src/net/sourceforge/plantuml/wire/CommandPinSpace.java create mode 100644 src/net/sourceforge/plantuml/wire/CommandVspace.java create mode 100644 src/net/sourceforge/plantuml/wire/WireDiagram.java create mode 100644 src/net/sourceforge/plantuml/wire/WireDiagramFactory.java create mode 100644 stdlib/logos-abx.repx create mode 100644 stdlib/logos-dex.repx diff --git a/pom.xml b/pom.xml index e163f67e5..bec6253cb 100644 --- a/pom.xml +++ b/pom.xml @@ -35,7 +35,7 @@ net.sourceforge.plantuml plantuml - 1.2020.1-SNAPSHOT + 1.2020.2-SNAPSHOT jar PlantUML diff --git a/src/net/sourceforge/plantuml/FontParam.java b/src/net/sourceforge/plantuml/FontParam.java index a29fc1215..1842eb5d1 100644 --- a/src/net/sourceforge/plantuml/FontParam.java +++ b/src/net/sourceforge/plantuml/FontParam.java @@ -94,11 +94,11 @@ public enum FontParam { SEQUENCE_GROUP_HEADER(13, Font.BOLD), // PARTICIPANT(14, Font.PLAIN), // PARTICIPANT_STEREOTYPE(14, Font.ITALIC), // - SEQUENCE_TITLE(14, Font.BOLD), // STATE(14, Font.PLAIN), // STATE_ATTRIBUTE(12, Font.PLAIN), // LEGEND(14, Font.PLAIN), // TITLE(18, Font.PLAIN), // + // SEQUENCE_TITLE(14, Font.BOLD), // CAPTION(14, Font.PLAIN), // SWIMLANE_TITLE(18, Font.PLAIN), // FOOTER(10, Font.PLAIN, "#888888", FontParamConstant.FAMILY), // diff --git a/src/net/sourceforge/plantuml/PSystemBuilder.java b/src/net/sourceforge/plantuml/PSystemBuilder.java index 0ce4e66a5..3fbbe0459 100644 --- a/src/net/sourceforge/plantuml/PSystemBuilder.java +++ b/src/net/sourceforge/plantuml/PSystemBuilder.java @@ -75,10 +75,11 @@ import net.sourceforge.plantuml.nwdiag.NwDiagramFactory; import net.sourceforge.plantuml.openiconic.PSystemListOpenIconicFactory; import net.sourceforge.plantuml.openiconic.PSystemOpenIconicFactory; import net.sourceforge.plantuml.oregon.PSystemOregonFactory; -import net.sourceforge.plantuml.project3.GanttDiagramFactory; +import net.sourceforge.plantuml.project.GanttDiagramFactory; import net.sourceforge.plantuml.salt.PSystemSaltFactory; import net.sourceforge.plantuml.sequencediagram.SequenceDiagramFactory; import net.sourceforge.plantuml.sprite.ListSpriteDiagramFactory; +import net.sourceforge.plantuml.sprite.StdlibDiagramFactory; import net.sourceforge.plantuml.sprite.PSystemListInternalSpritesFactory; import net.sourceforge.plantuml.statediagram.StateDiagramFactory; import net.sourceforge.plantuml.stats.StatsUtilsIncrement; @@ -88,6 +89,7 @@ import net.sourceforge.plantuml.version.License; import net.sourceforge.plantuml.version.PSystemLicenseFactory; import net.sourceforge.plantuml.version.PSystemVersionFactory; import net.sourceforge.plantuml.wbs.WBSDiagramFactory; +import net.sourceforge.plantuml.wire.WireDiagramFactory; public class PSystemBuilder { @@ -178,6 +180,7 @@ public class PSystemBuilder { } factories.add(new PSystemDefinitionFactory()); factories.add(new ListSpriteDiagramFactory(skinParam)); + factories.add(new StdlibDiagramFactory(skinParam)); factories.add(new PSystemMathFactory(DiagramType.MATH)); factories.add(new PSystemLatexFactory(DiagramType.LATEX)); // factories.add(new PSystemStatsFactory()); @@ -200,6 +203,7 @@ public class PSystemBuilder { factories.add(new PSystemDedicationFactory()); factories.add(new TimingDiagramFactory()); factories.add(new HelpFactory()); + factories.add(new WireDiagramFactory()); return factories; } diff --git a/src/net/sourceforge/plantuml/PSystemUtils.java b/src/net/sourceforge/plantuml/PSystemUtils.java index 060f50966..c3fe74f62 100644 --- a/src/net/sourceforge/plantuml/PSystemUtils.java +++ b/src/net/sourceforge/plantuml/PSystemUtils.java @@ -52,7 +52,7 @@ import net.sourceforge.plantuml.cucadiagram.CucaDiagram; import net.sourceforge.plantuml.graphic.HtmlColorUtils; import net.sourceforge.plantuml.html.CucaDiagramHtmlMaker; import net.sourceforge.plantuml.png.PngSplitter; -import net.sourceforge.plantuml.project3.GanttDiagram; +import net.sourceforge.plantuml.project.GanttDiagram; import net.sourceforge.plantuml.sequencediagram.SequenceDiagram; public class PSystemUtils { diff --git a/src/net/sourceforge/plantuml/Pipe.java b/src/net/sourceforge/plantuml/Pipe.java index cb9031133..4f868072b 100644 --- a/src/net/sourceforge/plantuml/Pipe.java +++ b/src/net/sourceforge/plantuml/Pipe.java @@ -153,6 +153,8 @@ public class Pipe { final String s = readOneLine(); if (s == null) { closed = true; + } else if (s.startsWith("@@@format ")) { + manageFormat(s); } else { sb.append(s); sb.append(BackSlash.NEWLINE); @@ -171,6 +173,14 @@ public class Pipe { return source; } + private void manageFormat(String s) { + if (s.contains("png")) { + option.setFileFormatOption(new FileFormatOption(FileFormat.PNG)); + } else if (s.contains("svg")) { + option.setFileFormatOption(new FileFormatOption(FileFormat.SVG)); + } + } + private String readOneLine() throws IOException { final ByteArrayOutputStream baos = new ByteArrayOutputStream(); while (true) { diff --git a/src/net/sourceforge/plantuml/Pragma.java b/src/net/sourceforge/plantuml/Pragma.java index 59c69b60e..9e69cc7fb 100644 --- a/src/net/sourceforge/plantuml/Pragma.java +++ b/src/net/sourceforge/plantuml/Pragma.java @@ -62,6 +62,14 @@ public class Pragma { return isDefine("horizontallinebetweendifferentpackageallowed"); } + public boolean backToLegacyPackage() { + return isDefine("backtolegacypackage"); + } + + public boolean useNewPackage() { + return isDefine("usenewpackage"); + } + public boolean useVerticalIf() { final String teoz = getValue("useverticalif"); return "true".equalsIgnoreCase(teoz) || "on".equalsIgnoreCase(teoz); diff --git a/src/net/sourceforge/plantuml/UmlDiagramType.java b/src/net/sourceforge/plantuml/UmlDiagramType.java index d2a1d76f3..68947c1cc 100644 --- a/src/net/sourceforge/plantuml/UmlDiagramType.java +++ b/src/net/sourceforge/plantuml/UmlDiagramType.java @@ -36,5 +36,5 @@ package net.sourceforge.plantuml; public enum UmlDiagramType { - SEQUENCE, STATE, CLASS, OBJECT, ACTIVITY, DESCRIPTION, COMPOSITE, FLOW, TIMING, BPM, NWDIAG, MINDMAP, WBS, HELP + SEQUENCE, STATE, CLASS, OBJECT, ACTIVITY, DESCRIPTION, COMPOSITE, FLOW, TIMING, BPM, NWDIAG, MINDMAP, WBS, WIRE, HELP } diff --git a/src/net/sourceforge/plantuml/activitydiagram/ActivityDiagramFactory.java b/src/net/sourceforge/plantuml/activitydiagram/ActivityDiagramFactory.java index 2c5146cb7..7d6c7a750 100644 --- a/src/net/sourceforge/plantuml/activitydiagram/ActivityDiagramFactory.java +++ b/src/net/sourceforge/plantuml/activitydiagram/ActivityDiagramFactory.java @@ -51,8 +51,8 @@ import net.sourceforge.plantuml.command.Command; import net.sourceforge.plantuml.command.CommandFootboxIgnored; import net.sourceforge.plantuml.command.CommandRankDir; import net.sourceforge.plantuml.command.UmlDiagramFactory; -import net.sourceforge.plantuml.command.note.FactoryNoteActivityCommand; -import net.sourceforge.plantuml.command.note.FactoryNoteOnLinkCommand; +import net.sourceforge.plantuml.command.note.CommandFactoryNoteActivity; +import net.sourceforge.plantuml.command.note.CommandFactoryNoteOnLink; public class ActivityDiagramFactory extends UmlDiagramFactory { @@ -79,11 +79,11 @@ public class ActivityDiagramFactory extends UmlDiagramFactory { cmds.add(new CommandEndPartition()); cmds.add(new CommandLinkLongActivity()); - final FactoryNoteActivityCommand factoryNoteActivityCommand = new FactoryNoteActivityCommand(); + final CommandFactoryNoteActivity factoryNoteActivityCommand = new CommandFactoryNoteActivity(); cmds.add(factoryNoteActivityCommand.createSingleLine()); cmds.add(factoryNoteActivityCommand.createMultiLine(false)); - final FactoryNoteOnLinkCommand factoryNoteOnLinkCommand = new FactoryNoteOnLinkCommand(); + final CommandFactoryNoteOnLink factoryNoteOnLinkCommand = new CommandFactoryNoteOnLink(); cmds.add(factoryNoteOnLinkCommand.createSingleLine()); cmds.add(factoryNoteOnLinkCommand.createMultiLine(false)); diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ActivityDiagram3.java b/src/net/sourceforge/plantuml/activitydiagram3/ActivityDiagram3.java index 2e912745d..f1c2c1c72 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/ActivityDiagram3.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/ActivityDiagram3.java @@ -371,10 +371,10 @@ public class ActivityDiagram3 extends UmlDiagram { return CommandExecutionResult.error("Cannot find if"); } - public void startRepeat(HtmlColor color, Display label) { + public void startRepeat(HtmlColor color, Display label, BoxStyle boxStyleIn, Colors colors) { manageSwimlaneStrategy(); final InstructionRepeat instructionRepeat = new InstructionRepeat(swinlanes.getCurrentSwimlane(), current(), - nextLinkRenderer(), color, label); + nextLinkRenderer(), color, label, boxStyleIn, colors); current().add(instructionRepeat); setCurrent(instructionRepeat); setNextLinkRendererInternal(LinkRendering.none()); diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ActivityDiagramFactory3.java b/src/net/sourceforge/plantuml/activitydiagram3/ActivityDiagramFactory3.java index 2a83e2060..2ef005d91 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/ActivityDiagramFactory3.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/ActivityDiagramFactory3.java @@ -111,6 +111,7 @@ public class ActivityDiagramFactory3 extends UmlDiagramFactory { cmds.add(new CommandGroupEnd3()); cmds.add(new CommandArrow3()); cmds.add(new CommandArrowLong3()); + cmds.add(new CommandRepeat3()); cmds.add(new CommandActivity3()); cmds.add(new CommandIf4()); cmds.add(new CommandIf2()); @@ -126,7 +127,6 @@ public class ActivityDiagramFactory3 extends UmlDiagramFactory { cmds.add(new CommandCase()); cmds.add(new CommandEndSwitch()); - cmds.add(new CommandRepeat3()); cmds.add(new CommandRepeatWhile3()); cmds.add(new CommandRepeatWhile3Multilines()); cmds.add(new CommandBackward3()); diff --git a/src/net/sourceforge/plantuml/activitydiagram3/InstructionRepeat.java b/src/net/sourceforge/plantuml/activitydiagram3/InstructionRepeat.java index ef21f3b56..40467e168 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/InstructionRepeat.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/InstructionRepeat.java @@ -55,8 +55,9 @@ public class InstructionRepeat implements Instruction { private final LinkRendering nextLinkRenderer; private final Swimlane swimlane; private Swimlane swimlaneOut; - private final HtmlColor color; +// private final HtmlColor color; private boolean killed = false; + private final BoxStyle boxStyleIn; private Display backward = Display.NULL; private Display test = Display.NULL; @@ -66,13 +67,15 @@ public class InstructionRepeat implements Instruction { private boolean testCalled = false; private LinkRendering endRepeatLinkRendering = LinkRendering.none(); private LinkRendering backRepeatLinkRendering = LinkRendering.none(); + private final Colors colors; public boolean containsBreak() { return repeatList.containsBreak(); } public InstructionRepeat(Swimlane swimlane, Instruction parent, LinkRendering nextLinkRenderer, HtmlColor color, - Display startLabel) { + Display startLabel, BoxStyle boxStyleIn, Colors colors) { + this.boxStyleIn = boxStyleIn; this.startLabel = startLabel; this.parent = parent; this.swimlane = swimlane; @@ -80,7 +83,7 @@ public class InstructionRepeat implements Instruction { if (nextLinkRenderer == null) { throw new IllegalArgumentException(); } - this.color = color; + this.colors = colors; } private boolean isLastOfTheParent() { @@ -100,11 +103,11 @@ public class InstructionRepeat implements Instruction { } public Ftile createFtile(FtileFactory factory) { - final Ftile back = Display.isNull(backward) ? null : factory.activity(backward, swimlane, BoxStyle.PLAIN, - Colors.empty()); - final Ftile result = factory.repeat(swimlane, swimlaneOut, startLabel, - factory.decorateOut(repeatList.createFtile(factory), endRepeatLinkRendering), test, yes, out, color, - backRepeatLinkRendering, back, isLastOfTheParent()); + final Ftile back = Display.isNull(backward) ? null + : factory.activity(backward, swimlane, BoxStyle.PLAIN, Colors.empty()); + final Ftile decorateOut = factory.decorateOut(repeatList.createFtile(factory), endRepeatLinkRendering); + final Ftile result = factory.repeat(boxStyleIn, swimlane, swimlaneOut, startLabel, decorateOut, test, yes, out, + colors, backRepeatLinkRendering, back, isLastOfTheParent()); if (killed) { return new FtileKilled(result); } diff --git a/src/net/sourceforge/plantuml/activitydiagram3/command/CommandRepeat3.java b/src/net/sourceforge/plantuml/activitydiagram3/command/CommandRepeat3.java index 1f9dfff74..929768ce3 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/command/CommandRepeat3.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/command/CommandRepeat3.java @@ -35,8 +35,10 @@ */ package net.sourceforge.plantuml.activitydiagram3.command; +import net.sourceforge.plantuml.ColorParam; import net.sourceforge.plantuml.LineLocation; import net.sourceforge.plantuml.activitydiagram3.ActivityDiagram3; +import net.sourceforge.plantuml.activitydiagram3.ftile.BoxStyle; import net.sourceforge.plantuml.command.CommandExecutionResult; import net.sourceforge.plantuml.command.SingleLineCommand2; import net.sourceforge.plantuml.command.regex.IRegex; @@ -45,8 +47,11 @@ import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexOptional; import net.sourceforge.plantuml.command.regex.RegexResult; import net.sourceforge.plantuml.cucadiagram.Display; +import net.sourceforge.plantuml.cucadiagram.Stereotype; import net.sourceforge.plantuml.graphic.HtmlColor; import net.sourceforge.plantuml.graphic.color.ColorParser; +import net.sourceforge.plantuml.graphic.color.ColorType; +import net.sourceforge.plantuml.graphic.color.Colors; public class CommandRepeat3 extends SingleLineCommand2 { @@ -56,20 +61,39 @@ public class CommandRepeat3 extends SingleLineCommand2 { static IRegex getRegexConcat() { return RegexConcat.build(CommandRepeat3.class.getName(), RegexLeaf.start(), // + new RegexLeaf("STEREO", "(\\<{2}.*\\>{2})?"), // ColorParser.exp4(), // new RegexLeaf("repeat"), // RegexLeaf.spaceZeroOrMore(), // new RegexOptional(new RegexLeaf("LABEL", ":(.*?)")), // - new RegexLeaf(";?"), // + new RegexOptional(new RegexLeaf("STYLE", CommandActivity3.ENDING_GROUP)), // + // new RegexLeaf(";?"), // RegexLeaf.end()); } + private static ColorParser color() { + return ColorParser.simpleColor(ColorType.BACK); + } + @Override protected CommandExecutionResult executeArg(ActivityDiagram3 diagram, LineLocation location, RegexResult arg) { final HtmlColor color = diagram.getSkinParam().getIHtmlColorSet().getColorIfValid(arg.get("COLOR", 0)); final Display label = Display.getWithNewlines(arg.get("LABEL", 0)); + final BoxStyle boxStyle; + final String styleString = arg.get("STYLE", 0); + if (styleString == null) { + boxStyle = BoxStyle.PLAIN; + } else { + boxStyle = BoxStyle.fromChar(styleString.charAt(0)); + } + Colors colors = color().getColor(arg, diagram.getSkinParam().getIHtmlColorSet()); + final String stereo = arg.get("STEREO", 0); + if (stereo != null) { + final Stereotype stereotype = new Stereotype(stereo); + colors = colors.applyStereotype(stereotype, diagram.getSkinParam(), ColorParam.activityBackground); + } - diagram.startRepeat(color, label); + diagram.startRepeat(color, label, boxStyle, colors); return CommandExecutionResult.ok(); } diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ftile/FtileFactory.java b/src/net/sourceforge/plantuml/activitydiagram3/ftile/FtileFactory.java index 2f38386b4..3ad653946 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/ftile/FtileFactory.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/ftile/FtileFactory.java @@ -77,9 +77,9 @@ public interface FtileFactory { public Ftile assembly(Ftile tile1, Ftile tile2); - public Ftile repeat(Swimlane swimlane, Swimlane swimlaneOut, Display startLabel, Ftile repeat, Display test, - Display yes, Display out, HtmlColor color, LinkRendering backRepeatLinkRendering, Ftile backward, - boolean noOut); + public Ftile repeat(BoxStyle boxStyleIn, Swimlane swimlane, Swimlane swimlaneOut, Display startLabel, Ftile repeat, + Display test, Display yes, Display out, Colors colors, LinkRendering backRepeatLinkRendering, + Ftile backward, boolean noOut); public Ftile createWhile(Swimlane swimlane, Ftile whileBlock, Display test, Display yes, Display out, LinkRendering afterEndwhile, HtmlColor color, Instruction specialOut); diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ftile/FtileFactoryDelegator.java b/src/net/sourceforge/plantuml/activitydiagram3/ftile/FtileFactoryDelegator.java index 04cd426d1..fce49ae03 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/ftile/FtileFactoryDelegator.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/ftile/FtileFactoryDelegator.java @@ -85,8 +85,8 @@ public class FtileFactoryDelegator implements FtileFactory { final LinkRendering linkRendering = tile.getInLinkRendering(); if (linkRendering == null) { if (SkinParam.USE_STYLES()) { - final Style style = getDefaultStyleDefinitionArrow().getMergedStyle( - skinParam().getCurrentStyleBuilder()); + final Style style = getDefaultStyleDefinitionArrow() + .getMergedStyle(skinParam().getCurrentStyleBuilder()); return Rainbow.build(style, skinParam().getIHtmlColorSet()); } else { color = Rainbow.build(skinParam()); @@ -96,8 +96,8 @@ public class FtileFactoryDelegator implements FtileFactory { } if (color.size() == 0) { if (SkinParam.USE_STYLES()) { - final Style style = getDefaultStyleDefinitionArrow().getMergedStyle( - skinParam().getCurrentStyleBuilder()); + final Style style = getDefaultStyleDefinitionArrow() + .getMergedStyle(skinParam().getCurrentStyleBuilder()); return Rainbow.build(style, skinParam().getIHtmlColorSet()); } else { color = Rainbow.build(skinParam()); @@ -179,10 +179,10 @@ public class FtileFactoryDelegator implements FtileFactory { return factory.assembly(tile1, tile2); } - public Ftile repeat(Swimlane swimlane, Swimlane swimlaneOut, Display startLabel, Ftile repeat, Display test, - Display yes, Display out, HtmlColor color, LinkRendering backRepeatLinkRendering, Ftile backward, + public Ftile repeat(BoxStyle boxStyleIn, Swimlane swimlane, Swimlane swimlaneOut, Display startLabel, Ftile repeat, + Display test, Display yes, Display out, Colors colors, LinkRendering backRepeatLinkRendering, Ftile backward, boolean noOut) { - return factory.repeat(swimlane, swimlaneOut, startLabel, repeat, test, yes, out, color, + return factory.repeat(boxStyleIn, swimlane, swimlaneOut, startLabel, repeat, test, yes, out, colors, backRepeatLinkRendering, backward, noOut); } diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileFactoryDelegatorRepeat.java b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileFactoryDelegatorRepeat.java index 94266dd75..2086d28ea 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileFactoryDelegatorRepeat.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileFactoryDelegatorRepeat.java @@ -59,6 +59,7 @@ import net.sourceforge.plantuml.cucadiagram.Display; import net.sourceforge.plantuml.graphic.FontConfiguration; import net.sourceforge.plantuml.graphic.HtmlColor; import net.sourceforge.plantuml.graphic.Rainbow; +import net.sourceforge.plantuml.graphic.color.ColorType; import net.sourceforge.plantuml.graphic.color.Colors; import net.sourceforge.plantuml.style.PName; import net.sourceforge.plantuml.style.Style; @@ -73,31 +74,36 @@ public class FtileFactoryDelegatorRepeat extends FtileFactoryDelegator { } @Override - public Ftile repeat(Swimlane swimlane, Swimlane swimlaneOut, Display startLabel, final Ftile repeat, Display test, - Display yes, Display out, HtmlColor color, LinkRendering backRepeatLinkRendering, Ftile backward, - boolean noOut) { + public Ftile repeat(BoxStyle boxStyleIn, Swimlane swimlane, Swimlane swimlaneOut, Display startLabel, + final Ftile repeat, Display test, Display yes, Display out, Colors colors, + LinkRendering backRepeatLinkRendering, Ftile backward, boolean noOut) { final ConditionStyle conditionStyle = skinParam().getConditionStyle(); final HtmlColor borderColor; - final HtmlColor backColor; + final HtmlColor diamondColor; final Rainbow arrowColor; final FontConfiguration fcDiamond; final FontConfiguration fcArrow; if (SkinParam.USE_STYLES()) { - final Style styleArrow = getDefaultStyleDefinitionArrow().getMergedStyle( - skinParam().getCurrentStyleBuilder()); - final Style styleDiamond = getDefaultStyleDefinitionDiamond().getMergedStyle( - skinParam().getCurrentStyleBuilder()); + final Style styleArrow = getDefaultStyleDefinitionArrow() + .getMergedStyle(skinParam().getCurrentStyleBuilder()); + final Style styleDiamond = getDefaultStyleDefinitionDiamond() + .getMergedStyle(skinParam().getCurrentStyleBuilder()); borderColor = styleDiamond.value(PName.LineColor).asColor(skinParam().getIHtmlColorSet()); - backColor = styleDiamond.value(PName.BackGroundColor).asColor(skinParam().getIHtmlColorSet()); + diamondColor = styleDiamond.value(PName.BackGroundColor).asColor(skinParam().getIHtmlColorSet()); arrowColor = Rainbow.build(styleArrow, skinParam().getIHtmlColorSet()); fcDiamond = styleDiamond.getFontConfiguration(skinParam().getIHtmlColorSet()); fcArrow = styleArrow.getFontConfiguration(skinParam().getIHtmlColorSet()); } else { borderColor = getRose().getHtmlColor(skinParam(), ColorParam.activityDiamondBorder); - backColor = color == null ? getRose().getHtmlColor(skinParam(), ColorParam.activityDiamondBackground) - : color; + // diamondColor = color == null ? getRose().getHtmlColor(skinParam(), + // ColorParam.activityDiamondBackground) : color; + if (colors.getColor(ColorType.BACK) != null && Display.isNull(startLabel)) { + diamondColor = colors.getColor(ColorType.BACK); + } else { + diamondColor = getRose().getHtmlColor(skinParam(), ColorParam.activityDiamondBackground); + } arrowColor = Rainbow.build(skinParam()); fcDiamond = new FontConfiguration(skinParam(), FontParam.ACTIVITY_DIAMOND, null); fcArrow = new FontConfiguration(skinParam(), FontParam.ARROW, null); @@ -106,18 +112,17 @@ public class FtileFactoryDelegatorRepeat extends FtileFactoryDelegator { final LinkRendering endRepeatLinkRendering = repeat.getOutLinkRendering(); final Rainbow endRepeatLinkColor = endRepeatLinkRendering == null ? null : endRepeatLinkRendering.getRainbow(); - final Ftile backStart = Display.isNull(startLabel) ? null : this.activity(startLabel, swimlane, BoxStyle.PLAIN, - Colors.empty()); + final Ftile entry = getEntry(swimlane, startLabel, colors, boxStyleIn); - Ftile result = FtileRepeat.create(backRepeatLinkRendering, swimlane, swimlaneOut, backStart, repeat, test, yes, - out, borderColor, backColor, arrowColor, endRepeatLinkColor, conditionStyle, this.skinParam(), - fcDiamond, fcArrow, backward, noOut); + Ftile result = FtileRepeat.create(backRepeatLinkRendering, swimlane, swimlaneOut, entry, repeat, test, yes, out, + borderColor, diamondColor, arrowColor, endRepeatLinkColor, conditionStyle, this.skinParam(), fcDiamond, + fcArrow, backward, noOut); final List weldingPoints = repeat.getWeldingPoints(); if (weldingPoints.size() > 0) { // printAllChild(repeat); - final Ftile diamondBreak = new FtileDiamond(repeat.skinParam(), backColor, borderColor, swimlane); + final Ftile diamondBreak = new FtileDiamond(repeat.skinParam(), diamondColor, borderColor, swimlane); result = assembly(FtileUtils.addHorizontalMargin(result, 10, 0), diamondBreak); final Genealogy genealogy = new Genealogy(result); @@ -129,8 +134,8 @@ public class FtileFactoryDelegatorRepeat extends FtileFactoryDelegator { final UTranslate tr2 = genealogy.getTranslate(diamondBreak, ug.getStringBounder()); final Dimension2D dimDiamond = diamondBreak.calculateDimension(ug.getStringBounder()); - final Snake snake = new Snake(getFtile1().arrowHorizontalAlignment(), arrowColor, Arrows - .asToRight()); + final Snake snake = new Snake(getFtile1().arrowHorizontalAlignment(), arrowColor, + Arrows.asToRight()); snake.addPoint(tr1.getDx(), tr1.getDy()); snake.addPoint(0, tr1.getDy()); snake.addPoint(0, tr2.getDy() + dimDiamond.getHeight() / 2); @@ -151,4 +156,12 @@ public class FtileFactoryDelegatorRepeat extends FtileFactoryDelegator { } return result; } + + private Ftile getEntry(Swimlane swimlane, Display startLabel, Colors colors, BoxStyle boxStyleIn) { + if (Display.isNull(startLabel)) { + return null; + } + // final Colors colors = Colors.empty().add(ColorType.BACK, back); + return this.activity(startLabel, swimlane, boxStyleIn, colors); + } } diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileRepeat.java b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileRepeat.java index b3becbd6d..3fe4b96fd 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileRepeat.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileRepeat.java @@ -111,8 +111,8 @@ class FtileRepeat extends AbstractFtile { } public static Ftile create(LinkRendering backRepeatLinkRendering, Swimlane swimlane, Swimlane swimlaneOut, - Ftile backStart, Ftile repeat, Display test, Display yes, Display out, HtmlColor borderColor, - HtmlColor backColor, Rainbow arrowColor, Rainbow endRepeatLinkColor, ConditionStyle conditionStyle, + Ftile entry, Ftile repeat, Display test, Display yes, Display out, HtmlColor borderColor, + HtmlColor diamondColor, Rainbow arrowColor, Rainbow endRepeatLinkColor, ConditionStyle conditionStyle, ISkinSimple spriteContainer, FontConfiguration fcDiamond, FontConfiguration fcArrow, Ftile backward, boolean noOut) { @@ -126,10 +126,10 @@ class FtileRepeat extends AbstractFtile { final Ftile diamond1; // assert swimlane == repeat.getSwimlaneIn(); - if (backStart == null) { - diamond1 = new FtileDiamond(repeat.skinParam(), backColor, borderColor, repeat.getSwimlaneIn()); + if (entry == null) { + diamond1 = new FtileDiamond(repeat.skinParam(), diamondColor, borderColor, repeat.getSwimlaneIn()); } else { - diamond1 = backStart; + diamond1 = entry; } final FtileRepeat result; if (conditionStyle == ConditionStyle.INSIDE) { @@ -137,16 +137,16 @@ class FtileRepeat extends AbstractFtile { if (noOut && Display.isNull(test)) { diamond2 = new FtileEmpty(repeat.skinParam()); } else { - diamond2 = new FtileDiamondInside(repeat.skinParam(), backColor, borderColor, swimlaneOut, tbTest) + diamond2 = new FtileDiamondInside(repeat.skinParam(), diamondColor, borderColor, swimlaneOut, tbTest) .withEast(yesTb).withSouth(outTb); } result = new FtileRepeat(repeat, diamond1, diamond2, TextBlockUtils.empty(0, 0), backward); } else if (conditionStyle == ConditionStyle.DIAMOND) { - final Ftile diamond2 = new FtileDiamond(repeat.skinParam(), backColor, borderColor, swimlane) + final Ftile diamond2 = new FtileDiamond(repeat.skinParam(), diamondColor, borderColor, swimlane) .withEast(tbTest); result = new FtileRepeat(repeat, diamond1, diamond2, tbTest, backward); } else if (conditionStyle == ConditionStyle.FOO1) { - final Ftile diamond2 = new FtileDiamondFoo1(repeat.skinParam(), backColor, borderColor, swimlane, tbTest); + final Ftile diamond2 = new FtileDiamondFoo1(repeat.skinParam(), diamondColor, borderColor, swimlane, tbTest); result = new FtileRepeat(repeat, diamond1, diamond2, TextBlockUtils.empty(0, 0), backward); } else { throw new IllegalStateException(); diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/VCompactFactory.java b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/VCompactFactory.java index a7fe6e000..3dedf46a4 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/VCompactFactory.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/VCompactFactory.java @@ -122,7 +122,8 @@ public class VCompactFactory implements FtileFactory { } public Ftile spot(Swimlane swimlane, String spot, HtmlColor color) { - // final HtmlColor color = rose.getHtmlColor(skinParam, ColorParam.activityBackground); + // final HtmlColor color = rose.getHtmlColor(skinParam, + // ColorParam.activityBackground); final UFont font = skinParam.getFont(null, false, FontParam.ACTIVITY); return new FtileCircleSpot(skinParam(), swimlane, spot, font, color); } @@ -140,8 +141,10 @@ public class VCompactFactory implements FtileFactory { } public Ftile activity(Display label, Swimlane swimlane, BoxStyle boxStyle, Colors colors) { - // final HtmlColor borderColor = rose.getHtmlColor(skinParam, ColorParam.activityBorder); - // final HtmlColor backColor = color == null ? rose.getHtmlColor(skinParam, ColorParam.activityBackground) : + // final HtmlColor borderColor = rose.getHtmlColor(skinParam, + // ColorParam.activityBorder); + // final HtmlColor backColor = color == null ? rose.getHtmlColor(skinParam, + // ColorParam.activityBackground) : // color; final UFont font = skinParam.getFont(null, false, FontParam.ACTIVITY); return FtileBox.create(colors.mute(skinParam), label, swimlane, boxStyle); @@ -159,9 +162,9 @@ public class VCompactFactory implements FtileFactory { return new FtileAssemblySimple(tile1, tile2); } - public Ftile repeat(Swimlane swimlane, Swimlane swimlaneOut, Display startLabel, Ftile repeat, Display test, - Display yes, Display out, HtmlColor color, LinkRendering backRepeatLinkRendering, Ftile backward, - boolean noOut) { + public Ftile repeat(BoxStyle boxStyleIn, Swimlane swimlane, Swimlane swimlaneOut, Display startLabel, Ftile repeat, + Display test, Display yes, Display out, Colors colors, LinkRendering backRepeatLinkRendering, + Ftile backward, boolean noOut) { return repeat; } diff --git a/src/net/sourceforge/plantuml/classdiagram/ClassDiagram.java b/src/net/sourceforge/plantuml/classdiagram/ClassDiagram.java index 4e17c1041..16c7b1257 100644 --- a/src/net/sourceforge/plantuml/classdiagram/ClassDiagram.java +++ b/src/net/sourceforge/plantuml/classdiagram/ClassDiagram.java @@ -37,6 +37,7 @@ package net.sourceforge.plantuml.classdiagram; import java.io.IOException; import java.io.OutputStream; +import java.util.Set; import net.sourceforge.plantuml.FileFormatOption; import net.sourceforge.plantuml.ISkinSimple; @@ -53,6 +54,7 @@ import net.sourceforge.plantuml.cucadiagram.ILeaf; import net.sourceforge.plantuml.cucadiagram.Ident; import net.sourceforge.plantuml.cucadiagram.LeafType; import net.sourceforge.plantuml.cucadiagram.Link; +import net.sourceforge.plantuml.cucadiagram.SuperGroup; import net.sourceforge.plantuml.graphic.TextBlock; import net.sourceforge.plantuml.graphic.USymbol; import net.sourceforge.plantuml.objectdiagram.AbstractClassOrObjectDiagram; diff --git a/src/net/sourceforge/plantuml/classdiagram/ClassDiagramFactory.java b/src/net/sourceforge/plantuml/classdiagram/ClassDiagramFactory.java index f9c87602d..068293331 100644 --- a/src/net/sourceforge/plantuml/classdiagram/ClassDiagramFactory.java +++ b/src/net/sourceforge/plantuml/classdiagram/ClassDiagramFactory.java @@ -67,12 +67,14 @@ import net.sourceforge.plantuml.command.CommandPackageEmpty; import net.sourceforge.plantuml.command.CommandPage; import net.sourceforge.plantuml.command.CommandRankDir; import net.sourceforge.plantuml.command.UmlDiagramFactory; -import net.sourceforge.plantuml.command.note.FactoryNoteCommand; -import net.sourceforge.plantuml.command.note.FactoryNoteOnEntityCommand; -import net.sourceforge.plantuml.command.note.FactoryNoteOnLinkCommand; -import net.sourceforge.plantuml.command.note.FactoryTipOnEntityCommand; +import net.sourceforge.plantuml.command.note.CommandConstraintOnLinks; +import net.sourceforge.plantuml.command.note.CommandFactoryNote; +import net.sourceforge.plantuml.command.note.CommandFactoryNoteOnEntity; +import net.sourceforge.plantuml.command.note.CommandFactoryNoteOnLink; +import net.sourceforge.plantuml.command.note.CommandFactoryTipOnEntity; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.descdiagram.command.CommandCreateElementMultilines; +import net.sourceforge.plantuml.descdiagram.command.CommandCreateElementParenthesis; import net.sourceforge.plantuml.descdiagram.command.CommandNewpage; import net.sourceforge.plantuml.descdiagram.command.CommandPackageWithUSymbol; import net.sourceforge.plantuml.objectdiagram.command.CommandCreateEntityObject; @@ -112,6 +114,7 @@ public class ClassDiagramFactory extends UmlDiagramFactory { cmds.add(new CommandCreateEntityObject()); cmds.add(new CommandAllowMixing()); + cmds.add(new CommandCreateElementParenthesis()); cmds.add(new CommandLayoutNewLine()); cmds.add(new CommandPackage()); @@ -121,7 +124,7 @@ public class ClassDiagramFactory extends UmlDiagramFactory { cmds.add(new CommandCreateElementFull2(Mode.NORMAL_KEYWORD)); cmds.add(new CommandCreateElementFull2(Mode.WITH_MIX_PREFIX)); - final FactoryNoteCommand factoryNoteCommand = new FactoryNoteCommand(); + final CommandFactoryNote factoryNoteCommand = new CommandFactoryNote(); cmds.add(factoryNoteCommand.createSingleLine()); cmds.add(new CommandNamespace()); @@ -134,12 +137,12 @@ public class ClassDiagramFactory extends UmlDiagramFactory { cmds.add(new CommandImport()); - final FactoryTipOnEntityCommand factoryTipOnEntityCommand = new FactoryTipOnEntityCommand("a", new RegexLeaf( + final CommandFactoryTipOnEntity factoryTipOnEntityCommand = new CommandFactoryTipOnEntity("a", new RegexLeaf( "ENTITY", "(" + CommandCreateClass.CODE_NO_DOTDOT + "|[%g][^%g]+[%g])::([%g][^%g]+[%g]|[^%s]+)")); cmds.add(factoryTipOnEntityCommand.createMultiLine(true)); cmds.add(factoryTipOnEntityCommand.createMultiLine(false)); - final FactoryNoteOnEntityCommand factoryNoteOnEntityCommand = new FactoryNoteOnEntityCommand("class", + final CommandFactoryNoteOnEntity factoryNoteOnEntityCommand = new CommandFactoryNoteOnEntity("class", new RegexLeaf("ENTITY", "(" + CommandCreateClass.CODE + "|[%g][^%g]+[%g])")); cmds.add(factoryNoteOnEntityCommand.createSingleLine()); cmds.add(new CommandUrl()); @@ -148,9 +151,10 @@ public class ClassDiagramFactory extends UmlDiagramFactory { cmds.add(factoryNoteOnEntityCommand.createMultiLine(false)); cmds.add(factoryNoteCommand.createMultiLine(false)); - final FactoryNoteOnLinkCommand factoryNoteOnLinkCommand = new FactoryNoteOnLinkCommand(); + final CommandFactoryNoteOnLink factoryNoteOnLinkCommand = new CommandFactoryNoteOnLink(); cmds.add(factoryNoteOnLinkCommand.createSingleLine()); cmds.add(factoryNoteOnLinkCommand.createMultiLine(false)); + cmds.add(new CommandConstraintOnLinks()); cmds.add(new CommandDiamondAssociation()); diff --git a/src/net/sourceforge/plantuml/classdiagram/command/CommandCreateClassMultilines.java b/src/net/sourceforge/plantuml/classdiagram/command/CommandCreateClassMultilines.java index e34aff45a..b6da5b900 100644 --- a/src/net/sourceforge/plantuml/classdiagram/command/CommandCreateClassMultilines.java +++ b/src/net/sourceforge/plantuml/classdiagram/command/CommandCreateClassMultilines.java @@ -247,6 +247,7 @@ public class CommandCreateClassMultilines extends CommandMultilines2 { return new BlocLines(result); } + public static BlocLines fromArray(String[] array) { + final List result = new ArrayList(); + for (String single : array) { + result.add(new StringLocated(single, null)); + } + return new BlocLines(result); + } + public static BlocLines getWithNewlines(String s) { final List result = new ArrayList(); for (String cs : BackSlash.getWithNewlines(s)) { diff --git a/src/net/sourceforge/plantuml/command/FactorySpriteCommand.java b/src/net/sourceforge/plantuml/command/CommandFactorySprite.java similarity index 94% rename from src/net/sourceforge/plantuml/command/FactorySpriteCommand.java rename to src/net/sourceforge/plantuml/command/CommandFactorySprite.java index 7c9bc6e5b..5033e9c03 100644 --- a/src/net/sourceforge/plantuml/command/FactorySpriteCommand.java +++ b/src/net/sourceforge/plantuml/command/CommandFactorySprite.java @@ -52,14 +52,14 @@ import net.sourceforge.plantuml.sprite.Sprite; import net.sourceforge.plantuml.sprite.SpriteColorBuilder4096; import net.sourceforge.plantuml.sprite.SpriteGrayLevel; -public final class FactorySpriteCommand implements SingleMultiFactoryCommand { +public final class CommandFactorySprite implements SingleMultiFactoryCommand { private IRegex getRegexConcatMultiLine() { - return RegexConcat.build(FactorySpriteCommand.class.getName() + "multi", RegexLeaf.start(), // + return RegexConcat.build(CommandFactorySprite.class.getName() + "multi", RegexLeaf.start(), // new RegexLeaf("sprite"), // RegexLeaf.spaceOneOrMore(), // new RegexLeaf("\\$?"), // - new RegexLeaf("NAME", "([\\p{L}0-9_]+)"), // + new RegexLeaf("NAME", "([-.\\p{L}0-9_]+)"), // RegexLeaf.spaceZeroOrMore(), // new RegexOptional(new RegexLeaf("DIM", "\\[(\\d+)x(\\d+)/(?:(\\d+)(z)?|(color))\\]")), // RegexLeaf.spaceZeroOrMore(), // @@ -67,11 +67,11 @@ public final class FactorySpriteCommand implements SingleMultiFactoryCommand { + + public CommandConstraintOnLinks() { + super(getRegexConcat()); + } + + private static IRegex getRegexConcat() { + return RegexConcat.build(CommandConstraintOnLinks.class.getName(), RegexLeaf.start(), // + new RegexLeaf("constraint"), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("on"), // + RegexLeaf.spaceOneOrMore(), // + new RegexLeaf("links"), // + RegexLeaf.spaceZeroOrMore(), // + color().getRegex(), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf(":"), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("NOTE", "(.*)"), RegexLeaf.end()); + } + + private static ColorParser color() { + return ColorParser.simpleColor(ColorType.BACK); + } + + @Override + protected CommandExecutionResult executeArg(CucaDiagram diagram, LineLocation location, RegexResult arg) { + final List links = diagram.getTwoLastLinks(); + if (links == null) { + return CommandExecutionResult.error("Cannot put constraint on two last links"); + } + final BlocLines note = BlocLines.getWithNewlines(arg.get("NOTE", 0)); + return diagram.constraintOnLinks(links.get(0), links.get(1), note.toDisplay()); + } + +} diff --git a/src/net/sourceforge/plantuml/command/note/FactoryNoteCommand.java b/src/net/sourceforge/plantuml/command/note/CommandFactoryNote.java similarity index 96% rename from src/net/sourceforge/plantuml/command/note/FactoryNoteCommand.java rename to src/net/sourceforge/plantuml/command/note/CommandFactoryNote.java index 1791f0f74..791a0fe5e 100644 --- a/src/net/sourceforge/plantuml/command/note/FactoryNoteCommand.java +++ b/src/net/sourceforge/plantuml/command/note/CommandFactoryNote.java @@ -57,10 +57,10 @@ import net.sourceforge.plantuml.cucadiagram.Stereotag; import net.sourceforge.plantuml.graphic.color.ColorParser; import net.sourceforge.plantuml.graphic.color.ColorType; -public final class FactoryNoteCommand implements SingleMultiFactoryCommand { +public final class CommandFactoryNote implements SingleMultiFactoryCommand { private IRegex getRegexConcatMultiLine() { - return RegexConcat.build(FactoryNoteCommand.class.getName() + "multi", RegexLeaf.start(), // + return RegexConcat.build(CommandFactoryNote.class.getName() + "multi", RegexLeaf.start(), // new RegexLeaf("note"), // RegexLeaf.spaceOneOrMore(), // new RegexLeaf("as"), // @@ -75,7 +75,7 @@ public final class FactoryNoteCommand implements SingleMultiFactoryCommand { +public final class CommandFactoryNoteActivity implements SingleMultiFactoryCommand { private IRegex getRegexConcatMultiLine() { - return RegexConcat.build(FactoryNoteActivityCommand.class.getName() + "multi", RegexLeaf.start(), // + return RegexConcat.build(CommandFactoryNoteActivity.class.getName() + "multi", RegexLeaf.start(), // new RegexLeaf("note"), // RegexLeaf.spaceOneOrMore(), // new RegexLeaf("POSITION", "(right|left|top|bottom)"), // @@ -78,7 +78,7 @@ public final class FactoryNoteActivityCommand implements SingleMultiFactoryComma } private IRegex getRegexConcatSingleLine() { - return RegexConcat.build(FactoryNoteActivityCommand.class.getName() + "single", RegexLeaf.start(), // + return RegexConcat.build(CommandFactoryNoteActivity.class.getName() + "single", RegexLeaf.start(), // new RegexLeaf("note"), // RegexLeaf.spaceOneOrMore(), // new RegexLeaf("POSITION", "(right|left|top|bottom)"), // diff --git a/src/net/sourceforge/plantuml/command/note/FactoryNoteOnEntityCommand.java b/src/net/sourceforge/plantuml/command/note/CommandFactoryNoteOnEntity.java similarity index 96% rename from src/net/sourceforge/plantuml/command/note/FactoryNoteOnEntityCommand.java rename to src/net/sourceforge/plantuml/command/note/CommandFactoryNoteOnEntity.java index 12f54bcb8..078b2d202 100644 --- a/src/net/sourceforge/plantuml/command/note/FactoryNoteOnEntityCommand.java +++ b/src/net/sourceforge/plantuml/command/note/CommandFactoryNoteOnEntity.java @@ -69,18 +69,18 @@ import net.sourceforge.plantuml.graphic.color.ColorType; import net.sourceforge.plantuml.graphic.color.Colors; import net.sourceforge.plantuml.utils.UniqueSequence; -public final class FactoryNoteOnEntityCommand implements SingleMultiFactoryCommand { +public final class CommandFactoryNoteOnEntity implements SingleMultiFactoryCommand { private final IRegex partialPattern; private final String key; - public FactoryNoteOnEntityCommand(String key, IRegex partialPattern) { + public CommandFactoryNoteOnEntity(String key, IRegex partialPattern) { this.partialPattern = partialPattern; this.key = key; } private IRegex getRegexConcatSingleLine(IRegex partialPattern) { - return RegexConcat.build(FactoryNoteOnEntityCommand.class.getName() + key + "single", RegexLeaf.start(), // + return RegexConcat.build(CommandFactoryNoteOnEntity.class.getName() + key + "single", RegexLeaf.start(), // new RegexLeaf("note"), // RegexLeaf.spaceOneOrMore(), // new RegexLeaf("POSITION", "(right|left|top|bottom)"), // @@ -109,7 +109,7 @@ public final class FactoryNoteOnEntityCommand implements SingleMultiFactoryComma private IRegex getRegexConcatMultiLine(IRegex partialPattern, final boolean withBracket) { if (withBracket) { - return RegexConcat.build(FactoryNoteOnEntityCommand.class.getName() + key + "multi" + withBracket, + return RegexConcat.build(CommandFactoryNoteOnEntity.class.getName() + key + "multi" + withBracket, RegexLeaf.start(), // new RegexLeaf("note"), // RegexLeaf.spaceOneOrMore(), // @@ -131,7 +131,7 @@ public final class FactoryNoteOnEntityCommand implements SingleMultiFactoryComma RegexLeaf.end() // ); } - return RegexConcat.build(FactoryNoteOnEntityCommand.class.getName() + key + "multi" + withBracket, + return RegexConcat.build(CommandFactoryNoteOnEntity.class.getName() + key + "multi" + withBracket, RegexLeaf.start(), // new RegexLeaf("note"), // RegexLeaf.spaceOneOrMore(), // diff --git a/src/net/sourceforge/plantuml/command/note/FactoryNoteOnLinkCommand.java b/src/net/sourceforge/plantuml/command/note/CommandFactoryNoteOnLink.java similarity index 96% rename from src/net/sourceforge/plantuml/command/note/FactoryNoteOnLinkCommand.java rename to src/net/sourceforge/plantuml/command/note/CommandFactoryNoteOnLink.java index 4023ecfe5..43e1462bf 100644 --- a/src/net/sourceforge/plantuml/command/note/FactoryNoteOnLinkCommand.java +++ b/src/net/sourceforge/plantuml/command/note/CommandFactoryNoteOnLink.java @@ -57,10 +57,10 @@ import net.sourceforge.plantuml.graphic.color.ColorParser; import net.sourceforge.plantuml.graphic.color.ColorType; import net.sourceforge.plantuml.graphic.color.Colors; -public final class FactoryNoteOnLinkCommand implements SingleMultiFactoryCommand { +public final class CommandFactoryNoteOnLink implements SingleMultiFactoryCommand { private IRegex getRegexConcatSingleLine() { - return RegexConcat.build(FactoryNoteOnLinkCommand.class.getName() + "single", RegexLeaf.start(), // + return RegexConcat.build(CommandFactoryNoteOnLink.class.getName() + "single", RegexLeaf.start(), // new RegexLeaf("note"), // RegexLeaf.spaceOneOrMore(), // new RegexLeaf("POSITION", "(right|left|top|bottom)?"), // @@ -77,7 +77,7 @@ public final class FactoryNoteOnLinkCommand implements SingleMultiFactoryCommand } private IRegex getRegexConcatMultiLine() { - return RegexConcat.build(FactoryNoteOnLinkCommand.class.getName() + "multi", RegexLeaf.start(), // + return RegexConcat.build(CommandFactoryNoteOnLink.class.getName() + "multi", RegexLeaf.start(), // new RegexLeaf("note"), // RegexLeaf.spaceOneOrMore(), // new RegexLeaf("POSITION", "(right|left|top|bottom)?"), // diff --git a/src/net/sourceforge/plantuml/command/note/FactoryTipOnEntityCommand.java b/src/net/sourceforge/plantuml/command/note/CommandFactoryTipOnEntity.java similarity index 96% rename from src/net/sourceforge/plantuml/command/note/FactoryTipOnEntityCommand.java rename to src/net/sourceforge/plantuml/command/note/CommandFactoryTipOnEntity.java index 6cbd56e22..cea206040 100644 --- a/src/net/sourceforge/plantuml/command/note/FactoryTipOnEntityCommand.java +++ b/src/net/sourceforge/plantuml/command/note/CommandFactoryTipOnEntity.java @@ -61,19 +61,19 @@ import net.sourceforge.plantuml.cucadiagram.LinkDecor; import net.sourceforge.plantuml.cucadiagram.LinkType; import net.sourceforge.plantuml.graphic.color.ColorParser; -public final class FactoryTipOnEntityCommand implements SingleMultiFactoryCommand { +public final class CommandFactoryTipOnEntity implements SingleMultiFactoryCommand { private final IRegex partialPattern; private final String key; - public FactoryTipOnEntityCommand(String key, IRegex partialPattern) { + public CommandFactoryTipOnEntity(String key, IRegex partialPattern) { this.partialPattern = partialPattern; this.key = key; } private RegexConcat getRegexConcatMultiLine(IRegex partialPattern, final boolean withBracket) { if (withBracket) { - return RegexConcat.build(FactoryTipOnEntityCommand.class.getName() + key + withBracket, RegexLeaf.start(), // + return RegexConcat.build(CommandFactoryTipOnEntity.class.getName() + key + withBracket, RegexLeaf.start(), // new RegexLeaf("note"), // RegexLeaf.spaceOneOrMore(), // new RegexLeaf("POSITION", "(right|left)"), // @@ -90,7 +90,7 @@ public final class FactoryTipOnEntityCommand implements SingleMultiFactoryComman RegexLeaf.end() // ); } - return RegexConcat.build(FactoryTipOnEntityCommand.class.getName() + key + withBracket, RegexLeaf.start(), // + return RegexConcat.build(CommandFactoryTipOnEntity.class.getName() + key + withBracket, RegexLeaf.start(), // new RegexLeaf("note"), // RegexLeaf.spaceOneOrMore(), // new RegexLeaf("POSITION", "(right|left)"), // diff --git a/src/net/sourceforge/plantuml/core/DiagramType.java b/src/net/sourceforge/plantuml/core/DiagramType.java index db4317d06..24bfeddbe 100644 --- a/src/net/sourceforge/plantuml/core/DiagramType.java +++ b/src/net/sourceforge/plantuml/core/DiagramType.java @@ -38,13 +38,16 @@ package net.sourceforge.plantuml.core; import net.sourceforge.plantuml.utils.StartUtils; public enum DiagramType { - UML, BPM, DITAA, DOT, PROJECT, JCCKIT, SALT, FLOW, CREOLE, JUNGLE, CUTE, MATH, LATEX, DEFINITION, GANTT, NW, MINDMAP, WBS, UNKNOWN; + UML, BPM, DITAA, DOT, PROJECT, JCCKIT, SALT, FLOW, CREOLE, JUNGLE, CUTE, MATH, LATEX, DEFINITION, GANTT, NW, MINDMAP, WBS, WIRE, UNKNOWN; static public DiagramType getTypeFromArobaseStart(String s) { s = s.toLowerCase(); // if (s.startsWith("@startuml2")) { // return UML2; // } + if (StartUtils.startsWithSymbolAnd("startwire", s)) { + return WIRE; + } if (StartUtils.startsWithSymbolAnd("startbpm", s)) { return BPM; } diff --git a/src/net/sourceforge/plantuml/creole/AtomImg.java b/src/net/sourceforge/plantuml/creole/AtomImg.java index 29a164dec..7f23d9df3 100644 --- a/src/net/sourceforge/plantuml/creole/AtomImg.java +++ b/src/net/sourceforge/plantuml/creole/AtomImg.java @@ -71,11 +71,13 @@ public class AtomImg extends AbstractAtom implements Atom { private final BufferedImage image; private final double scale; private final Url url; - - private AtomImg(BufferedImage image, double scale, Url url) { + private final String rawFileName; + + private AtomImg(BufferedImage image, double scale, Url url, String rawFileName) { this.image = image; this.scale = scale; this.url = url; + this.rawFileName = rawFileName; } public static Atom createQrcode(String flash, double scale) { @@ -84,7 +86,7 @@ public class AtomImg extends AbstractAtom implements Atom { if (im == null) { im = new BufferedImage(10, 10, BufferedImage.TYPE_INT_RGB); } - return new AtomImg(new UImage(im).scaleNearestNeighbor(scale).getImage(), 1, null); + return new AtomImg(new UImage(null, im).scaleNearestNeighbor(scale).getImage(), 1, null, null); } public static Atom create(String src, ImgValign valign, int vspace, double scale, Url url) { @@ -118,7 +120,7 @@ public class AtomImg extends AbstractAtom implements Atom { if (read == null) { return AtomText.create("(Cannot decode: " + f.getCanonicalPath() + ")", fc); } - return new AtomImg(FileUtils.ImageIO_read(f), scale, url); + return new AtomImg(FileUtils.ImageIO_read(f), scale, url, src); } catch (IOException e) { return AtomText.create("ERROR " + e.toString(), fc); } @@ -130,7 +132,7 @@ public class AtomImg extends AbstractAtom implements Atom { if (read == null) { return AtomText.create("(Cannot decode: " + source + ")", fc); } - return new AtomImg(read, scale, url); + return new AtomImg(read, scale, url, null); } private static Atom build(String text, final FontConfiguration fc, URL source, double scale, Url url) @@ -139,7 +141,7 @@ public class AtomImg extends AbstractAtom implements Atom { if (read == null) { return AtomText.create("(Cannot decode: " + text + ")", fc); } - return new AtomImg(read, scale, url); + return new AtomImg(read, scale, url, source.getPath()); } // Added by Alain Corbiere @@ -178,7 +180,7 @@ public class AtomImg extends AbstractAtom implements Atom { if (url != null) { ug.startUrl(url); } - ug.draw(new UImage(image).scale(scale)); + ug.draw(new UImage(rawFileName, image).scale(scale)); if (url != null) { ug.closeAction(); } diff --git a/src/net/sourceforge/plantuml/creole/AtomMath.java b/src/net/sourceforge/plantuml/creole/AtomMath.java index f386ef003..4815d8735 100644 --- a/src/net/sourceforge/plantuml/creole/AtomMath.java +++ b/src/net/sourceforge/plantuml/creole/AtomMath.java @@ -99,7 +99,7 @@ public class AtomMath extends AbstractAtom implements Atom { final SvgString svg = math.getSvg(scale, fore, back); ug.draw(new UImageSvg(svg)); } else { - final UImage image = new UImage(math.getImage(scale, fore, back), math.getFormula()); + final UImage image = new UImage(null, math.getImage(scale, fore, back), math.getFormula()); ug.draw(image); } } diff --git a/src/net/sourceforge/plantuml/creole/AtomText.java b/src/net/sourceforge/plantuml/creole/AtomText.java index e9c346d7c..2d1b61d4b 100644 --- a/src/net/sourceforge/plantuml/creole/AtomText.java +++ b/src/net/sourceforge/plantuml/creole/AtomText.java @@ -90,13 +90,12 @@ public class AtomText extends AbstractAtom implements Atom { public static Atom create(String text, FontConfiguration fontConfiguration) { return new AtomText(text, fontConfiguration, null, ZERO, ZERO); } - + // public static AtomText createHeading(String text, FontConfiguration fontConfiguration, int order) { // fontConfiguration = FOO(fontConfiguration, order); // return new AtomText(text, fontConfiguration, null, ZERO, ZERO); // } - public static Atom createUrl(Url url, FontConfiguration fontConfiguration, ISkinSimple skinSimple) { fontConfiguration = fontConfiguration.hyperlink(); final Display display = Display.getWithNewlines(url.getLabel()); @@ -113,8 +112,8 @@ public class AtomText extends AbstractAtom implements Atom { private static Atom createAtomText(final String text, Url url, FontConfiguration fontConfiguration, ISkinSimple skinSimple) { - final Pattern p = Pattern.compile(Splitter.openiconPattern + "|" + Splitter.spritePattern2 + "|" - + Splitter.imgPatternNoSrcColon); + final Pattern p = Pattern.compile( + Splitter.openiconPattern + "|" + Splitter.spritePattern2 + "|" + Splitter.imgPatternNoSrcColon); final Matcher m = p.matcher(text); final List result = new ArrayList(); while (m.find()) { @@ -176,14 +175,15 @@ public class AtomText extends AbstractAtom implements Atom { return text + " " + fontConfiguration; } - private AtomText(String text, FontConfiguration style, Url url, DelayedDouble marginLeft, DelayedDouble marginRight) { + private AtomText(String text, FontConfiguration style, Url url, DelayedDouble marginLeft, + DelayedDouble marginRight) { if (text.contains("" + BackSlash.hiddenNewLine())) { throw new IllegalArgumentException(text); } this.marginLeft = marginLeft; this.marginRight = marginRight; - this.text = StringUtils.manageTildeArobaseStart(StringUtils.manageUnicodeNotationUplus(StringUtils - .manageAmpDiese(StringUtils.showComparatorCharacters(CharHidder.unhide(text))))); + this.text = StringUtils.manageTildeArobaseStart(StringUtils.manageUnicodeNotationUplus( + StringUtils.manageAmpDiese(StringUtils.showComparatorCharacters(CharHidder.unhide(text))))); this.fontConfiguration = style; this.url = url; } @@ -234,42 +234,43 @@ public class AtomText extends AbstractAtom implements Atom { } public void drawU(UGraphic ug) { - if (ug.matchesProperty("SPECIALTXT")) { - ug.draw(this); - return; - } if (url != null) { ug.startUrl(url); } - HtmlColor textColor = fontConfiguration.getColor(); - FontConfiguration useFontConfiguration = fontConfiguration; - if (textColor instanceof HtmlColorAutomatic && ug.getParam().getBackcolor() != null) { - textColor = ((HtmlColorSimple) ug.getParam().getBackcolor()).opposite(); - useFontConfiguration = fontConfiguration.changeColor(textColor); - } - if (marginLeft != ZERO) { - ug = ug.apply(new UTranslate(marginLeft.getDouble(ug.getStringBounder()), 0)); - } + if (ug.matchesProperty("SPECIALTXT")) { + ug.draw(this); + } else { + HtmlColor textColor = fontConfiguration.getColor(); + FontConfiguration useFontConfiguration = fontConfiguration; + if (textColor instanceof HtmlColorAutomatic && ug.getParam().getBackcolor() != null) { + textColor = ((HtmlColorSimple) ug.getParam().getBackcolor()).opposite(); + useFontConfiguration = fontConfiguration.changeColor(textColor); + } + if (marginLeft != ZERO) { + ug = ug.apply(new UTranslate(marginLeft.getDouble(ug.getStringBounder()), 0)); + } - final StringTokenizer tokenizer = new StringTokenizer(text, "\t", true); + final StringTokenizer tokenizer = new StringTokenizer(text, "\t", true); - double x = 0; - // final int ypos = fontConfiguration.getSpace(); - final Dimension2D rect = ug.getStringBounder().calculateDimension(fontConfiguration.getFont(), text); - final double descent = getDescent(); - final double ypos = rect.getHeight() - descent; - if (tokenizer.hasMoreTokens()) { - final double tabSize = getTabSize(ug.getStringBounder()); - while (tokenizer.hasMoreTokens()) { - final String s = tokenizer.nextToken(); - if (s.equals("\t")) { - final double remainder = x % tabSize; - x += tabSize - remainder; - } else { - final UText utext = new UText(s, useFontConfiguration); - final Dimension2D dim = ug.getStringBounder().calculateDimension(fontConfiguration.getFont(), s); - ug.apply(new UTranslate(x, ypos)).draw(utext); - x += dim.getWidth(); + double x = 0; + // final int ypos = fontConfiguration.getSpace(); + final Dimension2D rect = ug.getStringBounder().calculateDimension(fontConfiguration.getFont(), text); + final double descent = getDescent(); + final double ypos = rect.getHeight() - descent; + if (tokenizer.hasMoreTokens()) { + final double tabSize = getTabSize(ug.getStringBounder()); + while (tokenizer.hasMoreTokens()) { + final String s = tokenizer.nextToken(); + if (s.equals("\t")) { + final double remainder = x % tabSize; + x += tabSize - remainder; + } else { + final UText utext = new UText(s, useFontConfiguration); + final Dimension2D dim = ug.getStringBounder().calculateDimension(fontConfiguration.getFont(), + s); + ug.apply(new UTranslate(x, ypos)).draw(utext); + x += dim.getWidth(); + } } } } diff --git a/src/net/sourceforge/plantuml/cucadiagram/Bodier.java b/src/net/sourceforge/plantuml/cucadiagram/Bodier.java index 911299aa0..c2e881429 100644 --- a/src/net/sourceforge/plantuml/cucadiagram/Bodier.java +++ b/src/net/sourceforge/plantuml/cucadiagram/Bodier.java @@ -107,7 +107,7 @@ public class Bodier { private boolean isMethod(String s) { if (type == LeafType.ANNOTATION || type == LeafType.ABSTRACT_CLASS || type == LeafType.CLASS || type == LeafType.INTERFACE || type == LeafType.ENUM) { - return MemberImpl.isMethod(s); + return Member.isMethod(s); } return false; } @@ -123,7 +123,7 @@ public class Bodier { if (s.length() == 0 && methodsToDisplay.size() == 0) { continue; } - final Member m = new MemberImpl(s, true, manageModifier); + final Member m = new Member(s, true, manageModifier); if (hides == null || hides.contains(m.getVisibilityModifier()) == false) { methodsToDisplay.add(m); } @@ -151,7 +151,7 @@ public class Bodier { if (s.length() == 0 && fieldsToDisplay.size() == 0) { continue; } - final Member m = new MemberImpl(s, false, manageModifier); + final Member m = new Member(s, false, manageModifier); if (hides == null || hides.contains(m.getVisibilityModifier()) == false) { fieldsToDisplay.add(m); } @@ -187,7 +187,7 @@ public class Bodier { } final List result = new ArrayList(); for (String s : rawBody) { - final Member m = new MemberImpl(s, isMethod(s), manageModifier); + final Member m = new Member(s, isMethod(s), manageModifier); if (hides.contains(m.getVisibilityModifier()) == false) { result.add(s); } diff --git a/src/net/sourceforge/plantuml/cucadiagram/BodyEnhanced.java b/src/net/sourceforge/plantuml/cucadiagram/BodyEnhanced.java index 2bdf76bfd..a1fef7abd 100644 --- a/src/net/sourceforge/plantuml/cucadiagram/BodyEnhanced.java +++ b/src/net/sourceforge/plantuml/cucadiagram/BodyEnhanced.java @@ -170,7 +170,7 @@ public class BodyEnhanced extends AbstractTextBlock implements TextBlock, WithPo align, skinParam, CreoleMode.FULL); blocks.add(bloc); } else { - final Member m = new MemberImpl(s, MemberImpl.isMethod(s), manageModifier); + final Member m = new Member(s, Member.isMethod(s), manageModifier); members.add(m); if (m.getUrl() != null) { urls.add(m.getUrl()); @@ -179,7 +179,7 @@ public class BodyEnhanced extends AbstractTextBlock implements TextBlock, WithPo } } if (inEllipse && members.size() == 0) { - members.add(new MemberImpl("", false, false)); + members.add(new Member("", false, false)); } blocks.add(decorate(stringBounder, new MethodsOrFieldsArea(members, fontParam, skinParam, align, stereotype, entity), separator, title)); diff --git a/src/net/sourceforge/plantuml/cucadiagram/CucaDiagram.java b/src/net/sourceforge/plantuml/cucadiagram/CucaDiagram.java index 0339e91b8..754c848a9 100644 --- a/src/net/sourceforge/plantuml/cucadiagram/CucaDiagram.java +++ b/src/net/sourceforge/plantuml/cucadiagram/CucaDiagram.java @@ -53,6 +53,7 @@ import net.sourceforge.plantuml.Log; import net.sourceforge.plantuml.UmlDiagram; import net.sourceforge.plantuml.UmlDiagramType; import net.sourceforge.plantuml.api.ImageDataSimple; +import net.sourceforge.plantuml.command.CommandExecutionResult; import net.sourceforge.plantuml.core.ImageData; import net.sourceforge.plantuml.creole.CreoleMode; import net.sourceforge.plantuml.cucadiagram.dot.CucaDiagramTxtMaker; @@ -69,10 +70,36 @@ import net.sourceforge.plantuml.xmlsc.StateDiagramScxmlMaker; public abstract class CucaDiagram extends UmlDiagram implements GroupHierarchy, PortionShower { + static private final boolean G1972 = false; + + // private String namespaceSeparator = "."; + // private String namespaceSeparator1 = GO1972 ? "::" : "."; + private String namespaceSeparator = null; + private boolean namespaceSeparatorHasBeenSet = false; + public final boolean V1972() { + if (getPragma().backToLegacyPackage()) { + return false; + } + if (getPragma().useNewPackage()) { + return true; + } + if (G1972) + return true; return false; } + public final boolean mergeIntricated() { + if (getNamespaceSeparator() == null) { + return false; + } + return this.V1972() && this.getUmlDiagramType() == UmlDiagramType.CLASS; + } + + public Set getAllSuperGroups() { + return entityFactory.getAllSuperGroups(); + } + private int horizontalPages = 1; private int verticalPages = 1; @@ -105,13 +132,15 @@ public abstract class CucaDiagram extends UmlDiagram implements GroupHierarchy, return this.stacks2.get(stacks2.size() - 1); } - private String namespaceSeparator = "."; - final public void setNamespaceSeparator(String namespaceSeparator) { + this.namespaceSeparatorHasBeenSet = true; this.namespaceSeparator = namespaceSeparator; } final public String getNamespaceSeparator() { + if (namespaceSeparatorHasBeenSet == false) { + return V1972() ? "::" : "."; + } return namespaceSeparator; } @@ -135,6 +164,10 @@ public abstract class CucaDiagram extends UmlDiagram implements GroupHierarchy, return false; } + final public void setLastEntity(ILeaf foo) { + this.lastEntity = foo; + } + final protected ILeaf getOrCreateLeafDefault(Ident idNewLong, Code code, LeafType type, USymbol symbol) { checkNotNull(idNewLong); if (type == null) { @@ -182,7 +215,7 @@ public abstract class CucaDiagram extends UmlDiagram implements GroupHierarchy, } final public Ident buildLeafIdent(String id) { - return getLastID().add(id, namespaceSeparator); + return getLastID().add(id, getNamespaceSeparator()); } final public Ident buildLeafIdentSpecial(String id) { @@ -196,7 +229,7 @@ public abstract class CucaDiagram extends UmlDiagram implements GroupHierarchy, } final public Ident buildFullyQualified(String id) { - return entityFactory.buildFullyQualified(getLastID(), Ident.empty().add(id, namespaceSeparator)); + return entityFactory.buildFullyQualified(getLastID(), Ident.empty().add(id, getNamespaceSeparator())); } final public Code buildCode(String s) { @@ -260,7 +293,7 @@ public abstract class CucaDiagram extends UmlDiagram implements GroupHierarchy, } gotoGroupInternalWithNamespace(ident, code, display, code, type, parent); } else if (strategy == NamespaceStrategy.SINGLE) { - final Ident newIdLong = buildLeafIdentSpecial(ident.toString(this.namespaceSeparator)); + final Ident newIdLong = buildLeafIdentSpecial(ident.toString(this.getNamespaceSeparator())); gotoGroupExternal(newIdLong, code, display, null, type, parent); stacks2.add(newIdLong); } else { @@ -363,7 +396,7 @@ public abstract class CucaDiagram extends UmlDiagram implements GroupHierarchy, return; } final boolean mutation; - if (namespaceSeparator == null) + if (getNamespaceSeparator() == null) mutation = entityFactory.getLeafVerySmart(idNewLong) != null; else mutation = entityFactory.getLeafStrict(idNewLong) != null; @@ -491,6 +524,10 @@ public abstract class CucaDiagram extends UmlDiagram implements GroupHierarchy, return entityFactory.getRootGroup(); } + public SuperGroup getRootSuperGroup() { + return entityFactory.getRootSuperGroup(); + } + public final Collection getLeafsvalues() { return entityFactory.leafs2(); } @@ -606,6 +643,8 @@ public abstract class CucaDiagram extends UmlDiagram implements GroupHierarchy, throw new UnsupportedOperationException(); } + entityFactory.buildSuperGroups(); + final CucaDiagramFileMaker maker = this.isUseJDot() ? new CucaDiagramFileMakerJDot(this, fileFormatOption.getDefaultStringBounder()) : new CucaDiagramFileMakerSvek(this); @@ -807,6 +846,21 @@ public abstract class CucaDiagram extends UmlDiagram implements GroupHierarchy, return null; } + final public List getTwoLastLinks() { + final List result = new ArrayList(); + final List links = getLinks(); + for (int i = links.size() - 1; i >= 0; i--) { + final Link link = links.get(i); + if (link.getEntity1().getLeafType() != LeafType.NOTE && link.getEntity2().getLeafType() != LeafType.NOTE) { + result.add(link); + if (result.size() == 2) { + return Collections.unmodifiableList(result); + } + } + } + return null; + } + private ILeaf lastEntity = null; final public ILeaf getLastEntity() { @@ -854,4 +908,11 @@ public abstract class CucaDiagram extends UmlDiagram implements GroupHierarchy, entityFactory.incRawLayout(); } + public CommandExecutionResult constraintOnLinks(Link link1, Link link2, Display display) { + final LinkConstraint linkConstraint = new LinkConstraint(link1, link2, display); + link1.setLinkConstraint(linkConstraint); + link2.setLinkConstraint(linkConstraint); + return CommandExecutionResult.ok(); + } + } diff --git a/src/net/sourceforge/plantuml/cucadiagram/GroupHierarchy.java b/src/net/sourceforge/plantuml/cucadiagram/GroupHierarchy.java index b951020b4..794b1c54d 100644 --- a/src/net/sourceforge/plantuml/cucadiagram/GroupHierarchy.java +++ b/src/net/sourceforge/plantuml/cucadiagram/GroupHierarchy.java @@ -36,10 +36,17 @@ package net.sourceforge.plantuml.cucadiagram; import java.util.Collection; +import java.util.Set; public interface GroupHierarchy { + public IGroup getRootGroup(); + + public SuperGroup getRootSuperGroup(); + public Collection getChildrenGroups(IGroup parent); - + + public Set getAllSuperGroups(); + public boolean isEmpty(IGroup g); } diff --git a/src/net/sourceforge/plantuml/cucadiagram/Ident.java b/src/net/sourceforge/plantuml/cucadiagram/Ident.java index 253b1591e..077b023b4 100644 --- a/src/net/sourceforge/plantuml/cucadiagram/Ident.java +++ b/src/net/sourceforge/plantuml/cucadiagram/Ident.java @@ -281,4 +281,12 @@ public class Ident implements Code { return parts.size(); } + public Ident getPrefix(int toIndex) { + return new Ident(this.parts.subList(0, toIndex)); + } + + public Ident getSuffix(int fromIndex) { + return new Ident(this.parts.subList(fromIndex, this.parts.size())); + } + } diff --git a/src/net/sourceforge/plantuml/cucadiagram/Link.java b/src/net/sourceforge/plantuml/cucadiagram/Link.java index 90185ae76..ad74b7850 100644 --- a/src/net/sourceforge/plantuml/cucadiagram/Link.java +++ b/src/net/sourceforge/plantuml/cucadiagram/Link.java @@ -115,11 +115,10 @@ public class Link extends WithLinkType implements Hideable, Removeable { public UComment commentForSvg() { if (type.looksLikeRevertedForSvg()) { - return new UComment("reverse link " + getEntity1().getCodeGetName() + " to " - + getEntity2().getCodeGetName()); + return new UComment( + "reverse link " + getEntity1().getCodeGetName() + " to " + getEntity2().getCodeGetName()); } - return new UComment("link " + getEntity1().getCodeGetName() + " to " - + getEntity2().getCodeGetName()); + return new UComment("link " + getEntity1().getCodeGetName() + " to " + getEntity2().getCodeGetName()); } public Link(IEntity cl1, IEntity cl2, LinkType type, Display label, int length, StyleBuilder styleBuilder) { @@ -196,6 +195,7 @@ public class Link extends WithLinkType implements Hideable, Removeable { result.port1 = this.port2; result.port2 = this.port1; result.url = this.url; + result.linkConstraint = this.linkConstraint; return result; } @@ -253,11 +253,11 @@ public class Link extends WithLinkType implements Hideable, Removeable { } public EntityPort getEntityPort1(Bibliotekon bibliotekon) { - return new EntityPort(bibliotekon.getShapeUid((ILeaf) cl1), port1); + return new EntityPort(bibliotekon.getNodeUid((ILeaf) cl1), port1); } public EntityPort getEntityPort2(Bibliotekon bibliotekon) { - return new EntityPort(bibliotekon.getShapeUid((ILeaf) cl2), port2); + return new EntityPort(bibliotekon.getNodeUid((ILeaf) cl2), port2); } @Override @@ -474,7 +474,8 @@ public class Link extends WithLinkType implements Hideable, Removeable { public boolean hasEntryPoint() { return (getEntity1().isGroup() == false && ((ILeaf) getEntity1()).getEntityPosition() != EntityPosition.NORMAL) - || (getEntity2().isGroup() == false && ((ILeaf) getEntity2()).getEntityPosition() != EntityPosition.NORMAL); + || (getEntity2().isGroup() == false + && ((ILeaf) getEntity2()).getEntityPosition() != EntityPosition.NORMAL); } public boolean hasTwoEntryPointsSameContainer() { @@ -570,4 +571,14 @@ public class Link extends WithLinkType implements Hideable, Removeable { return umlType; } + private LinkConstraint linkConstraint; + + public void setLinkConstraint(LinkConstraint linkConstraint) { + this.linkConstraint = linkConstraint; + } + + public final LinkConstraint getLinkConstraint() { + return linkConstraint; + } + } diff --git a/src/net/sourceforge/plantuml/cucadiagram/LinkConstraint.java b/src/net/sourceforge/plantuml/cucadiagram/LinkConstraint.java new file mode 100644 index 000000000..fc5dba195 --- /dev/null +++ b/src/net/sourceforge/plantuml/cucadiagram/LinkConstraint.java @@ -0,0 +1,106 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.cucadiagram; + +import java.awt.geom.Dimension2D; +import java.awt.geom.Point2D; + +import net.sourceforge.plantuml.FontParam; +import net.sourceforge.plantuml.ISkinParam; +import net.sourceforge.plantuml.graphic.FontConfiguration; +import net.sourceforge.plantuml.graphic.HorizontalAlignment; +import net.sourceforge.plantuml.graphic.HtmlColorUtils; +import net.sourceforge.plantuml.graphic.TextBlock; +import net.sourceforge.plantuml.ugraphic.UChangeColor; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.ULine; +import net.sourceforge.plantuml.ugraphic.UStroke; +import net.sourceforge.plantuml.ugraphic.UTranslate; + +public class LinkConstraint { + + private final Link link1; + private final Link link2; + private final Display display; + + private double x1; + private double y1; + private double x2; + private double y2; + + public LinkConstraint(Link link1, Link link2, Display display) { + this.link1 = link1; + this.link2 = link2; + this.display = display; + } + + public void setPosition(Link link, Point2D pt) { + if (link == link1) { + x1 = pt.getX(); + y1 = pt.getY(); + } else if (link == link2) { + x2 = pt.getX(); + y2 = pt.getY(); + } else { + throw new IllegalArgumentException(); + } + } + + public void drawMe(UGraphic ug, ISkinParam skinParam) { + if (x1 == 0 && y1 == 0) { + return; + } + if (x2 == 0 && y2 == 0) { + return; + } + ug = ug.apply(new UChangeColor(HtmlColorUtils.BLACK)); +// ug.apply(new UTranslate(x1, y1)).draw(new URectangle(10, 10)); +// ug.apply(new UTranslate(x2, y2)).draw(new URectangle(10, 10)); + + final ULine line = new ULine(x2 - x1, y2 - y1); + ug = ug.apply(new UStroke(3, 3, 1)); + ug.apply(new UTranslate(x1, y1)).draw(line); + + final TextBlock label = display.create(new FontConfiguration(skinParam, FontParam.ARROW, null), + HorizontalAlignment.CENTER, skinParam); + final Dimension2D dimLabel = label.calculateDimension(ug.getStringBounder()); + final double x = (x1 + x2) / 2 - dimLabel.getWidth() / 2; + final double y = (y1 + y2) / 2 - dimLabel.getHeight() / 2; + label.drawU(ug.apply(new UTranslate(x, y))); + + } + +} diff --git a/src/net/sourceforge/plantuml/cucadiagram/Member.java b/src/net/sourceforge/plantuml/cucadiagram/Member.java index 91dbcf015..427502ad9 100644 --- a/src/net/sourceforge/plantuml/cucadiagram/Member.java +++ b/src/net/sourceforge/plantuml/cucadiagram/Member.java @@ -35,20 +35,171 @@ */ package net.sourceforge.plantuml.cucadiagram; +import net.sourceforge.plantuml.Guillemet; +import net.sourceforge.plantuml.StringUtils; import net.sourceforge.plantuml.Url; +import net.sourceforge.plantuml.UrlBuilder; +import net.sourceforge.plantuml.UrlBuilder.ModeUrl; +import net.sourceforge.plantuml.command.regex.Matcher2; +import net.sourceforge.plantuml.command.regex.MyPattern; +import net.sourceforge.plantuml.command.regex.Pattern2; import net.sourceforge.plantuml.skin.VisibilityModifier; -public interface Member { +public class Member { - public Url getUrl(); + private final String display; + private final boolean staticModifier; + private final boolean abstractModifier; + private final Url url; + private final boolean hasUrl; - public String getDisplay(boolean withVisibilityChar); + private final VisibilityModifier visibilityModifier; - public boolean hasUrl(); + @Override + public String toString() { + return super.toString() + " " + display; + } - public VisibilityModifier getVisibilityModifier(); + public Member(String tmpDisplay, boolean isMethod, boolean manageModifier) { + tmpDisplay = tmpDisplay.replaceAll("(?i)\\{(method|field)\\}\\s*", ""); + if (manageModifier) { + final Pattern2 finalUrl = MyPattern.cmpile("^(.*?)(?:\\[(" + UrlBuilder.getRegexp() + ")\\])?$"); + final Matcher2 matcher = finalUrl.matcher(tmpDisplay); + if (matcher.matches() == false) { + throw new IllegalStateException(); + } + tmpDisplay = matcher.group(1); + final String urlString = matcher.group(2); + if (urlString == null) { + this.url = null; + } else { + this.url = new UrlBuilder(null, ModeUrl.STRICT).getUrl(urlString); + } + } else { + this.url = null; + } + this.hasUrl = this.url != null; + final String lower = StringUtils.goLowerCase(tmpDisplay); - public boolean isStatic(); + if (manageModifier) { + this.staticModifier = lower.contains("{static}") || lower.contains("{classifier}"); + this.abstractModifier = lower.contains("{abstract}"); + String displayClean = tmpDisplay.replaceAll("(?i)\\{(static|classifier|abstract)\\}\\s*", "").trim(); + if (displayClean.length() == 0) { + displayClean = " "; + } - public boolean isAbstract(); + if (VisibilityModifier.isVisibilityCharacter(displayClean)) { + visibilityModifier = VisibilityModifier.getVisibilityModifier(displayClean, isMethod == false); + this.display = StringUtils.trin(Guillemet.GUILLEMET.manageGuillemet(displayClean.substring(1))); + } else { + this.display = Guillemet.GUILLEMET.manageGuillemet(displayClean); + visibilityModifier = null; + } + } else { + this.staticModifier = false; + this.visibilityModifier = null; + this.abstractModifier = false; + tmpDisplay = StringUtils.trin(tmpDisplay); + this.display = tmpDisplay.length() == 0 ? " " : Guillemet.GUILLEMET.manageGuillemet(StringUtils + .trin(tmpDisplay)); + } + } + + public String getDisplay(boolean withVisibilityChar) { + if (withVisibilityChar) { + return getDisplayWithVisibilityChar(); + } + return getDisplayWithoutVisibilityChar(); + } + + private String getDisplayWithoutVisibilityChar() { + // assert display.length() == 0 || VisibilityModifier.isVisibilityCharacter(display.charAt(0)) == false; + return display; + } + + private String getDisplayWithVisibilityChar() { + if (isPrivate()) { + return "-" + display; + } + if (isPublic()) { + return "+" + display; + } + if (isPackagePrivate()) { + return "~" + display; + } + if (isProtected()) { + return "#" + display; + } + if (isIEMandatory()) { + return "*" + display; + } + return display; + } + + @Override + public boolean equals(Object obj) { + final Member other = (Member) obj; + return this.display.equals(other.display); + } + + @Override + public int hashCode() { + return display.hashCode(); + } + + public final boolean isStatic() { + return staticModifier; + } + + public final boolean isAbstract() { + return abstractModifier; + } + + private boolean isPrivate() { + return visibilityModifier == VisibilityModifier.PRIVATE_FIELD + || visibilityModifier == VisibilityModifier.PRIVATE_METHOD; + } + + private boolean isProtected() { + return visibilityModifier == VisibilityModifier.PROTECTED_FIELD + || visibilityModifier == VisibilityModifier.PROTECTED_METHOD; + } + + private boolean isPublic() { + return visibilityModifier == VisibilityModifier.PUBLIC_FIELD + || visibilityModifier == VisibilityModifier.PUBLIC_METHOD; + } + + private boolean isPackagePrivate() { + return visibilityModifier == VisibilityModifier.PACKAGE_PRIVATE_FIELD + || visibilityModifier == VisibilityModifier.PACKAGE_PRIVATE_METHOD; + } + + private boolean isIEMandatory() { + return visibilityModifier == VisibilityModifier.IE_MANDATORY; + } + + public final VisibilityModifier getVisibilityModifier() { + return visibilityModifier; + } + + public final Url getUrl() { + return url; + } + + public boolean hasUrl() { + return hasUrl; + } + + public static boolean isMethod(String s) { + // s = UrlBuilder.purgeUrl(s); + if (s.contains("{method}")) { + return true; + } + if (s.contains("{field}")) { + return false; + } + return s.contains("(") || s.contains(")"); + } } diff --git a/src/net/sourceforge/plantuml/cucadiagram/MemberImpl.java b/src/net/sourceforge/plantuml/cucadiagram/MemberImpl.java deleted file mode 100644 index 3c5b94a28..000000000 --- a/src/net/sourceforge/plantuml/cucadiagram/MemberImpl.java +++ /dev/null @@ -1,205 +0,0 @@ -/* ======================================================================== - * PlantUML : a free UML diagram generator - * ======================================================================== - * - * (C) Copyright 2009-2020, Arnaud Roques - * - * Project Info: http://plantuml.com - * - * If you like this project or if you find it useful, you can support us at: - * - * http://plantuml.com/patreon (only 1$ per month!) - * http://plantuml.com/paypal - * - * This file is part of PlantUML. - * - * PlantUML is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * PlantUML distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - * License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - * - * - * Original Author: Arnaud Roques - * - * - */ -package net.sourceforge.plantuml.cucadiagram; - -import net.sourceforge.plantuml.Guillemet; -import net.sourceforge.plantuml.StringUtils; -import net.sourceforge.plantuml.Url; -import net.sourceforge.plantuml.UrlBuilder; -import net.sourceforge.plantuml.UrlBuilder.ModeUrl; -import net.sourceforge.plantuml.command.regex.Matcher2; -import net.sourceforge.plantuml.command.regex.MyPattern; -import net.sourceforge.plantuml.command.regex.Pattern2; -import net.sourceforge.plantuml.skin.VisibilityModifier; - -public class MemberImpl implements Member { - - private final String display; - private final boolean staticModifier; - private final boolean abstractModifier; - private final Url url; - private final boolean hasUrl; - - private final VisibilityModifier visibilityModifier; - - @Override - public String toString() { - return super.toString() + " " + display; - } - - public MemberImpl(String tmpDisplay, boolean isMethod, boolean manageModifier) { - tmpDisplay = tmpDisplay.replaceAll("(?i)\\{(method|field)\\}\\s*", ""); - if (manageModifier) { - final Pattern2 finalUrl = MyPattern.cmpile("^(.*?)(?:\\[(" + UrlBuilder.getRegexp() + ")\\])?$"); - final Matcher2 matcher = finalUrl.matcher(tmpDisplay); - if (matcher.matches() == false) { - throw new IllegalStateException(); - } - tmpDisplay = matcher.group(1); - final String urlString = matcher.group(2); - if (urlString == null) { - this.url = null; - } else { - this.url = new UrlBuilder(null, ModeUrl.STRICT).getUrl(urlString); - } - } else { - this.url = null; - } - this.hasUrl = this.url != null; - final String lower = StringUtils.goLowerCase(tmpDisplay); - - if (manageModifier) { - this.staticModifier = lower.contains("{static}") || lower.contains("{classifier}"); - this.abstractModifier = lower.contains("{abstract}"); - String displayClean = tmpDisplay.replaceAll("(?i)\\{(static|classifier|abstract)\\}\\s*", "").trim(); - if (displayClean.length() == 0) { - displayClean = " "; - } - - if (VisibilityModifier.isVisibilityCharacter(displayClean)) { - visibilityModifier = VisibilityModifier.getVisibilityModifier(displayClean, isMethod == false); - this.display = StringUtils.trin(Guillemet.GUILLEMET.manageGuillemet(displayClean.substring(1))); - } else { - this.display = Guillemet.GUILLEMET.manageGuillemet(displayClean); - visibilityModifier = null; - } - } else { - this.staticModifier = false; - this.visibilityModifier = null; - this.abstractModifier = false; - tmpDisplay = StringUtils.trin(tmpDisplay); - this.display = tmpDisplay.length() == 0 ? " " : Guillemet.GUILLEMET.manageGuillemet(StringUtils - .trin(tmpDisplay)); - } - } - - public String getDisplay(boolean withVisibilityChar) { - if (withVisibilityChar) { - return getDisplayWithVisibilityChar(); - } - return getDisplayWithoutVisibilityChar(); - } - - private String getDisplayWithoutVisibilityChar() { - // assert display.length() == 0 || VisibilityModifier.isVisibilityCharacter(display.charAt(0)) == false; - return display; - } - - private String getDisplayWithVisibilityChar() { - if (isPrivate()) { - return "-" + display; - } - if (isPublic()) { - return "+" + display; - } - if (isPackagePrivate()) { - return "~" + display; - } - if (isProtected()) { - return "#" + display; - } - if (isIEMandatory()) { - return "*" + display; - } - return display; - } - - @Override - public boolean equals(Object obj) { - final MemberImpl other = (MemberImpl) obj; - return this.display.equals(other.display); - } - - @Override - public int hashCode() { - return display.hashCode(); - } - - public final boolean isStatic() { - return staticModifier; - } - - public final boolean isAbstract() { - return abstractModifier; - } - - private boolean isPrivate() { - return visibilityModifier == VisibilityModifier.PRIVATE_FIELD - || visibilityModifier == VisibilityModifier.PRIVATE_METHOD; - } - - private boolean isProtected() { - return visibilityModifier == VisibilityModifier.PROTECTED_FIELD - || visibilityModifier == VisibilityModifier.PROTECTED_METHOD; - } - - private boolean isPublic() { - return visibilityModifier == VisibilityModifier.PUBLIC_FIELD - || visibilityModifier == VisibilityModifier.PUBLIC_METHOD; - } - - private boolean isPackagePrivate() { - return visibilityModifier == VisibilityModifier.PACKAGE_PRIVATE_FIELD - || visibilityModifier == VisibilityModifier.PACKAGE_PRIVATE_METHOD; - } - - private boolean isIEMandatory() { - return visibilityModifier == VisibilityModifier.IE_MANDATORY; - } - - public final VisibilityModifier getVisibilityModifier() { - return visibilityModifier; - } - - public final Url getUrl() { - return url; - } - - public boolean hasUrl() { - return hasUrl; - } - - public static boolean isMethod(String s) { - // s = UrlBuilder.purgeUrl(s); - if (s.contains("{method}")) { - return true; - } - if (s.contains("{field}")) { - return false; - } - return s.contains("(") || s.contains(")"); - } -} diff --git a/src/net/sourceforge/plantuml/project3/Instant.java b/src/net/sourceforge/plantuml/cucadiagram/SuperGroup.java similarity index 80% rename from src/net/sourceforge/plantuml/project3/Instant.java rename to src/net/sourceforge/plantuml/cucadiagram/SuperGroup.java index 280ce5198..20e69a0c1 100644 --- a/src/net/sourceforge/plantuml/project3/Instant.java +++ b/src/net/sourceforge/plantuml/cucadiagram/SuperGroup.java @@ -33,14 +33,21 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.cucadiagram; -public interface Instant extends Value, Comparable { +import java.util.HashSet; +import java.util.Set; - public Instant increment(); +public class SuperGroup { - public Instant decrement(); + private final Set groups = new HashSet(); - public String toShortString(); + public SuperGroup(IGroup g) { + this.groups.add(g); + } + + public IGroup getFirstGroup() { + return groups.iterator().next(); + } } diff --git a/src/net/sourceforge/plantuml/cucadiagram/dot/DotData.java b/src/net/sourceforge/plantuml/cucadiagram/dot/DotData.java index 45baa7f9e..803ba1e53 100644 --- a/src/net/sourceforge/plantuml/cucadiagram/dot/DotData.java +++ b/src/net/sourceforge/plantuml/cucadiagram/dot/DotData.java @@ -75,6 +75,10 @@ final public class DotData implements PortionShower { private final ColorMapper colorMapper; private final EntityFactory entityFactory; + public EntityFactory getEntityFactory() { + return entityFactory; + } + public DotData(IGroup topParent, List links, Collection leafs, UmlDiagramType umlDiagramType, ISkinParam skinParam, GroupHierarchy groupHierarchy, PortionShower portionShower, ColorMapper colorMapper, EntityFactory entityFactory, boolean isHideEmptyDescriptionForState, DotMode dotMode, diff --git a/src/net/sourceforge/plantuml/cucadiagram/entity/EntityFactory.java b/src/net/sourceforge/plantuml/cucadiagram/entity/EntityFactory.java index 4e65ca09b..be3c760fc 100644 --- a/src/net/sourceforge/plantuml/cucadiagram/entity/EntityFactory.java +++ b/src/net/sourceforge/plantuml/cucadiagram/entity/EntityFactory.java @@ -38,13 +38,17 @@ package net.sourceforge.plantuml.cucadiagram.entity; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import net.sourceforge.plantuml.OptionFlags; +import net.sourceforge.plantuml.ColorParam; +import net.sourceforge.plantuml.ISkinParam; +import net.sourceforge.plantuml.creole.CreoleMode; import net.sourceforge.plantuml.cucadiagram.Bodier; import net.sourceforge.plantuml.cucadiagram.Code; import net.sourceforge.plantuml.cucadiagram.CucaDiagram; @@ -58,6 +62,10 @@ import net.sourceforge.plantuml.cucadiagram.ILeaf; import net.sourceforge.plantuml.cucadiagram.Ident; import net.sourceforge.plantuml.cucadiagram.LeafType; import net.sourceforge.plantuml.cucadiagram.Link; +import net.sourceforge.plantuml.cucadiagram.SuperGroup; +import net.sourceforge.plantuml.graphic.HtmlColor; +import net.sourceforge.plantuml.graphic.USymbol; +import net.sourceforge.plantuml.graphic.color.ColorType; import net.sourceforge.plantuml.skin.VisibilityModifier; public final class EntityFactory { @@ -73,14 +81,104 @@ public final class EntityFactory { private int rawLayout; private final IGroup rootGroup = new GroupRoot(this); + private final SuperGroup rootSuperGroup = new SuperGroup(rootGroup); + private final List hides2; private final List removed; /* private */ final public CucaDiagram namespaceSeparator; + // private final boolean mergeIntricated; + private Map emptyGroupsAsNode = new HashMap(); + + public ILeaf getLeafForEmptyGroup(IGroup g) { + return emptyGroupsAsNode.get(g); + } + + public SuperGroup getRootSuperGroup() { + return rootSuperGroup; + } + + private Set superGroups = null; + final Map groupToSuper = new LinkedHashMap(); + + public Set getAllSuperGroups() { + return Collections.unmodifiableSet(superGroups); + } + + public void buildSuperGroups() { + superGroups = new HashSet(); + for (IGroup g : groups2.values()) { + final SuperGroup sg = new SuperGroup(g); + superGroups.add(sg); + groupToSuper.put(g, sg); + } + } + + public ILeaf createLeafForEmptyGroup(IGroup g, ISkinParam skinParam) { + final ILeaf folder = this.createLeaf(g.getIdent(), g.getCode(), g.getDisplay(), LeafType.EMPTY_PACKAGE, + g.getParentContainer(), null, this.namespaceSeparator.getNamespaceSeparator()); + ((EntityImpl) folder).setOriginalGroup(g); + final USymbol symbol = g.getUSymbol(); + folder.setUSymbol(symbol); + folder.setStereotype(g.getStereotype()); + if (g.getUrl99() != null) { + folder.addUrl(g.getUrl99()); + } + if (g.getColors(skinParam).getColor(ColorType.BACK) == null) { + final ColorParam param = symbol == null ? ColorParam.packageBackground : symbol.getColorParamBack(); + final HtmlColor c1 = skinParam.getHtmlColor(param, g.getStereotype(), false); + folder.setSpecificColorTOBEREMOVED(ColorType.BACK, c1 == null ? skinParam.getBackgroundColor() : c1); + } else { + folder.setSpecificColorTOBEREMOVED(ColorType.BACK, g.getColors(skinParam).getColor(ColorType.BACK)); + } + emptyGroupsAsNode.put(g, folder); + return folder; + } + + public Display getIntricatedDisplay(Ident ident) { + final Set known = new HashSet(groups2.keySet()); + known.removeAll(hiddenBecauseOfIntrication); + String sep = namespaceSeparator.getNamespaceSeparator(); + if (sep == null) { + sep = "."; + } + for (int check = ident.size() - 1; check > 0; check--) { + if (known.contains(ident.getPrefix(check))) { + // if (hiddenBecauseOfIntrication.contains(ident.getPrefix(check)) == false) { + return Display.getWithNewlines(ident.getSuffix(check).toString(sep)) + .withCreoleMode(CreoleMode.SIMPLE_LINE); + } + } + return Display.getWithNewlines(ident.toString(sep)).withCreoleMode(CreoleMode.SIMPLE_LINE); + } + + private final Collection hiddenBecauseOfIntrication = new ArrayList(); + + public IGroup isIntricated(IGroup parent) { + final int leafs = parent.getLeafsDirect().size(); + final Collection children = parent.getChildren(); + if (leafs == 0 && children.size() == 1) { + final IGroup g = children.iterator().next(); + if (g.getLeafsDirect().size() == 0 && g.getChildren().size() == 0 + && g.getGroupType() == GroupType.PACKAGE) { + return null; + } + for (Link link : this.getLinks()) { + if (link.contains(parent)) { + return null; + } + } + ((EntityImpl) g).setIntricated(true); + hiddenBecauseOfIntrication.add(parent.getIdent()); + return g; + } + return null; + } public EntityFactory(List hides2, List removed, CucaDiagram namespaceSeparator) { this.hides2 = hides2; this.removed = removed; this.namespaceSeparator = namespaceSeparator; + // this.mergeIntricated = namespaceSeparator.mergeIntricated(); // if (OptionFlags.V1972(namespaceSeparator)) { // this.leafsByCode = null; @@ -400,9 +498,10 @@ public final class EntityFactory { if (result != null) { return result; } - System.err.println("getParentContainer::groups2=" + groups2); - result = createGroup(parent, parent, Display.getWithNewlines(parent.getName()), null, GroupType.PACKAGE, - null, Collections.emptySet(), namespaceSeparator.getNamespaceSeparator()); +// System.err.println("getParentContainer::groups2=" + groups2); + final Display display = Display.getWithNewlines(parent.getName()); + result = createGroup(parent, parent, display, null, GroupType.PACKAGE, null, + Collections.emptySet(), namespaceSeparator.getNamespaceSeparator()); addGroup(result); return result; } @@ -412,4 +511,5 @@ public final class EntityFactory { return parentContainer; } + } diff --git a/src/net/sourceforge/plantuml/cucadiagram/entity/EntityImpl.java b/src/net/sourceforge/plantuml/cucadiagram/entity/EntityImpl.java index 8eb85b7f1..019e5cbf7 100644 --- a/src/net/sourceforge/plantuml/cucadiagram/entity/EntityImpl.java +++ b/src/net/sourceforge/plantuml/cucadiagram/entity/EntityImpl.java @@ -45,12 +45,15 @@ import java.util.List; import java.util.Map; import java.util.Set; +import javax.swing.text.html.HTMLDocument.HTMLReader.IsindexAction; + import net.sourceforge.plantuml.FontParam; import net.sourceforge.plantuml.Guillemet; import net.sourceforge.plantuml.ISkinParam; import net.sourceforge.plantuml.OptionFlags; import net.sourceforge.plantuml.StringUtils; import net.sourceforge.plantuml.Url; +import net.sourceforge.plantuml.creole.CreoleMode; import net.sourceforge.plantuml.cucadiagram.Bodier; import net.sourceforge.plantuml.cucadiagram.Code; import net.sourceforge.plantuml.cucadiagram.Display; @@ -79,7 +82,7 @@ import net.sourceforge.plantuml.svek.SingleStrategy; import net.sourceforge.plantuml.ugraphic.UFont; import net.sourceforge.plantuml.utils.UniqueSequence; -final class EntityImpl implements ILeaf, IGroup { +final public class EntityImpl implements ILeaf, IGroup { private final EntityFactory entityFactory; @@ -232,6 +235,9 @@ final class EntityImpl implements ILeaf, IGroup { } public Display getDisplay() { + if (intricated) { + return entityFactory.getIntricatedDisplay(ident); + } return display; } @@ -261,7 +267,8 @@ final class EntityImpl implements ILeaf, IGroup { @Override public String toString() { - // return super.toString() + code + " " + display + "(" + leafType + ")[" + groupType + "] " + xposition + " " + // return super.toString() + code + " " + display + "(" + leafType + ")[" + + // groupType + "] " + xposition + " " // + getUid(); if (entityFactory.namespaceSeparator.V1972()) return getUid() + " " + ident + " " + display + "(" + leafType + ")[" + groupType + "]"; @@ -435,46 +442,51 @@ final class EntityImpl implements ILeaf, IGroup { if (dest.isGroup() == false) { throw new UnsupportedOperationException(); } - System.err.println("moveEntitiesTo1972::before1::groups2=" + entityFactory.groups2()); + // System.err.println("moveEntitiesTo1972::before1::groups2=" + + // entityFactory.groups2()); final Ident firstIdent = getIdent(); final Ident destIdent = dest.getIdent(); - System.err.println("moveEntitiesTo1972::this=" + firstIdent); - System.err.println("moveEntitiesTo1972::dest=" + destIdent); + // System.err.println("moveEntitiesTo1972::this=" + firstIdent); + // System.err.println("moveEntitiesTo1972::dest=" + destIdent); if (destIdent.startsWith(firstIdent) == false) { throw new UnsupportedOperationException(); } - System.err.println("moveEntitiesTo1972::before2::groups2=" + entityFactory.groups2()); + // System.err.println("moveEntitiesTo1972::before2::groups2=" + + // entityFactory.groups2()); for (ILeaf ent : new ArrayList(entityFactory.leafs2())) { Ident ident = ent.getIdent(); if (ident.equals(firstIdent) == false && ident.startsWith(firstIdent) && ident.startsWith(destIdent) == false) { - System.err.print("moving leaf ident1=" + ident); + // System.err.print("moving leaf ident1=" + ident); entityFactory.leafs2.remove(ident); ident = ident.move(firstIdent, destIdent); - System.err.println(" to ident2=" + ident); + // System.err.println(" to ident2=" + ident); ((EntityImpl) ent).ident = ident; ((EntityImpl) ent).code = ident; entityFactory.leafs2.put(ident, ent); } } - System.err.println("moveEntitiesTo1972::before3::groups2=" + entityFactory.groups2()); + // System.err.println("moveEntitiesTo1972::before3::groups2=" + + // entityFactory.groups2()); for (IGroup ent : new ArrayList(entityFactory.groups2())) { Ident ident = ent.getIdent(); - System.err.println("found=" + ident + " " + ident.startsWith(firstIdent) + " " - + ident.startsWith(destIdent)); + // System.err.println("found=" + ident + " " + ident.startsWith(firstIdent) + " + // " + // + ident.startsWith(destIdent)); if (ident.equals(firstIdent) == false && ident.startsWith(firstIdent) && ident.startsWith(destIdent) == false) { - System.err.print("moving gr ident1=" + ident); + // System.err.print("moving gr ident1=" + ident); entityFactory.groups2.remove(ident); ident = ident.move(firstIdent, destIdent); - System.err.println(" to ident2=" + ident); + // System.err.println(" to ident2=" + ident); ((EntityImpl) ent).ident = ident; ((EntityImpl) ent).code = ident; entityFactory.groups2.put(ident, ent); - System.err.println("-->groups2=" + entityFactory.groups2()); + // System.err.println("-->groups2=" + entityFactory.groups2()); } } - System.err.println("moveEntitiesTo1972::after::groups2=" + entityFactory.groups2()); + // System.err.println("moveEntitiesTo1972::after::groups2=" + + // entityFactory.groups2()); // for (IGroup g : dest.getChildren()) { // // ((EntityImpl) g).parentContainer = dest; // throw new IllegalStateException(); @@ -757,4 +769,21 @@ final class EntityImpl implements ILeaf, IGroup { return legend; } + private boolean intricated; + + public void setIntricated(boolean intricated) { + this.intricated = intricated; + + } + + private IGroup originalGroup; + + public void setOriginalGroup(IGroup originalGroup) { + this.originalGroup = originalGroup; + } + + public IGroup getOriginalGroup() { + return originalGroup; + } + } diff --git a/src/net/sourceforge/plantuml/descdiagram/DescriptionDiagramFactory.java b/src/net/sourceforge/plantuml/descdiagram/DescriptionDiagramFactory.java index 3fb4d72a0..098e63917 100644 --- a/src/net/sourceforge/plantuml/descdiagram/DescriptionDiagramFactory.java +++ b/src/net/sourceforge/plantuml/descdiagram/DescriptionDiagramFactory.java @@ -49,9 +49,9 @@ import net.sourceforge.plantuml.command.CommandFootboxIgnored; import net.sourceforge.plantuml.command.CommandPage; import net.sourceforge.plantuml.command.CommandRankDir; import net.sourceforge.plantuml.command.UmlDiagramFactory; -import net.sourceforge.plantuml.command.note.FactoryNoteCommand; -import net.sourceforge.plantuml.command.note.FactoryNoteOnEntityCommand; -import net.sourceforge.plantuml.command.note.FactoryNoteOnLinkCommand; +import net.sourceforge.plantuml.command.note.CommandFactoryNote; +import net.sourceforge.plantuml.command.note.CommandFactoryNoteOnEntity; +import net.sourceforge.plantuml.command.note.CommandFactoryNoteOnLink; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexOr; import net.sourceforge.plantuml.descdiagram.command.CommandArchimate; @@ -92,10 +92,10 @@ public class DescriptionDiagramFactory extends UmlDiagramFactory { // cmds.add(new CommandPackageWithUSymbol()); cmds.add(new CommandEndPackage()); - final FactoryNoteCommand factoryNoteCommand = new FactoryNoteCommand(); + final CommandFactoryNote factoryNoteCommand = new CommandFactoryNote(); cmds.add(factoryNoteCommand.createMultiLine(false)); - final FactoryNoteOnEntityCommand factoryNoteOnEntityCommand = new FactoryNoteOnEntityCommand("desc", + final CommandFactoryNoteOnEntity factoryNoteOnEntityCommand = new CommandFactoryNoteOnEntity("desc", new RegexOr("ENTITY", // new RegexLeaf("[\\p{L}0-9_.]+"), // new RegexLeaf("\\(\\)[%s]*[\\p{L}0-9_.]+"), // @@ -117,7 +117,7 @@ public class DescriptionDiagramFactory extends UmlDiagramFactory { cmds.add(factoryNoteOnEntityCommand.createMultiLine(false)); cmds.add(factoryNoteCommand.createMultiLine(false)); - final FactoryNoteOnLinkCommand factoryNoteOnLinkCommand = new FactoryNoteOnLinkCommand(); + final CommandFactoryNoteOnLink factoryNoteOnLinkCommand = new CommandFactoryNoteOnLink(); cmds.add(factoryNoteOnLinkCommand.createSingleLine()); cmds.add(factoryNoteOnLinkCommand.createMultiLine(false)); diff --git a/src/net/sourceforge/plantuml/descdiagram/command/CommandCreateElementParenthesis.java b/src/net/sourceforge/plantuml/descdiagram/command/CommandCreateElementParenthesis.java new file mode 100644 index 000000000..ba251cd1f --- /dev/null +++ b/src/net/sourceforge/plantuml/descdiagram/command/CommandCreateElementParenthesis.java @@ -0,0 +1,242 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.descdiagram.command; + +import net.sourceforge.plantuml.FontParam; +import net.sourceforge.plantuml.LineLocation; +import net.sourceforge.plantuml.OptionFlags; +import net.sourceforge.plantuml.StringUtils; +import net.sourceforge.plantuml.Url; +import net.sourceforge.plantuml.UrlBuilder; +import net.sourceforge.plantuml.UrlBuilder.ModeUrl; +import net.sourceforge.plantuml.classdiagram.AbstractEntityDiagram; +import net.sourceforge.plantuml.classdiagram.ClassDiagram; +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.command.SingleLineCommand2; +import net.sourceforge.plantuml.command.regex.IRegex; +import net.sourceforge.plantuml.command.regex.RegexConcat; +import net.sourceforge.plantuml.command.regex.RegexLeaf; +import net.sourceforge.plantuml.command.regex.RegexOptional; +import net.sourceforge.plantuml.command.regex.RegexOr; +import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.cucadiagram.Code; +import net.sourceforge.plantuml.cucadiagram.Display; +import net.sourceforge.plantuml.cucadiagram.IEntity; +import net.sourceforge.plantuml.cucadiagram.ILeaf; +import net.sourceforge.plantuml.cucadiagram.Ident; +import net.sourceforge.plantuml.cucadiagram.LeafType; +import net.sourceforge.plantuml.cucadiagram.Stereotype; +import net.sourceforge.plantuml.descdiagram.DescriptionDiagram; +import net.sourceforge.plantuml.graphic.HtmlColor; +import net.sourceforge.plantuml.graphic.USymbol; +import net.sourceforge.plantuml.graphic.color.ColorParser; +import net.sourceforge.plantuml.graphic.color.ColorType; +import net.sourceforge.plantuml.graphic.color.Colors; + +public class CommandCreateElementParenthesis extends SingleLineCommand2 { + + public CommandCreateElementParenthesis() { + super(getRegexConcat()); + } + + private static IRegex getRegexConcat() { + return RegexConcat.build(CommandCreateElementParenthesis.class.getName(), RegexLeaf.start(), // + new RegexLeaf("\\(\\)[%s]+"), // + color2().getRegex(), // + RegexLeaf.spaceZeroOrMore(), // + new RegexOr(// + new RegexLeaf("CODE1", CommandCreateElementFull.CODE_WITH_QUOTE), // + new RegexConcat(// + new RegexLeaf("DISPLAY2", CommandCreateElementFull.DISPLAY), // + new RegexOptional( // + new RegexConcat( // + RegexLeaf.spaceOneOrMore(), // + new RegexLeaf("STEREOTYPE2", "(\\<\\<.+\\>\\>)")// + )), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("as"), // + RegexLeaf.spaceOneOrMore(), // + new RegexLeaf("CODE2", CommandCreateElementFull.CODE)), // + new RegexConcat(// + new RegexLeaf("CODE3", CommandCreateElementFull.CODE), // + new RegexOptional( // + new RegexConcat( // + RegexLeaf.spaceOneOrMore(), // + new RegexLeaf("STEREOTYPE3", "(\\<\\<.+\\>\\>)") // + )), // + RegexLeaf.spaceOneOrMore(), // + new RegexLeaf("as"), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("DISPLAY3", CommandCreateElementFull.DISPLAY)), // + new RegexConcat(// + new RegexLeaf("DISPLAY4", CommandCreateElementFull.DISPLAY_WITHOUT_QUOTE), // + new RegexOptional( // + new RegexConcat( // + RegexLeaf.spaceOneOrMore(), // + new RegexLeaf("STEREOTYPE4", "(\\<\\<.+\\>\\>)") // + )), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("as"), // + RegexLeaf.spaceOneOrMore(), // + new RegexLeaf("CODE4", CommandCreateElementFull.CODE)) // + ), // + new RegexOptional( // + new RegexConcat( // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("STEREOTYPE", "(\\<\\<.+\\>\\>)") // + )), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("URL", "(" + UrlBuilder.getRegexp() + ")?"), // + RegexLeaf.spaceZeroOrMore(), // + color().getRegex(), RegexLeaf.end()); + } + + private static ColorParser color() { + return ColorParser.simpleColor(ColorType.BACK); + } + + private static ColorParser color2() { + return ColorParser.simpleColor(ColorType.BACK, "COLOR2"); + } + +// private static final String CODE_CORE = "[\\p{L}0-9_.]+|\\(\\)[%s]*[\\p{L}0-9_.]+|\\(\\)[%s]*[%g][^%g]+[%g]|:[^:]+:|\\([^()]+\\)|\\[[^\\[\\]]+\\]"; +// public static final String CODE = "(" + CODE_CORE + ")"; +// public static final String CODE_WITH_QUOTE = "(" + CODE_CORE + "|[%g].+?[%g])"; +// +// private static final String DISPLAY_CORE = "[%g].+?[%g]|:[^:]+:|\\([^()]+\\)|\\[[^\\[\\]]+\\]"; +// public static final String DISPLAY = "(" + DISPLAY_CORE + ")"; +// public static final String DISPLAY_WITHOUT_QUOTE = "(" + DISPLAY_CORE + "|[\\p{L}0-9_.]+)"; + + @Override + final protected boolean isForbidden(CharSequence line) { + if (line.toString().matches("^[\\p{L}0-9_.]+$")) { + return true; + } + return false; + } + + @Override + protected CommandExecutionResult executeArg(ClassDiagram diagram, LineLocation location, RegexResult arg) { + String codeRaw = arg.getLazzy("CODE", 0); + final String displayRaw = arg.getLazzy("DISPLAY", 0); + final String symbol = "interface"; + final LeafType type; + final USymbol usymbol; + + type = LeafType.DESCRIPTION; + usymbol = USymbol.getFromString(symbol, diagram.getSkinParam()); + + final String idShort = StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(codeRaw); + final Ident ident = diagram.buildLeafIdent(idShort); + final Code code = diagram.V1972() ? ident : diagram.buildCode(idShort); + if (!diagram.V1972() && diagram.isGroup(code)) { + return CommandExecutionResult.error("This element (" + code.getName() + ") is already defined"); + } + if (diagram.V1972() && diagram.isGroupStrict(ident)) { + return CommandExecutionResult.error("This element (" + ident.getName() + ") is already defined"); + } + String display = displayRaw; + if (display == null) { + display = code.getName(); + } + display = StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(display); + final String stereotype = arg.getLazzy("STEREOTYPE", 0); + if (existsWithBadType3(diagram, code, ident, type, usymbol)) { + return CommandExecutionResult.error("This element (" + code.getName() + ") is already defined"); + } + final IEntity entity = diagram.getOrCreateLeaf(ident, code, type, usymbol); + entity.setDisplay(Display.getWithNewlines(display)); + entity.setUSymbol(usymbol); + if (stereotype != null) { + entity.setStereotype(new Stereotype(stereotype, diagram.getSkinParam().getCircledCharacterRadius(), + diagram.getSkinParam().getFont(null, false, FontParam.CIRCLED_CHARACTER), + diagram.getSkinParam().getIHtmlColorSet())); + } + + final String urlString = arg.get("URL", 0); + if (urlString != null) { + final UrlBuilder urlBuilder = new UrlBuilder(diagram.getSkinParam().getValue("topurl"), ModeUrl.STRICT); + final Url url = urlBuilder.getUrl(urlString); + entity.addUrl(url); + } + + Colors colors = color().getColor(arg, diagram.getSkinParam().getIHtmlColorSet()); + + final HtmlColor lineColor = diagram.getSkinParam().getIHtmlColorSet().getColorIfValid(arg.get("LINECOLOR", 1)); + if (lineColor != null) { + colors = colors.add(ColorType.LINE, lineColor); + } + entity.setColors(colors); + + // entity.setSpecificColorTOBEREMOVED(ColorType.BACK, + // diagram.getSkinParam().getIHtmlColorSet().getColorIfValid(arg.get("COLOR", + // 0))); + return CommandExecutionResult.ok(); + } + + public static boolean existsWithBadType3(AbstractEntityDiagram diagram, Code code, Ident ident, LeafType type, + USymbol usymbol) { + if (diagram.V1972()) { + if (diagram.leafExistSmart(ident) == false) { + return false; + } + final ILeaf other = diagram.getLeafSmart(ident); + if (other.getLeafType() != type) { + return true; + } + if (usymbol != null && other.getUSymbol() != usymbol) { + return true; + } + return false; + } else { + if (diagram.leafExist(code) == false) { + return false; + } + final ILeaf other = diagram.getLeaf(code); + if (other.getLeafType() != type) { + return true; + } + if (usymbol != null && other.getUSymbol() != usymbol) { + return true; + } + return false; + } + } + + private char getCharEncoding(final String codeRaw) { + return codeRaw != null && codeRaw.length() > 2 ? codeRaw.charAt(0) : 0; + } +} diff --git a/src/net/sourceforge/plantuml/donors/PSystemDonors.java b/src/net/sourceforge/plantuml/donors/PSystemDonors.java index 15e8628b5..36f2fb985 100644 --- a/src/net/sourceforge/plantuml/donors/PSystemDonors.java +++ b/src/net/sourceforge/plantuml/donors/PSystemDonors.java @@ -71,24 +71,24 @@ public class PSystemDonors extends AbstractPSystem { private static final int COLS = 6; private static final int FREE_LINES = 6; - public static final String DONORS = "6_C902mFU3XMJbc44wzsvvsjcZxOY0eHBCyJYiF08fxk1iGVuDxfSR-H_YAwqhrlcX5jsPhYFACe5WGz" - + "tYRN3DlSsmEncfYlaZlpHhymBmn9Q4C2N8Sx8ZvLXfGWbehklqpSdcuT5-9WXmgX75BSio7JYHWNmTFc" - + "zIrbijRaGSBf_cywBUuU2c6MPYkSZqQe_GEd6AjhBdS_Yheqwk8kLQrkXHhJgOjZk2eqogi7lhPGCYey" - + "DCvtG8jPCTb3f4JhnX6YHcU6aPgqpiaJUMh_KI-WJUToJOcS2UKnIYIwRYkTsNVG_OBabn0AkM2Bm08g" - + "7BuJj7Ljn4X2CcWOwibeRBbconCt377enBxyer7KkATaUXhQ965Ne2JgQnoGz4eZMiJiz6P09SzeCQD9" - + "KbVcJNXy7PQcQ1qqt0iMOPQq2Qi9v4te2P_mLPTCpl5ILF2cfoIFPflGKDasuDxCwDjSInBbVxSnS-Qx" - + "HxLvIcUhgut_sHnorvHLosz66-qSmRs_BQHWSR50VW2zD2SgoPzbtrX8GhYtqWiPdFklNAC8d3qo5HR_" - + "4LjQe__MbMniHIoF6mjyN5zNcfB1bbo5N8Q-fbNABPqlb9IcnkSXZvQEpoJMbCpgdQUFKJAtyl-xOILc" - + "Li90LwQORRfUK3HMiPgUR4m4fq7tXjm4o0ke3fDRULWznA_p0Pct9ICHkGt9AEJhB-MGYnGciAO7Iim0" - + "5ayfxI69U212JJlGsr1fHTeYzDjDUjgMZ8Nxf3yyxfePepoYaneduO-5mE669JLlfhkqxz4JU8ulpwlk" - + "8tMi0bpBlJTSfFeP3AmhBHY1r1tHsFUoIyAXWH9Px2Ll3V4zmneN3ps-u4mM7M96c-EGvQ5oEncjz1R3" - + "koP3tocJpTkhlyWRIBm8wo4T6OtW_M7oI2qkaOHqi1m_Mm1Yvk8LkrBWcaBLBJidc-iKfhglFeHAyEDy" - + "0gFoBJp3MElkHN46DCgS4_DUMVFHU0qfFXPGFOS8MjA9CaTAKQQjPMJCMeEUWzR1zbFT5lJR-5R3gaBn" - + "RH7TiTW0Q7t6DAFtS0Cy4Ifg5Rpaf330Nxz-JG_6EiJujPVDY8DaSqaCeGAQqtznMfflnz0IrblqVzks" - + "lQsSF_zUHtPm6esxhog8deB0_rsKd8EchlEf-c_WWoJYW9MOjN4IAo-DtWWa9JYE3rPHJqqpwdToHhaj" - + "jUYTnuSg_NQgn84vDoo_QAKeXoznohQtXbEbP3_-nk8aXuP_YYfhChagfJKnefhOsL6Sfx7lKOgxhbf1" - + "17FW4e6zN_zqckOXO_QBbJaC1qD-FY9T3k6kXRMOriPfWVtYhEyjRLqouN_92ByKQzhEwc6wSVnRsWNA" - + "lXr9mdWKi7PAd2Ua1lyb0m00"; + public static final String DONORS = "6qOA02mFU3XMJbc44wzsfuUeUc2VR6qyRpkVqESmi8ZJNK3y1jWxFUutqbz4LxhtJJEYBLjJd6SKnOAW" + + "nzlacc6RUtiWLXFpLN9dtkWNveKX2Mr8WEjmHyIdof0IVEycQbqbNzfRkOJbCk0By7OGIqNtNoPkJxUE" + + "2t6mGuLG3YdksVytfxRkNbM58LrMhTFH5Ih0gi0ZOdS_QdDfrCPtKvlUX09qAd45DrMLy7hZfYBDuAxZ" + + "N3gqw1GZpI8bNZUE43SwC_JKfF1ByaH6vZ_g1RJfNAufaJEXF4Q9HDTjVqVs7PG_BNb1H48ks2ImW4gE" + + "m0cANXinFY8oQEZgIMDihcRC4oyCAUZ4lloZKTIufsHw6bfyH5s1ahYlSG3Iatgqu6nXDA2i9rkCQ9Ag" + + "C_CbtByEorDwpJJS3nPHbhG9hYd8cz0JFk6hBfcSuwMeuIy_JVB8rmGQBbi6t9iEVOjhaqIvdMsQkVDf" + + "KssUqjdgQkD_DeVSDMNLyfjHH2D7SEzl2obON5e0FmAzD2SgoPzb7rd8Xd1jfHVITQvUkHeHBjcGgM9T" + + "_eWjh-d_wE9ocn7Bus2HpvwlCqt9G4jTYLo6lj3AvhRE5qfAK-FpoAEbupFXcgpPlUFqFihcDF-_RYip" + + "un80dPbY5dJze1YifjNmP0CHc1QwFUGcG5v0TPZSoiFg4R_E1mHlAYCHXGrAB-Hzi-MGYnGciBmxIdG0" + + "9ayfxU4Zve48HUs2daQLUgGiGh_TfATjsPYuJ_fWVzPW3FAOpjOu2Nyi18umpAf5ixvR-m8z1LUvNEPL" + + "Ty_Fgm3M5juBBbBz90DwfGKZ8hL6DFQzx99mQA0mYxFahI6-PrXZvQ7x1vpMeatCQ3CVCWsI6ybgfRSO" + + "tZKP_kOXgzcnMkGvi4V4PaWpenMyFveyKejBV4Hqi9mWMm0Ivk8LU_72dIjLkPoSRAvJcEgnMWiLyhla" + + "4rYgmCBJWxNo7i0piaUnSpZlbJKVZTUGuda1bNAOe2wTA7Ea56NQMY33rghrRBGEjf_gM31lurivAmw5" + + "jqrqrhX1mHGsdHAuqOYHA2SQ5NhPay80V_twbNfoKmSPl_QooJYriY6MGgMSByiNfw3nTWoj-rlqVzks" + + "lQsSF_zUDvkSUkFjAmNGSv0S_nxAhAEBajNzDFWRR9WCSC1AAjeuuSf3Isy5aXRinpk3gFFjZEQTd2ot" + + "f1QzSlvGsT_zoIm7LtF3YejwYdBu4gTiUsi45M_x_ZS6MpaC_4LKcPFXwgzUBICAnFOsuZoDVOzIt5cL" + + "11BCZii4pdxrqscQXupPHoYp7Yu2-Vc8T3c4XnRKqhGuJWHMnHdUUwTroOJ_9JU9kEgdh2tLGq_ZL6vg" + + "5sZuTYMA6qQ1uI9cny3uTfEJ5RZvfeTwgBOVwVGN4oSkAeRTtdDs0W00"; /* * Special thanks to our sponsors and donors: @@ -110,8 +110,8 @@ public class PSystemDonors extends AbstractPSystem { final List cols = getCols(getDonors(), COLS, FREE_LINES); return new UDrawable() { public void drawU(UGraphic ug) { - final TextBlockBackcolored header = GraphicStrings.createBlackOnWhite(Arrays - .asList("Special thanks to our sponsors and donors !")); + final TextBlockBackcolored header = GraphicStrings + .createBlackOnWhite(Arrays.asList("Special thanks to our sponsors and donors !")); header.drawU(ug); final StringBounder stringBounder = ug.getStringBounder(); ug = ug.apply(new UTranslate(0, header.calculateDimension(stringBounder).getHeight())); @@ -143,7 +143,8 @@ public class PSystemDonors extends AbstractPSystem { private List getDonors() throws IOException { final List lines = new ArrayList(); - final Transcoder t = new TranscoderImpl(new AsciiEncoder(), new StringCompressorNone(), new CompressionBrotli()); + final Transcoder t = new TranscoderImpl(new AsciiEncoder(), new StringCompressorNone(), + new CompressionBrotli()); final String s = t.decode(DONORS).replace('*', '.'); final StringTokenizer st = new StringTokenizer(s, BackSlash.NEWLINE); while (st.hasMoreTokens()) { diff --git a/src/net/sourceforge/plantuml/graphic/QuoteUtils.java b/src/net/sourceforge/plantuml/graphic/QuoteUtils.java index c70d29477..1e39528fd 100644 --- a/src/net/sourceforge/plantuml/graphic/QuoteUtils.java +++ b/src/net/sourceforge/plantuml/graphic/QuoteUtils.java @@ -42,298 +42,209 @@ import java.util.List; public class QuoteUtils { - static private final List quotes = Arrays - .asList("Ur'f qrnq, Wvz.", - "Ol Tenogune'f unzzre, ol gur fbaf bs Jbeina, lbh funyy or niratrq.", - "Ebnqf? Jurer jr'er tbvat, jr qba'g arrq ebnqf.", - "Gur gvzr vf bhg bs wbvag.", - "P'rfg phevrhk purm yrf znevaf pr orfbva qr snver qrf cuenfrf.", - "V'z gnyxvat nobhg gur bgure Crgre, gur bar ba gur bgure fvqr.", - "Znl gur Sbepr or jvgu lbh!", - "Arire tvir hc, arire fheeraqre...", - "Unfgn yn ivfgn, onol.", - "Url, Qbp, jr orggre onpx hc. Jr qba'g unir rabhtu ebnq gb trg hc gb 88.", - "Terrgvatf, Cebsrffbe Snyxra. Funyy jr cynl n tnzr?", - "V pna'g punatr gur ynj bs culfvpf!", - "N fgenatr tnzr. Gur bayl jvaavat zbir vf abg gb cynl.", - "V'z gur Tngrxrrcre, ner lbh gur Xrlznfgre?", - "V nz gur Znfgre Pbageby Cebtenz. Ab bar Hfre jebgr zr.", - "Yvsr? Qba'g gnyx gb zr nobhg yvsr.", - "V nyjnlf gubhtug fbzrguvat jnf shaqnzragnyyl jebat jvgu gur havirefr.", - "N ebobg znl abg vawher n uhzna orvat be, guebhtu vanpgvba, nyybj n uhzna orvat gb pbzr gb unez.", - "Fheeraqre znl or bhe bayl bcgvba.", - "Fvk ol avar. Sbegl gjb.", - "Vg'f yvsr, Wvz, ohg abg nf jr xabj vg.", - "Qba'g Cnavp!", - "Jung qb lbh zrna? Na Nsevpna be Rhebcrna fjnyybj?", - "V arrq lbhe obbgf lbhe pybgurf naq lbhe zbgbeplpyr", - "Lbh sbetbg gb fnl cyrnfr...", - "Lbh unir qvrq bs qlfragrel.", - "Jbhyqa'g lbh cersre n avpr tnzr bs purff?", - "Jura lbh unir ryvzvangrq gur vzcbffvoyr, jungrire erznvaf, ubjrire vzcebonoyr, zhfg or gur gehgu.", - "V xabj abj jul lbh pel. Ohg vg'f fbzrguvat V pna arire qb.", - "Erfvfgnapr vf shgvyr. Lbh jvyy or nffvzvyngrq.", - "Nalguvat qvssrerag vf tbbq.", - "Penpxrq ol Nyqb Erfrg naq Ynherag Ehrvy.", - "V'z obgu. V'z n pryroevgl va na rzretrapl.", - "Qb lbh xabj guvf terng terng cbyvfu npgbe, Wbfrcu Ghen?", - "Gb vasvavgl naq orlbaq!", - "Fcnpr: gur svany sebagvre...", - "Fhe zba ovyyrg, grarm, l n rpevg Fnvag-Ynmner, p'rfg zrf lrhk bh dhbv ?", - "Gur obl vf vzcbegnag. Ur unf gb yvir.", - "Bapr hcba n gvzr va n tnynkl sne, sne njnl...", - "Naq lbh xabj gurer'f n ybat ybat jnl nurnq bs lbh...", - "Na nyyretl gb bkltra? Ryz oyvtug?", - "Ohg nybef lbh ner Serapu!", - "A'nv-wr qbap gnag irph dhr cbhe prggr vasnzvr?", - "Fbzrguvat vf ebggra va gur Fgngr bs Qraznex.", - "Url, jung qb lbh jnag? Zvenpyrf?", - "1.21 tvtnjnggf! 1.21 tvtnjnggf. Terng Fpbgg! ", - "Jung gur uryy vf n tvtnjngg?", - "V arrq n inpngvba.", - "Ba qrienvg wnznvf dhvggre Zbagnhona.", - "Zl sbepr vf n cyngsbez gung lbh pna pyvzo ba...", - "Gurer'f fbzrguvat jrveq, naq vg qba'g ybbx tbbq...", - "Rg evra ienvzrag ar punatr znvf gbhg rfg qvssrerag", - "Ornz zr hc, Fpbggl.", - "Gurer vf ab fcbba.", - "Sbyybj gur juvgr enoovg.", - "Arire fraq n uhzna gb qb n znpuvar'f wbo.", - "Theh zrqvgngvba. Cerff yrsg zbhfr ohggba gb pbagvahr.", - "V qba'g guvax jr'er va Xnafnf nalzber.", - "Yhxr, V nz lbhe sngure.", - "Oybbq, Fjrng naq Grnef", - "Ubhfgba, jr unir n ceboyrz.", - "Xrlobneq snvyher, cerff nal xrl gb pbagvahr", - "Ovt zvfgnxr!", - "Ubj znal HZY qrfvtaref qbrf vg gnxr gb punatr n yvtugohyo ?", - "Qb lbh yvxr zbivrf nobhg tynqvngbef ?", - "Gur fcvevg bs yrneavat vf n ynfgvat sebagvre.", - "Vg vf phevbhf sbe fnvybef guvf arrq sbe znxvat fragraprf.", - "Ubcvat sbe gur orfg, ohg rkcrpgvat gur jbefg", - "Gur jvyy gb tb ba jura V'z uheg qrrc vafvqr.", - "Vs vg oyrrqf, jr pna xvyy vg.", - "Ubhfgba, V unir n onq srryvat nobhg guvf zvffvba.", - "Znzn nyjnlf fnvq yvsr jnf yvxr n obk bs pubpbyngrf. Lbh arire xabj jung lbh'er tbaan trg.", - "Ol gur jnl, vf gurer nalbar ba obneq jub xabjf ubj gb syl n cynar?", - "Qnir, guvf pbairefngvba pna freir ab checbfr nalzber. Tbbqolr.", - "Vg pna bayl or nggevohgnoyr gb uhzna reebe.", - "Ybbxf yvxr V cvpxrq gur jebat jrrx gb dhvg fzbxvat.", - "Lbh uhznaf npg fb fgenatr. Rirelguvat lbh perngr vf hfrq gb qrfgebl.", - "Jurer qvq lbh yrnea ubj gb artbgvngr yvxr gung?", - "Fve, ner lbh pynffvsvrq nf uhzna?", - "Jr'er abg tbaan znxr vg, ner jr?", - "Vg'f va lbhe angher gb qrfgebl lbhefryirf.", - "Gur zber pbagnpg V unir jvgu uhznaf, gur zber V yrnea.", - "Jbhyq vg fnir lbh n ybg bs gvzr vs V whfg tnir hc naq jrag znq abj?", - "Ernyvgl vf serdhragyl vanpphengr.", - "Qba'g oryvrir nalguvat lbh ernq ba gur arg. Rkprcg guvf. Jryy, vapyhqvat guvf, V fhccbfr.", - "N phc bs grn jbhyq erfgber zl abeznyvgl.", - "Nalguvat gung guvaxf ybtvpnyyl pna or sbbyrq ol fbzrguvat ryfr gung guvaxf ng yrnfg nf ybtvpnyyl nf vg qbrf.", - "Va na vasvavgr Havirefr nalguvat pna unccra.", - "Fbzrgvzrf vs lbh erprvirq na nafjre, gur dhrfgvba zvtug or gnxra njnl.", - "Cyrnfr pnyy zr Rqqvr vs vg jvyy uryc lbh gb erynk.", - "V qba'g oryvrir vg. Cebir vg gb zr naq V fgvyy jba'g oryvrir vg.", - "Gbgnyyl znq, hggre abafrafr. Ohg jr'yy qb vg orpnhfr vg'f oevyyvnag abafrafr.", - "Guvf fragrapr vf abg gehr.", - "V jbhyq engure qvr fgnaqvat guna yvir ba zl xarrf.", - "Lbh ner orvat jngpurq.", - "Qvq lbh srrq gurz nsgre zvqavtug?", - "Ubj qb lbh rkcynva fpubby gb uvture vagryyvtrapr?", - "Crbcyr fbzrgvzrf znxr zvfgnxrf.", - "Ybbx, V qba'g unir gvzr sbe n pbairefngvba evtug abj.", - "Nyy ceboyrzf va pbzchgre fpvrapr pna or fbyirq ol nabgure yriry bs vaqverpgvba", - "...rkprcg sbe gur ceboyrz bs gbb znal yriryf bs vaqverpgvba", - "V xabj orpnhfr V ohvyg vg", - "Rira gur fznyyrfg crefba pna punatr gur pbhefr bs gur shgher.", - "Vs lbh ner n sevraq, lbh fcrnx gur cnffjbeq, naq gur qbbef jvyy bcra.", - "Lbh Funyy Abg Cnff", - "73.6% Bs Nyy Fgngvfgvpf Ner Znqr Hc", - "Jr pna arvgure pbasvez abe qral gung guvf vf penfuvat", - "Jura gur orngvat bs lbhe urneg rpubrf gur orngvat bs gur qehzf", - "Arire gehfg n pbzchgre lbh pna'g guebj bhg n jvaqbj", - "Lrnu, V'z pnyz. V'z n pnyz crefba. Vf gurer fbzr ernfba V fubhyqa'g or pnyz?", - "Rirelobql whfg fgnl pnyz. Gur fvghngvba vf haqre pbageby.", - "Uvccl, lbh guvax rirelguvat vf n pbafcvenpl.", - "Gurfr thlf ner nobhg nf zhpu sha nf n gnk nhqvg.", - "Gurer vf fbzrguvat qbja gurer! Fbzrguvat abg hf.", - "V fnj n tyvzcfr bs zl shgher naq rirelguvat'f punatrq sbe zr abj.", - "Va fcnpr ab bar pna urne lbh fpernz", - "V pna'g yvr gb lbh nobhg lbhe punaprf, ohg... lbh unir zl flzcnguvrf.", - "Gurer vf na rkcynangvba sbe guvf, lbh xabj.", - "V'z nsenvq V unir fbzr onq arjf.", - "Qb zr n snibhe. Qvfpbaarpg zr. V pbhyq or erjbexrq, ohg V'yy arire or gbc bs gur yvar ntnva.", - "Gnxr vg rnfl, qba'g chfu gur yvggyr ohggba ba gur wblfgvpx!", - "V'z n irel cevingr crefba.", - "Gb fphycg na ryrcunag sebz n ovt oybpx bs zneoyr, whfg xabpx njnl nyy gur ovgf gung qba'g ybbx yvxr na ryrcunag.", - "Jub fnvq lbh pbhyq gnyx gb zr? Unir V tbg fbzrguvat ba zl snpr ?", - "Jr'ir orra guebhtu jbefg", - "Havgrq jr fgnaq", - "Jr funyy arire fheeraqre", - "Nofbyhgr ubarfgl vfa'g nyjnlf gur zbfg qvcybzngvp abe gur fnsrfg sbez bs pbzzhavpngvba jvgu rzbgvbany orvatf.", - "Vg'f... pbzcyvpngrq.", - "Qb abg bcra hagvy 1985", - "V fgvyy zrff hc ohg V'yy whfg fgneg ntnva", - "V jba'g tvir hc, ab V jba'g tvir va; Gvyy V ernpu gur raq; Naq gura V'yy fgneg ntnva", - "V jnaan gel rira gubhtu V pbhyq snvy", - "Fbzrgvzrf jr pbzr ynfg ohg jr qvq bhe orfg", - "Vs lbh frr fbzrguvat, fnl fbzrguvat", - "Va gurbel gurer vf ab qvssrerapr orgjrra gurbel naq cenpgvpr. Ohg, va cenpgvpr, gurer vf.", - "Vs V pnaabg oevat lbh pbzsbeg gura ng yrnfg V oevat lbh ubcr", - "Jr nyy zhfg yrnea sebz fznyy zvfsbeghar, pbhag gur oyrffvatf gung ner erny", - "Cercner Guerr Frnyrq Rairybcrf...", - "Lbh xabj gung guvat lbh whfg qvq? Qba'g qb gung", - "Vg gbbx zr n ybat gvzr gb haqrefgnaq gung vs lbh jnag gb qb guvf wbo jryy lbh unir gb fgnl qrgnpurq.", - "Qb lbh yvxr lbhe zbeavat grn jrnx be fgebat ?", - "Jvagre vf pbzvat", - "Jung sbbyf gurfr zbegnyf or!", - "Fbzrguvat jvpxrq guvf jnl pbzrf.", - "V guvax V trg vg, jung jnf vg? Cbxre Avtug? Onpurybe Cnegl?", - "Vg'f nyevtug gb or fpnerq. Erzrzore, gurer vf ab pbhentr jvgubhg srne.", - "Guebhtu ernqvarff naq qvfpvcyvar jr ner znfgref bs bhe sngr.", - "Jvgu terng cbjre pbzrf terng erfcbafvovyvgl", - "Vs n znpuvar pna yrnea gur inyhr bs uhzna yvsr, znlor jr pna gbb ?", - "Bayl tbvat sbejneq 'pnhfr jr pna'g svaq erirefr.", - "Jr'er abg tbaan fvg va fvyrapr, jr'er abg tbaan yvir jvgu srne", - "Oba, qnaf qvk zvahgrf wr abhf pbafvqrer pbzzr qrsvavgvirzrag creqhf.", - "Pn fren fherzrag ovra dhnaq pn fren svav.", - "Vg'f gur ynfg cvrpr bs gur chmmyr ohg lbh whfg pna'g znxr vg svg", - "Qbpgbe fnlf lbh'er pherq ohg lbh fgvyy srry gur cnva", - "Vf negvsvpvny vagryyvtrapr gur rknpg bccbfvgr bs angheny fghcvqvgl ?", - "Sbeprzrag, pn qrcraq, pn qrcnffr...", - "Gurer'f orra n cnggrea bs vafhobeqvangr orunivbe erpragyl.", - "Ab. Jr ner abg na rssrpgvir grnz.", - "Bhe wbo vf abg gb erzrzore... erzrzore?", - "Guvf vf zvffvba pbageby. Ubj ner lbh nyy qbvat guvf ybiryl zbeavat?", - "Vs lbh pbhyq frr lbhe jubyr yvsr ynvq bhg va sebag bs lbh, jbhyq lbh punatr guvatf?", - "Vf guvf n aba-mreb-fhz tnzr?", - "Abj gung'f n cebcre vagebqhpgvba.", - "Rirelguvat unf punatrq naq vg jba'g fgbc punatvat nalgvzr fbba.", - "Jung znxrf lbh qvssrerag znxrf lbh qnatrebhf", - "Qviretrapr vf rkgerzryl qnatrebhf", - "V'z Qviretrag. Naq V pna'g or pbagebyyrq", - "Znl gur bqqf or rire va lbhe snibe", - "Ab WninFpevcg senzrjbexf jrer perngrq qhevat gur jevgvat bs guvf zrffntr.", - "P'rfg cerffr-cherr dhv g'nf vagreebtr ?", - "Ybbx, nygreangvir snpgf ner abg snpgf. Gurl'er snyfrubbqf", - "Guvf vf abg n penfu, guvf vf zber bs na nygreangvir erfhyg.", - "Lbh yrnearq gb cebtenz va SBEGENA qvqa'g lbh?", - "Guvf oht vf n srngher nf qrfpevorq ol gur znexrgvat qrcnegzrag.", - "Abg rirelobql haqrefgnaqf gur uhzbe bs cebtenzzref.", - "Vs lbh yvir na beqvanel yvsr, nyy lbh'yy unir ner beqvanel fgbevrf.", - "Pbzr jvgu zr vs lbh jnag gb yvir", - "Gh y'nf gebhir bh pryhv-yn ?", - "Qb lbh ernyyl guvax lbh unir n punapr ntnvafg hf, Ze. Pbjobl?", - "Nggragvba, jubrire lbh ner, guvf punaary vf erfreirq sbe rzretrapl pnyyf bayl.", - "Qbrf vg fbhaq yvxr V'z beqrevat n cvmmn? ", - "Jr'er tbaan arrq fbzr zber SOV thlf, V thrff.", - "Trg ernql sbe ehfu ubhe", - "V unir gb jnea lbh, V'ir urneq eryngvbafuvcf onfrq ba vagrafr rkcrevraprf arire jbex.", - "Nalguvat ryfr ohg gur onfrzrag gung'yy xrrc guvf ryringbe sebz snyyvat?", - "Vf guvf grfgvat jurgure V'z n ercyvpnag be n yrfovna, Ze. Qrpxneq? ", - "V'ir qbar... dhrfgvbanoyr guvatf", - "Jbhyq lbh... yvxr gb or hctenqrq?", - "Snhg erpbaanvger... p'rfg qh oehgny!", - "Fv ba oevpbynvg cyhf fbhirag, ba nhenvg zbvaf yn grgr nhk orgvfrf.", - "Wr invf yhv snver har beqbaanapr, rg har frirer...", - "Znvf vy pbaanvg cnf Enbhy, pr zrp! vy in nibve ha erirvy cravoyr.", - "W'nv ibhyh rger qvcybzngr n pnhfr qr ibhf gbhf, rivgre dhr yr fnat pbhyr.", - "Vtabenapr oevatf punbf, abg xabjyrqtr.", - "Yrneavat vf nyjnlf n cnvashy cebprff.", - "V'z fbeel, ner lbh sebz gur cnfg ?", - "Unir lbh gevrq gheavat vg bss naq ba ntnva ?", - "Vs lbh qba'g xabj jurer lbh ner tbvat nal ebnq pna gnxr lbh gurer", - "Xrrc pnyz naq cerff Pgey-Nyg-Qry", - "Vs lbh glcr Tbbtyr vagb Tbbtyr, lbh pna oernx gur Vagrearg.", - "V unir cneg bs n cyna.", - "V'z cerggl fher gur nafjre vf: V nz Tebbg.", - "Nalguvat gung pna cbffvoyl tb jebat, qbrf", - "Cyhf pn engr, cyhf ba n qr punapr dhr pn znepur", - "Fb V thrff gur sbeghar gryyre'f evtug...", - "Jura rirelguvat'f tbar jebat fbzrubj...", - "V qba'g jnag gb yvir ba guvf cynarg nalzber", - "Oba, p'rfg y'urher bh yrf fbhiravef fr enzrarag...", - "Fhpprff pbafvfgf bs tbvat sebz snvyher gb snvyher jvgubhg ybff bs raguhfvnfz", - "Vs lbh'er tbvat guebhtu uryy, xrrc tbvat", - "Jre xnzcsg, xnaa ireyvrera. Jre avpug xnzcsg, ung fpuba ireybera.", - "P'rfg nh cvrq qh zhe dhr y'ba ibvg yr zvrhk yr zhe.", - "Jr xabj ubj uhznaf jbex. Gurl ner nyy fb cerqvpgnoyr.", - "Pyrneyl, lbh unir arire zrg n jbzna.", - "Gur qbtznf bs gur dhvrg cnfg ner vanqrdhngr gb gur fgbezl cerfrag", - "Ab jnl gb cerirag guvf, fnlf bayl angvba jurer guvf erthyneyl unccraf", - "L'n dhrydhrf dhrfgvbaf dhv erfgrag fbhf fvyrapr...", - "Vs gurer vf ab fbyhgvba, gurer vf ab ceboyrz", - "V unir zrzbevrf, ohg V pna'g gryy vs gurl'er erny.", - "L n pbzzr ha tbhg nzre ra abhf", - "L n qrf fvyraprf dhv qvfrag ornhpbhc", - "V frr lbh'ir unq fbzr qvfpvcyvanel ceboyrzf va gur cnfg.", - "Cercnengvba vf gur xrl gb fhpprffshy, vapbafcvphbhf gvzr geniry.", - "Vg'f arire gbb yngr gb or jub lbh zvtug unir orra.", - "Rg cbhe nyyre purm Zvpxrl vyf ibag fherzrag cnf pbafgehver har tner gbhf yrf 100 zrgerf", - "Nyy lbhe onfr ner orybat gb hf", - "Znqr ba Rnegu ol uhznaf", - "Jvaaref Qba'g Hfr Qehtf", - "Lbh xabj jung fhecevfrq zr gur zbfg? Vg jnfa'g zrrgvat gurz. Vg jnf zrrgvat lbh.", - "Va jne gurer ner ab jvaaref, bayl jvqbjf", - "Vs lbh guvax guvf Havirefr vf onq, lbh fubhyq frr fbzr bs gur bguref", - "Cnp-Zna'f n onq thl?", - "Zl ernyvgl vf whfg qvssrerag guna lbhef", - "L'ra n dh'bag rffnlr, vyf bag rh qrf ceboyrzrf", - "Gb ree vf uhzna, ohg gb ernyyl sbhy guvatf hc erdhverf n pbzchgre.", - "Vs lbh oryvrir rirelguvat lbh ernq, lbh orggre abg ernq", - "Gurer vf ab ceboyrz fb onq lbh pna'g znxr vg jbefr", - "Pn p'rfg qh ybheq... Ha gehp qr znynqr.", - "V qb abg guvax, gung V guvax.. V guvax.", - "Gurer ner cynprf ybjre guna gur onfrzrag", - "Gurer ner 10 glcrf bs crbcyr: gubfr jub haqrefgnaq ovanel, naq gubfr jub qba'g.", - "Cyrnfr zvaq gur tnc orgjrra gur genva naq gur cyngsbez", - "Nfuvzbgb av tb-puhv xhqnfnv", - "Vs lbh'er erprvivat guvf genafzvffvba, znxr ab nggrzcg gb pbzr gb vgf cbvag bs bevtva.", - "Obl, qb V ungr orvat evtug nyy gur gvzr!", - "Jub funirf gur oneore jub funirf nyy gur zra jub qba'g funir gurzfryirf?", - "V haqrefgnaq uhzna rzbgvbaf, nygubhtu V qb abg srry gurz zlfrys.", - "Lbh qvqa'g fnl gur zntvp jbeq!", - "Gurer vf ab ceboyrz gung n ynpx bs fbyhgvba jba'g svanyyl erfbyir.", - "V unir n inthr srryvat bs vzcraqvat zvfsbeghar.", - "Jura lbh'er va gebhoyr, pbashfr rirelguvat", - "Jung gur uryy vf Cebwrpg Ryebaq?", - "Qba'g qvt hc gur ovt obk bs cyhgbavhz, Znex", - "Uryc vf bayl 140 zvyyvba zvyrf njnl.", - "P unf gur fcrrq naq rssvpvrapl bs nffrzoyl ynathntr pbzovarq jvgu ernqnovyvgl bs nffrzoyl ynathntr", - "Crey vf gur bayl ynathntr gung ybbxf gur fnzr orsber naq nsgre EFN rapelcgvba", - "Gur zber vg snvyf, gur zber yvxryl vg vf gung vg jvyy jbex", - "V ubcr V qvqa'g gnxr hc gbb zhpu bs lbhe gvzr", "Lbh'er tbaan arrq n ovttre obng", - "Dhnaq ibhf rgrf rzorgrf, rzoebhvyyrm gbhg", "Gurer nva'g ab phevat jung'f jebat jvgu gung guvat", - "Vs lbh cevpx hf, qb jr abg oyrrq?", "V qvq lbhe wbo bapr - V jnf tbbq ng vg.", - "Vyf cbheenvrag snver har fryrpgvba nh fgnaqneq...", "Gung'f ab jnl gb gerng n sevraq.", - "Ubjrire ornhgvshy gur fgengrtl, lbh fubhyq bppnfvbanyyl ybbx ng gur erfhygf", - "Qba'g svk vg vs vg'f abg oebxra", - "Fhqqrayl V'z gnxvat fhttrfgvbaf sebz fbzr fgebat-nez zna jvgu na VD bs zvahf 50.", - "Fur ehvaf rirelguvat fur'f va. Fur ehvaf guvatf fur'f abg rira va.", - "Byvir, V guvax lbh fubhyq xabj guvf: lbh'er n ubeevoyr npgerff.", - "Lbh'er yngr! Qb lbh unir ab pbaprcg bs gvzr ?", - "P'zba zna, yrg'f qb fbzrguvat gung ernyyl pbbxf.", - "Nh sbaq, znvagranag, yrf qvcybzngrf ceraqenvrag cyhgbg yr cnf fhe yrf ubzzrf q'npgvba.", - "Whfg zragnyyl gubhtu... ner lbh bxnl ?", "Jr xabj fur'f bxnl orpnhfr fur'f oybaq", - "Gh oyhssrf Znegbav", "Lbh thlf ner trggvat cnvq?", - "Gurer'f n erq guvatl zbivat gbjneqf gur terra guvatl... V guvax jr'er gur terra guvatl", - "Nyy flfgrzf ner shapgvbavat Pbzznaqre", "V erzrzore gung fbhaq! Gung'f n onq fbhaq!", - "V xabj vg'f uneq sbe lbh gb haqrefgnaq rira fubeg fragraprf", - "Gur havirefr vf shyy bs vagryyvtrag yvsr. Vg'f whfg orra gbb vagryyvtrag gb pbzr urer.", - "Uryyb, jbhyq lbh yvxr gb urne n GPC wbxr ?", - "Rirel snvel gnyr arrqf n tbbq byq-snfuvbarq ivyynva", - "Fvapr gurer'f ab pbapyhfvba gb gur cnenqbk gurbel, gurer'f ab jnl gb cebir gurer'f ab cnenqbk.", - "Gnxr zr guebhtu gur qnexarff gb gur oernx bs gur qnl", - "Vg znxrf gur gehgu rira zber vapbzcerurafvoyr orpnhfr rirelguvat vf arj", - "V qba'g xabj ubj ohg V fhqqrayl ybfr pbageby", "Gurer ner zbzragf jura V guvax V'z tbvat penml", - "Jbhyq gung vg jrer fb fvzcyr", "Pnyy gung n xavsr? Guvf vf n xavsr.", - "Fhe y'bprna qh grzcf dhv tyvffr...", "Snvyher serr bcrengvbaf erdhver rkcrevrapr jvgu snvyher.", - "Pngnfgebcur vf nyjnlf whfg nebhaq gur pbeare.", - "Orjner bs ohtf va gur nobir pbqr; V unir bayl cebirq vg pbeerpg, abg gevrq vg", - "V'z abg n erny cebtenzzre. V guebj gbtrgure guvatf hagvy vg jbexf gura V zbir ba", - "#qrsvar DHRFGVBA ((oo)||!(oo))", "Pbzchgref ner hfryrff. Gurl pna bayl tvir lbh nafjref", - "Gur Vagrearg? Vf gung guvat fgvyy nebhaq?", - "Va beqre gb haqrefgnaq erphefvba, bar zhfg svefg haqrefgnaq erphefvba"); + static private final List quotes = Arrays.asList("Ur'f qrnq, Wvz.", + "Ol Tenogune'f unzzre, ol gur fbaf bs Jbeina, lbh funyy or niratrq.", + "Ebnqf? Jurer jr'er tbvat, jr qba'g arrq ebnqf.", "Gur gvzr vf bhg bs wbvag.", + "P'rfg phevrhk purm yrf znevaf pr orfbva qr snver qrf cuenfrf.", + "V'z gnyxvat nobhg gur bgure Crgre, gur bar ba gur bgure fvqr.", "Znl gur Sbepr or jvgu lbh!", + "Arire tvir hc, arire fheeraqre...", "Unfgn yn ivfgn, onol.", + "Url, Qbp, jr orggre onpx hc. Jr qba'g unir rabhtu ebnq gb trg hc gb 88.", + "Terrgvatf, Cebsrffbe Snyxra. Funyy jr cynl n tnzr?", "V pna'g punatr gur ynj bs culfvpf!", + "N fgenatr tnzr. Gur bayl jvaavat zbir vf abg gb cynl.", "V'z gur Tngrxrrcre, ner lbh gur Xrlznfgre?", + "V nz gur Znfgre Pbageby Cebtenz. Ab bar Hfre jebgr zr.", "Yvsr? Qba'g gnyx gb zr nobhg yvsr.", + "V nyjnlf gubhtug fbzrguvat jnf shaqnzragnyyl jebat jvgu gur havirefr.", + "N ebobg znl abg vawher n uhzna orvat be, guebhtu vanpgvba, nyybj n uhzna orvat gb pbzr gb unez.", + "Fheeraqre znl or bhe bayl bcgvba.", "Fvk ol avar. Sbegl gjb.", "Vg'f yvsr, Wvz, ohg abg nf jr xabj vg.", + "Qba'g Cnavp!", "Jung qb lbh zrna? Na Nsevpna be Rhebcrna fjnyybj?", + "V arrq lbhe obbgf lbhe pybgurf naq lbhe zbgbeplpyr", "Lbh sbetbg gb fnl cyrnfr...", + "Lbh unir qvrq bs qlfragrel.", "Jbhyqa'g lbh cersre n avpr tnzr bs purff?", + "Jura lbh unir ryvzvangrq gur vzcbffvoyr, jungrire erznvaf, ubjrire vzcebonoyr, zhfg or gur gehgu.", + "V xabj abj jul lbh pel. Ohg vg'f fbzrguvat V pna arire qb.", + "Erfvfgnapr vf shgvyr. Lbh jvyy or nffvzvyngrq.", "Nalguvat qvssrerag vf tbbq.", + "Penpxrq ol Nyqb Erfrg naq Ynherag Ehrvy.", "V'z obgu. V'z n pryroevgl va na rzretrapl.", + "Qb lbh xabj guvf terng terng cbyvfu npgbe, Wbfrcu Ghen?", "Gb vasvavgl naq orlbaq!", + "Fcnpr: gur svany sebagvre...", "Fhe zba ovyyrg, grarm, l n rpevg Fnvag-Ynmner, p'rfg zrf lrhk bh dhbv ?", + "Gur obl vf vzcbegnag. Ur unf gb yvir.", "Bapr hcba n gvzr va n tnynkl sne, sne njnl...", + "Naq lbh xabj gurer'f n ybat ybat jnl nurnq bs lbh...", "Na nyyretl gb bkltra? Ryz oyvtug?", + "Ohg nybef lbh ner Serapu!", "A'nv-wr qbap gnag irph dhr cbhe prggr vasnzvr?", + "Fbzrguvat vf ebggra va gur Fgngr bs Qraznex.", "Url, jung qb lbh jnag? Zvenpyrf?", + "1.21 tvtnjnggf! 1.21 tvtnjnggf. Terng Fpbgg! ", "Jung gur uryy vf n tvtnjngg?", "V arrq n inpngvba.", + "Ba qrienvg wnznvf dhvggre Zbagnhona.", "Zl sbepr vf n cyngsbez gung lbh pna pyvzo ba...", + "Gurer'f fbzrguvat jrveq, naq vg qba'g ybbx tbbq...", "Rg evra ienvzrag ar punatr znvf gbhg rfg qvssrerag", + "Ornz zr hc, Fpbggl.", "Gurer vf ab fcbba.", "Sbyybj gur juvgr enoovg.", + "Arire fraq n uhzna gb qb n znpuvar'f wbo.", "Theh zrqvgngvba. Cerff yrsg zbhfr ohggba gb pbagvahr.", + "V qba'g guvax jr'er va Xnafnf nalzber.", "Yhxr, V nz lbhe sngure.", "Oybbq, Fjrng naq Grnef", + "Ubhfgba, jr unir n ceboyrz.", "Xrlobneq snvyher, cerff nal xrl gb pbagvahr", "Ovt zvfgnxr!", + "Ubj znal HZY qrfvtaref qbrf vg gnxr gb punatr n yvtugohyo ?", "Qb lbh yvxr zbivrf nobhg tynqvngbef ?", + "Gur fcvevg bs yrneavat vf n ynfgvat sebagvre.", + "Vg vf phevbhf sbe fnvybef guvf arrq sbe znxvat fragraprf.", "Ubcvat sbe gur orfg, ohg rkcrpgvat gur jbefg", + "Gur jvyy gb tb ba jura V'z uheg qrrc vafvqr.", "Vs vg oyrrqf, jr pna xvyy vg.", + "Ubhfgba, V unir n onq srryvat nobhg guvf zvffvba.", + "Znzn nyjnlf fnvq yvsr jnf yvxr n obk bs pubpbyngrf. Lbh arire xabj jung lbh'er tbaan trg.", + "Ol gur jnl, vf gurer nalbar ba obneq jub xabjf ubj gb syl n cynar?", + "Qnir, guvf pbairefngvba pna freir ab checbfr nalzber. Tbbqolr.", + "Vg pna bayl or nggevohgnoyr gb uhzna reebe.", "Ybbxf yvxr V cvpxrq gur jebat jrrx gb dhvg fzbxvat.", + "Lbh uhznaf npg fb fgenatr. Rirelguvat lbh perngr vf hfrq gb qrfgebl.", + "Jurer qvq lbh yrnea ubj gb artbgvngr yvxr gung?", "Fve, ner lbh pynffvsvrq nf uhzna?", + "Jr'er abg tbaan znxr vg, ner jr?", "Vg'f va lbhe angher gb qrfgebl lbhefryirf.", + "Gur zber pbagnpg V unir jvgu uhznaf, gur zber V yrnea.", + "Jbhyq vg fnir lbh n ybg bs gvzr vs V whfg tnir hc naq jrag znq abj?", "Ernyvgl vf serdhragyl vanpphengr.", + "Qba'g oryvrir nalguvat lbh ernq ba gur arg. Rkprcg guvf. Jryy, vapyhqvat guvf, V fhccbfr.", + "N phc bs grn jbhyq erfgber zl abeznyvgl.", + "Nalguvat gung guvaxf ybtvpnyyl pna or sbbyrq ol fbzrguvat ryfr gung guvaxf ng yrnfg nf ybtvpnyyl nf vg qbrf.", + "Va na vasvavgr Havirefr nalguvat pna unccra.", + "Fbzrgvzrf vs lbh erprvirq na nafjre, gur dhrfgvba zvtug or gnxra njnl.", + "Cyrnfr pnyy zr Rqqvr vs vg jvyy uryc lbh gb erynk.", + "V qba'g oryvrir vg. Cebir vg gb zr naq V fgvyy jba'g oryvrir vg.", + "Gbgnyyl znq, hggre abafrafr. Ohg jr'yy qb vg orpnhfr vg'f oevyyvnag abafrafr.", + "Guvf fragrapr vf abg gehr.", "V jbhyq engure qvr fgnaqvat guna yvir ba zl xarrf.", + "Lbh ner orvat jngpurq.", "Qvq lbh srrq gurz nsgre zvqavtug?", + "Ubj qb lbh rkcynva fpubby gb uvture vagryyvtrapr?", "Crbcyr fbzrgvzrf znxr zvfgnxrf.", + "Ybbx, V qba'g unir gvzr sbe n pbairefngvba evtug abj.", + "Nyy ceboyrzf va pbzchgre fpvrapr pna or fbyirq ol nabgure yriry bs vaqverpgvba", + "...rkprcg sbe gur ceboyrz bs gbb znal yriryf bs vaqverpgvba", "V xabj orpnhfr V ohvyg vg", + "Rira gur fznyyrfg crefba pna punatr gur pbhefr bs gur shgher.", + "Vs lbh ner n sevraq, lbh fcrnx gur cnffjbeq, naq gur qbbef jvyy bcra.", "Lbh Funyy Abg Cnff", + "73.6% Bs Nyy Fgngvfgvpf Ner Znqr Hc", "Jr pna arvgure pbasvez abe qral gung guvf vf penfuvat", + "Jura gur orngvat bs lbhe urneg rpubrf gur orngvat bs gur qehzf", + "Arire gehfg n pbzchgre lbh pna'g guebj bhg n jvaqbj", + "Lrnu, V'z pnyz. V'z n pnyz crefba. Vf gurer fbzr ernfba V fubhyqa'g or pnyz?", + "Rirelobql whfg fgnl pnyz. Gur fvghngvba vf haqre pbageby.", "Uvccl, lbh guvax rirelguvat vf n pbafcvenpl.", + "Gurfr thlf ner nobhg nf zhpu sha nf n gnk nhqvg.", "Gurer vf fbzrguvat qbja gurer! Fbzrguvat abg hf.", + "V fnj n tyvzcfr bs zl shgher naq rirelguvat'f punatrq sbe zr abj.", "Va fcnpr ab bar pna urne lbh fpernz", + "V pna'g yvr gb lbh nobhg lbhe punaprf, ohg... lbh unir zl flzcnguvrf.", + "Gurer vf na rkcynangvba sbe guvf, lbh xabj.", "V'z nsenvq V unir fbzr onq arjf.", + "Qb zr n snibhe. Qvfpbaarpg zr. V pbhyq or erjbexrq, ohg V'yy arire or gbc bs gur yvar ntnva.", + "Gnxr vg rnfl, qba'g chfu gur yvggyr ohggba ba gur wblfgvpx!", "V'z n irel cevingr crefba.", + "Gb fphycg na ryrcunag sebz n ovt oybpx bs zneoyr, whfg xabpx njnl nyy gur ovgf gung qba'g ybbx yvxr na ryrcunag.", + "Jub fnvq lbh pbhyq gnyx gb zr? Unir V tbg fbzrguvat ba zl snpr ?", "Jr'ir orra guebhtu jbefg", + "Havgrq jr fgnaq", "Jr funyy arire fheeraqre", + "Nofbyhgr ubarfgl vfa'g nyjnlf gur zbfg qvcybzngvp abe gur fnsrfg sbez bs pbzzhavpngvba jvgu rzbgvbany orvatf.", + "Vg'f... pbzcyvpngrq.", "Qb abg bcra hagvy 1985", "V fgvyy zrff hc ohg V'yy whfg fgneg ntnva", + "V jba'g tvir hc, ab V jba'g tvir va; Gvyy V ernpu gur raq; Naq gura V'yy fgneg ntnva", + "V jnaan gel rira gubhtu V pbhyq snvy", "Fbzrgvzrf jr pbzr ynfg ohg jr qvq bhe orfg", + "Vs lbh frr fbzrguvat, fnl fbzrguvat", + "Va gurbel gurer vf ab qvssrerapr orgjrra gurbel naq cenpgvpr. Ohg, va cenpgvpr, gurer vf.", + "Vs V pnaabg oevat lbh pbzsbeg gura ng yrnfg V oevat lbh ubcr", + "Jr nyy zhfg yrnea sebz fznyy zvfsbeghar, pbhag gur oyrffvatf gung ner erny", + "Cercner Guerr Frnyrq Rairybcrf...", "Lbh xabj gung guvat lbh whfg qvq? Qba'g qb gung", + "Vg gbbx zr n ybat gvzr gb haqrefgnaq gung vs lbh jnag gb qb guvf wbo jryy lbh unir gb fgnl qrgnpurq.", + "Qb lbh yvxr lbhe zbeavat grn jrnx be fgebat ?", "Jvagre vf pbzvat", "Jung sbbyf gurfr zbegnyf or!", + "Fbzrguvat jvpxrq guvf jnl pbzrf.", "V guvax V trg vg, jung jnf vg? Cbxre Avtug? Onpurybe Cnegl?", + "Vg'f nyevtug gb or fpnerq. Erzrzore, gurer vf ab pbhentr jvgubhg srne.", + "Guebhtu ernqvarff naq qvfpvcyvar jr ner znfgref bs bhe sngr.", + "Jvgu terng cbjre pbzrf terng erfcbafvovyvgl", + "Vs n znpuvar pna yrnea gur inyhr bs uhzna yvsr, znlor jr pna gbb ?", + "Bayl tbvat sbejneq 'pnhfr jr pna'g svaq erirefr.", + "Jr'er abg tbaan fvg va fvyrapr, jr'er abg tbaan yvir jvgu srne", + "Oba, qnaf qvk zvahgrf wr abhf pbafvqrer pbzzr qrsvavgvirzrag creqhf.", + "Pn fren fherzrag ovra dhnaq pn fren svav.", + "Vg'f gur ynfg cvrpr bs gur chmmyr ohg lbh whfg pna'g znxr vg svg", + "Qbpgbe fnlf lbh'er pherq ohg lbh fgvyy srry gur cnva", + "Vf negvsvpvny vagryyvtrapr gur rknpg bccbfvgr bs angheny fghcvqvgl ?", + "Sbeprzrag, pn qrcraq, pn qrcnffr...", "Gurer'f orra n cnggrea bs vafhobeqvangr orunivbe erpragyl.", + "Ab. Jr ner abg na rssrpgvir grnz.", "Bhe wbo vf abg gb erzrzore... erzrzore?", + "Guvf vf zvffvba pbageby. Ubj ner lbh nyy qbvat guvf ybiryl zbeavat?", + "Vs lbh pbhyq frr lbhe jubyr yvsr ynvq bhg va sebag bs lbh, jbhyq lbh punatr guvatf?", + "Vf guvf n aba-mreb-fhz tnzr?", "Abj gung'f n cebcre vagebqhpgvba.", + "Rirelguvat unf punatrq naq vg jba'g fgbc punatvat nalgvzr fbba.", + "Jung znxrf lbh qvssrerag znxrf lbh qnatrebhf", "Qviretrapr vf rkgerzryl qnatrebhf", + "V'z Qviretrag. Naq V pna'g or pbagebyyrq", "Znl gur bqqf or rire va lbhe snibe", + "Ab WninFpevcg senzrjbexf jrer perngrq qhevat gur jevgvat bs guvf zrffntr.", + "P'rfg cerffr-cherr dhv g'nf vagreebtr ?", "Ybbx, nygreangvir snpgf ner abg snpgf. Gurl'er snyfrubbqf", + "Guvf vf abg n penfu, guvf vf zber bs na nygreangvir erfhyg.", + "Lbh yrnearq gb cebtenz va SBEGENA qvqa'g lbh?", + "Guvf oht vf n srngher nf qrfpevorq ol gur znexrgvat qrcnegzrag.", + "Abg rirelobql haqrefgnaqf gur uhzbe bs cebtenzzref.", + "Vs lbh yvir na beqvanel yvsr, nyy lbh'yy unir ner beqvanel fgbevrf.", "Pbzr jvgu zr vs lbh jnag gb yvir", + "Gh y'nf gebhir bh pryhv-yn ?", "Qb lbh ernyyl guvax lbh unir n punapr ntnvafg hf, Ze. Pbjobl?", + "Nggragvba, jubrire lbh ner, guvf punaary vf erfreirq sbe rzretrapl pnyyf bayl.", + "Qbrf vg fbhaq yvxr V'z beqrevat n cvmmn? ", "Jr'er tbaan arrq fbzr zber SOV thlf, V thrff.", + "Trg ernql sbe ehfu ubhe", + "V unir gb jnea lbh, V'ir urneq eryngvbafuvcf onfrq ba vagrafr rkcrevraprf arire jbex.", + "Nalguvat ryfr ohg gur onfrzrag gung'yy xrrc guvf ryringbe sebz snyyvat?", + "Vf guvf grfgvat jurgure V'z n ercyvpnag be n yrfovna, Ze. Qrpxneq? ", "V'ir qbar... dhrfgvbanoyr guvatf", + "Jbhyq lbh... yvxr gb or hctenqrq?", "Snhg erpbaanvger... p'rfg qh oehgny!", + "Fv ba oevpbynvg cyhf fbhirag, ba nhenvg zbvaf yn grgr nhk orgvfrf.", + "Wr invf yhv snver har beqbaanapr, rg har frirer...", + "Znvf vy pbaanvg cnf Enbhy, pr zrp! vy in nibve ha erirvy cravoyr.", + "W'nv ibhyh rger qvcybzngr n pnhfr qr ibhf gbhf, rivgre dhr yr fnat pbhyr.", + "Vtabenapr oevatf punbf, abg xabjyrqtr.", "Yrneavat vf nyjnlf n cnvashy cebprff.", + "V'z fbeel, ner lbh sebz gur cnfg ?", "Unir lbh gevrq gheavat vg bss naq ba ntnva ?", + "Vs lbh qba'g xabj jurer lbh ner tbvat nal ebnq pna gnxr lbh gurer", "Xrrc pnyz naq cerff Pgey-Nyg-Qry", + "Vs lbh glcr Tbbtyr vagb Tbbtyr, lbh pna oernx gur Vagrearg.", "V unir cneg bs n cyna.", + "V'z cerggl fher gur nafjre vf: V nz Tebbg.", "Nalguvat gung pna cbffvoyl tb jebat, qbrf", + "Cyhf pn engr, cyhf ba n qr punapr dhr pn znepur", "Fb V thrff gur sbeghar gryyre'f evtug...", + "Jura rirelguvat'f tbar jebat fbzrubj...", "V qba'g jnag gb yvir ba guvf cynarg nalzber", + "Oba, p'rfg y'urher bh yrf fbhiravef fr enzrarag...", + "Fhpprff pbafvfgf bs tbvat sebz snvyher gb snvyher jvgubhg ybff bs raguhfvnfz", + "Vs lbh'er tbvat guebhtu uryy, xrrc tbvat", + "Jre xnzcsg, xnaa ireyvrera. Jre avpug xnzcsg, ung fpuba ireybera.", + "P'rfg nh cvrq qh zhe dhr y'ba ibvg yr zvrhk yr zhe.", + "Jr xabj ubj uhznaf jbex. Gurl ner nyy fb cerqvpgnoyr.", "Pyrneyl, lbh unir arire zrg n jbzna.", + "Gur qbtznf bs gur dhvrg cnfg ner vanqrdhngr gb gur fgbezl cerfrag", + "Ab jnl gb cerirag guvf, fnlf bayl angvba jurer guvf erthyneyl unccraf", + "L'n dhrydhrf dhrfgvbaf dhv erfgrag fbhf fvyrapr...", "Vs gurer vf ab fbyhgvba, gurer vf ab ceboyrz", + "V unir zrzbevrf, ohg V pna'g gryy vs gurl'er erny.", "L n pbzzr ha tbhg nzre ra abhf", + "L n qrf fvyraprf dhv qvfrag ornhpbhc", "V frr lbh'ir unq fbzr qvfpvcyvanel ceboyrzf va gur cnfg.", + "Cercnengvba vf gur xrl gb fhpprffshy, vapbafcvphbhf gvzr geniry.", + "Vg'f arire gbb yngr gb or jub lbh zvtug unir orra.", + "Rg cbhe nyyre purm Zvpxrl vyf ibag fherzrag cnf pbafgehver har tner gbhf yrf 100 zrgerf", + "Nyy lbhe onfr ner orybat gb hf", "Znqr ba Rnegu ol uhznaf", "Jvaaref Qba'g Hfr Qehtf", + "Lbh xabj jung fhecevfrq zr gur zbfg? Vg jnfa'g zrrgvat gurz. Vg jnf zrrgvat lbh.", + "Va jne gurer ner ab jvaaref, bayl jvqbjf", + "Vs lbh guvax guvf Havirefr vf onq, lbh fubhyq frr fbzr bs gur bguref", "Cnp-Zna'f n onq thl?", + "Zl ernyvgl vf whfg qvssrerag guna lbhef", "L'ra n dh'bag rffnlr, vyf bag rh qrf ceboyrzrf", + "Gb ree vf uhzna, ohg gb ernyyl sbhy guvatf hc erdhverf n pbzchgre.", + "Vs lbh oryvrir rirelguvat lbh ernq, lbh orggre abg ernq", + "Gurer vf ab ceboyrz fb onq lbh pna'g znxr vg jbefr", "Pn p'rfg qh ybheq... Ha gehp qr znynqr.", + "V qb abg guvax, gung V guvax.. V guvax.", "Gurer ner cynprf ybjre guna gur onfrzrag", + "Gurer ner 10 glcrf bs crbcyr: gubfr jub haqrefgnaq ovanel, naq gubfr jub qba'g.", + "Cyrnfr zvaq gur tnc orgjrra gur genva naq gur cyngsbez", "Nfuvzbgb av tb-puhv xhqnfnv", + "Vs lbh'er erprvivat guvf genafzvffvba, znxr ab nggrzcg gb pbzr gb vgf cbvag bs bevtva.", + "Obl, qb V ungr orvat evtug nyy gur gvzr!", + "Jub funirf gur oneore jub funirf nyy gur zra jub qba'g funir gurzfryirf?", + "V haqrefgnaq uhzna rzbgvbaf, nygubhtu V qb abg srry gurz zlfrys.", "Lbh qvqa'g fnl gur zntvp jbeq!", + "Gurer vf ab ceboyrz gung n ynpx bs fbyhgvba jba'g svanyyl erfbyir.", + "V unir n inthr srryvat bs vzcraqvat zvfsbeghar.", "Jura lbh'er va gebhoyr, pbashfr rirelguvat", + "Jung gur uryy vf Cebwrpg Ryebaq?", "Qba'g qvt hc gur ovt obk bs cyhgbavhz, Znex", + "Uryc vf bayl 140 zvyyvba zvyrf njnl.", + "P unf gur fcrrq naq rssvpvrapl bs nffrzoyl ynathntr pbzovarq jvgu ernqnovyvgl bs nffrzoyl ynathntr", + "Crey vf gur bayl ynathntr gung ybbxf gur fnzr orsber naq nsgre EFN rapelcgvba", + "Gur zber vg snvyf, gur zber yvxryl vg vf gung vg jvyy jbex", + "V ubcr V qvqa'g gnxr hc gbb zhpu bs lbhe gvzr", "Lbh'er tbaan arrq n ovttre obng", + "Dhnaq ibhf rgrf rzorgrf, rzoebhvyyrm gbhg", "Gurer nva'g ab phevat jung'f jebat jvgu gung guvat", + "Vs lbh cevpx hf, qb jr abg oyrrq?", "V qvq lbhe wbo bapr - V jnf tbbq ng vg.", + "Vyf cbheenvrag snver har fryrpgvba nh fgnaqneq...", "Gung'f ab jnl gb gerng n sevraq.", + "Ubjrire ornhgvshy gur fgengrtl, lbh fubhyq bppnfvbanyyl ybbx ng gur erfhygf", + "Qba'g svk vg vs vg'f abg oebxra", + "Fhqqrayl V'z gnxvat fhttrfgvbaf sebz fbzr fgebat-nez zna jvgu na VD bs zvahf 50.", + "Fur ehvaf rirelguvat fur'f va. Fur ehvaf guvatf fur'f abg rira va.", + "Byvir, V guvax lbh fubhyq xabj guvf: lbh'er n ubeevoyr npgerff.", + "Lbh'er yngr! Qb lbh unir ab pbaprcg bs gvzr ?", "P'zba zna, yrg'f qb fbzrguvat gung ernyyl pbbxf.", + "Nh sbaq, znvagranag, yrf qvcybzngrf ceraqenvrag cyhgbg yr cnf fhe yrf ubzzrf q'npgvba.", + "Whfg zragnyyl gubhtu... ner lbh bxnl ?", "Jr xabj fur'f bxnl orpnhfr fur'f oybaq", "Gh oyhssrf Znegbav", + "Lbh thlf ner trggvat cnvq?", + "Gurer'f n erq guvatl zbivat gbjneqf gur terra guvatl... V guvax jr'er gur terra guvatl", + "Nyy flfgrzf ner shapgvbavat Pbzznaqre", "V erzrzore gung fbhaq! Gung'f n onq fbhaq!", + "V xabj vg'f uneq sbe lbh gb haqrefgnaq rira fubeg fragraprf", + "Gur havirefr vf shyy bs vagryyvtrag yvsr. Vg'f whfg orra gbb vagryyvtrag gb pbzr urer.", + "Uryyb, jbhyq lbh yvxr gb urne n GPC wbxr ?", "Rirel snvel gnyr arrqf n tbbq byq-snfuvbarq ivyynva", + "Fvapr gurer'f ab pbapyhfvba gb gur cnenqbk gurbel, gurer'f ab jnl gb cebir gurer'f ab cnenqbk.", + "Gnxr zr guebhtu gur qnexarff gb gur oernx bs gur qnl", + "Vg znxrf gur gehgu rira zber vapbzcerurafvoyr orpnhfr rirelguvat vf arj", + "V qba'g xabj ubj ohg V fhqqrayl ybfr pbageby", "Gurer ner zbzragf jura V guvax V'z tbvat penml", + "Jbhyq gung vg jrer fb fvzcyr", "Pnyy gung n xavsr? Guvf vf n xavsr.", "Fhe y'bprna qh grzcf dhv tyvffr...", + "Snvyher serr bcrengvbaf erdhver rkcrevrapr jvgu snvyher.", "Pngnfgebcur vf nyjnlf whfg nebhaq gur pbeare.", + "Orjner bs ohtf va gur nobir pbqr; V unir bayl cebirq vg pbeerpg, abg gevrq vg", + "V'z abg n erny cebtenzzre. V guebj gbtrgure guvatf hagvy vg jbexf gura V zbir ba", + "#qrsvar DHRFGVBA ((oo)||!(oo))", "Pbzchgref ner hfryrff. Gurl pna bayl tvir lbh nafjref", + "Gur Vagrearg? Vf gung guvat fgvyy nebhaq?", + "Va beqre gb haqrefgnaq erphefvba, bar zhfg svefg haqrefgnaq erphefvba", + "Obhagl Uhagvat vf n pbzcyvpngrq cebsrffvba.", + "Znahsnpghere'f cebgbpby qvpgngrf V pna abg or pncgherq. V zhfg frys-qrfgehpg.", "Snvyher vf abg na bcgvba", + "Rirelguvat snvyf nyy gur gvzr", "Gur orfg jnl gb nibvq snvyher vf gb snvy pbafgnagyl", + "Cerzngher bcgvzvmngvba vf gur ebbg bs nyy rivy", "Chgnva, w'ra nv zneer q'nibve gbhwbhef envfba"); private QuoteUtils() { } diff --git a/src/net/sourceforge/plantuml/graphic/TextBlockUtils.java b/src/net/sourceforge/plantuml/graphic/TextBlockUtils.java index 8297b19d5..e905f01cb 100644 --- a/src/net/sourceforge/plantuml/graphic/TextBlockUtils.java +++ b/src/net/sourceforge/plantuml/graphic/TextBlockUtils.java @@ -106,7 +106,8 @@ public class TextBlockUtils { return new TextBlockMarged(textBlock, marginX1, marginX2, marginY1, marginY2); } - public static TextBlock withMinWidth(TextBlock textBlock, double minWidth, HorizontalAlignment horizontalAlignment) { + public static TextBlock withMinWidth(TextBlock textBlock, double minWidth, + HorizontalAlignment horizontalAlignment) { return new TextBlockMinWidth(textBlock, minWidth, horizontalAlignment); } @@ -125,6 +126,10 @@ public class TextBlockUtils { return new PositionableImpl(pt, textBlock.calculateDimension(stringBounder)); } + public static Positionable asPositionable(Dimension2D dim, StringBounder stringBounder, Point2D pt) { + return new PositionableImpl(pt, dim); + } + public static TextBlock mergeLR(TextBlock b1, TextBlock b2, VerticalAlignment verticallAlignment) { return new TextBlockHorizontal(b1, b2, verticallAlignment); } @@ -133,7 +138,8 @@ public class TextBlockUtils { return new TextBlockVertical2(b1, b2, horizontalAlignment); } - // public static TextBlockBackcolored mergeColoredTB(TextBlockBackcolored b1, TextBlockBackcolored b2, + // public static TextBlockBackcolored mergeColoredTB(TextBlockBackcolored b1, + // TextBlockBackcolored b2, // HorizontalAlignment horizontalAlignment) { // return addBackcolor(mergeTB(b1, b2, horizontalAlignment), b1.getBackcolor()); // } diff --git a/src/net/sourceforge/plantuml/jdot/CucaDiagramFileMakerJDot.java b/src/net/sourceforge/plantuml/jdot/CucaDiagramFileMakerJDot.java index 19595dfb2..c5fde0062 100644 --- a/src/net/sourceforge/plantuml/jdot/CucaDiagramFileMakerJDot.java +++ b/src/net/sourceforge/plantuml/jdot/CucaDiagramFileMakerJDot.java @@ -83,6 +83,7 @@ import net.sourceforge.plantuml.cucadiagram.Link; import net.sourceforge.plantuml.cucadiagram.Member; import net.sourceforge.plantuml.cucadiagram.MethodsOrFieldsArea; import net.sourceforge.plantuml.cucadiagram.Stereotype; +import net.sourceforge.plantuml.cucadiagram.entity.EntityFactory; import net.sourceforge.plantuml.graphic.FontConfiguration; import net.sourceforge.plantuml.graphic.HorizontalAlignment; import net.sourceforge.plantuml.graphic.HtmlColor; @@ -102,7 +103,7 @@ import net.sourceforge.plantuml.svek.DotStringFactory; import net.sourceforge.plantuml.svek.GeneralImageBuilder; import net.sourceforge.plantuml.svek.GraphvizCrash; import net.sourceforge.plantuml.svek.IEntityImage; -import net.sourceforge.plantuml.svek.Shape; +import net.sourceforge.plantuml.svek.Node; import net.sourceforge.plantuml.ugraphic.ImageBuilder; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.UStroke; @@ -121,7 +122,6 @@ public class CucaDiagramFileMakerJDot implements CucaDiagramFileMaker { private final Map nodes = new LinkedHashMap(); private final Map edges = new LinkedHashMap(); private final Map clusters = new LinkedHashMap(); - private Map emptyGroups = new HashMap(); private final DotStringFactory dotStringFactory; @@ -141,11 +141,11 @@ public class CucaDiagramFileMakerJDot implements CucaDiagramFileMaker { for (Map.Entry ent : nodes.entrySet()) { final ILeaf leaf = ent.getKey(); - final ST_Agnode_s node = ent.getValue(); - final Point2D corner = getCorner(node); + final ST_Agnode_s agnode = ent.getValue(); + final Point2D corner = getCorner(agnode); - final Shape shape = dotStringFactory.getBibliotekon().getShape(leaf); - final IEntityImage image = shape.getImage(); + final Node node = dotStringFactory.getBibliotekon().getNode(leaf); + final IEntityImage image = node.getImage(); image.drawU(ug.apply(new UTranslate(corner))); } @@ -199,7 +199,8 @@ public class CucaDiagramFileMakerJDot implements CucaDiagramFileMaker { final Cluster cluster = dotStringFactory.getBibliotekon().getCluster(group); cluster.setPosition(llx, lly, urx, ury); JUtils.LOG2("cluster=" + cluster); - // ug.apply(new UTranslate(llx, lly)).apply(new UChangeColor(HtmlColorUtils.BLUE)) + // ug.apply(new UTranslate(llx, lly)).apply(new + // UChangeColor(HtmlColorUtils.BLUE)) // .draw(new URectangle(urx - llx, ury - lly)); cluster.drawU(ug, new UStroke(1.5), diagram.getUmlDiagramType(), diagram.getSkinParam()); } @@ -210,21 +211,9 @@ public class CucaDiagramFileMakerJDot implements CucaDiagramFileMaker { continue; } if (diagram.isEmpty(g) && g.getGroupType() == GroupType.PACKAGE) { - final ILeaf folder = diagram.getEntityFactory().createLeaf(g.getIdent(), g.getCode(), g.getDisplay(), - LeafType.EMPTY_PACKAGE, g.getParentContainer(), null, diagram.getNamespaceSeparator()); - emptyGroups.put(g, folder); - final USymbol symbol = g.getUSymbol(); - folder.setUSymbol(symbol); - folder.setStereotype(g.getStereotype()); - if (g.getColors(diagram.getSkinParam()).getColor(ColorType.BACK) == null) { - final ColorParam param = symbol == null ? ColorParam.packageBackground : symbol.getColorParamBack(); - final HtmlColor c1 = diagram.getSkinParam().getHtmlColor(param, g.getStereotype(), false); - folder.setSpecificColorTOBEREMOVED(ColorType.BACK, c1 == null ? diagram.getSkinParam() - .getBackgroundColor() : c1); - } else { - folder.setSpecificColorTOBEREMOVED(ColorType.BACK, - g.getColors(diagram.getSkinParam()).getColor(ColorType.BACK)); - } + final ISkinParam skinParam = diagram.getSkinParam(); + final EntityFactory entityFactory = diagram.getEntityFactory(); + final ILeaf folder = entityFactory.createLeafForEmptyGroup(g, skinParam); printEntityNew(folder); } else { printGroup(g); @@ -261,10 +250,11 @@ public class CucaDiagramFileMakerJDot implements CucaDiagramFileMaker { final int suppWidthBecauseOfShape = uSymbol == null ? 0 : uSymbol.suppWidthBecauseOfShape(); titleAndAttributeWidth = (int) Math.max(dimLabel.getWidth(), attributeWidth) + suppWidthBecauseOfShape; - titleAndAttributeHeight = (int) (dimLabel.getHeight() + attributeHeight + marginForFields + suppHeightBecauseOfShape); + titleAndAttributeHeight = (int) (dimLabel.getHeight() + attributeHeight + marginForFields + + suppHeightBecauseOfShape); } - dotStringFactory.openCluster(g, titleAndAttributeWidth, titleAndAttributeHeight, title, stereo); + dotStringFactory.openCluster(titleAndAttributeWidth, titleAndAttributeHeight, title, stereo, g); this.printEntities(g.getLeafsDirect()); printGroups(g); @@ -291,16 +281,16 @@ public class CucaDiagramFileMakerJDot implements CucaDiagramFileMaker { } private void exportEntity(ST_Agraph_s g, ILeaf leaf) { - final Shape shape = dotStringFactory.getBibliotekon().getShape(leaf); + final Node node = dotStringFactory.getBibliotekon().getNode(leaf); // System.err.println("exportEntity " + leaf); - final ST_Agnode_s node = agnode(g, new CString(shape.getUid()), true); - agsafeset(node, new CString("shape"), new CString("box"), new CString("")); - final String width = "" + (shape.getWidth() / 72); - final String height = "" + (shape.getHeight() / 72); - agsafeset(node, new CString("width"), new CString(width), new CString("")); - agsafeset(node, new CString("height"), new CString(height), new CString("")); + final ST_Agnode_s agnode = agnode(g, new CString(node.getUid()), true); + agsafeset(agnode, new CString("shape"), new CString("box"), new CString("")); + final String width = "" + (node.getWidth() / 72); + final String height = "" + (node.getHeight() / 72); + agsafeset(agnode, new CString("width"), new CString(width), new CString("")); + agsafeset(agnode, new CString("height"), new CString(height), new CString("")); // System.err.println("NODE " + leaf.getUid() + " " + width + " " + height); - nodes.put(leaf, node); + nodes.put(leaf, agnode); } private void printEntity(ILeaf ent) { @@ -308,12 +298,8 @@ public class CucaDiagramFileMakerJDot implements CucaDiagramFileMaker { throw new IllegalStateException(); } final IEntityImage image = printEntityInternal(ent); - final Dimension2D dim = image.calculateDimension(stringBounder); - final Shape shape = new Shape(image, image.getShapeType(), dim.getWidth(), dim.getHeight(), - dotStringFactory.getColorSequence(), ent.isTop(), image.getShield(stringBounder), - ent.getEntityPosition()); - dotStringFactory.addShape(shape); - getBibliotekon().putShape(ent, shape); + final Node node = getBibliotekon().createNode(ent, image, dotStringFactory.getColorSequence(), stringBounder); + dotStringFactory.addNode(node); } private TextBlock getTitleBlock(IGroup g) { @@ -361,15 +347,15 @@ public class CucaDiagramFileMakerJDot implements CucaDiagramFileMaker { } private void printCluster(ST_Agraph_s g, Cluster cluster) { - for (Shape shape : cluster.getShapes()) { - final ST_Agnode_s node = agnode(g, new CString(shape.getUid()), true); - agsafeset(node, new CString("shape"), new CString("box"), new CString("")); - final String width = "" + (shape.getWidth() / 72); - final String height = "" + (shape.getHeight() / 72); - agsafeset(node, new CString("width"), new CString(width), new CString("")); - agsafeset(node, new CString("height"), new CString(height), new CString("")); - final ILeaf leaf = dotStringFactory.getBibliotekon().getLeaf(shape); - nodes.put(leaf, node); + for (Node node : cluster.getNodes()) { + final ST_Agnode_s agnode = agnode(g, new CString(node.getUid()), true); + agsafeset(agnode, new CString("shape"), new CString("box"), new CString("")); + final String width = "" + (node.getWidth() / 72); + final String height = "" + (node.getHeight() / 72); + agsafeset(agnode, new CString("width"), new CString(width), new CString("")); + agsafeset(agnode, new CString("height"), new CString(height), new CString("")); + final ILeaf leaf = dotStringFactory.getBibliotekon().getLeaf(node); + nodes.put(leaf, agnode); } } @@ -411,7 +397,8 @@ public class CucaDiagramFileMakerJDot implements CucaDiagramFileMaker { // agsafeset(node, new CString("height"), new CString(height), new CString("")); // nodes.put(leaf, node); // // System.err - // // .println("NODE " + leaf.getUid() + " [shape=box, width=" + width + ", height=" + height + "]"); + // // .println("NODE " + leaf.getUid() + " [shape=box, width=" + width + ", + // height=" + height + "]"); // } // for (Link link : diagram.getLinks()) { @@ -460,7 +447,8 @@ public class CucaDiagramFileMakerJDot implements CucaDiagramFileMaker { continue; } if (diagram.isEmpty(g) && g.getGroupType() == GroupType.PACKAGE) { - final ILeaf folder = emptyGroups.get(g); + final EntityFactory entityFactory = diagram.getEntityFactory(); + final ILeaf folder = entityFactory.getLeafForEmptyGroup(g); exportEntity(graph, folder); } else { exportGroup(graph, g); @@ -476,8 +464,8 @@ public class CucaDiagramFileMakerJDot implements CucaDiagramFileMaker { if (cluster.isLabel()) { final double width = cluster.getTitleAndAttributeWidth(); final double height = cluster.getTitleAndAttributeHeight() - 5; - agsafeset(cluster1, new CString("label"), - Macro.createHackInitDimensionFromLabel((int) width, (int) height), new CString("")); + agsafeset(cluster1, new CString("label"), Macro.createHackInitDimensionFromLabel((int) width, (int) height), + new CString("")); } this.exportEntities(cluster1, group.getLeafsDirect()); this.clusters.put(group, cluster1); @@ -517,9 +505,9 @@ public class CucaDiagramFileMakerJDot implements CucaDiagramFileMaker { if (n != null) { return n; } - final String id = getBibliotekon().getShapeUid((ILeaf) entity); + final String id = getBibliotekon().getNodeUid((ILeaf) entity); for (Map.Entry ent : nodes.entrySet()) { - if (id.equals(getBibliotekon().getShapeUid(ent.getKey()))) { + if (id.equals(getBibliotekon().getNodeUid(ent.getKey()))) { return ent.getValue(); } } @@ -543,10 +531,12 @@ public class CucaDiagramFileMakerJDot implements CucaDiagramFileMaker { int length = link.getLength(); // System.err.println("length=" + length); - // if (/* pragma.horizontalLineBetweenDifferentPackageAllowed() || */link.isInvis() || length != 1) { + // if (/* pragma.horizontalLineBetweenDifferentPackageAllowed() || + // */link.isInvis() || length != 1) { agsafeset(e, new CString("minlen"), new CString("" + (length - 1)), new CString("")); // } - // System.err.print("EDGE " + link.getEntity1().getUid() + "->" + link.getEntity2().getUid() + " minlen=" + // System.err.print("EDGE " + link.getEntity1().getUid() + "->" + + // link.getEntity2().getUid() + " minlen=" // + (length - 1) + " "); final TextBlock label = getLabel(link); @@ -600,12 +590,8 @@ public class CucaDiagramFileMakerJDot implements CucaDiagramFileMaker { throw new IllegalStateException(); } final IEntityImage image = printEntityInternal(ent); - final Dimension2D dim = image.calculateDimension(stringBounder); - final Shape shape = new Shape(image, image.getShapeType(), dim.getWidth(), dim.getHeight(), - dotStringFactory.getColorSequence(), ent.isTop(), image.getShield(stringBounder), - ent.getEntityPosition()); + final Node shape = getBibliotekon().createNode(ent, image, dotStringFactory.getColorSequence(), stringBounder); // dotStringFactory.addShape(shape); - getBibliotekon().putShape(ent, shape); } private Bibliotekon getBibliotekon() { diff --git a/src/net/sourceforge/plantuml/objectdiagram/ObjectDiagramFactory.java b/src/net/sourceforge/plantuml/objectdiagram/ObjectDiagramFactory.java index c01efadd7..e0ccf25a6 100644 --- a/src/net/sourceforge/plantuml/objectdiagram/ObjectDiagramFactory.java +++ b/src/net/sourceforge/plantuml/objectdiagram/ObjectDiagramFactory.java @@ -49,9 +49,9 @@ import net.sourceforge.plantuml.command.CommandPackage; import net.sourceforge.plantuml.command.CommandPage; import net.sourceforge.plantuml.command.CommandRankDir; import net.sourceforge.plantuml.command.UmlDiagramFactory; -import net.sourceforge.plantuml.command.note.FactoryNoteCommand; -import net.sourceforge.plantuml.command.note.FactoryNoteOnEntityCommand; -import net.sourceforge.plantuml.command.note.FactoryNoteOnLinkCommand; +import net.sourceforge.plantuml.command.note.CommandFactoryNote; +import net.sourceforge.plantuml.command.note.CommandFactoryNoteOnEntity; +import net.sourceforge.plantuml.command.note.CommandFactoryNoteOnLink; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.objectdiagram.command.CommandAddData; import net.sourceforge.plantuml.objectdiagram.command.CommandCreateEntityObject; @@ -78,7 +78,7 @@ public class ObjectDiagramFactory extends UmlDiagramFactory { cmds.add(new CommandLinkClass(UmlDiagramType.OBJECT)); // cmds.add(new CommandCreateEntityObject()); - final FactoryNoteCommand factoryNoteCommand = new FactoryNoteCommand(); + final CommandFactoryNote factoryNoteCommand = new CommandFactoryNote(); cmds.add(factoryNoteCommand.createSingleLine()); cmds.add(new CommandPackage()); @@ -88,7 +88,7 @@ public class ObjectDiagramFactory extends UmlDiagramFactory { // addCommand(new CommandStereotype()); // // addCommand(new CommandImport()); - final FactoryNoteOnEntityCommand factoryNoteOnEntityCommand = new FactoryNoteOnEntityCommand("object", + final CommandFactoryNoteOnEntity factoryNoteOnEntityCommand = new CommandFactoryNoteOnEntity("object", new RegexLeaf("ENTITY", "([\\p{L}0-9_.]+|[%g][^%g]+[%g])")); cmds.add(factoryNoteOnEntityCommand.createSingleLine()); @@ -99,7 +99,7 @@ public class ObjectDiagramFactory extends UmlDiagramFactory { cmds.add(factoryNoteOnEntityCommand.createMultiLine(false)); cmds.add(new CommandCreateEntityObjectMultilines()); - final FactoryNoteOnLinkCommand factoryNoteOnLinkCommand = new FactoryNoteOnLinkCommand(); + final CommandFactoryNoteOnLink factoryNoteOnLinkCommand = new CommandFactoryNoteOnLink(); cmds.add(factoryNoteOnLinkCommand.createSingleLine()); cmds.add(factoryNoteOnLinkCommand.createMultiLine(false)); diff --git a/src/net/sourceforge/plantuml/posimo/DotPath.java b/src/net/sourceforge/plantuml/posimo/DotPath.java index 88442609e..49016688d 100644 --- a/src/net/sourceforge/plantuml/posimo/DotPath.java +++ b/src/net/sourceforge/plantuml/posimo/DotPath.java @@ -45,9 +45,11 @@ import java.awt.geom.Rectangle2D; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import net.sourceforge.plantuml.EnsureVisible; import net.sourceforge.plantuml.asciiart.BasicCharArea; @@ -168,6 +170,29 @@ public class DotPath implements UShape, Moveable { return beziers.get(0).getP1(); } + public Set sample() { + final Set result = new HashSet(); + for (CubicCurve2D.Double bez : beziers) { + sample(bez, result); + } + return Collections.unmodifiableSet(result); + } + + private static void sample(CubicCurve2D bez, Set result) { + final Point2D p1 = bez.getCtrlP1(); + final Point2D p2 = bez.getCtrlP2(); + if (bez.getFlatnessSq() > 0.5 || p1.distance(p2) > 4) { + final CubicCurve2D.Double left = new CubicCurve2D.Double(); + final CubicCurve2D.Double right = new CubicCurve2D.Double(); + bez.subdivide(left, right); + sample(left, result); + sample(right, result); + } else { + result.add(p1); + result.add(p2); + } + } + public PointAndAngle getMiddle() { Point2D result = null; double angle = 0; @@ -361,8 +386,8 @@ public class DotPath implements UShape, Moveable { public void draw(Graphics2D g2d, double x, double y) { final GeneralPath p = new GeneralPath(); for (CubicCurve2D.Double bez : beziers) { - bez = new CubicCurve2D.Double(x + bez.x1, y + bez.y1, x + bez.ctrlx1, y + bez.ctrly1, x + bez.ctrlx2, y - + bez.ctrly2, x + bez.x2, y + bez.y2); + bez = new CubicCurve2D.Double(x + bez.x1, y + bez.y1, x + bez.ctrlx1, y + bez.ctrly1, x + bez.ctrlx2, + y + bez.ctrly2, x + bez.x2, y + bez.y2); p.append(bez, true); } g2d.draw(p); @@ -379,8 +404,8 @@ public class DotPath implements UShape, Moveable { public void drawOk(EpsGraphics eps, double x, double y) { // boolean first = true; for (CubicCurve2D.Double bez : beziers) { - bez = new CubicCurve2D.Double(x + bez.x1, y + bez.y1, x + bez.ctrlx1, y + bez.ctrly1, x + bez.ctrlx2, y - + bez.ctrly2, x + bez.x2, y + bez.y2); + bez = new CubicCurve2D.Double(x + bez.x1, y + bez.y1, x + bez.ctrlx1, y + bez.ctrly1, x + bez.ctrlx2, + y + bez.ctrly2, x + bez.x2, y + bez.y2); eps.epsLine(bez.x1, bez.y1, bez.x2, bez.y2); } } @@ -390,8 +415,8 @@ public class DotPath implements UShape, Moveable { final boolean dashed = false; boolean first = true; for (CubicCurve2D.Double bez : beziers) { - bez = new CubicCurve2D.Double(x + bez.x1, y + bez.y1, x + bez.ctrlx1, y + bez.ctrly1, x + bez.ctrlx2, y - + bez.ctrly2, x + bez.x2, y + bez.y2); + bez = new CubicCurve2D.Double(x + bez.x1, y + bez.y1, x + bez.ctrlx1, y + bez.ctrly1, x + bez.ctrlx2, + y + bez.ctrly2, x + bez.x2, y + bez.y2); if (first) { eps.movetoNoMacro(bez.x1, bez.y1); first = dashed; @@ -504,14 +529,14 @@ public class DotPath implements UShape, Moveable { area.drawHLine('-', (int) (bez.y1 / pixelYPerChar), (int) (bez.x1 / pixelXPerChar), (int) (bez.x2 / pixelXPerChar)); } /* - * else { throw new UnsupportedOperationException("bez=" + toString(bez)); } - */ + * else { throw new UnsupportedOperationException("bez=" + toString(bez)); } + */ } } static String toString(CubicCurve2D.Double c) { - return "(" + c.x1 + "," + c.y1 + ") " + "(" + c.ctrlx1 + "," + c.ctrly1 + ") " + "(" + c.ctrlx2 + "," - + c.ctrly2 + ") " + "(" + c.x2 + "," + c.y2 + ") "; + return "(" + c.x1 + "," + c.y1 + ") " + "(" + c.ctrlx1 + "," + c.ctrly1 + ") " + "(" + c.ctrlx2 + "," + c.ctrly2 + + ") " + "(" + c.x2 + "," + c.y2 + ") "; } @@ -526,8 +551,8 @@ public class DotPath implements UShape, Moveable { } public static CubicCurve2D.Double reverse(CubicCurve2D curv) { - return new CubicCurve2D.Double(curv.getX2(), curv.getY2(), curv.getCtrlX2(), curv.getCtrlY2(), - curv.getCtrlX1(), curv.getCtrlY1(), curv.getX1(), curv.getY1()); + return new CubicCurve2D.Double(curv.getX2(), curv.getY2(), curv.getCtrlX2(), curv.getCtrlY2(), curv.getCtrlX1(), + curv.getCtrlY1(), curv.getX1(), curv.getY1()); } public DotPath reverse() { diff --git a/src/net/sourceforge/plantuml/preproc/Stdlib.java b/src/net/sourceforge/plantuml/preproc/Stdlib.java index b29047a22..1332fc3aa 100644 --- a/src/net/sourceforge/plantuml/preproc/Stdlib.java +++ b/src/net/sourceforge/plantuml/preproc/Stdlib.java @@ -56,7 +56,7 @@ public class Stdlib { } } - private static Stdlib retrieve(final String name) throws IOException { + public static Stdlib retrieve(final String name) throws IOException { Stdlib result = all.get(name); if (result == null) { final DataInputStream dataStream = getDataStream(name); @@ -222,7 +222,7 @@ public class Stdlib { public static void extractStdLib() throws IOException { for (String name : getAll()) { final Stdlib folder = Stdlib.retrieve(name); - folder.extractMeFull(new File("stdlib", name)); + folder.extractMeFull(); } } @@ -237,7 +237,7 @@ public class Stdlib { return Collections.unmodifiableCollection(result); } - private void extractMeFull(File dir) throws IOException { + private void extractMeFull() throws IOException { final DataInputStream dataStream = getDataStream(); if (dataStream == null) { return; @@ -280,6 +280,46 @@ public class Stdlib { } } + public List extractAllSprites() throws IOException { + final List result = new ArrayList(); + final DataInputStream dataStream = getDataStream(); + if (dataStream == null) { + return Collections.unmodifiableList(result); + } + dataStream.readUTF(); + final InputStream spriteStream = getSpriteStream(); + try { + while (true) { + final String filename = dataStream.readUTF(); + if (filename.equals(SEPARATOR)) { + return Collections.unmodifiableList(result); + } + while (true) { + final String s = dataStream.readUTF(); + if (s.equals(SEPARATOR)) { + break; + } + if (isSpriteLine(s)) { + final Matcher m = sizePattern.matcher(s); + final boolean ok = m.find(); + if (ok == false) { + throw new IOException(s); + } + final int width = Integer.parseInt(m.group(1)); + final int height = Integer.parseInt(m.group(2)); + final String sprite = readSprite(width, height, spriteStream); + if (s.contains("_LARGE") == false) { + result.add(s + "\n" + sprite + "}"); + } + } + } + } + } finally { + dataStream.close(); + spriteStream.close(); + } + } + public static void addInfoVersion(List strings, boolean details) { try { for (String name : getAll()) { diff --git a/src/net/sourceforge/plantuml/project3/Arrows.java b/src/net/sourceforge/plantuml/project/Arrows.java similarity index 98% rename from src/net/sourceforge/plantuml/project3/Arrows.java rename to src/net/sourceforge/plantuml/project/Arrows.java index afa770a6c..521087deb 100644 --- a/src/net/sourceforge/plantuml/project3/Arrows.java +++ b/src/net/sourceforge/plantuml/project/Arrows.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project; import net.sourceforge.plantuml.Direction; import net.sourceforge.plantuml.ugraphic.UPolygon; diff --git a/src/net/sourceforge/plantuml/project3/Resources.java b/src/net/sourceforge/plantuml/project/Completion.java similarity index 76% rename from src/net/sourceforge/plantuml/project3/Resources.java rename to src/net/sourceforge/plantuml/project/Completion.java index d1159e667..7158898de 100644 --- a/src/net/sourceforge/plantuml/project3/Resources.java +++ b/src/net/sourceforge/plantuml/project/Completion.java @@ -33,21 +33,20 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project; -import java.util.LinkedHashSet; -import java.util.Set; +import net.sourceforge.plantuml.project.lang.Complement; -public class Resources /*implements LoadPlanable*/ { +public class Completion implements Complement { - private final Set all = new LinkedHashSet(); + private final int completion; -// public int getLoadAt(Instant instant) { -// int result = 0; -// for (Resource res : all) { -// result += res.getLoadAt(instant); -// } -// return result; -// } + public Completion(int completion) { + this.completion = completion; + } + + public final int getCompletion() { + return completion; + } } diff --git a/src/net/sourceforge/plantuml/project3/ConstantPlan.java b/src/net/sourceforge/plantuml/project/ConstantPlan.java similarity index 92% rename from src/net/sourceforge/plantuml/project3/ConstantPlan.java rename to src/net/sourceforge/plantuml/project/ConstantPlan.java index 078ef64dd..0703b2efb 100644 --- a/src/net/sourceforge/plantuml/project3/ConstantPlan.java +++ b/src/net/sourceforge/plantuml/project/ConstantPlan.java @@ -33,7 +33,9 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project; + +import net.sourceforge.plantuml.project.core.Wink; public class ConstantPlan implements LoadPlanable { @@ -51,7 +53,7 @@ public class ConstantPlan implements LoadPlanable { return new ConstantPlan(load); } - public int getLoadAt(Instant instant) { + public int getLoadAt(Wink instant) { return loadPerInstant; } diff --git a/src/net/sourceforge/plantuml/project3/DayAsDate.java b/src/net/sourceforge/plantuml/project/DayAsDate.java similarity index 74% rename from src/net/sourceforge/plantuml/project3/DayAsDate.java rename to src/net/sourceforge/plantuml/project/DayAsDate.java index 0a1d0ffc9..a9b0b97e3 100644 --- a/src/net/sourceforge/plantuml/project3/DayAsDate.java +++ b/src/net/sourceforge/plantuml/project/DayAsDate.java @@ -33,10 +33,15 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project; import java.util.Date; +import net.sourceforge.plantuml.project.core.Month; +import net.sourceforge.plantuml.project.core.Wink; +import net.sourceforge.plantuml.project.lang.Complement; +import net.sourceforge.plantuml.project.lang.Subject; + public class DayAsDate implements Complement, Comparable, Subject { private final int year; @@ -65,6 +70,10 @@ public class DayAsDate implements Complement, Comparable, Subject { this.month = month; } + public int getYear() { + return year; + } + private int internalNumber() { return year * 100 * 100 + month.ordinal() * 100 + dayOfMonth; } @@ -120,7 +129,7 @@ public class DayAsDate implements Complement, Comparable, Subject { return DayOfWeek.fromH(h); } - public InstantDay asInstantDay(DayAsDate reference) { + public Wink asInstantDay(DayAsDate reference) { // if (this.compareTo(reference) < 0) { // throw new IllegalArgumentException(); // } @@ -130,7 +139,39 @@ public class DayAsDate implements Complement, Comparable, Subject { current = current.next(); cmp++; } - return new InstantDay(cmp); + return new Wink(cmp); + } + + // http://www.proesite.com/timex/wkcalc.htm + public int ISO_WN() { + final int y = year; + int m = month.ordinal() + 1; + int d = dayOfMonth; + int dow = DOW(y, m, d); + int dow0101 = DOW(y, 1, 1); + + if (m == 1 && 3 < dow0101 && dow0101 < 7 - (d - 1)) { + // days before week 1 of the current year have the same week number as + // the last day of the last week of the previous year + + dow = dow0101 - 1; + dow0101 = DOW(y - 1, 1, 1); + m = 12; + d = 31; + } else if (m == 12 && 30 - (d - 1) < DOW(y + 1, 1, 1) && DOW(y + 1, 1, 1) < 4) { + // days after the last week of the current year have the same week number as + // the first day of the next year, (i.e. 1) + + return 1; + } + + return (DOW(y, 1, 1) < 4) ? 1 : 0 + 4 * (m - 1) + (2 * (m - 1) + (d - 1) + dow0101 - dow + 6) * 36 / 256; + + } + + private int DOW(int y, int m, int d) { + // TODO Auto-generated method stub + return 0; } public int compareTo(DayAsDate other) { diff --git a/src/net/sourceforge/plantuml/project3/DayOfWeek.java b/src/net/sourceforge/plantuml/project/DayOfWeek.java similarity index 93% rename from src/net/sourceforge/plantuml/project3/DayOfWeek.java rename to src/net/sourceforge/plantuml/project/DayOfWeek.java index 54af9a75b..37bcdb160 100644 --- a/src/net/sourceforge/plantuml/project3/DayOfWeek.java +++ b/src/net/sourceforge/plantuml/project/DayOfWeek.java @@ -33,9 +33,11 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project; import net.sourceforge.plantuml.StringUtils; +import net.sourceforge.plantuml.project.lang.Complement; +import net.sourceforge.plantuml.project.lang.Subject; public enum DayOfWeek implements Subject, Complement { diff --git a/src/net/sourceforge/plantuml/project3/DaysAsDates.java b/src/net/sourceforge/plantuml/project/DaysAsDates.java similarity index 93% rename from src/net/sourceforge/plantuml/project3/DaysAsDates.java rename to src/net/sourceforge/plantuml/project/DaysAsDates.java index abf96514c..612b68c1e 100644 --- a/src/net/sourceforge/plantuml/project3/DaysAsDates.java +++ b/src/net/sourceforge/plantuml/project/DaysAsDates.java @@ -33,10 +33,13 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project; import java.util.Iterator; +import net.sourceforge.plantuml.project.lang.Complement; +import net.sourceforge.plantuml.project.lang.Subject; + public class DaysAsDates implements Subject, Complement, Iterable { private final DayAsDate date1; diff --git a/src/net/sourceforge/plantuml/project3/Failable.java b/src/net/sourceforge/plantuml/project/Failable.java similarity index 97% rename from src/net/sourceforge/plantuml/project3/Failable.java rename to src/net/sourceforge/plantuml/project/Failable.java index 1263f66b6..482f1cdb2 100644 --- a/src/net/sourceforge/plantuml/project3/Failable.java +++ b/src/net/sourceforge/plantuml/project/Failable.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project; public class Failable { diff --git a/src/net/sourceforge/plantuml/project3/GCalendarSimple.java b/src/net/sourceforge/plantuml/project/GCalendar.java similarity index 84% rename from src/net/sourceforge/plantuml/project3/GCalendarSimple.java rename to src/net/sourceforge/plantuml/project/GCalendar.java index 349c638e5..05090b701 100644 --- a/src/net/sourceforge/plantuml/project3/GCalendarSimple.java +++ b/src/net/sourceforge/plantuml/project/GCalendar.java @@ -33,19 +33,21 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project; -public class GCalendarSimple implements GCalendar { +import net.sourceforge.plantuml.project.core.Wink; + +public class GCalendar { private final DayAsDate start; - public GCalendarSimple(DayAsDate start) { + public GCalendar(DayAsDate start) { this.start = start; } - public DayAsDate toDayAsDate(InstantDay day) { + public DayAsDate toDayAsDate(Wink day) { DayAsDate result = start; - final int target = day.getNumDay(); + final int target = day.getWink(); int work = 0; while (work < target) { result = result.next(); @@ -54,11 +56,11 @@ public class GCalendarSimple implements GCalendar { return result; } - public InstantDay fromDayAsDate(DayAsDate day) { + public Wink fromDayAsDate(DayAsDate day) { if (day.compareTo(start) < 0) { throw new IllegalArgumentException(); } - InstantDay result = new InstantDay(0); + Wink result = new Wink(0); while (toDayAsDate(result).equals(day) == false) { result = result.increment(); } diff --git a/src/net/sourceforge/plantuml/project3/GanttArrow.java b/src/net/sourceforge/plantuml/project/GanttArrow.java similarity index 92% rename from src/net/sourceforge/plantuml/project3/GanttArrow.java rename to src/net/sourceforge/plantuml/project/GanttArrow.java index f8f0842e6..e5390b1c3 100644 --- a/src/net/sourceforge/plantuml/project3/GanttArrow.java +++ b/src/net/sourceforge/plantuml/project/GanttArrow.java @@ -33,11 +33,16 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project; import net.sourceforge.plantuml.Direction; import net.sourceforge.plantuml.graphic.HtmlColorUtils; import net.sourceforge.plantuml.graphic.UDrawable; +import net.sourceforge.plantuml.project.core.Task; +import net.sourceforge.plantuml.project.core.TaskAttribute; +import net.sourceforge.plantuml.project.core.TaskInstant; +import net.sourceforge.plantuml.project.draw.TaskDraw; +import net.sourceforge.plantuml.project.timescale.TimeScale; import net.sourceforge.plantuml.ugraphic.UChangeBackColor; import net.sourceforge.plantuml.ugraphic.UChangeColor; import net.sourceforge.plantuml.ugraphic.UGraphic; @@ -88,6 +93,10 @@ public class GanttArrow implements UDrawable { final double x2 = getX(dest, atEnd.getInv()); final double y2 = draw2.getY(atEnd); + if (atStart == Direction.DOWN && y2 < y1) { + y1 = draw1.getY(atStart.getInv()); + } + if (this.atStart == Direction.DOWN && this.atEnd == Direction.RIGHT) { if (x2 > x1) { drawLine(ug, x1, y1, x1, y2, x2, y2); diff --git a/src/net/sourceforge/plantuml/project3/GanttConstraint.java b/src/net/sourceforge/plantuml/project/GanttConstraint.java similarity index 88% rename from src/net/sourceforge/plantuml/project3/GanttConstraint.java rename to src/net/sourceforge/plantuml/project/GanttConstraint.java index a5bbf5db0..19c1566a0 100644 --- a/src/net/sourceforge/plantuml/project3/GanttConstraint.java +++ b/src/net/sourceforge/plantuml/project/GanttConstraint.java @@ -33,9 +33,12 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project; import net.sourceforge.plantuml.graphic.UDrawable; +import net.sourceforge.plantuml.project.core.TaskInstant; +import net.sourceforge.plantuml.project.lang.Complement; +import net.sourceforge.plantuml.project.timescale.TimeScale; public class GanttConstraint implements Complement { diff --git a/src/net/sourceforge/plantuml/project3/GanttDiagram.java b/src/net/sourceforge/plantuml/project/GanttDiagram.java similarity index 63% rename from src/net/sourceforge/plantuml/project3/GanttDiagram.java rename to src/net/sourceforge/plantuml/project/GanttDiagram.java index b22f34344..6c6a66516 100644 --- a/src/net/sourceforge/plantuml/project3/GanttDiagram.java +++ b/src/net/sourceforge/plantuml/project/GanttDiagram.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project; import java.awt.geom.Dimension2D; import java.awt.geom.Rectangle2D; @@ -55,15 +55,11 @@ import net.sourceforge.plantuml.Dimension2DDouble; import net.sourceforge.plantuml.FileFormatOption; import net.sourceforge.plantuml.Scale; import net.sourceforge.plantuml.SkinParam; -import net.sourceforge.plantuml.SpriteContainerEmpty; import net.sourceforge.plantuml.TitledDiagram; import net.sourceforge.plantuml.UmlDiagramType; import net.sourceforge.plantuml.command.CommandExecutionResult; import net.sourceforge.plantuml.core.DiagramDescription; import net.sourceforge.plantuml.core.ImageData; -import net.sourceforge.plantuml.cucadiagram.Display; -import net.sourceforge.plantuml.graphic.FontConfiguration; -import net.sourceforge.plantuml.graphic.HorizontalAlignment; import net.sourceforge.plantuml.graphic.HtmlColor; import net.sourceforge.plantuml.graphic.HtmlColorSetSimple; import net.sourceforge.plantuml.graphic.HtmlColorUtils; @@ -71,16 +67,33 @@ import net.sourceforge.plantuml.graphic.IHtmlColorSet; import net.sourceforge.plantuml.graphic.InnerStrategy; import net.sourceforge.plantuml.graphic.StringBounder; import net.sourceforge.plantuml.graphic.TextBlock; +import net.sourceforge.plantuml.project.core.Moment; +import net.sourceforge.plantuml.project.core.MomentImpl; +import net.sourceforge.plantuml.project.core.PrintScale; +import net.sourceforge.plantuml.project.core.Resource; +import net.sourceforge.plantuml.project.core.Task; +import net.sourceforge.plantuml.project.core.TaskAttribute; +import net.sourceforge.plantuml.project.core.TaskCode; +import net.sourceforge.plantuml.project.core.TaskImpl; +import net.sourceforge.plantuml.project.core.TaskInstant; +import net.sourceforge.plantuml.project.core.TaskSeparator; +import net.sourceforge.plantuml.project.core.Wink; +import net.sourceforge.plantuml.project.draw.ResourceDraw; +import net.sourceforge.plantuml.project.draw.TaskDraw; +import net.sourceforge.plantuml.project.draw.TaskDrawRegular; +import net.sourceforge.plantuml.project.draw.TaskDrawSeparator; +import net.sourceforge.plantuml.project.draw.TimeHeader; +import net.sourceforge.plantuml.project.draw.TimeHeaderDaily; +import net.sourceforge.plantuml.project.draw.TimeHeaderSimple; +import net.sourceforge.plantuml.project.draw.TimeHeaderWeekly; +import net.sourceforge.plantuml.project.lang.ComplementColors; +import net.sourceforge.plantuml.project.lang.Subject; +import net.sourceforge.plantuml.project.timescale.TimeScale; import net.sourceforge.plantuml.svek.TextBlockBackcolored; import net.sourceforge.plantuml.ugraphic.ColorMapperIdentity; import net.sourceforge.plantuml.ugraphic.ImageBuilder; import net.sourceforge.plantuml.ugraphic.MinMax; -import net.sourceforge.plantuml.ugraphic.UChangeBackColor; -import net.sourceforge.plantuml.ugraphic.UChangeColor; -import net.sourceforge.plantuml.ugraphic.UFont; import net.sourceforge.plantuml.ugraphic.UGraphic; -import net.sourceforge.plantuml.ugraphic.ULine; -import net.sourceforge.plantuml.ugraphic.URectangle; import net.sourceforge.plantuml.ugraphic.UTranslate; public class GanttDiagram extends TitledDiagram implements Subject { @@ -89,13 +102,24 @@ public class GanttDiagram extends TitledDiagram implements Subject { private final Map byShortName = new HashMap(); private final List constraints = new ArrayList(); private final IHtmlColorSet colorSet = new HtmlColorSetSimple(); + private final Collection closedDayOfWeek = EnumSet.noneOf(DayOfWeek.class); private final Collection closedDayAsDate = new HashSet(); private final Collection openedDayAsDate = new HashSet(); - private GCalendar calendar; - private final Instant min = new InstantDay(0); - private Instant max; + private final Map resources = new LinkedHashMap(); + private final Map colorDays = new HashMap(); + private final Map nameDays = new HashMap(); + + private PrintScale printScale = PrintScale.DAILY; + private DayAsDate today; + private GCalendar calendar; + private double totalHeight; + private Wink min = new Wink(0); + private Wink max; + + private DayAsDate printStart; + private DayAsDate printEnd; public DiagramDescription getDescription() { return new DiagramDescription("(Project)"); @@ -148,16 +172,35 @@ public class GanttDiagram extends TitledDiagram implements Subject { return imageBuilder.writeImageTOBEMOVED(fileFormatOption, seed, os); } + public void setPrintScale(PrintScale printScale) { + this.printScale = printScale; + } + private TextBlockBackcolored getTextBlock() { - initMinMax(); - final TimeScale timeScale = getTimeScale(); - initTaskAndResourceDraws(timeScale); + if (printStart == null) { + initMinMax(); + } else { + this.min = calendar.fromDayAsDate(printStart); + this.max = calendar.fromDayAsDate(printEnd); + } + final TimeHeader timeHeader; + if (calendar == null) { + timeHeader = new TimeHeaderSimple(min, max); + } else if (printScale == PrintScale.WEEKLY) { + timeHeader = new TimeHeaderWeekly(calendar, min, max, getDefaultPlan(), colorDays, nameDays); + } else { + timeHeader = new TimeHeaderDaily(calendar, min, max, getDefaultPlan(), colorDays, nameDays, printStart, + printEnd); + } + initTaskAndResourceDraws(timeHeader.getTimeScale(), timeHeader.getFullHeaderHeight()); return new TextBlockBackcolored() { public void drawU(UGraphic ug) { - drawTimeHeader(ug, timeScale); - drawTasks(ug, timeScale); - drawConstraints(ug, timeScale); + timeHeader.drawTimeHeader(ug, totalHeight); + drawConstraints(ug, timeHeader.getTimeScale()); + drawTasksRect(ug); + drawTasksTitle(ug); + drawResources(ug); } public Rectangle2D getInnerPosition(String member, StringBounder stringBounder, InnerStrategy strategy) { @@ -165,8 +208,8 @@ public class GanttDiagram extends TitledDiagram implements Subject { } public Dimension2D calculateDimension(StringBounder stringBounder) { - final double xmin = timeScale.getStartingPosition(min); - final double xmax = timeScale.getEndingPosition(max); + final double xmin = timeHeader.getTimeScale().getStartingPosition(min); + final double xmax = timeHeader.getTimeScale().getEndingPosition(max); return new Dimension2DDouble(xmax - xmin, totalHeight); } @@ -180,25 +223,43 @@ public class GanttDiagram extends TitledDiagram implements Subject { }; } - private TimeScale getTimeScale() { - if (calendar == null) { - return new TimeScaleBasic(); + private void drawTasksRect(UGraphic ug) { + for (Task task : tasks.values()) { + final TaskDraw draw = task.getTaskDraw(); + final UTranslate move = new UTranslate(0, draw.getY()); + draw.drawU(ug.apply(move)); } - return new TimeScaleBasic2(getCalendarSimple()); - // return new TimeScaleWithoutWeekEnd(calendar); } - private GCalendarSimple getCalendarSimple() { - return (GCalendarSimple) calendar; + private void drawConstraints(final UGraphic ug, TimeScale timeScale) { + for (GanttConstraint constraint : constraints) { + constraint.getUDrawable(timeScale).drawU(ug); + } + } + + private void drawTasksTitle(final UGraphic ug1) { + for (Task task : tasks.values()) { + final TaskDraw draw = task.getTaskDraw(); + final UTranslate move = new UTranslate(0, draw.getY()); + draw.drawTitle(ug1.apply(move)); + } + } + + private void drawResources(UGraphic ug) { + for (Resource res : resources.values()) { + final ResourceDraw draw = res.getResourceDraw(); + final UTranslate move = new UTranslate(0, draw.getY()); + draw.drawU(ug.apply(move)); + } } public final LoadPlanable getDefaultPlan() { return new LoadPlanable() { - public int getLoadAt(Instant instant) { + public int getLoadAt(Wink instant) { if (calendar == null) { return 100; } - final DayAsDate day = getCalendarSimple().toDayAsDate((InstantDay) instant); + final DayAsDate day = calendar.toDayAsDate((Wink) instant); if (isClosed(day)) { return 0; } @@ -227,152 +288,8 @@ public class GanttDiagram extends TitledDiagram implements Subject { openedDayAsDate.add(day); } - private void drawConstraints(final UGraphic ug, TimeScale timeScale) { - for (GanttConstraint constraint : constraints) { - constraint.getUDrawable(timeScale).drawU(ug); - } - - } - - private double totalHeight; - - private void drawTimeHeader(final UGraphic ug, TimeScale timeScale) { - - final double xmin = timeScale.getStartingPosition(min); - final double xmax = timeScale.getEndingPosition(max); - if (calendar == null) { - drawSimpleDayCounter(ug, timeScale); - } else { - drawCalendar(ug, timeScale); - } - ug.apply(new UChangeColor(HtmlColorUtils.LIGHT_GRAY)).draw(new ULine(xmax - xmin, 0)); - ug.apply(new UChangeColor(HtmlColorUtils.LIGHT_GRAY)).apply(new UTranslate(0, getHeaderHeight() - 3)) - .draw(new ULine(xmax - xmin, 0)); - - } - - private final HtmlColor veryLightGray = new HtmlColorSetSimple().getColorIfValid("#E0E8E8"); - - private double getHeaderHeight() { - return getTimeHeaderHeight() + getHeaderNameDayHeight(); - } - - private double getTimeHeaderHeight() { - if (calendar != null) { - return Y_WEEKDAY + Y_NUMDAY; - } - return 16; - } - - private double getHeaderNameDayHeight() { - if (calendar != null && nameDays.size() > 0) { - return 16; - } - return 0; - } - - private static final int Y_WEEKDAY = 16; - private static final int Y_NUMDAY = 28; - - private void drawCalendar(final UGraphic ug, TimeScale timeScale) { - timeScale = new TimeScaleBasic(); - final ULine vbar = new ULine(0, totalHeight - Y_WEEKDAY); - Month lastMonth = null; - final GCalendarSimple calendarAll = getCalendarSimple(); - final Instant max2 = calendarAll.fromDayAsDate(calendar.toDayAsDate((InstantDay) max)); - for (Instant i = min; i.compareTo(max2.increment()) <= 0; i = i.increment()) { - final DayAsDate day = calendarAll.toDayAsDate((InstantDay) i); - final DayOfWeek dayOfWeek = day.getDayOfWeek(); - final boolean isWorkingDay = getDefaultPlan().getLoadAt(i) > 0; - final String d1 = "" + day.getDayOfMonth(); - final TextBlock num = getTextBlock(d1, 10, false); - final double x1 = timeScale.getStartingPosition(i); - final double x2 = timeScale.getEndingPosition(i); - if (i.compareTo(max2.increment()) < 0) { - final TextBlock weekDay = getTextBlock(dayOfWeek.shortName(), 10, false); - - final URectangle rect = new URectangle(x2 - x1 - 1, totalHeight - Y_WEEKDAY); - if (isWorkingDay) { - final HtmlColor back = colorDays.get(day); - if (back != null) { - ug.apply(new UChangeColor(null)).apply(new UChangeBackColor(back)) - .apply(new UTranslate(x1 + 1, Y_WEEKDAY)).draw(rect); - } - drawCenter(ug.apply(new UTranslate(0, Y_NUMDAY)), num, x1, x2); - drawCenter(ug.apply(new UTranslate(0, Y_WEEKDAY)), weekDay, x1, x2); - } else { - ug.apply(new UChangeColor(null)).apply(new UChangeBackColor(veryLightGray)) - .apply(new UTranslate(x1 + 1, Y_WEEKDAY)).draw(rect); - } - if (lastMonth != day.getMonth()) { - final int delta = 5; - if (lastMonth != null) { - final TextBlock lastMonthBlock = getTextBlock(lastMonth.name(), 12, true); - lastMonthBlock.drawU(ug.apply(new UTranslate(x1 - - lastMonthBlock.calculateDimension(ug.getStringBounder()).getWidth() - delta, 0))); - } - final TextBlock month = getTextBlock(day.getMonth().name(), 12, true); - month.drawU(ug.apply(new UTranslate(x1 + delta, 0))); - ug.apply(new UChangeColor(HtmlColorUtils.LIGHT_GRAY)).apply(new UTranslate(x1, 0)) - .draw(new ULine(0, Y_WEEKDAY)); - } - lastMonth = day.getMonth(); - } - ug.apply(new UChangeColor(HtmlColorUtils.LIGHT_GRAY)).apply(new UTranslate(x1, Y_WEEKDAY)).draw(vbar); - } - - if (nameDays.size() > 0) { - String last = null; - for (Instant i = min; i.compareTo(max2.increment()) <= 0; i = i.increment()) { - final DayAsDate day = calendarAll.toDayAsDate((InstantDay) i); - final String name = nameDays.get(day); - if (name != null && name.equals(last) == false) { - final double x1 = timeScale.getStartingPosition(i); - final double x2 = timeScale.getEndingPosition(i); - final TextBlock label = getTextBlock(name, 12, false); - final double h = label.calculateDimension(ug.getStringBounder()).getHeight(); - double y1 = getTimeHeaderHeight(); - double y2 = getHeaderHeight(); - label.drawU(ug.apply(new UTranslate(x1, Y_NUMDAY + 11))); - } - last = name; - } - - } - } - - private TextBlock getTextBlock(final String text, int size, boolean bold) { - return Display.getWithNewlines(text).create(getFontConfiguration(size, bold), HorizontalAlignment.LEFT, - new SpriteContainerEmpty()); - } - - private void drawCenter(final UGraphic ug, final TextBlock text, final double x1, final double x2) { - final double width = text.calculateDimension(ug.getStringBounder()).getWidth(); - final double delta = (x2 - x1) - width; - if (delta < 0) { - return; - } - text.drawU(ug.apply(new UTranslate(x1 + delta / 2, 0))); - } - - private void drawSimpleDayCounter(final UGraphic ug, TimeScale timeScale) { - final ULine vbar = new ULine(0, totalHeight); - for (Instant i = min; i.compareTo(max.increment()) <= 0; i = i.increment()) { - final TextBlock num = Display.getWithNewlines(i.toShortString()).create(getFontConfiguration(10, false), - HorizontalAlignment.LEFT, new SpriteContainerEmpty()); - final double x1 = timeScale.getStartingPosition(i); - final double x2 = timeScale.getEndingPosition(i); - final double width = num.calculateDimension(ug.getStringBounder()).getWidth(); - final double delta = (x2 - x1) - width; - if (i.compareTo(max.increment()) < 0) { - num.drawU(ug.apply(new UTranslate(x1 + delta / 2, 0))); - } - ug.apply(new UChangeColor(HtmlColorUtils.LIGHT_GRAY)).apply(new UTranslate(x1, 0)).draw(vbar); - } - } - - private void initTaskAndResourceDraws(TimeScale timeScale) { - double y = getHeaderHeight(); + private void initTaskAndResourceDraws(TimeScale timeScale, double headerHeight) { + double y = headerHeight; for (Task task : tasks.values()) { final TaskDraw draw; if (task instanceof TaskSeparator) { @@ -402,8 +319,8 @@ public class GanttDiagram extends TitledDiagram implements Subject { if (task instanceof TaskSeparator) { continue; } - final Instant start = task.getStart(); - final Instant end = task.getEnd(); + final Wink start = task.getStart(); + final Wink end = task.getEnd(); // if (min.compareTo(start) > 0) { // min = start; // } @@ -414,13 +331,13 @@ public class GanttDiagram extends TitledDiagram implements Subject { } if (calendar != null) { for (DayAsDate d : colorDays.keySet()) { - final Instant instant = calendar.fromDayAsDate(d); + final Wink instant = calendar.fromDayAsDate(d); if (instant.compareTo(max) > 0) { max = instant; } } for (DayAsDate d : nameDays.keySet()) { - final Instant instant = calendar.fromDayAsDate(d); + final Wink instant = calendar.fromDayAsDate(d); if (instant.compareTo(max) > 0) { max = instant; } @@ -443,28 +360,6 @@ public class GanttDiagram extends TitledDiagram implements Subject { return result; } - private void drawTasks(final UGraphic ug, TimeScale timeScale) { - for (Task task : tasks.values()) { - final TaskDraw draw = task.getTaskDraw(); - final UTranslate move = new UTranslate(0, draw.getY()); - draw.drawU(ug.apply(move)); - draw.drawTitle(ug.apply(move)); - } - for (Resource res : resources.values()) { - final ResourceDraw draw = res.getResourceDraw(); - final UTranslate move = new UTranslate(0, draw.getY()); - draw.drawU(ug.apply(move)); - } - } - - private FontConfiguration getFontConfiguration(int size, boolean bold) { - UFont font = UFont.serif(size); - if (bold) { - font = font.bold(); - } - return new FontConfiguration(font, HtmlColorUtils.BLACK, HtmlColorUtils.BLACK, false); - } - public Task getExistingTask(String id) { if (id == null) { throw new IllegalArgumentException(); @@ -538,7 +433,7 @@ public class GanttDiagram extends TitledDiagram implements Subject { } public void setStartingDate(DayAsDate start) { - this.calendar = new GCalendarSimple(start); + this.calendar = new GCalendar(start); } public DayAsDate getStartingDate() { @@ -552,14 +447,14 @@ public class GanttDiagram extends TitledDiagram implements Subject { if (this.calendar == null) { return null; } - return ((GCalendarSimple) this.calendar).toDayAsDate(new InstantDay(nday)); + return this.calendar.toDayAsDate(new Wink(nday)); } public int daysInWeek() { return 7 - closedDayOfWeek.size(); } - public Instant convert(DayAsDate day) { + public Wink convert(DayAsDate day) { return calendar.fromDayAsDate(day); } @@ -567,8 +462,6 @@ public class GanttDiagram extends TitledDiagram implements Subject { return getDefaultPlan().getLoadAt(convert(day)) > 0; } - private final Map resources = new LinkedHashMap(); - public void affectResource(Task result, String description) { final Pattern p = Pattern.compile("([^:]+)(:(\\d+))?"); final Matcher m = p.matcher(description); @@ -586,13 +479,13 @@ public class GanttDiagram extends TitledDiagram implements Subject { public Resource getResource(String resourceName) { Resource resource = resources.get(resourceName); if (resource == null) { - resource = new Resource(resourceName, getDefaultPlan(), getCalendarSimple()); + resource = new Resource(resourceName, getDefaultPlan(), calendar); } resources.put(resourceName, resource); return resource; } - public int getLoadForResource(Resource res, Instant i) { + public int getLoadForResource(Resource res, Wink i) { int result = 0; for (Task task : tasks.values()) { if (task instanceof TaskSeparator) { @@ -604,9 +497,6 @@ public class GanttDiagram extends TitledDiagram implements Subject { return result; } - private final Map colorDays = new HashMap(); - private final Map nameDays = new HashMap(); - public Moment getExistingMoment(String id) { Moment result = getExistingTask(id); if (result == null) { @@ -661,8 +551,6 @@ public class GanttDiagram extends TitledDiagram implements Subject { colorDay(today, colors.getCenter()); } - private DayAsDate today; - public CommandExecutionResult setToday(DayAsDate date) { this.today = date; return CommandExecutionResult.ok(); @@ -673,4 +561,9 @@ public class GanttDiagram extends TitledDiagram implements Subject { return CommandExecutionResult.ok(); } + public void setPrintInterval(DayAsDate start, DayAsDate end) { + this.printStart = start; + this.printEnd = end; + } + } diff --git a/src/net/sourceforge/plantuml/project3/GanttDiagramFactory.java b/src/net/sourceforge/plantuml/project/GanttDiagramFactory.java similarity index 74% rename from src/net/sourceforge/plantuml/project3/GanttDiagramFactory.java rename to src/net/sourceforge/plantuml/project/GanttDiagramFactory.java index 06ae4948f..d97972001 100644 --- a/src/net/sourceforge/plantuml/project3/GanttDiagramFactory.java +++ b/src/net/sourceforge/plantuml/project/GanttDiagramFactory.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project; import java.util.ArrayList; import java.util.Arrays; @@ -45,11 +45,30 @@ import net.sourceforge.plantuml.command.CommandNope; import net.sourceforge.plantuml.command.CommandScale; import net.sourceforge.plantuml.command.UmlDiagramFactory; import net.sourceforge.plantuml.core.DiagramType; +import net.sourceforge.plantuml.project.command.CommandGanttArrow; +import net.sourceforge.plantuml.project.command.CommandGanttArrow2; +import net.sourceforge.plantuml.project.command.CommandPage; +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.NaturalCommand; +import net.sourceforge.plantuml.project.command.NaturalCommandAnd; +import net.sourceforge.plantuml.project.command.NaturalCommandAndAnd; +import net.sourceforge.plantuml.project.lang.ComplementPattern; +import net.sourceforge.plantuml.project.lang.SubjectDayAsDate; +import net.sourceforge.plantuml.project.lang.SubjectDayOfWeek; +import net.sourceforge.plantuml.project.lang.SubjectDaysAsDates; +import net.sourceforge.plantuml.project.lang.SubjectPattern; +import net.sourceforge.plantuml.project.lang.SubjectProject; +import net.sourceforge.plantuml.project.lang.SubjectResource; +import net.sourceforge.plantuml.project.lang.SubjectTask; +import net.sourceforge.plantuml.project.lang.SubjectToday; +import net.sourceforge.plantuml.project.lang.VerbPattern; public class GanttDiagramFactory extends UmlDiagramFactory { static private final List subjects() { - return Arrays. asList(new SubjectTask(), new SubjectProject(), new SubjectDayOfWeek(), + return Arrays.asList(new SubjectTask(), new SubjectProject(), new SubjectDayOfWeek(), new SubjectDayAsDate(), new SubjectDaysAsDates(), new SubjectResource(), new SubjectToday()); } @@ -70,6 +89,8 @@ public class GanttDiagramFactory extends UmlDiagramFactory { cmds.add(new CommandGanttArrow2()); cmds.add(new CommandSeparator()); + cmds.add(new CommandPrintScale()); + cmds.add(new CommandPrintBetween()); cmds.add(new CommandScale()); cmds.add(new CommandPage()); // cmds.add(new CommandScaleWidthAndHeight()); @@ -102,7 +123,8 @@ public class GanttDiagramFactory extends UmlDiagramFactory { } for (ComplementPattern complement1 : verb1.getComplements()) { for (ComplementPattern complement2 : verb2.getComplements()) { - cache.add(NaturalCommandAnd.create(subject, verb1, complement1, verb2, complement2)); + cache.add( + NaturalCommandAnd.create(subject, verb1, complement1, verb2, complement2)); } } } diff --git a/src/net/sourceforge/plantuml/project3/Load.java b/src/net/sourceforge/plantuml/project/Load.java similarity index 78% rename from src/net/sourceforge/plantuml/project3/Load.java rename to src/net/sourceforge/plantuml/project/Load.java index d74b619a3..74d807464 100644 --- a/src/net/sourceforge/plantuml/project3/Load.java +++ b/src/net/sourceforge/plantuml/project/Load.java @@ -33,10 +33,24 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project; -public interface Load extends Value, Complement { +import net.sourceforge.plantuml.project.lang.Complement; - int getFullLoad(); +public class Load implements Value, Complement { + + private final int winks; + + private Load(int winks) { + this.winks = winks; + } + + public static Load inWinks(int winks) { + return new Load(winks); + } + + public int getFullLoad() { + return winks * 100; + } } diff --git a/src/net/sourceforge/plantuml/project3/LoadPlanable.java b/src/net/sourceforge/plantuml/project/LoadPlanable.java similarity index 90% rename from src/net/sourceforge/plantuml/project3/LoadPlanable.java rename to src/net/sourceforge/plantuml/project/LoadPlanable.java index 11560e6c1..15a909c7c 100644 --- a/src/net/sourceforge/plantuml/project3/LoadPlanable.java +++ b/src/net/sourceforge/plantuml/project/LoadPlanable.java @@ -33,9 +33,11 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project; + +import net.sourceforge.plantuml.project.core.Wink; public interface LoadPlanable { - public int getLoadAt(Instant instant); + public int getLoadAt(Wink instant); } diff --git a/src/net/sourceforge/plantuml/project3/PlanUtils.java b/src/net/sourceforge/plantuml/project/PlanUtils.java similarity index 90% rename from src/net/sourceforge/plantuml/project3/PlanUtils.java rename to src/net/sourceforge/plantuml/project/PlanUtils.java index 8afc8e87c..0d1ce7b18 100644 --- a/src/net/sourceforge/plantuml/project3/PlanUtils.java +++ b/src/net/sourceforge/plantuml/project/PlanUtils.java @@ -33,7 +33,9 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project; + +import net.sourceforge.plantuml.project.core.Wink; public class PlanUtils { @@ -43,7 +45,7 @@ public class PlanUtils { public static LoadPlanable minOf(final LoadPlanable p1, final LoadPlanable p2) { return new LoadPlanable() { - public int getLoadAt(Instant instant) { + public int getLoadAt(Wink instant) { return Math.min(p1.getLoadAt(instant), p2.getLoadAt(instant)); } }; @@ -51,7 +53,7 @@ public class PlanUtils { public static LoadPlanable multiply(final LoadPlanable p1, final LoadPlanable p2) { return new LoadPlanable() { - public int getLoadAt(Instant instant) { + public int getLoadAt(Wink instant) { return p1.getLoadAt(instant) * p2.getLoadAt(instant) / 100; } }; diff --git a/src/net/sourceforge/plantuml/project3/Solver3.java b/src/net/sourceforge/plantuml/project/Solver3.java similarity index 84% rename from src/net/sourceforge/plantuml/project3/Solver3.java rename to src/net/sourceforge/plantuml/project/Solver3.java index 203517de2..976ab40bd 100644 --- a/src/net/sourceforge/plantuml/project3/Solver3.java +++ b/src/net/sourceforge/plantuml/project/Solver3.java @@ -33,13 +33,16 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; +import net.sourceforge.plantuml.project.core.TaskAttribute; +import net.sourceforge.plantuml.project.core.Wink; + public class Solver3 { private final Map values = new LinkedHashMap(); @@ -53,8 +56,8 @@ public class Solver3 { public void setData(TaskAttribute attribute, Value value) { final Value previous = values.remove(attribute); if (previous != null && attribute == TaskAttribute.START) { - final Instant previousInstant = (Instant) previous; - if (previousInstant.compareTo((Instant) value) > 0) { + final Wink previousInstant = (Wink) previous; + if (previousInstant.compareTo((Wink) value) > 0) { value = previous; } } @@ -81,14 +84,14 @@ public class Solver3 { if (attribute == TaskAttribute.START) { return computeStart(); } - return LoadInDays.inDay(1); + return Load.inWinks(1); // throw new UnsupportedOperationException(attribute.toString()); } return result; } - private Instant computeEnd() { - Instant current = (Instant) values.get(TaskAttribute.START); + private Wink computeEnd() { + Wink current = (Wink) values.get(TaskAttribute.START); int fullLoad = ((Load) values.get(TaskAttribute.LOAD)).getFullLoad(); while (fullLoad > 0) { fullLoad -= loadPlanable.getLoadAt(current); @@ -97,12 +100,15 @@ public class Solver3 { return current.decrement(); } - private Instant computeStart() { - Instant current = (Instant) values.get(TaskAttribute.END); + private Wink computeStart() { + Wink current = (Wink) values.get(TaskAttribute.END); int fullLoad = ((Load) values.get(TaskAttribute.LOAD)).getFullLoad(); while (fullLoad > 0) { fullLoad -= loadPlanable.getLoadAt(current); current = current.decrement(); + if (current.getWink() <= 0) { + return current; + } } return current.increment(); } diff --git a/src/net/sourceforge/plantuml/project3/Today.java b/src/net/sourceforge/plantuml/project/Today.java similarity index 93% rename from src/net/sourceforge/plantuml/project3/Today.java rename to src/net/sourceforge/plantuml/project/Today.java index 9a15b24b8..f7c03b3d5 100644 --- a/src/net/sourceforge/plantuml/project3/Today.java +++ b/src/net/sourceforge/plantuml/project/Today.java @@ -33,7 +33,9 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project; + +import net.sourceforge.plantuml.project.lang.Subject; public class Today implements Subject { diff --git a/src/net/sourceforge/plantuml/project3/Value.java b/src/net/sourceforge/plantuml/project/Value.java similarity index 96% rename from src/net/sourceforge/plantuml/project3/Value.java rename to src/net/sourceforge/plantuml/project/Value.java index 18df4746b..59f98828a 100644 --- a/src/net/sourceforge/plantuml/project3/Value.java +++ b/src/net/sourceforge/plantuml/project/Value.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project; public interface Value { diff --git a/src/net/sourceforge/plantuml/project3/CommandGanttArrow.java b/src/net/sourceforge/plantuml/project/command/CommandGanttArrow.java similarity index 89% rename from src/net/sourceforge/plantuml/project3/CommandGanttArrow.java rename to src/net/sourceforge/plantuml/project/command/CommandGanttArrow.java index 6d47510ba..72416d7f8 100644 --- a/src/net/sourceforge/plantuml/project3/CommandGanttArrow.java +++ b/src/net/sourceforge/plantuml/project/command/CommandGanttArrow.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.command; import net.sourceforge.plantuml.LineLocation; import net.sourceforge.plantuml.command.CommandExecutionResult; @@ -42,6 +42,11 @@ import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexConcat; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.GanttConstraint; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.core.Task; +import net.sourceforge.plantuml.project.core.TaskAttribute; +import net.sourceforge.plantuml.project.core.TaskInstant; public class CommandGanttArrow extends SingleLineCommand2 { diff --git a/src/net/sourceforge/plantuml/project3/CommandGanttArrow2.java b/src/net/sourceforge/plantuml/project/command/CommandGanttArrow2.java similarity index 94% rename from src/net/sourceforge/plantuml/project3/CommandGanttArrow2.java rename to src/net/sourceforge/plantuml/project/command/CommandGanttArrow2.java index 33283a808..900dfce8c 100644 --- a/src/net/sourceforge/plantuml/project3/CommandGanttArrow2.java +++ b/src/net/sourceforge/plantuml/project/command/CommandGanttArrow2.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.command; import net.sourceforge.plantuml.LineLocation; import net.sourceforge.plantuml.command.CommandExecutionResult; @@ -42,6 +42,8 @@ import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexConcat; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.core.Task; public class CommandGanttArrow2 extends SingleLineCommand2 { diff --git a/src/net/sourceforge/plantuml/project3/CommandPage.java b/src/net/sourceforge/plantuml/project/command/CommandPage.java similarity index 96% rename from src/net/sourceforge/plantuml/project3/CommandPage.java rename to src/net/sourceforge/plantuml/project/command/CommandPage.java index 8c62678b8..60da3b674 100644 --- a/src/net/sourceforge/plantuml/project3/CommandPage.java +++ b/src/net/sourceforge/plantuml/project/command/CommandPage.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.command; import net.sourceforge.plantuml.LineLocation; import net.sourceforge.plantuml.command.CommandExecutionResult; @@ -42,6 +42,7 @@ import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexConcat; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.GanttDiagram; public class CommandPage extends SingleLineCommand2 { diff --git a/src/net/sourceforge/plantuml/project/command/CommandPrintBetween.java b/src/net/sourceforge/plantuml/project/command/CommandPrintBetween.java new file mode 100644 index 000000000..ed436bbc1 --- /dev/null +++ b/src/net/sourceforge/plantuml/project/command/CommandPrintBetween.java @@ -0,0 +1,84 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.project.command; + +import net.sourceforge.plantuml.LineLocation; +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.command.SingleLineCommand2; +import net.sourceforge.plantuml.command.regex.IRegex; +import net.sourceforge.plantuml.command.regex.RegexConcat; +import net.sourceforge.plantuml.command.regex.RegexLeaf; +import net.sourceforge.plantuml.command.regex.RegexOr; +import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.DayAsDate; +import net.sourceforge.plantuml.project.Failable; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.core.PrintScale; +import net.sourceforge.plantuml.project.lang.Complement; +import net.sourceforge.plantuml.project.lang.ComplementDate; + +public class CommandPrintBetween extends SingleLineCommand2 { + + private static final ComplementDate pattern = new ComplementDate(); + + public CommandPrintBetween() { + super(getRegexConcat()); + } + + static IRegex getRegexConcat() { + return RegexConcat.build(CommandPrintBetween.class.getName(), RegexLeaf.start(), // + // Print between 2020/02/14 and 2020/03/04 + new RegexLeaf("print"), // + RegexLeaf.spaceOneOrMore(), // + new RegexLeaf("between"), // + RegexLeaf.spaceOneOrMore(), // + pattern.toRegex("START"), // + RegexLeaf.spaceOneOrMore(), // + new RegexLeaf("and"), // + RegexLeaf.spaceOneOrMore(), // + pattern.toRegex("END"), // + RegexLeaf.end()); // + } + + @Override + protected CommandExecutionResult executeArg(GanttDiagram diagram, LineLocation location, RegexResult arg) { + final DayAsDate start = (DayAsDate) pattern.getComplement(diagram, arg, "START").get(); + final DayAsDate end = (DayAsDate) pattern.getComplement(diagram, arg, "END").get(); + diagram.setPrintInterval(start, end); + return CommandExecutionResult.ok(); + } + +} diff --git a/src/net/sourceforge/plantuml/project/command/CommandPrintScale.java b/src/net/sourceforge/plantuml/project/command/CommandPrintScale.java new file mode 100644 index 000000000..64c09ceda --- /dev/null +++ b/src/net/sourceforge/plantuml/project/command/CommandPrintScale.java @@ -0,0 +1,73 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.project.command; + +import net.sourceforge.plantuml.LineLocation; +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.command.SingleLineCommand2; +import net.sourceforge.plantuml.command.regex.IRegex; +import net.sourceforge.plantuml.command.regex.RegexConcat; +import net.sourceforge.plantuml.command.regex.RegexLeaf; +import net.sourceforge.plantuml.command.regex.RegexOr; +import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.core.PrintScale; + +public class CommandPrintScale extends SingleLineCommand2 { + + public CommandPrintScale() { + super(getRegexConcat()); + } + + static IRegex getRegexConcat() { + return RegexConcat.build(CommandPrintScale.class.getName(), RegexLeaf.start(), // + new RegexLeaf("printscale"), // + RegexLeaf.spaceOneOrMore(), // + new RegexOr("SCALE", // + new RegexLeaf("daily"), // + new RegexLeaf("weekly")), // + RegexLeaf.end()); // + } + + @Override + protected CommandExecutionResult executeArg(GanttDiagram diagram, LineLocation location, RegexResult arg) { + final String scaleString = arg.get("SCALE", 0); + final PrintScale scale = PrintScale.fromString(scaleString); + diagram.setPrintScale(scale); + return CommandExecutionResult.ok(); + } + +} diff --git a/src/net/sourceforge/plantuml/project3/CommandSeparator.java b/src/net/sourceforge/plantuml/project/command/CommandSeparator.java similarity index 95% rename from src/net/sourceforge/plantuml/project3/CommandSeparator.java rename to src/net/sourceforge/plantuml/project/command/CommandSeparator.java index 15fc31546..11e9bbfca 100644 --- a/src/net/sourceforge/plantuml/project3/CommandSeparator.java +++ b/src/net/sourceforge/plantuml/project/command/CommandSeparator.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.command; import net.sourceforge.plantuml.LineLocation; import net.sourceforge.plantuml.command.CommandExecutionResult; @@ -42,6 +42,7 @@ import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexConcat; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.GanttDiagram; public class CommandSeparator extends SingleLineCommand2 { diff --git a/src/net/sourceforge/plantuml/project3/NaturalCommand.java b/src/net/sourceforge/plantuml/project/command/NaturalCommand.java similarity index 86% rename from src/net/sourceforge/plantuml/project3/NaturalCommand.java rename to src/net/sourceforge/plantuml/project/command/NaturalCommand.java index d3b11bbaa..4266907ae 100644 --- a/src/net/sourceforge/plantuml/project3/NaturalCommand.java +++ b/src/net/sourceforge/plantuml/project/command/NaturalCommand.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.command; import net.sourceforge.plantuml.LineLocation; import net.sourceforge.plantuml.command.Command; @@ -42,6 +42,15 @@ import net.sourceforge.plantuml.command.SingleLineCommand2; import net.sourceforge.plantuml.command.regex.RegexConcat; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.Failable; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.lang.Complement; +import net.sourceforge.plantuml.project.lang.ComplementEmpty; +import net.sourceforge.plantuml.project.lang.ComplementPattern; +import net.sourceforge.plantuml.project.lang.Subject; +import net.sourceforge.plantuml.project.lang.SubjectPattern; +import net.sourceforge.plantuml.project.lang.Verb; +import net.sourceforge.plantuml.project.lang.VerbPattern; public class NaturalCommand extends SingleLineCommand2 { diff --git a/src/net/sourceforge/plantuml/project3/NaturalCommandAnd.java b/src/net/sourceforge/plantuml/project/command/NaturalCommandAnd.java similarity index 89% rename from src/net/sourceforge/plantuml/project3/NaturalCommandAnd.java rename to src/net/sourceforge/plantuml/project/command/NaturalCommandAnd.java index 82346d993..663c0d8b1 100644 --- a/src/net/sourceforge/plantuml/project3/NaturalCommandAnd.java +++ b/src/net/sourceforge/plantuml/project/command/NaturalCommandAnd.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.command; import net.sourceforge.plantuml.LineLocation; import net.sourceforge.plantuml.command.Command; @@ -42,6 +42,14 @@ import net.sourceforge.plantuml.command.SingleLineCommand2; import net.sourceforge.plantuml.command.regex.RegexConcat; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.Failable; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.lang.Complement; +import net.sourceforge.plantuml.project.lang.ComplementPattern; +import net.sourceforge.plantuml.project.lang.Subject; +import net.sourceforge.plantuml.project.lang.SubjectPattern; +import net.sourceforge.plantuml.project.lang.Verb; +import net.sourceforge.plantuml.project.lang.VerbPattern; public class NaturalCommandAnd extends SingleLineCommand2 { diff --git a/src/net/sourceforge/plantuml/project3/NaturalCommandAndAnd.java b/src/net/sourceforge/plantuml/project/command/NaturalCommandAndAnd.java similarity index 91% rename from src/net/sourceforge/plantuml/project3/NaturalCommandAndAnd.java rename to src/net/sourceforge/plantuml/project/command/NaturalCommandAndAnd.java index 4395d8be9..63b0d8080 100644 --- a/src/net/sourceforge/plantuml/project3/NaturalCommandAndAnd.java +++ b/src/net/sourceforge/plantuml/project/command/NaturalCommandAndAnd.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.command; import net.sourceforge.plantuml.LineLocation; import net.sourceforge.plantuml.command.Command; @@ -42,6 +42,13 @@ import net.sourceforge.plantuml.command.SingleLineCommand2; import net.sourceforge.plantuml.command.regex.RegexConcat; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.lang.Complement; +import net.sourceforge.plantuml.project.lang.ComplementPattern; +import net.sourceforge.plantuml.project.lang.Subject; +import net.sourceforge.plantuml.project.lang.SubjectPattern; +import net.sourceforge.plantuml.project.lang.Verb; +import net.sourceforge.plantuml.project.lang.VerbPattern; public class NaturalCommandAndAnd extends SingleLineCommand2 { diff --git a/src/net/sourceforge/plantuml/project3/Moment.java b/src/net/sourceforge/plantuml/project/core/Moment.java similarity index 92% rename from src/net/sourceforge/plantuml/project3/Moment.java rename to src/net/sourceforge/plantuml/project/core/Moment.java index fb18a4396..cea85f99a 100644 --- a/src/net/sourceforge/plantuml/project3/Moment.java +++ b/src/net/sourceforge/plantuml/project/core/Moment.java @@ -33,12 +33,12 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.core; public interface Moment { - public Instant getStart(); + public Wink getStart(); - public Instant getEnd(); + public Wink getEnd(); } diff --git a/src/net/sourceforge/plantuml/project3/MomentImpl.java b/src/net/sourceforge/plantuml/project/core/MomentImpl.java similarity index 87% rename from src/net/sourceforge/plantuml/project3/MomentImpl.java rename to src/net/sourceforge/plantuml/project/core/MomentImpl.java index a56938456..410d3059b 100644 --- a/src/net/sourceforge/plantuml/project3/MomentImpl.java +++ b/src/net/sourceforge/plantuml/project/core/MomentImpl.java @@ -33,23 +33,23 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.core; public class MomentImpl implements Moment { - private final Instant start; - private final Instant end; + private final Wink start; + private final Wink end; - public MomentImpl(Instant start, Instant end) { + public MomentImpl(Wink start, Wink end) { this.start = start; this.end = end; } - public Instant getStart() { + public Wink getStart() { return start; } - public Instant getEnd() { + public Wink getEnd() { return end; } diff --git a/src/net/sourceforge/plantuml/project3/Month.java b/src/net/sourceforge/plantuml/project/core/Month.java similarity index 92% rename from src/net/sourceforge/plantuml/project3/Month.java rename to src/net/sourceforge/plantuml/project/core/Month.java index 64fe1f816..73528c4fc 100644 --- a/src/net/sourceforge/plantuml/project3/Month.java +++ b/src/net/sourceforge/plantuml/project/core/Month.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.core; import net.sourceforge.plantuml.StringUtils; @@ -48,6 +48,14 @@ public enum Month { this.daysPerMonth = daysPerMonth; } + public String shortName() { + return niceName().substring(0, 3); + } + + public String niceName() { + return StringUtils.capitalize(name()); + } + static public String getRegexString() { final StringBuilder sb = new StringBuilder(); for (Month month : Month.values()) { @@ -83,4 +91,5 @@ public enum Month { public int m() { return 3 + (ordinal() + 10) % 12; } + } diff --git a/src/net/sourceforge/plantuml/project3/GCalendar.java b/src/net/sourceforge/plantuml/project/core/PrintScale.java similarity index 85% rename from src/net/sourceforge/plantuml/project3/GCalendar.java rename to src/net/sourceforge/plantuml/project/core/PrintScale.java index b621e33e8..ecde6640c 100644 --- a/src/net/sourceforge/plantuml/project3/GCalendar.java +++ b/src/net/sourceforge/plantuml/project/core/PrintScale.java @@ -33,14 +33,15 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.core; -public interface GCalendar { - - public DayAsDate toDayAsDate(InstantDay day); - - public DayAsDate getStartingDate(); - - public InstantDay fromDayAsDate(DayAsDate day); +public enum PrintScale { + DAILY, WEEKLY; + static public PrintScale fromString(String value) { + if (value.startsWith("w")) { + return WEEKLY; + } + return DAILY; + } } diff --git a/src/net/sourceforge/plantuml/project3/Resource.java b/src/net/sourceforge/plantuml/project/core/Resource.java similarity index 79% rename from src/net/sourceforge/plantuml/project3/Resource.java rename to src/net/sourceforge/plantuml/project/core/Resource.java index 54eb1d9b5..a5cb17364 100644 --- a/src/net/sourceforge/plantuml/project3/Resource.java +++ b/src/net/sourceforge/plantuml/project/core/Resource.java @@ -33,19 +33,26 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.core; import java.util.Collection; import java.util.EnumSet; import java.util.Set; import java.util.TreeSet; +import net.sourceforge.plantuml.project.DayAsDate; +import net.sourceforge.plantuml.project.DayOfWeek; +import net.sourceforge.plantuml.project.GCalendar; +import net.sourceforge.plantuml.project.LoadPlanable; +import net.sourceforge.plantuml.project.draw.ResourceDraw; +import net.sourceforge.plantuml.project.lang.Subject; + public class Resource implements Subject { private final String name; private ResourceDraw draw; - private final Set closed = new TreeSet(); - private final Set forcedOn = new TreeSet(); + private final Set closed = new TreeSet(); + private final Set forcedOn = new TreeSet(); private final GCalendar calendar; private final Collection closedDayOfWeek = EnumSet.noneOf(DayOfWeek.class); @@ -83,12 +90,12 @@ public class Resource implements Subject { this.draw = draw; } - public boolean isClosedAt(Instant instant) { + public boolean isClosedAt(Wink instant) { if (this.forcedOn.contains(instant)) { return false; } if (closedDayOfWeek.size() > 0 && calendar != null) { - final DayAsDate d = calendar.toDayAsDate((InstantDay) instant); + final DayAsDate d = calendar.toDayAsDate((Wink) instant); if (closedDayOfWeek.contains(d.getDayOfWeek())) { return true; } @@ -96,11 +103,11 @@ public class Resource implements Subject { return this.closed.contains(instant); } - public void addCloseDay(Instant instant) { + public void addCloseDay(Wink instant) { this.closed.add(instant); } - public void addForceOnDay(Instant instant) { + public void addForceOnDay(Wink instant) { this.forcedOn.add(instant); } diff --git a/src/net/sourceforge/plantuml/project3/Task.java b/src/net/sourceforge/plantuml/project/core/Task.java similarity index 79% rename from src/net/sourceforge/plantuml/project3/Task.java rename to src/net/sourceforge/plantuml/project/core/Task.java index 0f2e8410f..74353fc61 100644 --- a/src/net/sourceforge/plantuml/project3/Task.java +++ b/src/net/sourceforge/plantuml/project/core/Task.java @@ -33,23 +33,28 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.core; + +import net.sourceforge.plantuml.project.Load; +import net.sourceforge.plantuml.project.draw.TaskDraw; +import net.sourceforge.plantuml.project.lang.ComplementColors; +import net.sourceforge.plantuml.project.lang.Subject; public interface Task extends Subject, Moment { public TaskCode getCode(); - public Instant getStart(); + public Wink getStart(); - public Instant getEnd(); + public Wink getEnd(); public Load getLoad(); public void setLoad(Load load); - public void setStart(Instant start); + public void setStart(Wink start); - public void setEnd(Instant end); + public void setEnd(Wink end); public void setTaskDraw(TaskDraw taskDraw); @@ -63,5 +68,7 @@ public interface Task extends Subject, Moment { public boolean isDiamond(); + public void setCompletion(int completion); + } diff --git a/src/net/sourceforge/plantuml/project3/TaskAttribute.java b/src/net/sourceforge/plantuml/project/core/TaskAttribute.java similarity index 96% rename from src/net/sourceforge/plantuml/project3/TaskAttribute.java rename to src/net/sourceforge/plantuml/project/core/TaskAttribute.java index f326e3778..6137ebd8e 100644 --- a/src/net/sourceforge/plantuml/project3/TaskAttribute.java +++ b/src/net/sourceforge/plantuml/project/core/TaskAttribute.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.core; public enum TaskAttribute { START, END, LOAD; diff --git a/src/net/sourceforge/plantuml/project3/TaskCode.java b/src/net/sourceforge/plantuml/project/core/TaskCode.java similarity index 97% rename from src/net/sourceforge/plantuml/project3/TaskCode.java rename to src/net/sourceforge/plantuml/project/core/TaskCode.java index e6466abc0..5ea518c0a 100644 --- a/src/net/sourceforge/plantuml/project3/TaskCode.java +++ b/src/net/sourceforge/plantuml/project/core/TaskCode.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.core; public class TaskCode { diff --git a/src/net/sourceforge/plantuml/project3/TaskImpl.java b/src/net/sourceforge/plantuml/project/core/TaskImpl.java similarity index 82% rename from src/net/sourceforge/plantuml/project3/TaskImpl.java rename to src/net/sourceforge/plantuml/project/core/TaskImpl.java index f5ed4f63d..f800558f6 100644 --- a/src/net/sourceforge/plantuml/project3/TaskImpl.java +++ b/src/net/sourceforge/plantuml/project/core/TaskImpl.java @@ -33,12 +33,19 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.core; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; +import net.sourceforge.plantuml.project.Load; +import net.sourceforge.plantuml.project.LoadPlanable; +import net.sourceforge.plantuml.project.PlanUtils; +import net.sourceforge.plantuml.project.Solver3; +import net.sourceforge.plantuml.project.draw.TaskDraw; +import net.sourceforge.plantuml.project.lang.ComplementColors; + public class TaskImpl implements Task, LoadPlanable { private final TaskCode code; @@ -51,11 +58,11 @@ public class TaskImpl implements Task, LoadPlanable { this.code = code; this.defaultPlan = defaultPlan; this.solver = new Solver3(this); - setStart(new InstantDay(0)); - setLoad(LoadInDays.inDay(1)); + setStart(new Wink(0)); + setLoad(Load.inWinks(1)); } - public int getLoadAt(Instant instant) { + public int getLoadAt(Wink instant) { LoadPlanable result = defaultPlan; if (resources2.size() > 0) { result = PlanUtils.multiply(defaultPlan, getRessourcePlan()); @@ -64,7 +71,7 @@ public class TaskImpl implements Task, LoadPlanable { // return PlanUtils.minOf(getLoad(), plan1).getLoadAt(instant); } - public int loadForResource(Resource res, Instant instant) { + public int loadForResource(Resource res, Wink instant) { if (resources2.keySet().contains(res) && instant.compareTo(getStart()) >= 0 && instant.compareTo(getEnd()) <= 0) { if (res.isClosedAt(instant)) { return 0; @@ -87,7 +94,7 @@ public class TaskImpl implements Task, LoadPlanable { } return new LoadPlanable() { - public int getLoadAt(Instant instant) { + public int getLoadAt(Wink instant) { int result = 0; for (Map.Entry ent : resources2.entrySet()) { final Resource res = ent.getKey(); @@ -137,16 +144,16 @@ public class TaskImpl implements Task, LoadPlanable { return code; } - public Instant getStart() { - Instant result = (Instant) solver.getData(TaskAttribute.START); + public Wink getStart() { + Wink result = (Wink) solver.getData(TaskAttribute.START); while (getLoadAt(result) == 0) { result = result.increment(); } return result; } - public Instant getEnd() { - return (Instant) solver.getData(TaskAttribute.END); + public Wink getEnd() { + return (Wink) solver.getData(TaskAttribute.END); } public Load getLoad() { @@ -157,11 +164,11 @@ public class TaskImpl implements Task, LoadPlanable { solver.setData(TaskAttribute.LOAD, load); } - public void setStart(Instant start) { + public void setStart(Wink start) { solver.setData(TaskAttribute.START, start); } - public void setEnd(Instant end) { + public void setEnd(Wink end) { solver.setData(TaskAttribute.END, end); } @@ -169,7 +176,7 @@ public class TaskImpl implements Task, LoadPlanable { private ComplementColors colors; public void setTaskDraw(TaskDraw taskDraw) { - taskDraw.setColors(colors); + taskDraw.setColorsAndCompletion(colors, completion); this.taskDraw = taskDraw; } @@ -192,5 +199,11 @@ public class TaskImpl implements Task, LoadPlanable { public boolean isDiamond() { return this.diamond; } + + private int completion = 100; + + public void setCompletion(int completion) { + this.completion = completion; + } } diff --git a/src/net/sourceforge/plantuml/project3/TaskInstant.java b/src/net/sourceforge/plantuml/project/core/TaskInstant.java similarity index 92% rename from src/net/sourceforge/plantuml/project3/TaskInstant.java rename to src/net/sourceforge/plantuml/project/core/TaskInstant.java index de638c38f..3d4d72e1e 100644 --- a/src/net/sourceforge/plantuml/project3/TaskInstant.java +++ b/src/net/sourceforge/plantuml/project/core/TaskInstant.java @@ -33,7 +33,9 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.core; + +import net.sourceforge.plantuml.project.lang.Complement; public class TaskInstant implements Complement { @@ -58,7 +60,7 @@ public class TaskInstant implements Complement { return new TaskInstant(task, attribute, newDelta); } - private Instant manageDelta(Instant value) { + private Wink manageDelta(Wink value) { if (delta > 0) { for (int i = 0; i < delta; i++) { value = value.increment(); @@ -72,7 +74,7 @@ public class TaskInstant implements Complement { return value; } - public Instant getInstantPrecise() { + public Wink getInstantPrecise() { if (attribute == TaskAttribute.START) { return manageDelta(task.getStart()); } @@ -82,7 +84,7 @@ public class TaskInstant implements Complement { throw new IllegalStateException(); } - public Instant getInstantTheorical() { + public Wink getInstantTheorical() { if (attribute == TaskAttribute.START) { return manageDelta(task.getStart()); } diff --git a/src/net/sourceforge/plantuml/project3/TaskSeparator.java b/src/net/sourceforge/plantuml/project/core/TaskSeparator.java similarity index 85% rename from src/net/sourceforge/plantuml/project3/TaskSeparator.java rename to src/net/sourceforge/plantuml/project/core/TaskSeparator.java index 093e82221..8f5942c74 100644 --- a/src/net/sourceforge/plantuml/project3/TaskSeparator.java +++ b/src/net/sourceforge/plantuml/project/core/TaskSeparator.java @@ -33,7 +33,11 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.core; + +import net.sourceforge.plantuml.project.Load; +import net.sourceforge.plantuml.project.draw.TaskDraw; +import net.sourceforge.plantuml.project.lang.ComplementColors; public class TaskSeparator implements Task { // public static final double SPACE = 15; @@ -51,19 +55,19 @@ public class TaskSeparator implements Task { return code; } - public Instant getStart() { + public Wink getStart() { throw new UnsupportedOperationException(); } - public Instant getEnd() { + public Wink getEnd() { throw new UnsupportedOperationException(); } - public void setStart(Instant start) { + public void setStart(Wink start) { throw new UnsupportedOperationException(); } - public void setEnd(Instant end) { + public void setEnd(Wink end) { throw new UnsupportedOperationException(); } @@ -104,4 +108,8 @@ public class TaskSeparator implements Task { throw new UnsupportedOperationException(); } + public void setCompletion(int completion) { + throw new UnsupportedOperationException(); + } + } diff --git a/src/net/sourceforge/plantuml/project3/InstantDay.java b/src/net/sourceforge/plantuml/project/core/Wink.java similarity index 72% rename from src/net/sourceforge/plantuml/project3/InstantDay.java rename to src/net/sourceforge/plantuml/project/core/Wink.java index 4a198651d..94c83dba5 100644 --- a/src/net/sourceforge/plantuml/project3/InstantDay.java +++ b/src/net/sourceforge/plantuml/project/core/Wink.java @@ -33,39 +33,41 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.core; -public class InstantDay implements Instant { +import net.sourceforge.plantuml.project.Value; - private final int numDay; +public class Wink implements Value, Comparable { - public InstantDay(int numDay) { - this.numDay = numDay; + private final int wink; + + public Wink(int wink) { + this.wink = wink; } @Override public String toString() { - return "(day +" + numDay + ")"; + return "(Wink +" + wink + ")"; } - public InstantDay increment() { - return new InstantDay(numDay + 1); + public Wink increment() { + return new Wink(wink + 1); } - public InstantDay decrement() { - return new InstantDay(numDay - 1); + public Wink decrement() { + return new Wink(wink - 1); } - final int getNumDay() { - return numDay; + public final int getWink() { + return wink; } - public int compareTo(Instant other) { - return this.numDay - ((InstantDay) other).numDay; + public int compareTo(Wink other) { + return this.wink - other.wink; } public String toShortString() { - return "" + (numDay + 1); + return "" + (wink + 1); } } diff --git a/src/net/sourceforge/plantuml/project3/ResourceDraw.java b/src/net/sourceforge/plantuml/project/draw/ResourceDraw.java similarity index 90% rename from src/net/sourceforge/plantuml/project3/ResourceDraw.java rename to src/net/sourceforge/plantuml/project/draw/ResourceDraw.java index 2f7e4e768..e95c35054 100644 --- a/src/net/sourceforge/plantuml/project3/ResourceDraw.java +++ b/src/net/sourceforge/plantuml/project/draw/ResourceDraw.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.draw; import net.sourceforge.plantuml.SpriteContainerEmpty; import net.sourceforge.plantuml.cucadiagram.Display; @@ -43,6 +43,10 @@ import net.sourceforge.plantuml.graphic.HtmlColor; import net.sourceforge.plantuml.graphic.HtmlColorUtils; import net.sourceforge.plantuml.graphic.TextBlock; import net.sourceforge.plantuml.graphic.UDrawable; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.core.Resource; +import net.sourceforge.plantuml.project.core.Wink; +import net.sourceforge.plantuml.project.timescale.TimeScale; import net.sourceforge.plantuml.ugraphic.UChangeColor; import net.sourceforge.plantuml.ugraphic.UFont; import net.sourceforge.plantuml.ugraphic.UGraphic; @@ -54,11 +58,11 @@ public class ResourceDraw implements UDrawable { private final Resource res; private final TimeScale timeScale; private final double y; - private final Instant min; - private final Instant max; + private final Wink min; + private final Wink max; private final GanttDiagram gantt; - public ResourceDraw(GanttDiagram gantt, Resource res, TimeScale timeScale, double y, Instant min, Instant max) { + public ResourceDraw(GanttDiagram gantt, Resource res, TimeScale timeScale, double y, Wink min, Wink max) { this.res = res; this.timeScale = timeScale; this.y = y; @@ -74,7 +78,7 @@ public class ResourceDraw implements UDrawable { final ULine line = new ULine(timeScale.getEndingPosition(max) - timeScale.getStartingPosition(min), 0); ug.apply(new UChangeColor(HtmlColorUtils.BLACK)) .apply(new UTranslate(0, title.calculateDimension(ug.getStringBounder()).getHeight())).draw(line); - for (Instant i = min; i.compareTo(max) <= 0; i = i.increment()) { + for (Wink i = min; i.compareTo(max) <= 0; i = i.increment()) { final int load = gantt.getLoadForResource(res, i); if (load > 0) { final FontConfiguration fontConfiguration = getFontConfiguration(9, load > 100 ? HtmlColorUtils.RED diff --git a/src/net/sourceforge/plantuml/project3/TaskDraw.java b/src/net/sourceforge/plantuml/project/draw/TaskDraw.java similarity index 89% rename from src/net/sourceforge/plantuml/project3/TaskDraw.java rename to src/net/sourceforge/plantuml/project/draw/TaskDraw.java index e84c44594..bd2b5381d 100644 --- a/src/net/sourceforge/plantuml/project3/TaskDraw.java +++ b/src/net/sourceforge/plantuml/project/draw/TaskDraw.java @@ -33,15 +33,16 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.draw; import net.sourceforge.plantuml.Direction; import net.sourceforge.plantuml.graphic.UDrawable; +import net.sourceforge.plantuml.project.lang.ComplementColors; import net.sourceforge.plantuml.ugraphic.UGraphic; public interface TaskDraw extends UDrawable { - public void setColors(ComplementColors colors); + public void setColorsAndCompletion(ComplementColors colors, int completion); public double getY(); diff --git a/src/net/sourceforge/plantuml/project3/TaskDrawRegular.java b/src/net/sourceforge/plantuml/project/draw/TaskDrawRegular.java similarity index 70% rename from src/net/sourceforge/plantuml/project3/TaskDrawRegular.java rename to src/net/sourceforge/plantuml/project/draw/TaskDrawRegular.java index 0ea267f01..1b8f26a0b 100644 --- a/src/net/sourceforge/plantuml/project3/TaskDrawRegular.java +++ b/src/net/sourceforge/plantuml/project/draw/TaskDrawRegular.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.draw; import net.sourceforge.plantuml.Direction; import net.sourceforge.plantuml.SpriteContainerEmpty; @@ -44,6 +44,10 @@ import net.sourceforge.plantuml.graphic.HtmlColor; import net.sourceforge.plantuml.graphic.HtmlColorSetSimple; import net.sourceforge.plantuml.graphic.HtmlColorUtils; import net.sourceforge.plantuml.graphic.TextBlock; +import net.sourceforge.plantuml.project.core.TaskImpl; +import net.sourceforge.plantuml.project.core.Wink; +import net.sourceforge.plantuml.project.lang.ComplementColors; +import net.sourceforge.plantuml.project.timescale.TimeScale; import net.sourceforge.plantuml.ugraphic.UChangeBackColor; import net.sourceforge.plantuml.ugraphic.UChangeColor; import net.sourceforge.plantuml.ugraphic.UFont; @@ -61,6 +65,7 @@ public class TaskDrawRegular implements TaskDraw { private final TimeScale timeScale; private final double y; private ComplementColors colors; + private int completion = 100; private final double margin = 2; @@ -73,10 +78,15 @@ public class TaskDrawRegular implements TaskDraw { public void drawTitle(UGraphic ug) { final TextBlock title = Display.getWithNewlines(task.getPrettyDisplay()).create(getFontConfiguration(), HorizontalAlignment.LEFT, new SpriteContainerEmpty()); - final double shapeHeight = getShapeHeight(100); final double titleHeight = title.calculateDimension(ug.getStringBounder()).getHeight(); - final double h = (margin + shapeHeight - titleHeight) / 2; - title.drawU(ug.apply(new UTranslate(timeScale.getEndingPosition(task.getStart()), h))); + final double h = (margin + getShapeHeight() - titleHeight) / 2; + final double endingPosition; + if (isDiamond()) { + endingPosition = timeScale.getStartingPosition(task.getStart()) + getHeight(); + } else { + endingPosition = timeScale.getEndingPosition(task.getStart()); + } + title.drawU(ug.apply(new UTranslate(endingPosition, h))); } private FontConfiguration getFontConfiguration() { @@ -88,12 +98,7 @@ public class TaskDrawRegular implements TaskDraw { final double start = timeScale.getStartingPosition(task.getStart()); ug1 = applyColors(ug1); UGraphic ug2 = ug1.apply(new UTranslate(start + margin, margin)); - final UShape shapeFull = getShape(100); - if (shapeFull instanceof UPolygon) { - ug2.draw(shapeFull); - } else { - ug2.draw(shapeFull); - } + drawShape(ug2); } private UGraphic applyColors(UGraphic ug) { @@ -106,25 +111,47 @@ public class TaskDrawRegular implements TaskDraw { return ug.apply(new UChangeColor(HtmlColorUtils.BLUE)).apply(new UChangeBackColor(defaultColor)); } - private UShape getShape(int load) { + private void drawShape(UGraphic ug) { if (isDiamond()) { - return getDiamond(); + ug.draw(getDiamond()); + return; } - final Instant instantStart = task.getStart(); - final Instant instantEnd = task.getEnd(); + final Wink instantStart = task.getStart(); + final Wink instantEnd = task.getEnd(); final double start = timeScale.getStartingPosition(instantStart); final double end = timeScale.getEndingPosition(instantEnd); - return new URectangle(end - start - 2 * margin, getShapeHeight(load), 8, 8); + + final double fullLength = end - start - 2 * margin; + if (fullLength < 10) { + return; + } + final URectangle full = new URectangle(fullLength, getShapeHeight(), 8, 8); + if (completion == 100) { + ug.draw(full); + return; + } + final double partialLength = fullLength * completion / 100.; + ug.apply(new UChangeColor(HtmlColorUtils.WHITE)).apply(new UChangeBackColor(HtmlColorUtils.WHITE)).draw(full); + if (partialLength > 2) { + final URectangle partial = new URectangle(partialLength, getShapeHeight(), 8, 8); + ug.apply(new UChangeColor(null)).draw(partial); + } + if (partialLength > 10 && partialLength < fullLength - 10) { + final URectangle patch = new URectangle(8, getShapeHeight()); + ug.apply(new UChangeColor(null)).apply(new UTranslate(partialLength - 8, 0)).draw(patch); + } + ug.apply(new UChangeBackColor(null)).draw(full); + } - private double getShapeHeight(int load) { - return (getHeight() - 2 * margin) * load / 100.0; + private double getShapeHeight() { + return getHeight() - 2 * margin; } private boolean isDiamond() { if (task.isDiamond()) { - final Instant instantStart = task.getStart(); - final Instant instantEnd = task.getEnd(); + final Wink instantStart = task.getStart(); + final Wink instantEnd = task.getEnd(); return instantStart.compareTo(instantEnd) == 0; } return false; @@ -158,7 +185,8 @@ public class TaskDrawRegular implements TaskDraw { return y + getHeight() / 2; } - public void setColors(ComplementColors colors) { + public void setColorsAndCompletion(ComplementColors colors, int completion) { this.colors = colors; + this.completion = completion; } } diff --git a/src/net/sourceforge/plantuml/project3/TaskDrawSeparator.java b/src/net/sourceforge/plantuml/project/draw/TaskDrawSeparator.java similarity index 89% rename from src/net/sourceforge/plantuml/project3/TaskDrawSeparator.java rename to src/net/sourceforge/plantuml/project/draw/TaskDrawSeparator.java index d29f73011..e54aeb308 100644 --- a/src/net/sourceforge/plantuml/project3/TaskDrawSeparator.java +++ b/src/net/sourceforge/plantuml/project/draw/TaskDrawSeparator.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.draw; import net.sourceforge.plantuml.Direction; import net.sourceforge.plantuml.SpriteContainerEmpty; @@ -43,6 +43,10 @@ import net.sourceforge.plantuml.graphic.HorizontalAlignment; import net.sourceforge.plantuml.graphic.HtmlColorUtils; import net.sourceforge.plantuml.graphic.TextBlock; import net.sourceforge.plantuml.graphic.TextBlockUtils; +import net.sourceforge.plantuml.project.core.TaskSeparator; +import net.sourceforge.plantuml.project.core.Wink; +import net.sourceforge.plantuml.project.lang.ComplementColors; +import net.sourceforge.plantuml.project.timescale.TimeScale; import net.sourceforge.plantuml.ugraphic.UChangeColor; import net.sourceforge.plantuml.ugraphic.UFont; import net.sourceforge.plantuml.ugraphic.UGraphic; @@ -53,11 +57,11 @@ public class TaskDrawSeparator implements TaskDraw { private final TimeScale timeScale; private final double y; - private final Instant min; - private final Instant max; + private final Wink min; + private final Wink max; private final String name; - public TaskDrawSeparator(TaskSeparator task, TimeScale timeScale, double y, Instant min, Instant max) { + public TaskDrawSeparator(TaskSeparator task, TimeScale timeScale, double y, Wink min, Wink max) { this.name = task.getName(); this.y = y; this.timeScale = timeScale; @@ -122,7 +126,7 @@ public class TaskDrawSeparator implements TaskDraw { return y + getHeight() / 2; } - public void setColors(ComplementColors colors) { + public void setColorsAndCompletion(ComplementColors colors, int completion) { } } diff --git a/src/net/sourceforge/plantuml/project/draw/TimeHeader.java b/src/net/sourceforge/plantuml/project/draw/TimeHeader.java new file mode 100644 index 000000000..982f9c82d --- /dev/null +++ b/src/net/sourceforge/plantuml/project/draw/TimeHeader.java @@ -0,0 +1,113 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.project.draw; + +import net.sourceforge.plantuml.SpriteContainerEmpty; +import net.sourceforge.plantuml.cucadiagram.Display; +import net.sourceforge.plantuml.graphic.FontConfiguration; +import net.sourceforge.plantuml.graphic.HorizontalAlignment; +import net.sourceforge.plantuml.graphic.HtmlColorUtils; +import net.sourceforge.plantuml.graphic.TextBlock; +import net.sourceforge.plantuml.project.core.Wink; +import net.sourceforge.plantuml.project.timescale.TimeScale; +import net.sourceforge.plantuml.ugraphic.UChangeColor; +import net.sourceforge.plantuml.ugraphic.UFont; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.ULine; +import net.sourceforge.plantuml.ugraphic.UTranslate; +import sun.security.x509.AVA; + +public abstract class TimeHeader { + + private final TimeScale timeScale; + protected final Wink min; + protected final Wink max; + + public TimeHeader(Wink min, Wink max, TimeScale timeScale) { + this.timeScale = timeScale; + this.min = min; + this.max = max; + } + + public abstract void drawTimeHeader(final UGraphic ug, double totalHeight); + + 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 ULine hline = new ULine(xmax - xmin, 0); + ug.apply(new UChangeColor(HtmlColorUtils.LIGHT_GRAY)).apply(new UTranslate(0, y)).draw(hline); + } + + final protected FontConfiguration getFontConfiguration(int size, boolean bold) { + UFont font = UFont.serif(size); + if (bold) { + font = font.bold(); + } + return new FontConfiguration(font, HtmlColorUtils.BLACK, HtmlColorUtils.BLACK, false); + } + + public final TimeScale getTimeScale() { + return timeScale; + } + + protected final TextBlock getTextBlock(final String text, int size, boolean bold) { + return Display.getWithNewlines(text).create(getFontConfiguration(size, bold), HorizontalAlignment.LEFT, + new SpriteContainerEmpty()); + } + + protected final void printCentered(UGraphic ug, TextBlock text, double start, double end) { + final double width = text.calculateDimension(ug.getStringBounder()).getWidth(); + final double available = end - start; + final double diff = Math.max(0, available - width); + text.drawU(ug.apply(new UTranslate(start + diff / 2, 0))); + } + + protected final void printCentered(UGraphic ug, double start, double end, TextBlock... texts) { + final double available = end - start; + for (int i = texts.length - 1; i >= 0; i--) { + final TextBlock text = texts[i]; + final double width = text.calculateDimension(ug.getStringBounder()).getWidth(); + if (i == 0 || width <= available) { + final double diff = Math.max(0, available - width); + text.drawU(ug.apply(new UTranslate(start + diff / 2, 0))); + return; + } + } + } + +} diff --git a/src/net/sourceforge/plantuml/project/draw/TimeHeaderDaily.java b/src/net/sourceforge/plantuml/project/draw/TimeHeaderDaily.java new file mode 100644 index 000000000..a0a819fef --- /dev/null +++ b/src/net/sourceforge/plantuml/project/draw/TimeHeaderDaily.java @@ -0,0 +1,188 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.project.draw; + +import java.util.Map; + +import net.sourceforge.plantuml.graphic.HtmlColor; +import net.sourceforge.plantuml.graphic.HtmlColorSetSimple; +import net.sourceforge.plantuml.graphic.HtmlColorUtils; +import net.sourceforge.plantuml.graphic.TextBlock; +import net.sourceforge.plantuml.project.DayAsDate; +import net.sourceforge.plantuml.project.DayOfWeek; +import net.sourceforge.plantuml.project.GCalendar; +import net.sourceforge.plantuml.project.LoadPlanable; +import net.sourceforge.plantuml.project.core.Month; +import net.sourceforge.plantuml.project.core.Wink; +import net.sourceforge.plantuml.project.timescale.TimeScaleDaily; +import net.sourceforge.plantuml.ugraphic.UChangeBackColor; +import net.sourceforge.plantuml.ugraphic.UChangeColor; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.ULine; +import net.sourceforge.plantuml.ugraphic.URectangle; +import net.sourceforge.plantuml.ugraphic.UTranslate; + +public class TimeHeaderDaily extends TimeHeader { + + private static final int Y_POS_WEEKDAY = 16; + private static final int Y_POS_NUMDAY = 28; + + private double getTimeHeaderHeight() { + return Y_POS_NUMDAY + 13; + } + + private final HtmlColor veryLightGray = new HtmlColorSetSimple().getColorIfValid("#E0E8E8"); + + private final GCalendar calendar; + private final LoadPlanable defaultPlan; + private final Map colorDays; + private final Map nameDays; + + public TimeHeaderDaily(GCalendar calendar, Wink min, Wink max, LoadPlanable defaultPlan, + Map colorDays, Map nameDays, DayAsDate printStart, + DayAsDate printEnd) { + super(min, max, new TimeScaleDaily(calendar, printStart)); + this.calendar = calendar; + this.defaultPlan = defaultPlan; + this.colorDays = colorDays; + this.nameDays = nameDays; + } + + @Override + public void drawTimeHeader(final UGraphic ug, double totalHeight) { + drawCalendar(ug, totalHeight); + drawHline(ug, 0); + drawHline(ug, getFullHeaderHeight()); + + } + + private void drawCalendar(final UGraphic ug, double totalHeight) { + Month lastMonth = null; + double lastChangeMonth = -1; + Wink wink = min; + while (wink.compareTo(max) <= 0) { + final DayAsDate day = calendar.toDayAsDate(wink); + final DayOfWeek dayOfWeek = day.getDayOfWeek(); + final boolean isWorkingDay = defaultPlan.getLoadAt(wink) > 0; + final String d1 = "" + day.getDayOfMonth(); + final TextBlock num = getTextBlock(d1, 10, false); + final double x1 = getTimeScale().getStartingPosition(wink); + final double x2 = getTimeScale().getEndingPosition(wink); + double startingY = getFullHeaderHeight(); + if (wink.compareTo(max.increment()) < 0) { + final TextBlock weekDay = getTextBlock(dayOfWeek.shortName(), 10, false); + + final URectangle rect = new URectangle(x2 - x1 - 1, totalHeight - getFullHeaderHeight()); + if (isWorkingDay) { + final HtmlColor back = colorDays.get(day); + if (back != null) { + ug.apply(new UChangeColor(null)).apply(new UChangeBackColor(back)) + .apply(new UTranslate(x1 + 1, getFullHeaderHeight())).draw(rect); + } + printCentered(ug.apply(new UTranslate(0, Y_POS_WEEKDAY)), weekDay, x1, x2); + printCentered(ug.apply(new UTranslate(0, Y_POS_NUMDAY)), num, x1, x2); + } else { + ug.apply(new UChangeColor(null)).apply(new UChangeBackColor(veryLightGray)) + .apply(new UTranslate(x1 + 1, getFullHeaderHeight())).draw(rect); + } + if (lastMonth != day.getMonth()) { + startingY = 0; + if (lastMonth != null) { + printMonth(ug, lastMonth, day.getYear(), lastChangeMonth, x1); + } + lastChangeMonth = x1; + lastMonth = day.getMonth(); + } + } + drawVbar(ug, x1, startingY, totalHeight); + wink = wink.increment(); + } + final DayAsDate day = calendar.toDayAsDate(max); + final double x1 = getTimeScale().getStartingPosition(wink); + drawVbar(ug, x1, Y_POS_WEEKDAY, totalHeight); + if (x1 > lastChangeMonth) { + printMonth(ug, lastMonth, day.getYear(), lastChangeMonth, x1); + } + + printNamedDays(ug); + + } + + private void printMonth(UGraphic ug, Month lastMonth, int year, double start, double end) { + final TextBlock tiny = getTextBlock(lastMonth.shortName(), 12, true); + final TextBlock small = getTextBlock(lastMonth.niceName(), 12, true); + final TextBlock big = getTextBlock(lastMonth.niceName() + " " + year, 12, true); + printCentered(ug, start, end, tiny, small, big); + } + + private void drawVbar(UGraphic ug, double x, double y1, double y2) { + final ULine vbar = new ULine(0, y2 - y1); + ug.apply(new UChangeColor(HtmlColorUtils.LIGHT_GRAY)).apply(new UTranslate(x, y1)).draw(vbar); + } + + private void printNamedDays(final UGraphic ug) { + if (nameDays.size() > 0) { + String last = null; + for (Wink wink = min; wink.compareTo(max.increment()) <= 0; wink = wink.increment()) { + final DayAsDate tmpday = calendar.toDayAsDate(wink); + final String name = nameDays.get(tmpday); + if (name != null && name.equals(last) == false) { + final double x1 = getTimeScale().getStartingPosition(wink); + final double x2 = getTimeScale().getEndingPosition(wink); + final TextBlock label = getTextBlock(name, 12, false); + final double h = label.calculateDimension(ug.getStringBounder()).getHeight(); + double y1 = getTimeHeaderHeight(); + double y2 = getFullHeaderHeight(); + label.drawU(ug.apply(new UTranslate(x1, Y_POS_NUMDAY + 11))); + } + last = name; + } + } + } + + @Override + public double getFullHeaderHeight() { + return getTimeHeaderHeight() + getHeaderNameDayHeight(); + } + + private double getHeaderNameDayHeight() { + if (nameDays.size() > 0) { + return 16; + } + return 0; + } + +} diff --git a/src/net/sourceforge/plantuml/project/draw/TimeHeaderSimple.java b/src/net/sourceforge/plantuml/project/draw/TimeHeaderSimple.java new file mode 100644 index 000000000..2d07d261d --- /dev/null +++ b/src/net/sourceforge/plantuml/project/draw/TimeHeaderSimple.java @@ -0,0 +1,97 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.project.draw; + +import net.sourceforge.plantuml.SpriteContainerEmpty; +import net.sourceforge.plantuml.cucadiagram.Display; +import net.sourceforge.plantuml.graphic.HorizontalAlignment; +import net.sourceforge.plantuml.graphic.HtmlColorUtils; +import net.sourceforge.plantuml.graphic.TextBlock; +import net.sourceforge.plantuml.project.core.Wink; +import net.sourceforge.plantuml.project.timescale.TimeScale; +import net.sourceforge.plantuml.project.timescale.TimeScaleWink; +import net.sourceforge.plantuml.ugraphic.UChangeColor; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.ULine; +import net.sourceforge.plantuml.ugraphic.UTranslate; + +public class TimeHeaderSimple extends TimeHeader { + + public TimeHeaderSimple(Wink min, Wink max) { + super(min, max, new TimeScaleWink()); + } + + @Override + public void drawTimeHeader(final UGraphic ug, double totalHeight) { + final double xmin = getTimeScale().getStartingPosition(min); + final double xmax = getTimeScale().getEndingPosition(max); + drawSimpleDayCounter(ug, getTimeScale(), totalHeight); + ug.apply(new UChangeColor(HtmlColorUtils.LIGHT_GRAY)).draw(new ULine(xmax - xmin, 0)); + ug.apply(new UChangeColor(HtmlColorUtils.LIGHT_GRAY)).apply(new UTranslate(0, getFullHeaderHeight() - 3)) + .draw(new ULine(xmax - xmin, 0)); + + } + + private void drawSimpleDayCounter(final UGraphic ug, TimeScale timeScale, double totalHeight) { + final ULine vbar = new ULine(0, totalHeight); + for (Wink i = min; i.compareTo(max.increment()) <= 0; i = i.increment()) { + final TextBlock num = Display.getWithNewlines(i.toShortString()).create(getFontConfiguration(10, false), + HorizontalAlignment.LEFT, new SpriteContainerEmpty()); + final double x1 = timeScale.getStartingPosition(i); + final double x2 = timeScale.getEndingPosition(i); + final double width = num.calculateDimension(ug.getStringBounder()).getWidth(); + final double delta = (x2 - x1) - width; + if (i.compareTo(max.increment()) < 0) { + num.drawU(ug.apply(new UTranslate(x1 + delta / 2, 0))); + } + ug.apply(new UChangeColor(HtmlColorUtils.LIGHT_GRAY)).apply(new UTranslate(x1, 0)).draw(vbar); + } + } + + @Override + public double getFullHeaderHeight() { + return getTimeHeaderHeight() + getHeaderNameDayHeight(); + } + + private double getTimeHeaderHeight() { + return 16; + } + + private double getHeaderNameDayHeight() { + return 0; + } + +} diff --git a/src/net/sourceforge/plantuml/project/draw/TimeHeaderWeekly.java b/src/net/sourceforge/plantuml/project/draw/TimeHeaderWeekly.java new file mode 100644 index 000000000..d6433515c --- /dev/null +++ b/src/net/sourceforge/plantuml/project/draw/TimeHeaderWeekly.java @@ -0,0 +1,188 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.project.draw; + +import java.util.Map; + +import net.sourceforge.plantuml.SpriteContainerEmpty; +import net.sourceforge.plantuml.cucadiagram.Display; +import net.sourceforge.plantuml.graphic.HorizontalAlignment; +import net.sourceforge.plantuml.graphic.HtmlColor; +import net.sourceforge.plantuml.graphic.HtmlColorSetSimple; +import net.sourceforge.plantuml.graphic.HtmlColorUtils; +import net.sourceforge.plantuml.graphic.TextBlock; +import net.sourceforge.plantuml.project.DayAsDate; +import net.sourceforge.plantuml.project.DayOfWeek; +import net.sourceforge.plantuml.project.GCalendar; +import net.sourceforge.plantuml.project.LoadPlanable; +import net.sourceforge.plantuml.project.core.Month; +import net.sourceforge.plantuml.project.core.Wink; +import net.sourceforge.plantuml.project.timescale.TimeScaleWeekly; +import net.sourceforge.plantuml.ugraphic.UChangeColor; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.ULine; +import net.sourceforge.plantuml.ugraphic.UTranslate; + +public class TimeHeaderWeekly extends TimeHeader { + + private static final int Y_POS_NUMDAY = 16; + + private double getTimeHeaderHeight() { + return Y_POS_NUMDAY + 13; + } + + private final HtmlColor veryLightGray = new HtmlColorSetSimple().getColorIfValid("#E0E8E8"); + + private final GCalendar calendar; + private final LoadPlanable defaultPlan; + private final Map colorDays; + private final Map nameDays; + + public TimeHeaderWeekly(GCalendar calendar, Wink min, Wink max, LoadPlanable defaultPlan, + Map colorDays, Map nameDays) { + super(min, max, new TimeScaleWeekly(calendar)); + this.calendar = calendar; + this.defaultPlan = defaultPlan; + this.colorDays = colorDays; + this.nameDays = nameDays; + } + + @Override + public void drawTimeHeader(final UGraphic ug, double totalHeight) { + drawCalendar(ug, totalHeight); + drawHline(ug, 0); + drawHline(ug, Y_POS_NUMDAY); + drawHline(ug, getFullHeaderHeight()); + + } + + private void drawCalendar(final UGraphic ug, double totalHeight) { + Month lastMonth = null; + double lastChangeMonth = -1; + Wink wink = min; + while (wink.compareTo(max) <= 0) { + final DayAsDate day = calendar.toDayAsDate(wink); + final DayOfWeek dayOfWeek = day.getDayOfWeek(); + final String d1 = "" + day.getDayOfMonth(); + final TextBlock num = getTextBlock(d1, 10, false); + final double x1 = getTimeScale().getStartingPosition(wink); + final double x2 = getTimeScale().getEndingPosition(wink); + double startingY = getFullHeaderHeight(); + if (wink.compareTo(max.increment()) < 0) { + if (dayOfWeek == DayOfWeek.MONDAY) { + printLeft(ug.apply(new UTranslate(0, Y_POS_NUMDAY)), num, x1 + 5); + } + if (lastMonth != day.getMonth()) { + startingY = Y_POS_NUMDAY; + drawVbar(ug, x1, 0, Y_POS_NUMDAY); + if (lastMonth != null) { + printMonth(ug, lastMonth, day.getYear(), lastChangeMonth, x1); + } + lastChangeMonth = x1; + lastMonth = day.getMonth(); + } + } + if (dayOfWeek == DayOfWeek.MONDAY) { + drawVbar(ug, x1, Y_POS_NUMDAY, totalHeight); + } + wink = wink.increment(); + } + final DayAsDate day = calendar.toDayAsDate(wink); + final double x1 = getTimeScale().getStartingPosition(wink); + if (x1 > lastChangeMonth) { + printMonth(ug, lastMonth, day.getYear(), lastChangeMonth, x1); + } + + printNamedDays(ug); + + } + + private void printMonth(UGraphic ug, Month lastMonth, int year, double start, double end) { + final TextBlock small = getTextBlock(lastMonth.shortName(), 12, true); + final TextBlock big = getTextBlock(lastMonth.shortName() + " " + year, 12, true); + printCentered(ug, start, end, small, big); + } + + private void drawVbar(UGraphic ug, double x, double y1, double y2) { + final ULine vbar = new ULine(0, y2 - y1); + ug.apply(new UChangeColor(HtmlColorUtils.LIGHT_GRAY)).apply(new UTranslate(x, y1)).draw(vbar); + } + + private void printNamedDays(final UGraphic ug) { +// if (nameDays.size() > 0) { +// String last = null; +// for (Wink wink = min; wink.compareTo(max.increment()) <= 0; wink = wink.increment()) { +// final DayAsDate tmpday = calendar.toDayAsDate(wink); +// final String name = nameDays.get(tmpday); +// if (name != null && name.equals(last) == false) { +// final double x1 = getTimeScale().getStartingPosition(wink); +// final double x2 = getTimeScale().getEndingPosition(wink); +// final TextBlock label = getTextBlock(name, 12, false); +// final double h = label.calculateDimension(ug.getStringBounder()).getHeight(); +// double y1 = getTimeHeaderHeight(); +// double y2 = getFullHeaderHeight(); +// label.drawU(ug.apply(new UTranslate(x1, Y_POS_NUMDAY + 11))); +// } +// last = name; +// } +// } + } + + private void printLeft(UGraphic ug, TextBlock text, double start) { + text.drawU(ug.apply(new UTranslate(start, 0))); + } + + @Override + public double getFullHeaderHeight() { + return getTimeHeaderHeight() + getHeaderNameDayHeight(); + } + + private double getHeaderNameDayHeight() { +// if (nameDays.size() > 0) { +// return 16; +// } + return 0; + } + +// private void drawCenter(final UGraphic ug, final TextBlock text, final double x1, final double x2) { +// final double width = text.calculateDimension(ug.getStringBounder()).getWidth(); +// final double delta = (x2 - x1) - width; +// if (delta < 0) { +// return; +// } +// text.drawU(ug.apply(new UTranslate(x1 + delta / 2, 0))); +// } +} diff --git a/src/net/sourceforge/plantuml/project3/Complement.java b/src/net/sourceforge/plantuml/project/lang/Complement.java similarity index 96% rename from src/net/sourceforge/plantuml/project3/Complement.java rename to src/net/sourceforge/plantuml/project/lang/Complement.java index d9731d5f7..b20145e45 100644 --- a/src/net/sourceforge/plantuml/project3/Complement.java +++ b/src/net/sourceforge/plantuml/project/lang/Complement.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; public interface Complement { diff --git a/src/net/sourceforge/plantuml/project3/ComplementBeforeOrAfterOrAtTaskStartOrEnd.java b/src/net/sourceforge/plantuml/project/lang/ComplementBeforeOrAfterOrAtTaskStartOrEnd.java similarity index 88% rename from src/net/sourceforge/plantuml/project3/ComplementBeforeOrAfterOrAtTaskStartOrEnd.java rename to src/net/sourceforge/plantuml/project/lang/ComplementBeforeOrAfterOrAtTaskStartOrEnd.java index 304eea13b..27f31f020 100644 --- a/src/net/sourceforge/plantuml/project3/ComplementBeforeOrAfterOrAtTaskStartOrEnd.java +++ b/src/net/sourceforge/plantuml/project/lang/ComplementBeforeOrAfterOrAtTaskStartOrEnd.java @@ -33,11 +33,16 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.Failable; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.core.Moment; +import net.sourceforge.plantuml.project.core.TaskAttribute; +import net.sourceforge.plantuml.project.core.TaskInstant; public class ComplementBeforeOrAfterOrAtTaskStartOrEnd implements ComplementPattern { diff --git a/src/net/sourceforge/plantuml/project3/ComplementClose.java b/src/net/sourceforge/plantuml/project/lang/ComplementClose.java similarity index 92% rename from src/net/sourceforge/plantuml/project3/ComplementClose.java rename to src/net/sourceforge/plantuml/project/lang/ComplementClose.java index b0059976a..e66247aa5 100644 --- a/src/net/sourceforge/plantuml/project3/ComplementClose.java +++ b/src/net/sourceforge/plantuml/project/lang/ComplementClose.java @@ -33,11 +33,13 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.Failable; +import net.sourceforge.plantuml.project.GanttDiagram; public class ComplementClose implements ComplementPattern { diff --git a/src/net/sourceforge/plantuml/project3/ComplementColors.java b/src/net/sourceforge/plantuml/project/lang/ComplementColors.java similarity index 97% rename from src/net/sourceforge/plantuml/project3/ComplementColors.java rename to src/net/sourceforge/plantuml/project/lang/ComplementColors.java index a583fcd93..4bb445c1f 100644 --- a/src/net/sourceforge/plantuml/project3/ComplementColors.java +++ b/src/net/sourceforge/plantuml/project/lang/ComplementColors.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import net.sourceforge.plantuml.graphic.HtmlColor; import net.sourceforge.plantuml.ugraphic.UChangeBackColor; diff --git a/src/net/sourceforge/plantuml/project/lang/ComplementCompleted.java b/src/net/sourceforge/plantuml/project/lang/ComplementCompleted.java new file mode 100644 index 000000000..e6ff4b7f8 --- /dev/null +++ b/src/net/sourceforge/plantuml/project/lang/ComplementCompleted.java @@ -0,0 +1,55 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.project.lang; + +import net.sourceforge.plantuml.command.regex.IRegex; +import net.sourceforge.plantuml.command.regex.RegexLeaf; +import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.Completion; +import net.sourceforge.plantuml.project.Failable; +import net.sourceforge.plantuml.project.GanttDiagram; + +public class ComplementCompleted implements ComplementPattern { + + public IRegex toRegex(String suffix) { + return new RegexLeaf("COMPLEMENT" + suffix, "(\\d+).*completed?"); + } + + public Failable getComplement(GanttDiagram system, RegexResult arg, String suffix) { + final String value = arg.get("COMPLEMENT" + suffix, 0); + return Failable.ok(new Completion(Integer.parseInt(value))); + } +} diff --git a/src/net/sourceforge/plantuml/project3/ComplementDate.java b/src/net/sourceforge/plantuml/project/lang/ComplementDate.java similarity index 94% rename from src/net/sourceforge/plantuml/project3/ComplementDate.java rename to src/net/sourceforge/plantuml/project/lang/ComplementDate.java index 5683fabe8..e4cdb55ee 100644 --- a/src/net/sourceforge/plantuml/project3/ComplementDate.java +++ b/src/net/sourceforge/plantuml/project/lang/ComplementDate.java @@ -33,13 +33,17 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexConcat; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexOr; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.DayAsDate; +import net.sourceforge.plantuml.project.Failable; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.core.Month; public class ComplementDate implements ComplementPattern { diff --git a/src/net/sourceforge/plantuml/project3/ComplementDates.java b/src/net/sourceforge/plantuml/project/lang/ComplementDates.java similarity index 93% rename from src/net/sourceforge/plantuml/project3/ComplementDates.java rename to src/net/sourceforge/plantuml/project/lang/ComplementDates.java index b09f2fad0..7cbb13e74 100644 --- a/src/net/sourceforge/plantuml/project3/ComplementDates.java +++ b/src/net/sourceforge/plantuml/project/lang/ComplementDates.java @@ -33,12 +33,16 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexConcat; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.DayAsDate; +import net.sourceforge.plantuml.project.DaysAsDates; +import net.sourceforge.plantuml.project.Failable; +import net.sourceforge.plantuml.project.GanttDiagram; public class ComplementDates implements ComplementPattern { diff --git a/src/net/sourceforge/plantuml/project3/ComplementDayOfWeek.java b/src/net/sourceforge/plantuml/project/lang/ComplementDayOfWeek.java similarity index 90% rename from src/net/sourceforge/plantuml/project3/ComplementDayOfWeek.java rename to src/net/sourceforge/plantuml/project/lang/ComplementDayOfWeek.java index ce2a97577..416352281 100644 --- a/src/net/sourceforge/plantuml/project3/ComplementDayOfWeek.java +++ b/src/net/sourceforge/plantuml/project/lang/ComplementDayOfWeek.java @@ -33,12 +33,15 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexConcat; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.DayOfWeek; +import net.sourceforge.plantuml.project.Failable; +import net.sourceforge.plantuml.project.GanttDiagram; public class ComplementDayOfWeek implements ComplementPattern { diff --git a/src/net/sourceforge/plantuml/project3/ComplementEmpty.java b/src/net/sourceforge/plantuml/project/lang/ComplementEmpty.java similarity index 91% rename from src/net/sourceforge/plantuml/project3/ComplementEmpty.java rename to src/net/sourceforge/plantuml/project/lang/ComplementEmpty.java index 874804789..ef9a03c4c 100644 --- a/src/net/sourceforge/plantuml/project3/ComplementEmpty.java +++ b/src/net/sourceforge/plantuml/project/lang/ComplementEmpty.java @@ -33,11 +33,13 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.Failable; +import net.sourceforge.plantuml.project.GanttDiagram; public class ComplementEmpty implements ComplementPattern { diff --git a/src/net/sourceforge/plantuml/project3/ComplementInColors.java b/src/net/sourceforge/plantuml/project/lang/ComplementInColors.java similarity index 93% rename from src/net/sourceforge/plantuml/project3/ComplementInColors.java rename to src/net/sourceforge/plantuml/project/lang/ComplementInColors.java index b8826e5ae..0c9b5b68c 100644 --- a/src/net/sourceforge/plantuml/project3/ComplementInColors.java +++ b/src/net/sourceforge/plantuml/project/lang/ComplementInColors.java @@ -33,12 +33,14 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; import net.sourceforge.plantuml.graphic.HtmlColor; +import net.sourceforge.plantuml.project.Failable; +import net.sourceforge.plantuml.project.GanttDiagram; public class ComplementInColors implements ComplementPattern { diff --git a/src/net/sourceforge/plantuml/project3/ComplementInColors2.java b/src/net/sourceforge/plantuml/project/lang/ComplementInColors2.java similarity index 93% rename from src/net/sourceforge/plantuml/project3/ComplementInColors2.java rename to src/net/sourceforge/plantuml/project/lang/ComplementInColors2.java index 93f6d8a5f..fb1b504c2 100644 --- a/src/net/sourceforge/plantuml/project3/ComplementInColors2.java +++ b/src/net/sourceforge/plantuml/project/lang/ComplementInColors2.java @@ -33,12 +33,14 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; import net.sourceforge.plantuml.graphic.HtmlColor; +import net.sourceforge.plantuml.project.Failable; +import net.sourceforge.plantuml.project.GanttDiagram; public class ComplementInColors2 implements ComplementPattern { diff --git a/src/net/sourceforge/plantuml/project3/ComplementName.java b/src/net/sourceforge/plantuml/project/lang/ComplementName.java similarity index 96% rename from src/net/sourceforge/plantuml/project3/ComplementName.java rename to src/net/sourceforge/plantuml/project/lang/ComplementName.java index ed0e8ffee..75cf8997d 100644 --- a/src/net/sourceforge/plantuml/project3/ComplementName.java +++ b/src/net/sourceforge/plantuml/project/lang/ComplementName.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; public class ComplementName implements Complement { diff --git a/src/net/sourceforge/plantuml/project3/ComplementNamed.java b/src/net/sourceforge/plantuml/project/lang/ComplementNamed.java similarity index 92% rename from src/net/sourceforge/plantuml/project3/ComplementNamed.java rename to src/net/sourceforge/plantuml/project/lang/ComplementNamed.java index 0eee95740..55ee6fd6e 100644 --- a/src/net/sourceforge/plantuml/project3/ComplementNamed.java +++ b/src/net/sourceforge/plantuml/project/lang/ComplementNamed.java @@ -33,11 +33,13 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.Failable; +import net.sourceforge.plantuml.project.GanttDiagram; public class ComplementNamed implements ComplementPattern { diff --git a/src/net/sourceforge/plantuml/project3/ComplementOpen.java b/src/net/sourceforge/plantuml/project/lang/ComplementOpen.java similarity index 92% rename from src/net/sourceforge/plantuml/project3/ComplementOpen.java rename to src/net/sourceforge/plantuml/project/lang/ComplementOpen.java index 975352f0f..69fd6bec0 100644 --- a/src/net/sourceforge/plantuml/project3/ComplementOpen.java +++ b/src/net/sourceforge/plantuml/project/lang/ComplementOpen.java @@ -33,11 +33,13 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.Failable; +import net.sourceforge.plantuml.project.GanttDiagram; public class ComplementOpen implements ComplementPattern { diff --git a/src/net/sourceforge/plantuml/project3/ComplementPattern.java b/src/net/sourceforge/plantuml/project/lang/ComplementPattern.java similarity index 91% rename from src/net/sourceforge/plantuml/project3/ComplementPattern.java rename to src/net/sourceforge/plantuml/project/lang/ComplementPattern.java index 7f429a27f..cf5b0057f 100644 --- a/src/net/sourceforge/plantuml/project3/ComplementPattern.java +++ b/src/net/sourceforge/plantuml/project/lang/ComplementPattern.java @@ -33,10 +33,12 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.Failable; +import net.sourceforge.plantuml.project.GanttDiagram; public interface ComplementPattern { diff --git a/src/net/sourceforge/plantuml/project3/ComplementSeveralDays.java b/src/net/sourceforge/plantuml/project/lang/ComplementSeveralDays.java similarity index 89% rename from src/net/sourceforge/plantuml/project3/ComplementSeveralDays.java rename to src/net/sourceforge/plantuml/project/lang/ComplementSeveralDays.java index 91a1cd021..41a35d4bb 100644 --- a/src/net/sourceforge/plantuml/project3/ComplementSeveralDays.java +++ b/src/net/sourceforge/plantuml/project/lang/ComplementSeveralDays.java @@ -33,12 +33,15 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexConcat; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.Failable; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.Load; public class ComplementSeveralDays implements ComplementPattern { @@ -52,7 +55,7 @@ public class ComplementSeveralDays implements ComplementPattern { final boolean inWeeks = arg.get("COMPLEMENT" + suffix, 1).startsWith("w"); final int factor = inWeeks ? system.daysInWeek() : 1; final int days = Integer.parseInt(number) * factor; - return Failable. ok(LoadInDays.inDay(days)); + return Failable. ok(Load.inWinks(days)); } } diff --git a/src/net/sourceforge/plantuml/project3/Subject.java b/src/net/sourceforge/plantuml/project/lang/Subject.java similarity index 96% rename from src/net/sourceforge/plantuml/project3/Subject.java rename to src/net/sourceforge/plantuml/project/lang/Subject.java index ef1be6430..fba6a654e 100644 --- a/src/net/sourceforge/plantuml/project3/Subject.java +++ b/src/net/sourceforge/plantuml/project/lang/Subject.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; public interface Subject { diff --git a/src/net/sourceforge/plantuml/project3/SubjectDayAsDate.java b/src/net/sourceforge/plantuml/project/lang/SubjectDayAsDate.java similarity index 93% rename from src/net/sourceforge/plantuml/project3/SubjectDayAsDate.java rename to src/net/sourceforge/plantuml/project/lang/SubjectDayAsDate.java index 27737ac72..55992f2b8 100644 --- a/src/net/sourceforge/plantuml/project3/SubjectDayAsDate.java +++ b/src/net/sourceforge/plantuml/project/lang/SubjectDayAsDate.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import java.util.Arrays; import java.util.Collection; @@ -42,6 +42,8 @@ import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexConcat; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.DayAsDate; +import net.sourceforge.plantuml.project.GanttDiagram; public class SubjectDayAsDate implements SubjectPattern { diff --git a/src/net/sourceforge/plantuml/project3/SubjectDayOfWeek.java b/src/net/sourceforge/plantuml/project/lang/SubjectDayOfWeek.java similarity index 92% rename from src/net/sourceforge/plantuml/project3/SubjectDayOfWeek.java rename to src/net/sourceforge/plantuml/project/lang/SubjectDayOfWeek.java index 899d5e3cb..5f2ab8192 100644 --- a/src/net/sourceforge/plantuml/project3/SubjectDayOfWeek.java +++ b/src/net/sourceforge/plantuml/project/lang/SubjectDayOfWeek.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import java.util.Arrays; import java.util.Collection; @@ -41,6 +41,8 @@ import java.util.Collection; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.DayOfWeek; +import net.sourceforge.plantuml.project.GanttDiagram; public class SubjectDayOfWeek implements SubjectPattern { diff --git a/src/net/sourceforge/plantuml/project3/SubjectDaysAsDates.java b/src/net/sourceforge/plantuml/project/lang/SubjectDaysAsDates.java similarity index 95% rename from src/net/sourceforge/plantuml/project3/SubjectDaysAsDates.java rename to src/net/sourceforge/plantuml/project/lang/SubjectDaysAsDates.java index ac7d04973..95398e7a5 100644 --- a/src/net/sourceforge/plantuml/project3/SubjectDaysAsDates.java +++ b/src/net/sourceforge/plantuml/project/lang/SubjectDaysAsDates.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import java.util.Arrays; import java.util.Collection; @@ -43,6 +43,9 @@ import net.sourceforge.plantuml.command.regex.RegexConcat; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexOr; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.DayAsDate; +import net.sourceforge.plantuml.project.DaysAsDates; +import net.sourceforge.plantuml.project.GanttDiagram; public class SubjectDaysAsDates implements SubjectPattern { diff --git a/src/net/sourceforge/plantuml/project3/SubjectPattern.java b/src/net/sourceforge/plantuml/project/lang/SubjectPattern.java similarity index 93% rename from src/net/sourceforge/plantuml/project3/SubjectPattern.java rename to src/net/sourceforge/plantuml/project/lang/SubjectPattern.java index 99d39c346..155f4719b 100644 --- a/src/net/sourceforge/plantuml/project3/SubjectPattern.java +++ b/src/net/sourceforge/plantuml/project/lang/SubjectPattern.java @@ -33,12 +33,13 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import java.util.Collection; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.GanttDiagram; public interface SubjectPattern { diff --git a/src/net/sourceforge/plantuml/project3/SubjectProject.java b/src/net/sourceforge/plantuml/project/lang/SubjectProject.java similarity index 94% rename from src/net/sourceforge/plantuml/project3/SubjectProject.java rename to src/net/sourceforge/plantuml/project/lang/SubjectProject.java index 49e83f809..88d36c2e4 100644 --- a/src/net/sourceforge/plantuml/project3/SubjectProject.java +++ b/src/net/sourceforge/plantuml/project/lang/SubjectProject.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import java.util.Arrays; import java.util.Collection; @@ -41,6 +41,7 @@ import java.util.Collection; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.GanttDiagram; public class SubjectProject implements SubjectPattern { diff --git a/src/net/sourceforge/plantuml/project3/SubjectResource.java b/src/net/sourceforge/plantuml/project/lang/SubjectResource.java similarity index 95% rename from src/net/sourceforge/plantuml/project3/SubjectResource.java rename to src/net/sourceforge/plantuml/project/lang/SubjectResource.java index 510d074b3..7723325c1 100644 --- a/src/net/sourceforge/plantuml/project3/SubjectResource.java +++ b/src/net/sourceforge/plantuml/project/lang/SubjectResource.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import java.util.Arrays; import java.util.Collection; @@ -42,6 +42,7 @@ import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexConcat; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.GanttDiagram; public class SubjectResource implements SubjectPattern { diff --git a/src/net/sourceforge/plantuml/project3/SubjectTask.java b/src/net/sourceforge/plantuml/project/lang/SubjectTask.java similarity index 93% rename from src/net/sourceforge/plantuml/project3/SubjectTask.java rename to src/net/sourceforge/plantuml/project/lang/SubjectTask.java index e570b3e77..2b73cb61f 100644 --- a/src/net/sourceforge/plantuml/project3/SubjectTask.java +++ b/src/net/sourceforge/plantuml/project/lang/SubjectTask.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import java.util.Arrays; import java.util.Collection; @@ -44,6 +44,8 @@ import net.sourceforge.plantuml.command.regex.RegexConcat; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexOptional; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.core.Task; public class SubjectTask implements SubjectPattern { @@ -51,7 +53,7 @@ public class SubjectTask implements SubjectPattern { return Arrays . asList(new VerbLasts(), new VerbTaskStarts(), new VerbTaskStartsAbsolute(), new VerbHappens(), new VerbEnds(), new VerbTaskEndsAbsolute(), new VerbIsColored(), - new VerbIsDeleted()); + new VerbIsDeleted(), new VerbIsForTask()); } public IRegex toRegex() { diff --git a/src/net/sourceforge/plantuml/project3/SubjectToday.java b/src/net/sourceforge/plantuml/project/lang/SubjectToday.java similarity index 92% rename from src/net/sourceforge/plantuml/project3/SubjectToday.java rename to src/net/sourceforge/plantuml/project/lang/SubjectToday.java index 595414566..1e58b7d78 100644 --- a/src/net/sourceforge/plantuml/project3/SubjectToday.java +++ b/src/net/sourceforge/plantuml/project/lang/SubjectToday.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import java.util.Arrays; import java.util.Collection; @@ -42,6 +42,8 @@ import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexConcat; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.Today; public class SubjectToday implements SubjectPattern { diff --git a/src/net/sourceforge/plantuml/project3/Verb.java b/src/net/sourceforge/plantuml/project/lang/Verb.java similarity index 96% rename from src/net/sourceforge/plantuml/project3/Verb.java rename to src/net/sourceforge/plantuml/project/lang/Verb.java index cd74b50df..dc46160a2 100644 --- a/src/net/sourceforge/plantuml/project3/Verb.java +++ b/src/net/sourceforge/plantuml/project/lang/Verb.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import net.sourceforge.plantuml.command.CommandExecutionResult; diff --git a/src/net/sourceforge/plantuml/project3/VerbAre.java b/src/net/sourceforge/plantuml/project/lang/VerbAre.java similarity index 93% rename from src/net/sourceforge/plantuml/project3/VerbAre.java rename to src/net/sourceforge/plantuml/project/lang/VerbAre.java index 79ca1ca53..188e25d88 100644 --- a/src/net/sourceforge/plantuml/project3/VerbAre.java +++ b/src/net/sourceforge/plantuml/project/lang/VerbAre.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import java.util.Arrays; import java.util.Collection; @@ -42,6 +42,8 @@ import net.sourceforge.plantuml.command.CommandExecutionResult; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.DayOfWeek; +import net.sourceforge.plantuml.project.GanttDiagram; public class VerbAre implements VerbPattern { diff --git a/src/net/sourceforge/plantuml/project3/VerbEnds.java b/src/net/sourceforge/plantuml/project/lang/VerbEnds.java similarity index 87% rename from src/net/sourceforge/plantuml/project3/VerbEnds.java rename to src/net/sourceforge/plantuml/project/lang/VerbEnds.java index 67637111d..37e67b3cf 100644 --- a/src/net/sourceforge/plantuml/project3/VerbEnds.java +++ b/src/net/sourceforge/plantuml/project/lang/VerbEnds.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import java.util.Arrays; import java.util.Collection; @@ -42,6 +42,11 @@ import net.sourceforge.plantuml.command.CommandExecutionResult; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.GanttConstraint; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.core.Task; +import net.sourceforge.plantuml.project.core.TaskAttribute; +import net.sourceforge.plantuml.project.core.TaskInstant; public class VerbEnds implements VerbPattern { diff --git a/src/net/sourceforge/plantuml/project3/VerbHappens.java b/src/net/sourceforge/plantuml/project/lang/VerbHappens.java similarity index 88% rename from src/net/sourceforge/plantuml/project3/VerbHappens.java rename to src/net/sourceforge/plantuml/project/lang/VerbHappens.java index ba647d221..c17a697d8 100644 --- a/src/net/sourceforge/plantuml/project3/VerbHappens.java +++ b/src/net/sourceforge/plantuml/project/lang/VerbHappens.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import java.util.Arrays; import java.util.Collection; @@ -42,6 +42,11 @@ import net.sourceforge.plantuml.command.CommandExecutionResult; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.DayAsDate; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.Load; +import net.sourceforge.plantuml.project.core.Task; +import net.sourceforge.plantuml.project.core.TaskInstant; public class VerbHappens implements VerbPattern { @@ -57,7 +62,7 @@ public class VerbHappens implements VerbPattern { return new Verb() { public CommandExecutionResult execute(Subject subject, Complement complement) { final Task task = (Task) subject; - task.setLoad(LoadInDays.inDay(1)); + task.setLoad(Load.inWinks(1)); if (complement instanceof DayAsDate) { final DayAsDate start = (DayAsDate) complement; final DayAsDate startingDate = project.getStartingDate(); diff --git a/src/net/sourceforge/plantuml/project3/VerbIsColored.java b/src/net/sourceforge/plantuml/project/lang/VerbIsColored.java similarity index 93% rename from src/net/sourceforge/plantuml/project3/VerbIsColored.java rename to src/net/sourceforge/plantuml/project/lang/VerbIsColored.java index a067a1345..a20d65314 100644 --- a/src/net/sourceforge/plantuml/project3/VerbIsColored.java +++ b/src/net/sourceforge/plantuml/project/lang/VerbIsColored.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import java.util.Arrays; import java.util.Collection; @@ -42,6 +42,8 @@ import net.sourceforge.plantuml.command.CommandExecutionResult; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.core.Task; public class VerbIsColored implements VerbPattern { diff --git a/src/net/sourceforge/plantuml/project3/VerbIsColoredForToday.java b/src/net/sourceforge/plantuml/project/lang/VerbIsColoredForToday.java similarity index 93% rename from src/net/sourceforge/plantuml/project3/VerbIsColoredForToday.java rename to src/net/sourceforge/plantuml/project/lang/VerbIsColoredForToday.java index fa9d5b39d..db4ba86b4 100644 --- a/src/net/sourceforge/plantuml/project3/VerbIsColoredForToday.java +++ b/src/net/sourceforge/plantuml/project/lang/VerbIsColoredForToday.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import java.util.Arrays; import java.util.Collection; @@ -42,6 +42,8 @@ import net.sourceforge.plantuml.command.CommandExecutionResult; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.Today; public class VerbIsColoredForToday implements VerbPattern { diff --git a/src/net/sourceforge/plantuml/project3/VerbIsDeleted.java b/src/net/sourceforge/plantuml/project/lang/VerbIsDeleted.java similarity index 93% rename from src/net/sourceforge/plantuml/project3/VerbIsDeleted.java rename to src/net/sourceforge/plantuml/project/lang/VerbIsDeleted.java index 6b1830d1b..b17519734 100644 --- a/src/net/sourceforge/plantuml/project3/VerbIsDeleted.java +++ b/src/net/sourceforge/plantuml/project/lang/VerbIsDeleted.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import java.util.Arrays; import java.util.Collection; @@ -42,6 +42,8 @@ import net.sourceforge.plantuml.command.CommandExecutionResult; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.core.Task; public class VerbIsDeleted implements VerbPattern { diff --git a/src/net/sourceforge/plantuml/project/lang/VerbIsForTask.java b/src/net/sourceforge/plantuml/project/lang/VerbIsForTask.java new file mode 100644 index 000000000..800473f5e --- /dev/null +++ b/src/net/sourceforge/plantuml/project/lang/VerbIsForTask.java @@ -0,0 +1,70 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.project.lang; + +import java.util.Arrays; +import java.util.Collection; + +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.command.regex.IRegex; +import net.sourceforge.plantuml.command.regex.RegexLeaf; +import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.Completion; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.core.Task; + +public class VerbIsForTask implements VerbPattern { + + public Collection getComplements() { + return Arrays.asList(new ComplementCompleted()); + } + + public IRegex toRegex() { + return new RegexLeaf("is"); + } + + public Verb getVerb(final GanttDiagram project, RegexResult arg) { + return new Verb() { + public CommandExecutionResult execute(Subject subject, Complement complement) { + final Task task = (Task) subject; + final Completion completed = (Completion) complement; + task.setCompletion(completed.getCompletion()); + return CommandExecutionResult.ok(); + } + + }; + } +} diff --git a/src/net/sourceforge/plantuml/project3/VerbIsForToday.java b/src/net/sourceforge/plantuml/project/lang/VerbIsForToday.java similarity index 91% rename from src/net/sourceforge/plantuml/project3/VerbIsForToday.java rename to src/net/sourceforge/plantuml/project/lang/VerbIsForToday.java index 61aa0d559..030df6334 100644 --- a/src/net/sourceforge/plantuml/project3/VerbIsForToday.java +++ b/src/net/sourceforge/plantuml/project/lang/VerbIsForToday.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import java.util.Arrays; import java.util.Collection; @@ -42,6 +42,8 @@ import net.sourceforge.plantuml.command.CommandExecutionResult; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.DayAsDate; +import net.sourceforge.plantuml.project.GanttDiagram; public class VerbIsForToday implements VerbPattern { @@ -56,7 +58,7 @@ public class VerbIsForToday implements VerbPattern { public Verb getVerb(final GanttDiagram project, RegexResult arg) { return new Verb() { public CommandExecutionResult execute(Subject subject, Complement complement) { - final Today task = (Today) subject; + // final Today task = (Today) subject; final DayAsDate date = (DayAsDate) complement; return project.setToday(date); } diff --git a/src/net/sourceforge/plantuml/project3/VerbIsOff.java b/src/net/sourceforge/plantuml/project/lang/VerbIsOff.java similarity index 90% rename from src/net/sourceforge/plantuml/project3/VerbIsOff.java rename to src/net/sourceforge/plantuml/project/lang/VerbIsOff.java index 7ce044d75..285ea496a 100644 --- a/src/net/sourceforge/plantuml/project3/VerbIsOff.java +++ b/src/net/sourceforge/plantuml/project/lang/VerbIsOff.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import java.util.Arrays; import java.util.Collection; @@ -44,6 +44,11 @@ import net.sourceforge.plantuml.command.regex.RegexConcat; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexOr; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.DayAsDate; +import net.sourceforge.plantuml.project.DayOfWeek; +import net.sourceforge.plantuml.project.DaysAsDates; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.core.Resource; public class VerbIsOff implements VerbPattern { diff --git a/src/net/sourceforge/plantuml/project3/VerbIsOn.java b/src/net/sourceforge/plantuml/project/lang/VerbIsOn.java similarity index 91% rename from src/net/sourceforge/plantuml/project3/VerbIsOn.java rename to src/net/sourceforge/plantuml/project/lang/VerbIsOn.java index 11e468830..44003c446 100644 --- a/src/net/sourceforge/plantuml/project3/VerbIsOn.java +++ b/src/net/sourceforge/plantuml/project/lang/VerbIsOn.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import java.util.Arrays; import java.util.Collection; @@ -44,6 +44,10 @@ import net.sourceforge.plantuml.command.regex.RegexConcat; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexOr; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.DayAsDate; +import net.sourceforge.plantuml.project.DaysAsDates; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.core.Resource; public class VerbIsOn implements VerbPattern { diff --git a/src/net/sourceforge/plantuml/project3/VerbIsOrAre.java b/src/net/sourceforge/plantuml/project/lang/VerbIsOrAre.java similarity index 94% rename from src/net/sourceforge/plantuml/project3/VerbIsOrAre.java rename to src/net/sourceforge/plantuml/project/lang/VerbIsOrAre.java index fdc340126..dd639b263 100644 --- a/src/net/sourceforge/plantuml/project3/VerbIsOrAre.java +++ b/src/net/sourceforge/plantuml/project/lang/VerbIsOrAre.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import java.util.Arrays; import java.util.Collection; @@ -43,6 +43,9 @@ import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; import net.sourceforge.plantuml.graphic.HtmlColor; +import net.sourceforge.plantuml.project.DayAsDate; +import net.sourceforge.plantuml.project.DaysAsDates; +import net.sourceforge.plantuml.project.GanttDiagram; public class VerbIsOrAre implements VerbPattern { diff --git a/src/net/sourceforge/plantuml/project3/VerbIsOrAreNamed.java b/src/net/sourceforge/plantuml/project/lang/VerbIsOrAreNamed.java similarity index 91% rename from src/net/sourceforge/plantuml/project3/VerbIsOrAreNamed.java rename to src/net/sourceforge/plantuml/project/lang/VerbIsOrAreNamed.java index 91dcfd623..01062ee21 100644 --- a/src/net/sourceforge/plantuml/project3/VerbIsOrAreNamed.java +++ b/src/net/sourceforge/plantuml/project/lang/VerbIsOrAreNamed.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import java.util.Arrays; import java.util.Collection; @@ -42,6 +42,9 @@ import net.sourceforge.plantuml.command.CommandExecutionResult; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.DayAsDate; +import net.sourceforge.plantuml.project.DaysAsDates; +import net.sourceforge.plantuml.project.GanttDiagram; public class VerbIsOrAreNamed implements VerbPattern { diff --git a/src/net/sourceforge/plantuml/project3/VerbLasts.java b/src/net/sourceforge/plantuml/project/lang/VerbLasts.java similarity index 91% rename from src/net/sourceforge/plantuml/project3/VerbLasts.java rename to src/net/sourceforge/plantuml/project/lang/VerbLasts.java index 2a68a6ab7..71a0705f1 100644 --- a/src/net/sourceforge/plantuml/project3/VerbLasts.java +++ b/src/net/sourceforge/plantuml/project/lang/VerbLasts.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import java.util.Arrays; import java.util.Collection; @@ -42,6 +42,9 @@ import net.sourceforge.plantuml.command.CommandExecutionResult; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.Load; +import net.sourceforge.plantuml.project.core.Task; public class VerbLasts implements VerbPattern { diff --git a/src/net/sourceforge/plantuml/project3/VerbPattern.java b/src/net/sourceforge/plantuml/project/lang/VerbPattern.java similarity index 93% rename from src/net/sourceforge/plantuml/project3/VerbPattern.java rename to src/net/sourceforge/plantuml/project/lang/VerbPattern.java index c810ceffe..8360b4bb1 100644 --- a/src/net/sourceforge/plantuml/project3/VerbPattern.java +++ b/src/net/sourceforge/plantuml/project/lang/VerbPattern.java @@ -33,12 +33,13 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import java.util.Collection; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.GanttDiagram; public interface VerbPattern { diff --git a/src/net/sourceforge/plantuml/project3/VerbProjectStarts.java b/src/net/sourceforge/plantuml/project/lang/VerbProjectStarts.java similarity index 94% rename from src/net/sourceforge/plantuml/project3/VerbProjectStarts.java rename to src/net/sourceforge/plantuml/project/lang/VerbProjectStarts.java index d9bceb122..2d0b047fc 100644 --- a/src/net/sourceforge/plantuml/project3/VerbProjectStarts.java +++ b/src/net/sourceforge/plantuml/project/lang/VerbProjectStarts.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import java.util.Arrays; import java.util.Collection; @@ -45,6 +45,8 @@ import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexOptional; import net.sourceforge.plantuml.command.regex.RegexOr; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.DayAsDate; +import net.sourceforge.plantuml.project.GanttDiagram; public class VerbProjectStarts implements VerbPattern { diff --git a/src/net/sourceforge/plantuml/project3/VerbTaskEndsAbsolute.java b/src/net/sourceforge/plantuml/project/lang/VerbTaskEndsAbsolute.java similarity index 92% rename from src/net/sourceforge/plantuml/project3/VerbTaskEndsAbsolute.java rename to src/net/sourceforge/plantuml/project/lang/VerbTaskEndsAbsolute.java index 1fb86199e..10d44afd4 100644 --- a/src/net/sourceforge/plantuml/project3/VerbTaskEndsAbsolute.java +++ b/src/net/sourceforge/plantuml/project/lang/VerbTaskEndsAbsolute.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import java.util.Arrays; import java.util.Collection; @@ -42,6 +42,9 @@ import net.sourceforge.plantuml.command.CommandExecutionResult; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.DayAsDate; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.core.Task; public class VerbTaskEndsAbsolute implements VerbPattern { diff --git a/src/net/sourceforge/plantuml/project3/VerbTaskStarts.java b/src/net/sourceforge/plantuml/project/lang/VerbTaskStarts.java similarity index 87% rename from src/net/sourceforge/plantuml/project3/VerbTaskStarts.java rename to src/net/sourceforge/plantuml/project/lang/VerbTaskStarts.java index fc1468755..0418b49d4 100644 --- a/src/net/sourceforge/plantuml/project3/VerbTaskStarts.java +++ b/src/net/sourceforge/plantuml/project/lang/VerbTaskStarts.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import java.util.Arrays; import java.util.Collection; @@ -42,6 +42,11 @@ import net.sourceforge.plantuml.command.CommandExecutionResult; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.GanttConstraint; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.core.Task; +import net.sourceforge.plantuml.project.core.TaskAttribute; +import net.sourceforge.plantuml.project.core.TaskInstant; public class VerbTaskStarts implements VerbPattern { diff --git a/src/net/sourceforge/plantuml/project3/VerbTaskStartsAbsolute.java b/src/net/sourceforge/plantuml/project/lang/VerbTaskStartsAbsolute.java similarity index 92% rename from src/net/sourceforge/plantuml/project3/VerbTaskStartsAbsolute.java rename to src/net/sourceforge/plantuml/project/lang/VerbTaskStartsAbsolute.java index 5f8b4eca3..22dee2089 100644 --- a/src/net/sourceforge/plantuml/project3/VerbTaskStartsAbsolute.java +++ b/src/net/sourceforge/plantuml/project/lang/VerbTaskStartsAbsolute.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.lang; import java.util.Arrays; import java.util.Collection; @@ -42,6 +42,9 @@ import net.sourceforge.plantuml.command.CommandExecutionResult; import net.sourceforge.plantuml.command.regex.IRegex; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; +import net.sourceforge.plantuml.project.DayAsDate; +import net.sourceforge.plantuml.project.GanttDiagram; +import net.sourceforge.plantuml.project.core.Task; public class VerbTaskStartsAbsolute implements VerbPattern { diff --git a/src/net/sourceforge/plantuml/project3/TimeScale.java b/src/net/sourceforge/plantuml/project/timescale/TimeScale.java similarity index 84% rename from src/net/sourceforge/plantuml/project3/TimeScale.java rename to src/net/sourceforge/plantuml/project/timescale/TimeScale.java index 7644d444b..b5baf4ef6 100644 --- a/src/net/sourceforge/plantuml/project3/TimeScale.java +++ b/src/net/sourceforge/plantuml/project/timescale/TimeScale.java @@ -33,14 +33,16 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.timescale; + +import net.sourceforge.plantuml.project.core.Wink; public interface TimeScale { - public double getStartingPosition(Instant instant); + public double getStartingPosition(Wink instant); - public double getEndingPosition(Instant instant); + public double getEndingPosition(Wink instant); - public double getWidth(Instant instant); + public double getWidth(Wink instant); } diff --git a/src/net/sourceforge/plantuml/project/timescale/TimeScaleDaily.java b/src/net/sourceforge/plantuml/project/timescale/TimeScaleDaily.java new file mode 100644 index 000000000..e8bafb6cb --- /dev/null +++ b/src/net/sourceforge/plantuml/project/timescale/TimeScaleDaily.java @@ -0,0 +1,69 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.project.timescale; + +import net.sourceforge.plantuml.project.DayAsDate; +import net.sourceforge.plantuml.project.GCalendar; +import net.sourceforge.plantuml.project.core.Wink; + +public final class TimeScaleDaily implements TimeScale { + + private final TimeScaleWink basic; + private final double delta; + + public TimeScaleDaily(GCalendar calendar, DayAsDate zeroDay) { + this.basic = new TimeScaleWink(); + if (zeroDay == null) { + this.delta = 0; + } else { + this.delta = basic.getStartingPosition(calendar.fromDayAsDate(zeroDay)); + } + + } + + public double getStartingPosition(Wink instant) { + return basic.getStartingPosition(instant) - delta; + } + + public double getEndingPosition(Wink instant) { + return basic.getEndingPosition(instant) - delta; + } + + public double getWidth(Wink instant) { + return basic.getWidth(instant); + } + +} diff --git a/src/net/sourceforge/plantuml/project3/LoadInDays.java b/src/net/sourceforge/plantuml/project/timescale/TimeScaleWeekly.java similarity index 65% rename from src/net/sourceforge/plantuml/project3/LoadInDays.java rename to src/net/sourceforge/plantuml/project/timescale/TimeScaleWeekly.java index 7ef804869..c06dc0780 100644 --- a/src/net/sourceforge/plantuml/project3/LoadInDays.java +++ b/src/net/sourceforge/plantuml/project/timescale/TimeScaleWeekly.java @@ -33,28 +33,30 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.timescale; -public class LoadInDays implements Load { +import net.sourceforge.plantuml.project.GCalendar; +import net.sourceforge.plantuml.project.core.Wink; - private final int days; - private final int loadPerDay; +public class TimeScaleWeekly implements TimeScale { - private LoadInDays(int days, int loadPerDay) { - this.days = days; - this.loadPerDay = loadPerDay; + private static final int COMPRESS = 4; + private final TimeScale daily; + + public TimeScaleWeekly(GCalendar calendar) { + this.daily = new TimeScaleDaily(calendar, null); } - public static LoadInDays inDay(int days) { - return new LoadInDays(days, 100); + public double getStartingPosition(Wink instant) { + return daily.getStartingPosition(instant) / COMPRESS; } - public int getFullLoad() { - return days * loadPerDay; + public double getEndingPosition(Wink instant) { + return daily.getEndingPosition(instant) / COMPRESS; } - public int getLoadAt(Instant instant) { - return loadPerDay; + public double getWidth(Wink instant) { + return daily.getWidth(instant) / COMPRESS; } } diff --git a/src/net/sourceforge/plantuml/project3/TimeScaleBasic.java b/src/net/sourceforge/plantuml/project/timescale/TimeScaleWink.java similarity index 79% rename from src/net/sourceforge/plantuml/project3/TimeScaleBasic.java rename to src/net/sourceforge/plantuml/project/timescale/TimeScaleWink.java index 85d5d9f3a..118642613 100644 --- a/src/net/sourceforge/plantuml/project3/TimeScaleBasic.java +++ b/src/net/sourceforge/plantuml/project/timescale/TimeScaleWink.java @@ -33,22 +33,24 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.timescale; -public class TimeScaleBasic implements TimeScale { +import net.sourceforge.plantuml.project.core.Wink; + +public class TimeScaleWink implements TimeScale { private final double scale = 16.0; - public double getStartingPosition(Instant instant) { - final int day = ((InstantDay) instant).getNumDay(); - return day * scale; + public double getStartingPosition(Wink instant) { + final int wink = instant.getWink(); + return wink * scale; } - public double getEndingPosition(Instant instant) { + public double getEndingPosition(Wink instant) { return getStartingPosition(instant) + getWidth(instant); } - public double getWidth(Instant instant) { + public double getWidth(Wink instant) { return scale; } diff --git a/src/net/sourceforge/plantuml/project3/TimeScaleWithoutWeekEnd.java b/src/net/sourceforge/plantuml/project/timescale/UnusedTimeScaleWithoutWeekEnd.java similarity index 72% rename from src/net/sourceforge/plantuml/project3/TimeScaleWithoutWeekEnd.java rename to src/net/sourceforge/plantuml/project/timescale/UnusedTimeScaleWithoutWeekEnd.java index 9ef521c4c..da6e677e5 100644 --- a/src/net/sourceforge/plantuml/project3/TimeScaleWithoutWeekEnd.java +++ b/src/net/sourceforge/plantuml/project/timescale/UnusedTimeScaleWithoutWeekEnd.java @@ -33,32 +33,37 @@ * * */ -package net.sourceforge.plantuml.project3; +package net.sourceforge.plantuml.project.timescale; -public class TimeScaleWithoutWeekEnd implements TimeScale { +import net.sourceforge.plantuml.project.DayAsDate; +import net.sourceforge.plantuml.project.DayOfWeek; +import net.sourceforge.plantuml.project.GCalendar; +import net.sourceforge.plantuml.project.core.Wink; + +public class UnusedTimeScaleWithoutWeekEnd implements TimeScale { private final double scale = 16.0; private final GCalendar calendar; - public TimeScaleWithoutWeekEnd(GCalendar calendar) { + public UnusedTimeScaleWithoutWeekEnd(GCalendar calendar) { if (calendar == null) { throw new IllegalArgumentException(); } this.calendar = calendar; } - public double getStartingPosition(Instant instant) { + public double getStartingPosition(Wink instant) { double result = 0; - InstantDay current = (InstantDay) instant; - while (current.getNumDay() > 0) { + Wink current = (Wink) instant; + while (current.getWink() > 0) { current = current.decrement(); result += getWidth(current); } return result; } - public double getWidth(Instant instant) { - final DayAsDate day = calendar.toDayAsDate((InstantDay) instant); + public double getWidth(Wink instant) { + final DayAsDate day = calendar.toDayAsDate((Wink) instant); final DayOfWeek dayOfWeek = day.getDayOfWeek(); if (dayOfWeek == DayOfWeek.SATURDAY || dayOfWeek == DayOfWeek.SUNDAY) { return 1; @@ -66,7 +71,7 @@ public class TimeScaleWithoutWeekEnd implements TimeScale { return scale; } - public double getEndingPosition(Instant instant) { + public double getEndingPosition(Wink instant) { throw new UnsupportedOperationException(); } diff --git a/src/net/sourceforge/plantuml/project3/TimeScaleBasic2.java b/src/net/sourceforge/plantuml/project3/TimeScaleBasic2.java deleted file mode 100644 index 5341ef0a1..000000000 --- a/src/net/sourceforge/plantuml/project3/TimeScaleBasic2.java +++ /dev/null @@ -1,79 +0,0 @@ -/* ======================================================================== - * PlantUML : a free UML diagram generator - * ======================================================================== - * - * (C) Copyright 2009-2020, Arnaud Roques - * - * Project Info: http://plantuml.com - * - * If you like this project or if you find it useful, you can support us at: - * - * http://plantuml.com/patreon (only 1$ per month!) - * http://plantuml.com/paypal - * - * This file is part of PlantUML. - * - * PlantUML is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * PlantUML distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - * License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - * - * - * Original Author: Arnaud Roques - * - * - */ -package net.sourceforge.plantuml.project3; - -import java.util.Map; -import java.util.TreeMap; - -public class TimeScaleBasic2 implements TimeScale { - - private final GCalendar calendar; - private final GCalendar calendarAllOpen; - private final TimeScaleBasic basic = new TimeScaleBasic(); - private final Map cache = new TreeMap(); - - public TimeScaleBasic2(GCalendarSimple calendar) { - this.calendar = calendar; - this.calendarAllOpen = calendar; - } - - private Instant changeInstantSlow(Instant instant) { - final DayAsDate day = calendar.toDayAsDate((InstantDay) instant); - return calendarAllOpen.fromDayAsDate(day); - } - - private Instant changeInstant(Instant instant) { - Instant result = cache.get(instant); - if (result == null) { - result = changeInstantSlow(instant); - cache.put(instant, result); - } - return result; - } - - public double getStartingPosition(Instant instant) { - return basic.getStartingPosition(changeInstant(instant)); - } - - public double getEndingPosition(Instant instant) { - return basic.getEndingPosition(changeInstant(instant)); - } - - public double getWidth(Instant instant) { - return basic.getWidth(changeInstant(instant)); - } - -} diff --git a/src/net/sourceforge/plantuml/salt/PSystemSalt.java b/src/net/sourceforge/plantuml/salt/PSystemSalt.java index e7fc050b6..9ade106b7 100644 --- a/src/net/sourceforge/plantuml/salt/PSystemSalt.java +++ b/src/net/sourceforge/plantuml/salt/PSystemSalt.java @@ -54,7 +54,7 @@ import net.sourceforge.plantuml.api.ImageDataSimple; import net.sourceforge.plantuml.command.BlocLines; import net.sourceforge.plantuml.command.Command; import net.sourceforge.plantuml.command.CommandExecutionResult; -import net.sourceforge.plantuml.command.FactorySpriteCommand; +import net.sourceforge.plantuml.command.CommandFactorySprite; import net.sourceforge.plantuml.core.DiagramDescription; import net.sourceforge.plantuml.core.ImageData; import net.sourceforge.plantuml.graphic.HtmlColorUtils; @@ -143,8 +143,7 @@ public class PSystemSalt extends AbstractPSystem implements WithSprite { private List manageSprite() { - final FactorySpriteCommand factorySpriteCommand = new FactorySpriteCommand(); - Command cmd = factorySpriteCommand.createMultiLine(false); + final Command cmd = new CommandFactorySprite().createMultiLine(false); final List result = new ArrayList(); for (Iterator it = data.iterator(); it.hasNext();) { diff --git a/src/net/sourceforge/plantuml/sequencediagram/graphic/SequenceDiagramFileMakerPuma2.java b/src/net/sourceforge/plantuml/sequencediagram/graphic/SequenceDiagramFileMakerPuma2.java index f76166c40..5c9ea175d 100644 --- a/src/net/sourceforge/plantuml/sequencediagram/graphic/SequenceDiagramFileMakerPuma2.java +++ b/src/net/sourceforge/plantuml/sequencediagram/graphic/SequenceDiagramFileMakerPuma2.java @@ -166,7 +166,7 @@ public class SequenceDiagramFileMakerPuma2 implements FileMaker { diagram.getSkinParam()); } else { compTitle = TextBlockUtils.withMargin(TextBlockUtils.title( - new FontConfiguration(drawableSet.getSkinParam(), FontParam.SEQUENCE_TITLE, null), + new FontConfiguration(drawableSet.getSkinParam(), FontParam.TITLE, null), page.getTitle(), drawableSet.getSkinParam()), 7, 7); } final Dimension2D dimTitle = compTitle.calculateDimension(stringBounder); diff --git a/src/net/sourceforge/plantuml/sequencediagram/teoz/SequenceDiagramFileMakerTeoz.java b/src/net/sourceforge/plantuml/sequencediagram/teoz/SequenceDiagramFileMakerTeoz.java index 4a1825953..f6dbe4135 100644 --- a/src/net/sourceforge/plantuml/sequencediagram/teoz/SequenceDiagramFileMakerTeoz.java +++ b/src/net/sourceforge/plantuml/sequencediagram/teoz/SequenceDiagramFileMakerTeoz.java @@ -229,7 +229,7 @@ public class SequenceDiagramFileMakerTeoz implements FileMaker { .getIHtmlColorSet(), diagram.getSkinParam()); return compTitle; } else { - compTitle = TextBlockUtils.title(new FontConfiguration(getSkinParam(), FontParam.SEQUENCE_TITLE, null), + compTitle = TextBlockUtils.title(new FontConfiguration(getSkinParam(), FontParam.TITLE, null), diagram.getTitle().getDisplay(), getSkinParam()); return TextBlockUtils.withMargin(compTitle, 7, 7); } diff --git a/src/net/sourceforge/plantuml/sprite/CommandStdlib.java b/src/net/sourceforge/plantuml/sprite/CommandStdlib.java new file mode 100644 index 000000000..3f862c965 --- /dev/null +++ b/src/net/sourceforge/plantuml/sprite/CommandStdlib.java @@ -0,0 +1,67 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.sprite; + +import net.sourceforge.plantuml.LineLocation; +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.command.SingleLineCommand2; +import net.sourceforge.plantuml.command.regex.IRegex; +import net.sourceforge.plantuml.command.regex.RegexConcat; +import net.sourceforge.plantuml.command.regex.RegexLeaf; +import net.sourceforge.plantuml.command.regex.RegexResult; + +public class CommandStdlib extends SingleLineCommand2 { + + public CommandStdlib() { + super(getRegexConcat()); + } + + private static IRegex getRegexConcat() { + return RegexConcat.build(CommandStdlib.class.getName(), RegexLeaf.start(), // + new RegexLeaf("stdlib"), // + RegexLeaf.spaceOneOrMore(), // + new RegexLeaf("NAME", "([-\\w]+)"), // + RegexLeaf.end()); + } + + @Override + protected CommandExecutionResult executeArg(StdlibDiagram system, LineLocation location, RegexResult arg) { + final String name = arg.get("NAME", 0); + system.setStdlibName(name); + return CommandExecutionResult.ok(); + } + +} diff --git a/src/net/sourceforge/plantuml/sprite/StdlibDiagram.java b/src/net/sourceforge/plantuml/sprite/StdlibDiagram.java new file mode 100644 index 000000000..0edd374b0 --- /dev/null +++ b/src/net/sourceforge/plantuml/sprite/StdlibDiagram.java @@ -0,0 +1,164 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.sprite; + +import java.awt.geom.Dimension2D; +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; + +import net.sourceforge.plantuml.Dimension2DDouble; +import net.sourceforge.plantuml.FileFormatOption; +import net.sourceforge.plantuml.ISkinSimple; +import net.sourceforge.plantuml.UmlDiagram; +import net.sourceforge.plantuml.UmlDiagramType; +import net.sourceforge.plantuml.WithSprite; +import net.sourceforge.plantuml.command.BlocLines; +import net.sourceforge.plantuml.command.Command; +import net.sourceforge.plantuml.command.CommandFactorySprite; +import net.sourceforge.plantuml.core.DiagramDescription; +import net.sourceforge.plantuml.core.ImageData; +import net.sourceforge.plantuml.cucadiagram.Display; +import net.sourceforge.plantuml.graphic.AbstractTextBlock; +import net.sourceforge.plantuml.graphic.FontConfiguration; +import net.sourceforge.plantuml.graphic.HorizontalAlignment; +import net.sourceforge.plantuml.graphic.HtmlColorUtils; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.graphic.TextBlock; +import net.sourceforge.plantuml.graphic.TextBlockUtils; +import net.sourceforge.plantuml.preproc.Stdlib; +import net.sourceforge.plantuml.ugraphic.ImageBuilder; +import net.sourceforge.plantuml.ugraphic.UFont; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.UTranslate; + +public class StdlibDiagram extends UmlDiagram { + + private static final int WIDTH = 1800; + private String name; + + public StdlibDiagram(ISkinSimple skinParam) { + super(skinParam); + } + + public DiagramDescription getDescription() { + return new DiagramDescription("(Sprites)"); + } + + @Override + public UmlDiagramType getUmlDiagramType() { + return UmlDiagramType.HELP; + } + + @Override + protected ImageData exportDiagramInternal(OutputStream os, int index, FileFormatOption fileFormatOption) + throws IOException { + + final TextBlock result = getTable(); + final double margin = 10; + final double dpiFactor = 1; + + final ImageBuilder imageBuilder = new ImageBuilder(getSkinParam(), dpiFactor, + fileFormatOption.isWithMetadata() ? getMetadata() : null, getWarningOrError(), margin, margin, + getAnimation()); + imageBuilder.setUDrawable(result); + + return imageBuilder.writeImageTOBEMOVED(fileFormatOption, seed(), os); + } + + private TextBlock getTable() { + return new AbstractTextBlock() { + + public void drawU(UGraphic ug) { + try { + drawInternal(ug); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public Dimension2D calculateDimension(StringBounder stringBounder) { + return new Dimension2DDouble(WIDTH, 4096); + } + }; + } + + public void setStdlibName(String name) { + this.name = name; + } + + private void drawInternal(UGraphic ug) throws IOException { + double x = 0; + double y = 0; + double rawHeight = 0; + final Stdlib folder = Stdlib.retrieve(name); + + final CommandFactorySprite factorySpriteCommand = new CommandFactorySprite(); + + Command cmd = factorySpriteCommand.createMultiLine(false); + + final List all = folder.extractAllSprites(); + int nb = 0; + for (String s : all) { + // System.err.println("s="+s); + final BlocLines bloc = BlocLines.fromArray(s.split("\n")); + cmd.execute(this, bloc); +// System.err.println("nb=" + nb); + nb++; + } + + for (String n : getSkinParam().getAllSpriteNames()) { + final Sprite sprite = getSkinParam().getSprite(n); + TextBlock blockName = Display.create(n).create(FontConfiguration.blackBlueTrue(UFont.sansSerif(14)), + HorizontalAlignment.LEFT, getSkinParam()); + TextBlock tb = sprite.asTextBlock(HtmlColorUtils.BLACK, 1.0); + tb = TextBlockUtils.mergeTB(tb, blockName, HorizontalAlignment.CENTER); + tb.drawU(ug.apply(new UTranslate(x, y))); + final Dimension2D dim = tb.calculateDimension(ug.getStringBounder()); + rawHeight = Math.max(rawHeight, dim.getHeight()); + x += dim.getWidth(); + x += 30; + if (x > WIDTH) { + x = 0; + y += rawHeight + 50; + rawHeight = 0; + if (y > 1024) { +// break; + } + } + } + } +} diff --git a/src/net/sourceforge/plantuml/sprite/StdlibDiagramFactory.java b/src/net/sourceforge/plantuml/sprite/StdlibDiagramFactory.java new file mode 100644 index 000000000..b2d427689 --- /dev/null +++ b/src/net/sourceforge/plantuml/sprite/StdlibDiagramFactory.java @@ -0,0 +1,66 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.sprite; + +import java.util.ArrayList; +import java.util.List; + +import net.sourceforge.plantuml.ISkinSimple; +import net.sourceforge.plantuml.command.Command; +import net.sourceforge.plantuml.command.UmlDiagramFactory; + +public class StdlibDiagramFactory extends UmlDiagramFactory { + + private final ISkinSimple skinParam; + + public StdlibDiagramFactory(ISkinSimple skinParam) { + this.skinParam = skinParam; + } + + @Override + protected List createCommands() { + + final List cmds = new ArrayList(); + cmds.add(new CommandStdlib()); + return cmds; + } + + @Override + public StdlibDiagram createEmptyDiagram() { + return new StdlibDiagram(skinParam); + } + +} diff --git a/src/net/sourceforge/plantuml/statediagram/StateDiagramFactory.java b/src/net/sourceforge/plantuml/statediagram/StateDiagramFactory.java index 654c05526..0f54ec44b 100644 --- a/src/net/sourceforge/plantuml/statediagram/StateDiagramFactory.java +++ b/src/net/sourceforge/plantuml/statediagram/StateDiagramFactory.java @@ -47,9 +47,9 @@ import net.sourceforge.plantuml.command.Command; import net.sourceforge.plantuml.command.CommandFootboxIgnored; import net.sourceforge.plantuml.command.CommandRankDir; import net.sourceforge.plantuml.command.UmlDiagramFactory; -import net.sourceforge.plantuml.command.note.FactoryNoteCommand; -import net.sourceforge.plantuml.command.note.FactoryNoteOnEntityCommand; -import net.sourceforge.plantuml.command.note.FactoryNoteOnLinkCommand; +import net.sourceforge.plantuml.command.note.CommandFactoryNote; +import net.sourceforge.plantuml.command.note.CommandFactoryNoteOnEntity; +import net.sourceforge.plantuml.command.note.CommandFactoryNoteOnLink; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexOr; import net.sourceforge.plantuml.statediagram.command.CommandAddField; @@ -85,7 +85,7 @@ public class StateDiagramFactory extends UmlDiagramFactory { cmds.add(new CommandAddField()); cmds.add(new CommandConcurrentState()); - final FactoryNoteOnEntityCommand factoryNoteOnEntityCommand = new FactoryNoteOnEntityCommand("state", + final CommandFactoryNoteOnEntity factoryNoteOnEntityCommand = new CommandFactoryNoteOnEntity("state", new RegexOr("ENTITY", new RegexLeaf("[\\p{L}0-9_.]+"), // new RegexLeaf("[%g][^%g]+[%g]") // )); @@ -93,12 +93,12 @@ public class StateDiagramFactory extends UmlDiagramFactory { cmds.add(factoryNoteOnEntityCommand.createMultiLine(false)); cmds.add(factoryNoteOnEntityCommand.createSingleLine()); - final FactoryNoteOnLinkCommand factoryNoteOnLinkCommand = new FactoryNoteOnLinkCommand(); + final CommandFactoryNoteOnLink factoryNoteOnLinkCommand = new CommandFactoryNoteOnLink(); cmds.add(factoryNoteOnLinkCommand.createSingleLine()); cmds.add(factoryNoteOnLinkCommand.createMultiLine(false)); cmds.add(new CommandUrl()); - final FactoryNoteCommand factoryNoteCommand = new FactoryNoteCommand(); + final CommandFactoryNote factoryNoteCommand = new CommandFactoryNote(); cmds.add(factoryNoteCommand.createSingleLine()); cmds.add(factoryNoteCommand.createMultiLine(false)); diff --git a/src/net/sourceforge/plantuml/svek/Bibliotekon.java b/src/net/sourceforge/plantuml/svek/Bibliotekon.java index 0ddcc33c0..7122bf6ca 100644 --- a/src/net/sourceforge/plantuml/svek/Bibliotekon.java +++ b/src/net/sourceforge/plantuml/svek/Bibliotekon.java @@ -48,24 +48,27 @@ import net.sourceforge.plantuml.cucadiagram.IEntity; import net.sourceforge.plantuml.cucadiagram.IGroup; import net.sourceforge.plantuml.cucadiagram.ILeaf; import net.sourceforge.plantuml.cucadiagram.Link; +import net.sourceforge.plantuml.graphic.StringBounder; public class Bibliotekon { private final List allCluster = new ArrayList(); - private final Map shapeMap = new LinkedHashMap();; + private final Map nodeMap = new LinkedHashMap();; private final List lines0 = new ArrayList(); private final List lines1 = new ArrayList(); private final List allLines = new ArrayList(); - public void putShape(ILeaf ent, Shape shape) { - shapeMap.put(ent, shape); + public Node createNode(ILeaf ent, IEntityImage image, ColorSequence colorSequence, StringBounder stringBounder) { + final Node node = new Node(ent, image, colorSequence, stringBounder); + nodeMap.put(ent, node); + return node; } public Cluster getCluster(IGroup ent) { for (Cluster cl : allCluster) { - if (cl.getGroup() == ent) { + if (cl.getGroups().contains(ent)) { return cl; } } @@ -105,12 +108,12 @@ public class Bibliotekon { allCluster.add(current); } - public Shape getShape(IEntity ent) { - return shapeMap.get(ent); + public Node getNode(IEntity ent) { + return nodeMap.get(ent); } - public String getShapeUid(ILeaf ent) { - final Shape result = getShape(ent); + public String getNodeUid(ILeaf ent) { + final Node result = getNode(ent); if (result != null) { String uid = result.getUid(); if (result.isShielded()) { @@ -120,9 +123,9 @@ public class Bibliotekon { } assert result == null; if (ent.isGroup()) { - for (IEntity i : shapeMap.keySet()) { + for (IEntity i : nodeMap.keySet()) { if (ent.getCodeGetName().equals(i.getCodeGetName())) { - return getShape(i).getUid(); + return getNode(i).getUid(); } } return Cluster.getSpecialPointId(ent); @@ -132,8 +135,8 @@ public class Bibliotekon { public String getWarningOrError(int warningOrError) { final StringBuilder sb = new StringBuilder(); - for (Map.Entry ent : shapeMap.entrySet()) { - final Shape sh = ent.getValue(); + for (Map.Entry ent : nodeMap.entrySet()) { + final Node sh = ent.getValue(); final double maxX = sh.getMinX() + sh.getWidth(); if (maxX > warningOrError) { final IEntity entity = ent.getKey(); @@ -147,8 +150,8 @@ public class Bibliotekon { public Map getMaxX() { final Map result = new HashMap(); - for (Map.Entry ent : shapeMap.entrySet()) { - final Shape sh = ent.getValue(); + for (Map.Entry ent : nodeMap.entrySet()) { + final Node sh = ent.getValue(); final double maxX = sh.getMinX() + sh.getWidth(); final IEntity entity = ent.getKey(); result.put(entity.getCodeGetName(), maxX); @@ -172,8 +175,8 @@ public class Bibliotekon { return Collections.unmodifiableList(allCluster); } - public Collection allShapes() { - return Collections.unmodifiableCollection(shapeMap.values()); + public Collection allNodes() { + return Collections.unmodifiableCollection(nodeMap.values()); } public List getAllLineConnectedTo(IEntity leaf) { @@ -205,9 +208,9 @@ public class Bibliotekon { return null; } - public ILeaf getLeaf(Shape shape) { - for (Map.Entry ent : shapeMap.entrySet()) { - if (ent.getValue() == shape) { + public ILeaf getLeaf(Node node) { + for (Map.Entry ent : nodeMap.entrySet()) { + if (ent.getValue() == node) { return ent.getKey(); } } diff --git a/src/net/sourceforge/plantuml/svek/Cluster.java b/src/net/sourceforge/plantuml/svek/Cluster.java index bec6e4ec4..ab5681e45 100644 --- a/src/net/sourceforge/plantuml/svek/Cluster.java +++ b/src/net/sourceforge/plantuml/svek/Cluster.java @@ -96,9 +96,9 @@ import net.sourceforge.plantuml.utils.UniqueSequence; public class Cluster implements Moveable { - private final Cluster parent; + private final Cluster parentCluster; private final IGroup group; - private final List shapes = new ArrayList(); + private final List nodes = new ArrayList(); private final List children = new ArrayList(); private final int color; private final int colorTitle; @@ -128,7 +128,7 @@ public class Cluster implements Moveable { } private boolean hasEntryOrExitPoint() { - for (Shape sh : shapes) { + for (Node sh : nodes) { if (sh.getEntityPosition() != EntityPosition.NORMAL) { return true; } @@ -137,16 +137,16 @@ public class Cluster implements Moveable { } public Cluster(ColorSequence colorSequence, ISkinParam skinParam, IGroup root) { - this(null, root, colorSequence, skinParam); + this(null, colorSequence, skinParam, root); } private ColorParam border; - private Cluster(Cluster parent, IGroup group, ColorSequence colorSequence, ISkinParam skinParam) { + private Cluster(Cluster parentCluster, ColorSequence colorSequence, ISkinParam skinParam, IGroup group) { if (group == null) { throw new IllegalStateException(); } - this.parent = parent; + this.parentCluster = parentCluster; this.group = group; if (group.getUSymbol() != null) { border = group.getUSymbol().getColorParamBorder(); @@ -161,46 +161,46 @@ public class Cluster implements Moveable { return super.toString() + " " + group; } - public final Cluster getParent() { - return parent; + public final Cluster getParentCluster() { + return parentCluster; } - public void addShape(Shape sh) { - if (sh == null) { + public void addNode(Node node) { + if (node == null) { throw new IllegalArgumentException(); } - this.shapes.add(sh); - sh.setCluster(this); + this.nodes.add(node); + node.setCluster(this); } - public final List getShapes() { - return Collections.unmodifiableList(shapes); + public final List getNodes() { + return Collections.unmodifiableList(nodes); } - private List getShapesOrderedTop(Collection lines) { - final List firsts = new ArrayList(); + private List getNodesOrderedTop(Collection lines) { + final List firsts = new ArrayList(); final Set tops = new HashSet(); - final Map shs = new HashMap(); + final Map shs = new HashMap(); - for (final Iterator it = shapes.iterator(); it.hasNext();) { - final Shape sh = it.next(); - shs.put(sh.getUid(), sh); - if (sh.isTop() && sh.getEntityPosition() == EntityPosition.NORMAL) { - firsts.add(sh); - tops.add(sh.getUid()); + for (final Iterator it = nodes.iterator(); it.hasNext();) { + final Node node = it.next(); + shs.put(node.getUid(), node); + if (node.isTop() && node.getEntityPosition() == EntityPosition.NORMAL) { + firsts.add(node); + tops.add(node.getUid()); } } for (Line l : lines) { if (tops.contains(l.getStartUidPrefix())) { - final Shape sh = shs.get(l.getEndUidPrefix()); + final Node sh = shs.get(l.getEndUidPrefix()); if (sh != null && sh.getEntityPosition() == EntityPosition.NORMAL) { firsts.add(0, sh); } } if (l.isInverted()) { - final Shape sh = shs.get(l.getStartUidPrefix()); + final Node sh = shs.get(l.getStartUidPrefix()); if (sh != null && sh.getEntityPosition() == EntityPosition.NORMAL) { firsts.add(0, sh); } @@ -210,11 +210,11 @@ public class Cluster implements Moveable { return firsts; } - private List getShapesEntryExit(EnumSet positions) { - final List result = new ArrayList(); + private List getNodesEntryExit(EnumSet positions) { + final List result = new ArrayList(); - for (final Iterator it = shapes.iterator(); it.hasNext();) { - final Shape sh = it.next(); + for (final Iterator it = nodes.iterator(); it.hasNext();) { + final Node sh = it.next(); if (positions.contains(sh.getEntityPosition())) { result.add(sh); } @@ -222,13 +222,13 @@ public class Cluster implements Moveable { return result; } - private List getShapesOrderedWithoutTop(Collection lines) { - final List all = new ArrayList(shapes); + private List getNodesOrderedWithoutTop(Collection lines) { + final List all = new ArrayList(nodes); final Set tops = new HashSet(); - final Map shs = new HashMap(); + final Map shs = new HashMap(); - for (final Iterator it = all.iterator(); it.hasNext();) { - final Shape sh = it.next(); + for (final Iterator it = all.iterator(); it.hasNext();) { + final Node sh = it.next(); if (sh.getEntityPosition() != EntityPosition.NORMAL) { it.remove(); continue; @@ -242,14 +242,14 @@ public class Cluster implements Moveable { for (Line l : lines) { if (tops.contains(l.getStartUidPrefix())) { - final Shape sh = shs.get(l.getEndUidPrefix()); + final Node sh = shs.get(l.getEndUidPrefix()); if (sh != null) { all.remove(sh); } } if (l.isInverted()) { - final Shape sh = shs.get(l.getStartUidPrefix()); + final Node sh = shs.get(l.getStartUidPrefix()); if (sh != null) { all.remove(sh); } @@ -263,9 +263,9 @@ public class Cluster implements Moveable { return Collections.unmodifiableList(children); } - public Cluster createChild(IGroup g, int titleAndAttributeWidth, int titleAndAttributeHeight, TextBlock title, - TextBlock stereo, ColorSequence colorSequence, ISkinParam skinParam) { - final Cluster child = new Cluster(this, g, colorSequence, skinParam); + public Cluster createChild(int titleAndAttributeWidth, int titleAndAttributeHeight, TextBlock title, + TextBlock stereo, ColorSequence colorSequence, ISkinParam skinParam, IGroup g) { + final Cluster child = new Cluster(this, colorSequence, skinParam, g); child.titleAndAttributeWidth = titleAndAttributeWidth; child.titleAndAttributeHeight = titleAndAttributeHeight; child.ztitle = title; @@ -274,8 +274,8 @@ public class Cluster implements Moveable { return child; } - public final IGroup getGroup() { - return group; + public final Set getGroups() { + return Collections.singleton(group); } public final int getTitleAndAttributeWidth() { @@ -385,8 +385,8 @@ public class Cluster implements Moveable { HtmlColor backColor = getBackColor(umlDiagramType); backColor = getBackColor(backColor, skinParam2, group.getStereotype()); if (ztitle != null || zstereo != null) { - final double roundCorner = group.getUSymbol() == null ? 0 : group.getUSymbol().getSkinParameter() - .getRoundCorner(skinParam, stereotype); + final double roundCorner = group.getUSymbol() == null ? 0 + : group.getUSymbol().getSkinParameter().getRoundCorner(skinParam, stereotype); final UStroke stroke2 = getStrokeInternal(skinParam2); final ClusterDecoration decoration = new ClusterDecoration(packageStyle, group.getUSymbol(), ztitle, @@ -427,7 +427,7 @@ public class Cluster implements Moveable { public void manageEntryExitPoint(StringBounder stringBounder) { final Collection insides = new ArrayList(); final List points = new ArrayList(); - for (Shape sh : shapes) { + for (Node sh : nodes) { if (sh.getEntityPosition() == EntityPosition.NORMAL) { insides.add(sh.getClusterPosition()); } else { @@ -485,8 +485,9 @@ public class Cluster implements Moveable { final HtmlColor background = getColor(skinParam2, ColorParam.background, null); final TextBlockWidth attribute = getTextBlockAttribute(skinParam2); final double attributeHeight = attribute.calculateDimension(ug.getStringBounder()).getHeight(); - final RoundedContainer r = new RoundedContainer(total, suppY, attributeHeight - + (attributeHeight > 0 ? IEntityImage.MARGIN : 0), borderColor, stateBack, background, stroke); + final RoundedContainer r = new RoundedContainer(total, suppY, + attributeHeight + (attributeHeight > 0 ? IEntityImage.MARGIN : 0), borderColor, stateBack, background, + stroke); r.drawU(ug.apply(new UTranslate(minX, minY)), skinParam2.shadowing(group.getStereotype())); if (ztitle != null) { @@ -536,12 +537,12 @@ public class Cluster implements Moveable { } public void printCluster1(StringBuilder sb, Collection lines, StringBounder stringBounder) { - for (Shape sh : getShapesOrderedTop(lines)) { - sh.appendShape(sb, stringBounder); + for (Node node : getNodesOrderedTop(lines)) { + node.appendShape(sb, stringBounder); } } - private List addProtection(List entries, double width) { + private List addProtection(List entries, double width) { final List result = new ArrayList(); result.add(entries.get(0)); for (int i = 1; i < entries.size(); i++) { @@ -551,10 +552,10 @@ public class Cluster implements Moveable { return result; } - private double getMaxWidthFromLabelForEntryExit(List entries, StringBounder stringBounder) { + private double getMaxWidthFromLabelForEntryExit(List entries, StringBounder stringBounder) { double result = -Double.MAX_VALUE; - for (Shape shape : entries) { - final double w = getMaxWidthFromLabelForEntryExit(shape, stringBounder); + for (Node node : entries) { + final double w = getMaxWidthFromLabelForEntryExit(node, stringBounder); if (w > result) { result = w; } @@ -562,19 +563,19 @@ public class Cluster implements Moveable { return result; } - private double getMaxWidthFromLabelForEntryExit(Shape shape, StringBounder stringBounder) { - return shape.getMaxWidthFromLabelForEntryExit(stringBounder); + private double getMaxWidthFromLabelForEntryExit(Node node, StringBounder stringBounder) { + return node.getMaxWidthFromLabelForEntryExit(stringBounder); } public void printClusterEntryExit(StringBuilder sb, StringBounder stringBounder) { - final List shapesEntryExitList = getShapesEntryExit(EntityPosition.getInputs()); - final double maxWith = getMaxWidthFromLabelForEntryExit(shapesEntryExitList, stringBounder); + final List nodesEntryExitList = getNodesEntryExit(EntityPosition.getInputs()); + final double maxWith = getMaxWidthFromLabelForEntryExit(nodesEntryExitList, stringBounder); final double naturalSpace = 70; final List entries; if (maxWith > naturalSpace) { - entries = addProtection(shapesEntryExitList, maxWith - naturalSpace); + entries = addProtection(nodesEntryExitList, maxWith - naturalSpace); } else { - entries = shapesEntryExitList; + entries = nodesEntryExitList; } if (entries.size() > 0) { sb.append("{rank=source;"); @@ -586,26 +587,26 @@ public class Cluster implements Moveable { sh.appendShape(sb, stringBounder); } } - final List exits = getShapesEntryExit(EntityPosition.getOutputs()); + final List exits = getNodesEntryExit(EntityPosition.getOutputs()); if (exits.size() > 0) { sb.append("{rank=sink;"); - for (Shape sh : exits) { + for (Node sh : exits) { sb.append(sh.getUid() + ";"); } sb.append("}"); - for (Shape sh : exits) { + for (Node sh : exits) { sh.appendShape(sb, stringBounder); } } } - public boolean printCluster2(StringBuilder sb, Collection lines, StringBounder stringBounder, - DotMode dotMode, GraphvizVersion graphvizVersion, UmlDiagramType type) { + public boolean printCluster2(StringBuilder sb, Collection lines, StringBounder stringBounder, DotMode dotMode, + GraphvizVersion graphvizVersion, UmlDiagramType type) { // Log.println("Cluster::printCluster " + this); boolean added = false; - for (Shape sh : getShapesOrderedWithoutTop(lines)) { - sh.appendShape(sb, stringBounder); + for (Node node : getNodesOrderedWithoutTop(lines)) { + node.appendShape(sb, stringBounder); added = true; } @@ -647,7 +648,7 @@ public class Cluster implements Moveable { } public void fillRankMin(Set rankMin) { - for (Shape sh : getShapes()) { + for (Node sh : getNodes()) { if (sh.isTop()) { rankMin.add(sh.getUid()); } @@ -659,8 +660,8 @@ public class Cluster implements Moveable { } private boolean isInCluster(String uid) { - for (Shape sh : shapes) { - if (sh.getUid().equals(uid)) { + for (Node node : nodes) { + if (node.getUid().equals(uid)) { return true; } } @@ -865,16 +866,16 @@ public class Cluster implements Moveable { } final Stereotype stereo = group.getStereotype(); final USymbol sym = group.getUSymbol() == null ? USymbol.PACKAGE : group.getUSymbol(); - final ColorParam backparam = umlDiagramType == UmlDiagramType.ACTIVITY ? ColorParam.partitionBackground : sym - .getColorParamBack(); + final ColorParam backparam = umlDiagramType == UmlDiagramType.ACTIVITY ? ColorParam.partitionBackground + : sym.getColorParamBack(); final HtmlColor c1 = skinParam.getHtmlColor(backparam, stereo, false); if (c1 != null) { return c1; } - if (parent == null) { + if (parentCluster == null) { return null; } - return parent.getBackColor(umlDiagramType); + return parentCluster.getBackColor(umlDiagramType); } public boolean isClusterOf(IEntity ent) { diff --git a/src/net/sourceforge/plantuml/svek/CucaDiagramFileMakerSvek.java b/src/net/sourceforge/plantuml/svek/CucaDiagramFileMakerSvek.java index f649e5bfd..276944096 100644 --- a/src/net/sourceforge/plantuml/svek/CucaDiagramFileMakerSvek.java +++ b/src/net/sourceforge/plantuml/svek/CucaDiagramFileMakerSvek.java @@ -78,13 +78,15 @@ public final class CucaDiagramFileMakerSvek implements CucaDiagramFileMaker { private GeneralImageBuilder createDotDataImageBuilder(DotMode dotMode, StringBounder stringBounder) { final DotData dotData = new DotData(diagram.getEntityFactory().getRootGroup(), getOrderedLinks(), diagram.getLeafsvalues(), diagram.getUmlDiagramType(), diagram.getSkinParam(), diagram, diagram, - diagram.getColorMapper(), diagram.getEntityFactory(), diagram.isHideEmptyDescriptionForState(), - dotMode, diagram.getNamespaceSeparator(), diagram.getPragma()); - return new GeneralImageBuilder(dotData, diagram.getEntityFactory(), diagram.getSource(), diagram.getPragma(), - stringBounder); + diagram.getColorMapper(), diagram.getEntityFactory(), diagram.isHideEmptyDescriptionForState(), dotMode, + diagram.getNamespaceSeparator(), diagram.getPragma()); + final boolean intricated = diagram.mergeIntricated(); + return new GeneralImageBuilder(intricated, dotData, diagram.getEntityFactory(), diagram.getSource(), + diagram.getPragma(), stringBounder); } + private ImageData createFileInternal(OutputStream os, List dotStrings, FileFormatOption fileFormatOption) throws IOException, InterruptedException { if (diagram.getUmlDiagramType() == UmlDiagramType.ACTIVITY) { diff --git a/src/net/sourceforge/plantuml/svek/DotStringFactory.java b/src/net/sourceforge/plantuml/svek/DotStringFactory.java index f94c68d24..5d1fad9d4 100644 --- a/src/net/sourceforge/plantuml/svek/DotStringFactory.java +++ b/src/net/sourceforge/plantuml/svek/DotStringFactory.java @@ -60,6 +60,7 @@ import net.sourceforge.plantuml.cucadiagram.dot.GraphvizUtils; import net.sourceforge.plantuml.cucadiagram.dot.GraphvizVersion; import net.sourceforge.plantuml.cucadiagram.dot.GraphvizVersions; import net.sourceforge.plantuml.cucadiagram.dot.ProcessState; +import net.sourceforge.plantuml.cucadiagram.entity.EntityFactory; import net.sourceforge.plantuml.graphic.StringBounder; import net.sourceforge.plantuml.graphic.TextBlock; import net.sourceforge.plantuml.posimo.Moveable; @@ -104,8 +105,8 @@ public class DotStringFactory implements Moveable { this.current = root; } - public void addShape(Shape shape) { - current.addShape(shape); + public void addNode(Node node) { + current.addNode(node); } private void printMinRanking(StringBuilder sb) { @@ -343,7 +344,8 @@ public class DotStringFactory implements Moveable { return graphviz.getDotExe(); } - public ClusterPosition solve(final String svg) throws IOException, InterruptedException { + public ClusterPosition solve(boolean mergeIntricated, EntityFactory entityFactory, final String svg) + throws IOException, InterruptedException { if (svg.length() == 0) { throw new EmptySvgException(); } @@ -360,18 +362,18 @@ public class DotStringFactory implements Moveable { final Point2DFunction move = new YDelta(fullHeight); final SvgResult svgResult = new SvgResult(svg, move); - for (Shape sh : bibliotekon.allShapes()) { - int idx = svg.indexOf("" + sh.getUid() + ""); - if (sh.getType() == ShapeType.RECTANGLE || sh.getType() == ShapeType.RECTANGLE_HTML_FOR_PORTS - || sh.getType() == ShapeType.RECTANGLE_WITH_CIRCLE_INSIDE || sh.getType() == ShapeType.FOLDER - || sh.getType() == ShapeType.DIAMOND) { + for (Node node : bibliotekon.allNodes()) { + int idx = svg.indexOf("" + node.getUid() + ""); + if (node.getType() == ShapeType.RECTANGLE || node.getType() == ShapeType.RECTANGLE_HTML_FOR_PORTS + || node.getType() == ShapeType.RECTANGLE_WITH_CIRCLE_INSIDE || node.getType() == ShapeType.FOLDER + || node.getType() == ShapeType.DIAMOND) { final List points = svgResult.substring(idx).extractList(SvgResult.POINTS_EQUALS); final double minY = SvekUtils.getMinY(points); - final double overscanX = sh.getOverscanX(stringBounder); + final double overscanX = node.getOverscanX(stringBounder); final double minX = SvekUtils.getMinX(points); corner1.manage(minX - overscanX, minY); - sh.moveSvek(minX, minY); - } else if (sh.getType() == ShapeType.ROUND_RECTANGLE) { + node.moveSvek(minX, minY); + } else if (node.getType() == ShapeType.ROUND_RECTANGLE) { final int idx2 = svg.indexOf("d=\"", idx + 1); idx = svg.indexOf("points=\"", idx + 1); final List points; @@ -388,29 +390,35 @@ public class DotStringFactory implements Moveable { final double minX = SvekUtils.getMinX(points); final double minY = SvekUtils.getMinY(points); corner1.manage(minX, minY); - sh.moveSvek(minX, minY); - } else if (sh.getType() == ShapeType.OCTAGON) { + node.moveSvek(minX, minY); + } else if (node.getType() == ShapeType.OCTAGON) { idx = svg.indexOf("points=\"", idx + 1); final int starting = idx; final List points = svgResult.substring(starting).extractList(SvgResult.POINTS_EQUALS); final double minX = SvekUtils.getMinX(points); final double minY = SvekUtils.getMinY(points); corner1.manage(minX, minY); - sh.moveSvek(minX, minY); - sh.setOctagon(minX, minY, points); - } else if (sh.getType() == ShapeType.CIRCLE || sh.getType() == ShapeType.CIRCLE_IN_RECT - || sh.getType() == ShapeType.OVAL) { + node.moveSvek(minX, minY); + node.setOctagon(minX, minY, points); + } else if (node.getType() == ShapeType.CIRCLE || node.getType() == ShapeType.CIRCLE_IN_RECT + || node.getType() == ShapeType.OVAL) { final double cx = SvekUtils.getValue(svg, idx, "cx"); final double cy = SvekUtils.getValue(svg, idx, "cy") + fullHeight; final double rx = SvekUtils.getValue(svg, idx, "rx"); final double ry = SvekUtils.getValue(svg, idx, "ry"); - sh.moveSvek(cx - rx, cy - ry); + node.moveSvek(cx - rx, cy - ry); } else { - throw new IllegalStateException(sh.getType().toString() + " " + sh.getUid()); + throw new IllegalStateException(node.getType().toString() + " " + node.getUid()); } } for (Cluster cluster : bibliotekon.allCluster()) { + if (mergeIntricated) { + final IGroup group = cluster.getGroups().iterator().next(); + if (entityFactory.isIntricated(group) != null) { + continue; + } + } int idx = getClusterIndex(svg, cluster.getColor()); final int starting = idx; final List points = svgResult.substring(starting).extractList(SvgResult.POINTS_EQUALS); @@ -438,7 +446,7 @@ public class DotStringFactory implements Moveable { } for (Line line : bibliotekon.allLines()) { - line.manageCollision(bibliotekon.allShapes()); + line.manageCollision(bibliotekon.allNodes()); } corner1.manage(0, 0); return new ClusterPosition(corner1.getMinX(), corner1.getMinY(), fullWidth, fullHeight); @@ -459,22 +467,22 @@ public class DotStringFactory implements Moveable { return idx; } - public void openCluster(IGroup g, int titleAndAttributeWidth, int titleAndAttributeHeight, TextBlock title, - TextBlock stereo) { - this.current = current.createChild(g, titleAndAttributeWidth, titleAndAttributeHeight, title, stereo, - colorSequence, skinParam); + public void openCluster(int titleAndAttributeWidth, int titleAndAttributeHeight, TextBlock title, TextBlock stereo, + IGroup g) { + this.current = current.createChild(titleAndAttributeWidth, titleAndAttributeHeight, title, stereo, + colorSequence, skinParam, g); bibliotekon.addCluster(this.current); } public void closeCluster() { - if (current.getParent() == null) { + if (current.getParentCluster() == null) { throw new IllegalStateException(); } - this.current = current.getParent(); + this.current = current.getParentCluster(); } public void moveSvek(double deltaX, double deltaY) { - for (Shape sh : bibliotekon.allShapes()) { + for (Node sh : bibliotekon.allNodes()) { sh.moveSvek(deltaX, deltaY); } for (Line line : bibliotekon.allLines()) { diff --git a/src/net/sourceforge/plantuml/svek/GeneralImageBuilder.java b/src/net/sourceforge/plantuml/svek/GeneralImageBuilder.java index c04b8dffe..a0025f320 100644 --- a/src/net/sourceforge/plantuml/svek/GeneralImageBuilder.java +++ b/src/net/sourceforge/plantuml/svek/GeneralImageBuilder.java @@ -84,6 +84,7 @@ import net.sourceforge.plantuml.cucadiagram.dot.ExeState; import net.sourceforge.plantuml.cucadiagram.dot.GraphvizVersion; import net.sourceforge.plantuml.cucadiagram.dot.Neighborhood; import net.sourceforge.plantuml.cucadiagram.entity.EntityFactory; +import net.sourceforge.plantuml.cucadiagram.entity.EntityImpl; import net.sourceforge.plantuml.descdiagram.EntityImageDesignedDomain; import net.sourceforge.plantuml.descdiagram.EntityImageDomain; import net.sourceforge.plantuml.descdiagram.EntityImageMachine; @@ -226,8 +227,8 @@ public final class GeneralImageBuilder { if (leaf.getLeafType() == LeafType.EMPTY_PACKAGE) { if (leaf.getUSymbol() != null) { // final HtmlColor black = HtmlColorUtils.BLACK; - final HtmlColor black = SkinParamUtils.getColor(skinParam, leaf.getStereotype(), leaf.getUSymbol() - .getColorParamBorder()); + final HtmlColor black = SkinParamUtils.getColor(skinParam, leaf.getStereotype(), + leaf.getUSymbol().getColorParamBorder()); return new EntityImageDescription(leaf, new SkinParamForecolored(skinParam, black), portionShower, links); } @@ -274,15 +275,17 @@ public final class GeneralImageBuilder { private Map maxX; private final StringBounder stringBounder; + private final boolean mergeIntricated; - public GeneralImageBuilder(DotData dotData, EntityFactory entityFactory, UmlSource source, Pragma pragma, - StringBounder stringBounder) { + public GeneralImageBuilder(boolean mergeIntricated, DotData dotData, EntityFactory entityFactory, UmlSource source, + Pragma pragma, StringBounder stringBounder) { this.dotData = dotData; this.entityFactory = entityFactory; this.source = source; this.pragma = pragma; this.stringBounder = stringBounder; this.strictUmlStyle = dotData.getSkinParam().strictUmlStyle(); + this.mergeIntricated = mergeIntricated; } final public StyleSignature getDefaultStyleDefinitionArrow() { @@ -362,8 +365,8 @@ public final class GeneralImageBuilder { final ISkinParam skinParam = dotData.getSkinParam(); final FontConfiguration labelFont; if (SkinParam.USE_STYLES()) { - final Style style = getDefaultStyleDefinitionArrow().getMergedStyle( - skinParam.getCurrentStyleBuilder()); + final Style style = getDefaultStyleDefinitionArrow() + .getMergedStyle(skinParam.getCurrentStyleBuilder()); labelFont = style.getFontConfiguration(skinParam.getIHtmlColorSet()); } else { labelFont = new FontConfiguration(skinParam, FontParam.ARROW, null); @@ -375,17 +378,17 @@ public final class GeneralImageBuilder { dotStringFactory.getBibliotekon().addLine(line); if (isOpalisable(link.getEntity1())) { - final Shape shape = dotStringFactory.getBibliotekon().getShape(link.getEntity1()); - final Shape other = dotStringFactory.getBibliotekon().getShape(link.getEntity2()); + final Node node = dotStringFactory.getBibliotekon().getNode(link.getEntity1()); + final Node other = dotStringFactory.getBibliotekon().getNode(link.getEntity2()); if (other != null) { - ((EntityImageNote) shape.getImage()).setOpaleLine(line, shape, other); + ((EntityImageNote) node.getImage()).setOpaleLine(line, node, other); line.setOpale(true); } } else if (isOpalisable(link.getEntity2())) { - final Shape shape = dotStringFactory.getBibliotekon().getShape(link.getEntity2()); - final Shape other = dotStringFactory.getBibliotekon().getShape(link.getEntity1()); + final Node node = dotStringFactory.getBibliotekon().getNode(link.getEntity2()); + final Node other = dotStringFactory.getBibliotekon().getNode(link.getEntity1()); if (other != null) { - ((EntityImageNote) shape.getImage()).setOpaleLine(line, shape, other); + ((EntityImageNote) node.getImage()).setOpaleLine(line, node, other); line.setOpale(true); } } @@ -413,7 +416,8 @@ public final class GeneralImageBuilder { } final String graphvizVersion = extractGraphvizVersion(svg); try { - final ClusterPosition position = dotStringFactory.solve(svg).delta(10, 10); + final ClusterPosition position = dotStringFactory.solve(mergeIntricated, dotData.getEntityFactory(), svg) + .delta(10, 10); final double minY = position.getMinY(); final double minX = position.getMinX(); if (minX > 0 || minY > 0) { @@ -493,12 +497,8 @@ public final class GeneralImageBuilder { throw new IllegalStateException(); } final IEntityImage image = printEntityInternal(dotStringFactory, ent); - final Dimension2D dim = image.calculateDimension(stringBounder); - final Shape shape = new Shape(image, image.getShapeType(), dim.getWidth(), dim.getHeight(), - dotStringFactory.getColorSequence(), ent.isTop(), image.getShield(stringBounder), - ent.getEntityPosition()); - dotStringFactory.addShape(shape); - dotStringFactory.getBibliotekon().putShape(ent, shape); + final Node node = dotStringFactory.getBibliotekon().createNode(ent, image, dotStringFactory.getColorSequence(), stringBounder); + dotStringFactory.addNode(node); } private IEntityImage printEntityInternal(DotStringFactory dotStringFactory, ILeaf ent) { @@ -546,29 +546,15 @@ public final class GeneralImageBuilder { } private void printGroups(DotStringFactory dotStringFactory, IGroup parent) { - for (IGroup g : dotData.getGroupHierarchy().getChildrenGroups(parent)) { + final Collection groups = dotData.getGroupHierarchy().getChildrenGroups(parent); + for (IGroup g : groups) { if (g.isRemoved()) { continue; } if (dotData.isEmpty(g) && g.getGroupType() == GroupType.PACKAGE) { + final ISkinParam skinParam = dotData.getSkinParam(); entityFactory.thisIsGoingToBeALeaf(g.getIdent()); - final ILeaf folder = entityFactory.createLeaf(g.getIdent(), g.getCode(), g.getDisplay(), - LeafType.EMPTY_PACKAGE, g.getParentContainer(), null, dotData.getNamespaceSeparator()); - final USymbol symbol = g.getUSymbol(); - folder.setUSymbol(symbol); - folder.setStereotype(g.getStereotype()); - if (g.getUrl99() != null) { - folder.addUrl(g.getUrl99()); - } - if (g.getColors(dotData.getSkinParam()).getColor(ColorType.BACK) == null) { - final ColorParam param = symbol == null ? ColorParam.packageBackground : symbol.getColorParamBack(); - final HtmlColor c1 = dotData.getSkinParam().getHtmlColor(param, g.getStereotype(), false); - folder.setSpecificColorTOBEREMOVED(ColorType.BACK, c1 == null ? dotData.getSkinParam() - .getBackgroundColor() : c1); - } else { - folder.setSpecificColorTOBEREMOVED(ColorType.BACK, - g.getColors(dotData.getSkinParam()).getColor(ColorType.BACK)); - } + final ILeaf folder = entityFactory.createLeafForEmptyGroup(g, skinParam); printEntity(dotStringFactory, folder); } else { printGroup(dotStringFactory, g); @@ -580,6 +566,13 @@ public final class GeneralImageBuilder { if (g.getGroupType() == GroupType.CONCURRENT_STATE) { return; } + if (mergeIntricated) { + final IGroup intricated = dotData.getEntityFactory().isIntricated(g); + if (intricated != null) { + printGroup(dotStringFactory, intricated); + return; + } + } int titleAndAttributeWidth = 0; int titleAndAttributeHeight = 0; @@ -605,10 +598,11 @@ public final class GeneralImageBuilder { final int suppWidthBecauseOfShape = uSymbol == null ? 0 : uSymbol.suppWidthBecauseOfShape(); titleAndAttributeWidth = (int) Math.max(dimLabel.getWidth(), attributeWidth) + suppWidthBecauseOfShape; - titleAndAttributeHeight = (int) (dimLabel.getHeight() + attributeHeight + marginForFields + suppHeightBecauseOfShape); + titleAndAttributeHeight = (int) (dimLabel.getHeight() + attributeHeight + marginForFields + + suppHeightBecauseOfShape); } - dotStringFactory.openCluster(g, titleAndAttributeWidth, titleAndAttributeHeight, title, stereo); + dotStringFactory.openCluster(titleAndAttributeWidth, titleAndAttributeHeight, title, stereo, g); this.printEntities(dotStringFactory, g.getLeafsDirect()); printGroups(dotStringFactory, g); diff --git a/src/net/sourceforge/plantuml/svek/GroupPngMakerActivity.java b/src/net/sourceforge/plantuml/svek/GroupPngMakerActivity.java index 3f34446a1..4ac245131 100644 --- a/src/net/sourceforge/plantuml/svek/GroupPngMakerActivity.java +++ b/src/net/sourceforge/plantuml/svek/GroupPngMakerActivity.java @@ -39,6 +39,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Set; import net.sourceforge.plantuml.ColorParam; import net.sourceforge.plantuml.ISkinParam; @@ -51,6 +52,7 @@ import net.sourceforge.plantuml.cucadiagram.IEntity; import net.sourceforge.plantuml.cucadiagram.IGroup; import net.sourceforge.plantuml.cucadiagram.Link; import net.sourceforge.plantuml.cucadiagram.Stereotype; +import net.sourceforge.plantuml.cucadiagram.SuperGroup; import net.sourceforge.plantuml.cucadiagram.dot.DotData; import net.sourceforge.plantuml.graphic.FontConfiguration; import net.sourceforge.plantuml.graphic.HtmlColor; @@ -71,6 +73,18 @@ public final class GroupPngMakerActivity { class InnerGroupHierarchy implements GroupHierarchy { + public Set getAllSuperGroups() { + throw new UnsupportedOperationException(); + } + + public IGroup getRootGroup() { + throw new UnsupportedOperationException(); + } + + public SuperGroup getRootSuperGroup() { + throw new UnsupportedOperationException(); + } + public Collection getChildrenGroups(IGroup parent) { if (EntityUtils.groupRoot(parent)) { return diagram.getChildrenGroups(group); @@ -82,6 +96,8 @@ public final class GroupPngMakerActivity { return diagram.isEmpty(g); } + + } public GroupPngMakerActivity(CucaDiagram diagram, IGroup group, StringBounder stringBounder) { @@ -118,18 +134,18 @@ public final class GroupPngMakerActivity { skinParam, new InnerGroupHierarchy(), diagram.getColorMapper(), diagram.getEntityFactory(), false, DotMode.NORMAL, diagram.getNamespaceSeparator(), diagram.getPragma()); - final GeneralImageBuilder svek2 = new GeneralImageBuilder(dotData, diagram.getEntityFactory(), + final GeneralImageBuilder svek2 = new GeneralImageBuilder(false, dotData, diagram.getEntityFactory(), diagram.getSource(), diagram.getPragma(), stringBounder); if (group.getGroupType() == GroupType.INNER_ACTIVITY) { final Stereotype stereo = group.getStereotype(); final HtmlColor borderColor = getColor(ColorParam.activityBorder, stereo); - final HtmlColor backColor = group.getColors(skinParam).getColor(ColorType.BACK) == null ? getColor( - ColorParam.background, stereo) : group.getColors(skinParam).getColor(ColorType.BACK); + final HtmlColor backColor = group.getColors(skinParam).getColor(ColorType.BACK) == null + ? getColor(ColorParam.background, stereo) + : group.getColors(skinParam).getColor(ColorType.BACK); final double shadowing; if (SkinParam.USE_STYLES()) { - final Style style = getDefaultStyleDefinitionGroup().getMergedStyle( - skinParam.getCurrentStyleBuilder()); + final Style style = getDefaultStyleDefinitionGroup().getMergedStyle(skinParam.getCurrentStyleBuilder()); shadowing = style.value(PName.Shadowing).asDouble(); } else { shadowing = skinParam.shadowing(group.getStereotype()) ? 4 : 0; diff --git a/src/net/sourceforge/plantuml/svek/GroupPngMakerState.java b/src/net/sourceforge/plantuml/svek/GroupPngMakerState.java index 529f3dcd0..5368d1e04 100644 --- a/src/net/sourceforge/plantuml/svek/GroupPngMakerState.java +++ b/src/net/sourceforge/plantuml/svek/GroupPngMakerState.java @@ -38,6 +38,7 @@ package net.sourceforge.plantuml.svek; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Set; import net.sourceforge.plantuml.ColorParam; import net.sourceforge.plantuml.FontParam; @@ -53,6 +54,7 @@ import net.sourceforge.plantuml.cucadiagram.ILeaf; import net.sourceforge.plantuml.cucadiagram.LeafType; import net.sourceforge.plantuml.cucadiagram.Link; import net.sourceforge.plantuml.cucadiagram.Stereotype; +import net.sourceforge.plantuml.cucadiagram.SuperGroup; import net.sourceforge.plantuml.cucadiagram.dot.DotData; import net.sourceforge.plantuml.graphic.FontConfiguration; import net.sourceforge.plantuml.graphic.HorizontalAlignment; @@ -75,6 +77,18 @@ public final class GroupPngMakerState { class InnerGroupHierarchy implements GroupHierarchy { + public Set getAllSuperGroups() { + throw new UnsupportedOperationException(); + } + + public IGroup getRootGroup() { + throw new UnsupportedOperationException(); + } + + public SuperGroup getRootSuperGroup() { + throw new UnsupportedOperationException(); + } + public Collection getChildrenGroups(IGroup parent) { if (EntityUtils.groupRoot(parent)) { return diagram.getChildrenGroups(group); @@ -110,9 +124,8 @@ public final class GroupPngMakerState { public IEntityImage getImage() { final Display display = group.getDisplay(); final ISkinParam skinParam = diagram.getSkinParam(); - final TextBlock title = display.create( - new FontConfiguration(skinParam, FontParam.STATE, group.getStereotype()), HorizontalAlignment.CENTER, - diagram.getSkinParam()); + final TextBlock title = display.create(new FontConfiguration(skinParam, FontParam.STATE, group.getStereotype()), + HorizontalAlignment.CENTER, diagram.getSkinParam()); if (group.size() == 0 && group.getChildren().size() == 0) { return new EntityImageState(group, diagram.getSkinParam()); @@ -124,7 +137,7 @@ public final class GroupPngMakerState { diagram.isHideEmptyDescriptionForState(), DotMode.NORMAL, diagram.getNamespaceSeparator(), diagram.getPragma()); - final GeneralImageBuilder svek2 = new GeneralImageBuilder(dotData, diagram.getEntityFactory(), + final GeneralImageBuilder svek2 = new GeneralImageBuilder(false, dotData, diagram.getEntityFactory(), diagram.getSource(), diagram.getPragma(), stringBounder); if (group.getGroupType() == GroupType.CONCURRENT_STATE) { @@ -141,22 +154,23 @@ public final class GroupPngMakerState { borderColor = getColor(ColorParam.stateBorder, group.getStereotype()); } final Stereotype stereo = group.getStereotype(); - final HtmlColor backColor = group.getColors(skinParam).getColor(ColorType.BACK) == null ? getColor( - ColorParam.stateBackground, stereo) : group.getColors(skinParam).getColor(ColorType.BACK); + final HtmlColor backColor = group.getColors(skinParam).getColor(ColorType.BACK) == null + ? getColor(ColorParam.stateBackground, stereo) + : group.getColors(skinParam).getColor(ColorType.BACK); final TextBlockWidth attribute = getAttributes(skinParam); final Stereotype stereotype = group.getStereotype(); final boolean withSymbol = stereotype != null && stereotype.isWithOOSymbol(); final boolean containsOnlyConcurrentStates = containsOnlyConcurrentStates(dotData); - final IEntityImage image = containsOnlyConcurrentStates ? buildImageForConcurrentState(dotData) : svek2 - .buildImage(null, new String[0]); + final IEntityImage image = containsOnlyConcurrentStates ? buildImageForConcurrentState(dotData) + : svek2.buildImage(null, new String[0]); UStroke stroke = group.getColors(skinParam).getSpecificLineStroke(); if (stroke == null) { stroke = new UStroke(1.5); } - return new InnerStateAutonom(image, title, attribute, borderColor, backColor, skinParam.shadowing(group - .getStereotype()), group.getUrl99(), withSymbol, stroke); + return new InnerStateAutonom(image, title, attribute, borderColor, backColor, + skinParam.shadowing(group.getStereotype()), group.getUrl99(), withSymbol, stroke); } diff --git a/src/net/sourceforge/plantuml/svek/Line.java b/src/net/sourceforge/plantuml/svek/Line.java index d4fc07a24..9e321e755 100644 --- a/src/net/sourceforge/plantuml/svek/Line.java +++ b/src/net/sourceforge/plantuml/svek/Line.java @@ -37,6 +37,7 @@ package net.sourceforge.plantuml.svek; import java.awt.geom.Dimension2D; import java.awt.geom.Point2D; +import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Set; @@ -97,11 +98,13 @@ import net.sourceforge.plantuml.ugraphic.UChangeColor; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.ULine; import net.sourceforge.plantuml.ugraphic.UPolygon; +import net.sourceforge.plantuml.ugraphic.URectangle; import net.sourceforge.plantuml.ugraphic.UStroke; import net.sourceforge.plantuml.ugraphic.UTranslate; public class Line implements Moveable, Hideable { + private static final Dimension2DDouble CONSTRAINT_SPOT = new Dimension2DDouble(10, 10); private final Cluster ltail; private final Cluster lhead; private final Link link; @@ -142,6 +145,7 @@ public class Line implements Moveable, Hideable { private final boolean useRankSame; private final UStroke defaultThickness; private HtmlColor arrowLollipopColor; + private final ISkinParam skinParam; // private final UmlDiagramType umlType; @@ -212,7 +216,7 @@ public class Line implements Moveable, Hideable { private Cluster getCluster2(Bibliotekon bibliotekon, IEntity entityMutable) { for (Cluster cl : bibliotekon.allCluster()) { - if (entityMutable == cl.getGroup()) { + if (cl.getGroups().contains(entityMutable)) { return cl; } } @@ -225,6 +229,7 @@ public class Line implements Moveable, Hideable { if (link == null) { throw new IllegalArgumentException(); } + this.skinParam = skinParam; // this.umlType = link.getUmlDiagramType(); this.useRankSame = skinParam.useRankSame(); this.startUid = link.getEntityPort1(bibliotekon); @@ -341,7 +346,8 @@ public class Line implements Moveable, Hideable { final VisibilityModifier visibilityModifier = link.getVisibilityModifier(); if (visibilityModifier != null) { final Rose rose = new Rose(); - // final HtmlColor back = visibilityModifier.getBackground() == null ? null : rose.getHtmlColor(skinParam, + // final HtmlColor back = visibilityModifier.getBackground() == null ? null : + // rose.getHtmlColor(skinParam, // visibilityModifier.getBackground()); final HtmlColor fore = rose.getHtmlColor(skinParam, visibilityModifier.getForeground()); TextBlock visibility = visibilityModifier.getUBlock(skinParam.classAttributeIconSize(), fore, null, false); @@ -402,17 +408,17 @@ public class Line implements Moveable, Hideable { sb.append(","); } sb.append("color=\"" + StringUtils.getAsHtml(lineColor) + "\""); - if (labelText != null) { + if (labelText != null || link.getLinkConstraint() != null) { sb.append(","); if (graphvizVersion.useXLabelInsteadOfLabel() || dotMode == DotMode.NO_LEFT_RIGHT_AND_XLABEL) { sb.append("xlabel=<"); } else { sb.append("label=<"); } - appendTable(sb, eventuallyDivideByTwo(labelText.calculateDimension(stringBounder)), noteLabelColor, - graphvizVersion); + final Dimension2D dimNote = labelText == null ? CONSTRAINT_SPOT + : labelText.calculateDimension(stringBounder); + appendTable(sb, eventuallyDivideByTwo(dimNote), noteLabelColor, graphvizVersion); sb.append(">"); - // sb.append(",labelfloat=true"); } if (startTailText != null) { @@ -420,14 +426,12 @@ public class Line implements Moveable, Hideable { sb.append("taillabel=<"); appendTable(sb, startTailText.calculateDimension(stringBounder), startTailColor, graphvizVersion); sb.append(">"); - // sb.append(",labelangle=0"); } if (endHeadText != null) { sb.append(","); sb.append("headlabel=<"); appendTable(sb, endHeadText.calculateDimension(stringBounder), endHeadColor, graphvizVersion); sb.append(">"); - // sb.append(",labelangle=0"); } if (link.isInvis()) { @@ -495,7 +499,7 @@ public class Line implements Moveable, Hideable { } private UDrawable getExtremity(LinkDecor decor, PointListIterator pointListIterator, final Point2D center, - double angle, Cluster cluster, Shape shapeContact) { + double angle, Cluster cluster, Node nodeContact) { final ExtremityFactory extremityFactory = decor.getExtremityFactory(backgroundColor); if (cluster != null) { @@ -518,8 +522,8 @@ public class Line implements Moveable, Hideable { final Point2D p1 = points.get(1); final Point2D p2 = points.get(2); Side side = null; - if (shapeContact != null) { - side = shapeContact.getClusterPosition().getClosestSide(p1); + if (nodeContact != null) { + side = nodeContact.getClusterPosition().getClosestSide(p1); } return extremityFactory.createUDrawable(p0, p1, p2, side); } else if (decor == LinkDecor.NONE) { @@ -565,9 +569,11 @@ public class Line implements Moveable, Hideable { dotPath = new DotPath(path); if (projectionCluster != null) { - // System.err.println("Line::solveLine1 projectionCluster=" + projectionCluster.getClusterPosition()); + // System.err.println("Line::solveLine1 projectionCluster=" + + // projectionCluster.getClusterPosition()); projectionCluster.manageEntryExitPoint(stringBounder); - // System.err.println("Line::solveLine2 projectionCluster=" + projectionCluster.getClusterPosition()); + // System.err.println("Line::solveLine2 projectionCluster=" + + // projectionCluster.getClusterPosition()); // if (lhead != null) // System.err.println("Line::solveLine ltail=" + lhead.getClusterPosition()); // if (ltail != null) @@ -580,15 +586,15 @@ public class Line implements Moveable, Hideable { final LinkType linkType = link.getType(); this.extremity1 = getExtremity(linkType.getDecor2(), pointListIterator, dotPath.getStartPoint(), - dotPath.getStartAngle() + Math.PI, ltail, bibliotekon.getShape(link.getEntity1())); + dotPath.getStartAngle() + Math.PI, ltail, bibliotekon.getNode(link.getEntity1())); this.extremity2 = getExtremity(linkType.getDecor1(), pointListIterator, dotPath.getEndPoint(), - dotPath.getEndAngle(), lhead, bibliotekon.getShape(link.getEntity2())); + dotPath.getEndAngle(), lhead, bibliotekon.getNode(link.getEntity2())); if (link.getEntity1().getLeafType() == LeafType.LOLLIPOP_HALF) { - bibliotekon.getShape(link.getEntity1()).addImpact(dotPath.getStartAngle() + Math.PI); + bibliotekon.getNode(link.getEntity1()).addImpact(dotPath.getStartAngle() + Math.PI); } if (link.getEntity2().getLeafType() == LeafType.LOLLIPOP_HALF) { - bibliotekon.getShape(link.getEntity2()).addImpact(dotPath.getEndAngle()); + bibliotekon.getNode(link.getEntity2()).addImpact(dotPath.getEndAngle()); } if (extremity1 instanceof Extremity && extremity2 instanceof Extremity) { @@ -603,19 +609,20 @@ public class Line implements Moveable, Hideable { if (dist1start > dist1end && dist2end > dist2start) { pointListIterator = lineSvg.getPointsWithThisColor(lineColor); this.extremity2 = getExtremity(linkType.getDecor1(), pointListIterator, dotPath.getEndPoint(), - dotPath.getEndAngle(), lhead, bibliotekon.getShape(link.getEntity2())); + dotPath.getEndAngle(), lhead, bibliotekon.getNode(link.getEntity2())); this.extremity1 = getExtremity(linkType.getDecor2(), pointListIterator, dotPath.getStartPoint(), - dotPath.getStartAngle() + Math.PI, ltail, bibliotekon.getShape(link.getEntity1())); + dotPath.getStartAngle() + Math.PI, ltail, bibliotekon.getNode(link.getEntity1())); } } } - if (this.labelText != null) { + if (this.labelText != null || link.getLinkConstraint() != null) { final Point2D pos = getXY(fullSvg, this.noteLabelColor); if (pos != null) { corner1.manage(pos); - this.labelXY = TextBlockUtils.asPositionable(labelText, stringBounder, pos); + this.labelXY = labelText == null ? TextBlockUtils.asPositionable(CONSTRAINT_SPOT, stringBounder, pos) + : TextBlockUtils.asPositionable(labelText, stringBounder, pos); } } @@ -708,8 +715,8 @@ public class Line implements Moveable, Hideable { if (link.getEntity2().isGroup() && link.getEntity2().getUSymbol() instanceof USymbolFolder) { final Cluster endCluster = bibliotekon.getCluster((IGroup) link.getEntity2()); if (endCluster != null) { - final double deltaFolderH = endCluster - .checkFolderPosition(dotPath.getEndPoint(), ug.getStringBounder()); + final double deltaFolderH = endCluster.checkFolderPosition(dotPath.getEndPoint(), + ug.getStringBounder()); todraw = new DotPath(dotPath); todraw.moveEndPoint(0, deltaFolderH); // moveEndY = deltaFolderH; @@ -739,16 +746,17 @@ public class Line implements Moveable, Hideable { if (this.labelText != null && this.labelXY != null && link.getNoteLinkStrategy() != NoteLinkStrategy.HALF_NOT_PRINTED) { - this.labelText.drawU(ug.apply(new UTranslate(x + this.labelXY.getPosition().getX(), y - + this.labelXY.getPosition().getY()))); + this.labelText.drawU(ug.apply( + new UTranslate(x + this.labelXY.getPosition().getX(), y + this.labelXY.getPosition().getY()))); } - if (this.startTailText != null && this.startTailLabelXY != null && this.startTailLabelXY.getPosition() != null) { - this.startTailText.drawU(ug.apply(new UTranslate(x + this.startTailLabelXY.getPosition().getX(), y - + this.startTailLabelXY.getPosition().getY()))); + if (this.startTailText != null && this.startTailLabelXY != null + && this.startTailLabelXY.getPosition() != null) { + this.startTailText.drawU(ug.apply(new UTranslate(x + this.startTailLabelXY.getPosition().getX(), + y + this.startTailLabelXY.getPosition().getY()))); } if (this.endHeadText != null && this.endHeadLabelXY != null && this.endHeadLabelXY.getPosition() != null) { - this.endHeadText.drawU(ug.apply(new UTranslate(x + this.endHeadLabelXY.getPosition().getX(), y - + this.endHeadLabelXY.getPosition().getY()))); + this.endHeadText.drawU(ug.apply(new UTranslate(x + this.endHeadLabelXY.getPosition().getX(), + y + this.endHeadLabelXY.getPosition().getY()))); } if (linkType.getMiddleDecor() != LinkMiddleDecor.NONE) { @@ -763,6 +771,40 @@ public class Line implements Moveable, Hideable { if (url != null) { ug.closeAction(); } + + if (link.getLinkConstraint() != null) { + final double xConstraint = x + this.labelXY.getPosition().getX(); + final double yConstraint = y + this.labelXY.getPosition().getY(); +// ug.apply(new UTranslate(xConstraint, yConstraint)).draw(new URectangle(10, 10)); + final List square = getSquare(xConstraint, yConstraint); + final Set bez = dotPath.sample(); + Point2D minPt = null; + double minDist = Double.MAX_VALUE; + for (Point2D pt : square) { + for (Point2D pt2 : bez) { + final double distance = pt2.distance(pt); + if (minPt == null || distance < minDist) { + minPt = pt; + minDist = distance; + } + } + } + link.getLinkConstraint().setPosition(link, minPt); + link.getLinkConstraint().drawMe(ug, skinParam); + } + } + + private List getSquare(double x, double y) { + final List result = new ArrayList(); + result.add(new Point2D.Double(x, y)); + result.add(new Point2D.Double(x + 5, y)); + result.add(new Point2D.Double(x + 10, y)); + result.add(new Point2D.Double(x, y + 5)); + result.add(new Point2D.Double(x + 10, y + 5)); + result.add(new Point2D.Double(x, y + 10)); + result.add(new Point2D.Double(x + 5, y + 10)); + result.add(new Point2D.Double(x + 10, y + 10)); + return result; } private String uniq(final Set ids, final String comment) { @@ -871,11 +913,12 @@ public class Line implements Moveable, Hideable { return strategy.getResult() + getDecorDzeta(); } - public void manageCollision(Collection allShapes) { + public void manageCollision(Collection allNodes) { - for (Shape sh : allShapes) { + for (Node sh : allNodes) { final Positionable cl = PositionableUtils.addMargin(sh, 8, 8); - if (startTailText != null && startTailLabelXY != null && PositionableUtils.intersect(cl, startTailLabelXY)) { + if (startTailText != null && startTailLabelXY != null + && PositionableUtils.intersect(cl, startTailLabelXY)) { startTailLabelXY = PositionableUtils.moveAwayFrom(cl, startTailLabelXY); } if (endHeadText != null && endHeadLabelXY != null && PositionableUtils.intersect(cl, endHeadLabelXY)) { @@ -903,7 +946,7 @@ public class Line implements Moveable, Hideable { } - private void avoid(Point2D.Double move, Positionable pos, Shape sh) { + private void avoid(Point2D.Double move, Positionable pos, Node sh) { final Oscillator oscillator = new Oscillator(); final Point2D.Double orig = new Point2D.Double(move.x, move.y); while (cut(pos, sh)) { @@ -912,7 +955,7 @@ public class Line implements Moveable, Hideable { } } - private boolean cut(Positionable pos, Shape sh) { + private boolean cut(Positionable pos, Node sh) { return BezierUtils.intersect(pos, sh) || tooClose(pos); } diff --git a/src/net/sourceforge/plantuml/svek/Shape.java b/src/net/sourceforge/plantuml/svek/Node.java similarity index 91% rename from src/net/sourceforge/plantuml/svek/Shape.java rename to src/net/sourceforge/plantuml/svek/Node.java index da602d413..06fc8ec28 100644 --- a/src/net/sourceforge/plantuml/svek/Shape.java +++ b/src/net/sourceforge/plantuml/svek/Node.java @@ -44,6 +44,9 @@ import net.sourceforge.plantuml.Dimension2DDouble; import net.sourceforge.plantuml.Hideable; import net.sourceforge.plantuml.StringUtils; import net.sourceforge.plantuml.cucadiagram.EntityPosition; +import net.sourceforge.plantuml.cucadiagram.IGroup; +import net.sourceforge.plantuml.cucadiagram.ILeaf; +import net.sourceforge.plantuml.cucadiagram.entity.EntityImpl; import net.sourceforge.plantuml.graphic.StringBounder; import net.sourceforge.plantuml.posimo.Positionable; import net.sourceforge.plantuml.svek.image.EntityImageDescription; @@ -52,7 +55,7 @@ import net.sourceforge.plantuml.svek.image.EntityImageStateBorder; import net.sourceforge.plantuml.ugraphic.Shadowable; import net.sourceforge.plantuml.ugraphic.UPolygon; -public class Shape implements Positionable, IShapePseudo, Hideable { +public class Node implements Positionable, IShapePseudo, Hideable { private final ShapeType type; private final double width; @@ -89,21 +92,32 @@ public class Shape implements Positionable, IShapePseudo, Hideable { return super.toString() + " " + image + " " + type; } - public Shape(IEntityImage image, ShapeType type, double width, double height, ColorSequence colorSequence, - boolean top, Margins shield, EntityPosition entityPosition) { - this.entityPosition = entityPosition; + private final ILeaf leaf; + private final IGroup group; + + Node(ILeaf ent, IEntityImage image, ColorSequence colorSequence, StringBounder stringBounder) { + final Dimension2D dim = image.calculateDimension(stringBounder); + this.entityPosition = ent.getEntityPosition(); this.image = image; - this.top = top; - this.type = type; - this.width = width; - this.height = height; + this.top = ent.isTop(); + this.type = image.getShapeType(); + this.width = dim.getWidth(); + this.height = dim.getHeight(); this.color = colorSequence.getValue(); this.uid = String.format("sh%04d", color); - this.shield = shield; + this.shield = image.getShield(stringBounder); if (shield.isZero() == false && type != ShapeType.RECTANGLE && type != ShapeType.RECTANGLE_HTML_FOR_PORTS && type != ShapeType.RECTANGLE_WITH_CIRCLE_INSIDE) { throw new IllegalArgumentException(); } + + if (((EntityImpl) ent).getOriginalGroup() == null) { + this.group = null; + this.leaf = ent; + } else { + this.group = ((EntityImpl) ent).getOriginalGroup(); + this.leaf = null; + } } public final ShapeType getType() { diff --git a/src/net/sourceforge/plantuml/svek/SvekResult.java b/src/net/sourceforge/plantuml/svek/SvekResult.java index 7d84de7bb..da89ae854 100644 --- a/src/net/sourceforge/plantuml/svek/SvekResult.java +++ b/src/net/sourceforge/plantuml/svek/SvekResult.java @@ -86,11 +86,11 @@ public final class SvekResult extends AbstractTextBlock implements IEntityImage, } color = HtmlColorUtils.noGradient(color); - for (Shape shape : dotStringFactory.getBibliotekon().allShapes()) { - final double minX = shape.getMinX(); - final double minY = shape.getMinY(); - final UGraphic ug2 = shape.isHidden() ? ug.apply(UHidden.HIDDEN) : ug; - final IEntityImage image = shape.getImage(); + for (Node node : dotStringFactory.getBibliotekon().allNodes()) { + final double minX = node.getMinX(); + final double minY = node.getMinY(); + final UGraphic ug2 = node.isHidden() ? ug.apply(UHidden.HIDDEN) : ug; + final IEntityImage image = node.getImage(); image.drawU(ug2.apply(new UTranslate(minX, minY))); if (image instanceof Untranslated) { ((Untranslated) image).drawUntranslated(ug.apply(new UChangeColor(color)), minX, minY); diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageActivity.java b/src/net/sourceforge/plantuml/svek/image/EntityImageActivity.java index 76f29aaa2..3fd49b074 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageActivity.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageActivity.java @@ -58,7 +58,7 @@ import net.sourceforge.plantuml.style.Style; import net.sourceforge.plantuml.style.StyleSignature; import net.sourceforge.plantuml.svek.AbstractEntityImage; import net.sourceforge.plantuml.svek.Bibliotekon; -import net.sourceforge.plantuml.svek.Shape; +import net.sourceforge.plantuml.svek.Node; import net.sourceforge.plantuml.svek.ShapeType; import net.sourceforge.plantuml.ugraphic.Shadowable; import net.sourceforge.plantuml.ugraphic.UChangeBackColor; @@ -122,8 +122,8 @@ public class EntityImageActivity extends AbstractEntityImage { } private UGraphic drawOctagon(UGraphic ug) { - final Shape shape = bibliotekon.getShape(getEntity()); - final Shadowable octagon = shape.getOctagon(); + final Node node = bibliotekon.getNode(getEntity()); + final Shadowable octagon = node.getOctagon(); octagon.setDeltaShadow(shadowing); ug = applyColors(ug); ug.apply(new UStroke(1.5)).draw(octagon); diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageLollipopInterfaceEye1.java b/src/net/sourceforge/plantuml/svek/image/EntityImageLollipopInterfaceEye1.java index 563b1a929..dfc585561 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageLollipopInterfaceEye1.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageLollipopInterfaceEye1.java @@ -99,7 +99,7 @@ public class EntityImageLollipopInterfaceEye1 extends AbstractEntityImage { ug.apply(new UStroke(1.5)).apply(new UTranslate(diff, diff)).draw(circle1); ug = ug.apply(new UChangeBackColor(null)); - Point2D pos = bibliotekon.getShape(getEntity()).getPosition(); + Point2D pos = bibliotekon.getNode(getEntity()).getPosition(); final List lines = bibliotekon.getAllLineConnectedTo(getEntity()); final UTranslate reverse = new UTranslate(pos).reverse(); diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageNote.java b/src/net/sourceforge/plantuml/svek/image/EntityImageNote.java index d0010698c..6ea5297ea 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageNote.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageNote.java @@ -73,7 +73,7 @@ import net.sourceforge.plantuml.style.Style; import net.sourceforge.plantuml.style.StyleSignature; import net.sourceforge.plantuml.svek.AbstractEntityImage; import net.sourceforge.plantuml.svek.Line; -import net.sourceforge.plantuml.svek.Shape; +import net.sourceforge.plantuml.svek.Node; import net.sourceforge.plantuml.svek.ShapeType; import net.sourceforge.plantuml.ugraphic.UChangeBackColor; import net.sourceforge.plantuml.ugraphic.UChangeColor; @@ -211,7 +211,7 @@ public class EntityImageNote extends AbstractEntityImage implements Stencil { } else { final StringBounder stringBounder = ug.getStringBounder(); DotPath path = opaleLine.getDotPath(); - path.moveSvek(-shape.getMinX(), -shape.getMinY()); + path.moveSvek(-node.getMinX(), -node.getMinY()); Point2D p1 = path.getStartPoint(); Point2D p2 = path.getEndPoint(); final double textWidth = getTextWidth(stringBounder); @@ -225,9 +225,9 @@ public class EntityImageNote extends AbstractEntityImage implements Stencil { final Direction strategy = getOpaleStrategy(textWidth, textHeight, p1); final Point2D pp1 = path.getStartPoint(); final Point2D pp2 = path.getEndPoint(); - final Point2D newRefpp2 = move(pp2, shape.getMinX(), shape.getMinY()); - final Point2D projection = move(other.projection(newRefpp2, stringBounder), -shape.getMinX(), - -shape.getMinY()); + final Point2D newRefpp2 = move(pp2, node.getMinX(), node.getMinY()); + final Point2D projection = move(other.projection(newRefpp2, stringBounder), -node.getMinX(), + -node.getMinY()); final Opale opale = new Opale(shadowing, borderColor, noteBackgroundColor, textBlock, true); opale.setRoundCorner(getRoundCorner()); opale.setOpale(strategy, pp1, projection); @@ -296,15 +296,15 @@ public class EntityImageNote extends AbstractEntityImage implements Stencil { } private Line opaleLine; - private Shape shape; - private Shape other; + private Node node; + private Node other; - public void setOpaleLine(Line line, Shape shape, Shape other) { + public void setOpaleLine(Line line, Node node, Node other) { if (other == null) { throw new IllegalArgumentException(); } this.opaleLine = line; - this.shape = shape; + this.node = node; this.other = other; } diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageStateBorder.java b/src/net/sourceforge/plantuml/svek/image/EntityImageStateBorder.java index 840e2d9fc..e9b8fd36c 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageStateBorder.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageStateBorder.java @@ -55,7 +55,7 @@ import net.sourceforge.plantuml.graphic.color.ColorType; import net.sourceforge.plantuml.svek.AbstractEntityImage; import net.sourceforge.plantuml.svek.Bibliotekon; import net.sourceforge.plantuml.svek.Cluster; -import net.sourceforge.plantuml.svek.Shape; +import net.sourceforge.plantuml.svek.Node; import net.sourceforge.plantuml.svek.ShapeType; import net.sourceforge.plantuml.ugraphic.UChangeBackColor; import net.sourceforge.plantuml.ugraphic.UChangeColor; @@ -89,8 +89,8 @@ public class EntityImageStateBorder extends AbstractEntityImage { private boolean upPosition() { final Point2D clusterCenter = stateParent.getClusterPosition().getPointCenter(); - final Shape sh = bibliotekon.getShape(getEntity()); - return sh.getMinY() < clusterCenter.getY(); + final Node node = bibliotekon.getNode(getEntity()); + return node.getMinY() < clusterCenter.getY(); } public Dimension2D calculateDimension(StringBounder stringBounder) { diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageTips.java b/src/net/sourceforge/plantuml/svek/image/EntityImageTips.java index 8825e7267..60d17a2fc 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageTips.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageTips.java @@ -61,7 +61,7 @@ import net.sourceforge.plantuml.graphic.color.ColorType; import net.sourceforge.plantuml.skin.rose.Rose; import net.sourceforge.plantuml.svek.AbstractEntityImage; import net.sourceforge.plantuml.svek.Bibliotekon; -import net.sourceforge.plantuml.svek.Shape; +import net.sourceforge.plantuml.svek.Node; import net.sourceforge.plantuml.svek.ShapeType; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.UTranslate; @@ -120,17 +120,17 @@ public class EntityImageTips extends AbstractEntityImage { final IEntity other = bibliotekon.getOnlyOther(getEntity()); - final Shape shapeMe = bibliotekon.getShape(getEntity()); - final Shape shapeOther = bibliotekon.getShape(other); - final Point2D positionMe = shapeMe.getPosition(); - final Point2D positionOther = shapeOther.getPosition(); - bibliotekon.getShape(getEntity()); + final Node nodeMe = bibliotekon.getNode(getEntity()); + final Node nodeOther = bibliotekon.getNode(other); + final Point2D positionMe = nodeMe.getPosition(); + final Point2D positionOther = nodeOther.getPosition(); + bibliotekon.getNode(getEntity()); final Position position = getPosition(); Direction direction = position.reverseDirection(); double height = 0; for (Map.Entry ent : getEntity().getTips().entrySet()) { final Display display = ent.getValue(); - final Rectangle2D memberPosition = shapeOther.getImage().getInnerPosition(ent.getKey(), stringBounder, + final Rectangle2D memberPosition = nodeOther.getImage().getInnerPosition(ent.getKey(), stringBounder, InnerStrategy.STRICT); if (memberPosition == null) { return; diff --git a/src/net/sourceforge/plantuml/svg/SvgGraphics.java b/src/net/sourceforge/plantuml/svg/SvgGraphics.java index 7b4c221b9..3ff140f66 100644 --- a/src/net/sourceforge/plantuml/svg/SvgGraphics.java +++ b/src/net/sourceforge/plantuml/svg/SvgGraphics.java @@ -538,13 +538,13 @@ public class SvgGraphics { private Transformer getTransformer() throws TransformerException { // Get a TransformerFactory object. TransformerFactory xformFactory = null; - try { - final Class factoryClass = Class - .forName("com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"); - xformFactory = (TransformerFactory) factoryClass.newInstance(); - } catch (Exception e) { +// try { +// final Class factoryClass = Class +// .forName("com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"); +// xformFactory = (TransformerFactory) factoryClass.newInstance(); +// } catch (Exception e) { xformFactory = TransformerFactory.newInstance(); - } +// } Log.info("TransformerFactory=" + xformFactory.getClass()); // Get an XSL Transformer object. diff --git a/src/net/sourceforge/plantuml/tikz/TikzGraphics.java b/src/net/sourceforge/plantuml/tikz/TikzGraphics.java index a7ce8e804..8898591df 100644 --- a/src/net/sourceforge/plantuml/tikz/TikzGraphics.java +++ b/src/net/sourceforge/plantuml/tikz/TikzGraphics.java @@ -135,8 +135,7 @@ public class TikzGraphics { out(os, " \\p2=(sourcenode.south east),"); out(os, " \\n1={\\x2-\\x1},"); out(os, " \\n2={\\y2-\\y1} in"); - out(os, - " node [inner sep=0pt, outer sep=0pt,anchor=north west,at=(\\p1)] {\\href{#1}{\\XeTeXLinkBox{\\phantom{\\rule{\\n1}{\\n2}}}}}"); + out(os, " node [inner sep=0pt, outer sep=0pt,anchor=north west,at=(\\p1)] {\\href{#1}{\\XeTeXLinkBox{\\phantom{\\rule{\\n1}{\\n2}}}}}"); out(os, " %xelatex needs \\XeTeXLinkBox, won't create a link unless it"); out(os, " %finds text --- rules don't work without \\XeTeXLinkBox."); out(os, " %Still builds correctly with pdflatex and lualatex"); @@ -151,8 +150,7 @@ public class TikzGraphics { out(os, " \\p2=(sourcenode.south east),"); out(os, " \\n1={\\x2-\\x1},"); out(os, " \\n2={\\y2-\\y1} in"); - out(os, - " node [inner sep=0pt, outer sep=0pt,anchor=north west,at=(\\p1)] {\\hyperref [#1]{\\XeTeXLinkBox{\\phantom{\\rule{\\n1}{\\n2}}}}}"); + out(os, " node [inner sep=0pt, outer sep=0pt,anchor=north west,at=(\\p1)] {\\hyperref [#1]{\\XeTeXLinkBox{\\phantom{\\rule{\\n1}{\\n2}}}}}"); out(os, " %xelatex needs \\XeTeXLinkBox, won't create a link unless it"); out(os, " %finds text --- rules don't work without \\XeTeXLinkBox."); out(os, " %Still builds correctly with pdflatex and lualatex"); @@ -318,6 +316,9 @@ public class TikzGraphics { } public void appendRaw(double x, double y, String formula) { + if (formula == null) { + throw new IllegalArgumentException(); + } final StringBuilder sb = new StringBuilder("\\node at " + couple(x, y)); sb.append("[below right"); sb.append("]{"); @@ -487,7 +488,8 @@ public class TikzGraphics { } else if (type == USegmentType.SEG_QUADTO) { throw new UnsupportedOperationException(); } else if (type == USegmentType.SEG_CUBICTO) { - // curvetoNoMacro(coord[0] + x, coord[1] + y, coord[2] + x, coord[3] + y, coord[4] + x, coord[5] + y); + // curvetoNoMacro(coord[0] + x, coord[1] + y, coord[2] + x, coord[3] + y, + // coord[4] + x, coord[5] + y); sb.append(" ..controls "); sb.append(couple(coord[0] + x, coord[1] + y)); sb.append(" and "); @@ -543,8 +545,8 @@ public class TikzGraphics { } public void drawPathIterator(double x, double y, PathIterator path) { - final StringBuilder sb = new StringBuilder("\\draw[color=" + getColorName(color) + ",fill=" - + getColorName(color) + "] "); + final StringBuilder sb = new StringBuilder( + "\\draw[color=" + getColorName(color) + ",fill=" + getColorName(color) + "] "); final double coord[] = new double[6]; while (path.isDone() == false) { final int code = path.currentSegment(coord); diff --git a/src/net/sourceforge/plantuml/ugraphic/UImage.java b/src/net/sourceforge/plantuml/ugraphic/UImage.java index 569cff812..261855154 100644 --- a/src/net/sourceforge/plantuml/ugraphic/UImage.java +++ b/src/net/sourceforge/plantuml/ugraphic/UImage.java @@ -46,14 +46,24 @@ public class UImage implements UShape { private final BufferedImage image; private final String formula; + private final String rawFileName; - public UImage(BufferedImage image) { - this(image, null); + public String getRawFileName() { + return rawFileName; } - public UImage(BufferedImage image, String formula) { + public UImage(BufferedImage image) { + this(null, image, null); + } + + public UImage(String rawFileName, BufferedImage image) { + this(rawFileName, image, null); + } + + public UImage(String rawFileName, BufferedImage image, String formula) { this.image = image; this.formula = formula; + this.rawFileName = rawFileName; } public UImage scale(double scale) { @@ -74,7 +84,7 @@ public class UImage implements UShape { final AffineTransform at = new AffineTransform(); at.scale(scale, scale); final AffineTransformOp scaleOp = new AffineTransformOp(at, type); - return new UImage(scaleOp.filter(image, after), formula); + return new UImage(rawFileName, scaleOp.filter(image, after), formula); } public final BufferedImage getImage() { @@ -109,7 +119,7 @@ public class UImage implements UShape { } } } - return new UImage(copy, formula); + return new UImage(rawFileName, copy, formula); } public UImage muteTransparentColor(Color newColor) { @@ -127,7 +137,7 @@ public class UImage implements UShape { } } } - return new UImage(copy, formula); + return new UImage(rawFileName, copy, formula); } private int getDarkerRgb() { @@ -135,7 +145,8 @@ public class UImage implements UShape { for (int i = 0; i < image.getWidth(); i++) { for (int j = 0; j < image.getHeight(); j++) { final int color = image.getRGB(i, j); - // System.err.println("i="+i+" j="+j+" "+Integer.toHexString(color)+" "+isTransparent(color)); + // System.err.println("i="+i+" j="+j+" "+Integer.toHexString(color)+" + // "+isTransparent(color)); final int rgb = getRgb(color); final int a = getA(color); if (a != mask_a__) { @@ -171,7 +182,8 @@ public class UImage implements UShape { // return true; // } - // From https://stackoverflow.com/questions/3514158/how-do-you-clone-a-bufferedimage + // From + // https://stackoverflow.com/questions/3514158/how-do-you-clone-a-bufferedimage private static BufferedImage deepCopyOld(BufferedImage bi) { final ColorModel cm = bi.getColorModel(); final boolean isAlphaPremultiplied = cm.isAlphaPremultiplied(); @@ -180,7 +192,8 @@ public class UImage implements UShape { } private BufferedImage deepCopy2() { - final BufferedImage result = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB); + final BufferedImage result = new BufferedImage(image.getWidth(), image.getHeight(), + BufferedImage.TYPE_INT_ARGB); for (int i = 0; i < this.image.getWidth(); i++) { for (int j = 0; j < this.image.getHeight(); j++) { result.setRGB(i, j, image.getRGB(i, j)); diff --git a/src/net/sourceforge/plantuml/ugraphic/tikz/DriverImageTikz.java b/src/net/sourceforge/plantuml/ugraphic/tikz/DriverImageTikz.java index 0ad98c118..5ee37cedf 100644 --- a/src/net/sourceforge/plantuml/ugraphic/tikz/DriverImageTikz.java +++ b/src/net/sourceforge/plantuml/ugraphic/tikz/DriverImageTikz.java @@ -45,6 +45,15 @@ public class DriverImageTikz implements UDriver { public void draw(UShape ushape, double x, double y, ColorMapper mapper, UParam param, TikzGraphics tikz) { final UImage shape = (UImage) ushape; - tikz.appendRaw(x, y, shape.getFormula()); + final String rawFileName = shape.getRawFileName(); + if (rawFileName != null) { + final String raw = "\\includegraphics{" + rawFileName + "}"; + tikz.appendRaw(x, y, raw); + return; + } + final String formula = shape.getFormula(); + if (formula != null) { + tikz.appendRaw(x, y, formula); + } } } diff --git a/src/net/sourceforge/plantuml/version/Version.java b/src/net/sourceforge/plantuml/version/Version.java index f56c78261..b7321e099 100644 --- a/src/net/sourceforge/plantuml/version/Version.java +++ b/src/net/sourceforge/plantuml/version/Version.java @@ -43,7 +43,7 @@ public class Version { private static final int MAJOR_SEPARATOR = 1000000; public static int version() { - return 1202000; + return 1202001; } public static int versionPatched() { @@ -59,12 +59,11 @@ public class Version { } return dotted(version()); } - + public static String fullDescription() { return "PlantUML version " + Version.versionString() + " (" + Version.compileTimeString() + ")"; } - private static String dotted(int nb) { final String minor = "" + nb % MAJOR_SEPARATOR; final String major = "" + nb / MAJOR_SEPARATOR; @@ -93,7 +92,7 @@ public class Version { } public static long compileTime() { - return 1578745853861L; + return 1581874832922L; } public static String compileTimeString() { diff --git a/src/net/sourceforge/plantuml/wire/Block.java b/src/net/sourceforge/plantuml/wire/Block.java new file mode 100644 index 000000000..32eb6c3cf --- /dev/null +++ b/src/net/sourceforge/plantuml/wire/Block.java @@ -0,0 +1,208 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.wire; + +import java.awt.geom.Dimension2D; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import net.sourceforge.plantuml.Dimension2DDouble; +import net.sourceforge.plantuml.FontParam; +import net.sourceforge.plantuml.ISkinParam; +import net.sourceforge.plantuml.command.Position; +import net.sourceforge.plantuml.cucadiagram.Display; +import net.sourceforge.plantuml.graphic.AbstractTextBlock; +import net.sourceforge.plantuml.graphic.FontConfiguration; +import net.sourceforge.plantuml.graphic.HorizontalAlignment; +import net.sourceforge.plantuml.graphic.HtmlColorUtils; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.graphic.TextBlock; +import net.sourceforge.plantuml.ugraphic.MinMax; +import net.sourceforge.plantuml.ugraphic.UChangeColor; +import net.sourceforge.plantuml.ugraphic.UEllipse; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.URectangle; +import net.sourceforge.plantuml.ugraphic.UTranslate; + +public class Block extends AbstractTextBlock { + + static class Pos { + final double x; + final double y; + + public Pos(double x, double y) { + this.x = x; + this.y = y; + } + + UGraphic move(UGraphic ug) { + return ug.apply(new UTranslate(x, y)); + } + } + + private final Map children = new LinkedHashMap(); + private final Display display; + private final Dimension2DDouble fixedDim; + private final ISkinParam skinParam; + + private final List left = new ArrayList(); + private final List right = new ArrayList(); + private final List top = new ArrayList(); + private final List bottom = new ArrayList(); + + private double x = 10; + private double y = 10; + + private MinMax minMax = MinMax.getEmpty(true); + private Block parent; + + public Block(ISkinParam skinParam) { + this(skinParam, Display.empty(), null); + } + + private Block(ISkinParam skinParam, Display display, Dimension2DDouble fixedDim) { + this.skinParam = skinParam; + this.display = display; + this.fixedDim = fixedDim; + + } + + private List getPins(Position position) { + switch (position) { + case LEFT: + return left; + case RIGHT: + return right; + case TOP: + return top; + case BOTTOM: + return bottom; + } + throw new IllegalArgumentException(); + } + + public Dimension2D calculateDimension(StringBounder stringBounder) { + if (fixedDim == null) { + return minMax.getDimension(); + } + return fixedDim; + } + + public void drawU(UGraphic ug) { + ug = ug.apply(new UChangeColor(HtmlColorUtils.BLACK)); + if (children.size() == 0) { + final TextBlock label = display.create(new FontConfiguration(skinParam, FontParam.COMPONENT, null), + HorizontalAlignment.CENTER, skinParam); + label.drawU(ug.apply(new UTranslate(10, 10))); + } else { + for (Entry ent : children.entrySet()) { + ent.getKey().drawU(ent.getValue().move(ug)); + } + } + ug.draw(new URectangle(calculateDimension(ug.getStringBounder()))); + + drawPins(Position.BOTTOM, ug); + drawPins(Position.TOP, ug); + drawPins(Position.LEFT, ug); + drawPins(Position.RIGHT, ug); + + } + + private void drawPins(Position pos, UGraphic ug) { + double px = -2; + double py = 10; + if (pos == Position.RIGHT) { + px = calculateDimension(ug.getStringBounder()).getWidth() - 2; + } + if (pos == Position.TOP) { + px = 10; + py = -2; + } + if (pos == Position.BOTTOM) { + px = 10; + py = calculateDimension(ug.getStringBounder()).getHeight() - 2; + } + for (String pin : getPins(pos)) { + ug.apply(new UTranslate(px, py)).draw(new UEllipse(4, 4)); + if (pos == Position.LEFT || pos == Position.RIGHT) { + py += 15; + } else { + px += 15; + } + } + } + + public Block componentEnd() { + parent.minMax = parent.minMax.addPoint(parent.x + this.minMax.getMaxX() + 10, + parent.y + this.minMax.getMaxY() + 10); + parent.x += this.minMax.getMaxX() + 10; + return parent; + } + + public Block addNewBlock(String name, int width, int height) { + final Dimension2DDouble dim = new Dimension2DDouble(width, height); + final Block child = new Block(skinParam, Display.create(name), dim); + children.put(child, new Pos(x, y)); + y += dim.getHeight() + 10; + minMax = minMax.addPoint(x + dim.getWidth() + 10, y); + return child; + } + + public Block createContainer(String name) { + final Block result = new Block(skinParam); + result.parent = this; + children.put(result, new Pos(x, y)); + return result; + } + + public void vspace(int vspace) { + y += vspace - 10; + minMax = minMax.addPoint(x, y); + } + + public void newColumn() { + this.x = minMax.getMaxX(); + this.y = 10; + } + + public void addPin(Position position, String pin) { + getPins(position).add(pin); + } + +} diff --git a/src/net/sourceforge/plantuml/wire/CommandComponent.java b/src/net/sourceforge/plantuml/wire/CommandComponent.java new file mode 100644 index 000000000..a9bf9d4e9 --- /dev/null +++ b/src/net/sourceforge/plantuml/wire/CommandComponent.java @@ -0,0 +1,82 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.wire; + +import net.sourceforge.plantuml.LineLocation; +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.command.SingleLineCommand2; +import net.sourceforge.plantuml.command.regex.IRegex; +import net.sourceforge.plantuml.command.regex.RegexConcat; +import net.sourceforge.plantuml.command.regex.RegexLeaf; +import net.sourceforge.plantuml.command.regex.RegexOptional; +import net.sourceforge.plantuml.command.regex.RegexResult; + +public class CommandComponent extends SingleLineCommand2 { + + public CommandComponent() { + super(false, getRegexConcat()); + } + + static IRegex getRegexConcat() { + return RegexConcat.build(CommandComponent.class.getName(), RegexLeaf.start(), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("TYPE", "component"), // + RegexLeaf.spaceOneOrMore(), // + new RegexLeaf("NAME", "([\\w]+)"), // + new RegexOptional(new RegexConcat( // + RegexLeaf.spaceOneOrMore(), // + new RegexLeaf("\\["), // + new RegexLeaf("WIDTH", "([\\d]+)"), // + new RegexLeaf("[x*]"), // + new RegexLeaf("HEIGHT", "([\\d]+)"), // + new RegexLeaf("\\]")) // + ), // + RegexLeaf.end()); + } + + @Override + protected CommandExecutionResult executeArg(WireDiagram diagram, LineLocation location, RegexResult arg) { + final String name = arg.get("NAME", 0); + final String width = arg.get("WIDTH", 0); + final String height = arg.get("HEIGHT", 0); + if (width != null) { + return diagram.addComponent(name, Integer.parseInt(width), Integer.parseInt(height)); + } else { + return diagram.addComponent(name); + } + } + +} diff --git a/src/net/sourceforge/plantuml/wire/CommandContainer.java b/src/net/sourceforge/plantuml/wire/CommandContainer.java new file mode 100644 index 000000000..2c1ce3692 --- /dev/null +++ b/src/net/sourceforge/plantuml/wire/CommandContainer.java @@ -0,0 +1,70 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.wire; + +import net.sourceforge.plantuml.LineLocation; +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.command.SingleLineCommand2; +import net.sourceforge.plantuml.command.regex.IRegex; +import net.sourceforge.plantuml.command.regex.RegexConcat; +import net.sourceforge.plantuml.command.regex.RegexLeaf; +import net.sourceforge.plantuml.command.regex.RegexOptional; +import net.sourceforge.plantuml.command.regex.RegexResult; + +public class CommandContainer extends SingleLineCommand2 { + + public CommandContainer() { + super(false, getRegexConcat()); + } + + static IRegex getRegexConcat() { + return RegexConcat.build(CommandContainer.class.getName(), RegexLeaf.start(), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("TYPE", "component"), // + RegexLeaf.spaceOneOrMore(), // + new RegexLeaf("NAME", "([\\w]+)"), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("\\{"), // + RegexLeaf.end()); + } + + @Override + protected CommandExecutionResult executeArg(WireDiagram diagram, LineLocation location, RegexResult arg) { + final String name = arg.get("NAME", 0); + return diagram.addStartContainer(name); + } + +} diff --git a/src/net/sourceforge/plantuml/wire/CommandContainerEnd.java b/src/net/sourceforge/plantuml/wire/CommandContainerEnd.java new file mode 100644 index 000000000..3fc90ce4f --- /dev/null +++ b/src/net/sourceforge/plantuml/wire/CommandContainerEnd.java @@ -0,0 +1,65 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.wire; + +import net.sourceforge.plantuml.LineLocation; +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.command.SingleLineCommand2; +import net.sourceforge.plantuml.command.regex.IRegex; +import net.sourceforge.plantuml.command.regex.RegexConcat; +import net.sourceforge.plantuml.command.regex.RegexLeaf; +import net.sourceforge.plantuml.command.regex.RegexOptional; +import net.sourceforge.plantuml.command.regex.RegexResult; + +public class CommandContainerEnd extends SingleLineCommand2 { + + public CommandContainerEnd() { + super(false, getRegexConcat()); + } + + static IRegex getRegexConcat() { + return RegexConcat.build(CommandContainerEnd.class.getName(), RegexLeaf.start(), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("\\}"), // + RegexLeaf.end()); + } + + @Override + protected CommandExecutionResult executeArg(WireDiagram diagram, LineLocation location, RegexResult arg) { + return diagram.componentEnd(); + } + +} diff --git a/src/net/sourceforge/plantuml/wire/CommandNewColumn.java b/src/net/sourceforge/plantuml/wire/CommandNewColumn.java new file mode 100644 index 000000000..650e5543c --- /dev/null +++ b/src/net/sourceforge/plantuml/wire/CommandNewColumn.java @@ -0,0 +1,65 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.wire; + +import net.sourceforge.plantuml.LineLocation; +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.command.SingleLineCommand2; +import net.sourceforge.plantuml.command.regex.IRegex; +import net.sourceforge.plantuml.command.regex.RegexConcat; +import net.sourceforge.plantuml.command.regex.RegexLeaf; +import net.sourceforge.plantuml.command.regex.RegexOptional; +import net.sourceforge.plantuml.command.regex.RegexResult; + +public class CommandNewColumn extends SingleLineCommand2 { + + public CommandNewColumn() { + super(false, getRegexConcat()); + } + + static IRegex getRegexConcat() { + return RegexConcat.build(CommandNewColumn.class.getName(), RegexLeaf.start(), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("-+"), // + RegexLeaf.end()); + } + + @Override + protected CommandExecutionResult executeArg(WireDiagram diagram, LineLocation location, RegexResult arg) { + return diagram.newColumn(); + } + +} diff --git a/src/net/sourceforge/plantuml/wire/CommandPin.java b/src/net/sourceforge/plantuml/wire/CommandPin.java new file mode 100644 index 000000000..c346cd8b5 --- /dev/null +++ b/src/net/sourceforge/plantuml/wire/CommandPin.java @@ -0,0 +1,79 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.wire; + +import net.sourceforge.plantuml.LineLocation; +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.command.Position; +import net.sourceforge.plantuml.command.SingleLineCommand2; +import net.sourceforge.plantuml.command.regex.IRegex; +import net.sourceforge.plantuml.command.regex.RegexConcat; +import net.sourceforge.plantuml.command.regex.RegexLeaf; +import net.sourceforge.plantuml.command.regex.RegexOr; +import net.sourceforge.plantuml.command.regex.RegexResult; + +public class CommandPin extends SingleLineCommand2 { + + public CommandPin() { + super(false, getRegexConcat()); + } + + static IRegex getRegexConcat() { + return RegexConcat.build(CommandPin.class.getName(), RegexLeaf.start(), // + RegexLeaf.spaceZeroOrMore(), // + new RegexOr("POSITION", // + new RegexLeaf("top"), // + new RegexLeaf("bottom"), // + new RegexLeaf("left"), // + new RegexLeaf("right")), // + new RegexLeaf(":"), // + new RegexLeaf("PINS", "(.*)"), // + RegexLeaf.end()); + } + + @Override + protected CommandExecutionResult executeArg(WireDiagram diagram, LineLocation location, RegexResult arg) { + final Position position = Position.fromString(arg.get("POSITION", 0)); + final String pins = arg.get("PINS", 0); + + for (String s : pins.split(",")) { + diagram.addPin(position, s.trim()); + } + + return CommandExecutionResult.ok(); + } + +} diff --git a/src/net/sourceforge/plantuml/wire/CommandPinSpace.java b/src/net/sourceforge/plantuml/wire/CommandPinSpace.java new file mode 100644 index 000000000..ce213ab7c --- /dev/null +++ b/src/net/sourceforge/plantuml/wire/CommandPinSpace.java @@ -0,0 +1,72 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.wire; + +import net.sourceforge.plantuml.LineLocation; +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.command.SingleLineCommand2; +import net.sourceforge.plantuml.command.regex.IRegex; +import net.sourceforge.plantuml.command.regex.RegexConcat; +import net.sourceforge.plantuml.command.regex.RegexLeaf; +import net.sourceforge.plantuml.command.regex.RegexOptional; +import net.sourceforge.plantuml.command.regex.RegexOr; +import net.sourceforge.plantuml.command.regex.RegexResult; + +public class CommandPinSpace extends SingleLineCommand2 { + + public CommandPinSpace() { + super(false, getRegexConcat()); + } + + static IRegex getRegexConcat() { + return RegexConcat.build(CommandPinSpace.class.getName(), RegexLeaf.start(), // + RegexLeaf.spaceZeroOrMore(), // + new RegexOr("POSITION", // + new RegexLeaf("top"), // + new RegexLeaf("bottom"), // + new RegexLeaf("left"), // + new RegexLeaf("right")), // + new RegexLeaf(" "), // + new RegexLeaf(".*"), // + RegexLeaf.end()); + } + + @Override + protected CommandExecutionResult executeArg(WireDiagram diagram, LineLocation location, RegexResult arg) { + return CommandExecutionResult.ok(); + } + +} diff --git a/src/net/sourceforge/plantuml/wire/CommandVspace.java b/src/net/sourceforge/plantuml/wire/CommandVspace.java new file mode 100644 index 000000000..b78fe2e0b --- /dev/null +++ b/src/net/sourceforge/plantuml/wire/CommandVspace.java @@ -0,0 +1,68 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.wire; + +import net.sourceforge.plantuml.LineLocation; +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.command.SingleLineCommand2; +import net.sourceforge.plantuml.command.regex.IRegex; +import net.sourceforge.plantuml.command.regex.RegexConcat; +import net.sourceforge.plantuml.command.regex.RegexLeaf; +import net.sourceforge.plantuml.command.regex.RegexOptional; +import net.sourceforge.plantuml.command.regex.RegexResult; + +public class CommandVspace extends SingleLineCommand2 { + + public CommandVspace() { + super(false, getRegexConcat()); + } + + static IRegex getRegexConcat() { + return RegexConcat.build(CommandVspace.class.getName(), RegexLeaf.start(), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("TYPE", "vspace"), // + RegexLeaf.spaceOneOrMore(), // + new RegexLeaf("HEIGHT", "([\\d]+)"), // + RegexLeaf.end()); + } + + @Override + protected CommandExecutionResult executeArg(WireDiagram diagram, LineLocation location, RegexResult arg) { + final String height = arg.get("HEIGHT", 0); + return diagram.vspace(Integer.parseInt(height)); + } + +} diff --git a/src/net/sourceforge/plantuml/wire/WireDiagram.java b/src/net/sourceforge/plantuml/wire/WireDiagram.java new file mode 100644 index 000000000..1002bc4ee --- /dev/null +++ b/src/net/sourceforge/plantuml/wire/WireDiagram.java @@ -0,0 +1,163 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.wire; + +import java.awt.geom.Dimension2D; +import java.awt.geom.Rectangle2D; +import java.io.IOException; +import java.io.OutputStream; + +import net.sourceforge.plantuml.AnnotatedWorker; +import net.sourceforge.plantuml.FileFormatOption; +import net.sourceforge.plantuml.ISkinParam; +import net.sourceforge.plantuml.Scale; +import net.sourceforge.plantuml.UmlDiagram; +import net.sourceforge.plantuml.UmlDiagramType; +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.command.Position; +import net.sourceforge.plantuml.core.DiagramDescription; +import net.sourceforge.plantuml.core.ImageData; +import net.sourceforge.plantuml.graphic.HtmlColor; +import net.sourceforge.plantuml.graphic.InnerStrategy; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.graphic.TextBlock; +import net.sourceforge.plantuml.svek.TextBlockBackcolored; +import net.sourceforge.plantuml.ugraphic.ImageBuilder; +import net.sourceforge.plantuml.ugraphic.MinMax; +import net.sourceforge.plantuml.ugraphic.UGraphic; + +public class WireDiagram extends UmlDiagram { + + private final Block root = new Block(getSkinParam()); + private Block current = root; + private Block last; + + public DiagramDescription getDescription() { + return new DiagramDescription("Wire Diagram"); + } + + @Override + public UmlDiagramType getUmlDiagramType() { + return UmlDiagramType.WIRE; + } + + @Override + protected ImageData exportDiagramInternal(OutputStream os, int index, FileFormatOption fileFormatOption) + throws IOException { + final Scale scale = getScale(); + + final double dpiFactor = scale == null ? getScaleCoef(fileFormatOption) : scale.getScale(100, 100); + final ISkinParam skinParam = getSkinParam(); + final ImageBuilder imageBuilder = new ImageBuilder(skinParam.getColorMapper(), dpiFactor, + skinParam.getBackgroundColor(), fileFormatOption.isWithMetadata() ? getMetadata() : null, "", 10, 10, + null, skinParam.handwritten()); + TextBlock result = getTextBlock(); + + result = new AnnotatedWorker(this, skinParam, fileFormatOption.getDefaultStringBounder()).addAdd(result); + imageBuilder.setUDrawable(result); + + return imageBuilder.writeImageTOBEMOVED(fileFormatOption, seed(), os); + } + + private TextBlockBackcolored getTextBlock() { + return new TextBlockBackcolored() { + + public void drawU(UGraphic ug) { + drawMe(ug); + } + + public Rectangle2D getInnerPosition(String member, StringBounder stringBounder, InnerStrategy strategy) { + return null; + } + + public Dimension2D calculateDimension(StringBounder stringBounder) { + return getDrawingElement().calculateDimension(stringBounder); + + } + + public MinMax getMinMax(StringBounder stringBounder) { + throw new UnsupportedOperationException(); + } + + public HtmlColor getBackcolor() { + return null; + } + }; + } + + private void drawMe(UGraphic ug) { + getDrawingElement().drawU(ug); + + } + + private TextBlock getDrawingElement() { + return current; + } + + public CommandExecutionResult addComponent(String name) { + return addComponent(name, 100, 100); + } + + public CommandExecutionResult addComponent(String name, int width, int height) { + this.last = current.addNewBlock(name, width, height); + return CommandExecutionResult.ok(); + } + + public CommandExecutionResult vspace(int vspace) { + current.vspace(vspace); + return CommandExecutionResult.ok(); + } + + public CommandExecutionResult newColumn() { + current.newColumn(); + return CommandExecutionResult.ok(); + } + + public CommandExecutionResult addStartContainer(String name) { + current = current.createContainer(name); + return CommandExecutionResult.ok(); + } + + public CommandExecutionResult componentEnd() { + current = current.componentEnd(); + return CommandExecutionResult.ok(); + } + + public void addPin(Position position, String pin) { + last.addPin(position, pin); + } + +} diff --git a/src/net/sourceforge/plantuml/wire/WireDiagramFactory.java b/src/net/sourceforge/plantuml/wire/WireDiagramFactory.java new file mode 100644 index 000000000..e15d2b5c4 --- /dev/null +++ b/src/net/sourceforge/plantuml/wire/WireDiagramFactory.java @@ -0,0 +1,72 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.wire; + +import java.util.ArrayList; +import java.util.List; + +import net.sourceforge.plantuml.command.Command; +import net.sourceforge.plantuml.command.UmlDiagramFactory; +import net.sourceforge.plantuml.core.DiagramType; + +public class WireDiagramFactory extends UmlDiagramFactory { + + public WireDiagramFactory() { + super(DiagramType.WIRE); + } + + @Override + protected List createCommands() { + + final List cmds = new ArrayList(); + addCommonCommands1(cmds); + cmds.add(new CommandComponent()); + cmds.add(new CommandContainer()); + cmds.add(new CommandContainerEnd()); + cmds.add(new CommandPin()); + cmds.add(new CommandPinSpace()); + cmds.add(new CommandVspace()); + cmds.add(new CommandNewColumn()); + + return cmds; + } + + @Override + public WireDiagram createEmptyDiagram() { + return new WireDiagram(); + } + +} diff --git a/stdlib/cloudinsight-abx.repx b/stdlib/cloudinsight-abx.repx index 6d6d7832fa174b32beb00e4eb7388ba3c36d6882..b72613854113994e9a0a765e11b6b59f9993b62f 100644 GIT binary patch literal 803 zcmV+;1Kj)@L=ylk3TziQNZTnVZ*ZGghk>}&_T8tZ$F`n;2aq0UudsN4U$U&&%9ka7 zOKvVe!4lwr=E)&MfxNSTHG+y{t73ZK>0LH^Dp(Oo+{u-}tqd+|XEM3&0NvzCY-vA^ z(uComRwA)z6t={9-*y(ALByEJ;pW%>1$^A=`+D>6*A?ITW~S!~N1dsJzYRzvq#52Y z->a8O|7$jR@jf`n-yYnhx^3$QKNB8U4mPkS`;X%vZ+`yXUi3+td4GWa_pX7% z@9={;EevLhM}4IIy4Gz7mPTsStUc1*Gsa{)T`N z*qKs!ne!3cLGyqa2gcbQ@=HIxzpqpVjsOhDPd8{~>tvwuHWCTo7u`@}**38zaGG&o ztbTC5%1OB}dV>mx;Mm@0@G3R#&;5*p!=#_z43DF}lF4u2qdPepE;NebJ+(?#f3>{t z#3^$K5#z!$33xEd`CHMrz0K8-lc1wJlF;!T3ki|8UV0%I4b(iZ|LiiA(S}ydbCF)5 z4?CW0=H-vqymN6}(sVQXpg7`t_yU=Ejb-l{R2Zx>@JogM1$GOl<9V0s5`IxUWxXQm z*O|9*y08aGnB{TUH7UP=%gFpj4FN0VndNoR-^k6C$|d{s#vgB7^7Lj}EGMHk!col z%S`d|)LRMus(4%UcbHDsNh_fu5UVma!~PJgvLmh1s3akRC9w?O}(%&rb&{dfy` z^x|A}<>n?2&xhX7_A8aQ-(>8562(#O2k;lmdtbS)L+*<3-(ca0yS6UGhS1$6LxAzc zy{}SyS2GUY`g+Gr@)x^}eADuFNDgZVQOI24rH5%bS2oT2UVjYms)i#zorWl$bGw(% hZyw{-)iJcAhUv6=Uq{W+U0MBOZh9s$j-u2BF0 literal 802 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�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 w5&1LK;or!3?Wz+fCk=@^B%yY2O;?nl&M<-U%Q^