You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@causeway.apache.org by ah...@apache.org on 2023/09/20 09:18:31 UTC

[causeway] branch 3582-autoalign.dropdown.links updated: CAUSEWAY-3582: let CssMenuItem implement Menuable

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch 3582-autoalign.dropdown.links
in repository https://gitbox.apache.org/repos/asf/causeway.git


The following commit(s) were added to refs/heads/3582-autoalign.dropdown.links by this push:
     new efede463ab CAUSEWAY-3582: let CssMenuItem implement Menuable
efede463ab is described below

commit efede463ab37f54742116885f419480921bbc2d7
Author: Andi Huber <ah...@apache.org>
AuthorDate: Wed Sep 20 11:18:27 2023 +0200

    CAUSEWAY-3582: let CssMenuItem implement Menuable
---
 .../viewer/wicket/model/links/Menuable.java        |  3 +-
 .../actionmenu/serviceactions/CssMenuItem.java     | 59 ++++++++------------
 .../actionmenu/serviceactions/MenuActionPanel.java |  4 +-
 .../serviceactions/ServiceActionUtil.java          | 10 ++--
 .../CollectionPresentationSelectorPanel.java       | 62 +++++++++++-----------
 .../ui/components/collection/selector/_Util.java   | 43 ++++++---------
 6 files changed, 76 insertions(+), 105 deletions(-)

diff --git a/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/links/Menuable.java b/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/links/Menuable.java
index 955fddca8e..a7e8b03538 100644
--- a/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/links/Menuable.java
+++ b/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/links/Menuable.java
@@ -34,7 +34,8 @@ public interface Menuable extends Serializable {
     public enum Kind {
         SECTION_SEPARATOR("list-separator"),
         SECTION_LABEL("list-section-label"),
-        LINK("viewItem");
+        LINK("viewItem"),
+        SUBMENU(null);
         @Getter private final String cssClassForLiElement;
         public boolean isSectionSeparator() { return this==SECTION_SEPARATOR;}
         public boolean isSectionLabel() { return this==SECTION_LABEL;}
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/serviceactions/CssMenuItem.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/serviceactions/CssMenuItem.java
index 399c3d6cd1..1666f1d681 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/serviceactions/CssMenuItem.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/serviceactions/CssMenuItem.java
@@ -16,7 +16,6 @@
  * under the License. */
 package org.apache.causeway.viewer.wicket.ui.components.actionmenu.serviceactions;
 
-import java.io.Serializable;
 import java.util.Collections;
 import java.util.List;
 
@@ -29,6 +28,7 @@ import org.apache.causeway.commons.internal.base._Casts;
 import org.apache.causeway.commons.internal.collections._Lists;
 import org.apache.causeway.core.metamodel.spec.feature.ObjectAction;
 import org.apache.causeway.viewer.wicket.model.links.LinkAndLabel;
+import org.apache.causeway.viewer.wicket.model.links.Menuable;
 import org.apache.causeway.viewer.wicket.ui.util.Wkt;
 import org.apache.causeway.viewer.wicket.ui.util.WktComponents;
 import org.apache.causeway.viewer.wicket.ui.util.WktDecorators;
@@ -37,34 +37,43 @@ import org.apache.causeway.viewer.wicket.ui.util.WktTooltips;
 import lombok.Getter;
 import lombok.Setter;
 import lombok.val;
+import lombok.experimental.Accessors;
 
 class CssMenuItem
-implements Serializable {
+implements Menuable {
 
     private static final long serialVersionUID = 1L;
     private static final String ID_MENU_LINK = "menuLink";
     private static final String ID_MENU_LABEL = "menuLabel";
     private static final String ID_SUB_MENU_ITEMS = "subMenuItems";
 
-    public static CssMenuItem newMenuItem(final String name) {
-        return new CssMenuItem(name, MenuItemType.ACTION_OR_SUBMENU_CONTAINER);
+    public static CssMenuItem newMenuItemWithLink(final String name) {
+        return new CssMenuItem(name, Menuable.Kind.LINK);
+    }
+
+    public static CssMenuItem newMenuItemWithSubmenu(final String name) {
+        return new CssMenuItem(name, Menuable.Kind.SUBMENU);
+    }
+
+    //TODO[CAUSEWAY-3582] perhaps use Menuables from model instead
+    public static CssMenuItem newSpacer() {
+        return new CssMenuItem("---", Menuable.Kind.SECTION_SEPARATOR);
+    }
+
+    //TODO[CAUSEWAY-3582] perhaps use Menuables from model instead
+    public static CssMenuItem newSectionLabel(final String named) {
+        return new CssMenuItem(named, Menuable.Kind.SECTION_LABEL);
     }
 
     @Getter private final String name;
 
     @Getter @Setter private LinkAndLabel linkAndLabel;
 
-    private CssMenuItem(final String name, final MenuItemType itemType) {
+    private CssMenuItem(final String name, final Menuable.Kind menuableKind) {
         this.name = name;
-        this.itemType = itemType;
+        this.menuableKind = menuableKind;
     }
 
-//    protected CssMenuItem newSubMenuItem(final String name, final MenuItemType itemType) {
-//        val subMenuItem = newMenuItem(name);
-//        subMenuItem.setParent(this);
-//        return subMenuItem;
-//    }
-
     private final List<CssMenuItem> subMenuItems = _Lists.newArrayList();
     protected void addSubMenuItem(final CssMenuItem cssMenuItem) {
         subMenuItems.add(cssMenuItem);
@@ -179,29 +188,7 @@ implements Serializable {
         return parent != null;
     }
 
-    // -- SUPPORT FOR SPECIAL MENU ITEMS
-
-    public enum MenuItemType {
-        SPACER,
-        SECTION_LABEL,
-        ACTION_OR_SUBMENU_CONTAINER;
-
-        boolean isActionOrSubMenuContainer() {
-            return this == ACTION_OR_SUBMENU_CONTAINER;
-        }
-    }
-
-    @Getter
-    private final MenuItemType itemType;
-
-    public static CssMenuItem newSpacer() {
-        return new CssMenuItem("---", MenuItemType.SPACER);
-    }
-
-    public static CssMenuItem newSectionLabel(final String named) {
-        return new CssMenuItem(named, MenuItemType.SECTION_LABEL);
-    }
-
-
+    @Getter(onMethod_={@Override}) @Accessors(fluent=true)
+    private final Menuable.Kind menuableKind;
 
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/serviceactions/MenuActionPanel.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/serviceactions/MenuActionPanel.java
index 9855ea9a38..d753c2a082 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/serviceactions/MenuActionPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/serviceactions/MenuActionPanel.java
@@ -44,8 +44,8 @@ public abstract class MenuActionPanel extends PanelBase {
         return Wkt.listView("subMenuItems", subMenuItems, listItem->{
             val subMenuItem = listItem.getModelObject();
 
-            switch(subMenuItem.getItemType()) {
-            case SPACER:
+            switch(subMenuItem.menuableKind()) {
+            case SECTION_SEPARATOR:
                 addSpacer(subMenuItem, listItem);
                 return;
             case SECTION_LABEL:
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/serviceactions/ServiceActionUtil.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/serviceactions/ServiceActionUtil.java
index 8b58620648..e61ce2538c 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/serviceactions/ServiceActionUtil.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/serviceactions/ServiceActionUtil.java
@@ -105,7 +105,7 @@ public final class ServiceActionUtil {
 
         @Override
         public void addTopLevel(final MenuItemDto menuDto) {
-            currentTopLevelMenu = CssMenuItem.newMenuItem(menuDto.getName());
+            currentTopLevelMenu = CssMenuItem.newMenuItemWithSubmenu(menuDto.getName());
             onNewMenuItem.accept(currentTopLevelMenu);
         }
 
@@ -119,7 +119,7 @@ public final class ServiceActionUtil {
         public void addSubMenu(final MenuItemDto menuDto) {
             val managedAction = menuDto.getManagedAction();
 
-            val menuItem = CssMenuItem.newMenuItem(menuDto.getName());
+            val menuItem = CssMenuItem.newMenuItemWithLink(menuDto.getName());
             currentTopLevelMenu.addSubMenuItem(menuItem);
 
             menuItem.setLinkAndLabel(newActionLink(managedAction));
@@ -131,15 +131,11 @@ public final class ServiceActionUtil {
             currentTopLevelMenu.addSubMenuItem(menuSectionLabel);
         }
 
-        private LinkAndLabel newActionLink(
-                final ManagedAction managedAction) {
-
+        private LinkAndLabel newActionLink(final ManagedAction managedAction) {
             val serviceModel = UiObjectWkt.ofAdapter(commonContext, managedAction.getOwner());
-
             return LinkAndLabelFactory.forMenu(serviceModel)
                     .apply(managedAction.getAction());
         }
-
     }
 
     public static void buildMenu(
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collection/selector/CollectionPresentationSelectorPanel.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collection/selector/CollectionPresentationSelectorPanel.java
index 489935ae0f..b9b837811e 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collection/selector/CollectionPresentationSelectorPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collection/selector/CollectionPresentationSelectorPanel.java
@@ -154,8 +154,8 @@ extends PanelAbstract<DataTableModel, EntityCollectionModel> {
                 return;
             }
 
-            val repeatedViewEntry = (RepeatedViewEntry) menuable;
-            final ComponentFactory componentFactory = repeatedViewEntry.getComponentFactory();
+            val linkEntry = (LinkEntry) menuable;
+            final ComponentFactory componentFactory = linkEntry.getComponentFactory();
 
             // add direct download link instead of a panel
             if(componentFactory.getComponentType() == UiComponentType.COLLECTION_CONTENTS_EXPORT) {
@@ -167,7 +167,7 @@ extends PanelAbstract<DataTableModel, EntityCollectionModel> {
                 item.addOrReplace(downloadLink);
 
                 // add title and icon to the link
-                RepeatedViewEntry.addLinkWithIconAndTitle(item, downloadLink);
+                addLinkWithIconAndTitle(item, downloadLink);
                 return;
             }
 
@@ -183,7 +183,7 @@ extends PanelAbstract<DataTableModel, EntityCollectionModel> {
 
                 /* [CAUSEWAY-3415] do a full page reload when required,
                  * to properly trigger all client side java-script, that decorates HTML (datatable.net, vega, ...) */
-                if(repeatedViewEntry.isPageReloadRequiredOnTableViewActivation()) {
+                if(linkEntry.isPageReloadRequiredOnTableViewActivation()) {
                     linksSelectorPanel.reloadPage();
                 } else {
                     target.add(linksSelectorPanel, views);
@@ -191,15 +191,13 @@ extends PanelAbstract<DataTableModel, EntityCollectionModel> {
             });
 
             // add title and icon to the link
-            RepeatedViewEntry.addLinkWithIconAndTitle(item, link);
+            addLinkWithIconAndTitle(item, link);
             val checkmarkForSelectedPresentation = Wkt.labelAdd(link, ID_VIEW_ITEM_CHECKMARK, "");
 
-            val isSelectedPresentation = repeatedViewEntry.isSelectedIn(this);
+            val isSelectedPresentation = linkEntry.isSelectedIn(this);
             checkmarkForSelectedPresentation.setVisible(isSelectedPresentation);
-
-            // if selected, disable the link
             if (isSelectedPresentation) {
-                repeatedViewEntry.markAsSelected(viewButtonIcon, link);
+                linkEntry.markAsSelected(viewButtonIcon, link);
             }
 
         });
@@ -237,13 +235,13 @@ extends PanelAbstract<DataTableModel, EntityCollectionModel> {
         return sortedWithSeparators;
     }
 
-    private List<RepeatedViewEntry> sorted(
+    private List<LinkEntry> sorted(
             final Can<ComponentFactory> componentFactories,
             final Predicate<? super ComponentFactory> filter) {
-        final List<RepeatedViewEntry> sorted = componentFactories.stream()
+        final List<LinkEntry> sorted = componentFactories.stream()
             .filter(filter)
             .sorted(_Util.orderByOrderOfAppearanceInUiDropdown())
-            .map((final ComponentFactory factory)->RepeatedViewEntry.linkEntry(factory))
+            .map((final ComponentFactory factory)->LinkEntry.linkEntry(factory))
             .collect(Collectors.toList());
         return sorted;
     }
@@ -254,16 +252,25 @@ extends PanelAbstract<DataTableModel, EntityCollectionModel> {
                 new CausewaySelectorEvent(component, CollectionPresentationSelectorHelper.UIHINT_EVENT_VIEW_KEY, viewName, target));
     }
 
+    // -- UTILITY
 
+    static void addLinkWithIconAndTitle(
+            final @NonNull ListItem<? extends Menuable> item,
+            final @NonNull MarkupContainer link) {
+        WktLinks.listItemAsDropdownLink((ListItem<LinkEntry>)item, link,
+                ID_VIEW_ITEM_TITLE, LinkEntry::nameFor,
+                ID_VIEW_ITEM_ICON, null,
+                LinkEntry::cssClassFor);
+    }
 
     @lombok.Value
-    static class RepeatedViewEntry implements Menuable {
+    static class LinkEntry implements Menuable {
         private static final long serialVersionUID = 1L;
 
         // -- FACTORIES
 
-        public static RepeatedViewEntry linkEntry(final @NonNull ComponentFactory componentFactory) {
-            return new RepeatedViewEntry(componentFactory);
+        public static LinkEntry linkEntry(final @NonNull ComponentFactory componentFactory) {
+            return new LinkEntry(componentFactory);
         }
 
         // -- CONSTRUCTION
@@ -279,32 +286,23 @@ extends PanelAbstract<DataTableModel, EntityCollectionModel> {
             return _Util.isPageReloadRequiredOnTableViewActivation(componentFactory);
         }
 
-        // -- UPDATE STATE
-
+        /**
+         * Disables the link the selected presentation's link,
+         * also sets the icon left of the drop-down caret.
+         */
         void markAsSelected(final Label viewButtonIcon, final AjaxLinkNoPropagate link) {
             final IModel<String> cssClass = _Util.cssClassFor(componentFactory, viewButtonIcon);
             Wkt.cssReplace(viewButtonIcon, "ViewLinkItem " + cssClass.getObject());
             link.setEnabled(false);
         }
 
-        // -- UTILITY
-
-        static void addLinkWithIconAndTitle(
-                final @NonNull ListItem<? extends Menuable> item,
-                final @NonNull MarkupContainer link) {
-            WktLinks.listItemAsDropdownLink((ListItem<RepeatedViewEntry>)item, link,
-                    ID_VIEW_ITEM_TITLE, RepeatedViewEntry::nameFor,
-                    ID_VIEW_ITEM_ICON, null,
-                    RepeatedViewEntry::cssClassFor);
-        }
-
         // -- HELPER
 
-        private static IModel<String> nameFor(final RepeatedViewEntry either) {
-            return _Util.nameFor(either.getComponentFactory());
+        private static IModel<String> nameFor(final LinkEntry linkEntry) {
+            return _Util.nameFor(linkEntry.getComponentFactory());
         }
-        private static IModel<String> cssClassFor(final RepeatedViewEntry either, final Label viewIcon) {
-            return _Util.cssClassFor(either.getComponentFactory(), viewIcon);
+        private static IModel<String> cssClassFor(final LinkEntry linkEntry, final Label viewIcon) {
+            return _Util.cssClassFor(linkEntry.getComponentFactory(), viewIcon);
         }
 
         @Override
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collection/selector/_Util.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collection/selector/_Util.java
index aa8bca97f1..4bca7665f5 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collection/selector/_Util.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collection/selector/_Util.java
@@ -25,47 +25,36 @@ import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.Model;
 
+import org.apache.causeway.commons.internal.base._Casts;
 import org.apache.causeway.commons.internal.base._Strings;
 import org.apache.causeway.viewer.commons.model.components.UiComponentType;
 import org.apache.causeway.viewer.wicket.ui.CollectionContentsAsFactory;
 import org.apache.causeway.viewer.wicket.ui.ComponentFactory;
 
-import lombok.val;
 import lombok.experimental.UtilityClass;
 
 @UtilityClass
 class _Util {
 
     IModel<String> nameFor(final ComponentFactory componentFactory) {
-        IModel<String> name = null;
-        if (componentFactory instanceof CollectionContentsAsFactory) {
-            val collectionContentsAsFactory = (CollectionContentsAsFactory) componentFactory;
-            name = collectionContentsAsFactory.getTitleLabel();
-        }
-        if (name == null) {
-            name = Model.of(componentFactory.getName());
-        }
-        return name;
+        return _Casts.castTo(CollectionContentsAsFactory.class, componentFactory)
+            .map(CollectionContentsAsFactory::getTitleLabel)
+            .orElseGet(()->Model.of(componentFactory.getName()));
     }
 
     IModel<String> cssClassFor(final ComponentFactory componentFactory, final Label viewIcon) {
-        IModel<String> cssClass = null;
-        if (componentFactory instanceof CollectionContentsAsFactory) {
-            val collectionContentsAsFactory = (CollectionContentsAsFactory) componentFactory;
-            cssClass = collectionContentsAsFactory.getCssClass();
-            viewIcon.setDefaultModelObject("");
-            viewIcon.setEscapeModelStrings(true);
-        }
-        if (cssClass == null) {
-            String name = componentFactory.getName();
-            cssClass = Model.of(_Strings.asLowerDashed.apply(name));
-            // Small hack: if there is no specific CSS class then we assume that background-image is used
-            // the span.ViewItemLink should have some content to show it
-            // FIX: find a way to do this with CSS (width and height don't seems to help)
-            viewIcon.setDefaultModelObject("&#160;&#160;&#160;&#160;&#160;");
-            viewIcon.setEscapeModelStrings(false);
-        }
-        return cssClass;
+        return _Casts.castTo(CollectionContentsAsFactory.class, componentFactory)
+            .map(CollectionContentsAsFactory::getCssClass)
+            .map(cssClass->{
+                viewIcon.setDefaultModelObject("");
+                viewIcon.setEscapeModelStrings(true);
+                return cssClass;
+            })
+            .orElseGet(()->{
+                viewIcon.setDefaultModelObject("&#160;&#160;&#160;&#160;&#160;");
+                viewIcon.setEscapeModelStrings(false);
+                return Model.of(_Strings.asLowerDashed.apply(componentFactory.getName()));
+            });
     }
 
     int orderOfAppearanceInUiDropdownFor(final ComponentFactory componentFactory) {