You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2014/02/06 15:53:25 UTC

git commit: ISIS-691: improved null handling for drop-down lists

Updated Branches:
  refs/heads/master 2cb6f17c9 -> 325fc45c7


ISIS-691: improved null handling for drop-down lists

- for entity refs, if null, shouldn't default to showing the first in list
- for values (enums), should be able to set to null (in list, the blank line)
- get rid of clear link for entity refs, instead set by choosing from list, same as the value drop-down


Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/325fc45c
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/325fc45c
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/325fc45c

Branch: refs/heads/master
Commit: 325fc45c717165624aca945c43f2b155a7ab1e89
Parents: 2cb6f17
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Thu Feb 6 14:53:03 2014 +0000
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Thu Feb 6 14:53:03 2014 +0000

----------------------------------------------------------------------
 .../viewer/dnd/tck/dependency-reduced-pom.xml   | 143 -------------------
 .../model/mementos/ObjectAdapterMemento.java    |   6 +-
 .../model/models/ScalarModelWithPending.java    |  16 ++-
 .../ObjectAdapterMementoProviderAbstract.java   |  24 +++-
 .../entitylink/EntityLinkSelect2Panel.html      |   5 -
 .../entitylink/EntityLinkSelect2Panel.java      |  44 ++----
 .../valuechoices/ValueChoicesSelect2Panel.java  |  35 +++--
 .../specimpl/ObjectActionParameterAbstract.java |   8 +-
 .../core/progmodel/facets/CollectionUtils.java  |   2 +-
 .../collection/ObjectToAdapterFunction.java     |   2 +-
 .../adaptermanager/AdapterManagerDefault.java   |   3 +
 .../dom/src/main/java/dom/todo/ToDoItem.java    |   8 +-
 .../java/dom/todo/ToDoItemContributions.java    |   3 +-
 ...oDoItemContributionsTest_updateCategory.java |   3 +-
 14 files changed, 80 insertions(+), 222 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/325fc45c/component/viewer/dnd/tck/dependency-reduced-pom.xml
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/tck/dependency-reduced-pom.xml b/component/viewer/dnd/tck/dependency-reduced-pom.xml
deleted file mode 100644
index 232a656..0000000
--- a/component/viewer/dnd/tck/dependency-reduced-pom.xml
+++ /dev/null
@@ -1,143 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-  <parent>
-    <artifactId>isis-core-tck</artifactId>
-    <groupId>org.apache.isis.core</groupId>
-    <version>1.4.0-SNAPSHOT</version>
-    <relativePath>../../../../core/tck/pom.xml</relativePath>
-  </parent>
-  <modelVersion>4.0.0</modelVersion>
-  <groupId>org.apache.isis.viewer</groupId>
-  <artifactId>isis-viewer-dnd-tck</artifactId>
-  <name>Isis Drag-n-Drop Viewer TCK tests</name>
-  <build>
-    <plugins>
-      <plugin>
-        <artifactId>maven-shade-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>shade</goal>
-            </goals>
-            <configuration>
-              <transformers>
-                <transformer>
-                  <mainClass>org.apache.isis.Isis</mainClass>
-                </transformer>
-              </transformers>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-    </plugins>
-  </build>
-  <profiles>
-    <profile>
-      <id>exec-dnd</id>
-      <build>
-        <plugins>
-          <plugin>
-            <artifactId>maven-antrun-plugin</artifactId>
-            <version>1.6</version>
-            <executions>
-              <execution>
-                <goals>
-                  <goal>run</goal>
-                </goals>
-                <configuration>
-                  <tasks>
-                    <exec>
-                      <arg />
-                      <arg />
-                      <arg />
-                      <arg />
-                      <arg />
-                      <arg />
-                    </exec>
-                  </tasks>
-                </configuration>
-              </execution>
-            </executions>
-            <configuration>
-              <tasks>
-                <exec>
-                  <arg />
-                  <arg />
-                  <arg />
-                  <arg />
-                  <arg />
-                  <arg />
-                </exec>
-              </tasks>
-            </configuration>
-          </plugin>
-        </plugins>
-      </build>
-    </profile>
-  </profiles>
-  <dependencies>
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <version>4.11</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.jmock</groupId>
-      <artifactId>jmock-junit4</artifactId>
-      <version>2.6.0</version>
-      <scope>test</scope>
-      <exclusions>
-        <exclusion>
-          <artifactId>junit-dep</artifactId>
-          <groupId>junit</groupId>
-        </exclusion>
-        <exclusion>
-          <artifactId>jmock</artifactId>
-          <groupId>org.jmock</groupId>
-        </exclusion>
-      </exclusions>
-    </dependency>
-    <dependency>
-      <groupId>org.jmock</groupId>
-      <artifactId>jmock-legacy</artifactId>
-      <version>2.6.0</version>
-      <scope>test</scope>
-      <exclusions>
-        <exclusion>
-          <artifactId>cglib-nodep</artifactId>
-          <groupId>cglib</groupId>
-        </exclusion>
-        <exclusion>
-          <artifactId>objenesis</artifactId>
-          <groupId>org.objenesis</groupId>
-        </exclusion>
-        <exclusion>
-          <artifactId>jmock</artifactId>
-          <groupId>org.jmock</groupId>
-        </exclusion>
-      </exclusions>
-    </dependency>
-    <dependency>
-      <groupId>cglib</groupId>
-      <artifactId>cglib-nodep</artifactId>
-      <version>2.2.2</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.objenesis</groupId>
-      <artifactId>objenesis</artifactId>
-      <version>1.3</version>
-      <scope>test</scope>
-    </dependency>
-  </dependencies>
-  <properties>
-    <relativeUrl>dnd-tck/</relativeUrl>
-    <isis-objectstore-xml.version>1.0.0-SNAPSHOT</isis-objectstore-xml.version>
-    <siteBaseDir>..</siteBaseDir>
-    <distMgmtSiteUrl>file:///tmp/m2-sites/isis/viewer/dnd</distMgmtSiteUrl>
-    <isis-viewer-dnd.version>1.0.0-SNAPSHOT</isis-viewer-dnd.version>
-  </properties>
-</project>
-

http://git-wip-us.apache.org/repos/asf/isis/blob/325fc45c/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/ObjectAdapterMemento.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/ObjectAdapterMemento.java b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/ObjectAdapterMemento.java
index d6140f9..58f5a66 100644
--- a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/ObjectAdapterMemento.java
+++ b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/ObjectAdapterMemento.java
@@ -42,7 +42,6 @@ import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
 import org.apache.isis.core.runtime.memento.Memento;
 import org.apache.isis.core.runtime.system.context.IsisContext;
 import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
-import org.apache.isis.viewer.wicket.model.util.OidMatchers;
 
 public class ObjectAdapterMemento implements Serializable {
 
@@ -223,7 +222,7 @@ public class ObjectAdapterMemento implements Serializable {
     private Memento transientMemento;
 
     private ObjectAdapterMemento(final RootOid rootOid) {
-        Ensure.ensureThatArg(rootOid, OidMatchers.isPersistent());
+        Ensure.ensureThatArg(rootOid, Oid.Matchers.isPersistent());
         this.persistentOidStr = rootOid.enString(getOidMarshaller());
         this.objectSpecId = rootOid.getObjectSpecId();
         this.type = Type.PERSISTENT;
@@ -326,6 +325,9 @@ public class ObjectAdapterMemento implements Serializable {
         // ignoring the concurrency checking
         final ObjectAdapter currAdapter = getObjectAdapter(ConcurrencyChecking.NO_CHECK);
         for (ObjectAdapterMemento each : list) {
+            if(each == null) {
+                continue;
+            }
             final ObjectAdapter otherAdapter = each.getObjectAdapter(ConcurrencyChecking.NO_CHECK);
             if(currAdapter == otherAdapter) {
                 return true;

http://git-wip-us.apache.org/repos/asf/isis/blob/325fc45c/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModelWithPending.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModelWithPending.java b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModelWithPending.java
index 47b4455..d153f08 100644
--- a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModelWithPending.java
+++ b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModelWithPending.java
@@ -22,6 +22,7 @@ import org.apache.wicket.model.Model;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager.ConcurrencyChecking;
 import org.apache.isis.viewer.wicket.model.mementos.ObjectAdapterMemento;
 
@@ -70,15 +71,20 @@ public interface ScalarModelWithPending extends Serializable {
                         LOG.debug("setting to: " + adapterMemento!=null?adapterMemento.toString():null);
                     }
                     owner.setPending(adapterMemento);
-                    if (owner.getScalarModel() != null && owner.getPending() != null) {
-                        if (LOG.isDebugEnabled()) {
-                            LOG.debug("setting to pending: " + owner.getPending().toString());
+                    if (owner.getScalarModel() != null) {
+                        if(adapterMemento == null) {
+                            owner.getScalarModel().setObject((ObjectAdapter)null);
+                        } else {
+                            if (owner.getPending() != null) {
+                                if (LOG.isDebugEnabled()) {
+                                    LOG.debug("setting to pending: " + owner.getPending().toString());
+                                }
+                                owner.getScalarModel().setObject(owner.getPending().getObjectAdapter(ConcurrencyChecking.NO_CHECK));
+                            }
                         }
-                        owner.getScalarModel().setObject(owner.getPending().getObjectAdapter(ConcurrencyChecking.NO_CHECK));
                     }
                 }
             };
         }
-
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/325fc45c/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/ObjectAdapterMementoProviderAbstract.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/ObjectAdapterMementoProviderAbstract.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/ObjectAdapterMementoProviderAbstract.java
index ebf4db0..a55a20f 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/ObjectAdapterMementoProviderAbstract.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/ObjectAdapterMementoProviderAbstract.java
@@ -21,32 +21,45 @@ import java.util.List;
 
 import com.google.common.base.Function;
 import com.google.common.collect.Collections2;
+import com.google.common.collect.Lists;
 import com.vaynberg.wicket.select2.TextChoiceProvider;
 
 import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager.ConcurrencyChecking;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
 import org.apache.isis.core.metamodel.adapter.oid.RootOidDefault;
 import org.apache.isis.viewer.wicket.model.mementos.ObjectAdapterMemento;
+import org.apache.isis.viewer.wicket.model.models.ScalarModel;
 
 public abstract class ObjectAdapterMementoProviderAbstract extends TextChoiceProvider<ObjectAdapterMemento> {
+
     private static final long serialVersionUID = 1L;
+    
+    private static final String NULL_PLACEHOLDER = "$$_isis_null_$$";
+    private static final String NULL_DISPLAY_TEXT = "";
+
+    private final ScalarModel scalarModel;
 
-    public ObjectAdapterMementoProviderAbstract(){}
+    public ObjectAdapterMementoProviderAbstract(final ScalarModel scalarModel){
+        this.scalarModel = scalarModel;}
     
     @Override
     protected String getDisplayText(ObjectAdapterMemento choice) {
-        return choice.getObjectAdapter(ConcurrencyChecking.NO_CHECK).titleString(null);
+        return choice != null? choice.getObjectAdapter(ConcurrencyChecking.NO_CHECK).titleString(null) : NULL_DISPLAY_TEXT;
     }
 
     @Override
     protected Object getId(ObjectAdapterMemento choice) {
-        return choice.toString();
+        return choice != null? choice.toString(): NULL_PLACEHOLDER;
     }
 
     @Override
     public void query(String term, int page, com.vaynberg.wicket.select2.Response<ObjectAdapterMemento> response) {
         
-        List<ObjectAdapterMemento> mementos = obtainMementos(term);
+        final List<ObjectAdapterMemento> mementos = Lists.newArrayList(obtainMementos(term));
+        // if not mandatory, and the list doesn't contain null already, then add it in.
+        if(!scalarModel.isRequired() && !mementos.contains(null)) {
+            mementos.add(0, null);
+        }
         response.addAll(mementos);
     }
 
@@ -58,6 +71,9 @@ public abstract class ObjectAdapterMementoProviderAbstract extends TextChoicePro
 
             @Override
             public ObjectAdapterMemento apply(String input) {
+                if(NULL_PLACEHOLDER.equals(input)) {
+                    return null;
+                }
                 final RootOid oid = RootOidDefault.deString(input, ObjectAdapterMemento.getOidMarshaller());
                 return ObjectAdapterMemento.createPersistent(oid);
             }

http://git-wip-us.apache.org/repos/asf/isis/blob/325fc45c/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/entitylink/EntityLinkSelect2Panel.html
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/entitylink/EntityLinkSelect2Panel.html b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/entitylink/EntityLinkSelect2Panel.html
index a46232b..fc8df46 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/entitylink/EntityLinkSelect2Panel.html
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/entitylink/EntityLinkSelect2Panel.html
@@ -33,11 +33,6 @@
 				<div>
 					<input wicket:id="autoComplete" type="hidden" class="autoComplete" />
 					<span wicket:id="entityIconAndTitle">[icon and title]</span>
-					<div>
-						<a href="#" wicket:id="entityClearLink" class="entityClearLink">
-							<span>clear</span>
-						</a>
-					</div>
 				    <div class="clear"/>
 	  			</div>
 			</div>

http://git-wip-us.apache.org/repos/asf/isis/blob/325fc45c/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/entitylink/EntityLinkSelect2Panel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/entitylink/EntityLinkSelect2Panel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/entitylink/EntityLinkSelect2Panel.java
index ddebba3..9388f32 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/entitylink/EntityLinkSelect2Panel.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/entitylink/EntityLinkSelect2Panel.java
@@ -67,8 +67,6 @@ public class EntityLinkSelect2Panel extends FormComponentPanelAbstract<ObjectAda
 
     private static final String ID_ENTITY_ICON_AND_TITLE = "entityIconAndTitle";
 
-    private static final String ID_ENTITY_CLEAR_LINK = "entityClearLink";
-    
     /**
      * This component may be null if there are no choices or autoComplete, or if in read-only mode.
      */
@@ -188,11 +186,7 @@ public class EntityLinkSelect2Panel extends FormComponentPanelAbstract<ObjectAda
         final ObjectAdapter adapter = getPendingElseCurrentAdapter();
 
         syncLinkWithInput(adapter);
-
-        syncEntityClearLinksWithInput(adapter);
-
         doSyncWithInputIfAutoCompleteOrChoices();
-        
         syncVisibilityAndUsability();
     }
 
@@ -252,7 +246,7 @@ public class EntityLinkSelect2Panel extends FormComponentPanelAbstract<ObjectAda
 
     private ChoiceProvider<ObjectAdapterMemento> providerForObjectAutoComplete() {
         final EntityModel entityModel = getScalarModel();
-        return new ObjectAdapterMementoProviderAbstract() {
+        return new ObjectAdapterMementoProviderAbstract(getScalarModel()) {
 
             private static final long serialVersionUID = 1L;
 
@@ -269,7 +263,7 @@ public class EntityLinkSelect2Panel extends FormComponentPanelAbstract<ObjectAda
 
     private ChoiceProvider<ObjectAdapterMemento> providerForParamOrPropertyAutoComplete() {
         final EntityModel entityModel = getScalarModel();
-        return new ObjectAdapterMementoProviderAbstract() {
+        return new ObjectAdapterMementoProviderAbstract(getScalarModel()) {
             
             private static final long serialVersionUID = 1L;
             
@@ -281,7 +275,7 @@ public class EntityLinkSelect2Panel extends FormComponentPanelAbstract<ObjectAda
                     autoCompleteChoices.addAll(scalarModel.getAutoComplete(term));
                 }
                 // take a copy otherwise is only lazily evaluated
-                return Lists.newArrayList(Lists.transform(autoCompleteChoices, MementoFunctions.fromAdapter()));
+                return Lists.newArrayList(Lists.transform(autoCompleteChoices, ObjectAdapterMemento.Functions.fromAdapter()));
             }
             
         };
@@ -307,29 +301,6 @@ public class EntityLinkSelect2Panel extends FormComponentPanelAbstract<ObjectAda
     }
 
 
-    private void syncEntityClearLinksWithInput(final ObjectAdapter adapter) {
-        if (adapter == null) {
-            permanentlyHide(ID_ENTITY_CLEAR_LINK);
-            return;
-        } 
-        
-        if(getScalarModel().isRequired()) {
-            permanentlyHide(ID_ENTITY_CLEAR_LINK);
-            return;
-        }
-        
-        entityClearLink = new Link<String>(ID_ENTITY_CLEAR_LINK) {
-            private static final long serialVersionUID = 1L;
-
-            @Override
-            public void onClick() {
-                onSelected((ObjectAdapterMemento)null);
-            }
-        };
-        addOrReplace(entityClearLink);
-    }
-
-
     private void addOrReplaceIconAndTitle(ObjectAdapter pendingOrCurrentAdapter) {
         final EntityModel entityModelForLink = new EntityModel(pendingOrCurrentAdapter);
         entityModelForLink.setContextAdapterIfAny(getScalarModel().getContextAdapterIfAny());
@@ -438,7 +409,7 @@ public class EntityLinkSelect2Panel extends FormComponentPanelAbstract<ObjectAda
     }
 
     private ObjectAdapterMementoProviderAbstract providerForChoices(final List<ObjectAdapterMemento> choiceMementos) {
-        return new ObjectAdapterMementoProviderAbstract() {
+        return new ObjectAdapterMementoProviderAbstract(getScalarModel()) {
             private static final long serialVersionUID = 1L;
             @Override
             protected List<ObjectAdapterMemento> obtainMementos(String unused) {
@@ -449,7 +420,12 @@ public class EntityLinkSelect2Panel extends FormComponentPanelAbstract<ObjectAda
 
     private void resetIfCurrentNotInChoices(final Select2Choice<ObjectAdapterMemento> select2Field, final List<ObjectAdapterMemento> choiceMementos) {
         final ObjectAdapterMemento curr = select2Field.getModelObject();
-        if(curr == null || !curr.containedIn(choiceMementos)) {
+        if(curr == null) {
+            select2Field.getModel().setObject(null);
+            getModel().setObject(null);
+            return;
+        }
+        if(!curr.containedIn(choiceMementos)) {
             if(!choiceMementos.isEmpty()) {
                 final ObjectAdapterMemento newAdapterMemento = choiceMementos.get(0);
                 select2Field.getModel().setObject(newAdapterMemento);

http://git-wip-us.apache.org/repos/asf/isis/blob/325fc45c/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/valuechoices/ValueChoicesSelect2Panel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/valuechoices/ValueChoicesSelect2Panel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/valuechoices/ValueChoicesSelect2Panel.java
index eabb48f..61e8cf2 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/valuechoices/ValueChoicesSelect2Panel.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/valuechoices/ValueChoicesSelect2Panel.java
@@ -20,7 +20,6 @@ import java.util.Collection;
 import java.util.List;
 
 import com.google.common.base.Predicate;
-import com.google.common.base.Strings;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.Lists;
 import com.vaynberg.wicket.select2.ChoiceProvider;
@@ -28,7 +27,6 @@ import com.vaynberg.wicket.select2.Select2Choice;
 
 import org.apache.wicket.AttributeModifier;
 import org.apache.wicket.Component;
-import org.apache.wicket.behavior.AttributeAppender;
 import org.apache.wicket.behavior.Behavior;
 import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.form.FormComponentLabel;
@@ -47,12 +45,8 @@ import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;
 
 public class ValueChoicesSelect2Panel extends ScalarPanelAbstract implements ScalarModelWithPending {
 
-
     private static final long serialVersionUID = 1L;
 
-    // a guesstimate to convert a single character into 'em' units
-    private static final double CHAR_TO_EM_MULTIPLIER = 0.8;
-    
     private static final String ID_SCALAR_IF_REGULAR = "scalarIfRegular";
     private static final String ID_SCALAR_IF_COMPACT = "scalarIfCompact";
 
@@ -104,7 +98,6 @@ public class ValueChoicesSelect2Panel extends ScalarPanelAbstract implements Sca
     }
 
 
-
     protected void addStandardSemantics() {
         setRequiredIfSpecified();
     }
@@ -142,7 +135,7 @@ public class ValueChoicesSelect2Panel extends ScalarPanelAbstract implements Sca
 
     
     protected ChoiceProvider<ObjectAdapterMemento> newChoiceProvider(final List<ObjectAdapterMemento> choicesMementos) {
-        ChoiceProvider<ObjectAdapterMemento> provider = new ObjectAdapterMementoProviderAbstract() {
+        ChoiceProvider<ObjectAdapterMemento> provider = new ObjectAdapterMementoProviderAbstract(getScalarModel()) {
 
             private static final long serialVersionUID = 1L;
 
@@ -175,12 +168,14 @@ public class ValueChoicesSelect2Panel extends ScalarPanelAbstract implements Sca
     }
 
     @Override
-    protected void onBeforeRenderWhenViewMode() { // View: Read only
+    protected void onBeforeRenderWhenViewMode() { 
+        // View: Read only
         select2Field.setEnabled(false);
     }
 
     @Override
-    protected void onBeforeRenderWhenEnabled() { // Edit: read/write
+    protected void onBeforeRenderWhenEnabled() { 
+        // Edit: read/write
         select2Field.setEnabled(true);
     }
 
@@ -220,14 +215,18 @@ public class ValueChoicesSelect2Panel extends ScalarPanelAbstract implements Sca
         select2Field.setProvider(provider);
         getModel().clearPending();
         final ObjectAdapterMemento objectAdapterMemento = getModel().getObjectAdapterMemento();
-        if(!choicesMementos.contains(objectAdapterMemento)) {
-            final ObjectAdapterMemento newAdapterMemento = 
-                    !choicesMementos.isEmpty() 
-                    ? choicesMementos.get(0) 
-                    : null;
-            select2Field.getModel().setObject(newAdapterMemento);
-            getModel().setObject(
-                    newAdapterMemento != null? newAdapterMemento.getObjectAdapter(ConcurrencyChecking.NO_CHECK): null);
+        if(objectAdapterMemento == null) {
+            select2Field.getModel().setObject(null);
+        } else {
+            if(!choicesMementos.contains(objectAdapterMemento)) {
+                final ObjectAdapterMemento newAdapterMemento = 
+                        !choicesMementos.isEmpty() 
+                        ? choicesMementos.get(0) 
+                                : null;
+                        select2Field.getModel().setObject(newAdapterMemento);
+                        getModel().setObject(
+                                newAdapterMemento != null? newAdapterMemento.getObjectAdapter(ConcurrencyChecking.NO_CHECK): null);
+            }
         }
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/325fc45c/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionParameterAbstract.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionParameterAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionParameterAbstract.java
index 425fc94..26733d9 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionParameterAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionParameterAbstract.java
@@ -47,7 +47,6 @@ import org.apache.isis.core.metamodel.facets.TypedHolder;
 import org.apache.isis.core.metamodel.facets.describedas.DescribedAsFacet;
 import org.apache.isis.core.metamodel.facets.mandatory.MandatoryFacet;
 import org.apache.isis.core.metamodel.facets.named.NamedFacet;
-import org.apache.isis.core.metamodel.facets.object.bounded.ChoicesFacetUtils;
 import org.apache.isis.core.metamodel.facets.param.autocomplete.ActionParameterAutoCompleteFacet;
 import org.apache.isis.core.metamodel.facets.param.choices.ActionParameterChoicesFacet;
 import org.apache.isis.core.metamodel.facets.param.defaults.ActionParameterDefaultsFacet;
@@ -313,7 +312,8 @@ public abstract class ObjectActionParameterAbstract implements ObjectActionParam
             final Object[] choices = facet.getChoices(target, args);
             checkChoicesOrAutoCompleteType(getSpecificationLookup(), choices, getSpecification());
             for (final Object choice : choices) {
-                adapters.add(getAdapterMap().adapterFor(choice));
+                ObjectAdapter adapter = choice != null? getAdapterMap().adapterFor(choice) : null;
+                adapters.add(adapter);
             }
         }
         // now incorporated into above choices processing (BoundedFacet is no more)
@@ -374,6 +374,10 @@ public abstract class ObjectActionParameterAbstract implements ObjectActionParam
     static void checkChoicesOrAutoCompleteType(final SpecificationLoader specificationLookup, final Object[] objects, final ObjectSpecification paramSpec) {
         for (final Object object : objects) {
 
+            if(object == null) {
+                continue;
+            }
+            
             // check type, but wrap first 
             // (eg we treat int.class and java.lang.Integer.class as compatible with each other)
             final Class<? extends Object> choiceClass = object.getClass();

http://git-wip-us.apache.org/repos/asf/isis/blob/325fc45c/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/CollectionUtils.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/CollectionUtils.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/CollectionUtils.java
index 9a9757b..bb56812 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/CollectionUtils.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/CollectionUtils.java
@@ -35,7 +35,7 @@ public final class CollectionUtils {
         final Object[] optionArray = new Object[facet.size(collection)];
         int j = 0;
         for (final ObjectAdapter nextElement : facet.iterable(collection)) {
-            optionArray[j++] = nextElement.getObject();
+            optionArray[j++] = nextElement != null? nextElement.getObject(): null;
         }
         return optionArray;
     }

http://git-wip-us.apache.org/repos/asf/isis/blob/325fc45c/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/collections/collection/ObjectToAdapterFunction.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/collections/collection/ObjectToAdapterFunction.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/collections/collection/ObjectToAdapterFunction.java
index 4d1ada3..eb011ca 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/collections/collection/ObjectToAdapterFunction.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/collections/collection/ObjectToAdapterFunction.java
@@ -39,7 +39,7 @@ public final class ObjectToAdapterFunction implements Function<Object,ObjectAdap
 
     @Override
     public ObjectAdapter apply(final Object object) {
-        return getAdapterManager().adapterFor(object);
+        return object != null? getAdapterManager().adapterFor(object): null;
     }
 
     // //////////////////////////////////////////////////////////////////

http://git-wip-us.apache.org/repos/asf/isis/blob/325fc45c/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adaptermanager/AdapterManagerDefault.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adaptermanager/AdapterManagerDefault.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adaptermanager/AdapterManagerDefault.java
index 8008327..dbfc2df 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adaptermanager/AdapterManagerDefault.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adaptermanager/AdapterManagerDefault.java
@@ -161,6 +161,9 @@ public class AdapterManagerDefault implements AdapterManagerSpi {
     @Override
     public ObjectAdapter adapterFor(final Object pojo) {
 
+        if(pojo == null) {
+            return null;
+        }
         final ObjectAdapter existingOrValueAdapter = existingOrValueAdapter(pojo);
         if(existingOrValueAdapter != null) {
             return existingOrValueAdapter;

http://git-wip-us.apache.org/repos/asf/isis/blob/325fc45c/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItem.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItem.java b/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItem.java
index 5a4ca57..f7fe8d6 100644
--- a/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItem.java
+++ b/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItem.java
@@ -205,17 +205,17 @@ public class ToDoItem implements Comparable<ToDoItem> /*, Locatable*/ { // GMAP3
         Professional {
             @Override
             public List<Subcategory> subcategories() {
-                return Arrays.asList(Subcategory.OpenSource, Subcategory.Consulting, Subcategory.Education);
+                return Arrays.asList(null, Subcategory.OpenSource, Subcategory.Consulting, Subcategory.Education);
             }
         }, Domestic {
             @Override
             public List<Subcategory> subcategories() {
-                return Arrays.asList(Subcategory.Shopping, Subcategory.Housework, Subcategory.Garden, Subcategory.Chores);
+                return Arrays.asList(null, Subcategory.Shopping, Subcategory.Housework, Subcategory.Garden, Subcategory.Chores);
             }
         }, Other {
             @Override
             public List<Subcategory> subcategories() {
-                return Arrays.asList(Subcategory.Other);
+                return Arrays.asList(null, Subcategory.Other);
             }
         };
         
@@ -272,7 +272,7 @@ public class ToDoItem implements Comparable<ToDoItem> /*, Locatable*/ { // GMAP3
 
     private Subcategory subcategory;
 
-    @javax.jdo.annotations.Column(allowsNull="false")
+    @javax.jdo.annotations.Column(allowsNull="true")
     public Subcategory getSubcategory() {
         return subcategory;
     }

http://git-wip-us.apache.org/repos/asf/isis/blob/325fc45c/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItemContributions.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItemContributions.java b/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItemContributions.java
index a264349..5720521 100644
--- a/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItemContributions.java
+++ b/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItemContributions.java
@@ -41,6 +41,7 @@ import org.apache.isis.applib.annotation.Named;
 import org.apache.isis.applib.annotation.NotContributed;
 import org.apache.isis.applib.annotation.NotContributed.As;
 import org.apache.isis.applib.annotation.NotInServiceMenu;
+import org.apache.isis.applib.annotation.Optional;
 import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.applib.query.QueryDefault;
 
@@ -177,7 +178,7 @@ public class ToDoItemContributions extends AbstractFactoryAndRepository {
     public ToDoItem updateCategory(
             final ToDoItem item, 
             final @Named("Category") Category category,
-            final @Named("Subcategory") Subcategory subcategory) {
+            final @Optional @Named("Subcategory") Subcategory subcategory) {
         item.setCategory(category);
         item.setSubcategory(subcategory);
         return item;

http://git-wip-us.apache.org/repos/asf/isis/blob/325fc45c/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/actions/ToDoItemContributionsTest_updateCategory.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/actions/ToDoItemContributionsTest_updateCategory.java b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/actions/ToDoItemContributionsTest_updateCategory.java
index bbdedb2..eb9fe0f 100644
--- a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/actions/ToDoItemContributionsTest_updateCategory.java
+++ b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/actions/ToDoItemContributionsTest_updateCategory.java
@@ -81,10 +81,9 @@ public class ToDoItemContributionsTest_updateCategory extends ToDoIntegTest {
     }
 
     @Test
-    public void subcategoryCannotBeNull() throws Exception {
+    public void subcategoryCanBeNull() throws Exception {
         
         // when, then
-        expectedExceptions.expectMessage("Subcategory is mandatory");
         toDoItemContributions.updateCategory(toDoItem, Category.Professional, null);
     }