From eb93b9db1d73571eb50f70e7266820e84e7f4eed Mon Sep 17 00:00:00 2001
From: felmer <felmer>
Date: Thu, 4 Oct 2012 08:38:59 +0000
Subject: [PATCH] SP-298, BIS-210: first functional GUI version

SVN: 26986
---
 .../OpenBIS-without-entry-point.gwt.xml       |   1 +
 .../ManagedPropertyFormHelper.java            | 156 +++++++++++++++++
 .../ManagedPropertyGridActionDialog.java      | 111 ++-----------
 .../openbis/generic/server/CommonServer.java  |  28 ++--
 .../dataaccess/EntityPropertiesConverter.java | 117 ++++++++++---
 .../dto/ManagedInputWidgetDescription.java    |  27 +++
 .../api/IManagedInputWidgetDescription.java   |   4 +
 .../ManagedPropertyEvaluator.java             | 145 +++++++++++++---
 .../application/ClientPluginFactory.java      |   2 +-
 ...AbstractGenericEntityRegistrationForm.java |  19 ++-
 .../application/ClientPluginFactory.java      |   3 +-
 .../dataset/DataSetPropertyEditor.java        |  13 +-
 .../dataset/GenericDataSetEditForm.java       |  10 +-
 ...ractGenericExperimentRegisterEditForm.java |  12 +-
 .../experiment/ExperimentPropertyEditor.java  |  10 +-
 .../GenericExperimentRegistrationForm.java    |   6 +-
 .../experiment/ManagedPropertyField.java      | 157 ++++++++++++++++++
 .../experiment/PropertiesEditor.java          |  85 ++++++++--
 .../material/GenericMaterialEditForm.java     |  10 +-
 .../material/MaterialPropertyEditor.java      |  10 +-
 ...AbstractGenericSampleRegisterEditForm.java |  21 ++-
 .../sample/GenericSampleEditForm.java         |   2 +-
 .../sample/GenericSampleRegistrationForm.java |   5 +-
 .../sample/SamplePropertyEditor.java          |  13 +-
 .../ManagedPropertyEvaluatorTest.java         | 138 ++++++++++-----
 .../wizard/BiologicalSampleCreatingPage.java  |  10 +-
 26 files changed, 855 insertions(+), 260 deletions(-)
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/managed_property/ManagedPropertyFormHelper.java
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/ManagedPropertyField.java

diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/OpenBIS-without-entry-point.gwt.xml b/openbis/source/java/ch/systemsx/cisd/openbis/OpenBIS-without-entry-point.gwt.xml
index 6a418d5cdad..967a56e06cd 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/OpenBIS-without-entry-point.gwt.xml
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/OpenBIS-without-entry-point.gwt.xml
@@ -11,6 +11,7 @@
   -->
   <inherits name='com.google.gwt.user.User' />
   <inherits name="com.google.gwt.i18n.I18N" />
+  <inherits name="com.google.gwt.json.JSON" />
   
   <!--
     // Inherit the core EXT GWT stuff.
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/managed_property/ManagedPropertyFormHelper.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/managed_property/ManagedPropertyFormHelper.java
new file mode 100644
index 00000000000..6a3d5c72113
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/managed_property/ManagedPropertyFormHelper.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2012 ETH Zuerich, CISD
+ *
+ * Licensed 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 ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.managed_property;
+
+import java.util.List;
+import java.util.Map;
+
+import com.extjs.gxt.ui.client.widget.form.ComboBox.TriggerAction;
+import com.extjs.gxt.ui.client.widget.form.FormPanel;
+import com.extjs.gxt.ui.client.widget.form.SimpleComboBox;
+import com.extjs.gxt.ui.client.widget.form.TextField;
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.field.MultilineVarcharField;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.widget.FieldUtil;
+import ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ManagedComboBoxInputWidgetDescription;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.api.IManagedInputWidgetDescription;
+
+/**
+ * @author Franz-Josef Elmer
+ */
+public class ManagedPropertyFormHelper
+{
+    private final IViewContext<?> viewContext;
+
+    private final FormPanel formPanel;
+
+    private final Map<String, TextField<?>> inputFieldsByLabel;
+
+    public ManagedPropertyFormHelper(IViewContext<?> viewContext, FormPanel formPanel,
+            Map<String, TextField<?>> inputFieldsByLabel)
+    {
+        this.viewContext = viewContext;
+        this.formPanel = formPanel;
+        this.inputFieldsByLabel = inputFieldsByLabel;
+
+    }
+
+    public void fillForm(List<IManagedInputWidgetDescription> inputWidgetDescriptions)
+    {
+        for (IManagedInputWidgetDescription inputDescription : inputWidgetDescriptions)
+        {
+            trySetBoundedValue(inputDescription);
+            TextField<?> field;
+            switch (inputDescription.getManagedInputFieldType())
+            {
+                case TEXT:
+                    field = createTextField(inputDescription);
+                    break;
+                case MULTILINE_TEXT:
+                    field = createMultilineTextField(inputDescription);
+                    break;
+                case COMBO_BOX:
+                    field = createComboBoxField(inputDescription);
+                    break;
+                default:
+                    throw new UnsupportedOperationException(); // can't happen
+            }
+            final String label = inputDescription.getLabel();
+            if (label == null)
+            {
+                throwFailToCreateContentException("Label is not set in input widget description");
+            }
+            field.setFieldLabel(label);
+
+            if (inputDescription.getDescription() != null)
+            {
+                AbstractImagePrototype infoIcon =
+                        AbstractImagePrototype.create(viewContext.getImageBundle().getInfoIcon());
+                FieldUtil.addInfoIcon(field, inputDescription.getDescription(),
+                        infoIcon.createImage());
+            }
+            FieldUtil.setMandatoryFlag(field, inputDescription.isMandatory());
+
+            inputFieldsByLabel.put(label, field);
+            formPanel.add(field);
+        }
+
+    }
+
+    protected void trySetBoundedValue(IManagedInputWidgetDescription inputDescription)
+    {
+    }
+
+    private TextField<?> createTextField(IManagedInputWidgetDescription inputDescription)
+    {
+        final TextField<String> field = new TextField<String>();
+        if (inputDescription.getValue() != null)
+        {
+            FieldUtil.setValueWithUnescaping(field, inputDescription.getValue());
+            field.updateOriginalValue(field.getValue());
+        }
+        return field;
+    }
+
+    private TextField<?> createMultilineTextField(IManagedInputWidgetDescription inputDescription)
+    {
+        final TextField<String> field =
+                new MultilineVarcharField(inputDescription.getLabel(), false);
+        if (inputDescription.getValue() != null)
+        {
+            FieldUtil.setValueWithUnescaping(field, inputDescription.getValue());
+            field.updateOriginalValue(field.getValue());
+        }
+        return field;
+    }
+
+    private TextField<?> createComboBoxField(IManagedInputWidgetDescription inputDescription)
+    {
+        final SimpleComboBox<String> comboBox = new SimpleComboBox<String>();
+        comboBox.setTriggerAction(TriggerAction.ALL);
+        comboBox.setEditable(false);
+        comboBox.setForceSelection(true);
+        if (inputDescription instanceof ManagedComboBoxInputWidgetDescription)
+        {
+            final ManagedComboBoxInputWidgetDescription comboBoxDescription =
+                    (ManagedComboBoxInputWidgetDescription) inputDescription;
+            comboBox.add(comboBoxDescription.getOptions());
+
+            if (inputDescription.getValue() != null)
+            {
+                comboBox.setSimpleValue(inputDescription.getValue());
+                comboBox.updateOriginalValue(comboBox.getValue());
+            }
+            return comboBox;
+        } else
+        {
+            throwFailToCreateContentException("'" + inputDescription.getLabel()
+                    + "' description should be a subclass of ManagedComboBoxInputWidgetDescription");
+            return null;
+        }
+    }
+
+    private void throwFailToCreateContentException(String detailedErrorMsg)
+            throws UserFailureException
+    {
+        throw new UserFailureException("Failed to create content.", detailedErrorMsg);
+    }
+
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/managed_property/ManagedPropertyGridActionDialog.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/managed_property/ManagedPropertyGridActionDialog.java
index 8306ff66c42..76ab67e95fc 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/managed_property/ManagedPropertyGridActionDialog.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/managed_property/ManagedPropertyGridActionDialog.java
@@ -23,25 +23,18 @@ import java.util.List;
 import java.util.Map;
 
 import com.extjs.gxt.ui.client.widget.Info;
-import com.extjs.gxt.ui.client.widget.form.ComboBox.TriggerAction;
-import com.extjs.gxt.ui.client.widget.form.SimpleComboBox;
 import com.extjs.gxt.ui.client.widget.form.SimpleComboValue;
 import com.extjs.gxt.ui.client.widget.form.TextField;
 import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwt.user.client.ui.AbstractImagePrototype;
 
 import ch.systemsx.cisd.openbis.generic.client.web.client.ICommonClientServiceAsync;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
-import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.field.MultilineVarcharField;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.widget.AbstractDataConfirmationDialog;
-import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.widget.FieldUtil;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.GWTUtils;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.lang.StringEscapeUtils;
-import ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException;
 import ch.systemsx.cisd.openbis.generic.shared.basic.IEntityInformationHolder;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ISerializableComparable;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ManagedComboBoxInputWidgetDescription;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ManagedTableWidgetDescription;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ManagedUiTableActionDescription;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ReportRowModel;
@@ -70,6 +63,8 @@ public final class ManagedPropertyGridActionDialog extends
     private final Map<String, TextField<?>> inputFieldsByLabel =
             new LinkedHashMap<String, TextField<?>>();
 
+    private final ManagedPropertyFormHelper formHelper;
+
     public ManagedPropertyGridActionDialog(IViewContext<ICommonClientServiceAsync> viewContext,
             String editTitle, List<TableModelRowWithObject<ReportRowModel>> data,
             AsyncCallback<Void> callback, IEntityInformationHolder entity,
@@ -82,6 +77,14 @@ public final class ManagedPropertyGridActionDialog extends
         this.callback = callback;
         this.managedAction = managedAction;
         setWidth(400);
+        formHelper = new ManagedPropertyFormHelper(viewContext, formPanel, inputFieldsByLabel)
+            {
+                @Override
+                protected void trySetBoundedValue(IManagedInputWidgetDescription inputDescription)
+                {
+                    ManagedPropertyGridActionDialog.this.trySetBoundedValue(inputDescription);
+                }
+            };
     }
 
     @Override
@@ -130,44 +133,7 @@ public final class ManagedPropertyGridActionDialog extends
         formPanel.setLabelWidth(100);
         formPanel.setFieldWidth(200);
 
-        for (IManagedInputWidgetDescription inputDescription : managedAction
-                .getInputWidgetDescriptions())
-        {
-            trySetBoundedValue(inputDescription);
-            TextField<?> field;
-            switch (inputDescription.getManagedInputFieldType())
-            {
-                case TEXT:
-                    field = createTextField(inputDescription);
-                    break;
-                case MULTILINE_TEXT:
-                    field = createMultilineTextField(inputDescription);
-                    break;
-                case COMBO_BOX:
-                    field = createComboBoxField(inputDescription);
-                    break;
-                default:
-                    throw new UnsupportedOperationException(); // can't happen
-            }
-            final String label = inputDescription.getLabel();
-            if (label == null)
-            {
-                throwFailToCreateContentException("Label is not set in input widget description");
-            }
-            field.setFieldLabel(label);
-
-            if (inputDescription.getDescription() != null)
-            {
-                AbstractImagePrototype infoIcon =
-                        AbstractImagePrototype.create(viewContext.getImageBundle().getInfoIcon());
-                FieldUtil.addInfoIcon(field, inputDescription.getDescription(),
-                        infoIcon.createImage());
-            }
-            FieldUtil.setMandatoryFlag(field, inputDescription.isMandatory());
-
-            inputFieldsByLabel.put(label, field);
-            formPanel.add(field);
-        }
+        formHelper.fillForm(managedAction.getInputWidgetDescriptions());
     }
 
     /**
@@ -212,59 +178,4 @@ public final class ManagedPropertyGridActionDialog extends
         }
     }
 
-    private TextField<?> createTextField(IManagedInputWidgetDescription inputDescription)
-    {
-        final TextField<String> field = new TextField<String>();
-        if (inputDescription.getValue() != null)
-        {
-            FieldUtil.setValueWithUnescaping(field, inputDescription.getValue());
-            field.updateOriginalValue(field.getValue());
-        }
-        return field;
-    }
-
-    private TextField<?> createMultilineTextField(IManagedInputWidgetDescription inputDescription)
-    {
-        final TextField<String> field =
-                new MultilineVarcharField(inputDescription.getLabel(), false);
-        if (inputDescription.getValue() != null)
-        {
-            FieldUtil.setValueWithUnescaping(field, inputDescription.getValue());
-            field.updateOriginalValue(field.getValue());
-        }
-        return field;
-    }
-
-    private TextField<?> createComboBoxField(IManagedInputWidgetDescription inputDescription)
-    {
-        final SimpleComboBox<String> comboBox = new SimpleComboBox<String>();
-        comboBox.setTriggerAction(TriggerAction.ALL);
-        comboBox.setEditable(false);
-        comboBox.setForceSelection(true);
-        if (inputDescription instanceof ManagedComboBoxInputWidgetDescription)
-        {
-            final ManagedComboBoxInputWidgetDescription comboBoxDescription =
-                    (ManagedComboBoxInputWidgetDescription) inputDescription;
-            comboBox.add(comboBoxDescription.getOptions());
-
-            if (inputDescription.getValue() != null)
-            {
-                comboBox.setSimpleValue(inputDescription.getValue());
-                comboBox.updateOriginalValue(comboBox.getValue());
-            }
-            return comboBox;
-        } else
-        {
-            throwFailToCreateContentException("'" + inputDescription.getLabel()
-                    + "' description should be a subclass of ManagedComboBoxInputWidgetDescription");
-            return null;
-        }
-    }
-
-    private void throwFailToCreateContentException(String detailedErrorMsg)
-            throws UserFailureException
-    {
-        throw new UserFailureException("Failed to create content.", detailedErrorMsg);
-    }
-
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
index c3fca1bbb41..dd132d94aab 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
@@ -198,7 +198,6 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.LinkModel;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ListMaterialCriteria;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ListOrSearchSampleCriteria;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ListSampleCriteria;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ManagedTextInputWidgetDescription;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ManagedUiActionDescription;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.MatchingEntity;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Material;
@@ -619,9 +618,15 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
 
         List<? extends EntityTypePropertyType<?>> assignedPropertyTypes =
                 entityType.getAssignedPropertyTypes();
-        HashMap<String, List<IManagedInputWidgetDescription>> result =
+        return listManagedInputWidgetDescriptions(assignedPropertyTypes);
+    }
+
+    private Map<String, List<IManagedInputWidgetDescription>> listManagedInputWidgetDescriptions(
+            List<? extends EntityTypePropertyType<?>> propertyTypes)
+    {
+        Map<String, List<IManagedInputWidgetDescription>> result =
                 new HashMap<String, List<IManagedInputWidgetDescription>>();
-        for (EntityTypePropertyType<?> entityTypePropertyType : assignedPropertyTypes)
+        for (EntityTypePropertyType<?> entityTypePropertyType : propertyTypes)
         {
             String propertyTypeCode = entityTypePropertyType.getPropertyType().getCode();
             if (entityTypePropertyType.isManaged())
@@ -629,22 +634,13 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
                 String script = entityTypePropertyType.getScript().getScript();
                 ManagedPropertyEvaluator evaluator =
                         ManagedPropertyEvaluatorFactory.createManagedPropertyEvaluator(script);
-                List<String> batchColumnNames = evaluator.getBatchColumnNames();
-                if (batchColumnNames.isEmpty() == false)
+                List<IManagedInputWidgetDescription> inputWidgetDescriptions =
+                        evaluator.getInputWidgetDescriptions();
+                if (inputWidgetDescriptions.isEmpty() == false)
                 {
-                    List<IManagedInputWidgetDescription> descriptions =
-                            new ArrayList<IManagedInputWidgetDescription>();
-                    for (String batchColumnName : batchColumnNames)
-                    {
-                        ManagedTextInputWidgetDescription description =
-                                new ManagedTextInputWidgetDescription();
-                        description.setLabel(batchColumnName);
-                        descriptions.add(description);
-                    }
-                    result.put(propertyTypeCode, descriptions);
+                    result.put(propertyTypeCode, inputWidgetDescriptions);
                 }
             }
-
         }
         return result;
     }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/EntityPropertiesConverter.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/EntityPropertiesConverter.java
index c79d113c023..a1cd6aa0d4f 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/EntityPropertiesConverter.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/EntityPropertiesConverter.java
@@ -19,6 +19,7 @@ package ch.systemsx.cisd.openbis.generic.server.dataaccess;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
@@ -28,7 +29,10 @@ import java.util.Set;
 
 import org.hibernate.Session;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
+
 import ch.rinn.restrictions.Private;
+import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
 import ch.systemsx.cisd.common.collections.IKeyExtractor;
 import ch.systemsx.cisd.common.collections.TableMap;
 import ch.systemsx.cisd.common.collections.TableMap.UniqueKeyViolationStrategy;
@@ -38,7 +42,9 @@ import ch.systemsx.cisd.openbis.generic.server.dataaccess.util.KeyExtractorFacto
 import ch.systemsx.cisd.openbis.generic.shared.basic.BasicConstant;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataTypeCode;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ManagedProperty;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.MaterialIdentifier;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.api.IManagedInputWidgetDescription;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.api.IManagedProperty;
 import ch.systemsx.cisd.openbis.generic.shared.dto.EntityPropertyPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.EntityTypePE;
@@ -50,6 +56,8 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.PropertyTypePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.VocabularyPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.VocabularyTermPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.properties.EntityKind;
+import ch.systemsx.cisd.openbis.generic.shared.managed_property.ManagedPropertyEvaluator;
+import ch.systemsx.cisd.openbis.generic.shared.managed_property.ManagedPropertyEvaluatorFactory;
 
 /**
  * The unique {@link IEntityPropertiesConverter} implementation.
@@ -63,6 +71,15 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.properties.EntityKind;
  */
 public final class EntityPropertiesConverter implements IEntityPropertiesConverter
 {
+    private static final IKeyExtractor<PropertyTypePE, ExtendedEntityTypePropertyType> EXTENDED_ETPT_KEY_EXTRACTOR =
+            new IKeyExtractor<PropertyTypePE, ExtendedEntityTypePropertyType>()
+                {
+                    @Override
+                    public PropertyTypePE getKey(ExtendedEntityTypePropertyType etpt)
+                    {
+                        return etpt.getEntityTypePropertyTypePE().getPropertyType();
+                    }
+                };
 
     private static final String NO_ENTITY_PROPERTY_VALUE_FOR_S =
             "Value of mandatory property '%s' not specified.";
@@ -83,8 +100,8 @@ public final class EntityPropertiesConverter implements IEntityPropertiesConvert
             new TableMap<String, PropertyTypePE>(
                     KeyExtractorFactory.getPropertyTypeByCodeKeyExtractor());
 
-    private Map<String /* Entity type code */, TableMap<PropertyTypePE, EntityTypePropertyTypePE>> entityTypePropertyTypesByEntityTypeAndPropertyType =
-            new HashMap<String, TableMap<PropertyTypePE, EntityTypePropertyTypePE>>();
+    private Map<String /* Entity type code */, TableMap<PropertyTypePE, ExtendedEntityTypePropertyType>> entityTypePropertyTypesByEntityTypeAndPropertyType =
+            new HashMap<String, TableMap<PropertyTypePE, ExtendedEntityTypePropertyType>>();
 
     private final ComplexPropertyValueHelper complexPropertyValueHelper;
 
@@ -189,26 +206,24 @@ public final class EntityPropertiesConverter implements IEntityPropertiesConvert
         return propertyType;
     }
 
-    private final EntityTypePropertyTypePE getEntityTypePropertyType(
+    private final ExtendedEntityTypePropertyType getEntityTypePropertyType(
             final EntityTypePE entityTypePE, final PropertyTypePE propertyType)
     {
         String entityTypeCode = entityTypePE.getCode();
-        TableMap<PropertyTypePE, EntityTypePropertyTypePE> map =
+        TableMap<PropertyTypePE, ExtendedEntityTypePropertyType> map =
                 entityTypePropertyTypesByEntityTypeAndPropertyType.get(entityTypeCode);
         if (map == null)
         {
-            IEntityPropertyTypeDAO entityPropertyTypeDAO =
-                    daoFactory.getEntityPropertyTypeDAO(entityKind);
-            List<EntityTypePropertyTypePE> entityPropertyTypes =
-                    entityPropertyTypeDAO.listEntityPropertyTypes(entityTypePE);
+            List<ExtendedEntityTypePropertyType> entityTypePropertyTypes =
+                    getEntityTypePropertyTypes(entityTypePE);
             map =
-                    new TableMap<PropertyTypePE, EntityTypePropertyTypePE>(entityPropertyTypes,
-                            EntityTypePropertyTypeByPropertyTypeKeyExtractor.INSTANCE,
+                    new TableMap<PropertyTypePE, ExtendedEntityTypePropertyType>(
+                            entityTypePropertyTypes, EXTENDED_ETPT_KEY_EXTRACTOR,
                             UniqueKeyViolationStrategy.KEEP_FIRST);
             entityTypePropertyTypesByEntityTypeAndPropertyType.put(entityTypeCode, map);
         }
 
-        final EntityTypePropertyTypePE entityTypePropertyType = map.tryGet(propertyType);
+        final ExtendedEntityTypePropertyType entityTypePropertyType = map.tryGet(propertyType);
 
         if (entityTypePropertyType == null)
         {
@@ -219,14 +234,32 @@ public final class EntityPropertiesConverter implements IEntityPropertiesConvert
         return entityTypePropertyType;
     }
 
+    private List<ExtendedEntityTypePropertyType> getEntityTypePropertyTypes(
+            EntityTypePE entityTypePE)
+    {
+        IEntityPropertyTypeDAO entityPropertyTypeDAO =
+                daoFactory.getEntityPropertyTypeDAO(entityKind);
+        List<EntityTypePropertyTypePE> entityPropertyTypes =
+                entityPropertyTypeDAO.listEntityPropertyTypes(entityTypePE);
+        List<ExtendedEntityTypePropertyType> result =
+                new ArrayList<ExtendedEntityTypePropertyType>();
+        for (EntityTypePropertyTypePE entityTypePropertyTypePE : entityPropertyTypes)
+        {
+            result.add(new ExtendedEntityTypePropertyType(entityTypePropertyTypePE));
+        }
+        return result;
+    }
+
     private final <T extends EntityPropertyPE> T tryConvertProperty(final PersonPE registrator,
             final EntityTypePE entityTypePE, final IEntityProperty property)
     {
         final String propertyCode = property.getPropertyType().getCode();
         final PropertyTypePE propertyType = getPropertyType(propertyCode);
         final String valueOrNull = property.tryGetAsString();
-        final EntityTypePropertyTypePE entityTypePropertyTypePE =
+        ExtendedEntityTypePropertyType extendedETPT =
                 getEntityTypePropertyType(entityTypePE, propertyType);
+        final EntityTypePropertyTypePE entityTypePropertyTypePE =
+                extendedETPT.getEntityTypePropertyTypePE();
         if (entityTypePropertyTypePE.isMandatory() && valueOrNull == null)
         {
             throw UserFailureException.fromTemplate(NO_ENTITY_PROPERTY_VALUE_FOR_S, propertyCode);
@@ -235,8 +268,9 @@ public final class EntityPropertiesConverter implements IEntityPropertiesConvert
         {
             final String validated =
                     propertyValueValidator.validatePropertyValue(propertyType, valueOrNull);
+
             return createEntityProperty(registrator, propertyType, entityTypePropertyTypePE,
-                    validated);
+                    extendedETPT.translate(validated));
         }
         return null;
     }
@@ -517,27 +551,60 @@ public final class EntityPropertiesConverter implements IEntityPropertiesConvert
     // Helper classes
     //
 
-    private final static class EntityTypePropertyTypeByPropertyTypeKeyExtractor implements
-            IKeyExtractor<PropertyTypePE, EntityTypePropertyTypePE>
+    private static final class ExtendedEntityTypePropertyType
     {
+        private final EntityTypePropertyTypePE entityTypePropertyTypePE;
+
+        private final List<IManagedInputWidgetDescription> inputWidgetDescriptions;
 
-        static final EntityTypePropertyTypeByPropertyTypeKeyExtractor INSTANCE =
-                new EntityTypePropertyTypeByPropertyTypeKeyExtractor();
+        private ManagedPropertyEvaluator evaluator;
 
-        private EntityTypePropertyTypeByPropertyTypeKeyExtractor()
+        ExtendedEntityTypePropertyType(EntityTypePropertyTypePE entityTypePropertyTypePE)
         {
-            // Can not be instantiated.
+            this.entityTypePropertyTypePE = entityTypePropertyTypePE;
+            if (entityTypePropertyTypePE.isManaged())
+            {
+                String script = entityTypePropertyTypePE.getScript().getScript();
+                evaluator = ManagedPropertyEvaluatorFactory.createManagedPropertyEvaluator(script);
+                inputWidgetDescriptions = evaluator.getInputWidgetDescriptions();
+            } else
+            {
+                inputWidgetDescriptions = Collections.emptyList();
+            }
         }
 
-        //
-        // IKeyExtractor
-        //
+        public EntityTypePropertyTypePE getEntityTypePropertyTypePE()
+        {
+            return entityTypePropertyTypePE;
+        }
 
-        @Override
-        public final PropertyTypePE getKey(final EntityTypePropertyTypePE e)
+        @SuppressWarnings("unchecked")
+        String translate(String propertyValue)
         {
-            return e.getPropertyType();
+            if (inputWidgetDescriptions.isEmpty() || propertyValue == null
+                    || propertyValue.startsWith(BasicConstant.ERROR_PROPERTY_PREFIX))
+            {
+                return propertyValue;
+            }
+            try
+            {
+                List<?> readValue = new ObjectMapper().readValue(propertyValue, List.class);
+                ManagedProperty managedProperty = new ManagedProperty();
+                for (Object row : readValue)
+                {
+                    if (row instanceof Map == false)
+                    {
+                        continue;
+                    }
+                    evaluator.updateFromBatchInput(managedProperty, (Map<String, String>) row);
+                }
+                return managedProperty.getValue();
+            } catch (Exception ex)
+            {
+                throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+            }
         }
+
     }
 
     public interface IHibernateSessionProvider
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ManagedInputWidgetDescription.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ManagedInputWidgetDescription.java
index bb4e5c96fef..9eb0400a2c5 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ManagedInputWidgetDescription.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ManagedInputWidgetDescription.java
@@ -16,6 +16,8 @@
 
 package ch.systemsx.cisd.openbis.generic.shared.basic.dto;
 
+import org.apache.commons.lang.StringUtils;
+
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.api.IManagedInputWidgetDescription;
 
 /**
@@ -25,6 +27,8 @@ public abstract class ManagedInputWidgetDescription implements IManagedInputWidg
 {
     private static final long serialVersionUID = 1L;
 
+    private String code;
+
     private String label;
 
     private String value;
@@ -37,6 +41,21 @@ public abstract class ManagedInputWidgetDescription implements IManagedInputWidg
     // IManagedInputWidgetDescription
     //
 
+    @Override
+    public String getCode()
+    {
+        return code;
+    }
+
+    public void setCode(String code)
+    {
+        if (StringUtils.isBlank(code))
+        {
+            throw new IllegalArgumentException("Code is null or a blank string.");
+        }
+        this.code = code.toUpperCase();
+    }
+
     @Override
     public String getLabel()
     {
@@ -45,7 +64,15 @@ public abstract class ManagedInputWidgetDescription implements IManagedInputWidg
 
     public void setLabel(String label)
     {
+        if (StringUtils.isBlank(label))
+        {
+            throw new IllegalArgumentException("Label is null or a blank string.");
+        }
         this.label = label;
+        if (code == null)
+        {
+            code = label.toUpperCase();
+        }
     }
 
     @Override
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/api/IManagedInputWidgetDescription.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/api/IManagedInputWidgetDescription.java
index d9cda035907..cd35ca1a00e 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/api/IManagedInputWidgetDescription.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/api/IManagedInputWidgetDescription.java
@@ -26,6 +26,10 @@ import java.io.Serializable;
 // NOTE: All methods of this interface are part of the Managed Properties API.
 public interface IManagedInputWidgetDescription extends Serializable
 {
+    /**
+     * Returns the code of this input field.
+     */
+    String getCode();
 
     /**
      * @return label of this input field
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/managed_property/ManagedPropertyEvaluator.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/managed_property/ManagedPropertyEvaluator.java
index a4dd0c5ebb8..18ccfba256b 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/managed_property/ManagedPropertyEvaluator.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/managed_property/ManagedPropertyEvaluator.java
@@ -17,9 +17,10 @@
 package ch.systemsx.cisd.openbis.generic.shared.managed_property;
 
 import java.util.ArrayList;
-import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.apache.log4j.Logger;
 
@@ -27,6 +28,8 @@ import ch.systemsx.cisd.common.evaluator.Evaluator;
 import ch.systemsx.cisd.common.evaluator.EvaluatorException;
 import ch.systemsx.cisd.common.logging.LogCategory;
 import ch.systemsx.cisd.common.logging.LogFactory;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ManagedUiActionDescriptionFactory;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.api.IManagedInputWidgetDescription;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.api.IManagedProperty;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.api.IManagedUiAction;
 import ch.systemsx.cisd.openbis.generic.shared.dto.EntityPropertyPE;
@@ -38,6 +41,30 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.EntityPropertyPE;
  */
 public class ManagedPropertyEvaluator
 {
+    private static final class UniqunessChecker
+    {
+        private final Set<String> codes = new HashSet<String>();
+
+        private final String type;
+
+        private final String codeName;
+
+        UniqunessChecker(String type, String codeName)
+        {
+            this.type = type;
+            this.codeName = codeName;
+        }
+
+        void check(String code)
+        {
+            if (codes.add(code) == false)
+            {
+                throw new EvaluatorException("There is already " + type + " with " + codeName
+                        + ": " + code);
+            }
+        }
+    }
+
     private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION,
             ManagedPropertyEvaluator.class);
 
@@ -56,6 +83,11 @@ public class ManagedPropertyEvaluator
      */
     private static final String BATCH_COLUMN_NAMES_FUNCTION = "batchColumnNames";
 
+    /**
+     * The name of the function that returns an array of @IManagedInputWidgetDescription.
+     */
+    private static final String INPUT_WIDGETS_FUNCTION = "inputWidgets";
+
     /**
      * The name of the function that expects a map of bindings.
      */
@@ -71,45 +103,101 @@ public class ManagedPropertyEvaluator
 
     private final boolean updateFromBatchFunctionDefined;
 
+    private List<IManagedInputWidgetDescription> inputWidgetDescriptions;
+
     public ManagedPropertyEvaluator(String scriptExpression)
     {
         evaluator = new Evaluator("", ManagedPropertyFunctions.class, scriptExpression);
         updateFromBatchFunctionDefined = evaluator.hasFunction(UPDATE_FROM_BATCH_INPUT_FUNCTION);
-        List<String> names = new ArrayList<String>();
-        if (evaluator.hasFunction(BATCH_COLUMN_NAMES_FUNCTION))
+        boolean batchColumnNamesFunctionDefined =
+                evaluator.hasFunction(BATCH_COLUMN_NAMES_FUNCTION);
+        boolean inputWidgetsFunctionDefined = evaluator.hasFunction(INPUT_WIDGETS_FUNCTION);
+        checkCombinationsOfDefinedFunctions(batchColumnNamesFunctionDefined,
+                inputWidgetsFunctionDefined);
+        columnNames = new ArrayList<String>();
+        inputWidgetDescriptions = new ArrayList<IManagedInputWidgetDescription>();
+        if (inputWidgetsFunctionDefined)
         {
-            if (updateFromBatchFunctionDefined == false)
-            {
-                throw new EvaluatorException("Function '" + BATCH_COLUMN_NAMES_FUNCTION
-                        + "' defined but not '" + UPDATE_FROM_BATCH_INPUT_FUNCTION + "'.");
-            }
-            Object result = evaluator.evalFunction(BATCH_COLUMN_NAMES_FUNCTION);
-            if (result instanceof List == false)
+            List<?> widgets = evalFunction(INPUT_WIDGETS_FUNCTION);
+            UniqunessChecker uniqunessChecker = new UniqunessChecker("an input widget", "code");
+            for (int i = 0; i < widgets.size(); i++)
             {
-                throw new EvaluatorException("Function '" + BATCH_COLUMN_NAMES_FUNCTION
-                        + "' doesn't return a List but an object of type '"
-                        + result.getClass().getName() + "': " + result);
+                Object widget = widgets.get(i);
+                if (widget == null)
+                {
+                    throw new EvaluatorException("Function " + INPUT_WIDGETS_FUNCTION
+                            + " has returned a list where the " + (i + 1) + ". element is null.");
+                }
+                if (widget instanceof IManagedInputWidgetDescription == false)
+                {
+                    throw new EvaluatorException("Function " + INPUT_WIDGETS_FUNCTION
+                            + " has returned a list where the " + (i + 1)
+                            + ". element isn't of type "
+                            + IManagedInputWidgetDescription.class.getName() + " but "
+                            + widget.getClass().getName() + ".");
+                }
+                IManagedInputWidgetDescription widgetDescription =
+                        (IManagedInputWidgetDescription) widget;
+                inputWidgetDescriptions.add(widgetDescription);
+                if (batchColumnNamesFunctionDefined == false)
+                {
+                    String code = widgetDescription.getCode();
+                    uniqunessChecker.check(code);
+                    columnNames.add(code);
+                }
             }
-            List<?> list = (List<?>) result;
-            List<String> notUpperCaseNames = new ArrayList<String>();
+        }
+        if (batchColumnNamesFunctionDefined)
+        {
+            List<?> list = evalFunction(BATCH_COLUMN_NAMES_FUNCTION);
+            UniqunessChecker uniqunessChecker =
+                    new UniqunessChecker("a batch column", "name in uppercase");
+            ManagedUiActionDescriptionFactory descriptionFactory =
+                    new ManagedUiActionDescriptionFactory();
             for (Object element : list)
             {
                 String columnName = element.toString();
-                if (columnName.toUpperCase().equals(columnName) == false)
+                String code = columnName.toUpperCase();
+                uniqunessChecker.check(code);
+                columnNames.add(code);
+                if (inputWidgetsFunctionDefined == false)
                 {
-                    notUpperCaseNames.add(columnName);
+                    inputWidgetDescriptions
+                            .add(descriptionFactory.createTextInputField(columnName));
                 }
-                names.add(columnName);
-            }
-            if (notUpperCaseNames.isEmpty() == false)
-            {
-                throw new EvaluatorException(
-                        "The following batch column names as returned by function '"
-                                + BATCH_COLUMN_NAMES_FUNCTION + "' are not in upper case: "
-                                + notUpperCaseNames);
             }
         }
-        columnNames = Collections.unmodifiableList(names);
+    }
+
+    private void checkCombinationsOfDefinedFunctions(boolean batchColumnNamesFunctionDefined,
+            boolean inputWidgetsFunctionDefined)
+    {
+        if ((batchColumnNamesFunctionDefined || inputWidgetsFunctionDefined)
+                && updateFromBatchFunctionDefined == false)
+        {
+            StringBuilder builder = new StringBuilder("Function ");
+            builder.append(UPDATE_FROM_BATCH_INPUT_FUNCTION);
+            builder.append(" is not defined although function");
+            boolean both = batchColumnNamesFunctionDefined && inputWidgetsFunctionDefined;
+            builder.append(both ? "s " : " ");
+            builder.append(batchColumnNamesFunctionDefined ? BATCH_COLUMN_NAMES_FUNCTION : "");
+            builder.append(both ? " and " : "");
+            builder.append(inputWidgetsFunctionDefined ? INPUT_WIDGETS_FUNCTION : "");
+            builder.append(both ? " are defined." : " is defined.");
+            throw new EvaluatorException(builder.toString());
+        }
+    }
+
+    private List<?> evalFunction(String functionName)
+    {
+        Object result = evaluator.evalFunction(functionName);
+        if (result instanceof List == false)
+        {
+            throw new EvaluatorException("Function '" + functionName
+                    + "' doesn't return a List but an object of type '"
+                    + result.getClass().getName() + "': " + result);
+        }
+        return (List<?>) result;
     }
 
     public void configureUI(IManagedProperty managedProperty, EntityPropertyPE entityPropertyPE)
@@ -142,6 +230,11 @@ public class ManagedPropertyEvaluator
         return columnNames;
     }
 
+    public List<IManagedInputWidgetDescription> getInputWidgetDescriptions()
+    {
+        return inputWidgetDescriptions;
+    }
+
     public void updateFromBatchInput(IManagedProperty managedProperty, Map<String, String> bindings)
     {
         if (updateFromBatchFunctionDefined == false)
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/demo/client/web/client/application/ClientPluginFactory.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/demo/client/web/client/application/ClientPluginFactory.java
index e871e661930..07faf80dca8 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/demo/client/web/client/application/ClientPluginFactory.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/demo/client/web/client/application/ClientPluginFactory.java
@@ -170,7 +170,7 @@ public final class ClientPluginFactory extends AbstractClientPluginFactory<DemoV
         {
             GenericSampleRegistrationForm form =
                     new GenericSampleRegistrationForm(new GenericViewContext(getViewContext()
-                            .getCommonViewContext()), sampleType, context);
+                            .getCommonViewContext()), inputWidgetDescriptions, sampleType, context);
             return new DatabaseModificationAwareWidget(form, form);
         }
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/AbstractGenericEntityRegistrationForm.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/AbstractGenericEntityRegistrationForm.java
index ef039d3a4d5..4f9fea55b83 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/AbstractGenericEntityRegistrationForm.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/AbstractGenericEntityRegistrationForm.java
@@ -17,7 +17,9 @@
 package ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import com.extjs.gxt.ui.client.widget.form.Field;
@@ -40,6 +42,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityKind;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityTypePropertyType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.api.IManagedInputWidgetDescription;
 import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.IGenericClientServiceAsync;
 import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.experiment.PropertiesEditor;
 
@@ -68,6 +71,8 @@ public abstract class AbstractGenericEntityRegistrationForm<T extends EntityType
 
     protected PropertiesEditor<T, S> propertiesEditor;
 
+    private final Map<String, List<IManagedInputWidgetDescription>> inputWidgetDescriptions;
+
     // ---------------------------------------------------------------------------------------------
     // Constructors
     // ---------------------------------------------------------------------------------------------
@@ -76,11 +81,16 @@ public abstract class AbstractGenericEntityRegistrationForm<T extends EntityType
      */
     protected AbstractGenericEntityRegistrationForm(
             final IViewContext<IGenericClientServiceAsync> viewContext,
+            Map<String, List<IManagedInputWidgetDescription>> inputWidgetDescriptionsOrNull,
             IIdAndCodeHolder identifiableOrNull, EntityKind entityKind)
     {
         super(viewContext, createId(identifiableOrNull, entityKind), DEFAULT_LABEL_WIDTH + 20,
                 DEFAULT_FIELD_WIDTH);
         this.viewContext = viewContext;
+        this.inputWidgetDescriptions =
+                inputWidgetDescriptionsOrNull == null ? Collections
+                        .<String, List<IManagedInputWidgetDescription>> emptyMap()
+                        : inputWidgetDescriptionsOrNull;
         this.entityKind = entityKind;
         this.techIdOrNull = TechId.create(identifiableOrNull);
     }
@@ -89,9 +99,11 @@ public abstract class AbstractGenericEntityRegistrationForm<T extends EntityType
      * For registering new entity.
      */
     protected AbstractGenericEntityRegistrationForm(
-            final IViewContext<IGenericClientServiceAsync> viewContext, EntityKind entityKind)
+            final IViewContext<IGenericClientServiceAsync> viewContext,
+            Map<String, List<IManagedInputWidgetDescription>> inputWidgetDescriptions,
+            EntityKind entityKind)
     {
-        this(viewContext, null, entityKind);
+        this(viewContext, inputWidgetDescriptions, null, entityKind);
     }
 
     // ---------------------------------------------------------------------------------------------
@@ -176,7 +188,7 @@ public abstract class AbstractGenericEntityRegistrationForm<T extends EntityType
     private final void createCommonFormFields()
     {
         propertiesEditor =
-                createPropertiesEditor(createId(techIdOrNull, entityKind),
+                createPropertiesEditor(createId(techIdOrNull, entityKind), inputWidgetDescriptions,
                         viewContext.getCommonViewContext());
         codeField =
                 new CodeFieldWithGenerator(viewContext, viewContext.getMessage(Dict.CODE),
@@ -311,6 +323,7 @@ public abstract class AbstractGenericEntityRegistrationForm<T extends EntityType
      * Returns the {@link PropertiesEditor} to be used for .
      */
     abstract protected PropertiesEditor<T, S> createPropertiesEditor(String string,
+            Map<String, List<IManagedInputWidgetDescription>> widgetDescriptions,
             IViewContext<ICommonClientServiceAsync> context);
 
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/ClientPluginFactory.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/ClientPluginFactory.java
index 90dd9fb1962..f57899f329c 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/ClientPluginFactory.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/ClientPluginFactory.java
@@ -223,7 +223,8 @@ public final class ClientPluginFactory extends AbstractClientPluginFactory<Gener
                 final ActionContext context)
         {
             GenericSampleRegistrationForm form =
-                    new GenericSampleRegistrationForm(getViewContext(), sampleType, context);
+                    new GenericSampleRegistrationForm(getViewContext(), inputWidgetDescriptions,
+                            sampleType, context);
             return new DatabaseModificationAwareWidget(form, form);
         }
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/dataset/DataSetPropertyEditor.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/dataset/DataSetPropertyEditor.java
index cd034a775df..93c4039cdca 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/dataset/DataSetPropertyEditor.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/dataset/DataSetPropertyEditor.java
@@ -16,19 +16,24 @@
 
 package ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.dataset;
 
+import java.util.List;
+import java.util.Map;
+
 import ch.systemsx.cisd.openbis.generic.client.web.client.ICommonClientServiceAsync;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetTypePropertyType;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.api.IManagedInputWidgetDescription;
 import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.experiment.PropertiesEditor;
 
-public class DataSetPropertyEditor extends
-        PropertiesEditor<DataSetType, DataSetTypePropertyType>
+public class DataSetPropertyEditor extends PropertiesEditor<DataSetType, DataSetTypePropertyType>
 {
 
-    public DataSetPropertyEditor(String id, IViewContext<ICommonClientServiceAsync> viewContext)
+    public DataSetPropertyEditor(String id,
+            Map<String, List<IManagedInputWidgetDescription>> inputWidgetDescriptions,
+            IViewContext<ICommonClientServiceAsync> viewContext)
     {
-        super(id, viewContext);
+        super(id, inputWidgetDescriptions, viewContext);
     }
 
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/dataset/GenericDataSetEditForm.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/dataset/GenericDataSetEditForm.java
index de50cac187a..6f2401bce4e 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/dataset/GenericDataSetEditForm.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/dataset/GenericDataSetEditForm.java
@@ -20,6 +20,7 @@ import static ch.systemsx.cisd.openbis.generic.client.web.client.application.fra
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 
 import com.extjs.gxt.ui.client.event.BaseEvent;
 import com.extjs.gxt.ui.client.event.Events;
@@ -63,6 +64,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityKind;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.LinkDataSet;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModelRowWithObject;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.api.IManagedInputWidgetDescription;
 import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.IGenericClientServiceAsync;
 import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.AbstractGenericEntityRegistrationForm;
 import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.experiment.PropertiesEditor;
@@ -108,7 +110,7 @@ public final class GenericDataSetEditForm extends
     private GenericDataSetEditForm(IViewContext<IGenericClientServiceAsync> viewContext,
             IIdAndCodeHolder identifiable)
     {
-        super(viewContext, identifiable, EntityKind.DATA_SET);
+        super(viewContext, null, identifiable, EntityKind.DATA_SET);
         setRevertButtonVisible(true);
         simpleId = createSimpleId(identifiable, EntityKind.DATA_SET);
     }
@@ -202,9 +204,11 @@ public final class GenericDataSetEditForm extends
 
     @Override
     protected PropertiesEditor<DataSetType, DataSetTypePropertyType> createPropertiesEditor(
-            String id, IViewContext<ICommonClientServiceAsync> context)
+            String id, Map<String, List<IManagedInputWidgetDescription>> inputWidgetDescriptions,
+            IViewContext<ICommonClientServiceAsync> context)
     {
-        DataSetPropertyEditor editor = new DataSetPropertyEditor(id, context);
+        DataSetPropertyEditor editor =
+                new DataSetPropertyEditor(id, inputWidgetDescriptions, context);
         return editor;
     }
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/AbstractGenericExperimentRegisterEditForm.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/AbstractGenericExperimentRegisterEditForm.java
index 74c5c44343f..7ac62518950 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/AbstractGenericExperimentRegisterEditForm.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/AbstractGenericExperimentRegisterEditForm.java
@@ -99,8 +99,6 @@ abstract public class AbstractGenericExperimentRegisterEditForm extends
 
     private LabelField templateField;
 
-    private final Map<String, List<IManagedInputWidgetDescription>> inputWidgetDescriptions;
-
     protected AbstractGenericExperimentRegisterEditForm(
             IViewContext<IGenericClientServiceAsync> viewContext,
             Map<String, List<IManagedInputWidgetDescription>> inputWidgetDescriptions,
@@ -114,9 +112,7 @@ abstract public class AbstractGenericExperimentRegisterEditForm extends
             Map<String, List<IManagedInputWidgetDescription>> inputWidgetDescriptions,
             ActionContext actionContext, IIdAndCodeHolder identifiable)
     {
-        super(viewContext, identifiable, EntityKind.EXPERIMENT);
-
-        this.inputWidgetDescriptions = inputWidgetDescriptions;
+        super(viewContext, inputWidgetDescriptions, identifiable, EntityKind.EXPERIMENT);
         simpleId = createSimpleId(identifiable, EntityKind.EXPERIMENT);
         attachmentsSessionKey = simpleId + "_attachments";
         samplesSessionKey = simpleId + "_samples";
@@ -179,9 +175,11 @@ abstract public class AbstractGenericExperimentRegisterEditForm extends
 
     @Override
     protected PropertiesEditor<ExperimentType, ExperimentTypePropertyType> createPropertiesEditor(
-            String id, IViewContext<ICommonClientServiceAsync> context)
+            String id, Map<String, List<IManagedInputWidgetDescription>> inputWidgetDescriptions,
+            IViewContext<ICommonClientServiceAsync> context)
     {
-        ExperimentPropertyEditor editor = new ExperimentPropertyEditor(id, context);
+        ExperimentPropertyEditor editor =
+                new ExperimentPropertyEditor(id, inputWidgetDescriptions, context);
         return editor;
     }
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/ExperimentPropertyEditor.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/ExperimentPropertyEditor.java
index b700732138b..082a0419578 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/ExperimentPropertyEditor.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/ExperimentPropertyEditor.java
@@ -16,18 +16,24 @@
 
 package ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.experiment;
 
+import java.util.List;
+import java.util.Map;
+
 import ch.systemsx.cisd.openbis.generic.client.web.client.ICommonClientServiceAsync;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExperimentType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExperimentTypePropertyType;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.api.IManagedInputWidgetDescription;
 
 public class ExperimentPropertyEditor extends
         PropertiesEditor<ExperimentType, ExperimentTypePropertyType>
 {
 
-    public ExperimentPropertyEditor(String id, IViewContext<ICommonClientServiceAsync> viewContext)
+    public ExperimentPropertyEditor(String id,
+            Map<String, List<IManagedInputWidgetDescription>> inputWidgetDescriptions,
+            IViewContext<ICommonClientServiceAsync> viewContext)
     {
-        super(id, viewContext);
+        super(id, inputWidgetDescriptions, viewContext);
     }
 
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/GenericExperimentRegistrationForm.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/GenericExperimentRegistrationForm.java
index bd76942dff7..dce9786ba70 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/GenericExperimentRegistrationForm.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/GenericExperimentRegistrationForm.java
@@ -110,9 +110,11 @@ public final class GenericExperimentRegistrationForm extends
 
     @Override
     protected PropertiesEditor<ExperimentType, ExperimentTypePropertyType> createPropertiesEditor(
-            String id, IViewContext<ICommonClientServiceAsync> context)
+            String id, Map<String, List<IManagedInputWidgetDescription>> inputWidgetDescriptions,
+            IViewContext<ICommonClientServiceAsync> context)
     {
-        ExperimentPropertyEditor editor = new ExperimentPropertyEditor(id, context);
+        ExperimentPropertyEditor editor =
+                new ExperimentPropertyEditor(id, inputWidgetDescriptions, context);
         return editor;
     }
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/ManagedPropertyField.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/ManagedPropertyField.java
new file mode 100644
index 00000000000..2e15b428598
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/ManagedPropertyField.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2012 ETH Zuerich, CISD
+ *
+ * Licensed 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 ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.experiment;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import com.extjs.gxt.ui.client.Style.HorizontalAlignment;
+import com.extjs.gxt.ui.client.event.ButtonEvent;
+import com.extjs.gxt.ui.client.event.Listener;
+import com.extjs.gxt.ui.client.event.MessageBoxEvent;
+import com.extjs.gxt.ui.client.event.SelectionListener;
+import com.extjs.gxt.ui.client.widget.Dialog;
+import com.extjs.gxt.ui.client.widget.HorizontalPanel;
+import com.extjs.gxt.ui.client.widget.MessageBox;
+import com.extjs.gxt.ui.client.widget.VerticalPanel;
+import com.extjs.gxt.ui.client.widget.button.Button;
+import com.extjs.gxt.ui.client.widget.form.Field;
+import com.extjs.gxt.ui.client.widget.form.FormPanel;
+import com.extjs.gxt.ui.client.widget.form.TextField;
+import com.google.gwt.user.client.ui.Widget;
+
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.AbstractRegistrationForm;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.managed_property.ManagedPropertyFormHelper;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.api.IManagedInputWidgetDescription;
+
+/**
+ * @author Franz-Josef Elmer
+ */
+public class ManagedPropertyField extends Field<List<Map<String, String>>>
+{
+    private static final int SPACING = 3;
+
+    private static final class Section
+    {
+        private final Map<String, TextField<?>> inputFields;
+
+        Section(Map<String, TextField<?>> inputFields)
+        {
+            this.inputFields = inputFields;
+        }
+    }
+
+    private final IViewContext<?> viewContext;
+
+    private final List<IManagedInputWidgetDescription> widgetDescriptions;
+
+    private final VerticalPanel verticalPanel;
+
+    private List<Section> sections = new ArrayList<Section>();
+
+    public ManagedPropertyField(IViewContext<?> viewContext, String label, boolean isMandatory,
+            List<IManagedInputWidgetDescription> widgetDescriptions)
+    {
+        this.viewContext = viewContext;
+        this.widgetDescriptions = widgetDescriptions;
+        verticalPanel = new VerticalPanel();
+        verticalPanel.setHorizontalAlign(HorizontalAlignment.RIGHT);
+
+        Button addButton = new Button("Add More");
+        addButton.addSelectionListener(new SelectionListener<ButtonEvent>()
+            {
+                @Override
+                public void componentSelected(ButtonEvent ce)
+                {
+                    addNewSection();
+                }
+            });
+        addButton.setToolTip("Add a new section.");
+        verticalPanel.add(addButton);
+        addNewSection();
+    }
+
+    public Widget getWidget()
+    {
+        return verticalPanel;
+    }
+
+    @Override
+    public List<Map<String, String>> getValue()
+    {
+        List<Map<String, String>> list = new ArrayList<Map<String, String>>();
+        for (Section section : sections)
+        {
+            HashMap<String, String> row = new HashMap<String, String>();
+            for (Entry<String, TextField<?>> entry : section.inputFields.entrySet())
+            {
+                row.put(entry.getKey(), entry.getValue().getRawValue());
+            }
+            list.add(row);
+        }
+        return list;
+    }
+
+    private void addNewSection()
+    {
+        FormPanel formPanel = new FormPanel();
+        formPanel.setLabelWidth(AbstractRegistrationForm.DEFAULT_LABEL_WIDTH - SPACING - 2);
+        formPanel.setFieldWidth(AbstractRegistrationForm.DEFAULT_FIELD_WIDTH);
+        formPanel.setHeaderVisible(false);
+        Map<String, TextField<?>> inputFieldsByLabel = new HashMap<String, TextField<?>>();
+        ManagedPropertyFormHelper formHelper =
+                new ManagedPropertyFormHelper(viewContext, formPanel, inputFieldsByLabel);
+        formHelper.fillForm(widgetDescriptions);
+        final HorizontalPanel horizontalPanel = new HorizontalPanel();
+        horizontalPanel.setSpacing(SPACING);
+        horizontalPanel.add(formPanel);
+        Button removeButton = new Button("-");
+        removeButton.setToolTip("Delete this section.");
+        final Section section = new Section(inputFieldsByLabel);
+        removeButton.addSelectionListener(new SelectionListener<ButtonEvent>()
+            {
+                @Override
+                public void componentSelected(ButtonEvent ce)
+                {
+                    MessageBox.confirm("Delete Section",
+                            "Do you really want to delete this section?",
+                            new Listener<MessageBoxEvent>()
+                                {
+                                    @Override
+                                    public void handleEvent(MessageBoxEvent be)
+                                    {
+                                        Button buttonClicked = be.getButtonClicked();
+                                        if (Dialog.YES.equals(buttonClicked.getItemId()))
+                                        {
+                                            sections.remove(section);
+                                            verticalPanel.remove(horizontalPanel);
+                                            verticalPanel.layout();
+                                        }
+                                    }
+                                });
+                }
+            });
+        horizontalPanel.add(removeButton);
+        sections.add(section);
+        verticalPanel.insert(horizontalPanel, verticalPanel.getItemCount() - 1);
+        verticalPanel.layout();
+    }
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/PropertiesEditor.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/PropertiesEditor.java
index 5ccaf55064f..e96b6ec02af 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/PropertiesEditor.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/PropertiesEditor.java
@@ -20,10 +20,14 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 
 import com.extjs.gxt.ui.client.widget.form.FieldSet;
 import com.extjs.gxt.ui.client.widget.form.FormPanel;
 import com.extjs.gxt.ui.client.widget.layout.FormLayout;
+import com.google.gwt.json.client.JSONArray;
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONString;
 
 import ch.systemsx.cisd.openbis.generic.client.web.client.ICommonClientServiceAsync;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
@@ -39,6 +43,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityTypePropertyType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.PropertyType;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.api.IManagedInputWidgetDescription;
 
 /**
  * @author Izabela Adamczyk
@@ -54,6 +59,8 @@ abstract public class PropertiesEditor<T extends EntityType, S extends EntityTyp
 
     private final IViewContext<ICommonClientServiceAsync> viewContext;
 
+    private final Map<String, List<IManagedInputWidgetDescription>> inputWidgetDescriptions;
+
     protected IEntityProperty createEntityProperty()
     {
         return new EntityProperty();
@@ -62,9 +69,12 @@ abstract public class PropertiesEditor<T extends EntityType, S extends EntityTyp
     /**
      * Requires initial values of properties.
      */
-    protected PropertiesEditor(String id, IViewContext<ICommonClientServiceAsync> viewContext)
+    protected PropertiesEditor(String id,
+            Map<String, List<IManagedInputWidgetDescription>> inputWidgetDescriptions,
+            IViewContext<ICommonClientServiceAsync> viewContext)
     {
         this.id = id;
+        this.inputWidgetDescriptions = inputWidgetDescriptions;
         this.viewContext = viewContext;
     }
 
@@ -129,13 +139,20 @@ abstract public class PropertiesEditor<T extends EntityType, S extends EntityTyp
         assert viewContext != null;
         final DatabaseModificationAwareField<?> field;
         final boolean isMandatory = etpt.isMandatory();
-        final String label =
-                PropertyTypeRenderer.getDisplayName(etpt.getPropertyType(), propertyTypes);
-        final String propertyTypeCode = etpt.getPropertyType().getCode();
-        boolean isManaged = etpt.isManaged();
-        field =
-                PropertyFieldFactory.createField(etpt.getPropertyType(), isMandatory, label,
-                        createFormFieldId(getId(), propertyTypeCode), value, viewContext);
+        PropertyType propertyType = etpt.getPropertyType();
+        final String label = PropertyTypeRenderer.getDisplayName(propertyType, propertyTypes);
+        final String propertyTypeCode = propertyType.getCode();
+        List<IManagedInputWidgetDescription> widgetDescriptions =
+                inputWidgetDescriptions.get(propertyTypeCode);
+        if (widgetDescriptions != null && widgetDescriptions.isEmpty() == false)
+        {
+            field = createManagedPropertySection(label, isMandatory, widgetDescriptions);
+        } else
+        {
+            field =
+                    PropertyFieldFactory.createField(propertyType, isMandatory, label,
+                            createFormFieldId(getId(), propertyTypeCode), value, viewContext);
+        }
         field.get().setData(ETPT, etpt);
         GWTUtils.setToolTip(field.get(), propertyTypeCode);
         // Hide any properties that are not to be shown in edit/update views (unless in debugging
@@ -147,6 +164,13 @@ abstract public class PropertiesEditor<T extends EntityType, S extends EntityTyp
         return field;
     }
 
+    private DatabaseModificationAwareField<?> createManagedPropertySection(String label,
+            boolean isMandatory, List<IManagedInputWidgetDescription> widgetDescriptions)
+    {
+        return DatabaseModificationAwareField.wrapUnaware(new ManagedPropertyField(viewContext,
+                label, isMandatory, widgetDescriptions));
+    }
+
     private boolean isDebuggingModeEnabled()
     {
         return viewContext.getDisplaySettingsManager().isDebuggingModeEnabled();
@@ -177,8 +201,27 @@ abstract public class PropertiesEditor<T extends EntityType, S extends EntityTyp
             if (etpt != null)
             {
                 final IEntityProperty entityProperty = createEntityProperty();
-                entityProperty.setValue(PropertyFieldFactory.valueToString(value));
-                entityProperty.setPropertyType(etpt.getPropertyType());
+                PropertyType propertyType = etpt.getPropertyType();
+                String valueAsString = PropertyFieldFactory.valueToString(value);
+                if (inputWidgetDescriptions.get(propertyType.getCode()) != null)
+                {
+                    JSONArray jsonArray = new JSONArray();
+                    @SuppressWarnings("unchecked")
+                    List<Map<String, String>> rows = (List<Map<String, String>>) value;
+                    for (int i = 0; i < rows.size(); i++)
+                    {
+                        Map<String, String> row = rows.get(i);
+                        JSONObject jsonObject = new JSONObject();
+                        for (Entry<String, String> entry : row.entrySet())
+                        {
+                            jsonObject.put(entry.getKey(), new JSONString(entry.getValue()));
+                        }
+                        jsonArray.set(i, jsonObject);
+                    }
+                    valueAsString = jsonArray.toString();
+                }
+                entityProperty.setValue(valueAsString);
+                entityProperty.setPropertyType(propertyType);
                 properties.add(entityProperty);
             }
         }
@@ -227,7 +270,21 @@ abstract public class PropertiesEditor<T extends EntityType, S extends EntityTyp
                 currentSectionFieldSet.add(field.get());
             } else
             {
-                form.add(field.get());
+                if (field.get() instanceof ManagedPropertyField)
+                {
+                    PropertyType propertyType = etpt.getPropertyType();
+                    String label = propertyType.getLabel();
+                    if (etpt.isMandatory())
+                    {
+                        label += " *";
+                    }
+                    FieldSet fieldSet = createSectionFieldSet(label);
+                    fieldSet.add(((ManagedPropertyField) field.get()).getWidget());
+                    form.add(fieldSet);
+                } else
+                {
+                    form.add(field.get());
+                }
             }
 
             previousSection = currentSection;
@@ -241,13 +298,13 @@ abstract public class PropertiesEditor<T extends EntityType, S extends EntityTyp
 
     private FieldSet createSectionFieldSet(String sectionName)
     {
-        return new PropertiesSectionFileSet(sectionName);
+        return new PropertiesSectionFieldSet(sectionName);
     }
 
-    private static final class PropertiesSectionFileSet extends FieldSet
+    private static final class PropertiesSectionFieldSet extends FieldSet
     {
 
-        public PropertiesSectionFileSet(final String sectionName)
+        public PropertiesSectionFieldSet(final String sectionName)
         {
             createForm(sectionName);
         }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/material/GenericMaterialEditForm.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/material/GenericMaterialEditForm.java
index 22e62919ebd..5f08018d6fc 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/material/GenericMaterialEditForm.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/material/GenericMaterialEditForm.java
@@ -19,6 +19,7 @@ package ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.ma
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
 
 import ch.systemsx.cisd.openbis.generic.client.web.client.ICommonClientServiceAsync;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.AbstractAsyncCallback;
@@ -31,6 +32,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityKind;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Material;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.MaterialType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.MaterialTypePropertyType;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.api.IManagedInputWidgetDescription;
 import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.IGenericClientServiceAsync;
 import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.AbstractGenericEntityRegistrationForm;
 import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.experiment.PropertiesEditor;
@@ -57,7 +59,7 @@ public final class GenericMaterialEditForm extends
     private GenericMaterialEditForm(IViewContext<IGenericClientServiceAsync> viewContext,
             IIdAndCodeHolder identifiable, boolean editMode)
     {
-        super(viewContext, identifiable, EntityKind.MATERIAL);
+        super(viewContext, null, identifiable, EntityKind.MATERIAL);
         setRevertButtonVisible(true);
     }
 
@@ -100,9 +102,11 @@ public final class GenericMaterialEditForm extends
 
     @Override
     protected PropertiesEditor<MaterialType, MaterialTypePropertyType> createPropertiesEditor(
-            String id, IViewContext<ICommonClientServiceAsync> context)
+            String id, Map<String, List<IManagedInputWidgetDescription>> inputWidgetDescriptions,
+            IViewContext<ICommonClientServiceAsync> context)
     {
-        MaterialPropertyEditor editor = new MaterialPropertyEditor(id, context);
+        MaterialPropertyEditor editor =
+                new MaterialPropertyEditor(id, inputWidgetDescriptions, context);
         return editor;
     }
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/material/MaterialPropertyEditor.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/material/MaterialPropertyEditor.java
index d3632452497..db73c45e6e0 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/material/MaterialPropertyEditor.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/material/MaterialPropertyEditor.java
@@ -16,19 +16,25 @@
 
 package ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.material;
 
+import java.util.List;
+import java.util.Map;
+
 import ch.systemsx.cisd.openbis.generic.client.web.client.ICommonClientServiceAsync;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.MaterialType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.MaterialTypePropertyType;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.api.IManagedInputWidgetDescription;
 import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.experiment.PropertiesEditor;
 
 public class MaterialPropertyEditor extends
         PropertiesEditor<MaterialType, MaterialTypePropertyType>
 {
 
-    public MaterialPropertyEditor(String id, IViewContext<ICommonClientServiceAsync> viewContext)
+    public MaterialPropertyEditor(String id,
+            Map<String, List<IManagedInputWidgetDescription>> inputWidgetDescriptions,
+            IViewContext<ICommonClientServiceAsync> viewContext)
     {
-        super(id, viewContext);
+        super(id, inputWidgetDescriptions, viewContext);
     }
 
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/AbstractGenericSampleRegisterEditForm.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/AbstractGenericSampleRegisterEditForm.java
index b234e7b9323..f541d150e71 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/AbstractGenericSampleRegisterEditForm.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/AbstractGenericSampleRegisterEditForm.java
@@ -20,6 +20,7 @@ import static ch.systemsx.cisd.openbis.generic.client.web.client.application.fra
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 
 import com.extjs.gxt.ui.client.event.ButtonEvent;
 import com.extjs.gxt.ui.client.event.Events;
@@ -62,6 +63,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleTypePropertyType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Space;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModelRowWithObject;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.api.IManagedInputWidgetDescription;
 import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.IGenericClientServiceAsync;
 import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.AbstractGenericEntityRegistrationForm;
 import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.experiment.PropertiesEditor;
@@ -107,16 +109,19 @@ abstract public class AbstractGenericSampleRegisterEditForm extends
     private Button saveUploadButton;
 
     protected AbstractGenericSampleRegisterEditForm(
-            IViewContext<IGenericClientServiceAsync> viewContext, ActionContext actionContext)
+            IViewContext<IGenericClientServiceAsync> viewContext,
+            Map<String, List<IManagedInputWidgetDescription>> inputWidgetDescriptions,
+            ActionContext actionContext)
     {
-        this(viewContext, actionContext, null);
+        this(viewContext, inputWidgetDescriptions, actionContext, null);
     }
 
     protected AbstractGenericSampleRegisterEditForm(
-            IViewContext<IGenericClientServiceAsync> viewContext, ActionContext actionContext,
-            IIdAndCodeHolder identifiable)
+            IViewContext<IGenericClientServiceAsync> viewContext,
+            Map<String, List<IManagedInputWidgetDescription>> inputWidgetDescriptions,
+            ActionContext actionContext, IIdAndCodeHolder identifiable)
     {
-        super(viewContext, identifiable, EntityKind.SAMPLE);
+        super(viewContext, inputWidgetDescriptions, identifiable, EntityKind.SAMPLE);
         this.simpleId = createSimpleId(identifiable, EntityKind.SAMPLE);
         this.attachmentsSessionKey = simpleId + "_attachments";
         List<String> sesionKeys = new ArrayList<String>();
@@ -252,9 +257,11 @@ abstract public class AbstractGenericSampleRegisterEditForm extends
 
     @Override
     protected PropertiesEditor<SampleType, SampleTypePropertyType> createPropertiesEditor(
-            String id, IViewContext<ICommonClientServiceAsync> context)
+            String id, Map<String, List<IManagedInputWidgetDescription>> inputWidgetDescriptions,
+            IViewContext<ICommonClientServiceAsync> context)
     {
-        SamplePropertyEditor editor = new SamplePropertyEditor(id, context);
+        SamplePropertyEditor editor =
+                new SamplePropertyEditor(id, inputWidgetDescriptions, context);
         return editor;
     }
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/GenericSampleEditForm.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/GenericSampleEditForm.java
index f0ee17240b9..eccc2f860f1 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/GenericSampleEditForm.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/GenericSampleEditForm.java
@@ -57,7 +57,7 @@ public final class GenericSampleEditForm extends AbstractGenericSampleRegisterEd
     private GenericSampleEditForm(IViewContext<IGenericClientServiceAsync> viewContext,
             IIdAndCodeHolder identifiable)
     {
-        super(viewContext, new ActionContext(), identifiable);
+        super(viewContext, null, new ActionContext(), identifiable);
         setRevertButtonVisible(true);
     }
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/GenericSampleRegistrationForm.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/GenericSampleRegistrationForm.java
index 490f37d86a0..022e9e2090f 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/GenericSampleRegistrationForm.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/GenericSampleRegistrationForm.java
@@ -17,6 +17,7 @@
 package ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.sample;
 
 import java.util.List;
+import java.util.Map;
 
 import ch.systemsx.cisd.common.shared.basic.utils.StringUtils;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ActionContext;
@@ -27,6 +28,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewSample;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Space;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.api.IManagedInputWidgetDescription;
 import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.IGenericClientServiceAsync;
 
 /**
@@ -38,9 +40,10 @@ public final class GenericSampleRegistrationForm extends AbstractGenericSampleRe
 {
     public GenericSampleRegistrationForm(
             final IViewContext<IGenericClientServiceAsync> viewContext,
+            Map<String, List<IManagedInputWidgetDescription>> inputWidgetDescriptions,
             final SampleType sampleType, ActionContext actionContext)
     {
-        super(viewContext, actionContext);
+        super(viewContext, inputWidgetDescriptions, actionContext);
         setResetButtonVisible(true);
         this.sampleType = sampleType;
     }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/SamplePropertyEditor.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/SamplePropertyEditor.java
index f9584f2fb4a..110164e48c5 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/SamplePropertyEditor.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/SamplePropertyEditor.java
@@ -16,19 +16,24 @@
 
 package ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.sample;
 
+import java.util.List;
+import java.util.Map;
+
 import ch.systemsx.cisd.openbis.generic.client.web.client.ICommonClientServiceAsync;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleTypePropertyType;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.api.IManagedInputWidgetDescription;
 import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.experiment.PropertiesEditor;
 
-public class SamplePropertyEditor extends
-        PropertiesEditor<SampleType, SampleTypePropertyType>
+public class SamplePropertyEditor extends PropertiesEditor<SampleType, SampleTypePropertyType>
 {
 
-    public SamplePropertyEditor(String id, IViewContext<ICommonClientServiceAsync> viewContext)
+    public SamplePropertyEditor(String id,
+            Map<String, List<IManagedInputWidgetDescription>> inputWidgetDescriptions,
+            IViewContext<ICommonClientServiceAsync> viewContext)
     {
-        super(id, viewContext);
+        super(id, inputWidgetDescriptions, viewContext);
     }
 
 }
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/managed_property/ManagedPropertyEvaluatorTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/managed_property/ManagedPropertyEvaluatorTest.java
index 59d0b937be0..5ae0dabda5b 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/managed_property/ManagedPropertyEvaluatorTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/managed_property/ManagedPropertyEvaluatorTest.java
@@ -283,59 +283,123 @@ public class ManagedPropertyEvaluatorTest extends AssertJUnit
         assertEquals(expectedMandatory, widget.isMandatory());
     }
 
-    @Test
+    @Test(expectedExceptionsMessageRegExp = "Function updateFromBatchInput is not defined "
+            + "although function batchColumnNames is defined.", expectedExceptions = EvaluatorException.class)
     public void testScriptWithBatchColumnNamesFunctionButMissingUpdateFromBatchFunction()
     {
-        try
-        {
-            new ManagedPropertyEvaluator("def batchColumnNames():\n return ['A']");
-            fail("EvaluatorException expected");
-        } catch (EvaluatorException ex)
-        {
-            assertEquals("Function 'batchColumnNames' defined but not 'updateFromBatchInput'.",
-                    ex.getMessage());
-        }
+        new ManagedPropertyEvaluator("def batchColumnNames():\n return ['A']");
     }
 
-    @Test
+    @Test(expectedExceptionsMessageRegExp = "Function updateFromBatchInput is not defined "
+            + "although function inputWidgets is defined.", expectedExceptions = EvaluatorException.class)
+    public void testScriptWithInputWidgetsFunctionButMissingUpdateFromBatchFunction()
+    {
+        new ManagedPropertyEvaluator(
+                "def inputWidgets():\n return [inputWidgetFactory().createTextInputField('Field')]");
+    }
+
+    @Test(expectedExceptionsMessageRegExp = "Function updateFromBatchInput is not defined "
+            + "although functions batchColumnNames and inputWidgets are defined.", expectedExceptions = EvaluatorException.class)
+    public void testScriptWithInputWidgetsFunctionAndBatchColumnNamesFunctionButMissingUpdateFromBatchFunction()
+    {
+        new ManagedPropertyEvaluator("def inputWidgets():\n"
+                + " return [inputWidgetFactory().createTextInputField('Field')]\n"
+                + "def batchColumnNames():\n return ['A']");
+    }
+
+    @Test(expectedExceptionsMessageRegExp = "Function inputWidgets has returned a list "
+            + "where the 2. element is null.", expectedExceptions = EvaluatorException.class)
+    public void testScriptWithInputWidgetsFunctionWithANullElement()
+    {
+        new ManagedPropertyEvaluator("def inputWidgets():\n"
+                + " return [inputWidgetFactory().createTextInputField('A'), None]\n"
+                + "def updateFromBatchInput():\n  None");
+    }
+
+    @Test(expectedExceptionsMessageRegExp = "Function inputWidgets has returned a list where "
+            + "the 2. element isn't of type "
+            + "ch.systemsx.cisd.openbis.generic.shared.basic.dto.api.IManagedInputWidgetDescription "
+            + "but java.lang.String.", expectedExceptions = EvaluatorException.class)
+    public void testScriptWithInputWidgetsFunctionWithElementOfWrongType()
+    {
+        new ManagedPropertyEvaluator("def inputWidgets():\n"
+                + " return [inputWidgetFactory().createTextInputField('A'), 'B']\n"
+                + "def updateFromBatchInput():\n  None");
+    }
+
+    @Test(expectedExceptionsMessageRegExp = "Function 'batchColumnNames' doesn't return a List "
+            + "but an object of type 'java.lang.Integer': 42", expectedExceptions = EvaluatorException.class)
     public void testScriptWithBatchColumnNamesFunctionWhichDoesNotReturnAList()
     {
-        try
-        {
-            new ManagedPropertyEvaluator("def batchColumnNames():\n return 42\n"
-                    + "def updateFromBatchInput():\n  None");
-            fail("EvaluatorException expected");
-        } catch (EvaluatorException ex)
-        {
-            assertEquals("Function 'batchColumnNames' doesn't return a List "
-                    + "but an object of type 'java.lang.Integer': 42", ex.getMessage());
-        }
+        new ManagedPropertyEvaluator("def batchColumnNames():\n return 42\n"
+                + "def updateFromBatchInput():\n  None");
     }
 
-    @Test
-    public void testScriptWithBatchColumnNamesFunctionWhichReturnLowerCaseNames()
+    @Test(expectedExceptionsMessageRegExp = "There is already an input widget with code: A", expectedExceptions = EvaluatorException.class)
+    public void testScriptWithInputWidgetsFunctionWithNonUniqueCodes()
     {
-        try
-        {
-            new ManagedPropertyEvaluator(
-                    "def batchColumnNames():\n return ['abc', 'A', 'e42', 42]\n"
-                            + "def updateFromBatchInput():\n  None");
-            fail("EvaluatorException expected");
-        } catch (EvaluatorException ex)
-        {
-            assertEquals("The following batch column names "
-                    + "as returned by function 'batchColumnNames' "
-                    + "are not in upper case: [abc, e42]", ex.getMessage());
-        }
+        new ManagedPropertyEvaluator("def inputWidgets():\n" + " f = inputWidgetFactory()\n"
+                + " w1 = f.createTextInputField('a')\n" + " w2 = f.createTextInputField('Alpha')\n"
+                + " w2.code = 'A'\n" + " return [w1, w2]\n" + "def updateFromBatchInput():\n  None");
     }
 
     @Test
     public void testGetBatchColumnNamesScript()
     {
         ManagedPropertyEvaluator evaluator =
-                new ManagedPropertyEvaluator("def batchColumnNames():\n return ['A', 42]\n"
+                new ManagedPropertyEvaluator("def batchColumnNames():\n return ['A', 'Beta']\n"
                         + "def updateFromBatchInput():\n  None");
-        assertEquals("[A, 42]", evaluator.getBatchColumnNames().toString());
+        assertEquals("[A, BETA]", evaluator.getBatchColumnNames().toString());
+        List<IManagedInputWidgetDescription> inputWidgetDescriptions =
+                evaluator.getInputWidgetDescriptions();
+        assertEquals("A", inputWidgetDescriptions.get(0).getCode());
+        assertEquals("A", inputWidgetDescriptions.get(0).getLabel());
+        assertEquals(ManagedInputFieldType.TEXT, inputWidgetDescriptions.get(0)
+                .getManagedInputFieldType());
+        assertEquals("BETA", inputWidgetDescriptions.get(1).getCode());
+        assertEquals("Beta", inputWidgetDescriptions.get(1).getLabel());
+        assertEquals(ManagedInputFieldType.TEXT, inputWidgetDescriptions.get(1)
+                .getManagedInputFieldType());
+        assertEquals(2, inputWidgetDescriptions.size());
+    }
+
+    @Test
+    public void testGetInputWidgetsScript()
+    {
+        ManagedPropertyEvaluator evaluator =
+                new ManagedPropertyEvaluator(
+                        "def inputWidgets():\n"
+                                + " return [inputWidgetFactory().createComboBoxInputField('Field', ['A', 'B'])]\n"
+                                + "def updateFromBatchInput():\n  None");
+        assertEquals("[FIELD]", evaluator.getBatchColumnNames().toString());
+        List<IManagedInputWidgetDescription> inputWidgetDescriptions =
+                evaluator.getInputWidgetDescriptions();
+        assertEquals("FIELD", inputWidgetDescriptions.get(0).getCode());
+        assertEquals("Field", inputWidgetDescriptions.get(0).getLabel());
+        assertEquals("[A, B]",
+                ((ManagedComboBoxInputWidgetDescription) inputWidgetDescriptions.get(0))
+                        .getOptions().toString());
+        assertEquals(1, inputWidgetDescriptions.size());
+    }
+
+    @Test
+    public void testGetInputWidgetsScriptAndBatchColumnNamesScript()
+    {
+        ManagedPropertyEvaluator evaluator =
+                new ManagedPropertyEvaluator(
+                        "def batchColumnNames():\n return ['A', 'Beta']\n"
+                                + "def inputWidgets():\n"
+                                + " return [inputWidgetFactory().createComboBoxInputField('Field', ['A', 'B'])]\n"
+                                + "def updateFromBatchInput():\n  None");
+        assertEquals("[A, BETA]", evaluator.getBatchColumnNames().toString());
+        List<IManagedInputWidgetDescription> inputWidgetDescriptions =
+                evaluator.getInputWidgetDescriptions();
+        assertEquals("FIELD", inputWidgetDescriptions.get(0).getCode());
+        assertEquals("Field", inputWidgetDescriptions.get(0).getLabel());
+        assertEquals("[A, B]",
+                ((ManagedComboBoxInputWidgetDescription) inputWidgetDescriptions.get(0))
+                        .getOptions().toString());
+        assertEquals(1, inputWidgetDescriptions.size());
     }
 
     @Test
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/proteomics/client/web/client/application/wizard/BiologicalSampleCreatingPage.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/proteomics/client/web/client/application/wizard/BiologicalSampleCreatingPage.java
index 71c9a9541e0..770a828280c 100644
--- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/proteomics/client/web/client/application/wizard/BiologicalSampleCreatingPage.java
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/proteomics/client/web/client/application/wizard/BiologicalSampleCreatingPage.java
@@ -16,8 +16,10 @@
 
 package ch.systemsx.cisd.openbis.plugin.proteomics.client.web.client.application.wizard;
 
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 
 import com.extjs.gxt.ui.client.event.SelectionChangedEvent;
 import com.extjs.gxt.ui.client.event.SelectionChangedListener;
@@ -42,6 +44,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityKind;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleTypePropertyType;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.api.IManagedInputWidgetDescription;
 import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.sample.AbstractGenericSampleRegisterEditForm;
 import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.sample.SamplePropertyEditor;
 import ch.systemsx.cisd.openbis.plugin.proteomics.client.web.client.IPhosphoNetXClientServiceAsync;
@@ -63,6 +66,9 @@ public class BiologicalSampleCreatingPage extends WizardPage<MsInjectionSampleAn
     private SamplePropertyEditor samplePropertyEditor;
     private ExperimentChooserFieldAdaptor experimentField;
 
+    private Map<String, List<IManagedInputWidgetDescription>> inputWidgetDescriptions = Collections
+            .<String, List<IManagedInputWidgetDescription>> emptyMap();
+
     public BiologicalSampleCreatingPage(IViewContext<IPhosphoNetXClientServiceAsync> viewContext,
             MsInjectionSampleAnnotationModel model)
     {
@@ -134,7 +140,9 @@ public class BiologicalSampleCreatingPage extends WizardPage<MsInjectionSampleAn
                 viewContext.getCommonViewContext());
         formPanel.add(experimentField.getChooserField());
 
-        samplePropertyEditor = new SamplePropertyEditor("bio-s", viewContext.getCommonViewContext());
+        samplePropertyEditor =
+                new SamplePropertyEditor("bio-s", inputWidgetDescriptions,
+                        viewContext.getCommonViewContext());
         samplePropertyEditor.initWithoutProperties(types);
         samplePropertyEditor.addPropertyFieldsWithFieldsetToPanel(formPanel);
         formPanel.layout();
-- 
GitLab