This is an automated email from the ASF dual-hosted git repository. ahuber pushed a commit to branch 3913-grid.fixes in repository https://gitbox.apache.org/repos/asf/causeway.git
commit ba05dbadf3d341a78213c62115ed05b6ec102492 Author: Andi Huber <[email protected]> AuthorDate: Thu Oct 23 17:42:32 2025 +0200 CAUSEWAY-2297: shifting responsibilities --- .../apache/causeway/applib/layout/grid/Grid.java | 49 +--- .../causeway/applib/layout/grid/GridAbstract.java | 210 -------------- .../applib/layout/grid/bootstrap/BSClearFix.java | 3 +- .../layout/grid/bootstrap/BSClearFixHidden.java | 2 +- .../layout/grid/bootstrap/BSClearFixVisible.java | 2 +- .../applib/layout/grid/bootstrap/BSCol.java | 27 +- .../applib/layout/grid/bootstrap/BSElement.java | 24 +- .../layout/grid/bootstrap/BSElementAbstract.java | 21 +- .../applib/layout/grid/bootstrap/BSGrid.java | 313 +++++---------------- .../{BSClearFixHidden.java => BSGridDto.java} | 41 ++- .../applib/layout/grid/bootstrap/BSRow.java | 96 ++----- .../applib/layout/grid/bootstrap/BSRowContent.java | 51 +--- .../layout/grid/bootstrap/BSRowContentOwner.java | 2 +- .../applib/layout/grid/bootstrap/BSRowOwner.java | 2 +- .../applib/layout/grid/bootstrap/BSTab.java | 90 +----- .../applib/layout/grid/bootstrap/BSTabGroup.java | 19 +- .../layout/grid/bootstrap/BSTabGroupOwner.java | 2 +- .../applib/layout/grid/bootstrap/BSTabOwner.java | 2 +- .../applib/layout/grid/bootstrap/BSUtil.java | 57 ++++ .../applib/layout/grid/bootstrap/BSWalker.java | 182 ++++++++++++ .../bootstrap/{HasCssId.java => HasElementId.java} | 2 +- .../applib/layout/grid/bootstrap/WithinGrid.java | 30 -- .../core/metamodel/layout/LayoutFacetUtil.java | 2 +- .../services/grid/GridSystemServiceAbstract.java | 4 +- .../grid/bootstrap/CollapseIfOneTabProcessor.java | 6 +- .../grid/bootstrap/EmptyTabRemovalProcessor.java | 15 +- .../grid/bootstrap/GridConverterFromDto.java | 78 +++++ .../grid/bootstrap/GridConverterToDto.java | 29 +- .../bootstrap/GridMarshallerServiceBootstrap.java | 44 ++- .../bootstrap/{_GridModel.java => GridModel.java} | 38 +-- .../grid/bootstrap/GridSystemServiceBootstrap.java | 14 +- .../sitemap/SitemapServiceDefault.java | 4 +- .../help/topics/welcome/WelcomeHelpPage.java | 2 +- .../resources/DomainObjectResourceServerside.java | 2 +- .../serviceactions/MenuActionPanel.java | 4 +- .../wicket/ui/components/layout/bs/col/Col.java | 5 +- .../components/layout/bs/tabs/TabGroupPanel.java | 3 +- 37 files changed, 592 insertions(+), 885 deletions(-) diff --git a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/Grid.java b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/Grid.java index 30901bafcda..590b5248598 100644 --- a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/Grid.java +++ b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/Grid.java @@ -31,24 +31,17 @@ /** * All top-level page layout classes should implement this interface. * - * <p> - * It is used by the {@link LayoutService} as a common based type for any layouts read in from XML. - * </p> + * <p>It is used by the {@link LayoutService} as a common based type for any layouts read in from XML. * * @since 1.x {@index} */ +@Programmatic public interface Grid { - @Programmatic Class<?> getDomainClass(); - - @Programmatic void setDomainClass(final Class<?> domainClass); - @Programmatic String getTnsAndSchemaLocation(); - - @Programmatic void setTnsAndSchemaLocation(final String tnsAndSchemaLocation); /** @@ -59,50 +52,22 @@ public interface Grid { * Governs meta-model facet precedence, that is, * facets from annotations should overrule those from fallback XML grids. */ - @Programmatic default boolean isFallback() { return false; } - @Programmatic boolean isNormalized(); - - @Programmatic void setNormalized(final boolean normalized); - @Programmatic LinkedHashMap<String, PropertyLayoutData> getAllPropertiesById(); - - @Programmatic LinkedHashMap<String, CollectionLayoutData> getAllCollectionsById(); - - @Programmatic LinkedHashMap<String, ActionLayoutData> getAllActionsById(); interface Visitor { - void visit(final DomainObjectLayoutData domainObjectLayoutData); - - void visit(final ActionLayoutData actionLayoutData); - - void visit(final PropertyLayoutData propertyLayoutData); - - void visit(final CollectionLayoutData collectionLayoutData); - - void visit(final FieldSet fieldSet); + default void visit(final DomainObjectLayoutData domainObjectLayoutData) {} + default void visit(final ActionLayoutData actionLayoutData) {} + default void visit(final PropertyLayoutData propertyLayoutData) {} + default void visit(final CollectionLayoutData collectionLayoutData) {} + default void visit(final FieldSet fieldSet) {} } - class VisitorAdapter implements Visitor { - @Override public void visit(final DomainObjectLayoutData domainObjectLayoutData) { - } - @Override public void visit(final ActionLayoutData actionLayoutData) { - } - @Override public void visit(final PropertyLayoutData propertyLayoutData) { - } - @Override public void visit(final CollectionLayoutData collectionLayoutData) { - } - @Override public void visit(final FieldSet fieldSet) { - } - } - - @Programmatic void visit(final Grid.Visitor visitor); - } diff --git a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/GridAbstract.java b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/GridAbstract.java deleted file mode 100644 index 4cf7468008d..00000000000 --- a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/GridAbstract.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.causeway.applib.layout.grid; - -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; - -import jakarta.xml.bind.annotation.XmlTransient; - -import org.apache.causeway.applib.annotation.Programmatic; -import org.apache.causeway.applib.layout.component.ActionLayoutData; -import org.apache.causeway.applib.layout.component.ActionLayoutDataOwner; -import org.apache.causeway.applib.layout.component.CollectionLayoutData; -import org.apache.causeway.applib.layout.component.CollectionLayoutDataOwner; -import org.apache.causeway.applib.layout.component.FieldSet; -import org.apache.causeway.applib.layout.component.FieldSetOwner; -import org.apache.causeway.applib.layout.component.PropertyLayoutData; -import org.apache.causeway.applib.layout.grid.bootstrap.BSGrid; -import org.apache.causeway.applib.services.layout.LayoutService; - -/** - * All top-level page layout classes should implement this interface. - * - * <p> - * It is used by the {@link LayoutService} as a common based type for any layouts read in from XML. - * </p> - * - * @since 1.x {@index} - */ -@XmlTransient // ignore this class -public abstract class GridAbstract implements Grid { - - private Class<?> domainClass; - - @Override - @Programmatic - @XmlTransient - public Class<?> getDomainClass() { - return domainClass; - } - - @Override - @Programmatic - public void setDomainClass(final Class<?> domainClass) { - this.domainClass = domainClass; - } - - private String tnsAndSchemaLocation; - @Override - @Programmatic - @XmlTransient - public String getTnsAndSchemaLocation() { - return tnsAndSchemaLocation; - } - - @Override - @Programmatic - public void setTnsAndSchemaLocation(final String tnsAndSchemaLocation) { - this.tnsAndSchemaLocation = tnsAndSchemaLocation; - } - - private boolean fallback; - @Override - @Programmatic - @XmlTransient - public boolean isFallback() { - return fallback; - } - @Programmatic - public void setFallback(final boolean fallback) { - this.fallback = fallback; - } - - private boolean normalized; - @Override - @Programmatic - @XmlTransient - public boolean isNormalized() { - return normalized; - } - @Override - @Programmatic - public void setNormalized(final boolean normalized) { - this.normalized = normalized; - } - - /** - * Convenience for subclasses. - */ - protected void traverseActions( - final ActionLayoutDataOwner actionLayoutDataOwner, - final GridAbstract.Visitor visitor) { - - final List<ActionLayoutData> actionLayoutDatas = actionLayoutDataOwner.getActions(); - if(actionLayoutDatas == null) { - return; - } - for (final ActionLayoutData actionLayoutData : new ArrayList<>(actionLayoutDatas)) { - actionLayoutData.setOwner(actionLayoutDataOwner); - visitor.visit(actionLayoutData); - } - } - - /** - * Convenience for subclasses. - */ - protected void traverseFieldSets(final FieldSetOwner fieldSetOwner, final GridAbstract.Visitor visitor) { - final List<FieldSet> fieldSets = fieldSetOwner.getFieldSets(); - for (FieldSet fieldSet : new ArrayList<>(fieldSets)) { - fieldSet.setOwner(fieldSetOwner); - visitor.visit(fieldSet); - traverseActions(fieldSet, visitor); - final List<PropertyLayoutData> properties = fieldSet.getProperties(); - for (final PropertyLayoutData property : new ArrayList<>(properties)) { - property.setOwner(fieldSet); - visitor.visit(property); - traverseActions(property, visitor); - } - } - } - - /** - * Convenience for subclasses. - */ - protected void traverseCollections( - final CollectionLayoutDataOwner owner, final GridAbstract.Visitor visitor) { - final List<CollectionLayoutData> collections = owner.getCollections(); - for (CollectionLayoutData collection : new ArrayList<>(collections)) { - collection.setOwner(owner); - visitor.visit(collection); - traverseActions(collection, visitor); - } - } - - @Override - @Programmatic - @XmlTransient - public LinkedHashMap<String, PropertyLayoutData> getAllPropertiesById() { - final LinkedHashMap<String, PropertyLayoutData> propertiesById = new LinkedHashMap<>(); - visit(new BSGrid.VisitorAdapter() { - @Override - public void visit(final PropertyLayoutData propertyLayoutData) { - propertiesById.put(propertyLayoutData.getId(), propertyLayoutData); - } - }); - return propertiesById; - } - - @Override - @Programmatic - @XmlTransient - public LinkedHashMap<String, CollectionLayoutData> getAllCollectionsById() { - final LinkedHashMap<String, CollectionLayoutData> collectionsById = new LinkedHashMap<>(); - - visit(new BSGrid.VisitorAdapter() { - @Override - public void visit(final CollectionLayoutData collectionLayoutData) { - collectionsById.put(collectionLayoutData.getId(), collectionLayoutData); - } - }); - return collectionsById; - } - - @Override - @Programmatic - @XmlTransient - public LinkedHashMap<String, ActionLayoutData> getAllActionsById() { - final LinkedHashMap<String, ActionLayoutData> actionsById = new LinkedHashMap<>(); - - visit(new BSGrid.VisitorAdapter() { - @Override - public void visit(final ActionLayoutData actionLayoutData) { - actionsById.put(actionLayoutData.getId(), actionLayoutData); - } - }); - return actionsById; - } - - @Programmatic - @XmlTransient - public LinkedHashMap<String, FieldSet> getAllFieldSetsByName() { - final LinkedHashMap<String, FieldSet> fieldSetsByName = new LinkedHashMap<>(); - - visit(new BSGrid.VisitorAdapter() { - @Override - public void visit(final FieldSet fieldSet) { - fieldSetsByName.put(fieldSet.getName(), fieldSet); - } - }); - return fieldSetsByName; - } - -} diff --git a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSClearFix.java b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSClearFix.java index 13355954d80..172aeae3315 100644 --- a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSClearFix.java +++ b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSClearFix.java @@ -21,7 +21,8 @@ /** * @since 1.x {@index} */ -public abstract class BSClearFix extends BSRowContent { +public sealed abstract class BSClearFix extends BSRowContent +permits BSClearFixHidden, BSClearFixVisible { private static final long serialVersionUID = 1L; diff --git a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSClearFixHidden.java b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSClearFixHidden.java index 08458d72d5c..d62fc449caf 100644 --- a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSClearFixHidden.java +++ b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSClearFixHidden.java @@ -37,7 +37,7 @@ @XmlType( name = "clearFixHidden" ) -public class BSClearFixHidden extends BSClearFix { +public final class BSClearFixHidden extends BSClearFix { private static final long serialVersionUID = 1L; diff --git a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSClearFixVisible.java b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSClearFixVisible.java index 2a6ed660694..1e37d7cfaa3 100644 --- a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSClearFixVisible.java +++ b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSClearFixVisible.java @@ -38,7 +38,7 @@ @XmlType( name = "clearFixVisible" ) -public class BSClearFixVisible extends BSClearFix { +public final class BSClearFixVisible extends BSClearFix { private static final long serialVersionUID = 1L; diff --git a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSCol.java b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSCol.java index c8ac69fec98..4c16460e887 100644 --- a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSCol.java +++ b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSCol.java @@ -41,24 +41,19 @@ /** * A column within a row which, depending on its {@link #getSpan()}, could be as narrow as 1/12th of the page's width, all the way up to spanning the entire page. * - * <p> - * Pretty much other content can be contained within a column, though most commonly it will be {@link FieldSet fieldset}s - * (a group of properties) or {@link CollectionLayoutData collection}s. However, columns can also be used to - * contain further {@link BSRow row}s (creating a nested grid of rows/cols/rows/cols) and {@link BSTabGroup tabgroup}s. - * </p> + * <p>Pretty much other content can be contained within a column, though most commonly it will be {@link FieldSet fieldset}s + * (a group of properties) or {@link CollectionLayoutData collection}s. However, columns can also be used to + * contain further {@link BSRow row}s (creating a nested grid of rows/cols/rows/cols) and {@link BSTabGroup tabgroup}s. * - * <p> - * It is rendered as a (eg) <div class="col-md-4 ..."> - * </p> + * <p>It is rendered as a (eg) <div class="col-md-4 ..."> * * @since 1.x {@index} */ @XmlRootElement( - name = "col" - ) + name = "col") @XmlType( - name = "col" - , propOrder = { + name = "col", + propOrder = { "sizeSpans", "domainObject", "actions", @@ -66,11 +61,9 @@ "tabGroups", "fieldSets", "collections", - "metadataError" - } - ) -public class BSCol extends BSRowContent -implements ActionLayoutDataOwner, BSTabGroupOwner, BSRowOwner, FieldSetOwner, HasCssId, + "metadataError"}) +public final class BSCol extends BSRowContent +implements ActionLayoutDataOwner, BSTabGroupOwner, BSRowOwner, FieldSetOwner, HasElementId, CollectionLayoutDataOwner, DomainObjectLayoutDataOwner { private static final long serialVersionUID = 1L; diff --git a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSElement.java b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSElement.java index 382dfa890f4..cf75b3ae304 100644 --- a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSElement.java +++ b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSElement.java @@ -20,10 +20,12 @@ import java.io.Serializable; +import org.apache.causeway.applib.layout.grid.Grid; + /** * @since 1.x {@index} */ -public interface BSElement extends WithinGrid, Serializable { +public interface BSElement extends Serializable { /** * Any additional CSS classes to render on the page element corresponding to this object, @@ -31,7 +33,25 @@ public interface BSElement extends WithinGrid, Serializable { * custom styling. */ String getCssClass(); - void setCssClass(final String cssClass); + public interface Visitor extends Grid.Visitor { + default void preVisit(final BSGrid bsGrid) {} + default void visit(final BSGrid bsGrid) {} + default void postVisit(final BSGrid bsGrid) {} + default void preVisit(final BSRow bsRow) {} + default void visit(final BSRow bsRow) {} + default void postVisit(final BSRow bsRow) {} + default void preVisit(final BSCol bsCol) {} + default void visit(final BSCol bsCol) {} + default void postVisit(final BSCol bsCol) {} + default void visit(final BSClearFix bsClearFix) {} + default void preVisit(final BSTabGroup bsTabGroup) {} + default void visit(final BSTabGroup bsTabGroup) {} + default void postVisit(final BSTabGroup bsTabGroup) {} + default void preVisit(final BSTab bsTab) {} + default void visit(final BSTab bsTab) {} + default void postVisit(final BSTab bsTab) {} + } + } diff --git a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSElementAbstract.java b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSElementAbstract.java index 66996801d5e..f5fe6833a27 100644 --- a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSElementAbstract.java +++ b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSElementAbstract.java @@ -20,31 +20,26 @@ import jakarta.xml.bind.annotation.XmlAttribute; +import lombok.Getter; +import lombok.Setter; + /** * Superclass for all layout classes, factoring out the common {@link #getCssClass()} attribute. * * @since 1.x {@index} */ -public abstract class BSElementAbstract implements BSElement { +public sealed abstract class BSElementAbstract implements BSElement +permits BSRow, BSRowContent, BSTab, BSTabGroup { private static final long serialVersionUID = 1L; - private String cssClass; - /** * Any additional CSS classes to render on the page element corresponding to this object, * eg as per the <a href="http://getbootstrap.com/css/#grid-less">Bootstrap mixins</a> or just for * custom styling. */ - @Override - @XmlAttribute(required = false) - public String getCssClass() { - return cssClass; - } - - @Override - public void setCssClass(final String cssClass) { - this.cssClass = cssClass; - } + @Getter(onMethod_ = {@XmlAttribute(required = false)}) + @Setter + private String cssClass; } diff --git a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSGrid.java b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSGrid.java index 144142be7a1..7246973dec1 100644 --- a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSGrid.java +++ b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSGrid.java @@ -22,274 +22,115 @@ import java.util.LinkedHashMap; import java.util.List; -import jakarta.xml.bind.annotation.XmlAttribute; -import jakarta.xml.bind.annotation.XmlElement; -import jakarta.xml.bind.annotation.XmlRootElement; -import jakarta.xml.bind.annotation.XmlTransient; -import jakarta.xml.bind.annotation.XmlType; - -import org.apache.causeway.applib.annotation.Programmatic; import org.apache.causeway.applib.layout.component.ActionLayoutData; import org.apache.causeway.applib.layout.component.CollectionLayoutData; -import org.apache.causeway.applib.layout.component.DomainObjectLayoutData; -import org.apache.causeway.applib.layout.component.FieldSet; import org.apache.causeway.applib.layout.component.PropertyLayoutData; import org.apache.causeway.applib.layout.grid.Grid; -import org.apache.causeway.applib.layout.grid.GridAbstract; import org.apache.causeway.applib.mixins.dto.Dto; +import lombok.Getter; +import lombok.Setter; + /** - * This is the top-level for rendering the domain object's properties, collections and actions. It simply consists - * of a number of rows. - * - * <p> - * The element is rendered as a <div class="..."> - * </p> + * This is the top-level for rendering the domain object's properties, collections and actions. + * It simply consists of a number of rows. * * @since 1.x {@index} */ -@XmlRootElement( - name = "grid" - ) -@XmlType( - name = "grid" - , propOrder = { - "rows", - "metadataErrors" - } - ) -public class BSGrid extends GridAbstract implements BSElement, Dto, BSRowOwner { +public final class BSGrid implements Grid, BSElement, Dto, BSRowOwner { private static final long serialVersionUID = 1L; - private String cssClass; - - @Override - @XmlAttribute(required = false) - public String getCssClass() { - return cssClass; - } - - @Override - public void setCssClass(final String cssClass) { - this.cssClass = cssClass; - } - - private List<BSRow> rows = new ArrayList<>(); - - // no wrapper - @Override - @XmlElement(name = "row", required = true) - public List<BSRow> getRows() { - return rows; - } - - public void setRows(final List<BSRow> rows) { - this.rows = rows; - } - - private List<String> metadataErrors = new ArrayList<>(); + @Getter @Setter private Class<?> domainClass; + @Getter @Setter private String tnsAndSchemaLocation; + @Getter @Setter private boolean fallback; + @Getter @Setter private boolean normalized; + @Getter @Setter private String cssClass; + @Getter private final List<BSRow> rows = new ArrayList<>(); /** * For diagnostics; populated by the framework if and only if a metadata error. */ - @XmlElement(name = "metadataError", required = false) - public List<String> getMetadataErrors() { - return metadataErrors; - } - - public void setMetadataErrors(final List<String> metadataErrors) { - this.metadataErrors = metadataErrors; - } - - @SuppressWarnings("unused") - private BSRowOwner owner; - - public interface Visitor extends Grid.Visitor { - void preVisit(final BSGrid bsGrid); - void visit(final BSGrid bsGrid); - void postVisit(final BSGrid bsGrid); - void preVisit(final BSRow bsRow); - void visit(final BSRow bsRow); - void postVisit(final BSRow bsRow); - void preVisit(final BSCol bsCol); - void visit(final BSCol bsCol); - void postVisit(final BSCol bsCol); - void visit(final BSClearFix bsClearFix); - void preVisit(final BSTabGroup bsTabGroup); - void visit(final BSTabGroup bsTabGroup); - void postVisit(final BSTabGroup bsTabGroup); - void preVisit(final BSTab bsTab); - void visit(final BSTab bsTab); - void postVisit(final BSTab bsTab); - } - - public static class VisitorAdapter extends Grid.VisitorAdapter implements Visitor { - @Override public void preVisit(final BSGrid bsGrid) { } - @Override public void visit(final BSGrid bsGrid) { } - @Override public void postVisit(final BSGrid bsGrid) { } - - @Override public void preVisit(final BSRow bsRow) { } - @Override public void visit(final BSRow bsRow) { } - @Override public void postVisit(final BSRow bsRow) { } - - @Override public void preVisit(final BSCol bsCol) { } - @Override public void visit(final BSCol bsCol) { } - @Override public void postVisit(final BSCol bsCol) { } - - @Override public void visit(final BSClearFix bsClearFix) { } - - @Override public void preVisit(final BSTabGroup bsTabGroup) { } - @Override public void visit(final BSTabGroup bsTabGroup) { } - @Override public void postVisit(final BSTabGroup bsTabGroup) { } - - @Override public void preVisit(final BSTab bsTab) { } - @Override public void visit(final BSTab bsTab) { } - @Override public void postVisit(final BSTab bsTab) { } - } + @Getter private final List<String> metadataErrors = new ArrayList<>(); @Override public void visit(final Grid.Visitor visitor) { - final BSGrid.Visitor bsVisitor = asBsVisitor(visitor); - bsVisitor.preVisit(this); - bsVisitor.visit(this); - traverseRows(this, visitor); - bsVisitor.postVisit(this); + new BSWalker(this).visit(visitor); } - protected void traverseRows(final BSRowOwner rowOwner, final Grid.Visitor visitor) { - final BSGrid.Visitor bsVisitor = asBsVisitor(visitor); - final List<BSRow> rows = rowOwner.getRows(); - for (BSRow bsRow : new ArrayList<>(rows)) { - bsRow.setOwner(this); - bsVisitor.preVisit(bsRow); - bsVisitor.visit(bsRow); - traverseCols(visitor, bsRow); - bsVisitor.postVisit(bsRow); - } - } - - private void traverseCols(final Grid.Visitor visitor, final BSRow bsRow) { - final BSGrid.Visitor bsVisitor = asBsVisitor(visitor); - final List<BSRowContent> cols = bsRow.getCols(); - for (BSRowContent rowContent : new ArrayList<>(cols)) { - rowContent.setOwner(bsRow); - if(rowContent instanceof BSCol) { - final BSCol bsCol = (BSCol) rowContent; - bsVisitor.preVisit(bsCol); - bsVisitor.visit(bsCol); - traverseDomainObject(bsCol, visitor); - traverseTabGroups(bsCol, visitor); - traverseActions(bsCol, visitor); - traverseFieldSets(bsCol, visitor); - traverseCollections(bsCol, visitor); - traverseRows(bsCol, visitor); - bsVisitor.postVisit(bsCol); - } else if (rowContent instanceof BSClearFix) { - final BSClearFix bsClearFix = (BSClearFix) rowContent; - bsVisitor.visit(bsClearFix); - } else { - throw new IllegalStateException( - "Unrecognized implementation of BSRowContent, " + rowContent); - } - } - } - - private void traverseDomainObject(final BSCol bsCol, final Grid.Visitor visitor) { - final DomainObjectLayoutData domainObject = bsCol.getDomainObject(); - if(domainObject == null) { - return; - } - domainObject.setOwner(bsCol); - visitor.visit(domainObject); - } - - private void traverseTabGroups( - final BSTabGroupOwner bsTabGroupOwner, - final Grid.Visitor visitor) { - final BSGrid.Visitor bsVisitor = asBsVisitor(visitor); - final List<BSTabGroup> tabGroups = bsTabGroupOwner.getTabGroups(); - for (BSTabGroup bsTabGroup : new ArrayList<>(tabGroups)) { - bsTabGroup.setOwner(bsTabGroupOwner); - bsVisitor.preVisit(bsTabGroup); - bsVisitor.visit(bsTabGroup); - traverseTabs(bsTabGroup, visitor); - bsVisitor.postVisit(bsTabGroup); - } - } - - private void traverseTabs( - final BSTabOwner bsTabOwner, - final Grid.Visitor visitor) { - final BSGrid.Visitor bsVisitor = asBsVisitor(visitor); - final List<BSTab> tabs = bsTabOwner.getTabs(); - for (BSTab tab : new ArrayList<>(tabs)) { - tab.setOwner(bsTabOwner); - bsVisitor.preVisit(tab); - bsVisitor.visit(tab); - traverseRows(tab, visitor); - bsVisitor.postVisit(tab); - } - } - - private static Visitor asBsVisitor(final Grid.Visitor visitor) { - return visitor instanceof Visitor? (Visitor) visitor : new BSGrid.VisitorAdapter() { - @Override public void visit(final DomainObjectLayoutData domainObjectLayoutData) { - visitor.visit(domainObjectLayoutData); - } - - @Override public void visit(final ActionLayoutData actionLayoutData) { - visitor.visit(actionLayoutData); - } - - @Override public void visit(final PropertyLayoutData propertyLayoutData) { - visitor.visit(propertyLayoutData); - } - - @Override public void visit(final CollectionLayoutData collectionLayoutData) { - visitor.visit(collectionLayoutData); - } - - @Override public void visit(final FieldSet fieldSet) { - visitor.visit(fieldSet); - } - }; - } - - @Programmatic - @XmlTransient - public LinkedHashMap<String, BSTab> getAllTabsByName() { - final LinkedHashMap<String, BSTab> tabsByName = new LinkedHashMap<>(); - - visit(new BSGrid.VisitorAdapter() { + @Override + public LinkedHashMap<String, PropertyLayoutData> getAllPropertiesById() { + final LinkedHashMap<String, PropertyLayoutData> propertiesById = new LinkedHashMap<>(); + visit(new BSElement.Visitor() { @Override - public void visit(final BSTab bSTab) { - tabsByName.put(bSTab.getName(), bSTab); + public void visit(final PropertyLayoutData propertyLayoutData) { + propertiesById.put(propertyLayoutData.getId(), propertyLayoutData); } }); - return tabsByName; + return propertiesById; } - @Programmatic - @XmlTransient - public LinkedHashMap<String, HasCssId> getAllCssId() { - final LinkedHashMap<String, HasCssId> divsByCssId = new LinkedHashMap<>(); - - visit(new BSGrid.VisitorAdapter() { + @Override + public LinkedHashMap<String, CollectionLayoutData> getAllCollectionsById() { + final LinkedHashMap<String, CollectionLayoutData> collectionsById = new LinkedHashMap<>(); + visit(new BSElement.Visitor() { @Override - public void visit(final BSRow bsRow) { - final String id = bsRow.getId(); - divsByCssId.put(id, bsRow); + public void visit(final CollectionLayoutData collectionLayoutData) { + collectionsById.put(collectionLayoutData.getId(), collectionLayoutData); } }); - return divsByCssId; + return collectionsById; } @Override - @Programmatic - @XmlTransient - public BSGrid getGrid() { - return this; - } + public LinkedHashMap<String, ActionLayoutData> getAllActionsById() { + final LinkedHashMap<String, ActionLayoutData> actionsById = new LinkedHashMap<>(); + visit(new BSElement.Visitor() { + @Override + public void visit(final ActionLayoutData actionLayoutData) { + actionsById.put(actionLayoutData.getId(), actionLayoutData); + } + }); + return actionsById; + } + +// -- UNUSED + +// public LinkedHashMap<String, BSTab> getAllTabsByName() { +// final LinkedHashMap<String, BSTab> tabsByName = new LinkedHashMap<>(); +// +// visit(new BSGrid.Visitor() { +// @Override +// public void visit(final BSTab bSTab) { +// tabsByName.put(bSTab.getName(), bSTab); +// } +// }); +// return tabsByName; +// } +// +// public LinkedHashMap<String, HasElementId> getAllCssId() { +// final LinkedHashMap<String, HasElementId> divsByCssId = new LinkedHashMap<>(); +// +// visit(new BSGrid.Visitor() { +// @Override +// public void visit(final BSRow bsRow) { +// final String id = bsRow.getId(); +// divsByCssId.put(id, bsRow); +// } +// }); +// return divsByCssId; +// } +// +// public LinkedHashMap<String, FieldSet> getAllFieldSetsByName() { +// final LinkedHashMap<String, FieldSet> fieldSetsByName = new LinkedHashMap<>(); +// +// visit(new BSGrid.Visitor() { +// @Override +// public void visit(final FieldSet fieldSet) { +// fieldSetsByName.put(fieldSet.getName(), fieldSet); +// } +// }); +// return fieldSetsByName; +// } } diff --git a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSClearFixHidden.java b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSGridDto.java similarity index 60% copy from api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSClearFixHidden.java copy to api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSGridDto.java index 08458d72d5c..c7f02262193 100644 --- a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSClearFixHidden.java +++ b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSGridDto.java @@ -18,32 +18,29 @@ */ package org.apache.causeway.applib.layout.grid.bootstrap; +import java.util.ArrayList; +import java.util.List; + +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlElement; import jakarta.xml.bind.annotation.XmlRootElement; import jakarta.xml.bind.annotation.XmlType; -/** - * One of the <a href="http://getbootstrap.com/css/#responsive-utilities">Responsive utility classes</a>. - * - * - * <p> - * It is rendered as a (eg) <div class="clearfix hidden-xs ..."> - * </p> - * - * @since 1.x {@index} - */ -@XmlRootElement( - name = "clearFixHidden" - ) -@XmlType( - name = "clearFixHidden" - ) -public class BSClearFixHidden extends BSClearFix { +import lombok.Getter; +import lombok.Setter; +@XmlRootElement(name = "grid") +@XmlType(name = "grid", propOrder = {"rows", "metadataErrors"}) +@Setter +public class BSGridDto implements BSElement, BSRowOwner { private static final long serialVersionUID = 1L; - @Override - public String toCssClass() { - return "clearfix " + getDisplayFragment(CssDisplay.NONE, getSize()) - + (getCssClass() != null? " " + getCssClass(): ""); - } + @Getter(onMethod_ = {@XmlAttribute(required = false)}) + private String cssClass; + + @Getter(onMethod_ = {@XmlElement(name = "row", required = true)}) + private List<BSRow> rows; + + @Getter(onMethod_ = {@XmlElement(name = "metadataError", required = false)}) + private List<String> metadataErrors = new ArrayList<>(); } diff --git a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSRow.java b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSRow.java index c5c1392d261..2405af61909 100644 --- a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSRow.java +++ b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSRow.java @@ -22,109 +22,53 @@ import java.util.List; import jakarta.xml.bind.annotation.XmlAttribute; -import jakarta.xml.bind.annotation.XmlElement; import jakarta.xml.bind.annotation.XmlElementRef; import jakarta.xml.bind.annotation.XmlElementRefs; -import jakarta.xml.bind.annotation.XmlTransient; import jakarta.xml.bind.annotation.XmlType; -import org.apache.causeway.applib.annotation.Programmatic; +import lombok.Getter; +import lombok.Setter; /** * Contains a row of content, either on the top-level {@link BSGrid page} or at any other lower-level element that can * contain rows, eg {@link BSTab tabs}. * - * <p> - * It is rendered as a <div class="row ..."> - * </p> + * <p>It is rendered as a <div class="row ..."> * * @since 1.x {@index} */ @XmlType( - name = "row" - , propOrder = { - "cols" - , "metadataError" - } - ) -public class BSRow extends BSElementAbstract implements HasCssId, BSRowContentOwner { + name = "row", + propOrder = {"cols", "metadataError"}) +public final class BSRow extends BSElementAbstract implements HasElementId, BSRowContentOwner { private static final long serialVersionUID = 1L; - private String id; - /** * As per <div id="...">...</div> : must be unique across entire page. */ - @Override - @XmlAttribute(required = false) - public String getId() { - return id; - } - - public void setId(final String id) { - this.id = id; - } - - private List<BSRowContent> cols = new ArrayList<>(); + @Getter(onMethod_ = {@XmlAttribute(required = false)}) + @Setter + private String id; - // no wrapper - @XmlElementRefs({ - @XmlElementRef(type = BSCol.class, name="col", required = true), - @XmlElementRef(type = BSClearFixVisible.class, name="clearFixVisible", required = false), - @XmlElementRef(type = BSClearFixHidden.class, name="clearFixHidden", required = false) + @Getter(onMethod_ = { + @XmlElementRefs({ + @XmlElementRef(type = BSCol.class, name="col", required = true), + @XmlElementRef(type = BSClearFixVisible.class, name="clearFixVisible", required = false), + @XmlElementRef(type = BSClearFixHidden.class, name="clearFixHidden", required = false) + }) }) - public List<BSRowContent> getCols() { - return cols; - } - - public void setCols(final List<BSRowContent> cols) { - this.cols = cols; - } - - private String metadataError; + private List<BSRowContent> cols = new ArrayList<>(); /** * For diagnostics; populated by the framework if and only if a metadata error. */ - @XmlElement(required = false) - public String getMetadataError() { - return metadataError; - } - - public void setMetadataError(final String metadataError) { - this.metadataError = metadataError; - } - - private BSRowOwner owner; - - /** - * Owner. - * - * <p> - * Set programmatically by framework after reading in from XML. - * </p> - */ - @XmlTransient - public BSRowOwner getOwner() { - return owner; - } - - public void setOwner(final BSRowOwner owner) { - this.owner = owner; - } - - @Override - @XmlTransient - @Programmatic - public BSGrid getGrid() { - return getOwner().getGrid(); - } + @Getter(onMethod_ = {@XmlAttribute(required = false)}) + @Setter + private String metadataError; @Override public String toString() { - return "BSRow{" + - "id='" + id + '\'' + - '}'; + return "BSRow{" + "id='" + id + '\'' + '}'; } } diff --git a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSRowContent.java b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSRowContent.java index 51dcacb2ed0..137e4df57bb 100644 --- a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSRowContent.java +++ b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSRowContent.java @@ -19,61 +19,28 @@ package org.apache.causeway.applib.layout.grid.bootstrap; import jakarta.xml.bind.annotation.XmlAttribute; -import jakarta.xml.bind.annotation.XmlTransient; -import org.apache.causeway.applib.annotation.Programmatic; +import lombok.Getter; +import lombok.Setter; /** * Common superclass for any content of a row. * - * <p> - * Most commonly the content of a row is {@link BSCol col}umns, but it may be either of the - * {@link BSClearFix clearfix} classes. - * </p> + * <p> Most commonly the content of a row is {@link BSCol col}umns, but it may be either of the + * {@link BSClearFix clearfix} classes. * * @since 1.x {@index} */ -public abstract class BSRowContent extends BSElementAbstract { +public sealed abstract class BSRowContent extends BSElementAbstract +permits BSCol, BSClearFix { private static final long serialVersionUID = 1L; - private Size size; - /** * Default if not specified is {@link Size#MD}. */ - @XmlAttribute(required = false) - public Size getSize() { - return size; - } - - public void setSize(final Size size) { - this.size = size; - } - - private BSRowContentOwner owner; - - /** - * Owner. - * - * <p> - * Set programmatically by framework after reading in from XML. - * </p> - */ - @XmlTransient - public BSRowContentOwner getOwner() { - return owner; - } - - public void setOwner(final BSRowContentOwner owner) { - this.owner = owner; - } - - @Override - @XmlTransient - @Programmatic - public BSGrid getGrid() { - return getOwner().getGrid(); - } + @Getter(onMethod_ = {@XmlAttribute(required = false)}) + @Setter + private Size size; } diff --git a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSRowContentOwner.java b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSRowContentOwner.java index be3c51d8d3e..cc69a5b65ef 100644 --- a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSRowContentOwner.java +++ b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSRowContentOwner.java @@ -23,6 +23,6 @@ /** * @since 1.x {@index} */ -public interface BSRowContentOwner extends Owner, WithinGrid { +public interface BSRowContentOwner extends Owner { } diff --git a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSRowOwner.java b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSRowOwner.java index 034417c51ab..f62bc730a2d 100644 --- a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSRowOwner.java +++ b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSRowOwner.java @@ -25,7 +25,7 @@ /** * @since 1.x {@index} */ -public interface BSRowOwner extends Owner, WithinGrid { +public interface BSRowOwner extends Owner { List<BSRow> getRows(); } diff --git a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSTab.java b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSTab.java index 617ba73d9f0..eac5aa463f0 100644 --- a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSTab.java +++ b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSTab.java @@ -20,37 +20,24 @@ import java.util.ArrayList; import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Predicate; - import jakarta.xml.bind.annotation.XmlAttribute; import jakarta.xml.bind.annotation.XmlElement; import jakarta.xml.bind.annotation.XmlTransient; import jakarta.xml.bind.annotation.XmlType; import org.apache.causeway.applib.annotation.Programmatic; -import org.apache.causeway.applib.layout.component.ActionLayoutData; -import org.apache.causeway.applib.layout.component.CollectionLayoutData; -import org.apache.causeway.applib.layout.component.DomainObjectLayoutData; -import org.apache.causeway.applib.layout.component.PropertyLayoutData; /** * Represents a tab within a {@link BSTabGroup tab group}. * - * <p> - * They simply contain one or more {@link BSRow row}s. - * </p> + * <p>They simply contain one or more {@link BSRow row}s. * * @since 1.x {@index} */ @XmlType( - name = "tab" - , propOrder = { - "name", - "rows" - } - ) -public class BSTab extends BSElementAbstract implements BSRowOwner { + name = "tab", + propOrder = {"name", "rows"}) +public final class BSTab extends BSElementAbstract implements BSRowOwner { private static final long serialVersionUID = 1L; @@ -95,75 +82,6 @@ public void setOwner(final BSTabOwner owner) { this.owner = owner; } - public static class Predicates { - public static Predicate<BSTab> notEmpty() { - final AtomicBoolean visitingTheNode = new AtomicBoolean(false); - final AtomicBoolean foundContent = new AtomicBoolean(false); - - return thisBsTab -> { - final BSGrid owningGrid = thisBsTab.getGrid(); - owningGrid.visit(new BSGrid.VisitorAdapter() { - - /** - * if found the tab, then reset 'foundContent' to false, and then use 'visitingTheNode' as - * a marker to indicate that the visitor is now being passed to the nodes underneath the tab. - * In those children, if visited (with the 'visitingTheNode' flag enabled), then simply set the - * 'foundContent' flag. - */ - @Override - public void preVisit(final BSTab bsTab) { - if(bsTab == thisBsTab) { - foundContent.set(false); - visitingTheNode.set(true); - } - } - - @Override public void postVisit(final BSTab bsTab) { - if(bsTab == thisBsTab) { - visitingTheNode.set(false); - } - } - - @Override - public void visit(final DomainObjectLayoutData domainObjectLayoutData) { - if(visitingTheNode.get()) { - foundContent.set(true); - } - } - - @Override - public void visit(final ActionLayoutData actionLayoutData) { - if(visitingTheNode.get()) { - foundContent.set(true); - } - } - - @Override - public void visit(final PropertyLayoutData propertyLayoutData) { - if(visitingTheNode.get()) { - foundContent.set(true); - } - } - - @Override - public void visit(final CollectionLayoutData collectionLayoutData) { - if(visitingTheNode.get()) { - foundContent.set(true); - } - } - }); - return foundContent.get(); - }; - } - } - - @Override - @XmlTransient - @Programmatic - public BSGrid getGrid() { - return getOwner().getGrid(); - } - /** * removes this tab from its tab-group */ diff --git a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSTabGroup.java b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSTabGroup.java index 16ee03d61fc..3d508a5f3bd 100644 --- a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSTabGroup.java +++ b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSTabGroup.java @@ -26,21 +26,17 @@ import jakarta.xml.bind.annotation.XmlTransient; import jakarta.xml.bind.annotation.XmlType; -import org.apache.causeway.applib.annotation.Programmatic; - /** * Represents a tab group containing one or more {@link BSTab tab}s. * * @since 1.x {@index} */ @XmlType( - name = "tabGroup" - , propOrder = { + name = "tabGroup", + propOrder = { "tabs", - "metadataError" - } - ) -public class BSTabGroup extends BSElementAbstract implements BSTabOwner { + "metadataError"}) +public final class BSTabGroup extends BSElementAbstract implements BSTabOwner { private static final long serialVersionUID = 1L; @@ -119,11 +115,4 @@ public void setMetadataError(final String metadataError) { this.metadataError = metadataError; } - @Override - @XmlTransient - @Programmatic - public BSGrid getGrid() { - return getOwner().getGrid(); - } - } diff --git a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSTabGroupOwner.java b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSTabGroupOwner.java index 0fe167965c4..e126c4be9ff 100644 --- a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSTabGroupOwner.java +++ b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSTabGroupOwner.java @@ -25,7 +25,7 @@ /** * @since 1.x {@index} */ -public interface BSTabGroupOwner extends Owner, WithinGrid { +public interface BSTabGroupOwner extends Owner { List<BSTabGroup> getTabGroups(); } diff --git a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSTabOwner.java b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSTabOwner.java index 6647b35550c..2f029798cbe 100644 --- a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSTabOwner.java +++ b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSTabOwner.java @@ -25,7 +25,7 @@ /** * @since 1.x {@index} */ -public interface BSTabOwner extends Owner, WithinGrid { +public interface BSTabOwner extends Owner { List<BSTab> getTabs(); } diff --git a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSUtil.java b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSUtil.java new file mode 100644 index 00000000000..4eb1f374cca --- /dev/null +++ b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSUtil.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.causeway.applib.layout.grid.bootstrap; + +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.causeway.applib.layout.component.ActionLayoutData; +import org.apache.causeway.applib.layout.component.CollectionLayoutData; +import org.apache.causeway.applib.layout.component.DomainObjectLayoutData; +import org.apache.causeway.applib.layout.component.PropertyLayoutData; + +import lombok.experimental.UtilityClass; + +@UtilityClass +public class BSUtil { + + public boolean hasContent(final BSTab thisBsTab) { + final AtomicBoolean foundContent = new AtomicBoolean(false); + new BSWalker(thisBsTab).visit(new BSElement.Visitor() { + @Override + public void visit(final DomainObjectLayoutData domainObjectLayoutData) { + foundContent.set(true); + } + @Override + public void visit(final ActionLayoutData actionLayoutData) { + foundContent.set(true); + } + @Override + public void visit(final PropertyLayoutData propertyLayoutData) { + foundContent.set(true); + } + @Override + public void visit(final CollectionLayoutData collectionLayoutData) { + foundContent.set(true); + } + }); + return foundContent.get(); + } + + +} diff --git a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSWalker.java b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSWalker.java new file mode 100644 index 00000000000..339853218da --- /dev/null +++ b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSWalker.java @@ -0,0 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.causeway.applib.layout.grid.bootstrap; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.causeway.applib.layout.component.ActionLayoutData; +import org.apache.causeway.applib.layout.component.ActionLayoutDataOwner; +import org.apache.causeway.applib.layout.component.CollectionLayoutData; +import org.apache.causeway.applib.layout.component.CollectionLayoutDataOwner; +import org.apache.causeway.applib.layout.component.DomainObjectLayoutData; +import org.apache.causeway.applib.layout.component.FieldSet; +import org.apache.causeway.applib.layout.component.FieldSetOwner; +import org.apache.causeway.applib.layout.component.PropertyLayoutData; +import org.apache.causeway.applib.layout.grid.Grid; + +public record BSWalker(BSRowOwner root) { + + public void visit(final Grid.Visitor visitor) { + final BSElement.Visitor bsVisitor = asBsVisitor(visitor); + if(root instanceof BSGrid bsGrid) { + bsVisitor.preVisit(bsGrid); + bsVisitor.visit(bsGrid); + traverseRows(root, bsVisitor); + bsVisitor.postVisit(bsGrid); + } else { + traverseRows(root, bsVisitor); + } + } + + private void traverseRows(final BSRowOwner rowOwner, final BSElement.Visitor visitor) { + final BSElement.Visitor bsVisitor = asBsVisitor(visitor); + final List<BSRow> rows = rowOwner.getRows(); + for (BSRow bsRow : new ArrayList<>(rows)) { + bsVisitor.preVisit(bsRow); + bsVisitor.visit(bsRow); + traverseCols(bsRow, visitor); + bsVisitor.postVisit(bsRow); + } + } + + private void traverseCols(final BSRow bsRow, final BSElement.Visitor visitor) { + final BSElement.Visitor bsVisitor = asBsVisitor(visitor); + final List<BSRowContent> cols = bsRow.getCols(); + for (BSRowContent rowContent : new ArrayList<>(cols)) { + if(rowContent instanceof BSCol) { + final BSCol bsCol = (BSCol) rowContent; + bsVisitor.preVisit(bsCol); + bsVisitor.visit(bsCol); + traverseDomainObject(bsCol, visitor); + traverseTabGroups(bsCol, visitor); + traverseActions(bsCol, visitor); + traverseFieldSets(bsCol, visitor); + traverseCollections(bsCol, visitor); + traverseRows(bsCol, visitor); + bsVisitor.postVisit(bsCol); + } else if (rowContent instanceof BSClearFix) { + final BSClearFix bsClearFix = (BSClearFix) rowContent; + bsVisitor.visit(bsClearFix); + } else { + throw new IllegalStateException( + "Unrecognized implementation of BSRowContent, " + rowContent); + } + } + } + + private void traverseDomainObject(final BSCol bsCol, final BSElement.Visitor visitor) { + final DomainObjectLayoutData domainObject = bsCol.getDomainObject(); + if(domainObject == null) return; + + domainObject.setOwner(bsCol); + visitor.visit(domainObject); + } + + private void traverseTabGroups(final BSTabGroupOwner bsTabGroupOwner, final BSElement.Visitor visitor) { + final BSElement.Visitor bsVisitor = asBsVisitor(visitor); + final List<BSTabGroup> tabGroups = bsTabGroupOwner.getTabGroups(); + for (BSTabGroup bsTabGroup : new ArrayList<>(tabGroups)) { + bsTabGroup.setOwner(bsTabGroupOwner); + bsVisitor.preVisit(bsTabGroup); + bsVisitor.visit(bsTabGroup); + traverseTabs(bsTabGroup, visitor); + bsVisitor.postVisit(bsTabGroup); + } + } + + private void traverseTabs(final BSTabOwner bsTabOwner, final BSElement.Visitor visitor) { + final BSElement.Visitor bsVisitor = asBsVisitor(visitor); + final List<BSTab> tabs = bsTabOwner.getTabs(); + for (BSTab tab : new ArrayList<>(tabs)) { + tab.setOwner(bsTabOwner); + bsVisitor.preVisit(tab); + bsVisitor.visit(tab); + traverseRows(tab, visitor); + bsVisitor.postVisit(tab); + } + } + + /** + * Convenience for subclasses. + */ + private void traverseActions(final ActionLayoutDataOwner actionLayoutDataOwner, final BSElement.Visitor visitor) { + final List<ActionLayoutData> actionLayoutDatas = actionLayoutDataOwner.getActions(); + if(actionLayoutDatas == null) return; + + for (final ActionLayoutData actionLayoutData : new ArrayList<>(actionLayoutDatas)) { + actionLayoutData.setOwner(actionLayoutDataOwner); + visitor.visit(actionLayoutData); + } + } + + /** + * Convenience for subclasses. + */ + private void traverseFieldSets(final FieldSetOwner fieldSetOwner, final BSElement.Visitor visitor) { + final List<FieldSet> fieldSets = fieldSetOwner.getFieldSets(); + for (FieldSet fieldSet : new ArrayList<>(fieldSets)) { + fieldSet.setOwner(fieldSetOwner); + visitor.visit(fieldSet); + traverseActions(fieldSet, visitor); + final List<PropertyLayoutData> properties = fieldSet.getProperties(); + for (final PropertyLayoutData property : new ArrayList<>(properties)) { + property.setOwner(fieldSet); + visitor.visit(property); + traverseActions(property, visitor); + } + } + } + + /** + * Convenience for subclasses. + */ + private void traverseCollections( + final CollectionLayoutDataOwner owner, final BSElement.Visitor visitor) { + final List<CollectionLayoutData> collections = owner.getCollections(); + for (CollectionLayoutData collection : new ArrayList<>(collections)) { + collection.setOwner(owner); + visitor.visit(collection); + traverseActions(collection, visitor); + } + } + + private BSElement.Visitor asBsVisitor(final Grid.Visitor visitor) { + return visitor instanceof BSElement.Visitor bsGridVisistor + ? bsGridVisistor + : new BSElement.Visitor() { + @Override public void visit(final DomainObjectLayoutData domainObjectLayoutData) { + visitor.visit(domainObjectLayoutData); + } + @Override public void visit(final ActionLayoutData actionLayoutData) { + visitor.visit(actionLayoutData); + } + @Override public void visit(final PropertyLayoutData propertyLayoutData) { + visitor.visit(propertyLayoutData); + } + @Override public void visit(final CollectionLayoutData collectionLayoutData) { + visitor.visit(collectionLayoutData); + } + @Override public void visit(final FieldSet fieldSet) { + visitor.visit(fieldSet); + } + }; + } + +} diff --git a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/HasCssId.java b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/HasElementId.java similarity index 97% rename from api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/HasCssId.java rename to api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/HasElementId.java index ce5d08d3a42..ac8bcc863a3 100644 --- a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/HasCssId.java +++ b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/HasElementId.java @@ -21,7 +21,7 @@ /** * @since 2.0 {@index} */ -public interface HasCssId { +public interface HasElementId { /** * As per <div id="...">...</div> : must be unique across entire page. diff --git a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/WithinGrid.java b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/WithinGrid.java deleted file mode 100644 index 40f8611acaf..00000000000 --- a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/WithinGrid.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.causeway.applib.layout.grid.bootstrap; - -import org.apache.causeway.applib.annotation.Programmatic; - -/** - * @since 1.x {@index} - */ -public interface WithinGrid { - - @Programmatic - BSGrid getGrid(); -} diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/layout/LayoutFacetUtil.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/layout/LayoutFacetUtil.java index dfe32602d39..dd6e953eadb 100644 --- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/layout/LayoutFacetUtil.java +++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/layout/LayoutFacetUtil.java @@ -367,7 +367,7 @@ public DomainObjectLayoutData createDomainObjectLayoutData() { } @RequiredArgsConstructor(staticName = "of") - public static class MetamodelToGridOverridingVisitor extends Grid.VisitorAdapter { + public static class MetamodelToGridOverridingVisitor implements Grid.Visitor { private final @NonNull ObjectSpecification objectSpec; diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridSystemServiceAbstract.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridSystemServiceAbstract.java index a64db222c1a..8098fd12677 100644 --- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridSystemServiceAbstract.java +++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridSystemServiceAbstract.java @@ -150,7 +150,7 @@ private void overwriteFacets( : Facet.Precedence.HIGH; // non-fallback case: XML layout overrules layout from annotations final AtomicInteger propertySequence = new AtomicInteger(0); - fcGrid.visit(new Grid.VisitorAdapter() { + fcGrid.visit(new Grid.Visitor() { private int collectionSequence = 1; private int actionDomainObjectSequence = 1; @@ -393,7 +393,7 @@ public void complete(final G grid, final Class<?> domainClass) { @Override public void minimal(final G grid, final Class<?> domainClass) { normalize(grid, domainClass); - grid.visit(new Grid.VisitorAdapter() { + grid.visit(new Grid.Visitor() { @Override public void visit(final ActionLayoutData actionLayoutData) { actionLayoutData.getOwner().getActions().remove(actionLayoutData); diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/CollapseIfOneTabProcessor.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/CollapseIfOneTabProcessor.java index f7b0e4bb594..c6f5b449309 100644 --- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/CollapseIfOneTabProcessor.java +++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/CollapseIfOneTabProcessor.java @@ -21,6 +21,7 @@ import java.util.Optional; import org.apache.causeway.applib.layout.grid.bootstrap.BSCol; +import org.apache.causeway.applib.layout.grid.bootstrap.BSElement; import org.apache.causeway.applib.layout.grid.bootstrap.BSGrid; import org.apache.causeway.applib.layout.grid.bootstrap.BSTabGroup; @@ -32,9 +33,9 @@ record CollapseIfOneTabProcessor(BSGrid bsGrid) { public void run() { - bsGrid.visit(new BSGrid.VisitorAdapter() { + bsGrid.visit(new BSElement.Visitor() { @Override - public void visit(BSTabGroup bsTabGroup) { + public void visit(final BSTabGroup bsTabGroup) { if(bsTabGroup.getTabs().size()!=1) return; // when has no tabs is also a no-op var isCollapseIfOne = Optional.ofNullable(bsTabGroup.isCollapseIfOne()) @@ -48,7 +49,6 @@ public void visit(BSTabGroup bsTabGroup) { bsTabGroup.getTabs().get(0).getRows() .forEach(row->{ parent.getRows().add(row); - row.setOwner(parent); }); } }); diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/EmptyTabRemovalProcessor.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/EmptyTabRemovalProcessor.java index 6655fa7620b..d33b51fe4ce 100644 --- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/EmptyTabRemovalProcessor.java +++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/EmptyTabRemovalProcessor.java @@ -25,6 +25,7 @@ import org.apache.causeway.applib.layout.component.CollectionLayoutData; import org.apache.causeway.applib.layout.component.DomainObjectLayoutData; import org.apache.causeway.applib.layout.component.PropertyLayoutData; +import org.apache.causeway.applib.layout.grid.bootstrap.BSElement; import org.apache.causeway.applib.layout.grid.bootstrap.BSGrid; import org.apache.causeway.applib.layout.grid.bootstrap.BSTab; @@ -41,19 +42,19 @@ public void run() { var emptyTabs = new ArrayList<BSTab>(); - bsGrid.visit(new BSGrid.VisitorAdapter() { + bsGrid.visit(new BSElement.Visitor() { final Stack<Flag> stack = new Stack<Flag>(); - @Override public void visit(ActionLayoutData actionLayoutData) { keep(); } - @Override public void visit(DomainObjectLayoutData domainObjectLayoutData) { keep(); } - @Override public void visit(PropertyLayoutData propertyLayoutData) { keep(); } - @Override public void visit(CollectionLayoutData collectionLayoutData) { keep(); } + @Override public void visit(final ActionLayoutData actionLayoutData) { keep(); } + @Override public void visit(final DomainObjectLayoutData domainObjectLayoutData) { keep(); } + @Override public void visit(final PropertyLayoutData propertyLayoutData) { keep(); } + @Override public void visit(final CollectionLayoutData collectionLayoutData) { keep(); } - @Override public void visit(BSTab bsTab) { + @Override public void visit(final BSTab bsTab) { stack.push(new Flag()); } - @Override public void postVisit(BSTab bsTab) { + @Override public void postVisit(final BSTab bsTab) { var flag = stack.pop(); if(!flag.keep) { // collecting into list, so we don't risk a ConcurrentModificationException, diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridConverterFromDto.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridConverterFromDto.java new file mode 100644 index 00000000000..ad9b0ba04f1 --- /dev/null +++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridConverterFromDto.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.causeway.core.metamodel.services.grid.bootstrap; + +import org.apache.causeway.applib.layout.grid.bootstrap.BSGrid; +import org.apache.causeway.applib.layout.grid.bootstrap.BSGridDto; + +record GridConverterFromDto(BSGridDto dto) { + + public BSGrid createGrid() { + var grid = new BSGrid(); + dto.getRows().forEach(row->{ + grid.getRows().add(row); + }); + dto.getRows().clear(); + return grid; + } + + +// private void getAllMemberById(final BSGridDto dto) { +// final LinkedHashMap<String, PropertyLayoutData> propertiesById = new LinkedHashMap<>(); +// final LinkedHashMap<String, CollectionLayoutData> collectionsById = new LinkedHashMap<>(); +// final LinkedHashMap<String, ActionLayoutData> actionsById = new LinkedHashMap<>(); +// +// new BSWalker(dto).visit(new Grid.Visitor() { +// @Override +// public void visit(final PropertyLayoutData propertyLayoutData) { +// propertiesById.put(propertyLayoutData.getId(), propertyLayoutData); +// } +// @Override +// public void visit(final CollectionLayoutData collectionLayoutData) { +// collectionsById.put(collectionLayoutData.getId(), collectionLayoutData); +// } +// @Override +// public void visit(final ActionLayoutData actionLayoutData) { +// actionsById.put(actionLayoutData.getId(), actionLayoutData); +// } +// }); +// } +// +// record DtoVisitor( +// LinkedHashMap<String, PropertyLayoutData> propertiesById, +// LinkedHashMap<String, CollectionLayoutData> collectionsById, +// LinkedHashMap<String, ActionLayoutData> actionsById) implements Grid.Visitor { +// DtoVisitor() { +// this(new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>()); +// } +// @Override +// public void visit(final PropertyLayoutData propertyLayoutData) { +// propertiesById.put(propertyLayoutData.getId(), propertyLayoutData); +// } +// @Override +// public void visit(final CollectionLayoutData collectionLayoutData) { +// collectionsById.put(collectionLayoutData.getId(), collectionLayoutData); +// } +// @Override +// public void visit(final ActionLayoutData actionLayoutData) { +// actionsById.put(actionLayoutData.getId(), actionLayoutData); +// } +// } + +} diff --git a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSElement.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridConverterToDto.java similarity index 57% copy from api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSElement.java copy to core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridConverterToDto.java index 382dfa890f4..a6cb956b5ca 100644 --- a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSElement.java +++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridConverterToDto.java @@ -16,22 +16,25 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.causeway.applib.layout.grid.bootstrap; +package org.apache.causeway.core.metamodel.services.grid.bootstrap; -import java.io.Serializable; +import org.apache.causeway.applib.layout.grid.bootstrap.BSGrid; +import org.apache.causeway.applib.layout.grid.bootstrap.BSGridDto; +import org.apache.causeway.applib.layout.grid.bootstrap.BSRowOwner; -/** - * @since 1.x {@index} - */ -public interface BSElement extends WithinGrid, Serializable { +record GridConverterToDto(BSGrid grid) { + + public BSGridDto createDto() { + var dto = new BSGridDto(); + traversRows(grid, dto); + return dto; + } - /** - * Any additional CSS classes to render on the page element corresponding to this object, - * eg as per the <a href="http://getbootstrap.com/css/#grid-less">Bootstrap mixins</a> or just for - * custom styling. - */ - String getCssClass(); + private void traversRows(final BSGrid grid, final BSRowOwner rowOwner) { + rowOwner.getRows().forEach(row->{ + grid.getRows().add(row); + }); - void setCssClass(final String cssClass); + } } diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridMarshallerServiceBootstrap.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridMarshallerServiceBootstrap.java index 0f9ea4d6b2f..d2b6294c54c 100644 --- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridMarshallerServiceBootstrap.java +++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridMarshallerServiceBootstrap.java @@ -19,6 +19,7 @@ package org.apache.causeway.core.metamodel.services.grid.bootstrap; import java.util.EnumSet; +import java.util.Map; import java.util.Objects; import jakarta.annotation.Priority; @@ -26,24 +27,22 @@ import jakarta.inject.Named; import jakarta.xml.bind.Marshaller; +import org.jspecify.annotations.NonNull; + import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import org.apache.causeway.applib.annotation.PriorityPrecedence; import org.apache.causeway.applib.layout.grid.bootstrap.BSGrid; +import org.apache.causeway.applib.layout.grid.bootstrap.BSGridDto; import org.apache.causeway.applib.services.grid.GridMarshallerService; import org.apache.causeway.applib.services.jaxb.JaxbService; import org.apache.causeway.applib.value.NamedWithMimeType.CommonMimeType; import org.apache.causeway.commons.functional.Try; -import org.apache.causeway.commons.internal.collections._Maps; import org.apache.causeway.commons.internal.exceptions._Exceptions; import org.apache.causeway.commons.io.JaxbUtils; import org.apache.causeway.core.metamodel.CausewayModuleCoreMetamodel; -import lombok.Getter; -import org.jspecify.annotations.NonNull; -import lombok.experimental.Accessors; - /** * Default implementation of {@link GridMarshallerService} using DTOs based on * <a href="https://getbootstrap.com>Bootstrap</a> design system. @@ -54,23 +53,21 @@ @Named(CausewayModuleCoreMetamodel.NAMESPACE + ".GridMarshallerServiceBootstrap") @Priority(PriorityPrecedence.MIDPOINT) @Qualifier("Default") -//@Slf4j -public class GridMarshallerServiceBootstrap -implements GridMarshallerService<BSGrid> { - - private final JaxbService jaxbService; +public record GridMarshallerServiceBootstrap( + JaxbService jaxbService, + EnumSet<CommonMimeType> supportedFormats) implements GridMarshallerService<BSGrid> { @Inject public GridMarshallerServiceBootstrap(final JaxbService jaxbService) { - super(); - this.jaxbService = jaxbService; + this(jaxbService, EnumSet.of(CommonMimeType.XML)); // eagerly create a JAXBContext for this grid type (and cache it) - JaxbUtils.jaxbContextFor(BSGrid.class, true); + JaxbUtils.jaxbContextFor(BSGridDto.class, true); } - @Getter(onMethod_={@Override}) @Accessors(fluent = true) - private final EnumSet<CommonMimeType> supportedFormats = - EnumSet.of(CommonMimeType.XML); + @Override + public EnumSet<CommonMimeType> supportedFormats() { + return supportedFormats; + } @Override public Class<BSGrid> supportedClass() { @@ -78,15 +75,15 @@ public Class<BSGrid> supportedClass() { } @Override - public String marshal(final @NonNull BSGrid grid, final @NonNull CommonMimeType format) { + public String marshal(final @NonNull BSGrid bsGrid, final @NonNull CommonMimeType format) { throwIfFormatNotSupported(format); switch(format) { case XML:{ - return jaxbService.toXml(grid, - _Maps.unmodifiable( - Marshaller.JAXB_SCHEMA_LOCATION, - Objects.requireNonNull(grid.getTnsAndSchemaLocation()) - )); + var dto = new GridConverterToDto(bsGrid).createDto(); + return jaxbService.toXml(dto, + Map.of( + Marshaller.JAXB_SCHEMA_LOCATION, + Objects.requireNonNull(bsGrid.getTnsAndSchemaLocation()))); } default: throw _Exceptions.unsupportedOperation("supported format %s is not implemented", format.name()); @@ -98,7 +95,8 @@ public Try<BSGrid> unmarshal(final String content, final @NonNull CommonMimeType throwIfFormatNotSupported(format); switch(format) { case XML:{ - return Try.call(()->jaxbService.fromXml(BSGrid.class, content)); + return Try.call(()->jaxbService.fromXml(BSGridDto.class, content)) + .mapSuccessWhenPresent(dto->new GridConverterFromDto(dto).createGrid()); } default: throw _Exceptions.unsupportedOperation("supported format %s is not implemented", format.name()); diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/_GridModel.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridModel.java similarity index 97% rename from core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/_GridModel.java rename to core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridModel.java index 71f0b099590..5f0aadbb5cc 100644 --- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/_GridModel.java +++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridModel.java @@ -26,6 +26,7 @@ import org.apache.causeway.applib.layout.component.FieldSet; import org.apache.causeway.applib.layout.grid.bootstrap.BSCol; +import org.apache.causeway.applib.layout.grid.bootstrap.BSElement; import org.apache.causeway.applib.layout.grid.bootstrap.BSGrid; import org.apache.causeway.applib.layout.grid.bootstrap.BSRow; import org.apache.causeway.applib.layout.grid.bootstrap.BSTabGroup; @@ -42,7 +43,7 @@ * @since 2.0 */ @NoArgsConstructor(access = AccessLevel.PRIVATE) -final class _GridModel { +final class GridModel { private final LinkedHashSet<String> allIds = _Sets.newLinkedHashSet(); private final LinkedHashMap<String, BSRow> rows = _Maps.newLinkedHashMap(); private final LinkedHashMap<String, BSCol> cols = _Maps.newLinkedHashMap(); @@ -77,19 +78,6 @@ Either<BSCol, BSTabGroup> nodeForUnreferencedCollections() { private boolean gridErrorsDetected = false; - public boolean contains(final String id) { - return allIds.contains(id); - } - - public Collection<FieldSet> fieldSets() { - return fieldSets.values(); - } - public boolean containsFieldSetId(final String id) { - return fieldSets.containsKey(id); - } - public FieldSet getFieldSet(final String id) { - return fieldSets.get(id); - } /** * find all row and col ids<br> @@ -99,11 +87,11 @@ public FieldSet getFieldSet(final String id) { * @param bsGrid * @return empty if not valid */ - public static Optional<_GridModel> createFrom(final BSGrid bsGrid) { + public static Optional<GridModel> createFrom(final BSGrid bsGrid) { - var gridModel = new _GridModel(); + var gridModel = new GridModel(); - bsGrid.visit(new BSGrid.VisitorAdapter(){ + bsGrid.visit(new BSElement.Visitor() { @Override public void visit(final BSRow bsRow) { final String id = bsRow.getId(); @@ -154,7 +142,7 @@ public void visit(final FieldSet fieldSet) { return Optional.empty(); } - bsGrid.visit(new BSGrid.VisitorAdapter(){ + bsGrid.visit(new BSElement.Visitor(){ @Override public void visit(final BSCol bsCol) { @@ -234,6 +222,20 @@ public void visit(final BSTabGroup bsTabGroup) { : Optional.empty(); } + public boolean contains(final String id) { + return allIds.contains(id); + } + + public Collection<FieldSet> fieldSets() { + return fieldSets.values(); + } + public boolean containsFieldSetId(final String id) { + return fieldSets.containsKey(id); + } + public FieldSet getFieldSet(final String id) { + return fieldSets.get(id); + } + private void putRow(final String id, final BSRow bsRow) { rows.put(id, bsRow); allIds.add(id); diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridSystemServiceBootstrap.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridSystemServiceBootstrap.java index aafb34fd5ab..25fa8deae96 100644 --- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridSystemServiceBootstrap.java +++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridSystemServiceBootstrap.java @@ -245,6 +245,12 @@ protected boolean validateAndNormalize( var bsGrid = (BSGrid) grid; var objectSpec = specLoaderProvider.get().specForTypeElseFail(domainClass); + var gridModelIfValid = GridModel.createFrom(bsGrid); + if(!gridModelIfValid.isPresent()) { // only present if valid + return false; + } + var gridModel = gridModelIfValid.get(); + var oneToOneAssociationById = ObjectMember.mapById(objectSpec.streamProperties(MixedIn.INCLUDED)); var oneToManyAssociationById = ObjectMember.mapById(objectSpec.streamCollections(MixedIn.INCLUDED)); var objectActionById = ObjectMember.mapById(objectSpec.streamRuntimeActions(MixedIn.INCLUDED)); @@ -253,12 +259,6 @@ protected boolean validateAndNormalize( var collectionLayoutDataById = bsGrid.getAllCollectionsById(); var actionLayoutDataById = bsGrid.getAllActionsById(); - var gridModelIfValid = _GridModel.createFrom(bsGrid); - if(!gridModelIfValid.isPresent()) { // only present if valid - return false; - } - var gridModel = gridModelIfValid.get(); - var layoutDataFactory = LayoutDataFactory.of(objectSpec); // * surplus ... those defined in the grid model but not available with the meta-model @@ -581,13 +581,11 @@ private void addUnreferencedCollectionsTo( }); final BSRow tabRow = new BSRow(); - tabRow.setOwner(bsTab); bsTab.getRows().add(tabRow); final BSCol tabRowCol = new BSCol(); tabRowCol.setSpan(12); tabRowCol.setSize(Size.MD); - tabRowCol.setOwner(tabRow); tabRow.getCols().add(tabRowCol); var collectionLayoutData = layoutFactory.apply(collectionId); diff --git a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/sitemap/SitemapServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/sitemap/SitemapServiceDefault.java index 3aec0af1e3e..3fee7508d78 100644 --- a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/sitemap/SitemapServiceDefault.java +++ b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/sitemap/SitemapServiceDefault.java @@ -36,7 +36,6 @@ import org.apache.causeway.applib.layout.component.ServiceActionLayoutData; import org.apache.causeway.applib.layout.grid.Grid; import org.apache.causeway.applib.layout.menubars.bootstrap.BSMenuBars; -import org.apache.causeway.applib.services.grid.GridService; import org.apache.causeway.applib.services.menu.MenuBarsService; import org.apache.causeway.applib.services.sitemap.SitemapService; import org.apache.causeway.commons.internal.base._NullSafe; @@ -63,7 +62,6 @@ public class SitemapServiceDefault implements SitemapService { private final SpecificationLoader specificationLoader; - private final GridService gridService; private final MenuBarsService menuBarsService; @Override @@ -122,7 +120,7 @@ public String toSitemapAdoc(final String title) { var grid = specificationLoader.specForType(actionElementType.getCorrespondingClass()) .flatMap(Facets::bootstrapGrid) .orElse(null); - grid.visit(new Grid.VisitorAdapter() { + grid.visit(new Grid.Visitor() { @Override public void visit(final ActionLayoutData actionLayoutData) { actionElementType.getAction(actionLayoutData.getId(), ActionScope.PRODUCTION_ONLY) .ifPresent(action->{ diff --git a/extensions/core/docgen/help/src/main/java/org/apache/causeway/extensions/docgen/help/topics/welcome/WelcomeHelpPage.java b/extensions/core/docgen/help/src/main/java/org/apache/causeway/extensions/docgen/help/topics/welcome/WelcomeHelpPage.java index 017bc2064e7..e5d3b2795a1 100644 --- a/extensions/core/docgen/help/src/main/java/org/apache/causeway/extensions/docgen/help/topics/welcome/WelcomeHelpPage.java +++ b/extensions/core/docgen/help/src/main/java/org/apache/causeway/extensions/docgen/help/topics/welcome/WelcomeHelpPage.java @@ -225,7 +225,7 @@ private StringBuffer documentationForObjectType(final ObjectSpecification object html.append("</ul>"); html.append("<ul>"); { - grid.visit(new Grid.VisitorAdapter() { + grid.visit(new Grid.Visitor() { @Override public void visit(final FieldSet fieldSet) { if (_NullSafe.isEmpty(fieldSet.getProperties())) { diff --git a/viewers/restfulobjects/viewer/src/main/java/org/apache/causeway/viewer/restfulobjects/viewer/resources/DomainObjectResourceServerside.java b/viewers/restfulobjects/viewer/src/main/java/org/apache/causeway/viewer/restfulobjects/viewer/resources/DomainObjectResourceServerside.java index 52a54ca69c4..91130c3beb5 100644 --- a/viewers/restfulobjects/viewer/src/main/java/org/apache/causeway/viewer/restfulobjects/viewer/resources/DomainObjectResourceServerside.java +++ b/viewers/restfulobjects/viewer/src/main/java/org/apache/causeway/viewer/restfulobjects/viewer/resources/DomainObjectResourceServerside.java @@ -269,7 +269,7 @@ public static void addLinks( final String instanceId, final Grid grid) { - grid.visit(new Grid.VisitorAdapter() { + grid.visit(new Grid.Visitor() { @Override public void visit(final DomainObjectLayoutData domainObjectLayoutData) { Link link = newLink( diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionlinks/serviceactions/MenuActionPanel.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionlinks/serviceactions/MenuActionPanel.java index 156588b7532..d36b6680028 100644 --- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionlinks/serviceactions/MenuActionPanel.java +++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionlinks/serviceactions/MenuActionPanel.java @@ -24,13 +24,11 @@ import org.apache.wicket.markup.html.list.ListItem; import org.apache.wicket.markup.html.list.ListView; import org.apache.wicket.markup.html.panel.Fragment; - import org.apache.causeway.commons.collections.Can; import org.apache.causeway.viewer.wicket.ui.panels.PanelBase; import org.apache.causeway.viewer.wicket.ui.util.Wkt; -@SuppressWarnings("rawtypes") -abstract class MenuActionPanel extends PanelBase { +abstract class MenuActionPanel extends PanelBase<Object> { private static final long serialVersionUID = 1L; diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/layout/bs/col/Col.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/layout/bs/col/Col.java index f1f181c6ac3..d03666c4faa 100644 --- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/layout/bs/col/Col.java +++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/layout/bs/col/Col.java @@ -34,6 +34,7 @@ import org.apache.causeway.applib.layout.grid.bootstrap.BSRow; import org.apache.causeway.applib.layout.grid.bootstrap.BSTab; import org.apache.causeway.applib.layout.grid.bootstrap.BSTabGroup; +import org.apache.causeway.applib.layout.grid.bootstrap.BSUtil; import org.apache.causeway.commons.collections.Can; import org.apache.causeway.commons.internal.base._NullSafe; import org.apache.causeway.commons.internal.collections._Lists; @@ -156,7 +157,7 @@ private void buildGui() { .filter(_NullSafe::isPresent) .filter(bsTabGroup -> _NullSafe.stream(bsTabGroup.getTabs()) - .anyMatch(BSTab.Predicates.notEmpty()) + .anyMatch(BSUtil::hasContent) ) .collect(Collectors.toList()); @@ -168,7 +169,7 @@ private void buildGui() { final String id = tabGroupRv.newChildId(); final List<BSTab> tabs = _NullSafe.stream(bsTabGroup.getTabs()) - .filter(BSTab.Predicates.notEmpty()) + .filter(BSUtil::hasContent) .collect(Collectors.toList()); switch (tabs.size()) { diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/layout/bs/tabs/TabGroupPanel.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/layout/bs/tabs/TabGroupPanel.java index bc992e0214c..14f3cfa0e19 100644 --- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/layout/bs/tabs/TabGroupPanel.java +++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/layout/bs/tabs/TabGroupPanel.java @@ -30,6 +30,7 @@ import org.apache.causeway.applib.layout.grid.bootstrap.BSTab; import org.apache.causeway.applib.layout.grid.bootstrap.BSTabGroup; +import org.apache.causeway.applib.layout.grid.bootstrap.BSUtil; import org.apache.causeway.commons.internal.base._NullSafe; import org.apache.causeway.viewer.wicket.model.models.UiObjectWkt; import org.apache.causeway.viewer.wicket.model.util.ComponentHintKey; @@ -54,7 +55,7 @@ private static List<ITab> tabsFor(final UiObjectWkt objectModel, final BSTabGrou final List<ITab> tabs = new ArrayList<>(); final List<BSTab> tablist = _NullSafe.stream(bsTabGroup.getTabs()) - .filter(BSTab.Predicates.notEmpty()) + .filter(BSUtil::hasContent) .collect(Collectors.toList()); for (var bsTab : tablist) {
