You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2020/01/05 21:52:33 UTC

[isis] branch master updated: ISIS-2256: fixes selection model running out of sync with checkboxes

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

ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/master by this push:
     new c10d4c1  ISIS-2256: fixes selection model running out of sync with checkboxes
c10d4c1 is described below

commit c10d4c1b6f6d0690f61583c956e667155b8a43bb
Author: Andi Huber <ah...@apache.org>
AuthorDate: Sun Jan 5 22:52:25 2020 +0100

    ISIS-2256: fixes selection model running out of sync with checkboxes
---
 .../wicket/model/models/EntityCollectionModel.java | 25 +++++++++++--------
 .../entityactions/EntityActionLinkFactory.java     |  2 +-
 .../serviceactions/ServiceActionLinkFactory.java   |  2 +-
 .../ui/components/collection/CollectionPanel.java  |  7 +++++-
 .../columns/ObjectAdapterToggleboxColumn.java      | 29 +++++++++++++---------
 .../widgets/checkbox/ContainedToggleboxPanel.java  | 11 ++++++--
 .../linkandlabel/ActionLinkFactoryAbstract.java    |  8 +++---
 7 files changed, 51 insertions(+), 33 deletions(-)

diff --git a/core/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java b/core/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java
index 62a3781..1b998af 100644
--- a/core/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java
+++ b/core/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java
@@ -23,6 +23,7 @@ import java.io.Serializable;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
+import java.util.Map;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -33,6 +34,7 @@ import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._Casts;
 import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.commons.internal.collections._Lists;
+import org.apache.isis.commons.internal.collections._Maps;
 import org.apache.isis.commons.internal.factory.InstanceUtil;
 import org.apache.isis.metamodel.adapter.oid.Oid;
 import org.apache.isis.metamodel.adapter.oid.RootOid;
@@ -345,7 +347,7 @@ implements LinksProvider, UiHintContainer {
     /**
      * Populated only if {@link Type#STANDALONE}.
      */
-    private List<ObjectMemento> toggledMementosList;
+    private Map<String, ObjectMemento> toggledMementos;
 
     /**
      * Populated only if {@link Type#PARENTED}.
@@ -387,7 +389,7 @@ implements LinksProvider, UiHintContainer {
         this.entityModel = entityModel;
         this.typeOf = typeOf;
         this.pageSize = pageSize;
-        this.toggledMementosList = _Lists.<ObjectMemento>newArrayList();
+        this.toggledMementos = _Maps.<String, ObjectMemento>newLinkedHashMap();
     }
 
 
@@ -511,23 +513,24 @@ implements LinksProvider, UiHintContainer {
     }
 
 
-    public void toggleSelectionOn(ManagedObject selectedAdapter) {
+    public boolean toggleSelectionOn(ManagedObject selectedAdapter) {
         //XXX lombok issue, cannot use val here
         final ObjectMemento selectedAsMemento = super.getMementoService().mementoForObject(selectedAdapter);
-
-        // try to remove; if couldn't, then mustn't have been in there, in which case add.
-        boolean removed = toggledMementosList.remove(selectedAsMemento);
-        if(!removed) {
-            toggledMementosList.add(selectedAsMemento);
-        }
+        final String selectedKey = selectedAsMemento.asString(); 
+        final ObjectMemento newValue = 
+                toggledMementos.compute(selectedKey, (k, v) -> (v==null) ? selectedAsMemento : null);
+        
+        final boolean isSelected = newValue!=null;
+        return isSelected;
+        
     }
 
     public Can<ObjectMemento> getToggleMementosList() {
-        return Can.ofCollection(this.toggledMementosList);
+        return Can.ofCollection(this.toggledMementos.values());
     }
 
     public void clearToggleMementosList() {
-        this.toggledMementosList.clear();
+        this.toggledMementos.clear();
     }
 
     public void addLinkAndLabels(List<LinkAndLabel> linkAndLabels) {
diff --git a/core/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/EntityActionLinkFactory.java b/core/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/EntityActionLinkFactory.java
index b817bcf..81a2958 100644
--- a/core/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/EntityActionLinkFactory.java
+++ b/core/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/EntityActionLinkFactory.java
@@ -60,7 +60,7 @@ public final class EntityActionLinkFactory extends ActionLinkFactoryAbstract {
         // previously we computed visibility and enablement here, but
         // this is now done at the point of rendereing
 
-        final AbstractLink link = newLink(linkId, objectAction, toggledMementosProviderIfAny);
+        final AbstractLink link = super.newLink(linkId, objectAction, toggledMementosProviderIfAny);
 
         return newLinkAndLabel(objectAdapter, objectAction, link);
     }
diff --git a/core/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/serviceactions/ServiceActionLinkFactory.java b/core/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/serviceactions/ServiceActionLinkFactory.java
index ce01cee..fa9fed7 100644
--- a/core/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/serviceactions/ServiceActionLinkFactory.java
+++ b/core/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/serviceactions/ServiceActionLinkFactory.java
@@ -45,7 +45,7 @@ class ServiceActionLinkFactory extends ActionLinkFactoryAbstract {
 
         val objectAdapter = this.targetEntityModel.load();
 
-        final AbstractLink link = newLink(linkId, objectAction, toggledMementosProviderIfAny);
+        final AbstractLink link = super.newLink(linkId, objectAction, toggledMementosProviderIfAny);
 
         return newLinkAndLabel(objectAdapter, objectAction, link);
     }
diff --git a/core/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/CollectionPanel.java b/core/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/CollectionPanel.java
index 5a45366..57c4e64 100644
--- a/core/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/CollectionPanel.java
+++ b/core/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/CollectionPanel.java
@@ -44,6 +44,7 @@ import org.apache.isis.viewer.wicket.ui.components.collection.selector.Collectio
 import org.apache.isis.viewer.wicket.ui.components.collection.selector.CollectionSelectorProvider;
 import org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable.columns.ObjectAdapterToggleboxColumn;
 import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelAbstract2;
+import org.apache.isis.viewer.wicket.ui.components.widgets.checkbox.ContainedToggleboxPanel;
 import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
 import org.apache.isis.webapp.context.memento.ObjectMemento;
 
@@ -157,7 +158,11 @@ implements CollectionSelectorProvider, BulkActionsProvider {
                         final Component context,
                         final ManagedObject selectedAdapter,
                         final AjaxRequestTarget ajaxRequestTarget) {
-                    getModel().toggleSelectionOn(selectedAdapter);
+                    
+                    ContainedToggleboxPanel togglePanel = (ContainedToggleboxPanel) context;
+                    
+                    boolean isSelected = getModel().toggleSelectionOn(selectedAdapter);
+                    togglePanel.setModel(isSelected); // sync the checkbox's model
                 }
 
             };
diff --git a/core/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterToggleboxColumn.java b/core/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterToggleboxColumn.java
index 37eb544..a6a1b9f 100644
--- a/core/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterToggleboxColumn.java
+++ b/core/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterToggleboxColumn.java
@@ -69,18 +69,26 @@ public final class ObjectAdapterToggleboxColumn extends ColumnAbstract<ManagedOb
     @Override
     public Component getHeader(String componentId) {
 
-        final ContainedToggleboxPanel toggle = new ContainedToggleboxPanel(componentId) {
+        final ContainedToggleboxPanel bulkToggle = new ContainedToggleboxPanel(componentId) {
             private static final long serialVersionUID = 1L;
             @Override
             public void onSubmit(AjaxRequestTarget target) {
-                for (ContainedToggleboxPanel toggle : rowToggles) {
-                    toggle.toggle(target);
-                    target.add(toggle);
+                final boolean setToChecked = !this.isChecked();
+                
+                for (ContainedToggleboxPanel rowToggle : rowToggles) {
+                    
+                    // smart update idiom: only toggle when needed
+                    if(setToChecked == rowToggle.isChecked()) {
+                        continue;
+                    }
+                    
+                    rowToggle.toggle(target);
+                    target.add(rowToggle);
                 }
             }
         };
-        toggle.add(new CssClassAppender("title-column"));
-        return toggle;
+        bulkToggle.add(new CssClassAppender("title-column"));
+        return bulkToggle;
     }
 
     private final List<ContainedToggleboxPanel> rowToggles = _Lists.newArrayList();
@@ -101,12 +109,9 @@ public final class ObjectAdapterToggleboxColumn extends ColumnAbstract<ManagedOb
             @Override
             public void onSubmit(AjaxRequestTarget target) {
                 val entityModel = (EntityModel) rowModel;
-                ManagedObject selectedAdapter = null;
-                {
-                    selectedAdapter = entityModel.load();
-                    if(onSelectionHandler != null) {
-                        onSelectionHandler.onSelected(this, selectedAdapter, target);
-                    }
+                val selectedAdapter = entityModel.load();
+                if(onSelectionHandler != null) {
+                    onSelectionHandler.onSelected(this, selectedAdapter, target);
                 }
             }
         };
diff --git a/core/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/checkbox/ContainedToggleboxPanel.java b/core/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/checkbox/ContainedToggleboxPanel.java
index aa5e643..12302ea 100644
--- a/core/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/checkbox/ContainedToggleboxPanel.java
+++ b/core/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/checkbox/ContainedToggleboxPanel.java
@@ -77,9 +77,16 @@ public class ContainedToggleboxPanel extends PanelAbstract<Model<Boolean>> {
      * @param target
      */
     public void toggle(AjaxRequestTarget target) {
-        checkbox.setModelObject(!checkbox.getModelObject());
-        final boolean checkboxValue = checkbox.getModelObject();
+        setModel(!isChecked());
         onSubmit(target);
     }
+    
+    public boolean isChecked() {
+        return checkbox.getModelObject();
+    }
+
+    public void setModel(boolean isChecked) {
+        checkbox.setModelObject(isChecked);
+    }
 
 }
diff --git a/core/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/linkandlabel/ActionLinkFactoryAbstract.java b/core/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/linkandlabel/ActionLinkFactoryAbstract.java
index 9c92a41..49858a0 100644
--- a/core/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/linkandlabel/ActionLinkFactoryAbstract.java
+++ b/core/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/linkandlabel/ActionLinkFactoryAbstract.java
@@ -17,9 +17,6 @@
 
 package org.apache.isis.viewer.wicket.ui.components.widgets.linkandlabel;
 
-import java.io.Serializable;
-import java.util.function.Function;
-
 import org.apache.wicket.Application;
 import org.apache.wicket.MarkupContainer;
 import org.apache.wicket.Page;
@@ -107,8 +104,9 @@ public abstract class ActionLinkFactoryAbstract implements ActionLinkFactory {
                     val actionPrompt = ActionParameterDefaultsFacetFromAssociatedCollection
                             .applyWithSelected(
                                     selectedPojos,
-                                    //TODO[2253] can we remove the Serializable cast? 
-                                    (Function<AjaxRequestTarget, ActionPrompt>&Serializable) this::performOnClick,
+                                    // if this lambda still needs to be serializable uncomment the cast ... 
+                                    //(Function<AjaxRequestTarget, ActionPrompt>&Serializable) 
+                                    this::performOnClick,
                                     target);
                     
                     if(actionPrompt != null) {