From fae68530e3c676e0a6e4ad575f90311b843e5b25 Mon Sep 17 00:00:00 2001 From: PlantUML Date: Tue, 19 Nov 2024 13:44:53 +0000 Subject: [PATCH] fix: hiding/showing a specific stereotype https://github.com/plantuml/plantuml/issues/1984 --- src/net/atmp/CucaDiagram.java | 27 ++-- .../command/CommandHideShowByGender.java | 129 +++++++++--------- .../svek/image/EntityImageClassHeader.java | 2 +- .../svek/image/EntityImageDescription.java | 18 +-- .../svek/image/EntityImageUseCase.java | 30 ++-- 5 files changed, 99 insertions(+), 107 deletions(-) diff --git a/src/net/atmp/CucaDiagram.java b/src/net/atmp/CucaDiagram.java index 272b3042815..57d427b8c78 100644 --- a/src/net/atmp/CucaDiagram.java +++ b/src/net/atmp/CucaDiagram.java @@ -575,33 +575,24 @@ public List getVisibleStereotypeLabels(Entity entity) { if (stereotype == null) return null; - // collect hide or show statements on stereotypes - final List commands = new ArrayList<>(); - for (EntityHideOrShow hideOrShowEntry : hideOrShows) - if (hideOrShowEntry.portion == EntityPortion.STEREOTYPE) - commands.add(hideOrShowEntry); - final List visibleStereotypeLabels = new ArrayList<>(); for (String stereoTypeLabel : entity.getStereotype().getLabels(Guillemet.DOUBLE_COMPARATOR)) - if (!isHiddenStereotypeLabel(stereoTypeLabel, commands)) + if (isStereotypeLabelShown(stereoTypeLabel)) visibleStereotypeLabels.add(stereoTypeLabel); return visibleStereotypeLabels; } - private boolean isHiddenStereotypeLabel(String stereoTypeLabel, List commands) { - for (EntityHideOrShow cmd : commands) { - // gender is here the stereotype name given in the hide or show command + private boolean isStereotypeLabelShown(String stereoTypeLabel) { + boolean result = true; + for (EntityHideOrShow cmd : hideOrShows) { + if (cmd.portion != EntityPortion.STEREOTYPE) + continue; final String gender = cmd.gender.getGender(); - if (gender != null && gender.equals(stereoTypeLabel)) { - return !cmd.show; - } else if (gender == null) { - // we have a hide or show command without a stereotype name => hide or show all - // stereotypes - return !cmd.show; - } + if (gender == null || gender.equals(stereoTypeLabel)) + result = cmd.show; } - return false; + return result; } public final void hideOrShow(EntityGender gender, EntityPortion portions, boolean show) { diff --git a/src/net/sourceforge/plantuml/classdiagram/command/CommandHideShowByGender.java b/src/net/sourceforge/plantuml/classdiagram/command/CommandHideShowByGender.java index d623002fb25..dc30a6f7f19 100644 --- a/src/net/sourceforge/plantuml/classdiagram/command/CommandHideShowByGender.java +++ b/src/net/sourceforge/plantuml/classdiagram/command/CommandHideShowByGender.java @@ -80,30 +80,31 @@ static IRegex getRegexConcat() { } private final EntityGender emptyByGender(EntityPortion portion) { - if (portion == EntityPortion.METHOD) { + if (portion == EntityPortion.METHOD) return EntityGenderUtils.emptyMethods(); - } - if (portion == EntityPortion.FIELD) { + + if (portion == EntityPortion.FIELD) return EntityGenderUtils.emptyFields(); - } - if (portion == EntityPortion.MEMBER) { + + if (portion == EntityPortion.MEMBER) throw new IllegalArgumentException(); - // return EntityGenderUtils.emptyMembers(); - } + // return EntityGenderUtils.emptyMembers(); + return EntityGenderUtils.all(); } @Override - protected CommandExecutionResult executeArg(UmlDiagram diagram, LineLocation location, RegexResult arg, ParserPass currentPass) { - if (diagram instanceof AbstractClassOrObjectDiagram) { + protected CommandExecutionResult executeArg(UmlDiagram diagram, LineLocation location, RegexResult arg, + ParserPass currentPass) { + if (diagram instanceof AbstractClassOrObjectDiagram) return executeClassDiagram((AbstractClassOrObjectDiagram) diagram, arg); - } - if (diagram instanceof DescriptionDiagram) { + + if (diagram instanceof DescriptionDiagram) return executeDescriptionDiagram((DescriptionDiagram) diagram, arg); - } - if (diagram instanceof SequenceDiagram) { + + if (diagram instanceof SequenceDiagram) return executeSequenceDiagram((SequenceDiagram) diagram, arg); - } + // Just ignored return CommandExecutionResult.ok(); } @@ -118,33 +119,33 @@ private CommandExecutionResult executeDescriptionDiagram(DescriptionDiagram diag final EntityPortion portion = getEntityPortion(arg.get("PORTION", 0)); final EntityGender gender; final String arg1 = arg.get("GENDER", 0); - if (arg1 == null) { + if (arg1 == null) gender = EntityGenderUtils.all(); - } else if (arg1.equalsIgnoreCase("class")) { + else if (arg1.equalsIgnoreCase("class")) gender = EntityGenderUtils.byEntityType(LeafType.CLASS); - } else if (arg1.equalsIgnoreCase("object")) { + else if (arg1.equalsIgnoreCase("object")) gender = EntityGenderUtils.byEntityType(LeafType.OBJECT); - } else if (arg1.equalsIgnoreCase("interface")) { + else if (arg1.equalsIgnoreCase("interface")) gender = EntityGenderUtils.byEntityType(LeafType.INTERFACE); - } else if (arg1.equalsIgnoreCase("enum")) { + else if (arg1.equalsIgnoreCase("enum")) gender = EntityGenderUtils.byEntityType(LeafType.ENUM); - } else if (arg1.equalsIgnoreCase("abstract")) { + else if (arg1.equalsIgnoreCase("abstract")) gender = EntityGenderUtils.byEntityType(LeafType.ABSTRACT_CLASS); - } else if (arg1.equalsIgnoreCase("annotation")) { + else if (arg1.equalsIgnoreCase("annotation")) gender = EntityGenderUtils.byEntityType(LeafType.ANNOTATION); - } else if (arg1.equalsIgnoreCase("protocol")) { + else if (arg1.equalsIgnoreCase("protocol")) gender = EntityGenderUtils.byEntityType(LeafType.PROTOCOL); - } else if (arg1.equalsIgnoreCase("struct")) { + else if (arg1.equalsIgnoreCase("struct")) gender = EntityGenderUtils.byEntityType(LeafType.STRUCT); - } else if (arg1.equalsIgnoreCase("exception")) { + else if (arg1.equalsIgnoreCase("exception")) gender = EntityGenderUtils.byEntityType(LeafType.EXCEPTION); - } else if (arg1.equalsIgnoreCase("metaclass")) { + else if (arg1.equalsIgnoreCase("metaclass")) gender = EntityGenderUtils.byEntityType(LeafType.METACLASS); - } else if (arg1.equalsIgnoreCase("stereotype")) { + else if (arg1.equalsIgnoreCase("stereotype")) gender = EntityGenderUtils.byEntityType(LeafType.STEREOTYPE); - } else if (arg1.startsWith("<<")) { + else if (arg1.startsWith("<<")) gender = EntityGenderUtils.byStereotype(arg1); - } else { + else { final Quark quark = diagram.quarkInContext(true, diagram.cleanId(arg1)); if (quark.getData() == null) return CommandExecutionResult.error("No such element " + quark.getName()); @@ -162,65 +163,65 @@ private CommandExecutionResult executeClassDiagram(AbstractClassOrObjectDiagram EntityGender gender = null; String arg1 = arg.get("GENDER", 0); - if (arg1 == null) { + if (arg1 == null) gender = EntityGenderUtils.all(); - } else if (arg1.equalsIgnoreCase("class")) { + else if (arg1.equalsIgnoreCase("class")) gender = EntityGenderUtils.byEntityType(LeafType.CLASS); - } else if (arg1.equalsIgnoreCase("object")) { + else if (arg1.equalsIgnoreCase("object")) gender = EntityGenderUtils.byEntityType(LeafType.OBJECT); - } else if (arg1.equalsIgnoreCase("interface")) { + else if (arg1.equalsIgnoreCase("interface")) gender = EntityGenderUtils.byEntityType(LeafType.INTERFACE); - } else if (arg1.equalsIgnoreCase("enum")) { + else if (arg1.equalsIgnoreCase("enum")) gender = EntityGenderUtils.byEntityType(LeafType.ENUM); - } else if (arg1.equalsIgnoreCase("abstract")) { + else if (arg1.equalsIgnoreCase("abstract")) gender = EntityGenderUtils.byEntityType(LeafType.ABSTRACT_CLASS); - } else if (arg1.equalsIgnoreCase("annotation")) { + else if (arg1.equalsIgnoreCase("annotation")) gender = EntityGenderUtils.byEntityType(LeafType.ANNOTATION); - } else if (arg1.equalsIgnoreCase("protocol")) { + else if (arg1.equalsIgnoreCase("protocol")) gender = EntityGenderUtils.byEntityType(LeafType.PROTOCOL); - } else if (arg1.equalsIgnoreCase("struct")) { + else if (arg1.equalsIgnoreCase("struct")) gender = EntityGenderUtils.byEntityType(LeafType.STRUCT); - } else if (arg1.equalsIgnoreCase("exception")) { + else if (arg1.equalsIgnoreCase("exception")) gender = EntityGenderUtils.byEntityType(LeafType.EXCEPTION); - } else if (arg1.equalsIgnoreCase("metaclass")) { + else if (arg1.equalsIgnoreCase("metaclass")) gender = EntityGenderUtils.byEntityType(LeafType.METACLASS); - } else if (arg1.equalsIgnoreCase("stereotype")) { + else if (arg1.equalsIgnoreCase("stereotype")) gender = EntityGenderUtils.byEntityType(LeafType.STEREOTYPE); - } else if (arg1.startsWith("<<")) { + else if (arg1.startsWith("<<")) gender = EntityGenderUtils.byStereotype(arg1); - } else { + else { arg1 = StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(arg1); final Quark quark = diagram.quarkInContext(true, diagram.cleanId(arg1)); - if (quark == null) { + if (quark == null) // Not sure it could really happens... to be checked return CommandExecutionResult.error("No such quark " + arg1); - } - if (portion == EntityPortion.METHOD) { - gender = EntityGenderUtils.byClassName(arg1); - } else { + + if (portion == EntityPortion.METHOD) + gender = EntityGenderUtils.byClassName(arg1); + else { Entity entity = quark.getData(); if (entity == null) return CommandExecutionResult.error("No such element " + quark.getName()); gender = EntityGenderUtils.byEntityAlone(entity); } } - final boolean empty = arg.get("EMPTY", 0) != null; - final boolean emptyMembers = empty && portion == EntityPortion.MEMBER; - if (empty && !emptyMembers) - gender = EntityGenderUtils.and(gender, emptyByGender(portion)); - - if (!diagram.getCurrentGroup().isRoot()) - gender = EntityGenderUtils.and(gender, EntityGenderUtils.byPackage(diagram.getCurrentGroup())); - - if (emptyMembers) { - diagram.hideOrShow(EntityGenderUtils.and(gender, emptyByGender(EntityPortion.FIELD)), - EntityPortion.FIELD, arg.get("COMMAND", 0).equalsIgnoreCase("show")); - diagram.hideOrShow(EntityGenderUtils.and(gender, emptyByGender(EntityPortion.METHOD)), - EntityPortion.METHOD, arg.get("COMMAND", 0).equalsIgnoreCase("show")); - } else { - diagram.hideOrShow(gender, portion, arg.get("COMMAND", 0).equalsIgnoreCase("show")); - } - return CommandExecutionResult.ok(); + final boolean empty = arg.get("EMPTY", 0) != null; + final boolean emptyMembers = empty && portion == EntityPortion.MEMBER; + if (empty && !emptyMembers) + gender = EntityGenderUtils.and(gender, emptyByGender(portion)); + + if (!diagram.getCurrentGroup().isRoot()) + gender = EntityGenderUtils.and(gender, EntityGenderUtils.byPackage(diagram.getCurrentGroup())); + + if (emptyMembers) { + diagram.hideOrShow(EntityGenderUtils.and(gender, emptyByGender(EntityPortion.FIELD)), EntityPortion.FIELD, + arg.get("COMMAND", 0).equalsIgnoreCase("show")); + diagram.hideOrShow(EntityGenderUtils.and(gender, emptyByGender(EntityPortion.METHOD)), EntityPortion.METHOD, + arg.get("COMMAND", 0).equalsIgnoreCase("show")); + } else + diagram.hideOrShow(gender, portion, arg.get("COMMAND", 0).equalsIgnoreCase("show")); + + return CommandExecutionResult.ok(); } private EntityPortion getEntityPortion(String s) { diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageClassHeader.java b/src/net/sourceforge/plantuml/svek/image/EntityImageClassHeader.java index d0c335d5266..a0d65eca242 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageClassHeader.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageClassHeader.java @@ -114,7 +114,7 @@ public EntityImageClassHeader(Entity entity, PortionShower portionShower) { } final TextBlock stereo; - List stereotypeLabels = portionShower.getVisibleStereotypeLabels(entity); + final List stereotypeLabels = portionShower.getVisibleStereotypeLabels(entity); if (stereotype == null || stereotype.getLabel(Guillemet.DOUBLE_COMPARATOR) == null || stereotypeLabels.isEmpty()) stereo = null; diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageDescription.java b/src/net/sourceforge/plantuml/svek/image/EntityImageDescription.java index 0f6c43cb20c..0fdee32ccf0 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageDescription.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageDescription.java @@ -39,12 +39,12 @@ import java.util.Collection; import java.util.EnumMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import net.sourceforge.plantuml.abel.Entity; -import net.sourceforge.plantuml.abel.EntityPortion; import net.sourceforge.plantuml.abel.Link; import net.sourceforge.plantuml.cucadiagram.BodyFactory; import net.sourceforge.plantuml.cucadiagram.PortionShower; @@ -181,20 +181,20 @@ else if (entity.getDisplay().equalsLike(codeDisplay)) else desc = BodyFactory.create3(entity.getDisplay(), getSkinParam(), defaultAlign, fc, style.wrapWidth(), style); - stereo = TextBlockUtils.empty(0, 0); - + final List stereotypeLabels = portionShower.getVisibleStereotypeLabels(entity); if (stereotype != null && stereotype.getSprite(getSkinParam()) != null) stereo = stereotype.getSprite(getSkinParam()); - else if (stereotype != null && stereotype.getLabel(Guillemet.DOUBLE_COMPARATOR) != null - && portionShower.showPortion(EntityPortion.STEREOTYPE, entity)) - stereo = Display.getWithNewlines(stereotype.getLabel(getSkinParam().guillemet())).create(fcStereo, - HorizontalAlignment.CENTER, getSkinParam()); + else if (stereotype == null || stereotype.getLabel(Guillemet.DOUBLE_COMPARATOR) == null + || stereotypeLabels.isEmpty()) + stereo = TextBlockUtils.empty(0, 0); + else + stereo = TextBlockUtils.withMargin( + Display.create(stereotypeLabels).create(fcStereo, HorizontalAlignment.CENTER, getSkinParam()), 1, + 0); name = BodyFactory.create2(getSkinParam().getDefaultTextAlignment(HorizontalAlignment.CENTER), codeDisplay, getSkinParam(), stereotype, entity, styleTitle); - // final HorizontalAlignment stereotypeAlignment = - // getSkinParam().getStereotypeAlignment(); final HorizontalAlignment stereotypeAlignment = styleStereo.getHorizontalAlignment(); if (hideText) diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageUseCase.java b/src/net/sourceforge/plantuml/svek/image/EntityImageUseCase.java index e4e381f1b06..d2ba9e4f0b3 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageUseCase.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageUseCase.java @@ -36,10 +36,10 @@ package net.sourceforge.plantuml.svek.image; import java.util.EnumMap; +import java.util.List; import java.util.Map; import net.sourceforge.plantuml.abel.Entity; -import net.sourceforge.plantuml.abel.EntityPortion; import net.sourceforge.plantuml.abel.LeafType; import net.sourceforge.plantuml.cucadiagram.BodyFactory; import net.sourceforge.plantuml.cucadiagram.PortionShower; @@ -66,7 +66,6 @@ import net.sourceforge.plantuml.klimt.shape.UHorizontalLine; import net.sourceforge.plantuml.klimt.shape.ULine; import net.sourceforge.plantuml.stereo.Stereotype; -import net.sourceforge.plantuml.style.ISkinParam; import net.sourceforge.plantuml.style.PName; import net.sourceforge.plantuml.style.SName; import net.sourceforge.plantuml.style.Style; @@ -93,20 +92,21 @@ public EntityImageUseCase(Entity entity, PortionShower portionShower) { final TextBlock tmp = BodyFactory.create2(getSkinParam().getDefaultTextAlignment(align), entity.getDisplay(), getSkinParam(), stereotype, entity, getStyle()); - if (stereotype == null || stereotype.getLabel(Guillemet.DOUBLE_COMPARATOR) == null - || portionShower.showPortion(EntityPortion.STEREOTYPE, entity) == false) { - this.desc = tmp; - } else { - final TextBlock stereo; - if (stereotype.getSprite(getSkinParam()) != null) { - stereo = stereotype.getSprite(getSkinParam()); - } else { - stereo = Display.getWithNewlines(stereotype.getLabel(getSkinParam().guillemet())).create( - FontConfiguration.create(getSkinParam(), FontParam.USECASE_STEREOTYPE, stereotype), - HorizontalAlignment.CENTER, getSkinParam()); - } - this.desc = TextBlockUtils.mergeTB(stereo, tmp, HorizontalAlignment.CENTER); + final TextBlock stereo; + final List stereotypeLabels = portionShower.getVisibleStereotypeLabels(entity); + if (stereotype != null && stereotype.getSprite(getSkinParam()) != null) + stereo = stereotype.getSprite(getSkinParam()); + else if (stereotype == null || stereotype.getLabel(Guillemet.DOUBLE_COMPARATOR) == null + || stereotypeLabels.isEmpty()) + stereo = TextBlockUtils.EMPTY_TEXT_BLOCK; + else { + final FontConfiguration fcStereo = FontConfiguration.create(getSkinParam(), FontParam.USECASE_STEREOTYPE, + stereotype); + final Display display = Display.create(stereotypeLabels); + stereo = display.create(fcStereo, HorizontalAlignment.CENTER, getSkinParam()); } + this.desc = TextBlockUtils.mergeTB(stereo, tmp, HorizontalAlignment.CENTER); + this.url = entity.getUrl99(); }